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

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

Issue 242363004: pkg/docgen: moved model classes into minilibs (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: cl nits Created 6 years, 8 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
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 library docgen.models; 5 library docgen.models;
6 6
7 import 'dart:io'; 7 export 'models/class.dart';
8 8 export 'models/indexable.dart';
9 import 'package:markdown/markdown.dart' as markdown; 9 export 'models/library.dart';
10 10 export 'models/method.dart';
11 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mir rors.dart'; 11 export 'models/parameter.dart';
12 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_ut il.dart' 12 export 'models/typedef.dart';
13 as dart2js_util; 13 export 'models/variable.dart';
14 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mi rrors.dart'
15 as dart2js_mirrors;
16
17 import 'library_helpers.dart';
18 import 'mdn.dart';
19 import 'model_helpers.dart';
20 import 'package_helpers.dart';
21
22 /// Docgen representation of an item to be documented, that wraps around a
23 /// dart2js mirror.
24 abstract class MirrorBased<TMirror extends DeclarationMirror> {
25 /// The original dart2js mirror around which this object wraps.
26 TMirror get mirror;
27
28 /// Return an informative [Object.toString] for debugging.
29 String toString() => "${super.toString()} - $mirror";
30 }
31
32 /// A Docgen wrapper around the dart2js mirror for a generic type.
33 class Generic extends MirrorBased<TypeVariableMirror> {
34 final TypeVariableMirror mirror;
35
36 Generic(this.mirror);
37
38 Map toMap() => {
39 'name': dart2js_util.nameOf(mirror),
40 'type': dart2js_util.qualifiedNameOf(mirror.upperBound)
41 };
42 }
43
44 /// For types that we do not explicitly create or have not yet created in our
45 /// entity map (like core types).
46 class DummyMirror implements Indexable {
47 final DeclarationMirror mirror;
48 /// The library that contains this element, if any. Used as a hint to help
49 /// determine which object we're referring to when looking up this mirror in
50 /// our map.
51 final Indexable owner;
52 DummyMirror(this.mirror, [this.owner]);
53
54 String get docName {
55 if (mirror == null) return '';
56 if (mirror is LibraryMirror) {
57 return dart2js_util.qualifiedNameOf(mirror).replaceAll('.','-');
58 }
59 var mirrorOwner = mirror.owner;
60 if (mirrorOwner == null) return dart2js_util.qualifiedNameOf(mirror);
61 var simpleName = dart2js_util.nameOf(mirror);
62 if (mirror is MethodMirror && (mirror as MethodMirror).isConstructor) {
63 // We name constructors specially -- repeating the class name and a
64 // "-" to separate the constructor from its name (if any).
65 simpleName = '${dart2js_util.nameOf(mirrorOwner)}-$simpleName';
66 }
67 return getDocgenObject(mirrorOwner, owner).docName + '.' +
68 simpleName;
69 }
70
71 bool get isPrivate => mirror == null? false : mirror.isPrivate;
72
73 String get packageName {
74 var libMirror = _getOwningLibraryFromMirror(mirror);
75 if (libMirror != null) {
76 return getPackageName(libMirror);
77 }
78 return '';
79 }
80
81 String get packagePrefix => packageName == null || packageName.isEmpty ?
82 '' : '$packageName/';
83
84 LibraryMirror _getOwningLibraryFromMirror(DeclarationMirror mirror) {
85 if (mirror is LibraryMirror) return mirror;
86 if (mirror == null) return null;
87 return _getOwningLibraryFromMirror(mirror.owner);
88 }
89
90 noSuchMethod(Invocation invocation) {
91 throw new UnimplementedError(invocation.memberName.toString());
92 }
93 }
94
95 /// An item that is categorized in our mirrorToDocgen map, as a distinct,
96 /// searchable element.
97 ///
98 /// These are items that refer to concrete entities (a Class, for example,
99 /// but not a Type, which is a "pointer" to a class) that we wish to be
100 /// globally resolvable. This includes things such as class methods and
101 /// variables, but parameters for methods are not "Indexable" as we do not want
102 /// the user to be able to search for a method based on its parameter names!
103 /// The set of indexable items also includes Typedefs, since the user can refer
104 /// to them as concrete entities in a particular scope.
105 abstract class Indexable<TMirror extends DeclarationMirror>
106 extends MirrorBased<TMirror> {
107
108 Library get owningLibrary => owner.owningLibrary;
109
110 String get qualifiedName => fileName;
111 final TMirror mirror;
112 final bool isPrivate;
113 /// The comment text pre-resolution. We keep this around because inherited
114 /// methods need to resolve links differently from the superclass.
115 String _unresolvedComment = '';
116
117 Indexable(TMirror mirror)
118 : this.mirror = mirror,
119 this.isPrivate = isHidden(mirror) {
120
121 var map = mirrorToDocgen[dart2js_util.qualifiedNameOf(this.mirror)];
122 if (map == null) map = new Map<String, Set<Indexable>>();
123
124 var set = map[owner.docName];
125 if (set == null) set = new Set<Indexable>();
126 set.add(this);
127 map[owner.docName] = set;
128 mirrorToDocgen[dart2js_util.qualifiedNameOf(this.mirror)] = map;
129 }
130
131 /// Returns this object's qualified name, but following the conventions
132 /// we're using in Dartdoc, which is that library names with dots in them
133 /// have them replaced with hyphens.
134 String get docName;
135
136 /// Converts all [foo] references in comments to <a>libraryName.foo</a>.
137 markdown.Node fixReference(String name) {
138 // Attempt the look up the whole name up in the scope.
139 String elementName = findElementInScope(name);
140 if (elementName != null) {
141 return new markdown.Element.text('a', elementName);
142 }
143 return fixComplexReference(name);
144 }
145
146 /// Look for the specified name starting with the current member, and
147 /// progressively working outward to the current library scope.
148 String findElementInScope(String name) =>
149 findElementInScopeWithPrefix(name, packagePrefix);
150
151 /// The reference to this element based on where it is printed as a
152 /// documentation file and also the unique URL to refer to this item.
153 ///
154 /// The qualified name (for URL purposes) and the file name are the same,
155 /// of the form packageName/ClassName or packageName/ClassName.methodName.
156 /// This defines both the URL and the directory structure.
157 String get fileName => packagePrefix + ownerPrefix + name;
158
159 /// The full docName of the owner element, appended with a '.' for this
160 /// object's name to be appended.
161 String get ownerPrefix => owner.docName != '' ? owner.docName + '.' : '';
162
163 /// The prefix String to refer to the package that this item is in, for URLs
164 /// and comment resolution.
165 ///
166 /// The prefix can be prepended to a qualified name to get a fully unique
167 /// name among all packages.
168 String get packagePrefix => '';
169
170 /// Documentation comment with converted markdown and all links resolved.
171 String _comment;
172
173 /// Accessor to documentation comment with markdown converted to html and all
174 /// links resolved.
175 String get comment {
176 if (_comment != null) return _comment;
177
178 _comment = _commentToHtml();
179 if (_comment.isEmpty) {
180 _comment = _mdnComment();
181 }
182 return _comment;
183 }
184
185 void set comment(x) {
186 _comment = x;
187 }
188
189 /// The simple name to refer to this item.
190 String get name => dart2js_util.nameOf(mirror);
191
192 /// Accessor to the parent item that owns this item.
193 ///
194 /// "Owning" is defined as the object one scope-level above which this item
195 /// is defined. Ex: The owner for a top level class, would be its enclosing
196 /// library. The owner of a local variable in a method would be the enclosing
197 /// method.
198 Indexable get owner => new DummyMirror(mirror.owner);
199
200 /// Generates MDN comments from database.json.
201 String _mdnComment();
202
203 /// The type of this member to be used in index.txt.
204 String get typeName => '';
205
206 /// Creates a [Map] with this [Indexable]'s name and a preview comment.
207 Map get previewMap {
208 var finalMap = { 'name' : name, 'qualifiedName' : qualifiedName };
209 var preview = _preview;
210 if(preview != null) finalMap['preview'] = preview;
211 return finalMap;
212 }
213
214 String get _preview {
215 if (comment != '') {
216 var index = comment.indexOf('</p>');
217 return index > 0 ?
218 '${comment.substring(0, index)}</p>' :
219 '<p><i>Comment preview not available</i></p>';
220 }
221 return null;
222 }
223
224 /// Accessor to obtain the raw comment text for a given item, _without_ any
225 /// of the links resolved.
226 String get _commentText {
227 String commentText;
228 mirror.metadata.forEach((metadata) {
229 if (metadata is CommentInstanceMirror) {
230 CommentInstanceMirror comment = metadata;
231 if (comment.isDocComment) {
232 if (commentText == null) {
233 commentText = comment.trimmedText;
234 } else {
235 commentText = '$commentText\n${comment.trimmedText}';
236 }
237 }
238 }
239 });
240 return commentText;
241 }
242
243 /// Returns any documentation comments associated with a mirror with
244 /// simple markdown converted to html.
245 ///
246 /// By default we resolve any comment references within our own scope.
247 /// However, if a method is inherited, we want the inherited comments, but
248 /// links to the subclasses's version of the methods.
249 String _commentToHtml([Indexable resolvingScope]) {
250 if (resolvingScope == null) resolvingScope = this;
251 var commentText = _commentText;
252 _unresolvedComment = commentText;
253
254 var linkResolver = (name) => resolvingScope.fixReference(name);
255 commentText = commentText == null ? '' :
256 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver,
257 inlineSyntaxes: MARKDOWN_SYNTAXES);
258 return commentText;
259 }
260
261 /// Return a map representation of this type.
262 Map toMap();
263
264 /// Expand the method map [mapToExpand] into a more detailed map that
265 /// separates out setters, getters, constructors, operators, and methods.
266 Map _expandMethodMap(Map<String, Method> mapToExpand) => {
267 'setters': recurseMap(filterMap(mapToExpand,
268 (key, val) => val.mirror.isSetter)),
269 'getters': recurseMap(filterMap(mapToExpand,
270 (key, val) => val.mirror.isGetter)),
271 'constructors': recurseMap(filterMap(mapToExpand,
272 (key, val) => val.mirror.isConstructor)),
273 'operators': recurseMap(filterMap(mapToExpand,
274 (key, val) => val.mirror.isOperator)),
275 'methods': recurseMap(filterMap(mapToExpand,
276 (key, val) => val.mirror.isRegularMethod && !val.mirror.isOperator))
277 };
278
279 /// Accessor to determine if this item and all of its owners are visible.
280 bool get isVisible => isFullChainVisible(this);
281
282 /// Returns true if [mirror] is the correct type of mirror that this Docgen
283 /// object wraps. (Workaround for the fact that Types are not first class.)
284 bool isValidMirror(DeclarationMirror mirror);
285 }
286
287 /// A class containing contents of a Dart library.
288 class Library extends Indexable {
289 final Map<String, Class> classes = {};
290 final Map<String, Typedef> typedefs = {};
291 final Map<String, Class> errors = {};
292
293 /// Top-level variables in the library.
294 Map<String, Variable> variables;
295
296 /// Top-level functions in the library.
297 Map<String, Method> functions;
298
299 String packageName = '';
300 bool _hasBeenCheckedForPackage = false;
301 String packageIntro;
302
303 Library get owningLibrary => this;
304
305 /// Returns the [Library] for the given [mirror] if it has already been
306 /// created, else creates it.
307 factory Library(LibraryMirror mirror) {
308 var library = getDocgenObject(mirror);
309 if (library is DummyMirror) {
310 library = new Library._(mirror);
311 }
312 return library;
313 }
314
315 Library._(LibraryMirror libraryMirror) : super(libraryMirror) {
316 var exported = calcExportedItems(libraryMirror);
317 var exportedClasses = addAll(exported['classes'],
318 dart2js_util.typesOf(libraryMirror.declarations));
319 updateLibraryPackage(mirror);
320 exportedClasses.forEach((String mirrorName, TypeMirror mirror) {
321 if (mirror is TypedefMirror) {
322 // This is actually a Dart2jsTypedefMirror, and it does define value,
323 // but we don't have visibility to that type.
324 if (includePrivateMembers || !mirror.isPrivate) {
325 typedefs[dart2js_util.nameOf(mirror)] = new Typedef(mirror, this);
326 }
327 } else if (mirror is ClassMirror) {
328 var clazz = new Class(mirror, this);
329
330 if (clazz.isError()) {
331 errors[dart2js_util.nameOf(mirror)] = clazz;
332 } else {
333 classes[dart2js_util.nameOf(mirror)] = clazz;
334 }
335 } else {
336 throw new ArgumentError(
337 '${dart2js_util.nameOf(mirror)} - no class type match. ');
338 }
339 });
340 this.functions = createMethods(addAll(exported['methods'],
341 libraryMirror.declarations.values.where(
342 (mirror) => mirror is MethodMirror)).values, this);
343 this.variables = createVariables(addAll(exported['variables'],
344 dart2js_util.variablesOf(libraryMirror.declarations)).values, this);
345 }
346
347 /// Look for the specified name starting with the current member, and
348 /// progressively working outward to the current library scope.
349 String findElementInScope(String name) {
350 var lookupFunc = determineLookupFunc(name);
351 var libraryScope = lookupFunc(mirror, name);
352 if (libraryScope != null) {
353 var result = getDocgenObject(libraryScope, this);
354 if (result is DummyMirror) return packagePrefix + result.docName;
355 return result.packagePrefix + result.docName;
356 }
357 return super.findElementInScope(name);
358 }
359
360 String _mdnComment() => '';
361
362 /// For a library's [mirror], determine the name of the package (if any) we
363 /// believe it came from (because of its file URI).
364 ///
365 /// If no package could be determined, we return an empty string.
366 void updateLibraryPackage(LibraryMirror mirror) {
367 if (mirror == null) return;
368 if (_hasBeenCheckedForPackage) return;
369 _hasBeenCheckedForPackage = true;
370 if (mirror.uri.scheme != 'file') return;
371 packageName = getPackageName(mirror);
372 // Associate the package readme with all the libraries. This is a bit
373 // wasteful, but easier than trying to figure out which partial match
374 // is best.
375 packageIntro = _packageIntro(getPackageDirectory(mirror));
376 }
377
378 String _packageIntro(packageDir) {
379 if (packageDir == null) return null;
380 var dir = new Directory(packageDir);
381 var files = dir.listSync();
382 var readmes = files.where((FileSystemEntity each) => (each is File &&
383 each.path.substring(packageDir.length + 1, each.path.length)
384 .startsWith('README'))).toList();
385 if (readmes.isEmpty) return '';
386 // If there are multiples, pick the shortest name.
387 readmes.sort((a, b) => a.path.length.compareTo(b.path.length));
388 var readme = readmes.first;
389 var linkResolver = (name) => globalFixReference(name);
390 var contents = markdown.markdownToHtml(readme
391 .readAsStringSync(), linkResolver: linkResolver,
392 inlineSyntaxes: MARKDOWN_SYNTAXES);
393 return contents;
394 }
395
396 String get packagePrefix => packageName == null || packageName.isEmpty ?
397 '' : '$packageName/';
398
399 Map get previewMap {
400 var map = {'packageName': packageName};
401 map.addAll(super.previewMap);
402 if (packageIntro != null) {
403 map['packageIntro'] = packageIntro;
404 }
405 return map;
406 }
407
408 String get name => docName;
409
410 String get docName {
411 return dart2js_util.qualifiedNameOf(mirror).replaceAll('.','-');
412 }
413
414 /// Checks if the given name is a key for any of the Class Maps.
415 bool containsKey(String name) =>
416 classes.containsKey(name) || errors.containsKey(name);
417
418 /// Generates a map describing the [Library] object.
419 Map toMap() => {
420 'name': name,
421 'qualifiedName': qualifiedName,
422 'comment': comment,
423 'variables': recurseMap(variables),
424 'functions': _expandMethodMap(functions),
425 'classes': {
426 'class': classes.values.where((c) => c.isVisible)
427 .map((e) => e.previewMap).toList(),
428 'typedef': recurseMap(typedefs),
429 'error': errors.values.where((e) => e.isVisible)
430 .map((e) => e.previewMap).toList()
431 },
432 'packageName': packageName,
433 'packageIntro' : packageIntro
434 };
435
436 String get typeName => 'library';
437
438 bool isValidMirror(DeclarationMirror mirror) => mirror is LibraryMirror;
439 }
440
441 abstract class OwnedIndexable<TMirror extends DeclarationMirror>
442 extends Indexable<TMirror> {
443 /// List of the meta annotations on this item.
444 final List<Annotation> annotations;
445
446 /// The object one scope-level above which this item is defined.
447 ///
448 /// Ex: The owner for a top level class, would be its enclosing library.
449 /// The owner of a local variable in a method would be the enclosing method.
450 final Indexable owner;
451
452 /// Returns this object's qualified name, but following the conventions
453 /// we're using in Dartdoc, which is that library names with dots in them
454 /// have them replaced with hyphens.
455 String get docName => owner.docName + '.' + dart2js_util.nameOf(mirror);
456
457 OwnedIndexable(DeclarationMirror mirror, Indexable owner)
458 : annotations = createAnnotations(mirror, owner.owningLibrary),
459 this.owner = owner,
460 super(mirror);
461
462 /// Generates MDN comments from database.json.
463 String _mdnComment() {
464 var domAnnotation = this.annotations.firstWhere(
465 (e) => e.mirror.qualifiedName == #metadata.DomName,
466 orElse: () => null);
467 if (domAnnotation == null) return '';
468 var domName = domAnnotation.parameters.single;
469
470 return mdnComment(rootDirectory, logger, domName);
471 }
472
473 String get packagePrefix => owner.packagePrefix;
474 }
475
476 /// A class containing contents of a Dart class.
477 class Class extends OwnedIndexable<dart2js_mirrors.Dart2JsInterfaceTypeMirror>
478 implements Comparable<Class> {
479
480 /// List of the names of interfaces that this class implements.
481 List<Class> interfaces = [];
482
483 /// Names of classes that extends or implements this class.
484 Set<Class> subclasses = new Set<Class>();
485
486 /// Top-level variables in the class.
487 Map<String, Variable> variables;
488
489 /// Inherited variables in the class.
490 final Map<String, Variable> inheritedVariables = {};
491
492 /// Methods in the class.
493 Map<String, Method> methods;
494
495 final Map<String, Method> inheritedMethods = new Map<String, Method>();
496
497 /// Generic infomation about the class.
498 final Map<String, Generic> generics;
499
500 Class superclass;
501 bool get isAbstract => mirror.isAbstract;
502
503 /// Make sure that we don't check for inherited comments more than once.
504 bool _commentsEnsured = false;
505
506 /// Returns the [Class] for the given [mirror] if it has already been created,
507 /// else creates it.
508 factory Class(ClassMirror mirror, Library owner) {
509 var clazz = getDocgenObject(mirror, owner);
510 if (clazz is DummyMirror) {
511 clazz = new Class._(mirror, owner);
512 }
513 return clazz;
514 }
515
516 /// Called when we are constructing a superclass or interface class, but it
517 /// is not known if it belongs to the same owner as the original class. In
518 /// this case, we create an object whose owner is what the original mirror
519 /// says it is.
520 factory Class._possiblyDifferentOwner(ClassMirror mirror,
521 Library originalOwner) {
522 if (mirror.owner is LibraryMirror) {
523 var realOwner = getDocgenObject(mirror.owner);
524 if (realOwner is Library) {
525 return new Class(mirror, realOwner);
526 } else {
527 return new Class(mirror, originalOwner);
528 }
529 } else {
530 return new Class(mirror, originalOwner);
531 }
532 }
533
534 Class._(ClassSourceMirror classMirror, Indexable owner)
535 : generics = createGenerics(classMirror),
536 super(classMirror, owner) {
537
538 // The reason we do this madness is the superclass and interface owners may
539 // not be this class's owner!! Example: BaseClient in http pkg.
540 var superinterfaces = classMirror.superinterfaces.map(
541 (interface) => new Class._possiblyDifferentOwner(interface, owner));
542 this.superclass = classMirror.superclass == null? null :
543 new Class._possiblyDifferentOwner(classMirror.superclass, owner);
544
545 interfaces = superinterfaces.toList();
546 variables = createVariables(
547 dart2js_util.variablesOf(classMirror.declarations), this);
548 methods = createMethods(classMirror.declarations.values.where(
549 (mirror) => mirror is MethodMirror), this);
550
551 // Tell superclass that you are a subclass, unless you are not
552 // visible or an intermediary mixin class.
553 if (!classMirror.isNameSynthetic && isVisible && superclass != null) {
554 superclass.addSubclass(this);
555 }
556
557 if (this.superclass != null) addInherited(superclass);
558 interfaces.forEach((interface) => addInherited(interface));
559 }
560
561 String _lookupInClassAndSuperclasses(String name) {
562 var lookupFunc = determineLookupFunc(name);
563 var classScope = this;
564 while (classScope != null) {
565 var classFunc = lookupFunc(classScope.mirror, name);
566 if (classFunc != null) {
567 return packagePrefix + getDocgenObject(classFunc, owner).docName;
568 }
569 classScope = classScope.superclass;
570 }
571 return null;
572 }
573
574 /// Look for the specified name starting with the current member, and
575 /// progressively working outward to the current library scope.
576 String findElementInScope(String name) {
577 var lookupFunc = determineLookupFunc(name);
578 var result = _lookupInClassAndSuperclasses(name);
579 if (result != null) {
580 return result;
581 }
582 result = owner.findElementInScope(name);
583 return result == null ? super.findElementInScope(name) : result;
584 }
585
586 String get typeName => 'class';
587
588 /// Add all inherited variables and methods from the provided superclass.
589 /// If [_includePrivate] is true, it also adds the variables and methods from
590 /// the superclass.
591 void addInherited(Class superclass) {
592 inheritedVariables.addAll(superclass.inheritedVariables);
593 inheritedVariables.addAll(_allButStatics(superclass.variables));
594 addInheritedMethod(superclass, this);
595 }
596
597 /** [newParent] refers to the actual class is currently using these methods.
598 * which may be different because with the mirror system, we only point to the
599 * original canonical superclasse's method.
600 */
601 void addInheritedMethod(Class parent, Class newParent) {
602 parent.inheritedMethods.forEach((name, method) {
603 if(!method.mirror.isConstructor){
604 inheritedMethods[name] = new Method(method.mirror, newParent, method);
605 }}
606 );
607 _allButStatics(parent.methods).forEach((name, method) {
608 if (!method.mirror.isConstructor) {
609 inheritedMethods[name] = new Method(method.mirror, newParent, method);
610 }}
611 );
612 }
613
614 /// Remove statics from the map of inherited items before adding them.
615 Map _allButStatics(Map items) {
616 var result = {};
617 items.forEach((name, item) {
618 if (!item.isStatic) {
619 result[name] = item;
620 }
621 });
622 return result;
623 }
624
625 /// Add the subclass to the class.
626 ///
627 /// If [this] is private (or an intermediary mixin class), it will add the
628 /// subclass to the list of subclasses in the superclasses.
629 void addSubclass(Class subclass) {
630 if (docName == 'dart-core.Object') return;
631
632 if (!includePrivateMembers && isPrivate || mirror.isNameSynthetic) {
633 if (superclass != null) superclass.addSubclass(subclass);
634 interfaces.forEach((interface) {
635 interface.addSubclass(subclass);
636 });
637 } else {
638 subclasses.add(subclass);
639 }
640 }
641
642 /// Check if this [Class] is an error or exception.
643 bool isError() {
644 if (qualifiedName == 'dart-core.Error' ||
645 qualifiedName == 'dart-core.Exception')
646 return true;
647 for (var interface in interfaces) {
648 if (interface.isError()) return true;
649 }
650 if (superclass == null) return false;
651 return superclass.isError();
652 }
653
654 /// Makes sure that all methods with inherited equivalents have comments.
655 void ensureComments() {
656 if (_commentsEnsured) return;
657 _commentsEnsured = true;
658 if (superclass != null) superclass.ensureComments();
659 inheritedMethods.forEach((qualifiedName, inheritedMethod) {
660 var method = methods[qualifiedName];
661 if (method != null) {
662 // if we have overwritten this method in this class, we still provide
663 // the opportunity to inherit the comments.
664 method.ensureCommentFor(inheritedMethod);
665 }
666 });
667 // we need to populate the comments for all methods. so that the subclasses
668 // can get for their inherited versions the comments.
669 methods.forEach((qualifiedName, method) {
670 if (!method.mirror.isConstructor) method.ensureCommentFor(method);
671 });
672 }
673
674 /// If a class extends a private superclass, find the closest public
675 /// superclass of the private superclass.
676 String validSuperclass() {
677 if (superclass == null) return 'dart-core.Object';
678 if (superclass.isVisible) return superclass.qualifiedName;
679 return superclass.validSuperclass();
680 }
681
682 /// Generates a map describing the [Class] object.
683 Map toMap() => {
684 'name': name,
685 'qualifiedName': qualifiedName,
686 'comment': comment,
687 'isAbstract' : isAbstract,
688 'superclass': validSuperclass(),
689 'implements': interfaces.where((i) => i.isVisible)
690 .map((e) => e.qualifiedName).toList(),
691 'subclass': (subclasses.toList()..sort())
692 .map((x) => x.qualifiedName).toList(),
693 'variables': recurseMap(variables),
694 'inheritedVariables': recurseMap(inheritedVariables),
695 'methods': _expandMethodMap(methods),
696 'inheritedMethods': _expandMethodMap(inheritedMethods),
697 'annotations': annotations.map((a) => a.toMap()).toList(),
698 'generics': recurseMap(generics)
699 };
700
701 int compareTo(Class other) => name.compareTo(other.name);
702
703 bool isValidMirror(DeclarationMirror mirror) => mirror is ClassMirror;
704 }
705
706 class Typedef extends OwnedIndexable {
707 final String returnType;
708
709 final Map<String, Parameter> parameters;
710
711 /// Generic information about the typedef.
712 final Map<String, Generic> generics;
713
714 /// Returns the [Library] for the given [mirror] if it has already been
715 /// created, else creates it.
716 factory Typedef(TypedefMirror mirror, Library owningLibrary) {
717 var aTypedef = getDocgenObject(mirror, owningLibrary);
718 if (aTypedef is DummyMirror) {
719 aTypedef = new Typedef._(mirror, owningLibrary);
720 }
721 return aTypedef;
722 }
723
724 Typedef._(TypedefMirror mirror, Library owningLibrary)
725 : returnType = getDocgenObject(mirror.referent.returnType).docName,
726 generics = createGenerics(mirror),
727 parameters = createParameters(mirror.referent.parameters,
728 owningLibrary),
729 super(mirror, owningLibrary);
730
731 Map toMap() {
732 var map = {
733 'name': name,
734 'qualifiedName': qualifiedName,
735 'comment': comment,
736 'return': returnType,
737 'parameters': recurseMap(parameters),
738 'annotations': annotations.map((a) => a.toMap()).toList(),
739 'generics': recurseMap(generics)
740 };
741
742 // Typedef is displayed on the library page as a class, so a preview is
743 // added manually
744 var preview = _preview;
745 if(preview != null) map['preview'] = preview;
746
747 return map;
748 }
749
750 markdown.Node fixReference(String name) => null;
751
752 String get typeName => 'typedef';
753
754 bool isValidMirror(DeclarationMirror mirror) => mirror is TypedefMirror;
755 }
756
757 /// A class containing properties of a Dart variable.
758 class Variable extends OwnedIndexable {
759
760 bool isFinal;
761 bool isStatic;
762 bool isConst;
763 Type type;
764 String _variableName;
765
766 factory Variable(String variableName, VariableMirror mirror,
767 Indexable owner) {
768 var variable = getDocgenObject(mirror);
769 if (variable is DummyMirror) {
770 return new Variable._(variableName, mirror, owner);
771 }
772 return variable;
773 }
774
775 Variable._(this._variableName, VariableMirror mirror, Indexable owner) :
776 super(mirror, owner) {
777 isFinal = mirror.isFinal;
778 isStatic = mirror.isStatic;
779 isConst = mirror.isConst;
780 type = new Type(mirror.type, owner.owningLibrary);
781 }
782
783 String get name => _variableName;
784
785 /// Generates a map describing the [Variable] object.
786 Map toMap() => {
787 'name': name,
788 'qualifiedName': qualifiedName,
789 'comment': comment,
790 'final': isFinal,
791 'static': isStatic,
792 'constant': isConst,
793 'type': new List.filled(1, type.toMap()),
794 'annotations': annotations.map((a) => a.toMap()).toList()
795 };
796
797 String get typeName => 'property';
798
799 get comment {
800 if (_comment != null) return _comment;
801 if (owner is Class) {
802 (owner as Class).ensureComments();
803 }
804 return super.comment;
805 }
806
807 String findElementInScope(String name) {
808 var lookupFunc = determineLookupFunc(name);
809 var result = lookupFunc(mirror, name);
810 if (result != null) {
811 result = getDocgenObject(result);
812 if (result is DummyMirror) return packagePrefix + result.docName;
813 return result.packagePrefix + result.docName;
814 }
815
816 if (owner != null) {
817 var result = owner.findElementInScope(name);
818 if (result != null) {
819 return result;
820 }
821 }
822 return super.findElementInScope(name);
823 }
824
825 bool isValidMirror(DeclarationMirror mirror) => mirror is VariableMirror;
826 }
827
828 /// A class containing properties of a Dart method.
829 class Method extends OwnedIndexable {
830
831 /// Parameters for this method.
832 final Map<String, Parameter> parameters;
833
834 final bool isStatic;
835 final bool isAbstract;
836 final bool isConst;
837 final Type returnType;
838 Method methodInheritedFrom;
839
840 /// Qualified name to state where the comment is inherited from.
841 String commentInheritedFrom = "";
842
843 factory Method(MethodMirror mirror, Indexable owner,
844 [Method methodInheritedFrom]) {
845 var method = getDocgenObject(mirror, owner);
846 if (method is DummyMirror) {
847 method = new Method._(mirror, owner, methodInheritedFrom);
848 }
849 return method;
850 }
851
852 Method._(MethodMirror mirror, Indexable owner, this.methodInheritedFrom)
853 : returnType = new Type(mirror.returnType, owner.owningLibrary),
854 isStatic = mirror.isStatic,
855 isAbstract = mirror.isAbstract,
856 isConst = mirror.isConstConstructor,
857 parameters = createParameters(mirror.parameters, owner),
858 super(mirror, owner);
859
860 Method get originallyInheritedFrom => methodInheritedFrom == null ?
861 this : methodInheritedFrom.originallyInheritedFrom;
862
863 /// Look for the specified name starting with the current member, and
864 /// progressively working outward to the current library scope.
865 String findElementInScope(String name) {
866 var lookupFunc = determineLookupFunc(name);
867
868 var memberScope = lookupFunc(this.mirror, name);
869 if (memberScope != null) {
870 // do we check for a dummy mirror returned here and look up with an owner
871 // higher ooooor in getDocgenObject do we include more things in our
872 // lookup
873 var result = getDocgenObject(memberScope, owner);
874 if (result is DummyMirror && owner.owner != null
875 && owner.owner is! DummyMirror) {
876 var aresult = getDocgenObject(memberScope, owner.owner);
877 if (aresult is! DummyMirror) result = aresult;
878 }
879 if (result is DummyMirror) return packagePrefix + result.docName;
880 return result.packagePrefix + result.docName;
881 }
882
883 if (owner != null) {
884 var result = owner.findElementInScope(name);
885 if (result != null) return result;
886 }
887 return super.findElementInScope(name);
888 }
889
890 String get docName {
891 if ((mirror as MethodMirror).isConstructor) {
892 // We name constructors specially -- including the class name again and a
893 // "-" to separate the constructor from its name (if any).
894 return '${owner.docName}.${dart2js_util.nameOf(mirror.owner)}-'
895 '${dart2js_util.nameOf(mirror)}';
896 }
897 return super.docName;
898 }
899
900 String get fileName => packagePrefix + docName;
901
902 /// Makes sure that the method with an inherited equivalent have comments.
903 void ensureCommentFor(Method inheritedMethod) {
904 if (comment.isNotEmpty) return;
905
906 comment = inheritedMethod._commentToHtml(this);
907 _unresolvedComment = inheritedMethod._unresolvedComment;
908 commentInheritedFrom = inheritedMethod.commentInheritedFrom == '' ?
909 new DummyMirror(inheritedMethod.mirror).docName :
910 inheritedMethod.commentInheritedFrom;
911 }
912
913 /// Generates a map describing the [Method] object.
914 Map toMap() => {
915 'name': name,
916 'qualifiedName': qualifiedName,
917 'comment': comment,
918 'commentFrom': (methodInheritedFrom != null &&
919 commentInheritedFrom == methodInheritedFrom.docName ? ''
920 : commentInheritedFrom),
921 'inheritedFrom': (methodInheritedFrom == null? '' :
922 originallyInheritedFrom.docName),
923 'static': isStatic,
924 'abstract': isAbstract,
925 'constant': isConst,
926 'return': [returnType.toMap()],
927 'parameters': recurseMap(parameters),
928 'annotations': annotations.map((a) => a.toMap()).toList()
929 };
930
931 String get typeName {
932 MethodMirror theMirror = mirror;
933 if (theMirror.isConstructor) return 'constructor';
934 if (theMirror.isGetter) return 'getter';
935 if (theMirror.isSetter) return'setter';
936 if (theMirror.isOperator) return 'operator';
937 return 'method';
938 }
939
940 get comment {
941 if (_comment != null) return _comment;
942 if (owner is Class) {
943 (owner as Class).ensureComments();
944 }
945 var result = super.comment;
946 if (result == '' && methodInheritedFrom != null) {
947 // This should be NOT from the MIRROR, but from the COMMENT.
948 methodInheritedFrom.comment; // Ensure comment field has been populated.
949 _unresolvedComment = methodInheritedFrom._unresolvedComment;
950
951 var linkResolver = (name) => fixReference(name);
952 comment = _unresolvedComment == null ? '' :
953 markdown.markdownToHtml(_unresolvedComment.trim(),
954 linkResolver: linkResolver, inlineSyntaxes: MARKDOWN_SYNTAXES);
955 commentInheritedFrom = comment != '' ?
956 methodInheritedFrom.commentInheritedFrom : '';
957 result = comment;
958 }
959 return result;
960 }
961
962 bool isValidMirror(DeclarationMirror mirror) => mirror is MethodMirror;
963 }
964
965 /// Docgen wrapper around the dart2js mirror for a Dart
966 /// method/function parameter.
967 class Parameter extends MirrorBased {
968 final ParameterMirror mirror;
969 final String name;
970 final bool isOptional;
971 final bool isNamed;
972 final bool hasDefaultValue;
973 final Type type;
974 final String defaultValue;
975 /// List of the meta annotations on the parameter.
976 final List<Annotation> annotations;
977
978 Parameter(ParameterMirror mirror, Library owningLibrary)
979 : this.mirror = mirror,
980 name = dart2js_util.nameOf(mirror),
981 isOptional = mirror.isOptional,
982 isNamed = mirror.isNamed,
983 hasDefaultValue = mirror.hasDefaultValue,
984 defaultValue = getDefaultValue(mirror),
985 type = new Type(mirror.type, owningLibrary),
986 annotations = createAnnotations(mirror, owningLibrary);
987
988 /// Generates a map describing the [Parameter] object.
989 Map toMap() => {
990 'name': name,
991 'optional': isOptional,
992 'named': isNamed,
993 'default': hasDefaultValue,
994 'type': new List.filled(1, type.toMap()),
995 'value': defaultValue,
996 'annotations': annotations.map((a) => a.toMap()).toList()
997 };
998 }
999
1000 /// Docgen wrapper around the mirror for a return type, and/or its generic
1001 /// type parameters.
1002 ///
1003 /// Return types are of a form [outer]<[inner]>.
1004 /// If there is no [inner] part, [inner] will be an empty list.
1005 ///
1006 /// For example:
1007 /// int size()
1008 /// "return" :
1009 /// - "outer" : "dart-core.int"
1010 /// "inner" :
1011 ///
1012 /// List<String> toList()
1013 /// "return" :
1014 /// - "outer" : "dart-core.List"
1015 /// "inner" :
1016 /// - "outer" : "dart-core.String"
1017 /// "inner" :
1018 ///
1019 /// Map<String, List<int>>
1020 /// "return" :
1021 /// - "outer" : "dart-core.Map"
1022 /// "inner" :
1023 /// - "outer" : "dart-core.String"
1024 /// "inner" :
1025 /// - "outer" : "dart-core.List"
1026 /// "inner" :
1027 /// - "outer" : "dart-core.int"
1028 /// "inner" :
1029 class Type extends MirrorBased {
1030 final TypeMirror mirror;
1031 final Library owningLibrary;
1032
1033 Type(this.mirror, this.owningLibrary);
1034
1035 Map toMap() {
1036 var result = getDocgenObject(mirror, owningLibrary);
1037 return {
1038 // We may encounter types whose corresponding library has not been
1039 // processed yet, so look up with the owningLibrary at the last moment.
1040 'outer': result.packagePrefix + result.docName,
1041 'inner': _createTypeGenerics(mirror).map((e) => e.toMap()).toList(),
1042 };
1043 }
1044
1045 /// Returns a list of [Type] objects constructed from TypeMirrors.
1046 List<Type> _createTypeGenerics(TypeMirror mirror) {
1047 if (mirror is! ClassMirror) return [];
1048 return mirror.typeArguments.map((e) => new Type(e, owningLibrary)).toList();
1049 }
1050 }
1051
1052 /// Holds the name of the annotation, and its parameters.
1053 class Annotation extends MirrorBased {
1054 /// The class of this annotation.
1055 final ClassMirror mirror;
1056 final Library owningLibrary;
1057 List<String> parameters;
1058
1059 Annotation(InstanceMirror originalMirror, this.owningLibrary)
1060 : mirror = originalMirror.type {
1061 parameters = dart2js_util.variablesOf(originalMirror.type.declarations)
1062 .where((e) => e.isFinal)
1063 .map((e) => originalMirror.getField(e.simpleName).reflectee)
1064 .where((e) => e != null)
1065 .toList();
1066 }
1067
1068 Map toMap() => {
1069 'name': getDocgenObject(mirror, owningLibrary).docName,
1070 'parameters': parameters
1071 };
1072 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698