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; |
11 | 11 |
12 import 'dart:convert'; | 12 import 'dart:convert'; |
13 | 13 |
| 14 import 'package:analyzer/src/codegen/html.dart'; |
| 15 import 'package:analyzer/src/codegen/tools.dart'; |
14 import 'package:html/dom.dart' as dom; | 16 import 'package:html/dom.dart' as dom; |
15 | 17 |
16 import 'api.dart'; | 18 import 'api.dart'; |
17 import 'codegen_tools.dart'; | |
18 import 'from_html.dart'; | 19 import 'from_html.dart'; |
19 import 'html_tools.dart'; | |
20 | 20 |
21 /** | 21 /** |
22 * Embedded stylesheet | 22 * Embedded stylesheet |
23 */ | 23 */ |
24 final String stylesheet = ''' | 24 final String stylesheet = ''' |
25 body { | 25 body { |
26 font-family: sans-serif, serif; | 26 font-family: sans-serif, serif; |
27 padding-left: 5%; | 27 padding-left: 5%; |
28 padding-right: 5%; | 28 padding-right: 5%; |
29 } | 29 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 margin-left: 0px; | 74 margin-left: 0px; |
75 | 75 |
76 -webkit-margin-before: 0px; | 76 -webkit-margin-before: 0px; |
77 -webkit-margin-start: 0px; | 77 -webkit-margin-start: 0px; |
78 -webkit-padding-start: 0px; | 78 -webkit-padding-start: 0px; |
79 | 79 |
80 list-style-type: none; | 80 list-style-type: none; |
81 } | 81 } |
82 '''.trim(); | 82 '''.trim(); |
83 | 83 |
84 final GeneratedFile target = new GeneratedFile('../../doc/api.html', () { | 84 final GeneratedFile target = |
85 ToHtmlVisitor visitor = new ToHtmlVisitor(readApi()); | 85 new GeneratedFile('doc/api.html', (String pkgPath) { |
| 86 ToHtmlVisitor visitor = new ToHtmlVisitor(readApi(pkgPath)); |
86 dom.Document document = new dom.Document(); | 87 dom.Document document = new dom.Document(); |
87 document.append(new dom.DocumentType('html', null, null)); | 88 document.append(new dom.DocumentType('html', null, null)); |
88 for (dom.Node node in visitor.collectHtml(visitor.visitApi)) { | 89 for (dom.Node node in visitor.collectHtml(visitor.visitApi)) { |
89 document.append(node); | 90 document.append(node); |
90 } | 91 } |
91 return document.outerHtml; | 92 return document.outerHtml; |
92 }); | 93 }); |
93 | 94 |
94 /** | 95 /** |
95 * Translate spec_input.html into api.html. | |
96 */ | |
97 main() { | |
98 target.generate(); | |
99 } | |
100 | |
101 /** | |
102 * Visitor that records the mapping from HTML elements to various kinds of API | 96 * Visitor that records the mapping from HTML elements to various kinds of API |
103 * nodes. | 97 * nodes. |
104 */ | 98 */ |
105 class ApiMappings extends HierarchicalApiVisitor { | 99 class ApiMappings extends HierarchicalApiVisitor { |
106 Map<dom.Element, Domain> domains = <dom.Element, Domain>{}; | 100 Map<dom.Element, Domain> domains = <dom.Element, Domain>{}; |
107 | 101 |
108 ApiMappings(Api api) : super(api); | 102 ApiMappings(Api api) : super(api); |
109 | 103 |
110 @override | 104 @override |
111 void visitDomain(Domain domain) { | 105 void visitDomain(Domain domain) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 if (subType == null) { | 191 if (subType == null) { |
198 p(() { | 192 p(() { |
199 write('none'); | 193 write('none'); |
200 }); | 194 }); |
201 } else { | 195 } else { |
202 visitTypeDecl(subType); | 196 visitTypeDecl(subType); |
203 } | 197 } |
204 } | 198 } |
205 } | 199 } |
206 | 200 |
| 201 void generateDomainIndex(Domain domain) { |
| 202 h4(() { |
| 203 write(domain.name); |
| 204 write(' ('); |
| 205 link('domain_${domain.name}', () => write('\u2191')); |
| 206 write(')'); |
| 207 }); |
| 208 if (domain.requests.length > 0) { |
| 209 element('div', {'class': 'subindex'}, () { |
| 210 generateRequestsIndex(domain.requests); |
| 211 if (domain.notifications.length > 0) { |
| 212 generateNotificationsIndex(domain.notifications); |
| 213 } |
| 214 }); |
| 215 } else if (domain.notifications.length > 0) { |
| 216 element('div', {'class': 'subindex'}, () { |
| 217 generateNotificationsIndex(domain.notifications); |
| 218 }); |
| 219 } |
| 220 } |
| 221 |
| 222 void generateIndex() { |
| 223 h3(() => write('Domains')); |
| 224 for (var domain in api.domains) { |
| 225 if (domain.requests.length == 0 && domain.notifications == 0) continue; |
| 226 generateDomainIndex(domain); |
| 227 } |
| 228 |
| 229 generateTypesIndex(definedTypes); |
| 230 generateRefactoringsIndex(api.refactorings); |
| 231 } |
| 232 |
| 233 void generateNotificationsIndex(Iterable<Notification> notifications) { |
| 234 h5(() => write("Notifications")); |
| 235 element('div', {'class': 'subindex'}, () { |
| 236 element('ul', {}, () { |
| 237 for (var notification in notifications) { |
| 238 element( |
| 239 'li', |
| 240 {}, |
| 241 () => link('notification_${notification.longEvent}', |
| 242 () => write(notification.event))); |
| 243 } |
| 244 }); |
| 245 }); |
| 246 } |
| 247 |
| 248 void generateRefactoringsIndex(Iterable<Refactoring> refactorings) { |
| 249 h3(() { |
| 250 write("Refactorings"); |
| 251 write(' ('); |
| 252 link('refactorings', () => write('\u2191')); |
| 253 write(')'); |
| 254 }); |
| 255 // TODO: Individual refactorings are not yet hyperlinked. |
| 256 element('div', {'class': 'subindex'}, () { |
| 257 element('ul', {}, () { |
| 258 for (var refactoring in refactorings) { |
| 259 element( |
| 260 'li', |
| 261 {}, |
| 262 () => link('refactoring_${refactoring.kind}', |
| 263 () => write(refactoring.kind))); |
| 264 } |
| 265 }); |
| 266 }); |
| 267 } |
| 268 |
| 269 void generateRequestsIndex(Iterable<Request> requests) { |
| 270 h5(() => write("Requests")); |
| 271 element('ul', {}, () { |
| 272 for (var request in requests) { |
| 273 element( |
| 274 'li', |
| 275 {}, |
| 276 () => link( |
| 277 'request_${request.longMethod}', () => write(request.method))); |
| 278 } |
| 279 }); |
| 280 } |
| 281 |
| 282 void generateTypesIndex(Set<String> types) { |
| 283 h3(() { |
| 284 write("Types"); |
| 285 write(' ('); |
| 286 link('types', () => write('\u2191')); |
| 287 write(')'); |
| 288 }); |
| 289 element('div', {'class': 'subindex'}, () { |
| 290 element('ul', {}, () { |
| 291 for (var type in types) { |
| 292 element('li', {}, () => link('type_$type', () => write(type))); |
| 293 } |
| 294 }); |
| 295 }); |
| 296 } |
| 297 |
207 void javadocParams(TypeObject typeObject) { | 298 void javadocParams(TypeObject typeObject) { |
208 if (typeObject != null) { | 299 if (typeObject != null) { |
209 for (TypeObjectField field in typeObject.fields) { | 300 for (TypeObjectField field in typeObject.fields) { |
210 hangingIndent(() { | 301 hangingIndent(() { |
211 write('@param ${field.name} '); | 302 write('@param ${field.name} '); |
212 translateHtml(field.html, squashParagraphs: true); | 303 translateHtml(field.html, squashParagraphs: true); |
213 }); | 304 }); |
214 } | 305 } |
215 } | 306 } |
216 } | 307 } |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 @override | 577 @override |
487 void visitTypeReference(TypeReference typeReference) {} | 578 void visitTypeReference(TypeReference typeReference) {} |
488 | 579 |
489 @override | 580 @override |
490 void visitTypes(Types types) { | 581 void visitTypes(Types types) { |
491 translateHtml(types.html); | 582 translateHtml(types.html); |
492 dl(() { | 583 dl(() { |
493 super.visitTypes(types); | 584 super.visitTypes(types); |
494 }); | 585 }); |
495 } | 586 } |
496 | |
497 void generateIndex() { | |
498 h3(() => write('Domains')); | |
499 for (var domain in api.domains) { | |
500 if (domain.requests.length == 0 && domain.notifications == 0) continue; | |
501 generateDomainIndex(domain); | |
502 } | |
503 | |
504 generateTypesIndex(definedTypes); | |
505 generateRefactoringsIndex(api.refactorings); | |
506 } | |
507 | |
508 void generateDomainIndex(Domain domain) { | |
509 h4(() { | |
510 write(domain.name); | |
511 write(' ('); | |
512 link('domain_${domain.name}', () => write('\u2191')); | |
513 write(')'); | |
514 }); | |
515 if (domain.requests.length > 0) { | |
516 element('div', {'class': 'subindex'}, () { | |
517 generateRequestsIndex(domain.requests); | |
518 if (domain.notifications.length > 0) { | |
519 generateNotificationsIndex(domain.notifications); | |
520 } | |
521 }); | |
522 } else if (domain.notifications.length > 0) { | |
523 element('div', {'class': 'subindex'}, () { | |
524 generateNotificationsIndex(domain.notifications); | |
525 }); | |
526 } | |
527 } | |
528 | |
529 void generateRequestsIndex(Iterable<Request> requests) { | |
530 h5(() => write("Requests")); | |
531 element('ul', {}, () { | |
532 for (var request in requests) { | |
533 element( | |
534 'li', | |
535 {}, | |
536 () => link( | |
537 'request_${request.longMethod}', () => write(request.method))); | |
538 } | |
539 }); | |
540 } | |
541 | |
542 void generateNotificationsIndex(Iterable<Notification> notifications) { | |
543 h5(() => write("Notifications")); | |
544 element('div', {'class': 'subindex'}, () { | |
545 element('ul', {}, () { | |
546 for (var notification in notifications) { | |
547 element( | |
548 'li', | |
549 {}, | |
550 () => link('notification_${notification.longEvent}', | |
551 () => write(notification.event))); | |
552 } | |
553 }); | |
554 }); | |
555 } | |
556 | |
557 void generateTypesIndex(Set<String> types) { | |
558 h3(() { | |
559 write("Types"); | |
560 write(' ('); | |
561 link('types', () => write('\u2191')); | |
562 write(')'); | |
563 }); | |
564 element('div', {'class': 'subindex'}, () { | |
565 element('ul', {}, () { | |
566 for (var type in types) { | |
567 element('li', {}, () => link('type_$type', () => write(type))); | |
568 } | |
569 }); | |
570 }); | |
571 } | |
572 | |
573 void generateRefactoringsIndex(Iterable<Refactoring> refactorings) { | |
574 h3(() { | |
575 write("Refactorings"); | |
576 write(' ('); | |
577 link('refactorings', () => write('\u2191')); | |
578 write(')'); | |
579 }); | |
580 // TODO: Individual refactorings are not yet hyperlinked. | |
581 element('div', {'class': 'subindex'}, () { | |
582 element('ul', {}, () { | |
583 for (var refactoring in refactorings) { | |
584 element( | |
585 'li', | |
586 {}, | |
587 () => link('refactoring_${refactoring.kind}', | |
588 () => write(refactoring.kind))); | |
589 } | |
590 }); | |
591 }); | |
592 } | |
593 } | 587 } |
594 | 588 |
595 /** | 589 /** |
596 * Visitor that generates a compact representation of a type, such as: | 590 * Visitor that generates a compact representation of a type, such as: |
597 * | 591 * |
598 * { | 592 * { |
599 * "id": String | 593 * "id": String |
600 * "error": optional Error | 594 * "error": optional Error |
601 * "result": { | 595 * "result": { |
602 * "version": String | 596 * "version": String |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
702 bool verticalBarNeeded = false; | 696 bool verticalBarNeeded = false; |
703 for (TypeDecl choice in typeUnion.choices) { | 697 for (TypeDecl choice in typeUnion.choices) { |
704 if (verticalBarNeeded) { | 698 if (verticalBarNeeded) { |
705 write(' | '); | 699 write(' | '); |
706 } | 700 } |
707 visitTypeDecl(choice); | 701 visitTypeDecl(choice); |
708 verticalBarNeeded = true; | 702 verticalBarNeeded = true; |
709 } | 703 } |
710 } | 704 } |
711 } | 705 } |
OLD | NEW |