OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 * To use it, from this directory, run: | 6 * To use it, from this directory, run: |
7 * | 7 * |
8 * $ ./dartdoc <path to .dart file> | 8 * $ ./dartdoc <path to .dart file> |
9 * | 9 * |
10 * This will create a "docs" directory with the docs for your libraries. To | 10 * This will create a "docs" directory with the docs for your libraries. To |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 | 369 |
370 if (type.name.endsWith('Exception')) { | 370 if (type.name.endsWith('Exception')) { |
371 exceptions.add(type); | 371 exceptions.add(type); |
372 } else { | 372 } else { |
373 types.add(type); | 373 types.add(type); |
374 } | 374 } |
375 } | 375 } |
376 | 376 |
377 if ((types.length == 0) && (exceptions.length == 0)) return; | 377 if ((types.length == 0) && (exceptions.length == 0)) return; |
378 | 378 |
379 writeType(String icon, Type type) { | 379 writeln('<ul class="icon">'); |
380 write('<li>'); | 380 types.forEach(docTypeNavigation); |
381 if (_currentType == type) { | 381 exceptions.forEach(docTypeNavigation); |
382 write( | |
383 '<div class="icon-$icon"></div><strong>${typeName(type)}</strong>'); | |
384 } else { | |
385 write(a(typeUrl(type), | |
386 '<div class="icon-$icon"></div>${typeName(type)}')); | |
387 } | |
388 writeln('</li>'); | |
389 } | |
390 | |
391 writeln('<ul>'); | |
392 types.forEach((type) => writeType(type.isClass ? 'class' : 'interface', | |
393 type)); | |
394 exceptions.forEach((type) => writeType('exception', type)); | |
395 writeln('</ul>'); | 382 writeln('</ul>'); |
396 } | 383 } |
397 | 384 |
| 385 /** Writes a linked navigation list item for the given type. */ |
| 386 docTypeNavigation(Type type) { |
| 387 var icon = 'interface'; |
| 388 if (type.name.endsWith('Exception')) { |
| 389 icon = 'exception'; |
| 390 } else if (type.isClass) { |
| 391 icon = 'class'; |
| 392 } |
| 393 |
| 394 write('<li>'); |
| 395 if (_currentType == type) { |
| 396 write( |
| 397 '<div class="icon-$icon"></div><strong>${typeName(type)}</strong>'); |
| 398 } else { |
| 399 write(a(typeUrl(type), |
| 400 '<div class="icon-$icon"></div>${typeName(type)}')); |
| 401 } |
| 402 writeln('</li>'); |
| 403 } |
| 404 |
398 docLibrary(Library library) { | 405 docLibrary(Library library) { |
399 _totalLibraries++; | 406 _totalLibraries++; |
400 _currentLibrary = library; | 407 _currentLibrary = library; |
401 _currentType = null; | 408 _currentType = null; |
402 | 409 |
403 startFile(libraryUrl(library)); | 410 startFile(libraryUrl(library)); |
404 writeHeader(library.name, [library.name, libraryUrl(library)]); | 411 writeHeader(library.name, [library.name, libraryUrl(library)]); |
405 writeln('<h2>Library <strong>${library.name}</strong></h2>'); | 412 writeln('<h2>Library <strong>${library.name}</strong></h2>'); |
406 | 413 |
407 // Look for a comment for the entire library. | 414 // Look for a comment for the entire library. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 '${type.isClass ? "Class" : "Interface"} ${typeName(type)}'; | 478 '${type.isClass ? "Class" : "Interface"} ${typeName(type)}'; |
472 writeHeader('Library ${type.library.name} / $typeTitle', | 479 writeHeader('Library ${type.library.name} / $typeTitle', |
473 [type.library.name, libraryUrl(type.library), | 480 [type.library.name, libraryUrl(type.library), |
474 typeName(type), typeUrl(type)]); | 481 typeName(type), typeUrl(type)]); |
475 writeln( | 482 writeln( |
476 ''' | 483 ''' |
477 <h2>${type.isClass ? "Class" : "Interface"} | 484 <h2>${type.isClass ? "Class" : "Interface"} |
478 <strong>${typeName(type, showBounds: true)}</strong></h2> | 485 <strong>${typeName(type, showBounds: true)}</strong></h2> |
479 '''); | 486 '''); |
480 | 487 |
| 488 docCode(type.span, getTypeComment(type)); |
481 docInheritance(type); | 489 docInheritance(type); |
482 | |
483 docCode(type.span, getTypeComment(type)); | |
484 docConstructors(type); | 490 docConstructors(type); |
485 docMembers(type); | 491 docMembers(type); |
486 | 492 |
487 writeFooter(); | 493 writeFooter(); |
488 endFile(); | 494 endFile(); |
489 } | 495 } |
490 | 496 |
491 /** Document the superclass, superinterfaces and default class of [Type]. */ | 497 /** |
492 docInheritance(Type type) { | 498 * Writes an inline type span for the given type. This is a little box with |
493 final isSubclass = (type.parent != null) && !type.parent.isObject; | 499 * an icon and the type's name. It's similar to how types appear in the |
494 | 500 * navigation, but is suitable for inline (as opposed to in a `<ul>`) use. |
495 Type defaultType; | 501 */ |
496 if (type.definition is TypeDefinition) { | 502 typeSpan(Type type) { |
497 TypeDefinition definition = type.definition; | 503 var icon = 'interface'; |
498 if (definition.defaultType != null) { | 504 if (type.name.endsWith('Exception')) { |
499 defaultType = definition.defaultType.type; | 505 icon = 'exception'; |
500 } | 506 } else if (type.isClass) { |
| 507 icon = 'class'; |
501 } | 508 } |
502 | 509 |
503 if (isSubclass || | 510 write('<span class="type-box"><span class="icon-$icon"></span>'); |
504 (type.interfaces != null && type.interfaces.length > 0) || | 511 if (_currentType == type) { |
505 (defaultType != null)) { | 512 write('<strong>${typeName(type)}</strong>'); |
| 513 } else { |
| 514 write(a(typeUrl(type), typeName(type))); |
| 515 } |
| 516 write('</span>'); |
| 517 } |
| 518 |
| 519 /** |
| 520 * Document the other types that touch [Type] in the inheritance hierarchy: |
| 521 * subclasses, superclasses, subinterfaces, superinferfaces, and default |
| 522 * class. |
| 523 */ |
| 524 docInheritance(Type type) { |
| 525 // Don't show the inheritance details for Object. It doesn't have any base |
| 526 // class (obviously) and it has too many subclasses to be useful. |
| 527 if (type.isObject) return; |
| 528 |
| 529 // Writes an unordered list of references to types with an optional header. |
| 530 listTypes(types, header) { |
| 531 if (types == null) return; |
| 532 |
| 533 // Skip private types. |
| 534 final publicTypes = types.filter((type) => !type.name.startsWith('_')); |
| 535 if (publicTypes.length == 0) return; |
| 536 |
| 537 writeln('<h3>$header</h3>'); |
506 writeln('<p>'); | 538 writeln('<p>'); |
| 539 bool first = true; |
| 540 for (final type in publicTypes) { |
| 541 if (!first) write(', '); |
| 542 typeSpan(type); |
| 543 first = false; |
| 544 } |
| 545 writeln('</p>'); |
| 546 } |
507 | 547 |
508 if (isSubclass) { | 548 if (type.isClass) { |
509 write('Extends ${typeReference(type.parent)}. '); | 549 // Show the chain of superclasses. |
| 550 if (!type.parent.isObject) { |
| 551 final supertypes = []; |
| 552 var thisType = type.parent; |
| 553 // As a sanity check, only show up to five levels of nesting, otherwise |
| 554 // the box starts to get hideous. |
| 555 do { |
| 556 supertypes.add(thisType); |
| 557 thisType = thisType.parent; |
| 558 } while (!thisType.isObject); |
| 559 |
| 560 writeln('<h3>Extends</h3>'); |
| 561 writeln('<p>'); |
| 562 for (var i = supertypes.length - 1; i >= 0; i--) { |
| 563 typeSpan(supertypes[i]); |
| 564 write(' > '); |
| 565 } |
| 566 |
| 567 // Write this class. |
| 568 typeSpan(type); |
| 569 writeln('</p>'); |
510 } | 570 } |
511 | 571 |
512 if (type.interfaces != null && type.interfaces.length > 0) { | 572 // Find the immediate declared subclasses (Type.subtypes includes many |
513 var interfaceStr = joinWithCommas(map(type.interfaces, typeReference)); | 573 // transitive subtypes). |
514 write('Implements ${interfaceStr}. '); | 574 final subtypes = []; |
| 575 for (final subtype in type.subtypes) { |
| 576 if (subtype.parent == type) subtypes.add(subtype); |
| 577 } |
| 578 subtypes.sort((a, b) => a.name.compareTo(b.name)); |
| 579 |
| 580 listTypes(subtypes, 'Subclasses'); |
| 581 listTypes(type.interfaces, 'Implements'); |
| 582 } else { |
| 583 // Show the default class. |
| 584 if (type.genericType.defaultType != null) { |
| 585 listTypes([type.genericType.defaultType], 'Default class'); |
515 } | 586 } |
516 | 587 |
517 if (defaultType != null) { | 588 // List extended interfaces. |
518 write('Has default class ${typeReference(defaultType)}.'); | 589 listTypes(type.interfaces, 'Extends'); |
| 590 |
| 591 // List subinterfaces and implementing classes. |
| 592 final subinterfaces = []; |
| 593 final implementing = []; |
| 594 |
| 595 for (final subtype in type.subtypes) { |
| 596 // We only want explicitly declared subinterfaces, so check that this |
| 597 // type is a superinterface. |
| 598 for (final supertype in subtype.interfaces) { |
| 599 if (supertype == type) { |
| 600 if (subtype.isClass) { |
| 601 implementing.add(subtype); |
| 602 } else { |
| 603 subinterfaces.add(subtype); |
| 604 } |
| 605 break; |
| 606 } |
| 607 } |
519 } | 608 } |
| 609 |
| 610 listTypes(subinterfaces, 'Subinterfaces'); |
| 611 listTypes(implementing, 'Implemented by'); |
520 } | 612 } |
521 } | 613 } |
522 | 614 |
523 /** Document the constructors for [Type], if any. */ | 615 /** Document the constructors for [Type], if any. */ |
524 docConstructors(Type type) { | 616 docConstructors(Type type) { |
525 final names = type.constructors.getKeys().filter( | 617 final names = type.constructors.getKeys().filter( |
526 (name) => !name.startsWith('_')); | 618 (name) => !name.startsWith('_')); |
527 | 619 |
528 if (names.length > 0) { | 620 if (names.length > 0) { |
529 writeln('<h3>Constructors</h3>'); | 621 writeln('<h3>Constructors</h3>'); |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
789 // TODO(rnystrom): This relies on a weird corner case of frog. Currently, | 881 // TODO(rnystrom): This relies on a weird corner case of frog. Currently, |
790 // the only time we get into this case is when we have a "raw" generic | 882 // the only time we get into this case is when we have a "raw" generic |
791 // that's been instantiated with Dynamic for all type arguments. It's kind | 883 // that's been instantiated with Dynamic for all type arguments. It's kind |
792 // of strange that frog works that way, but we take advantage of it to | 884 // of strange that frog works that way, but we take advantage of it to |
793 // show raw types without any type arguments. | 885 // show raw types without any type arguments. |
794 return; | 886 return; |
795 } | 887 } |
796 | 888 |
797 // See if it's an instantiation of a generic type. | 889 // See if it's an instantiation of a generic type. |
798 final typeArgs = type.typeArgsInOrder; | 890 final typeArgs = type.typeArgsInOrder; |
799 if (typeArgs != null) { | 891 if (typeArgs.length > 0) { |
800 write('<'); | 892 write('<'); |
801 bool first = true; | 893 bool first = true; |
802 for (final arg in typeArgs) { | 894 for (final arg in typeArgs) { |
803 if (!first) write(', '); | 895 if (!first) write(', '); |
804 first = false; | 896 first = false; |
805 linkToType(enclosingType, arg); | 897 linkToType(enclosingType, arg); |
806 } | 898 } |
807 write('>'); | 899 write('>'); |
808 } | 900 } |
809 } | 901 } |
(...skipping 20 matching lines...) Expand all Loading... |
830 typeParams.add(typeParam.name); | 922 typeParams.add(typeParam.name); |
831 } | 923 } |
832 } | 924 } |
833 | 925 |
834 final params = Strings.join(typeParams, ', '); | 926 final params = Strings.join(typeParams, ', '); |
835 return '${type.name}<$params>'; | 927 return '${type.name}<$params>'; |
836 } | 928 } |
837 | 929 |
838 // See if it's an instantiation of a generic type. | 930 // See if it's an instantiation of a generic type. |
839 final typeArgs = type.typeArgsInOrder; | 931 final typeArgs = type.typeArgsInOrder; |
840 if (typeArgs != null) { | 932 if (typeArgs.length > 0) { |
841 final args = Strings.join(map(typeArgs, (arg) => typeName(arg)), ', '); | 933 final args = Strings.join(map(typeArgs, (arg) => typeName(arg)), ', '); |
842 return '${type.genericType.name}<$args>'; | 934 return '${type.genericType.name}<$args>'; |
843 } | 935 } |
844 | 936 |
845 // Regular type. | 937 // Regular type. |
846 return type.name; | 938 return type.name; |
847 } | 939 } |
848 | 940 |
849 /** | 941 /** |
850 * Remove leading indentation to line up with first line. | 942 * Remove leading indentation to line up with first line. |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
964 | 1056 |
965 return new md.Element.text('code', name); | 1057 return new md.Element.text('code', name); |
966 } | 1058 } |
967 | 1059 |
968 // TODO(rnystrom): Move into SourceSpan? | 1060 // TODO(rnystrom): Move into SourceSpan? |
969 int getSpanColumn(SourceSpan span) { | 1061 int getSpanColumn(SourceSpan span) { |
970 final line = span.file.getLine(span.start); | 1062 final line = span.file.getLine(span.start); |
971 return span.file.getColumn(line, span.start); | 1063 return span.file.getColumn(line, span.start); |
972 } | 1064 } |
973 } | 1065 } |
OLD | NEW |