Chromium Code Reviews| Index: pkg/docgen/lib/docgen.dart |
| diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart |
| index 6ad260988ed81ff2477cc6d544e4242bf6a8e149..64d3dbb9ddffd3d574b6491ee66b08d02a773a0a 100644 |
| --- a/pkg/docgen/lib/docgen.dart |
| +++ b/pkg/docgen/lib/docgen.dart |
| @@ -53,6 +53,10 @@ markdown.Resolver linkResolver; |
| /// Index of all the qualified names documented. |
| Set<String> qualifiedNameIndex = new Set<String>(); |
| +/// Index of all the items to output. This also ensures that no class is |
| +/// created more than once. |
| +Map<String, Indexable> entityMap = new Map<String, Indexable>(); |
| + |
| /** |
| * Docgen constructor initializes the link resolver for markdown parsing. |
| * Also initializes the command line arguments. |
| @@ -195,21 +199,23 @@ Future<MirrorSystem> _analyzeLibraries(List<String> libraries, |
| /** |
| * Creates documentation for filtered libraries. |
| */ |
| -void _documentLibraries(List<LibraryMirror> libraries, |
| +void _documentLibraries(List<LibraryMirror> libs, |
| {bool includeSdk:false, bool includePrivate:false, bool |
| outputToYaml:true}) { |
| - libraries.forEach((lib) { |
| + libs.forEach((lib) { |
| // Files belonging to the SDK have a uri that begins with 'dart:'. |
| if (includeSdk || !lib.uri.toString().startsWith('dart:')) { |
| var library = generateLibrary(lib, includePrivate: includePrivate); |
| - _writeLibraryToFile(library, outputToYaml); |
| + entityMap[library.qualifiedName] = library; |
| } |
| }); |
| - // Outputs a text file with a list of files available after creating all |
| - // the libraries. This will help the viewer know what files are available |
| + // Output libraries and classes to file after all information is generated. |
| + entityMap.values.forEach((e) => _writeIndexableToFile(e, outputToYaml)); |
| + // Outputs a text file with a list of libraries available after creating all |
| + // the libraries. This will help the viewer know what libraries are available |
| // to read in. |
| - _writeToFile(listDir('docs').join('\n').replaceAll('docs/', ''), |
| - 'library_list.txt'); |
| + _writeToFile(entityMap.values.where((e) => e is Library) |
| + .map((e) => e.qualifiedName).join('\n'), 'library_list.txt'); |
| // Outputs all the qualified names documented. This will help generate search |
| // results. |
| _writeToFile(qualifiedNameIndex.join('\n'), 'index.txt'); |
| @@ -218,27 +224,26 @@ void _documentLibraries(List<LibraryMirror> libraries, |
| Library generateLibrary(dart2js.Dart2JsLibraryMirror library, |
| {bool includePrivate:false}) { |
| _currentLibrary = library; |
| - var result = new Library(library.qualifiedName, _getComment(library), |
| - _getVariables(library.variables, includePrivate), |
| - _getMethods(library.functions, includePrivate), |
| - _getClasses(library.classes, includePrivate)); |
| + var result = new Library(library.qualifiedName, _commentToHtml(library), |
| + _variables(library.variables, includePrivate), |
| + _methods(library.functions, includePrivate), |
| + _classes(library.classes, includePrivate)); |
| logger.fine('Generated library for ${result.name}'); |
| return result; |
| } |
| -void _writeLibraryToFile(Library result, bool outputToYaml) { |
| +void _writeIndexableToFile(Indexable result, bool outputToYaml) { |
| if (outputToYaml) { |
| - _writeToFile(getYamlString(result.toMap()), '${result.name}.yaml'); |
| + _writeToFile(getYamlString(result.toMap()), '${result.qualifiedName}.yaml'); |
| } else { |
| - _writeToFile(stringify(result.toMap()), '${result.name}.json'); |
| + _writeToFile(stringify(result.toMap()), '${result.qualifiedName}.json'); |
| } |
| - |
| } |
| /** |
| * Returns a list of meta annotations assocated with a mirror. |
| */ |
| -List<String> _getAnnotations(DeclarationMirror mirror) { |
| +List<String> _annotations(DeclarationMirror mirror) { |
| var annotations = mirror.metadata.where((e) => |
| e is dart2js.Dart2JsConstructedConstantMirror); |
| return annotations.map((e) => e.type.qualifiedName).toList(); |
| @@ -248,7 +253,7 @@ List<String> _getAnnotations(DeclarationMirror mirror) { |
| * Returns any documentation comments associated with a mirror with |
| * simple markdown converted to html. |
| */ |
| -String _getComment(DeclarationMirror mirror) { |
| +String _commentToHtml(DeclarationMirror mirror) { |
| String commentText; |
| mirror.metadata.forEach((metadata) { |
| if (metadata is CommentInstanceMirror) { |
| @@ -288,7 +293,7 @@ markdown.Node fixReference(String name, LibraryMirror currentLibrary, |
| /** |
| * Returns a map of [Variable] objects constructed from [mirrorMap]. |
| */ |
| -Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap, |
| +Map<String, Variable> _variables(Map<String, VariableMirror> mirrorMap, |
| bool includePrivate) { |
| var data = {}; |
| // TODO(janicejl): When map to map feature is created, replace the below with |
| @@ -298,7 +303,7 @@ Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap, |
| _currentMember = mirror; |
| data[mirrorName] = new Variable(mirrorName, mirror.isFinal, |
| mirror.isStatic, mirror.isConst, _type(mirror.type), |
| - _getComment(mirror), _getAnnotations(mirror), mirror.qualifiedName); |
| + _commentToHtml(mirror), _annotations(mirror), mirror.qualifiedName); |
| } |
| }); |
| return data; |
| @@ -307,104 +312,116 @@ Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap, |
| /** |
| * Returns a map of [Method] objects constructed from [mirrorMap]. |
| */ |
| -Map<String, Map<String, Method>> _getMethods |
| +MethodGroup _methods |
| (Map<String, MethodMirror> mirrorMap, bool includePrivate) { |
| - var setters = {}; |
| - var getters = {}; |
| - var constructors = {}; |
| - var operators = {}; |
| - var methods = {}; |
| + var group = new MethodGroup(); |
| mirrorMap.forEach((String mirrorName, MethodMirror mirror) { |
| if (includePrivate || !mirror.isPrivate) { |
| var method = new Method(mirrorName, mirror.isStatic, mirror.isAbstract, |
| mirror.isConstConstructor, _type(mirror.returnType), |
| - _getComment(mirror), _getParameters(mirror.parameters), |
| - _getAnnotations(mirror), mirror.qualifiedName); |
| + _commentToHtml(mirror), _parameters(mirror.parameters), |
| + _annotations(mirror), mirror.qualifiedName); |
| _currentMember = mirror; |
|
Alan Knight
2013/07/30 22:12:53
This whole method seems more like it should be a
|
| if (mirror.isSetter) { |
| - setters[mirrorName] = method; |
| + group.setters[mirrorName] = method; |
| } else if (mirror.isGetter) { |
| - getters[mirrorName] = method; |
| + group.getters[mirrorName] = method; |
| } else if (mirror.isConstructor) { |
| - constructors[mirrorName] = method; |
| + group.constructors[mirrorName] = method; |
| } else if (mirror.isOperator) { |
| - operators[mirrorName] = method; |
| + group.operators[mirrorName] = method; |
| } else if (mirror.isRegularMethod) { |
| - methods[mirrorName] = method; |
| + group.regularMethods[mirrorName] = method; |
| } else { |
| throw new ArgumentError('$mirrorName - no method type match'); |
| } |
| } |
| }); |
| - return { |
| - 'setters': setters, |
| - 'getters': getters, |
| - 'constructors': constructors, |
| - 'operators': operators, |
| - 'methods': methods |
| - }; |
| + return group; |
| } |
| /** |
| + * Returns the [Class] for the given [mirror] has already been created, and if |
| + * it does not exist, creates it. |
| + */ |
| +Class _findOrCreateClass(ClassMirror mirror, bool includePrivate) { |
|
Alan Knight
2013/07/30 22:12:53
Naming nit. The fact that we're caching these isn'
janicejl
2013/08/01 04:30:26
Done.
|
| + var clazz = entityMap[mirror.qualifiedName]; |
| + if (clazz == null) { |
| + var superclass = (mirror.superclass != null) ? |
| + mirror.superclass.qualifiedName : ''; |
| + var interfaces = |
| + mirror.superinterfaces.map((interface) => interface.qualifiedName); |
| + clazz = new Class(mirror.simpleName, superclass, _commentToHtml(mirror), |
| + interfaces.toList(), |
| + _variables(mirror.variables, includePrivate), |
| + _methods(mirror.methods, includePrivate), |
| + _annotations(mirror), |
| + _generics(mirror), mirror.qualifiedName); |
| + entityMap[mirror.qualifiedName] = clazz; |
| + } |
| + return clazz; |
| +} |
| + |
| +/** |
| * Returns a map of [Class] objects constructed from [mirrorMap]. |
| */ |
| -Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap, |
| +ClassGroup _classes(Map<String, ClassMirror> mirrorMap, |
| bool includePrivate) { |
| - var abstractClasses = {}; |
| - var classes = {}; |
| - var typedefs = {}; |
| - var errors = {}; |
| + var group = new ClassGroup(); |
| mirrorMap.forEach((String mirrorName, ClassMirror mirror) { |
| if (includePrivate || !mirror.isPrivate) { |
| - var superclass = (mirror.superclass != null) ? |
| - mirror.superclass.qualifiedName : ''; |
| - var interfaces = |
| - mirror.superinterfaces.map((interface) => interface.qualifiedName); |
| - var clazz = new Class(mirrorName, superclass, _getComment(mirror), |
| - interfaces.toList(), _getVariables(mirror.variables, includePrivate), |
| - _getMethods(mirror.methods, includePrivate), |
| - _getAnnotations(mirror), _getGenerics(mirror), mirror.qualifiedName); |
| _currentClass = mirror; |
| + var clazz = _findOrCreateClass(mirror, includePrivate); |
| + |
| + // Adding inherited superclass variables and methods. |
| + if (clazz.superclass != '') { |
| + var superclazz = _findOrCreateClass(mirror.superclass, includePrivate); |
| + superclazz.subclasses.add(clazz.qualifiedName); |
| + clazz.inheritedMethods.addInherited(superclazz); |
| + } |
| + |
| + // Adding inherited interface variables and methods. |
| + mirror.superinterfaces.forEach((interface) { |
| + var interfaceClass = _findOrCreateClass(interface, includePrivate); |
| + interfaceClass.subclasses.add(clazz.qualifiedName); |
| + clazz.inheritedVariables.addAll(interfaceClass.variables); |
| + clazz.inheritedMethods.addInherited(interfaceClass); |
| + }); |
| if (isError(mirror.qualifiedName)) { |
| - errors[mirrorName] = clazz; |
| + group.errors[mirrorName] = clazz; |
| } else if (mirror.isTypedef) { |
| - typedefs[mirrorName] = new Typedef(mirrorName, |
| - mirror.value.returnType.qualifiedName, _getComment(mirror), |
| - _getGenerics(mirror), _getParameters(mirror.value.parameters), |
| - _getAnnotations(mirror), mirror.qualifiedName); |
| + group.typedefs[mirrorName] = new Typedef(mirrorName, |
| + mirror.value.returnType.qualifiedName, _commentToHtml(mirror), |
| + _generics(mirror), _parameters(mirror.value.parameters), |
| + _annotations(mirror), mirror.qualifiedName); |
| } else if (mirror.isAbstract) { |
| - abstractClasses[mirrorName] = clazz; |
| + group.abstractClasses[mirrorName] = clazz; |
| } else if (mirror.isClass) { |
| - classes[mirrorName] = clazz; |
| + group.regularClasses[mirrorName] = clazz; |
| } else { |
| throw new ArgumentError('$mirrorName - no class type match. '); |
| } |
| } |
| }); |
| - return { |
| - 'abstract': abstractClasses, |
| - 'class': classes, |
| - 'typedef': typedefs, |
| - 'error': errors |
| - }; |
| + return group; |
| } |
| /** |
| * Returns a map of [Parameter] objects constructed from [mirrorList]. |
| */ |
| -Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) { |
| +Map<String, Parameter> _parameters(List<ParameterMirror> mirrorList) { |
| var data = {}; |
| mirrorList.forEach((ParameterMirror mirror) { |
| _currentMember = mirror; |
| data[mirror.simpleName] = new Parameter(mirror.simpleName, |
| mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue, |
| _type(mirror.type), mirror.defaultValue, |
| - _getAnnotations(mirror)); |
| + _annotations(mirror)); |
| }); |
| return data; |
| } |
| @@ -412,7 +429,7 @@ Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) { |
| /** |
| * Returns a map of [Generic] objects constructed from the class mirror. |
| */ |
| -Map<String, Generic> _getGenerics(ClassMirror mirror) { |
| +Map<String, Generic> _generics(ClassMirror mirror) { |
| return new Map.fromIterable(mirror.typeVariables, |
| key: (e) => e.toString(), |
| value: (e) => new Generic(e.toString(), e.upperBound.qualifiedName)); |
| @@ -501,23 +518,23 @@ class Library extends Indexable { |
| Map<String, Variable> variables; |
| /// Top-level functions in the library. |
| - Map<String, Map<String, Method>> functions; |
| + MethodGroup functions; |
| /// Classes defined within the library |
| - Map<String, Class> classes; |
| + ClassGroup classes; |
| Library(String name, String comment, this.variables, |
| this.functions, this.classes) : super(name, comment, name) {} |
| /// Generates a map describing the [Library] object. |
| Map toMap() => { |
| - 'name': name, |
| - 'qualifiedname': qualifiedName, |
| - 'comment': comment, |
| - 'variables': recurseMap(variables), |
| - 'functions': recurseMap(functions), |
| - 'classes': recurseMap(classes) |
| - }; |
| + 'name': name, |
| + 'qualifiedname': qualifiedName, |
| + 'comment': comment, |
| + 'variables': recurseMap(variables), |
| + 'functions': functions.toMap(), |
| + 'classes': classes.toMap() |
| + }; |
| } |
| /** |
| @@ -527,12 +544,21 @@ class Class extends Indexable { |
| /// List of the names of interfaces that this class implements. |
| List<String> interfaces; |
| + |
| + /// Names of classes that extends or implements this class. |
| + List<String> subclasses = []; |
| /// Top-level variables in the class. |
| Map<String, Variable> variables; |
| + |
| + /// Inherited variables in the class. |
| + Map<String, Variable> inheritedVariables = {}; |
| /// Methods in the class. |
| - Map<String, Map<String, Method>> methods; |
| + MethodGroup methods; |
| + |
| + /// Inherited methods in the class. |
| + MethodGroup inheritedMethods = new MethodGroup(); |
| /// Generic infomation about the class. |
| Map<String, Generic> generics; |
| @@ -548,16 +574,38 @@ class Class extends Indexable { |
| /// Generates a map describing the [Class] object. |
| Map toMap() => { |
| - 'name': name, |
| - 'qualifiedname': qualifiedName, |
| - 'comment': comment, |
| - 'superclass': superclass, |
| - 'implements': new List.from(interfaces), |
| - 'variables': recurseMap(variables), |
| - 'methods': recurseMap(methods), |
| - 'annotations': new List.from(annotations), |
| - 'generics': recurseMap(generics) |
| - }; |
| + 'name': name, |
| + 'qualifiedname': qualifiedName, |
| + 'comment': comment, |
| + 'superclass': superclass, |
| + 'implements': new List.from(interfaces), |
| + 'subclass': new List.from(subclasses), |
| + 'variables': recurseMap(variables), |
| + 'inheritedvariables': recurseMap(inheritedVariables), |
| + 'methods': methods.toMap(), |
| + 'inheritedmethods': inheritedMethods.toMap(), |
| + 'annotations': new List.from(annotations), |
| + 'generics': recurseMap(generics) |
| + }; |
| +} |
| + |
| +/** |
| + * A container to categorize classes into the following groups: abstract |
| + * classes, regular classes, typedefs, and errors. |
| + */ |
| +class ClassGroup { |
| + Map<String, Class> abstractClasses = {}; |
| + Map<String, Class> regularClasses = {}; |
| + Map<String, Typedef> typedefs = {}; |
| + Map<String, Class> errors = {}; |
| + |
| + Map toMap() => { |
| + 'abstract': new List.from(abstractClasses.values |
| + .map((e) => e.qualifiedName)), |
| + 'class': new List.from(regularClasses.values.map((e) => e.qualifiedName)), |
| + 'typedef': recurseMap(typedefs), |
| + 'error': new List.from(errors.values.map((e) => e.qualifiedName)) |
| + }; |
| } |
| class Typedef extends Indexable { |
| @@ -576,14 +624,14 @@ class Typedef extends Indexable { |
| String qualifiedName) : super(name, comment, qualifiedName) {} |
| Map toMap() => { |
| - 'name': name, |
| - 'qualifiedname': qualifiedName, |
| - 'comment': comment, |
| - 'return': returnType, |
| - 'parameters': recurseMap(parameters), |
| - 'annotations': new List.from(annotations), |
| - 'generics': recurseMap(generics) |
| - }; |
| + 'name': name, |
| + 'qualifiedname': qualifiedName, |
| + 'comment': comment, |
| + 'return': returnType, |
| + 'parameters': recurseMap(parameters), |
| + 'annotations': new List.from(annotations), |
| + 'generics': recurseMap(generics) |
| + }; |
| } |
| /** |
| @@ -605,15 +653,15 @@ class Variable extends Indexable { |
| /// Generates a map describing the [Variable] object. |
| Map toMap() => { |
| - 'name': name, |
| - 'qualifiedname': qualifiedName, |
| - 'comment': comment, |
| - 'final': isFinal.toString(), |
| - 'static': isStatic.toString(), |
| - 'constant': isConst.toString(), |
| - 'type': new List.filled(1, type.toMap()), |
| - 'annotations': new List.from(annotations) |
| - }; |
| + 'name': name, |
| + 'qualifiedname': qualifiedName, |
| + 'comment': comment, |
| + 'final': isFinal.toString(), |
| + 'static': isStatic.toString(), |
| + 'constant': isConst.toString(), |
| + 'type': new List.filled(1, type.toMap()), |
| + 'annotations': new List.from(annotations) |
| + }; |
| } |
| /** |
| @@ -639,16 +687,43 @@ class Method extends Indexable { |
| /// Generates a map describing the [Method] object. |
| Map toMap() => { |
| - 'name': name, |
| - 'qualifiedname': qualifiedName, |
| - 'comment': comment, |
| - 'static': isStatic.toString(), |
| - 'abstract': isAbstract.toString(), |
| - 'constant': isConst.toString(), |
| - 'return': new List.filled(1, returnType.toMap()), |
| - 'parameters': recurseMap(parameters), |
| - 'annotations': new List.from(annotations) |
| - }; |
| + 'name': name, |
| + 'qualifiedname': qualifiedName, |
| + 'comment': comment, |
| + 'static': isStatic.toString(), |
| + 'abstract': isAbstract.toString(), |
| + 'constant': isConst.toString(), |
| + 'return': new List.filled(1, returnType.toMap()), |
| + 'parameters': recurseMap(parameters), |
| + 'annotations': new List.from(annotations) |
| + }; |
| +} |
| + |
| +/** |
| + * A container to categorize methods into the following groups: setters, |
| + * getters, constructors, operators, regular methods. |
| + */ |
| +class MethodGroup { |
| + Map<String, Method> setters = {}; |
| + Map<String, Method> getters = {}; |
| + Map<String, Method> constructors = {}; |
| + Map<String, Method> operators = {}; |
| + Map<String, Method> regularMethods = {}; |
| + |
| + void addInherited(Class implemented) { |
| + setters.addAll(implemented.methods.setters); |
| + getters.addAll(implemented.methods.getters); |
| + operators.addAll(implemented.methods.operators); |
| + regularMethods.addAll(implemented.methods.regularMethods); |
| + } |
| + |
| + Map toMap() => { |
| + 'setters': recurseMap(setters), |
| + 'getters': recurseMap(getters), |
| + 'constructors': recurseMap(constructors), |
| + 'operators': recurseMap(operators), |
| + 'methods': recurseMap(regularMethods) |
| + }; |
| } |
| /** |
| @@ -671,14 +746,14 @@ class Parameter { |
| /// Generates a map describing the [Parameter] object. |
| Map toMap() => { |
| - 'name': name, |
| - 'optional': isOptional.toString(), |
| - 'named': isNamed.toString(), |
| - 'default': hasDefaultValue.toString(), |
| - 'type': new List.filled(1, type.toMap()), |
| - 'value': defaultValue, |
| - 'annotations': new List.from(annotations) |
| - }; |
| + 'name': name, |
| + 'optional': isOptional.toString(), |
| + 'named': isNamed.toString(), |
| + 'default': hasDefaultValue.toString(), |
| + 'type': new List.filled(1, type.toMap()), |
| + 'value': defaultValue, |
| + 'annotations': new List.from(annotations) |
| + }; |
| } |
| /** |
| @@ -691,9 +766,9 @@ class Generic { |
| Generic(this.name, this.type); |
| Map toMap() => { |
| - 'name': name, |
| - 'type': type |
| - }; |
| + 'name': name, |
| + 'type': type |
| + }; |
| } |
| /** |
| @@ -733,7 +808,7 @@ class Type { |
| Type(this.outer, this.inner); |
| Map toMap() => { |
| - 'outer': outer, |
| - 'inner': new List.from(inner.map((e) => e.toMap())) |
| - }; |
| + 'outer': outer, |
| + 'inner': new List.from(inner.map((e) => e.toMap())) |
| + }; |
| } |