| Index: utils/dartdoc/dartdoc.dart
|
| diff --git a/utils/dartdoc/dartdoc.dart b/utils/dartdoc/dartdoc.dart
|
| index b62d9ae64839759ece2a365cbf2937ef2cf912c3..b6e02de9ed6780d5c8998afb288565decdea6185 100644
|
| --- a/utils/dartdoc/dartdoc.dart
|
| +++ b/utils/dartdoc/dartdoc.dart
|
| @@ -376,23 +376,30 @@ class Dartdoc {
|
|
|
| if ((types.length == 0) && (exceptions.length == 0)) return;
|
|
|
| - writeType(String icon, Type type) {
|
| - write('<li>');
|
| - if (_currentType == type) {
|
| - write(
|
| - '<div class="icon-$icon"></div><strong>${typeName(type)}</strong>');
|
| - } else {
|
| - write(a(typeUrl(type),
|
| - '<div class="icon-$icon"></div>${typeName(type)}'));
|
| - }
|
| - writeln('</li>');
|
| + writeln('<ul class="icon">');
|
| + types.forEach(docTypeNavigation);
|
| + exceptions.forEach(docTypeNavigation);
|
| + writeln('</ul>');
|
| + }
|
| +
|
| + /** Writes a linked navigation list item for the given type. */
|
| + docTypeNavigation(Type type) {
|
| + var icon = 'interface';
|
| + if (type.name.endsWith('Exception')) {
|
| + icon = 'exception';
|
| + } else if (type.isClass) {
|
| + icon = 'class';
|
| }
|
|
|
| - writeln('<ul>');
|
| - types.forEach((type) => writeType(type.isClass ? 'class' : 'interface',
|
| - type));
|
| - exceptions.forEach((type) => writeType('exception', type));
|
| - writeln('</ul>');
|
| + write('<li>');
|
| + if (_currentType == type) {
|
| + write(
|
| + '<div class="icon-$icon"></div><strong>${typeName(type)}</strong>');
|
| + } else {
|
| + write(a(typeUrl(type),
|
| + '<div class="icon-$icon"></div>${typeName(type)}'));
|
| + }
|
| + writeln('</li>');
|
| }
|
|
|
| docLibrary(Library library) {
|
| @@ -478,9 +485,8 @@ class Dartdoc {
|
| <strong>${typeName(type, showBounds: true)}</strong></h2>
|
| ''');
|
|
|
| - docInheritance(type);
|
| -
|
| docCode(type.span, getTypeComment(type));
|
| + docInheritance(type);
|
| docConstructors(type);
|
| docMembers(type);
|
|
|
| @@ -488,35 +494,121 @@ class Dartdoc {
|
| endFile();
|
| }
|
|
|
| - /** Document the superclass, superinterfaces and default class of [Type]. */
|
| + /**
|
| + * Writes an inline type span for the given type. This is a little box with
|
| + * an icon and the type's name. It's similar to how types appear in the
|
| + * navigation, but is suitable for inline (as opposed to in a `<ul>`) use.
|
| + */
|
| + typeSpan(Type type) {
|
| + var icon = 'interface';
|
| + if (type.name.endsWith('Exception')) {
|
| + icon = 'exception';
|
| + } else if (type.isClass) {
|
| + icon = 'class';
|
| + }
|
| +
|
| + write('<span class="type-box"><span class="icon-$icon"></span>');
|
| + if (_currentType == type) {
|
| + write('<strong>${typeName(type)}</strong>');
|
| + } else {
|
| + write(a(typeUrl(type), typeName(type)));
|
| + }
|
| + write('</span>');
|
| + }
|
| +
|
| + /**
|
| + * Document the other types that touch [Type] in the inheritance hierarchy:
|
| + * subclasses, superclasses, subinterfaces, superinferfaces, and default
|
| + * class.
|
| + */
|
| docInheritance(Type type) {
|
| - final isSubclass = (type.parent != null) && !type.parent.isObject;
|
| + // Don't show the inheritance details for Object. It doesn't have any base
|
| + // class (obviously) and it has too many subclasses to be useful.
|
| + if (type.isObject) return;
|
| +
|
| + // Writes an unordered list of references to types with an optional header.
|
| + listTypes(types, header) {
|
| + if (types == null) return;
|
|
|
| - Type defaultType;
|
| - if (type.definition is TypeDefinition) {
|
| - TypeDefinition definition = type.definition;
|
| - if (definition.defaultType != null) {
|
| - defaultType = definition.defaultType.type;
|
| + // Skip private types.
|
| + final publicTypes = types.filter((type) => !type.name.startsWith('_'));
|
| + if (publicTypes.length == 0) return;
|
| +
|
| + writeln('<h3>$header</h3>');
|
| + writeln('<p>');
|
| + bool first = true;
|
| + for (final type in publicTypes) {
|
| + if (!first) write(', ');
|
| + typeSpan(type);
|
| + first = false;
|
| }
|
| + writeln('</p>');
|
| }
|
|
|
| - if (isSubclass ||
|
| - (type.interfaces != null && type.interfaces.length > 0) ||
|
| - (defaultType != null)) {
|
| - writeln('<p>');
|
| + if (type.isClass) {
|
| + // Show the chain of superclasses.
|
| + if (!type.parent.isObject) {
|
| + final supertypes = [];
|
| + var thisType = type.parent;
|
| + // As a sanity check, only show up to five levels of nesting, otherwise
|
| + // the box starts to get hideous.
|
| + do {
|
| + supertypes.add(thisType);
|
| + thisType = thisType.parent;
|
| + } while (!thisType.isObject);
|
| +
|
| + writeln('<h3>Extends</h3>');
|
| + writeln('<p>');
|
| + for (var i = supertypes.length - 1; i >= 0; i--) {
|
| + typeSpan(supertypes[i]);
|
| + write(' > ');
|
| + }
|
| +
|
| + // Write this class.
|
| + typeSpan(type);
|
| + writeln('</p>');
|
| + }
|
|
|
| - if (isSubclass) {
|
| - write('Extends ${typeReference(type.parent)}. ');
|
| + // Find the immediate declared subclasses (Type.subtypes includes many
|
| + // transitive subtypes).
|
| + final subtypes = [];
|
| + for (final subtype in type.subtypes) {
|
| + if (subtype.parent == type) subtypes.add(subtype);
|
| }
|
| + subtypes.sort((a, b) => a.name.compareTo(b.name));
|
|
|
| - if (type.interfaces != null && type.interfaces.length > 0) {
|
| - var interfaceStr = joinWithCommas(map(type.interfaces, typeReference));
|
| - write('Implements ${interfaceStr}. ');
|
| + listTypes(subtypes, 'Subclasses');
|
| + listTypes(type.interfaces, 'Implements');
|
| + } else {
|
| + // Show the default class.
|
| + if (type.genericType.defaultType != null) {
|
| + listTypes([type.genericType.defaultType], 'Default class');
|
| }
|
|
|
| - if (defaultType != null) {
|
| - write('Has default class ${typeReference(defaultType)}.');
|
| + // List extended interfaces.
|
| + listTypes(type.interfaces, 'Extends');
|
| +
|
| + // List subinterfaces and implementing classes.
|
| + final subinterfaces = [];
|
| + final implementing = [];
|
| +
|
| + for (final subtype in type.subtypes) {
|
| + // We only want explicitly declared subinterfaces, so check that this
|
| + // type is a superinterface.
|
| + for (final supertype in subtype.interfaces) {
|
| + if (supertype == type) {
|
| + if (subtype.isClass) {
|
| + implementing.add(subtype);
|
| + } else {
|
| + subinterfaces.add(subtype);
|
| + }
|
| + break;
|
| + }
|
| + }
|
| }
|
| +
|
| + listTypes(subinterfaces, 'Subinterfaces');
|
| + listTypes(implementing, 'Implemented by');
|
| }
|
| }
|
|
|
| @@ -796,7 +888,7 @@ class Dartdoc {
|
|
|
| // See if it's an instantiation of a generic type.
|
| final typeArgs = type.typeArgsInOrder;
|
| - if (typeArgs != null) {
|
| + if (typeArgs.length > 0) {
|
| write('<');
|
| bool first = true;
|
| for (final arg in typeArgs) {
|
| @@ -837,7 +929,7 @@ class Dartdoc {
|
|
|
| // See if it's an instantiation of a generic type.
|
| final typeArgs = type.typeArgsInOrder;
|
| - if (typeArgs != null) {
|
| + if (typeArgs.length > 0) {
|
| final args = Strings.join(map(typeArgs, (arg) => typeName(arg)), ', ');
|
| return '${type.genericType.name}<$args>';
|
| }
|
|
|