Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(322)

Side by Side Diff: utils/dartdoc/dartdoc.dart

Issue 9271020: Include subtype information in generated docs. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Respond to review. Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « utils/dartdoc/client-live-nav.dart ('k') | utils/dartdoc/static/styles.css » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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('&nbsp;&gt;&nbsp;');
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
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('&lt;'); 892 write('&lt;');
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('&gt;'); 899 write('&gt;');
808 } 900 }
809 } 901 }
(...skipping 20 matching lines...) Expand all
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}&lt;$params&gt;'; 927 return '${type.name}&lt;$params&gt;';
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}&lt;$args&gt;'; 934 return '${type.genericType.name}&lt;$args&gt;';
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
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 }
OLDNEW
« no previous file with comments | « utils/dartdoc/client-live-nav.dart ('k') | utils/dartdoc/static/styles.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698