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

Side by Side Diff: pkg/docgen/lib/docgen.dart

Issue 21096002: added inherited methods and variables (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 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 | « pkg/docgen/example/test.dart ('k') | pkg/docgen/test/single_library_test.dart » ('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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 * **docgen** is a tool for creating machine readable representations of Dart 6 * **docgen** is a tool for creating machine readable representations of Dart
7 * code metadata, including: classes, members, comments and annotations. 7 * code metadata, including: classes, members, comments and annotations.
8 * 8 *
9 * docgen is run on a `.dart` file or a directory containing `.dart` files. 9 * docgen is run on a `.dart` file or a directory containing `.dart` files.
10 * 10 *
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 43
44 /// Current class being documented to be used for comment links. 44 /// Current class being documented to be used for comment links.
45 ClassMirror _currentClass; 45 ClassMirror _currentClass;
46 46
47 /// Current member being documented to be used for comment links. 47 /// Current member being documented to be used for comment links.
48 MemberMirror _currentMember; 48 MemberMirror _currentMember;
49 49
50 /// Resolves reference links in doc comments. 50 /// Resolves reference links in doc comments.
51 markdown.Resolver linkResolver; 51 markdown.Resolver linkResolver;
52 52
53 /// Index of all the qualified names documented. 53 /// Index of all indexable items. This also ensures that no class is
54 Set<String> qualifiedNameIndex = new Set<String>(); 54 /// created more than once.
55 Map<String, Indexable> entityMap = new Map<String, Indexable>();
56
57 /// This is set from the command line arguments flag --include-private
58 bool _includePrivate = false;
55 59
56 /** 60 /**
57 * Docgen constructor initializes the link resolver for markdown parsing. 61 * Docgen constructor initializes the link resolver for markdown parsing.
58 * Also initializes the command line arguments. 62 * Also initializes the command line arguments.
59 * 63 *
60 * [packageRoot] is the packages directory of the directory being analyzed. 64 * [packageRoot] is the packages directory of the directory being analyzed.
61 * If [includeSdk] is `true`, then any SDK libraries explicitly imported will 65 * If [includeSdk] is `true`, then any SDK libraries explicitly imported will
62 * also be documented. 66 * also be documented.
63 * If [parseSdk] is `true`, then all Dart SDK libraries will be documented. 67 * If [parseSdk] is `true`, then all Dart SDK libraries will be documented.
64 * This option is useful when only the SDK libraries are needed. 68 * This option is useful when only the SDK libraries are needed.
65 * 69 *
66 * Returns `true` if docgen sucessfuly completes. 70 * Returns `true` if docgen sucessfuly completes.
67 */ 71 */
68 Future<bool> docgen(List<String> files, {String packageRoot, 72 Future<bool> docgen(List<String> files, {String packageRoot,
69 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, 73 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false,
70 bool parseSdk: false, bool append: false}) { 74 bool parseSdk: false, bool append: false}) {
75 _includePrivate = includePrivate;
Alan Knight 2013/08/01 18:27:19 It's hard to follow this in the web view, but the
71 if (!append) { 76 if (!append) {
72 var dir = new Directory('docs'); 77 var dir = new Directory('docs');
73 if (dir.existsSync()) dir.deleteSync(recursive: true); 78 if (dir.existsSync()) dir.deleteSync(recursive: true);
74 } 79 }
75 80
76 if (packageRoot == null && !parseSdk) { 81 if (packageRoot == null && !parseSdk) {
77 var type = FileSystemEntity.typeSync(files.first); 82 var type = FileSystemEntity.typeSync(files.first);
78 if (type == FileSystemEntityType.DIRECTORY) { 83 if (type == FileSystemEntityType.DIRECTORY) {
79 packageRoot = _findPackageRoot(files.first); 84 packageRoot = _findPackageRoot(files.first);
80 } else if (type == FileSystemEntityType.FILE) { 85 } else if (type == FileSystemEntityType.FILE) {
81 logger.warning('WARNING: No package root defined. If Docgen fails, try ' 86 logger.warning('WARNING: No package root defined. If Docgen fails, try '
82 'again by setting the --package-root option.'); 87 'again by setting the --package-root option.');
83 } 88 }
84 } 89 }
85 logger.info('Package Root: ${packageRoot}'); 90 logger.info('Package Root: ${packageRoot}');
86 91
87 linkResolver = (name) => 92 linkResolver = (name) =>
88 fixReference(name, _currentLibrary, _currentClass, _currentMember); 93 fixReference(name, _currentLibrary, _currentClass, _currentMember);
89 94
90 return getMirrorSystem(files, packageRoot: packageRoot, parseSdk: parseSdk) 95 return getMirrorSystem(files, packageRoot: packageRoot, parseSdk: parseSdk)
91 .then((MirrorSystem mirrorSystem) { 96 .then((MirrorSystem mirrorSystem) {
92 if (mirrorSystem.libraries.isEmpty) { 97 if (mirrorSystem.libraries.isEmpty) {
93 throw new StateError('No library mirrors were created.'); 98 throw new StateError('No library mirrors were created.');
94 } 99 }
95 _documentLibraries(mirrorSystem.libraries.values, 100 _documentLibraries(mirrorSystem.libraries.values,
96 includeSdk: includeSdk, includePrivate: includePrivate, 101 includeSdk: includeSdk, outputToYaml: outputToYaml, append: append);
97 outputToYaml: outputToYaml, append: append);
98 102
99 return true; 103 return true;
100 }); 104 });
101 } 105 }
102 106
103 List<String> _listLibraries(List<String> args) { 107 List<String> _listLibraries(List<String> args) {
104 if (args.length != 1) throw new UnsupportedError(USAGE); 108 if (args.length != 1) throw new UnsupportedError(USAGE);
105 var libraries = new List<String>(); 109 var libraries = new List<String>();
106 var type = FileSystemEntity.typeSync(args[0]); 110 var type = FileSystemEntity.typeSync(args[0]);
107 111
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 // Currently, a string is thrown when it fails to create a mirror 193 // Currently, a string is thrown when it fails to create a mirror
190 // system, and it is not possible to use the stack trace. BUG(#11622) 194 // system, and it is not possible to use the stack trace. BUG(#11622)
191 // To avoid printing the stack trace. 195 // To avoid printing the stack trace.
192 exit(1); 196 exit(1);
193 }); 197 });
194 } 198 }
195 199
196 /** 200 /**
197 * Creates documentation for filtered libraries. 201 * Creates documentation for filtered libraries.
198 */ 202 */
199 void _documentLibraries(List<LibraryMirror> libraries, 203 void _documentLibraries(List<LibraryMirror> libs,
200 {bool includeSdk: false, bool includePrivate: false, 204 {bool includeSdk: false, bool outputToYaml: true, bool append: false}) {
201 bool outputToYaml: true, bool append: false}) { 205 libs.forEach((lib) {
202 libraries.forEach((lib) {
203 // Files belonging to the SDK have a uri that begins with 'dart:'. 206 // Files belonging to the SDK have a uri that begins with 'dart:'.
204 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { 207 if (includeSdk || !lib.uri.toString().startsWith('dart:')) {
205 var library = generateLibrary(lib, includePrivate: includePrivate); 208 var library = generateLibrary(lib);
206 _writeLibraryToFile(library, outputToYaml); 209 entityMap[library.qualifiedName] = library;
207 } 210 }
208 }); 211 });
209 // Outputs a text file with a list of files available after creating all 212 // After everything is created, do a pass through all classes to make sure no
210 // the libraries. This will help the viewer know what files are available 213 // classes created from mixins are included.
Alan Knight 2013/08/01 18:27:19 I assume this means we're skipping intermediate en
janicejl 2013/08/01 20:15:40 Done.
214 entityMap.values.where((e) => e is Class).forEach((c) => c.makeValid());
215 // Everything is a subclass of Object, therefore empty the list to avoid a
216 // giant list of subclasses to be printed out.
217 entityMap['dart.core.Object'].subclasses.clear();
218 // Output libraries and classes to file after all information is generated.
219 entityMap.values.where((e) => (e is Class || e is Library))
220 .where((e) => _includePrivate || !e.isPrivate).forEach((output) {
221 _writeIndexableToFile(output, outputToYaml);
Alan Knight 2013/08/01 18:27:19 Nit. I think you could re-arrange the filtering c
janicejl 2013/08/01 20:15:40 Done.
222 });
223 // Outputs a text file with a list of libraries available after creating all
224 // the libraries. This will help the viewer know what libraries are available
211 // to read in. 225 // to read in.
212 _writeToFile(listDir('docs').join('\n').replaceAll('docs/', ''), 226 _writeToFile(entityMap.values.where((e) => e is Library)
213 'library_list.txt', append: append); 227 .where((e) => (_includePrivate || !e.isPrivate))
228 .map((e) => e.qualifiedName).join('\n'), 'library_list.txt',
229 append: append);
214 // Outputs all the qualified names documented. This will help generate search 230 // Outputs all the qualified names documented. This will help generate search
215 // results. 231 // results.
216 _writeToFile(qualifiedNameIndex.join('\n'), 'index.txt', append: append); 232 _writeToFile(entityMap.values.where((e) => (_includePrivate || !e.isPrivate))
233 .map((e) => e.qualifiedName).join('\n'), 'index.txt', append: append);
217 } 234 }
218 235
219 Library generateLibrary(dart2js.Dart2JsLibraryMirror library, 236 Library generateLibrary(dart2js.Dart2JsLibraryMirror library) {
220 {bool includePrivate: false}) {
221 _currentLibrary = library; 237 _currentLibrary = library;
222 var result = new Library(library.qualifiedName, _getComment(library), 238 var result = new Library(library.qualifiedName, _commentToHtml(library),
223 _getVariables(library.variables, includePrivate), 239 _variables(library.variables),
224 _getMethods(library.functions, includePrivate), 240 _methods(library.functions),
225 _getClasses(library.classes, includePrivate)); 241 _classes(library.classes), _isPrivate(library));
226 logger.fine('Generated library for ${result.name}'); 242 logger.fine('Generated library for ${result.name}');
227 return result; 243 return result;
228 } 244 }
229 245
230 void _writeLibraryToFile(Library result, bool outputToYaml) { 246 void _writeIndexableToFile(Indexable result, bool outputToYaml) {
231 if (outputToYaml) { 247 if (outputToYaml) {
232 _writeToFile(getYamlString(result.toMap()), '${result.name}.yaml'); 248 _writeToFile(getYamlString(result.toMap()), '${result.qualifiedName}.yaml');
233 } else { 249 } else {
234 _writeToFile(stringify(result.toMap()), '${result.name}.json'); 250 _writeToFile(stringify(result.toMap()), '${result.qualifiedName}.json');
235 } 251 }
252 }
236 253
254 /**
255 * Returns true if a library name starts with an underscore, and false
256 * otherwise.
Alan Knight 2013/08/01 18:27:19 How does the "._" case arise? Should probably be d
janicejl 2013/08/01 20:15:40 Done.
257 */
258 // This is because LibraryMirror.isPrivate returns `false` all the time.
259 bool _isLibraryPrivate(LibraryMirror mirror) {
260 if (mirror.simpleName.startsWith('_') || mirror.simpleName.contains('._')) {
261 return true;
262 }
263 return false;
264 }
265
266 /**
267 * A declaration is private if itself is private, or the owner is private.
268 */
269 bool _isPrivate(DeclarationMirror mirror) {
270 if (mirror is LibraryMirror) {
271 return _isLibraryPrivate(mirror);
272 } else if (mirror.owner is LibraryMirror) {
273 return (mirror.isPrivate || _isLibraryPrivate(mirror.owner));
274 } else {
275 return (mirror.isPrivate || _isPrivate(mirror.owner));
276 }
237 } 277 }
238 278
239 /** 279 /**
240 * Returns a list of meta annotations assocated with a mirror. 280 * Returns a list of meta annotations assocated with a mirror.
241 */ 281 */
242 List<String> _getAnnotations(DeclarationMirror mirror) { 282 List<String> _annotations(DeclarationMirror mirror) {
243 var annotations = mirror.metadata.where((e) => 283 var annotations = mirror.metadata.where((e) =>
244 e is dart2js.Dart2JsConstructedConstantMirror); 284 e is dart2js.Dart2JsConstructedConstantMirror);
245 return annotations.map((e) => e.type.qualifiedName).toList(); 285 return annotations.map((e) => e.type.qualifiedName).toList();
246 } 286 }
247 287
248 /** 288 /**
249 * Returns any documentation comments associated with a mirror with 289 * Returns any documentation comments associated with a mirror with
250 * simple markdown converted to html. 290 * simple markdown converted to html.
251 */ 291 */
252 String _getComment(DeclarationMirror mirror) { 292 String _commentToHtml(DeclarationMirror mirror) {
253 String commentText; 293 String commentText;
254 mirror.metadata.forEach((metadata) { 294 mirror.metadata.forEach((metadata) {
255 if (metadata is CommentInstanceMirror) { 295 if (metadata is CommentInstanceMirror) {
256 CommentInstanceMirror comment = metadata; 296 CommentInstanceMirror comment = metadata;
257 if (comment.isDocComment) { 297 if (comment.isDocComment) {
258 if (commentText == null) { 298 if (commentText == null) {
259 commentText = comment.trimmedText; 299 commentText = comment.trimmedText;
260 } else { 300 } else {
261 commentText = '$commentText ${comment.trimmedText}'; 301 commentText = '$commentText ${comment.trimmedText}';
262 } 302 }
(...skipping 19 matching lines...) Expand all
282 var classScope = currentClass == null ? 322 var classScope = currentClass == null ?
283 null : currentClass.lookupInScope(name); 323 null : currentClass.lookupInScope(name);
284 reference = classScope != null ? classScope.qualifiedName : name; 324 reference = classScope != null ? classScope.qualifiedName : name;
285 } 325 }
286 return new markdown.Element.text('a', reference); 326 return new markdown.Element.text('a', reference);
287 } 327 }
288 328
289 /** 329 /**
290 * Returns a map of [Variable] objects constructed from [mirrorMap]. 330 * Returns a map of [Variable] objects constructed from [mirrorMap].
291 */ 331 */
292 Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap, 332 Map<String, Variable> _variables(Map<String, VariableMirror> mirrorMap) {
293 bool includePrivate) {
294 var data = {}; 333 var data = {};
295 // TODO(janicejl): When map to map feature is created, replace the below with 334 // TODO(janicejl): When map to map feature is created, replace the below with
296 // a filter. Issue(#9590). 335 // a filter. Issue(#9590).
297 mirrorMap.forEach((String mirrorName, VariableMirror mirror) { 336 mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
298 if (includePrivate || !mirror.isPrivate) { 337 _currentMember = mirror;
299 _currentMember = mirror; 338 if (_includePrivate || !_isPrivate(mirror)) {
300 data[mirrorName] = new Variable(mirrorName, mirror.isFinal, 339 entityMap[mirror.qualifiedName] = new Variable(mirrorName, mirror.isFinal,
301 mirror.isStatic, mirror.isConst, _type(mirror.type), 340 mirror.isStatic, mirror.isConst, _type(mirror.type),
302 _getComment(mirror), _getAnnotations(mirror), mirror.qualifiedName); 341 _commentToHtml(mirror), _annotations(mirror), mirror.qualifiedName,
342 _isPrivate(mirror), mirror.owner.qualifiedName);
343 data[mirrorName] = entityMap[mirror.qualifiedName];
303 } 344 }
304 }); 345 });
305 return data; 346 return data;
306 } 347 }
307 348
308 /** 349 /**
309 * Returns a map of [Method] objects constructed from [mirrorMap]. 350 * Returns a map of [Method] objects constructed from [mirrorMap].
310 */ 351 */
311 Map<String, Map<String, Method>> _getMethods 352 MethodGroup _methods(Map<String, MethodMirror> mirrorMap) {
312 (Map<String, MethodMirror> mirrorMap, bool includePrivate) { 353 var group = new MethodGroup();
313
314 var setters = {};
315 var getters = {};
316 var constructors = {};
317 var operators = {};
318 var methods = {};
319
320 mirrorMap.forEach((String mirrorName, MethodMirror mirror) { 354 mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
321 if (includePrivate || !mirror.isPrivate) { 355 if (_includePrivate || !_isPrivate(mirror)) {
322 var method = new Method(mirrorName, mirror.isStatic, mirror.isAbstract, 356 group.addMethod(mirror);
323 mirror.isConstConstructor, _type(mirror.returnType),
324 _getComment(mirror), _getParameters(mirror.parameters),
325 _getAnnotations(mirror), mirror.qualifiedName);
326 _currentMember = mirror;
327 if (mirror.isSetter) {
328 setters[mirrorName] = method;
329 } else if (mirror.isGetter) {
330 getters[mirrorName] = method;
331 } else if (mirror.isConstructor) {
332 constructors[mirrorName] = method;
333 } else if (mirror.isOperator) {
334 operators[mirrorName] = method;
335 } else if (mirror.isRegularMethod) {
336 methods[mirrorName] = method;
337 } else {
338 throw new ArgumentError('$mirrorName - no method type match');
339 }
340 } 357 }
341 }); 358 });
342 return { 359 return group;
343 'setters': setters,
344 'getters': getters,
345 'constructors': constructors,
346 'operators': operators,
347 'methods': methods
348 };
349 } 360 }
350 361
351 /** 362 /**
363 * Returns the [Class] for the given [mirror] has already been created, and if
364 * it does not exist, creates it.
365 */
366 Class _class(ClassMirror mirror) {
367 var clazz = entityMap[mirror.qualifiedName];
368 if (clazz == null) {
369 var superclass = mirror.superclass != null ?
370 _class(mirror.superclass) : null;
371 var interfaces =
372 mirror.superinterfaces.map((interface) => _class(interface));
373 clazz = new Class(mirror.simpleName, superclass, _commentToHtml(mirror),
374 interfaces.toList(), _variables(mirror.variables),
375 _methods(mirror.methods), _annotations(mirror), _generics(mirror),
376 mirror.qualifiedName, _isPrivate(mirror), mirror.owner.qualifiedName);
377 entityMap[mirror.qualifiedName] = clazz;
378 }
379 return clazz;
380 }
381
382 /**
352 * Returns a map of [Class] objects constructed from [mirrorMap]. 383 * Returns a map of [Class] objects constructed from [mirrorMap].
353 */ 384 */
354 Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap, 385 ClassGroup _classes(Map<String, ClassMirror> mirrorMap) {
355 bool includePrivate) { 386 var group = new ClassGroup();
356
357 var abstractClasses = {};
358 var classes = {};
359 var typedefs = {};
360 var errors = {};
361
362 mirrorMap.forEach((String mirrorName, ClassMirror mirror) { 387 mirrorMap.forEach((String mirrorName, ClassMirror mirror) {
363 if (includePrivate || !mirror.isPrivate) { 388 group.addClass(mirror);
364 var superclass = (mirror.superclass != null) ?
365 mirror.superclass.qualifiedName : '';
366 var interfaces =
367 mirror.superinterfaces.map((interface) => interface.qualifiedName);
368 var clazz = new Class(mirrorName, superclass, _getComment(mirror),
369 interfaces.toList(), _getVariables(mirror.variables, includePrivate),
370 _getMethods(mirror.methods, includePrivate),
371 _getAnnotations(mirror), _getGenerics(mirror), mirror.qualifiedName);
372 _currentClass = mirror;
373
374 if (isError(mirror.qualifiedName)) {
375 errors[mirrorName] = clazz;
376 } else if (mirror.isTypedef) {
377 typedefs[mirrorName] = new Typedef(mirrorName,
378 mirror.value.returnType.qualifiedName, _getComment(mirror),
379 _getGenerics(mirror), _getParameters(mirror.value.parameters),
380 _getAnnotations(mirror), mirror.qualifiedName);
381 } else if (mirror.isAbstract) {
382 abstractClasses[mirrorName] = clazz;
383 } else if (mirror.isClass) {
384 classes[mirrorName] = clazz;
385 } else {
386 throw new ArgumentError('$mirrorName - no class type match. ');
387 }
388 }
389 }); 389 });
390 return { 390 return group;
391 'abstract': abstractClasses,
392 'class': classes,
393 'typedef': typedefs,
394 'error': errors
395 };
396 } 391 }
397 392
398 /** 393 /**
399 * Returns a map of [Parameter] objects constructed from [mirrorList]. 394 * Returns a map of [Parameter] objects constructed from [mirrorList].
400 */ 395 */
401 Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) { 396 Map<String, Parameter> _parameters(List<ParameterMirror> mirrorList) {
402 var data = {}; 397 var data = {};
403 mirrorList.forEach((ParameterMirror mirror) { 398 mirrorList.forEach((ParameterMirror mirror) {
404 _currentMember = mirror; 399 _currentMember = mirror;
405 data[mirror.simpleName] = new Parameter(mirror.simpleName, 400 data[mirror.simpleName] = new Parameter(mirror.simpleName,
406 mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue, 401 mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue,
407 _type(mirror.type), mirror.defaultValue, 402 _type(mirror.type), mirror.defaultValue,
408 _getAnnotations(mirror)); 403 _annotations(mirror));
409 }); 404 });
410 return data; 405 return data;
411 } 406 }
412 407
413 /** 408 /**
414 * Returns a map of [Generic] objects constructed from the class mirror. 409 * Returns a map of [Generic] objects constructed from the class mirror.
415 */ 410 */
416 Map<String, Generic> _getGenerics(ClassMirror mirror) { 411 Map<String, Generic> _generics(ClassMirror mirror) {
417 return new Map.fromIterable(mirror.typeVariables, 412 return new Map.fromIterable(mirror.typeVariables,
418 key: (e) => e.toString(), 413 key: (e) => e.toString(),
419 value: (e) => new Generic(e.toString(), e.upperBound.qualifiedName)); 414 value: (e) => new Generic(e.toString(), e.upperBound.qualifiedName));
420 } 415 }
421 416
422 /** 417 /**
423 * Returns a single [Type] object constructed from the Method.returnType 418 * Returns a single [Type] object constructed from the Method.returnType
424 * Type mirror. 419 * Type mirror.
425 */ 420 */
426 Type _type(TypeMirror mirror) { 421 Type _type(TypeMirror mirror) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 return qualifiedName.toLowerCase().contains('error') || 470 return qualifiedName.toLowerCase().contains('error') ||
476 qualifiedName.toLowerCase().contains('exception'); 471 qualifiedName.toLowerCase().contains('exception');
477 } 472 }
478 473
479 /** 474 /**
480 * A class representing all programming constructs, like library or class. 475 * A class representing all programming constructs, like library or class.
481 */ 476 */
482 class Indexable { 477 class Indexable {
483 String name; 478 String name;
484 String qualifiedName; 479 String qualifiedName;
480 bool isPrivate;
485 481
486 /// Documentation comment with converted markdown. 482 /// Documentation comment with converted markdown.
487 String comment; 483 String comment;
488 484
489 Indexable(this.name, this.comment, String qualifiedName) { 485 /// Qualified Name of the owner of this Indexable Item.
486 /// For Library, owner will be "";
487 String owner;
488
489 Indexable(this.name, this.comment, String qualifiedName, bool isPrivate,
490 this.owner) {
490 this.qualifiedName = qualifiedName; 491 this.qualifiedName = qualifiedName;
Alan Knight 2013/08/01 18:27:19 Why are these two in the body of the constructor i
janicejl 2013/08/01 20:15:40 Done.
491 qualifiedNameIndex.add(qualifiedName); 492 this.isPrivate = isPrivate;
492 } 493 }
493 } 494 }
494 495
495 /** 496 /**
496 * A class containing contents of a Dart library. 497 * A class containing contents of a Dart library.
497 */ 498 */
498 class Library extends Indexable { 499 class Library extends Indexable {
499 500
500 /// Top-level variables in the library. 501 /// Top-level variables in the library.
501 Map<String, Variable> variables; 502 Map<String, Variable> variables;
502 503
503 /// Top-level functions in the library. 504 /// Top-level functions in the library.
504 Map<String, Map<String, Method>> functions; 505 MethodGroup functions;
505 506
506 /// Classes defined within the library 507 /// Classes defined within the library
507 Map<String, Class> classes; 508 ClassGroup classes;
508 509
509 Library(String name, String comment, this.variables, 510 Library(String name, String comment, this.variables,
510 this.functions, this.classes) : super(name, comment, name) {} 511 this.functions, this.classes, bool isPrivate) : super(name, comment,
512 name, isPrivate, "") {}
511 513
512 /// Generates a map describing the [Library] object. 514 /// Generates a map describing the [Library] object.
513 Map toMap() => { 515 Map toMap() => {
514 'name': name, 516 'name': name,
515 'qualifiedname': qualifiedName, 517 'qualifiedname': qualifiedName,
516 'comment': comment, 518 'comment': comment,
517 'variables': recurseMap(variables), 519 'variables': recurseMap(variables),
518 'functions': recurseMap(functions), 520 'functions': functions.toMap(),
519 'classes': recurseMap(classes) 521 'classes': classes.toMap()
520 }; 522 };
521 } 523 }
522 524
523 /** 525 /**
524 * A class containing contents of a Dart class. 526 * A class containing contents of a Dart class.
525 */ 527 */
526 class Class extends Indexable { 528 class Class extends Indexable {
527 529
528 /// List of the names of interfaces that this class implements. 530 /// List of the names of interfaces that this class implements.
529 List<String> interfaces; 531 List<Class> interfaces = [];
532
533 /// Names of classes that extends or implements this class.
534 Set<String> subclasses = new Set<String>();
530 535
531 /// Top-level variables in the class. 536 /// Top-level variables in the class.
532 Map<String, Variable> variables; 537 Map<String, Variable> variables;
538
539 /// Inherited variables in the class.
540 Map<String, Variable> inheritedVariables = {};
533 541
534 /// Methods in the class. 542 /// Methods in the class.
535 Map<String, Map<String, Method>> methods; 543 MethodGroup methods;
544
545 /// Inherited methods in the class.
546 MethodGroup inheritedMethods = new MethodGroup();
536 547
537 /// Generic infomation about the class. 548 /// Generic infomation about the class.
538 Map<String, Generic> generics; 549 Map<String, Generic> generics;
539 550
540 String superclass; 551 Class superclass;
541 552
542 /// List of the meta annotations on the class. 553 /// List of the meta annotations on the class.
543 List<String> annotations; 554 List<String> annotations;
544 555
545 Class(String name, this.superclass, String comment, this.interfaces, 556 Class(String name, this.superclass, String comment, this.interfaces,
546 this.variables, this.methods, this.annotations, this.generics, 557 this.variables, this.methods, this.annotations, this.generics,
547 String qualifiedName) : super(name, comment, qualifiedName) {} 558 String qualifiedName, bool isPrivate, String owner) : super(name, comment,
559 qualifiedName, isPrivate, owner) {}
548 560
561 /**
562 * Add all inherited variables and classes from the provided superclass.
563 *
564 * If [_includePrivate] is `false`, it only adds the inherited variables and
565 * methods from the superclass.
566 * If [_includePrivate] is `true`, it adds both inherited variables and
567 * methods as well as variables and methods from the superclass.
Alan Knight 2013/08/01 18:27:19 These comments could be clearer.
janicejl 2013/08/01 20:15:40 Done.
568 */
569 void addInherited(Class superclass) {
570 inheritedVariables.addAll(superclass.inheritedVariables);
571 if (_includePrivate || !superclass.isPrivate) {
572 inheritedVariables.addAll(superclass.variables);
573 }
574 inheritedMethods.addInherited(superclass);
575 }
576
577 /**
578 * Add the subclass to the class.
579 *
580 * If this class is private, it will add it to it's superclasses.
Alan Knight 2013/08/01 18:27:19 Too many different "it"s. Refer to the things by n
janicejl 2013/08/01 20:15:40 Done.
581 */
582 void addSubClass(Class subclass) {
Alan Knight 2013/08/01 18:27:19 Be consistent between subClass and subclass. I thi
janicejl 2013/08/01 20:15:40 Done.
583 if (!_includePrivate && isPrivate) {
584 if (superclass != null) superclass.addSubClass(subclass);
585 interfaces.forEach((interface) {
586 interface.addSubClass(subclass);
587 });
588 } else {
589 subclasses.add(subclass.qualifiedName);
590 }
591 }
592
593 /**
594 * Ensures that the class is exists in the owner library.
Alan Knight 2013/08/01 18:27:19 No "is", and probably better to say "Check" than "
janicejl 2013/08/01 20:15:40 Done.
595 *
596 * If it does not exist in the owner library, it is a mixin and should be
597 * removed.
598 */
599 void makeValid() {
600 var library = entityMap[owner];
601 if (!library.classes.containsKey(name)) {
602 this.isPrivate = true;
603 // Since we are now making the mixin a private class, make all elements
604 // with the mixin as an owner private too.
605 entityMap.values.where((e) => e.owner == qualifiedName)
606 .forEach((element) => element.isPrivate = true);
607 // Move the subclass up to the next public superclass
608 subclasses.forEach((subclass) => addSubClass(entityMap[subclass]));
609 }
610 }
611
549 /// Generates a map describing the [Class] object. 612 /// Generates a map describing the [Class] object.
550 Map toMap() => { 613 Map toMap() => {
551 'name': name, 614 'name': name,
552 'qualifiedname': qualifiedName, 615 'qualifiedname': qualifiedName,
553 'comment': comment, 616 'comment': comment,
554 'superclass': superclass, 617 'superclass': superclass == null ? "" :
555 'implements': new List.from(interfaces), 618 (_includePrivate || !superclass.isPrivate) ?
556 'variables': recurseMap(variables), 619 superclass.qualifiedName : "",
557 'methods': recurseMap(methods), 620 'implements': new List.from(interfaces.where((e) =>
558 'annotations': new List.from(annotations), 621 (_includePrivate || !e.isPrivate)).map((e) => e.qualifiedName)),
559 'generics': recurseMap(generics) 622 'subclass': new List.from(subclasses),
560 }; 623 'variables': recurseMap(variables),
624 'inheritedvariables': recurseMap(inheritedVariables),
625 'methods': methods.toMap(),
626 'inheritedmethods': inheritedMethods.toMap(),
627 'annotations': new List.from(annotations),
628 'generics': recurseMap(generics)
629 };
630 }
631
632 /**
633 * A container to categorize classes into the following groups: abstract
634 * classes, regular classes, typedefs, and errors.
635 */
636 class ClassGroup {
637 Map<String, Class> abstractClasses = {};
638 Map<String, Class> regularClasses = {};
639 Map<String, Typedef> typedefs = {};
640 Map<String, Class> errors = {};
641
642 void addClass(ClassMirror mirror) {
643 _currentClass = mirror;
644 var clazz = _class(mirror);
645
646 // Adding inherited superclass variables and methods.
647 if (clazz.superclass != null) {
648 if (_includePrivate || !clazz.isPrivate) {
649 clazz.superclass.addSubClass(clazz);
650 }
651 clazz.addInherited(clazz.superclass);
652 }
653
654 // Adding inherited interface variables and methods.
655 clazz.interfaces.forEach((interface) {
Alan Knight 2013/08/01 18:27:19 The logic for superclasses and interfaces seems to
janicejl 2013/08/01 20:15:40 Done. At this point, it does not differentiate bet
656 if (_includePrivate || !clazz.isPrivate) {
657 interface.addSubClass(clazz);
658 }
659 clazz.addInherited(interface);
660 });
661
662 if (isError(mirror.qualifiedName)) {
663 errors[mirror.simpleName] = clazz;
664 } else if (mirror.isTypedef) {
665 entityMap[mirror.qualifiedName] = new Typedef(mirror.simpleName,
666 mirror.value.returnType.qualifiedName, _commentToHtml(mirror),
667 _generics(mirror), _parameters(mirror.value.parameters),
668 _annotations(mirror), mirror.qualifiedName, _isPrivate(mirror),
669 mirror.owner.qualifiedName);
670 typedefs[mirror.simpleName] = entityMap[mirror.qualifiedName];
671 } else if (mirror.isAbstract) {
672 abstractClasses[mirror.simpleName] = clazz;
673 } else if (mirror.isClass) {
674 regularClasses[mirror.simpleName] = clazz;
675 } else {
676 throw new ArgumentError('${mirror.simpleName} - no class type match. ');
677 }
678 }
679
680 /**
681 * Checks if the given name is a key for any of the Class Maps.
682 */
683 bool containsKey(String name) {
684 return abstractClasses.containsKey(name) ||
685 regularClasses.containsKey(name) ||
686 errors.containsKey(name);
687 }
688
689 Map toMap() => {
690 'abstract': new List.from(abstractClasses.values
691 .where((e) => (_includePrivate || !e.isPrivate))
Alan Knight 2013/08/01 18:27:19 This privacy test occurs a lot, seems like it coul
janicejl 2013/08/01 20:15:40 Done.
692 .map((e) => e.qualifiedName)),
693 'class': new List.from(regularClasses.values
694 .where((e) => (_includePrivate || !e.isPrivate))
695 .map((e) => e.qualifiedName)),
696 'typedef': recurseMap(typedefs),
697 'error': new List.from(errors.values
698 .where((e) => (_includePrivate || !e.isPrivate))
699 .map((e) => e.qualifiedName))
700 };
561 } 701 }
562 702
563 class Typedef extends Indexable { 703 class Typedef extends Indexable {
564 String returnType; 704 String returnType;
565 705
566 Map<String, Parameter> parameters; 706 Map<String, Parameter> parameters;
567 707
568 /// Generic information about the typedef. 708 /// Generic information about the typedef.
569 Map<String, Generic> generics; 709 Map<String, Generic> generics;
570 710
571 /// List of the meta annotations on the typedef. 711 /// List of the meta annotations on the typedef.
572 List<String> annotations; 712 List<String> annotations;
573 713
574 Typedef(String name, this.returnType, String comment, this.generics, 714 Typedef(String name, this.returnType, String comment, this.generics,
575 this.parameters, this.annotations, 715 this.parameters, this.annotations,
576 String qualifiedName) : super(name, comment, qualifiedName) {} 716 String qualifiedName, bool isPrivate, String owner) : super(name, comment,
717 qualifiedName, isPrivate, owner) {}
577 718
578 Map toMap() => { 719 Map toMap() => {
579 'name': name, 720 'name': name,
580 'qualifiedname': qualifiedName, 721 'qualifiedname': qualifiedName,
581 'comment': comment, 722 'comment': comment,
582 'return': returnType, 723 'return': returnType,
583 'parameters': recurseMap(parameters), 724 'parameters': recurseMap(parameters),
584 'annotations': new List.from(annotations), 725 'annotations': new List.from(annotations),
585 'generics': recurseMap(generics) 726 'generics': recurseMap(generics)
586 }; 727 };
587 } 728 }
588 729
589 /** 730 /**
590 * A class containing properties of a Dart variable. 731 * A class containing properties of a Dart variable.
591 */ 732 */
592 class Variable extends Indexable { 733 class Variable extends Indexable {
593 734
594 bool isFinal; 735 bool isFinal;
595 bool isStatic; 736 bool isStatic;
596 bool isConst; 737 bool isConst;
597 Type type; 738 Type type;
598 739
599 /// List of the meta annotations on the variable. 740 /// List of the meta annotations on the variable.
600 List<String> annotations; 741 List<String> annotations;
601 742
602 Variable(String name, this.isFinal, this.isStatic, this.isConst, this.type, 743 Variable(String name, this.isFinal, this.isStatic, this.isConst, this.type,
603 String comment, this.annotations, String qualifiedName) : super(name, 744 String comment, this.annotations, String qualifiedName, bool isPrivate,
604 comment, qualifiedName); 745 String owner) : super(name, comment, qualifiedName, isPrivate, owner);
605 746
606 /// Generates a map describing the [Variable] object. 747 /// Generates a map describing the [Variable] object.
607 Map toMap() => { 748 Map toMap() => {
608 'name': name, 749 'name': name,
609 'qualifiedname': qualifiedName, 750 'qualifiedname': qualifiedName,
610 'comment': comment, 751 'comment': comment,
611 'final': isFinal.toString(), 752 'final': isFinal.toString(),
612 'static': isStatic.toString(), 753 'static': isStatic.toString(),
613 'constant': isConst.toString(), 754 'constant': isConst.toString(),
614 'type': new List.filled(1, type.toMap()), 755 'type': new List.filled(1, type.toMap()),
615 'annotations': new List.from(annotations) 756 'annotations': new List.from(annotations)
616 }; 757 };
617 } 758 }
618 759
619 /** 760 /**
620 * A class containing properties of a Dart method. 761 * A class containing properties of a Dart method.
621 */ 762 */
622 class Method extends Indexable { 763 class Method extends Indexable {
623 764
624 /// Parameters for this method. 765 /// Parameters for this method.
625 Map<String, Parameter> parameters; 766 Map<String, Parameter> parameters;
626 767
627 bool isStatic; 768 bool isStatic;
628 bool isAbstract; 769 bool isAbstract;
629 bool isConst; 770 bool isConst;
630 Type returnType; 771 Type returnType;
631 772
632 /// List of the meta annotations on the method. 773 /// List of the meta annotations on the method.
633 List<String> annotations; 774 List<String> annotations;
634 775
635 Method(String name, this.isStatic, this.isAbstract, this.isConst, 776 Method(String name, this.isStatic, this.isAbstract, this.isConst,
636 this.returnType, String comment, this.parameters, this.annotations, 777 this.returnType, String comment, this.parameters, this.annotations,
637 String qualifiedName) 778 String qualifiedName, bool isPrivate, String owner) : super(name, comment,
638 : super(name, comment, qualifiedName); 779 qualifiedName, isPrivate, owner);
639 780
640 /// Generates a map describing the [Method] object. 781 /// Generates a map describing the [Method] object.
641 Map toMap() => { 782 Map toMap() => {
642 'name': name, 783 'name': name,
643 'qualifiedname': qualifiedName, 784 'qualifiedname': qualifiedName,
644 'comment': comment, 785 'comment': comment,
645 'static': isStatic.toString(), 786 'static': isStatic.toString(),
646 'abstract': isAbstract.toString(), 787 'abstract': isAbstract.toString(),
647 'constant': isConst.toString(), 788 'constant': isConst.toString(),
648 'return': new List.filled(1, returnType.toMap()), 789 'return': new List.filled(1, returnType.toMap()),
649 'parameters': recurseMap(parameters), 790 'parameters': recurseMap(parameters),
650 'annotations': new List.from(annotations) 791 'annotations': new List.from(annotations)
651 }; 792 };
652 } 793 }
653 794
654 /** 795 /**
796 * A container to categorize methods into the following groups: setters,
797 * getters, constructors, operators, regular methods.
798 */
799 class MethodGroup {
800 Map<String, Method> setters = {};
801 Map<String, Method> getters = {};
802 Map<String, Method> constructors = {};
803 Map<String, Method> operators = {};
804 Map<String, Method> regularMethods = {};
805
806 void addMethod(MethodMirror mirror) {
807 var method = new Method(mirror.simpleName, mirror.isStatic,
808 mirror.isAbstract, mirror.isConstConstructor, _type(mirror.returnType),
809 _commentToHtml(mirror), _parameters(mirror.parameters),
810 _annotations(mirror), mirror.qualifiedName, _isPrivate(mirror),
811 mirror.owner.qualifiedName);
812 entityMap[mirror.qualifiedName] = method;
813 _currentMember = mirror;
814 if (mirror.isSetter) {
815 setters[mirror.simpleName] = method;
816 } else if (mirror.isGetter) {
817 getters[mirror.simpleName] = method;
818 } else if (mirror.isConstructor) {
819 constructors[mirror.simpleName] = method;
820 } else if (mirror.isOperator) {
821 operators[mirror.simpleName] = method;
822 } else if (mirror.isRegularMethod) {
823 regularMethods[mirror.simpleName] = method;
824 } else {
825 throw new ArgumentError('${mirror.simpleName} - no method type match');
826 }
827 }
828
829 void addInherited(Class implemented) {
Alan Knight 2013/08/01 18:27:19 Why the name implemented here?
janicejl 2013/08/01 20:15:40 A parent class. I renamed implemented to parent.
830 setters.addAll(implemented.inheritedMethods.setters);
831 getters.addAll(implemented.inheritedMethods.getters);
832 operators.addAll(implemented.inheritedMethods.operators);
833 regularMethods.addAll(implemented.inheritedMethods.regularMethods);
834 if (_includePrivate || !implemented.isPrivate) {
835 setters.addAll(implemented.methods.setters);
836 getters.addAll(implemented.methods.getters);
837 operators.addAll(implemented.methods.operators);
838 regularMethods.addAll(implemented.methods.regularMethods);
839 }
840 }
841
842 Map toMap() => {
843 'setters': recurseMap(setters),
844 'getters': recurseMap(getters),
845 'constructors': recurseMap(constructors),
846 'operators': recurseMap(operators),
847 'methods': recurseMap(regularMethods)
848 };
849 }
850
851 /**
655 * A class containing properties of a Dart method/function parameter. 852 * A class containing properties of a Dart method/function parameter.
656 */ 853 */
657 class Parameter { 854 class Parameter {
658 855
659 String name; 856 String name;
660 bool isOptional; 857 bool isOptional;
661 bool isNamed; 858 bool isNamed;
662 bool hasDefaultValue; 859 bool hasDefaultValue;
663 Type type; 860 Type type;
664 String defaultValue; 861 String defaultValue;
665 862
666 /// List of the meta annotations on the parameter. 863 /// List of the meta annotations on the parameter.
667 List<String> annotations; 864 List<String> annotations;
668 865
669 Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue, 866 Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue,
670 this.type, this.defaultValue, this.annotations); 867 this.type, this.defaultValue, this.annotations);
671 868
672 /// Generates a map describing the [Parameter] object. 869 /// Generates a map describing the [Parameter] object.
673 Map toMap() => { 870 Map toMap() => {
674 'name': name, 871 'name': name,
675 'optional': isOptional.toString(), 872 'optional': isOptional.toString(),
676 'named': isNamed.toString(), 873 'named': isNamed.toString(),
677 'default': hasDefaultValue.toString(), 874 'default': hasDefaultValue.toString(),
678 'type': new List.filled(1, type.toMap()), 875 'type': new List.filled(1, type.toMap()),
679 'value': defaultValue, 876 'value': defaultValue,
680 'annotations': new List.from(annotations) 877 'annotations': new List.from(annotations)
681 }; 878 };
682 } 879 }
683 880
684 /** 881 /**
685 * A class containing properties of a Generic. 882 * A class containing properties of a Generic.
686 */ 883 */
687 class Generic { 884 class Generic {
688 String name; 885 String name;
689 String type; 886 String type;
690 887
691 Generic(this.name, this.type); 888 Generic(this.name, this.type);
692 889
693 Map toMap() => { 890 Map toMap() => {
694 'name': name, 891 'name': name,
695 'type': type 892 'type': type
696 }; 893 };
697 } 894 }
698 895
699 /** 896 /**
700 * Holds the name of a return type, and its generic type parameters. 897 * Holds the name of a return type, and its generic type parameters.
701 * 898 *
702 * Return types are of a form [outer]<[inner]>. 899 * Return types are of a form [outer]<[inner]>.
703 * If there is no [inner] part, [inner] will be an empty list. 900 * If there is no [inner] part, [inner] will be an empty list.
704 * 901 *
705 * For example: 902 * For example:
706 * int size() 903 * int size()
(...skipping 19 matching lines...) Expand all
726 * - "outer" : "dart.core.int" 923 * - "outer" : "dart.core.int"
727 * "inner" : 924 * "inner" :
728 */ 925 */
729 class Type { 926 class Type {
730 String outer; 927 String outer;
731 List<Type> inner; 928 List<Type> inner;
732 929
733 Type(this.outer, this.inner); 930 Type(this.outer, this.inner);
734 931
735 Map toMap() => { 932 Map toMap() => {
736 'outer': outer, 933 'outer': outer,
737 'inner': new List.from(inner.map((e) => e.toMap())) 934 'inner': new List.from(inner.map((e) => e.toMap()))
738 }; 935 };
739 } 936 }
OLDNEW
« no previous file with comments | « pkg/docgen/example/test.dart ('k') | pkg/docgen/test/single_library_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698