| 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 |