Index: pkg/analysis_server/tool/spec/to_html.dart |
diff --git a/pkg/analysis_server/tool/spec/to_html.dart b/pkg/analysis_server/tool/spec/to_html.dart |
index 8e8a8920e6186f8bbc802ba49dfa107d3a11e900..ed3827c3b5a3138666fbc9e0c2c11a35f5f6232a 100644 |
--- a/pkg/analysis_server/tool/spec/to_html.dart |
+++ b/pkg/analysis_server/tool/spec/to_html.dart |
@@ -63,35 +63,61 @@ dt.typeDefinition { |
} |
'''.trim(); |
+final GeneratedFile target = new GeneratedFile('../../doc/api.html', () { |
+ ToHtmlVisitor visitor = new ToHtmlVisitor(readApi()); |
+ dom.Document document = new dom.Document(); |
+ for (dom.Node node in visitor.collectHtml(visitor.visitApi)) { |
+ document.append(node); |
+ } |
+ return document.outerHtml; |
+}); |
+ |
+/** |
+ * Translate spec_input.html into api.html. |
+ */ |
+main() { |
+ target.generate(); |
+} |
+ |
+/** |
+ * Visitor that records the mapping from HTML elements to various kinds of API |
+ * nodes. |
+ */ |
+class ApiMappings extends HierarchicalApiVisitor { |
+ Map<dom.Element, Domain> domains = <dom.Element, Domain>{}; |
+ |
+ ApiMappings(Api api) : super(api); |
+ |
+ @override |
+ void visitDomain(Domain domain) { |
+ domains[domain.html] = domain; |
+ } |
+} |
+ |
/** |
* Helper methods for creating HTML elements. |
*/ |
abstract class HtmlMixin { |
- void element(String name, Map<dynamic, String> attributes, [void callback()]); |
- |
void anchor(String id, void callback()) { |
element('a', { |
'name': id |
}, callback); |
} |
- void link(String id, void callback()) { |
- element('a', { |
- 'href': '#$id' |
- }, callback); |
- } |
+ |
void b(void callback()) => element('b', {}, callback); |
+ void body(void callback()) => element('body', {}, callback); |
void box(void callback()) { |
element('div', { |
'class': 'box' |
}, callback); |
} |
void br() => element('br', {}); |
- void body(void callback()) => element('body', {}, callback); |
void dd(void callback()) => element('dd', {}, callback); |
void dl(void callback()) => element('dl', {}, callback); |
void dt(String cls, void callback()) => element('dt', { |
'class': cls |
}, callback); |
+ void element(String name, Map<dynamic, String> attributes, [void callback()]); |
void gray(void callback()) => element('span', { |
'style': 'color:#999999' |
}, callback); |
@@ -112,6 +138,11 @@ abstract class HtmlMixin { |
void head(void callback()) => element('head', {}, callback); |
void html(void callback()) => element('html', {}, callback); |
void i(void callback()) => element('i', {}, callback); |
+ void link(String id, void callback()) { |
+ element('a', { |
+ 'href': '#$id' |
+ }, callback); |
+ } |
void p(void callback()) => element('p', {}, callback); |
void pre(void callback()) => element('pre', {}, callback); |
void title(void callback()) => element('title', {}, callback); |
@@ -119,141 +150,10 @@ abstract class HtmlMixin { |
} |
/** |
- * Visitor that generates a compact representation of a type, such as: |
- * |
- * { |
- * "id": String |
- * "error": optional Error |
- * "result": { |
- * "version": String |
- * } |
- * } |
- */ |
-class TypeVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlCodeGenerator { |
- /** |
- * Set of fields which should be shown in boldface, or null if no field |
- * should be shown in boldface. |
- */ |
- final Set<String> fieldsToBold; |
- |
- /** |
- * True if a short description should be generated. In a short description, |
- * objects are shown as simply "object", and enums are shown as "String". |
- */ |
- final bool short; |
- |
- TypeVisitor(Api api, {this.fieldsToBold, this.short: false}) : super(api); |
- |
- @override |
- void visitTypeEnum(TypeEnum typeEnum) { |
- if (short) { |
- write('String'); |
- return; |
- } |
- writeln('enum {'); |
- indent(() { |
- for (TypeEnumValue value in typeEnum.values) { |
- writeln(value.value); |
- } |
- }); |
- write('}'); |
- } |
- |
- @override |
- void visitTypeList(TypeList typeList) { |
- write('List<'); |
- visitTypeDecl(typeList.itemType); |
- write('>'); |
- } |
- |
- @override |
- void visitTypeMap(TypeMap typeMap) { |
- write('Map<'); |
- visitTypeDecl(typeMap.keyType); |
- write(', '); |
- visitTypeDecl(typeMap.valueType); |
- write('>'); |
- } |
- |
- @override |
- void visitTypeObject(TypeObject typeObject) { |
- if (short) { |
- write('object'); |
- return; |
- } |
- writeln('{'); |
- indent(() { |
- for (TypeObjectField field in typeObject.fields) { |
- write('"'); |
- if (fieldsToBold != null && fieldsToBold.contains(field.name)) { |
- b(() { |
- write(field.name); |
- }); |
- } else { |
- write(field.name); |
- } |
- write('": '); |
- if (field.value != null) { |
- write(JSON.encode(field.value)); |
- } else { |
- if (field.optional) { |
- gray(() { |
- write('optional'); |
- }); |
- write(' '); |
- } |
- visitTypeDecl(field.type); |
- } |
- writeln(); |
- } |
- }); |
- write('}'); |
- } |
- |
- @override |
- void visitTypeReference(TypeReference typeReference) { |
- String displayName = typeReference.typeName; |
- if (api.types.containsKey(typeReference.typeName)) { |
- link('type_${typeReference.typeName}', () { |
- write(displayName); |
- }); |
- } else { |
- write(displayName); |
- } |
- } |
- |
- @override |
- void visitTypeUnion(TypeUnion typeUnion) { |
- bool verticalBarNeeded = false; |
- for (TypeDecl choice in typeUnion.choices) { |
- if (verticalBarNeeded) { |
- write(' | '); |
- } |
- visitTypeDecl(choice); |
- verticalBarNeeded = true; |
- } |
- } |
-} |
- |
-/** |
- * Visitor that records the mapping from HTML elements to various kinds of API |
- * nodes. |
- */ |
-class ApiMappings extends HierarchicalApiVisitor { |
- ApiMappings(Api api) : super(api); |
- |
- Map<dom.Element, Domain> domains = <dom.Element, Domain>{}; |
- |
- @override |
- void visitDomain(Domain domain) { |
- domains[domain.html] = domain; |
- } |
-} |
- |
-/** |
* Visitor that generates HTML documentation of the API. |
*/ |
-class ToHtmlVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlGenerator { |
+class ToHtmlVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlGenerator |
+ { |
/** |
* Set of types defined in the API. |
*/ |
@@ -270,79 +170,64 @@ class ToHtmlVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlGenerator |
apiMappings.visitApi(); |
} |
- @override |
- void visitApi() { |
- definedTypes = api.types.keys.toSet(); |
- |
- html(() { |
- translateHtml(api.html); |
- }); |
- } |
- |
- @override |
- void visitRefactorings(Refactorings refactorings) { |
- translateHtml(refactorings.html); |
- dl(() { |
- super.visitRefactorings(refactorings); |
- }); |
- } |
- |
- @override visitRefactoring(Refactoring refactoring) { |
- dt('refactoring', () { |
- write(refactoring.kind); |
- }); |
- dd(() { |
- translateHtml(refactoring.html); |
- describePayload(refactoring.feedback, 'Feedback', force: true); |
- describePayload(refactoring.options, 'Options', force: true); |
- }); |
- } |
- |
- @override |
- void visitTypes(Types types) { |
- translateHtml(types.html); |
- dl(() { |
- super.visitTypes(types); |
- }); |
- } |
- |
- @override |
- void visitDomain(Domain domain) { |
- h2('domain', () { |
- anchor('domain_${domain.name}', () { |
- write('Domain: ${domain.name}'); |
- }); |
- }); |
- translateHtml(domain.html); |
- if (domain.requests.isNotEmpty) { |
- h3(() { |
- write('Requests'); |
- }); |
- dl(() { |
- domain.requests.forEach(visitRequest); |
+ /** |
+ * Describe the payload of request, response, notification, refactoring |
+ * feedback, or refactoring options. |
+ * |
+ * If [force] is true, then a section is inserted even if the payload is |
+ * null. |
+ */ |
+ void describePayload(TypeObject subType, String name, {bool force: false}) { |
+ if (force || subType != null) { |
+ h4(() { |
+ write(name); |
}); |
+ if (subType == null) { |
+ p(() { |
+ write('none'); |
+ }); |
+ } else { |
+ visitTypeDecl(subType); |
+ } |
} |
- if (domain.notifications.isNotEmpty) { |
- h3(() { |
- write('Notifications'); |
- }); |
- dl(() { |
- domain.notifications.forEach(visitNotification); |
- }); |
+ } |
+ |
+ void javadocParams(TypeObject typeObject) { |
+ if (typeObject != null) { |
+ for (TypeObjectField field in typeObject.fields) { |
+ hangingIndent(() { |
+ write('@param ${field.name} '); |
+ translateHtml(field.html, squashParagraphs: true); |
+ }); |
+ } |
} |
} |
- @override |
- void visitNotification(Notification notification) { |
- dt('notification', () { |
- write(notification.longEvent); |
- }); |
- dd(() { |
- box(() { |
- showType('notification', notification.notificationType, notification.params); |
- }); |
- translateHtml(notification.html); |
- describePayload(notification.params, 'Parameters'); |
+ /** |
+ * Generate a description of [type] using [TypeVisitor]. |
+ * |
+ * If [shortDesc] is non-null, the output is prefixed with this string |
+ * and a colon. |
+ * |
+ * If [typeForBolding] is supplied, then fields in this type are shown in |
+ * boldface. |
+ */ |
+ void showType(String shortDesc, TypeDecl type, [TypeObject typeForBolding]) { |
+ Set<String> fieldsToBold = new Set<String>(); |
+ if (typeForBolding != null) { |
+ for (TypeObjectField field in typeForBolding.fields) { |
+ fieldsToBold.add(field.name); |
+ } |
+ } |
+ pre(() { |
+ if (shortDesc != null) { |
+ write('$shortDesc: '); |
+ } |
+ TypeVisitor typeVisitor = |
+ new TypeVisitor(api, fieldsToBold: fieldsToBold); |
+ addAll(typeVisitor.collectHtml(() { |
+ typeVisitor.visitTypeDecl(type); |
+ })); |
}); |
} |
@@ -395,64 +280,75 @@ class ToHtmlVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlGenerator |
} |
} |
- /** |
- * Generate a description of [type] using [TypeVisitor]. |
- * |
- * If [shortDesc] is non-null, the output is prefixed with this string |
- * and a colon. |
- * |
- * If [typeForBolding] is supplied, then fields in this type are shown in |
- * boldface. |
- */ |
- void showType(String shortDesc, TypeDecl type, [TypeObject typeForBolding]) { |
- Set<String> fieldsToBold = new Set<String>(); |
- if (typeForBolding != null) { |
- for (TypeObjectField field in typeForBolding.fields) { |
- fieldsToBold.add(field.name); |
- } |
- } |
- pre(() { |
- if (shortDesc != null) { |
- write('$shortDesc: '); |
- } |
- TypeVisitor typeVisitor = new TypeVisitor(api, fieldsToBold: fieldsToBold); |
- addAll(typeVisitor.collectHtml(() { |
- typeVisitor.visitTypeDecl(type); |
- })); |
+ @override |
+ void visitApi() { |
+ definedTypes = api.types.keys.toSet(); |
+ |
+ html(() { |
+ translateHtml(api.html); |
}); |
} |
- /** |
- * Describe the payload of request, response, notification, refactoring |
- * feedback, or refactoring options. |
- * |
- * If [force] is true, then a section is inserted even if the payload is |
- * null. |
- */ |
- void describePayload(TypeObject subType, String name, {bool force: false}) { |
- if (force || subType != null) { |
- h4(() { |
- write(name); |
+ @override |
+ void visitDomain(Domain domain) { |
+ h2('domain', () { |
+ anchor('domain_${domain.name}', () { |
+ write('Domain: ${domain.name}'); |
+ }); |
+ }); |
+ translateHtml(domain.html); |
+ if (domain.requests.isNotEmpty) { |
+ h3(() { |
+ write('Requests'); |
+ }); |
+ dl(() { |
+ domain.requests.forEach(visitRequest); |
+ }); |
+ } |
+ if (domain.notifications.isNotEmpty) { |
+ h3(() { |
+ write('Notifications'); |
+ }); |
+ dl(() { |
+ domain.notifications.forEach(visitNotification); |
}); |
- if (subType == null) { |
- p(() { |
- write('none'); |
- }); |
- } else { |
- visitTypeDecl(subType); |
- } |
} |
} |
- void javadocParams(TypeObject typeObject) { |
- if (typeObject != null) { |
- for (TypeObjectField field in typeObject.fields) { |
- hangingIndent(() { |
- write('@param ${field.name} '); |
- translateHtml(field.html, squashParagraphs: true); |
- }); |
- } |
- } |
+ @override |
+ void visitNotification(Notification notification) { |
+ dt('notification', () { |
+ write(notification.longEvent); |
+ }); |
+ dd(() { |
+ box(() { |
+ showType( |
+ 'notification', |
+ notification.notificationType, |
+ notification.params); |
+ }); |
+ translateHtml(notification.html); |
+ describePayload(notification.params, 'Parameters'); |
+ }); |
+ } |
+ |
+ @override visitRefactoring(Refactoring refactoring) { |
+ dt('refactoring', () { |
+ write(refactoring.kind); |
+ }); |
+ dd(() { |
+ translateHtml(refactoring.html); |
+ describePayload(refactoring.feedback, 'Feedback', force: true); |
+ describePayload(refactoring.options, 'Options', force: true); |
+ }); |
+ } |
+ |
+ @override |
+ void visitRefactorings(Refactorings refactorings) { |
+ translateHtml(refactorings.html); |
+ dl(() { |
+ super.visitRefactorings(refactorings); |
+ }); |
} |
@override |
@@ -500,7 +396,8 @@ class ToHtmlVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlGenerator |
void visitTypeEnumValue(TypeEnumValue typeEnumValue) { |
bool isDocumented = false; |
for (dom.Node node in typeEnumValue.html.nodes) { |
- if ((node is dom.Element && node.localName != 'code') || (node is dom.Text && node.text.trim().isNotEmpty)) { |
+ if ((node is dom.Element && node.localName != 'code') || |
+ (node is dom.Text && node.text.trim().isNotEmpty)) { |
isDocumented = true; |
break; |
} |
@@ -565,20 +462,130 @@ class ToHtmlVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlGenerator |
@override |
void visitTypeReference(TypeReference typeReference) { |
} |
-} |
-final GeneratedFile target = new GeneratedFile('../../doc/api.html', () { |
- ToHtmlVisitor visitor = new ToHtmlVisitor(readApi()); |
- dom.Document document = new dom.Document(); |
- for (dom.Node node in visitor.collectHtml(visitor.visitApi)) { |
- document.append(node); |
+ @override |
+ void visitTypes(Types types) { |
+ translateHtml(types.html); |
+ dl(() { |
+ super.visitTypes(types); |
+ }); |
} |
- return document.outerHtml; |
-}); |
+} |
/** |
- * Translate spec_input.html into api.html. |
+ * Visitor that generates a compact representation of a type, such as: |
+ * |
+ * { |
+ * "id": String |
+ * "error": optional Error |
+ * "result": { |
+ * "version": String |
+ * } |
+ * } |
*/ |
-main() { |
- target.generate(); |
+class TypeVisitor extends HierarchicalApiVisitor with HtmlMixin, |
+ HtmlCodeGenerator { |
+ /** |
+ * Set of fields which should be shown in boldface, or null if no field |
+ * should be shown in boldface. |
+ */ |
+ final Set<String> fieldsToBold; |
+ |
+ /** |
+ * True if a short description should be generated. In a short description, |
+ * objects are shown as simply "object", and enums are shown as "String". |
+ */ |
+ final bool short; |
+ |
+ TypeVisitor(Api api, {this.fieldsToBold, this.short: false}) : super(api); |
+ |
+ @override |
+ void visitTypeEnum(TypeEnum typeEnum) { |
+ if (short) { |
+ write('String'); |
+ return; |
+ } |
+ writeln('enum {'); |
+ indent(() { |
+ for (TypeEnumValue value in typeEnum.values) { |
+ writeln(value.value); |
+ } |
+ }); |
+ write('}'); |
+ } |
+ |
+ @override |
+ void visitTypeList(TypeList typeList) { |
+ write('List<'); |
+ visitTypeDecl(typeList.itemType); |
+ write('>'); |
+ } |
+ |
+ @override |
+ void visitTypeMap(TypeMap typeMap) { |
+ write('Map<'); |
+ visitTypeDecl(typeMap.keyType); |
+ write(', '); |
+ visitTypeDecl(typeMap.valueType); |
+ write('>'); |
+ } |
+ |
+ @override |
+ void visitTypeObject(TypeObject typeObject) { |
+ if (short) { |
+ write('object'); |
+ return; |
+ } |
+ writeln('{'); |
+ indent(() { |
+ for (TypeObjectField field in typeObject.fields) { |
+ write('"'); |
+ if (fieldsToBold != null && fieldsToBold.contains(field.name)) { |
+ b(() { |
+ write(field.name); |
+ }); |
+ } else { |
+ write(field.name); |
+ } |
+ write('": '); |
+ if (field.value != null) { |
+ write(JSON.encode(field.value)); |
+ } else { |
+ if (field.optional) { |
+ gray(() { |
+ write('optional'); |
+ }); |
+ write(' '); |
+ } |
+ visitTypeDecl(field.type); |
+ } |
+ writeln(); |
+ } |
+ }); |
+ write('}'); |
+ } |
+ |
+ @override |
+ void visitTypeReference(TypeReference typeReference) { |
+ String displayName = typeReference.typeName; |
+ if (api.types.containsKey(typeReference.typeName)) { |
+ link('type_${typeReference.typeName}', () { |
+ write(displayName); |
+ }); |
+ } else { |
+ write(displayName); |
+ } |
+ } |
+ |
+ @override |
+ void visitTypeUnion(TypeUnion typeUnion) { |
+ bool verticalBarNeeded = false; |
+ for (TypeDecl choice in typeUnion.choices) { |
+ if (verticalBarNeeded) { |
+ write(' | '); |
+ } |
+ visitTypeDecl(choice); |
+ verticalBarNeeded = true; |
+ } |
+ } |
} |