OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Code for displaying the API as HTML. This is used both for generating a | 6 * Code for displaying the API as HTML. This is used both for generating a |
7 * full description of the API as a web page, and for generating doc comments | 7 * full description of the API as a web page, and for generating doc comments |
8 * in generated code. | 8 * in generated code. |
9 */ | 9 */ |
10 library to.html; | 10 library to.html; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 font-weight: bold; | 56 font-weight: bold; |
57 } | 57 } |
58 dt.request { | 58 dt.request { |
59 font-weight: bold; | 59 font-weight: bold; |
60 } | 60 } |
61 dt.typeDefinition { | 61 dt.typeDefinition { |
62 font-weight: bold; | 62 font-weight: bold; |
63 } | 63 } |
64 '''.trim(); | 64 '''.trim(); |
65 | 65 |
| 66 final GeneratedFile target = new GeneratedFile('../../doc/api.html', () { |
| 67 ToHtmlVisitor visitor = new ToHtmlVisitor(readApi()); |
| 68 dom.Document document = new dom.Document(); |
| 69 for (dom.Node node in visitor.collectHtml(visitor.visitApi)) { |
| 70 document.append(node); |
| 71 } |
| 72 return document.outerHtml; |
| 73 }); |
| 74 |
| 75 /** |
| 76 * Translate spec_input.html into api.html. |
| 77 */ |
| 78 main() { |
| 79 target.generate(); |
| 80 } |
| 81 |
| 82 /** |
| 83 * Visitor that records the mapping from HTML elements to various kinds of API |
| 84 * nodes. |
| 85 */ |
| 86 class ApiMappings extends HierarchicalApiVisitor { |
| 87 Map<dom.Element, Domain> domains = <dom.Element, Domain>{}; |
| 88 |
| 89 ApiMappings(Api api) : super(api); |
| 90 |
| 91 @override |
| 92 void visitDomain(Domain domain) { |
| 93 domains[domain.html] = domain; |
| 94 } |
| 95 } |
| 96 |
66 /** | 97 /** |
67 * Helper methods for creating HTML elements. | 98 * Helper methods for creating HTML elements. |
68 */ | 99 */ |
69 abstract class HtmlMixin { | 100 abstract class HtmlMixin { |
70 void element(String name, Map<dynamic, String> attributes, [void callback()]); | |
71 | |
72 void anchor(String id, void callback()) { | 101 void anchor(String id, void callback()) { |
73 element('a', { | 102 element('a', { |
74 'name': id | 103 'name': id |
75 }, callback); | 104 }, callback); |
76 } | 105 } |
77 void link(String id, void callback()) { | 106 |
78 element('a', { | |
79 'href': '#$id' | |
80 }, callback); | |
81 } | |
82 void b(void callback()) => element('b', {}, callback); | 107 void b(void callback()) => element('b', {}, callback); |
| 108 void body(void callback()) => element('body', {}, callback); |
83 void box(void callback()) { | 109 void box(void callback()) { |
84 element('div', { | 110 element('div', { |
85 'class': 'box' | 111 'class': 'box' |
86 }, callback); | 112 }, callback); |
87 } | 113 } |
88 void br() => element('br', {}); | 114 void br() => element('br', {}); |
89 void body(void callback()) => element('body', {}, callback); | |
90 void dd(void callback()) => element('dd', {}, callback); | 115 void dd(void callback()) => element('dd', {}, callback); |
91 void dl(void callback()) => element('dl', {}, callback); | 116 void dl(void callback()) => element('dl', {}, callback); |
92 void dt(String cls, void callback()) => element('dt', { | 117 void dt(String cls, void callback()) => element('dt', { |
93 'class': cls | 118 'class': cls |
94 }, callback); | 119 }, callback); |
| 120 void element(String name, Map<dynamic, String> attributes, [void callback()]); |
95 void gray(void callback()) => element('span', { | 121 void gray(void callback()) => element('span', { |
96 'style': 'color:#999999' | 122 'style': 'color:#999999' |
97 }, callback); | 123 }, callback); |
98 void h1(void callback()) => element('h1', {}, callback); | 124 void h1(void callback()) => element('h1', {}, callback); |
99 void h2(String cls, void callback()) { | 125 void h2(String cls, void callback()) { |
100 if (cls == null) { | 126 if (cls == null) { |
101 return element('h2', {}, callback); | 127 return element('h2', {}, callback); |
102 } | 128 } |
103 return element('h2', { | 129 return element('h2', { |
104 'class': cls | 130 'class': cls |
105 }, callback); | 131 }, callback); |
106 } | 132 } |
107 void h3(void callback()) => element('h3', {}, callback); | 133 void h3(void callback()) => element('h3', {}, callback); |
108 void h4(void callback()) => element('h4', {}, callback); | 134 void h4(void callback()) => element('h4', {}, callback); |
109 void hangingIndent(void callback()) => element('div', { | 135 void hangingIndent(void callback()) => element('div', { |
110 'class': 'hangingIndent' | 136 'class': 'hangingIndent' |
111 }, callback); | 137 }, callback); |
112 void head(void callback()) => element('head', {}, callback); | 138 void head(void callback()) => element('head', {}, callback); |
113 void html(void callback()) => element('html', {}, callback); | 139 void html(void callback()) => element('html', {}, callback); |
114 void i(void callback()) => element('i', {}, callback); | 140 void i(void callback()) => element('i', {}, callback); |
| 141 void link(String id, void callback()) { |
| 142 element('a', { |
| 143 'href': '#$id' |
| 144 }, callback); |
| 145 } |
115 void p(void callback()) => element('p', {}, callback); | 146 void p(void callback()) => element('p', {}, callback); |
116 void pre(void callback()) => element('pre', {}, callback); | 147 void pre(void callback()) => element('pre', {}, callback); |
117 void title(void callback()) => element('title', {}, callback); | 148 void title(void callback()) => element('title', {}, callback); |
118 void tt(void callback()) => element('tt', {}, callback); | 149 void tt(void callback()) => element('tt', {}, callback); |
119 } | 150 } |
120 | 151 |
121 /** | 152 /** |
122 * Visitor that generates a compact representation of a type, such as: | |
123 * | |
124 * { | |
125 * "id": String | |
126 * "error": optional Error | |
127 * "result": { | |
128 * "version": String | |
129 * } | |
130 * } | |
131 */ | |
132 class TypeVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlCodeGenerat
or { | |
133 /** | |
134 * Set of fields which should be shown in boldface, or null if no field | |
135 * should be shown in boldface. | |
136 */ | |
137 final Set<String> fieldsToBold; | |
138 | |
139 /** | |
140 * True if a short description should be generated. In a short description, | |
141 * objects are shown as simply "object", and enums are shown as "String". | |
142 */ | |
143 final bool short; | |
144 | |
145 TypeVisitor(Api api, {this.fieldsToBold, this.short: false}) : super(api); | |
146 | |
147 @override | |
148 void visitTypeEnum(TypeEnum typeEnum) { | |
149 if (short) { | |
150 write('String'); | |
151 return; | |
152 } | |
153 writeln('enum {'); | |
154 indent(() { | |
155 for (TypeEnumValue value in typeEnum.values) { | |
156 writeln(value.value); | |
157 } | |
158 }); | |
159 write('}'); | |
160 } | |
161 | |
162 @override | |
163 void visitTypeList(TypeList typeList) { | |
164 write('List<'); | |
165 visitTypeDecl(typeList.itemType); | |
166 write('>'); | |
167 } | |
168 | |
169 @override | |
170 void visitTypeMap(TypeMap typeMap) { | |
171 write('Map<'); | |
172 visitTypeDecl(typeMap.keyType); | |
173 write(', '); | |
174 visitTypeDecl(typeMap.valueType); | |
175 write('>'); | |
176 } | |
177 | |
178 @override | |
179 void visitTypeObject(TypeObject typeObject) { | |
180 if (short) { | |
181 write('object'); | |
182 return; | |
183 } | |
184 writeln('{'); | |
185 indent(() { | |
186 for (TypeObjectField field in typeObject.fields) { | |
187 write('"'); | |
188 if (fieldsToBold != null && fieldsToBold.contains(field.name)) { | |
189 b(() { | |
190 write(field.name); | |
191 }); | |
192 } else { | |
193 write(field.name); | |
194 } | |
195 write('": '); | |
196 if (field.value != null) { | |
197 write(JSON.encode(field.value)); | |
198 } else { | |
199 if (field.optional) { | |
200 gray(() { | |
201 write('optional'); | |
202 }); | |
203 write(' '); | |
204 } | |
205 visitTypeDecl(field.type); | |
206 } | |
207 writeln(); | |
208 } | |
209 }); | |
210 write('}'); | |
211 } | |
212 | |
213 @override | |
214 void visitTypeReference(TypeReference typeReference) { | |
215 String displayName = typeReference.typeName; | |
216 if (api.types.containsKey(typeReference.typeName)) { | |
217 link('type_${typeReference.typeName}', () { | |
218 write(displayName); | |
219 }); | |
220 } else { | |
221 write(displayName); | |
222 } | |
223 } | |
224 | |
225 @override | |
226 void visitTypeUnion(TypeUnion typeUnion) { | |
227 bool verticalBarNeeded = false; | |
228 for (TypeDecl choice in typeUnion.choices) { | |
229 if (verticalBarNeeded) { | |
230 write(' | '); | |
231 } | |
232 visitTypeDecl(choice); | |
233 verticalBarNeeded = true; | |
234 } | |
235 } | |
236 } | |
237 | |
238 /** | |
239 * Visitor that records the mapping from HTML elements to various kinds of API | |
240 * nodes. | |
241 */ | |
242 class ApiMappings extends HierarchicalApiVisitor { | |
243 ApiMappings(Api api) : super(api); | |
244 | |
245 Map<dom.Element, Domain> domains = <dom.Element, Domain>{}; | |
246 | |
247 @override | |
248 void visitDomain(Domain domain) { | |
249 domains[domain.html] = domain; | |
250 } | |
251 } | |
252 | |
253 /** | |
254 * Visitor that generates HTML documentation of the API. | 153 * Visitor that generates HTML documentation of the API. |
255 */ | 154 */ |
256 class ToHtmlVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlGenerator
{ | 155 class ToHtmlVisitor extends HierarchicalApiVisitor with HtmlMixin, HtmlGenerator |
| 156 { |
257 /** | 157 /** |
258 * Set of types defined in the API. | 158 * Set of types defined in the API. |
259 */ | 159 */ |
260 Set<String> definedTypes = new Set<String>(); | 160 Set<String> definedTypes = new Set<String>(); |
261 | 161 |
262 /** | 162 /** |
263 * Mappings from HTML elements to API nodes. | 163 * Mappings from HTML elements to API nodes. |
264 */ | 164 */ |
265 ApiMappings apiMappings; | 165 ApiMappings apiMappings; |
266 | 166 |
267 ToHtmlVisitor(Api api) | 167 ToHtmlVisitor(Api api) |
268 : super(api), | 168 : super(api), |
269 apiMappings = new ApiMappings(api) { | 169 apiMappings = new ApiMappings(api) { |
270 apiMappings.visitApi(); | 170 apiMappings.visitApi(); |
271 } | 171 } |
272 | 172 |
273 @override | 173 /** |
274 void visitApi() { | 174 * Describe the payload of request, response, notification, refactoring |
275 definedTypes = api.types.keys.toSet(); | 175 * feedback, or refactoring options. |
| 176 * |
| 177 * If [force] is true, then a section is inserted even if the payload is |
| 178 * null. |
| 179 */ |
| 180 void describePayload(TypeObject subType, String name, {bool force: false}) { |
| 181 if (force || subType != null) { |
| 182 h4(() { |
| 183 write(name); |
| 184 }); |
| 185 if (subType == null) { |
| 186 p(() { |
| 187 write('none'); |
| 188 }); |
| 189 } else { |
| 190 visitTypeDecl(subType); |
| 191 } |
| 192 } |
| 193 } |
276 | 194 |
277 html(() { | 195 void javadocParams(TypeObject typeObject) { |
278 translateHtml(api.html); | 196 if (typeObject != null) { |
| 197 for (TypeObjectField field in typeObject.fields) { |
| 198 hangingIndent(() { |
| 199 write('@param ${field.name} '); |
| 200 translateHtml(field.html, squashParagraphs: true); |
| 201 }); |
| 202 } |
| 203 } |
| 204 } |
| 205 |
| 206 /** |
| 207 * Generate a description of [type] using [TypeVisitor]. |
| 208 * |
| 209 * If [shortDesc] is non-null, the output is prefixed with this string |
| 210 * and a colon. |
| 211 * |
| 212 * If [typeForBolding] is supplied, then fields in this type are shown in |
| 213 * boldface. |
| 214 */ |
| 215 void showType(String shortDesc, TypeDecl type, [TypeObject typeForBolding]) { |
| 216 Set<String> fieldsToBold = new Set<String>(); |
| 217 if (typeForBolding != null) { |
| 218 for (TypeObjectField field in typeForBolding.fields) { |
| 219 fieldsToBold.add(field.name); |
| 220 } |
| 221 } |
| 222 pre(() { |
| 223 if (shortDesc != null) { |
| 224 write('$shortDesc: '); |
| 225 } |
| 226 TypeVisitor typeVisitor = |
| 227 new TypeVisitor(api, fieldsToBold: fieldsToBold); |
| 228 addAll(typeVisitor.collectHtml(() { |
| 229 typeVisitor.visitTypeDecl(type); |
| 230 })); |
279 }); | 231 }); |
280 } | 232 } |
281 | 233 |
282 @override | |
283 void visitRefactorings(Refactorings refactorings) { | |
284 translateHtml(refactorings.html); | |
285 dl(() { | |
286 super.visitRefactorings(refactorings); | |
287 }); | |
288 } | |
289 | |
290 @override visitRefactoring(Refactoring refactoring) { | |
291 dt('refactoring', () { | |
292 write(refactoring.kind); | |
293 }); | |
294 dd(() { | |
295 translateHtml(refactoring.html); | |
296 describePayload(refactoring.feedback, 'Feedback', force: true); | |
297 describePayload(refactoring.options, 'Options', force: true); | |
298 }); | |
299 } | |
300 | |
301 @override | |
302 void visitTypes(Types types) { | |
303 translateHtml(types.html); | |
304 dl(() { | |
305 super.visitTypes(types); | |
306 }); | |
307 } | |
308 | |
309 @override | |
310 void visitDomain(Domain domain) { | |
311 h2('domain', () { | |
312 anchor('domain_${domain.name}', () { | |
313 write('Domain: ${domain.name}'); | |
314 }); | |
315 }); | |
316 translateHtml(domain.html); | |
317 if (domain.requests.isNotEmpty) { | |
318 h3(() { | |
319 write('Requests'); | |
320 }); | |
321 dl(() { | |
322 domain.requests.forEach(visitRequest); | |
323 }); | |
324 } | |
325 if (domain.notifications.isNotEmpty) { | |
326 h3(() { | |
327 write('Notifications'); | |
328 }); | |
329 dl(() { | |
330 domain.notifications.forEach(visitNotification); | |
331 }); | |
332 } | |
333 } | |
334 | |
335 @override | |
336 void visitNotification(Notification notification) { | |
337 dt('notification', () { | |
338 write(notification.longEvent); | |
339 }); | |
340 dd(() { | |
341 box(() { | |
342 showType('notification', notification.notificationType, notification.par
ams); | |
343 }); | |
344 translateHtml(notification.html); | |
345 describePayload(notification.params, 'Parameters'); | |
346 }); | |
347 } | |
348 | |
349 /** | 234 /** |
350 * Copy the contents of the given HTML element, translating the special | 235 * Copy the contents of the given HTML element, translating the special |
351 * elements that define the API appropriately. | 236 * elements that define the API appropriately. |
352 */ | 237 */ |
353 void translateHtml(dom.Element html, {bool squashParagraphs: false}) { | 238 void translateHtml(dom.Element html, {bool squashParagraphs: false}) { |
354 for (dom.Node node in html.nodes) { | 239 for (dom.Node node in html.nodes) { |
355 if (node is dom.Element) { | 240 if (node is dom.Element) { |
356 if (squashParagraphs && node.localName == 'p') { | 241 if (squashParagraphs && node.localName == 'p') { |
357 translateHtml(node, squashParagraphs: squashParagraphs); | 242 translateHtml(node, squashParagraphs: squashParagraphs); |
358 continue; | 243 continue; |
(...skipping 29 matching lines...) Expand all Loading... |
388 }); | 273 }); |
389 } | 274 } |
390 } | 275 } |
391 } else if (node is dom.Text) { | 276 } else if (node is dom.Text) { |
392 String text = node.text; | 277 String text = node.text; |
393 write(text); | 278 write(text); |
394 } | 279 } |
395 } | 280 } |
396 } | 281 } |
397 | 282 |
398 /** | |
399 * Generate a description of [type] using [TypeVisitor]. | |
400 * | |
401 * If [shortDesc] is non-null, the output is prefixed with this string | |
402 * and a colon. | |
403 * | |
404 * If [typeForBolding] is supplied, then fields in this type are shown in | |
405 * boldface. | |
406 */ | |
407 void showType(String shortDesc, TypeDecl type, [TypeObject typeForBolding]) { | |
408 Set<String> fieldsToBold = new Set<String>(); | |
409 if (typeForBolding != null) { | |
410 for (TypeObjectField field in typeForBolding.fields) { | |
411 fieldsToBold.add(field.name); | |
412 } | |
413 } | |
414 pre(() { | |
415 if (shortDesc != null) { | |
416 write('$shortDesc: '); | |
417 } | |
418 TypeVisitor typeVisitor = new TypeVisitor(api, fieldsToBold: fieldsToBold)
; | |
419 addAll(typeVisitor.collectHtml(() { | |
420 typeVisitor.visitTypeDecl(type); | |
421 })); | |
422 }); | |
423 } | |
424 | |
425 /** | |
426 * Describe the payload of request, response, notification, refactoring | |
427 * feedback, or refactoring options. | |
428 * | |
429 * If [force] is true, then a section is inserted even if the payload is | |
430 * null. | |
431 */ | |
432 void describePayload(TypeObject subType, String name, {bool force: false}) { | |
433 if (force || subType != null) { | |
434 h4(() { | |
435 write(name); | |
436 }); | |
437 if (subType == null) { | |
438 p(() { | |
439 write('none'); | |
440 }); | |
441 } else { | |
442 visitTypeDecl(subType); | |
443 } | |
444 } | |
445 } | |
446 | |
447 void javadocParams(TypeObject typeObject) { | |
448 if (typeObject != null) { | |
449 for (TypeObjectField field in typeObject.fields) { | |
450 hangingIndent(() { | |
451 write('@param ${field.name} '); | |
452 translateHtml(field.html, squashParagraphs: true); | |
453 }); | |
454 } | |
455 } | |
456 } | |
457 | |
458 @override | 283 @override |
| 284 void visitApi() { |
| 285 definedTypes = api.types.keys.toSet(); |
| 286 |
| 287 html(() { |
| 288 translateHtml(api.html); |
| 289 }); |
| 290 } |
| 291 |
| 292 @override |
| 293 void visitDomain(Domain domain) { |
| 294 h2('domain', () { |
| 295 anchor('domain_${domain.name}', () { |
| 296 write('Domain: ${domain.name}'); |
| 297 }); |
| 298 }); |
| 299 translateHtml(domain.html); |
| 300 if (domain.requests.isNotEmpty) { |
| 301 h3(() { |
| 302 write('Requests'); |
| 303 }); |
| 304 dl(() { |
| 305 domain.requests.forEach(visitRequest); |
| 306 }); |
| 307 } |
| 308 if (domain.notifications.isNotEmpty) { |
| 309 h3(() { |
| 310 write('Notifications'); |
| 311 }); |
| 312 dl(() { |
| 313 domain.notifications.forEach(visitNotification); |
| 314 }); |
| 315 } |
| 316 } |
| 317 |
| 318 @override |
| 319 void visitNotification(Notification notification) { |
| 320 dt('notification', () { |
| 321 write(notification.longEvent); |
| 322 }); |
| 323 dd(() { |
| 324 box(() { |
| 325 showType( |
| 326 'notification', |
| 327 notification.notificationType, |
| 328 notification.params); |
| 329 }); |
| 330 translateHtml(notification.html); |
| 331 describePayload(notification.params, 'Parameters'); |
| 332 }); |
| 333 } |
| 334 |
| 335 @override visitRefactoring(Refactoring refactoring) { |
| 336 dt('refactoring', () { |
| 337 write(refactoring.kind); |
| 338 }); |
| 339 dd(() { |
| 340 translateHtml(refactoring.html); |
| 341 describePayload(refactoring.feedback, 'Feedback', force: true); |
| 342 describePayload(refactoring.options, 'Options', force: true); |
| 343 }); |
| 344 } |
| 345 |
| 346 @override |
| 347 void visitRefactorings(Refactorings refactorings) { |
| 348 translateHtml(refactorings.html); |
| 349 dl(() { |
| 350 super.visitRefactorings(refactorings); |
| 351 }); |
| 352 } |
| 353 |
| 354 @override |
459 void visitRequest(Request request) { | 355 void visitRequest(Request request) { |
460 dt('request', () { | 356 dt('request', () { |
461 write(request.longMethod); | 357 write(request.longMethod); |
462 }); | 358 }); |
463 dd(() { | 359 dd(() { |
464 box(() { | 360 box(() { |
465 showType('request', request.requestType, request.params); | 361 showType('request', request.requestType, request.params); |
466 br(); | 362 br(); |
467 showType('response', request.responseType, request.result); | 363 showType('response', request.responseType, request.result); |
468 }); | 364 }); |
(...skipping 24 matching lines...) Expand all Loading... |
493 void visitTypeEnum(TypeEnum typeEnum) { | 389 void visitTypeEnum(TypeEnum typeEnum) { |
494 dl(() { | 390 dl(() { |
495 super.visitTypeEnum(typeEnum); | 391 super.visitTypeEnum(typeEnum); |
496 }); | 392 }); |
497 } | 393 } |
498 | 394 |
499 @override | 395 @override |
500 void visitTypeEnumValue(TypeEnumValue typeEnumValue) { | 396 void visitTypeEnumValue(TypeEnumValue typeEnumValue) { |
501 bool isDocumented = false; | 397 bool isDocumented = false; |
502 for (dom.Node node in typeEnumValue.html.nodes) { | 398 for (dom.Node node in typeEnumValue.html.nodes) { |
503 if ((node is dom.Element && node.localName != 'code') || (node is dom.Text
&& node.text.trim().isNotEmpty)) { | 399 if ((node is dom.Element && node.localName != 'code') || |
| 400 (node is dom.Text && node.text.trim().isNotEmpty)) { |
504 isDocumented = true; | 401 isDocumented = true; |
505 break; | 402 break; |
506 } | 403 } |
507 } | 404 } |
508 dt('value', () { | 405 dt('value', () { |
509 write(typeEnumValue.value); | 406 write(typeEnumValue.value); |
510 }); | 407 }); |
511 if (isDocumented) { | 408 if (isDocumented) { |
512 dd(() { | 409 dd(() { |
513 translateHtml(typeEnumValue.html); | 410 translateHtml(typeEnumValue.html); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 }); | 455 }); |
559 }); | 456 }); |
560 dd(() { | 457 dd(() { |
561 translateHtml(typeObjectField.html); | 458 translateHtml(typeObjectField.html); |
562 }); | 459 }); |
563 } | 460 } |
564 | 461 |
565 @override | 462 @override |
566 void visitTypeReference(TypeReference typeReference) { | 463 void visitTypeReference(TypeReference typeReference) { |
567 } | 464 } |
| 465 |
| 466 @override |
| 467 void visitTypes(Types types) { |
| 468 translateHtml(types.html); |
| 469 dl(() { |
| 470 super.visitTypes(types); |
| 471 }); |
| 472 } |
568 } | 473 } |
569 | 474 |
570 final GeneratedFile target = new GeneratedFile('../../doc/api.html', () { | 475 /** |
571 ToHtmlVisitor visitor = new ToHtmlVisitor(readApi()); | 476 * Visitor that generates a compact representation of a type, such as: |
572 dom.Document document = new dom.Document(); | 477 * |
573 for (dom.Node node in visitor.collectHtml(visitor.visitApi)) { | 478 * { |
574 document.append(node); | 479 * "id": String |
| 480 * "error": optional Error |
| 481 * "result": { |
| 482 * "version": String |
| 483 * } |
| 484 * } |
| 485 */ |
| 486 class TypeVisitor extends HierarchicalApiVisitor with HtmlMixin, |
| 487 HtmlCodeGenerator { |
| 488 /** |
| 489 * Set of fields which should be shown in boldface, or null if no field |
| 490 * should be shown in boldface. |
| 491 */ |
| 492 final Set<String> fieldsToBold; |
| 493 |
| 494 /** |
| 495 * True if a short description should be generated. In a short description, |
| 496 * objects are shown as simply "object", and enums are shown as "String". |
| 497 */ |
| 498 final bool short; |
| 499 |
| 500 TypeVisitor(Api api, {this.fieldsToBold, this.short: false}) : super(api); |
| 501 |
| 502 @override |
| 503 void visitTypeEnum(TypeEnum typeEnum) { |
| 504 if (short) { |
| 505 write('String'); |
| 506 return; |
| 507 } |
| 508 writeln('enum {'); |
| 509 indent(() { |
| 510 for (TypeEnumValue value in typeEnum.values) { |
| 511 writeln(value.value); |
| 512 } |
| 513 }); |
| 514 write('}'); |
575 } | 515 } |
576 return document.outerHtml; | |
577 }); | |
578 | 516 |
579 /** | 517 @override |
580 * Translate spec_input.html into api.html. | 518 void visitTypeList(TypeList typeList) { |
581 */ | 519 write('List<'); |
582 main() { | 520 visitTypeDecl(typeList.itemType); |
583 target.generate(); | 521 write('>'); |
| 522 } |
| 523 |
| 524 @override |
| 525 void visitTypeMap(TypeMap typeMap) { |
| 526 write('Map<'); |
| 527 visitTypeDecl(typeMap.keyType); |
| 528 write(', '); |
| 529 visitTypeDecl(typeMap.valueType); |
| 530 write('>'); |
| 531 } |
| 532 |
| 533 @override |
| 534 void visitTypeObject(TypeObject typeObject) { |
| 535 if (short) { |
| 536 write('object'); |
| 537 return; |
| 538 } |
| 539 writeln('{'); |
| 540 indent(() { |
| 541 for (TypeObjectField field in typeObject.fields) { |
| 542 write('"'); |
| 543 if (fieldsToBold != null && fieldsToBold.contains(field.name)) { |
| 544 b(() { |
| 545 write(field.name); |
| 546 }); |
| 547 } else { |
| 548 write(field.name); |
| 549 } |
| 550 write('": '); |
| 551 if (field.value != null) { |
| 552 write(JSON.encode(field.value)); |
| 553 } else { |
| 554 if (field.optional) { |
| 555 gray(() { |
| 556 write('optional'); |
| 557 }); |
| 558 write(' '); |
| 559 } |
| 560 visitTypeDecl(field.type); |
| 561 } |
| 562 writeln(); |
| 563 } |
| 564 }); |
| 565 write('}'); |
| 566 } |
| 567 |
| 568 @override |
| 569 void visitTypeReference(TypeReference typeReference) { |
| 570 String displayName = typeReference.typeName; |
| 571 if (api.types.containsKey(typeReference.typeName)) { |
| 572 link('type_${typeReference.typeName}', () { |
| 573 write(displayName); |
| 574 }); |
| 575 } else { |
| 576 write(displayName); |
| 577 } |
| 578 } |
| 579 |
| 580 @override |
| 581 void visitTypeUnion(TypeUnion typeUnion) { |
| 582 bool verticalBarNeeded = false; |
| 583 for (TypeDecl choice in typeUnion.choices) { |
| 584 if (verticalBarNeeded) { |
| 585 write(' | '); |
| 586 } |
| 587 visitTypeDecl(choice); |
| 588 verticalBarNeeded = true; |
| 589 } |
| 590 } |
584 } | 591 } |
OLD | NEW |