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

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

Issue 56183003: Refactor scripts, so we have a single entrypoint, dartdoc.py, to generate docs. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 1 month 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
« pkg/docgen/bin/dartdoc.py ('K') | « pkg/docgen/bin/upload_docgen.py ('k') | no next file » | 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 /// **docgen** is a tool for creating machine readable representations of Dart
Emily Fortuna 2013/11/01 22:34:46 there was a mixture of /// and /** throughout this
6 * **docgen** is a tool for creating machine readable representations of Dart 6 /// code metadata, including: classes, members, comments and annotations.
7 * code metadata, including: classes, members, comments and annotations. 7 ///
8 * 8 /// 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. 9 ///
10 * 10 /// $ dart docgen.dart [OPTIONS] [FILE/DIR]
11 * $ dart docgen.dart [OPTIONS] [FILE/DIR] 11 ///
12 * 12 /// This creates files called `docs/<library_name>.yaml` in your current
13 * This creates files called `docs/<library_name>.yaml` in your current 13 /// working directory.
14 * working directory.
15 */
16 library docgen; 14 library docgen;
17 15
18 import 'dart:convert'; 16 import 'dart:convert';
19 import 'dart:io'; 17 import 'dart:io';
20 import 'dart:async'; 18 import 'dart:async';
21 19
22 import 'package:logging/logging.dart'; 20 import 'package:logging/logging.dart';
23 import 'package:markdown/markdown.dart' as markdown; 21 import 'package:markdown/markdown.dart' as markdown;
24 import 'package:path/path.dart' as path; 22 import 'package:path/path.dart' as path;
25 import 'package:yaml/yaml.dart'; 23 import 'package:yaml/yaml.dart';
26 24
27 import 'dart2yaml.dart'; 25 import 'dart2yaml.dart';
28 import 'src/io.dart'; 26 import 'src/io.dart';
29 import '../../../sdk/lib/_internal/compiler/compiler.dart' as api; 27 import '../../../sdk/lib/_internal/compiler/compiler.dart' as api;
30 import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart'; 28 import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
31 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro r.dart' 29 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro r.dart'
32 as dart2js; 30 as dart2js;
33 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart' ; 31 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart' ;
34 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider. dart'; 32 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider. dart';
35 import '../../../sdk/lib/_internal/libraries.dart'; 33 import '../../../sdk/lib/_internal/libraries.dart';
36 34
37 var logger = new Logger('Docgen'); 35 var logger = new Logger('Docgen');
38 36
39 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] [fooDir/barFile]'; 37 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] fooDir/barFile';
40 38
41 39
42 List<String> validAnnotations = const ['metadata.Experimental', 40 List<String> skippedAnnotations = const [
43 'metadata.DomName', 'metadata.Deprecated', 'metadata.Unstable', 41 'metadata.DocsEditable', 'metadata.DomName'];
44 'meta.deprecated', 'metadata.SupportedBrowser'];
45 42
46 /// Current library being documented to be used for comment links. 43 /// Current library being documented to be used for comment links.
47 LibraryMirror _currentLibrary; 44 LibraryMirror _currentLibrary;
48 45
49 /// Current class being documented to be used for comment links. 46 /// Current class being documented to be used for comment links.
50 ClassMirror _currentClass; 47 ClassMirror _currentClass;
51 48
52 /// Current member being documented to be used for comment links. 49 /// Current member being documented to be used for comment links.
53 MemberMirror _currentMember; 50 MemberMirror _currentMember;
54 51
55 /// Support for [:foo:]-style code comments to the markdown parser. 52 /// Support for [:foo:]-style code comments to the markdown parser.
56 List<markdown.InlineSyntax> markdownSyntaxes = 53 List<markdown.InlineSyntax> markdownSyntaxes =
57 [new markdown.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')]; 54 [new markdown.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')];
58 55
59 /// Resolves reference links in doc comments. 56 /// Resolves reference links in doc comments.
60 markdown.Resolver linkResolver; 57 markdown.Resolver linkResolver;
61 58
62 /// Index of all indexable items. This also ensures that no class is 59 /// Index of all indexable items. This also ensures that no class is
63 /// created more than once. 60 /// created more than once.
64 Map<String, Indexable> entityMap = new Map<String, Indexable>(); 61 Map<String, Indexable> entityMap = new Map<String, Indexable>();
65 62
66 /// This is set from the command line arguments flag --include-private 63 /// This is set from the command line arguments flag --include-private
67 bool _includePrivate = false; 64 bool _includePrivate = false;
68 65
69 // TODO(janicejl): Make MDN content generic or pluggable. Maybe move 66 // TODO(janicejl): Make MDN content generic or pluggable. Maybe move
70 // MDN-specific code to its own library that is imported into the default impl? 67 // MDN-specific code to its own library that is imported into the default impl?
71 /// Map of all the comments for dom elements from MDN. 68 /// Map of all the comments for dom elements from MDN.
72 Map _mdn; 69 Map _mdn;
73 70
74 /** 71 /// Docgen constructor initializes the link resolver for markdown parsing.
75 * Docgen constructor initializes the link resolver for markdown parsing. 72 /// Also initializes the command line arguments.
76 * Also initializes the command line arguments. 73 ///
77 * 74 /// [packageRoot] is the packages directory of the directory being analyzed.
78 * [packageRoot] is the packages directory of the directory being analyzed. 75 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will
79 * If [includeSdk] is `true`, then any SDK libraries explicitly imported will 76 /// also be documented.
80 * also be documented. 77 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented.
81 * If [parseSdk] is `true`, then all Dart SDK libraries will be documented. 78 /// This option is useful when only the SDK libraries are needed.
82 * This option is useful when only the SDK libraries are needed. 79 ///
83 * 80 /// Returned Future completes with true if document generation is successful.
84 * Returns `true` if docgen sucessfuly completes.
85 */
86 Future<bool> docgen(List<String> files, {String packageRoot, 81 Future<bool> docgen(List<String> files, {String packageRoot,
87 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, 82 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false,
88 bool parseSdk: false, bool append: false, String introduction: ''}) { 83 bool parseSdk: false, bool append: false, String introduction: ''}) {
89 _includePrivate = includePrivate; 84 _includePrivate = includePrivate;
90 if (!append) { 85 if (!append) {
91 var dir = new Directory('docs'); 86 var dir = new Directory('docs');
92 if (dir.existsSync()) dir.deleteSync(recursive: true); 87 if (dir.existsSync()) dir.deleteSync(recursive: true);
93 } 88 }
94 89
95 if (packageRoot == null && !parseSdk) { 90 if (packageRoot == null && !parseSdk) {
96 var type = FileSystemEntity.typeSync(files.first); 91 var type = FileSystemEntity.typeSync(files.first);
97 if (type == FileSystemEntityType.DIRECTORY) { 92 if (type == FileSystemEntityType.DIRECTORY) {
98 packageRoot = _findPackageRoot(files.first); 93 packageRoot = _findPackageRoot(files.first);
99 } else if (type == FileSystemEntityType.FILE) { 94 } else if (type == FileSystemEntityType.FILE) {
100 logger.warning('WARNING: No package root defined. If Docgen fails, try ' 95 logger.warning('WARNING: No package root defined. If Docgen fails, try '
101 'again by setting the --package-root option.'); 96 'again by setting the --package-root option.');
102 } 97 }
103 } 98 }
104 logger.info('Package Root: ${packageRoot}'); 99 logger.info('Package Root: ${packageRoot}');
105 linkResolver = (name) => 100 linkResolver = (name) =>
106 fixReference(name, _currentLibrary, _currentClass, _currentMember); 101 fixReference(name, _currentLibrary, _currentClass, _currentMember);
107 102
108 return getMirrorSystem(files, packageRoot: packageRoot, parseSdk: parseSdk) 103 return getMirrorSystem(files, packageRoot: packageRoot, parseSdk: parseSdk)
109 .then((MirrorSystem mirrorSystem) { 104 .then((MirrorSystem mirrorSystem) {
110 if (mirrorSystem.libraries.isEmpty) { 105 if (mirrorSystem.libraries.isEmpty) {
111 throw new StateError('No library mirrors were created.'); 106 throw new StateError('No library mirrors were created.');
112 } 107 }
113 var librariesWeAskedFor = _listLibraries(files); 108 var librariesWeAskedFor = _listLibraries(files);
114 var librariesWeGot = mirrorSystem.libraries.values.where((each) 109 var librariesWeGot = mirrorSystem.libraries.values.where(
115 => each.uri.scheme == 'file'); 110 (each) => each.uri.scheme == 'file');
116 var sdkLibraries = mirrorSystem.libraries.values.where( 111 var sdkLibraries = mirrorSystem.libraries.values.where(
117 (each) => each.uri.scheme == 'dart'); 112 (each) => each.uri.scheme == 'dart');
118 var librariesWeGotByPath = new Map.fromIterables( 113 var librariesWeGotByPath = new Map.fromIterables(
119 librariesWeGot.map((each) => each.uri.toFilePath()), 114 librariesWeGot.map((each) => each.uri.toFilePath()),
120 librariesWeGot); 115 librariesWeGot);
121 var librariesToDocument = librariesWeAskedFor.map((each) => 116 var librariesToDocument = librariesWeAskedFor.map(
122 librariesWeGotByPath 117 (each) => librariesWeGotByPath.putIfAbsent(each,
123 .putIfAbsent(each, () => throw "Missing library $each")).toList(); 118 () => throw "Missing library $each")).toList();
124 librariesToDocument.addAll((includeSdk || parseSdk) ? sdkLibraries : []); 119 librariesToDocument.addAll((includeSdk || parseSdk) ? sdkLibraries : []);
125 _documentLibraries(librariesToDocument, includeSdk: includeSdk, 120 _documentLibraries(librariesToDocument, includeSdk: includeSdk,
126 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk, 121 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk,
127 introduction: introduction); 122 introduction: introduction);
128 return true; 123 return true;
129 }); 124 });
130 } 125 }
131 126
132 /// For a [library] and its corresponding [mirror] that we believe come 127 /// For a [library] and its corresponding [mirror] that we believe come
133 /// from a package (because it has a file 128 /// from a package (because it has a file
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 var files = listDir(directory, recursive: true); 206 var files = listDir(directory, recursive: true);
212 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. 207 // Return '' means that there was no pubspec.yaml and therefor no packageRoot.
213 String packageRoot = files.firstWhere((f) => 208 String packageRoot = files.firstWhere((f) =>
214 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => ''); 209 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => '');
215 if (packageRoot != '') { 210 if (packageRoot != '') {
216 packageRoot = path.join(path.dirname(packageRoot), 'packages'); 211 packageRoot = path.join(path.dirname(packageRoot), 'packages');
217 } 212 }
218 return packageRoot; 213 return packageRoot;
219 } 214 }
220 215
221 /** 216 /// Read a pubspec and return the library name.
222 * Read a pubspec and return the library name.
223 */
224 String _packageName(String pubspecName) { 217 String _packageName(String pubspecName) {
225 File pubspec = new File(pubspecName); 218 File pubspec = new File(pubspecName);
226 if (!pubspec.existsSync()) return ''; 219 if (!pubspec.existsSync()) return '';
227 var contents = pubspec.readAsStringSync(); 220 var contents = pubspec.readAsStringSync();
228 var spec = loadYaml(contents); 221 var spec = loadYaml(contents);
229 return spec["name"]; 222 return spec["name"];
230 } 223 }
231 224
232 List<String> _listSdk() { 225 List<String> _listSdk() {
233 var sdk = new List<String>(); 226 var sdk = new List<String>();
234 LIBRARIES.forEach((String name, LibraryInfo info) { 227 LIBRARIES.forEach((String name, LibraryInfo info) {
235 if (info.documented) { 228 if (info.documented) {
236 sdk.add('dart:$name'); 229 sdk.add('dart:$name');
237 logger.info('Add to SDK: ${sdk.last}'); 230 logger.info('Add to SDK: ${sdk.last}');
238 } 231 }
239 }); 232 });
240 return sdk; 233 return sdk;
241 } 234 }
242 235
243 /** 236 /// Analyzes set of libraries by getting a mirror system and triggers the
244 * Analyzes set of libraries by getting a mirror system and triggers the 237 /// documentation of the libraries.
245 * documentation of the libraries.
246 */
247 Future<MirrorSystem> getMirrorSystem(List<String> args, {String packageRoot, 238 Future<MirrorSystem> getMirrorSystem(List<String> args, {String packageRoot,
248 bool parseSdk: false}) { 239 bool parseSdk: false}) {
249 var libraries = !parseSdk ? _listLibraries(args) : _listSdk(); 240 var libraries = !parseSdk ? _listLibraries(args) : _listSdk();
250 if (libraries.isEmpty) throw new StateError('No Libraries.'); 241 if (libraries.isEmpty) throw new StateError('No Libraries.');
251 // Finds the root of SDK library based off the location of docgen. 242 // Finds the root of SDK library based off the location of docgen.
252 243
253 var root = findRootDirectory(); 244 var root = findRootDirectory();
254 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk'))); 245 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk')));
255 logger.info('SDK Root: ${sdkRoot}'); 246 logger.info('SDK Root: ${sdkRoot}');
256 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot); 247 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot);
257 } 248 }
258 249
259 String findRootDirectory() { 250 String findRootDirectory() {
260 var scriptDir = path.absolute(path.dirname(Platform.script.toFilePath())); 251 var scriptDir = path.absolute(path.dirname(Platform.script.toFilePath()));
261 var root = scriptDir; 252 var root = scriptDir;
262 while(path.basename(root) != 'dart') { 253 while(path.basename(root) != 'dart') {
263 root = path.dirname(root); 254 root = path.dirname(root);
264 } 255 }
265 return root; 256 return root;
266 } 257 }
267 258
268 /** 259 /// Analyzes set of libraries and provides a mirror system which can be used
269 * Analyzes set of libraries and provides a mirror system which can be used 260 /// for static inspection of the source code.
270 * for static inspection of the source code.
271 */
272 Future<MirrorSystem> _analyzeLibraries(List<String> libraries, 261 Future<MirrorSystem> _analyzeLibraries(List<String> libraries,
273 String libraryRoot, {String packageRoot}) { 262 String libraryRoot, {String packageRoot}) {
274 SourceFileProvider provider = new CompilerSourceFileProvider(); 263 SourceFileProvider provider = new CompilerSourceFileProvider();
275 api.DiagnosticHandler diagnosticHandler = 264 api.DiagnosticHandler diagnosticHandler =
276 (new FormattingDiagnosticHandler(provider) 265 (new FormattingDiagnosticHandler(provider)
277 ..showHints = false 266 ..showHints = false
278 ..showWarnings = false) 267 ..showWarnings = false)
279 .diagnosticHandler; 268 .diagnosticHandler;
280 Uri libraryUri = new Uri(scheme: 'file', path: appendSlash(libraryRoot)); 269 Uri libraryUri = new Uri(scheme: 'file', path: appendSlash(libraryRoot));
281 Uri packageUri = null; 270 Uri packageUri = null;
(...skipping 10 matching lines...) Expand all
292 ..catchError((error) { 281 ..catchError((error) {
293 logger.severe('Error: Failed to create mirror system. '); 282 logger.severe('Error: Failed to create mirror system. ');
294 // TODO(janicejl): Use the stack trace package when bug is resolved. 283 // TODO(janicejl): Use the stack trace package when bug is resolved.
295 // Currently, a string is thrown when it fails to create a mirror 284 // Currently, a string is thrown when it fails to create a mirror
296 // system, and it is not possible to use the stack trace. BUG(#11622) 285 // system, and it is not possible to use the stack trace. BUG(#11622)
297 // To avoid printing the stack trace. 286 // To avoid printing the stack trace.
298 exit(1); 287 exit(1);
299 }); 288 });
300 } 289 }
301 290
302 /** 291 /// Creates documentation for filtered libraries.
303 * Creates documentation for filtered libraries.
304 */
305 void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false, 292 void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false,
306 bool outputToYaml: true, bool append: false, bool parseSdk: false, 293 bool outputToYaml: true, bool append: false, bool parseSdk: false,
307 String introduction: ''}) { 294 String introduction: ''}) {
308 libs.forEach((lib) { 295 libs.forEach((lib) {
309 // Files belonging to the SDK have a uri that begins with 'dart:'. 296 // Files belonging to the SDK have a uri that begins with 'dart:'.
310 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { 297 if (includeSdk || !lib.uri.toString().startsWith('dart:')) {
311 var library = generateLibrary(lib); 298 var library = generateLibrary(lib);
312 entityMap[library.name] = library; 299 entityMap[library.name] = library;
313 } 300 }
314 }); 301 });
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 if (outputToYaml) { 379 if (outputToYaml) {
393 output = getYamlString(result.toMap()); 380 output = getYamlString(result.toMap());
394 outputFile = outputFile + '.yaml'; 381 outputFile = outputFile + '.yaml';
395 } else { 382 } else {
396 output = JSON.encode(result.toMap()); 383 output = JSON.encode(result.toMap());
397 outputFile = outputFile + '.json'; 384 outputFile = outputFile + '.json';
398 } 385 }
399 _writeToFile(output, outputFile); 386 _writeToFile(output, outputFile);
400 } 387 }
401 388
402 /** 389 /// Returns true if a library name starts with an underscore, and false
403 * Returns true if a library name starts with an underscore, and false 390 /// otherwise.
404 * otherwise. 391 ///
405 * 392 /// An example that starts with _ is _js_helper.
406 * An example that starts with _ is _js_helper. 393 /// An example that contains ._ is dart._collection.dev
407 * An example that contains ._ is dart._collection.dev
408 */
409 // This is because LibraryMirror.isPrivate returns `false` all the time. 394 // This is because LibraryMirror.isPrivate returns `false` all the time.
410 bool _isLibraryPrivate(LibraryMirror mirror) { 395 bool _isLibraryPrivate(LibraryMirror mirror) {
411 var sdkLibrary = LIBRARIES[mirror.simpleName]; 396 var sdkLibrary = LIBRARIES[mirror.simpleName];
412 if (sdkLibrary != null) { 397 if (sdkLibrary != null) {
413 return !sdkLibrary.documented; 398 return !sdkLibrary.documented;
414 } else if (mirror.simpleName.startsWith('_') || 399 } else if (mirror.simpleName.startsWith('_') ||
415 mirror.simpleName.contains('._')) { 400 mirror.simpleName.contains('._')) {
416 return true; 401 return true;
417 } 402 }
418 return false; 403 return false;
419 } 404 }
420 405
421 /** 406 /// A declaration is private if itself is private, or the owner is private.
422 * A declaration is private if itself is private, or the owner is private.
423 */
424 // Issue(12202) - A declaration is public even if it's owner is private. 407 // Issue(12202) - A declaration is public even if it's owner is private.
425 bool _isHidden(DeclarationMirror mirror) { 408 bool _isHidden(DeclarationMirror mirror) {
426 if (mirror is LibraryMirror) { 409 if (mirror is LibraryMirror) {
427 return _isLibraryPrivate(mirror); 410 return _isLibraryPrivate(mirror);
428 } else if (mirror.owner is LibraryMirror) { 411 } else if (mirror.owner is LibraryMirror) {
429 return (mirror.isPrivate || _isLibraryPrivate(mirror.owner)); 412 return (mirror.isPrivate || _isLibraryPrivate(mirror.owner));
430 } else { 413 } else {
431 return (mirror.isPrivate || _isHidden(mirror.owner)); 414 return (mirror.isPrivate || _isHidden(mirror.owner));
432 } 415 }
433 } 416 }
434 417
435 bool _isVisible(Indexable item) { 418 bool _isVisible(Indexable item) {
436 return _includePrivate || !item.isPrivate; 419 return _includePrivate || !item.isPrivate;
437 } 420 }
438 421
439 /** 422 /// Returns a list of meta annotations assocated with a mirror.
440 * Returns a list of meta annotations assocated with a mirror.
441 */
442 List<Annotation> _annotations(DeclarationMirror mirror) { 423 List<Annotation> _annotations(DeclarationMirror mirror) {
443 var annotationMirrors = mirror.metadata.where((e) => 424 var annotationMirrors = mirror.metadata.where((e) =>
444 e is dart2js.Dart2JsConstructedConstantMirror); 425 e is dart2js.Dart2JsConstructedConstantMirror);
445 var annotations = []; 426 var annotations = [];
446 annotationMirrors.forEach((annotation) { 427 annotationMirrors.forEach((annotation) {
447 var parameterList = annotation.type.variables.values 428 var parameterList = annotation.type.variables.values
448 .where((e) => e.isFinal) 429 .where((e) => e.isFinal)
449 .map((e) => annotation.getField(e.simpleName).reflectee) 430 .map((e) => annotation.getField(e.simpleName).reflectee)
450 .where((e) => e != null) 431 .where((e) => e != null)
451 .toList(); 432 .toList();
452 if (validAnnotations.contains(docName(annotation.type))) { 433 if (!skippedAnnotations.contains(docName(annotation.type))) {
453 annotations.add(new Annotation(docName(annotation.type), 434 annotations.add(new Annotation(docName(annotation.type),
454 parameterList)); 435 parameterList));
455 } 436 }
456 }); 437 });
457 return annotations; 438 return annotations;
458 } 439 }
459 440
460 /** 441 /// Returns any documentation comments associated with a mirror with
461 * Returns any documentation comments associated with a mirror with 442 /// simple markdown converted to html.
462 * simple markdown converted to html.
463 */
464 String _commentToHtml(DeclarationMirror mirror) { 443 String _commentToHtml(DeclarationMirror mirror) {
465 String commentText; 444 String commentText;
466 mirror.metadata.forEach((metadata) { 445 mirror.metadata.forEach((metadata) {
467 if (metadata is CommentInstanceMirror) { 446 if (metadata is CommentInstanceMirror) {
468 CommentInstanceMirror comment = metadata; 447 CommentInstanceMirror comment = metadata;
469 if (comment.isDocComment) { 448 if (comment.isDocComment) {
470 if (commentText == null) { 449 if (commentText == null) {
471 commentText = comment.trimmedText; 450 commentText = comment.trimmedText;
472 } else { 451 } else {
473 commentText = '$commentText ${comment.trimmedText}'; 452 commentText = '$commentText ${comment.trimmedText}';
474 } 453 }
475 } 454 }
476 } 455 }
477 }); 456 });
478 457
479 commentText = commentText == null ? '' : 458 commentText = commentText == null ? '' :
480 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver, 459 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver,
481 inlineSyntaxes: markdownSyntaxes); 460 inlineSyntaxes: markdownSyntaxes);
482 return commentText; 461 return commentText;
483 } 462 }
484 463
485 /** 464 /// Generates MDN comments from database.json.
486 * Generates MDN comments from database.json.
487 */
488 void _mdnComment(Indexable item) { 465 void _mdnComment(Indexable item) {
489 //Check if MDN is loaded. 466 //Check if MDN is loaded.
490 if (_mdn == null) { 467 if (_mdn == null) {
491 // Reading in MDN related json file. 468 // Reading in MDN related json file.
492 var root = findRootDirectory(); 469 var root = findRootDirectory();
493 var mdnPath = path.join(root, 'utils/apidoc/mdn/database.json'); 470 var mdnPath = path.join(root, 'utils/apidoc/mdn/database.json');
494 _mdn = JSON.decode(new File(mdnPath).readAsStringSync()); 471 _mdn = JSON.decode(new File(mdnPath).readAsStringSync());
495 } 472 }
496 if (item.comment.isNotEmpty) return; 473 if (item.comment.isNotEmpty) return;
497 var domAnnotation = item.annotations.firstWhere( 474 var domAnnotation = item.annotations.firstWhere(
498 (e) => e.qualifiedName == 'metadata.DomName', orElse: () => null); 475 (e) => e.qualifiedName == 'metadata.DomName', orElse: () => null);
499 if (domAnnotation == null) return; 476 if (domAnnotation == null) return;
500 var domName = domAnnotation.parameters.single; 477 var domName = domAnnotation.parameters.single;
501 var parts = domName.split('.'); 478 var parts = domName.split('.');
502 if (parts.length == 2) item.comment = _mdnMemberComment(parts[0], parts[1]); 479 if (parts.length == 2) item.comment = _mdnMemberComment(parts[0], parts[1]);
503 if (parts.length == 1) item.comment = _mdnTypeComment(parts[0]); 480 if (parts.length == 1) item.comment = _mdnTypeComment(parts[0]);
504 } 481 }
505 482
506 /** 483 /// Generates the MDN Comment for variables and method DOM elements.
507 * Generates the MDN Comment for variables and method DOM elements.
508 */
509 String _mdnMemberComment(String type, String member) { 484 String _mdnMemberComment(String type, String member) {
510 var mdnType = _mdn[type]; 485 var mdnType = _mdn[type];
511 if (mdnType == null) return ''; 486 if (mdnType == null) return '';
512 var mdnMember = mdnType['members'].firstWhere((e) => e['name'] == member, 487 var mdnMember = mdnType['members'].firstWhere((e) => e['name'] == member,
513 orElse: () => null); 488 orElse: () => null);
514 if (mdnMember == null) return ''; 489 if (mdnMember == null) return '';
515 if (mdnMember['help'] == null || mdnMember['help'] == '') return ''; 490 if (mdnMember['help'] == null || mdnMember['help'] == '') return '';
516 if (mdnMember['url'] == null) return ''; 491 if (mdnMember['url'] == null) return '';
517 return _htmlMdn(mdnMember['help'], mdnMember['url']); 492 return _htmlMdn(mdnMember['help'], mdnMember['url']);
518 } 493 }
519 494
520 /** 495 /// Generates the MDN Comment for class DOM elements.
521 * Generates the MDN Comment for class DOM elements.
522 */
523 String _mdnTypeComment(String type) { 496 String _mdnTypeComment(String type) {
524 var mdnType = _mdn[type]; 497 var mdnType = _mdn[type];
525 if (mdnType == null) return ''; 498 if (mdnType == null) return '';
526 if (mdnType['summary'] == null || mdnType['summary'] == "") return ''; 499 if (mdnType['summary'] == null || mdnType['summary'] == "") return '';
527 if (mdnType['srcUrl'] == null) return ''; 500 if (mdnType['srcUrl'] == null) return '';
528 return _htmlMdn(mdnType['summary'], mdnType['srcUrl']); 501 return _htmlMdn(mdnType['summary'], mdnType['srcUrl']);
529 } 502 }
530 503
531 String _htmlMdn(String content, String url) { 504 String _htmlMdn(String content, String url) {
532 return '<div class="mdn">' + content.trim() + '<p class="mdn-note">' 505 return '<div class="mdn">' + content.trim() + '<p class="mdn-note">'
533 '<a href="' + url.trim() + '">from Mdn</a></p></div>'; 506 '<a href="' + url.trim() + '">from Mdn</a></p></div>';
534 } 507 }
535 508
536 /** 509 /// Converts all [foo] references in comments to <a>libraryName.foo</a>.
537 * Converts all [foo] references in comments to <a>libraryName.foo</a>.
538 */
539 markdown.Node fixReference(String name, LibraryMirror currentLibrary, 510 markdown.Node fixReference(String name, LibraryMirror currentLibrary,
540 ClassMirror currentClass, MemberMirror currentMember) { 511 ClassMirror currentClass, MemberMirror currentMember) {
541 var reference; 512 var reference;
542 var memberScope = currentMember == null ? 513 var memberScope = currentMember == null ?
543 null : currentMember.lookupInScope(name); 514 null : currentMember.lookupInScope(name);
544 if (memberScope != null) { 515 if (memberScope != null) {
545 reference = docName(memberScope); 516 reference = docName(memberScope);
546 } else { 517 } else {
547 var classScope = currentClass == null ? 518 var classScope = currentClass == null ?
548 null : currentClass.lookupInScope(name); 519 null : currentClass.lookupInScope(name);
549 if (classScope != null) { 520 if (classScope != null) {
550 reference = docName(classScope); 521 reference = docName(classScope);
551 } else { 522 } else {
552 var libraryScope = currentLibrary == null ? 523 var libraryScope = currentLibrary == null ?
553 null : currentLibrary.lookupInScope(name); 524 null : currentLibrary.lookupInScope(name);
554 reference = libraryScope != null ? docName(libraryScope) : name; 525 reference = libraryScope != null ? docName(libraryScope) : name;
555 } 526 }
556 } 527 }
557 return new markdown.Element.text('a', reference); 528 return new markdown.Element.text('a', reference);
558 } 529 }
559 530
560 /** 531 /// Returns a map of [Variable] objects constructed from [mirrorMap].
561 * Returns a map of [Variable] objects constructed from [mirrorMap].
562 */
563 Map<String, Variable> _variables(Map<String, VariableMirror> mirrorMap) { 532 Map<String, Variable> _variables(Map<String, VariableMirror> mirrorMap) {
564 var data = {}; 533 var data = {};
565 // TODO(janicejl): When map to map feature is created, replace the below with 534 // TODO(janicejl): When map to map feature is created, replace the below with
566 // a filter. Issue(#9590). 535 // a filter. Issue(#9590).
567 mirrorMap.forEach((String mirrorName, VariableMirror mirror) { 536 mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
568 _currentMember = mirror; 537 _currentMember = mirror;
569 if (_includePrivate || !_isHidden(mirror)) { 538 if (_includePrivate || !_isHidden(mirror)) {
570 entityMap[docName(mirror)] = new Variable(mirrorName, mirror.isFinal, 539 entityMap[docName(mirror)] = new Variable(mirrorName, mirror.isFinal,
571 mirror.isStatic, mirror.isConst, _type(mirror.type), 540 mirror.isStatic, mirror.isConst, _type(mirror.type),
572 _commentToHtml(mirror), _annotations(mirror), docName(mirror), 541 _commentToHtml(mirror), _annotations(mirror), docName(mirror),
573 _isHidden(mirror), docName(mirror.owner)); 542 _isHidden(mirror), docName(mirror.owner));
574 data[mirrorName] = entityMap[docName(mirror)]; 543 data[mirrorName] = entityMap[docName(mirror)];
575 } 544 }
576 }); 545 });
577 return data; 546 return data;
578 } 547 }
579 548
580 /** 549 /// Returns a map of [Method] objects constructed from [mirrorMap].
581 * Returns a map of [Method] objects constructed from [mirrorMap].
582 */
583 MethodGroup _methods(Map<String, MethodMirror> mirrorMap) { 550 MethodGroup _methods(Map<String, MethodMirror> mirrorMap) {
584 var group = new MethodGroup(); 551 var group = new MethodGroup();
585 mirrorMap.forEach((String mirrorName, MethodMirror mirror) { 552 mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
586 if (_includePrivate || !mirror.isPrivate) { 553 if (_includePrivate || !mirror.isPrivate) {
587 group.addMethod(mirror); 554 group.addMethod(mirror);
588 } 555 }
589 }); 556 });
590 return group; 557 return group;
591 } 558 }
592 559
593 /** 560 /// Returns the [Class] for the given [mirror] has already been created, and if
594 * Returns the [Class] for the given [mirror] has already been created, and if 561 /// it does not exist, creates it.
595 * it does not exist, creates it.
596 */
597 Class _class(ClassMirror mirror) { 562 Class _class(ClassMirror mirror) {
598 var clazz = entityMap[docName(mirror)]; 563 var clazz = entityMap[docName(mirror)];
599 if (clazz == null) { 564 if (clazz == null) {
600 var superclass = mirror.superclass != null ? 565 var superclass = mirror.superclass != null ?
601 _class(mirror.superclass) : null; 566 _class(mirror.superclass) : null;
602 var interfaces = 567 var interfaces =
603 mirror.superinterfaces.map((interface) => _class(interface)); 568 mirror.superinterfaces.map((interface) => _class(interface));
604 clazz = new Class(mirror.simpleName, superclass, _commentToHtml(mirror), 569 clazz = new Class(mirror.simpleName, superclass, _commentToHtml(mirror),
605 interfaces.toList(), _variables(mirror.variables), 570 interfaces.toList(), _variables(mirror.variables),
606 _methods(mirror.methods), _annotations(mirror), _generics(mirror), 571 _methods(mirror.methods), _annotations(mirror), _generics(mirror),
607 docName(mirror), _isHidden(mirror), docName(mirror.owner), 572 docName(mirror), _isHidden(mirror), docName(mirror.owner),
608 mirror.isAbstract); 573 mirror.isAbstract);
609 if (superclass != null) clazz.addInherited(superclass); 574 if (superclass != null) clazz.addInherited(superclass);
610 interfaces.forEach((interface) => clazz.addInherited(interface)); 575 interfaces.forEach((interface) => clazz.addInherited(interface));
611 entityMap[docName(mirror)] = clazz; 576 entityMap[docName(mirror)] = clazz;
612 } 577 }
613 return clazz; 578 return clazz;
614 } 579 }
615 580
616 /** 581 /// Returns a map of [Class] objects constructed from [mirrorMap].
617 * Returns a map of [Class] objects constructed from [mirrorMap].
618 */
619 ClassGroup _classes(Map<String, ClassMirror> mirrorMap) { 582 ClassGroup _classes(Map<String, ClassMirror> mirrorMap) {
620 var group = new ClassGroup(); 583 var group = new ClassGroup();
621 mirrorMap.forEach((String mirrorName, ClassMirror mirror) { 584 mirrorMap.forEach((String mirrorName, ClassMirror mirror) {
622 group.addClass(mirror); 585 group.addClass(mirror);
623 }); 586 });
624 return group; 587 return group;
625 } 588 }
626 589
627 /** 590 /// Returns a map of [Parameter] objects constructed from [mirrorList].
628 * Returns a map of [Parameter] objects constructed from [mirrorList].
629 */
630 Map<String, Parameter> _parameters(List<ParameterMirror> mirrorList) { 591 Map<String, Parameter> _parameters(List<ParameterMirror> mirrorList) {
631 var data = {}; 592 var data = {};
632 mirrorList.forEach((ParameterMirror mirror) { 593 mirrorList.forEach((ParameterMirror mirror) {
633 _currentMember = mirror; 594 _currentMember = mirror;
634 data[mirror.simpleName] = new Parameter(mirror.simpleName, 595 data[mirror.simpleName] = new Parameter(mirror.simpleName,
635 mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue, 596 mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue,
636 _type(mirror.type), mirror.defaultValue, 597 _type(mirror.type), mirror.defaultValue,
637 _annotations(mirror)); 598 _annotations(mirror));
638 }); 599 });
639 return data; 600 return data;
640 } 601 }
641 602
642 /** 603 /// Returns a map of [Generic] objects constructed from the class mirror.
643 * Returns a map of [Generic] objects constructed from the class mirror.
644 */
645 Map<String, Generic> _generics(ClassMirror mirror) { 604 Map<String, Generic> _generics(ClassMirror mirror) {
646 return new Map.fromIterable(mirror.typeVariables, 605 return new Map.fromIterable(mirror.typeVariables,
647 key: (e) => e.toString(), 606 key: (e) => e.toString(),
648 value: (e) => new Generic(e.toString(), e.upperBound.qualifiedName)); 607 value: (e) => new Generic(e.toString(), e.upperBound.qualifiedName));
649 } 608 }
650 609
651 /** 610 /// Returns a single [Type] object constructed from the Method.returnType
652 * Returns a single [Type] object constructed from the Method.returnType 611 /// Type mirror.
653 * Type mirror.
654 */
655 Type _type(TypeMirror mirror) { 612 Type _type(TypeMirror mirror) {
656 return new Type(docName(mirror), _typeGenerics(mirror)); 613 return new Type(docName(mirror), _typeGenerics(mirror));
657 } 614 }
658 615
659 /** 616 /// Returns a list of [Type] objects constructed from TypeMirrors.
660 * Returns a list of [Type] objects constructed from TypeMirrors.
661 */
662 List<Type> _typeGenerics(TypeMirror mirror) { 617 List<Type> _typeGenerics(TypeMirror mirror) {
663 if (mirror is ClassMirror && !mirror.isTypedef) { 618 if (mirror is ClassMirror && !mirror.isTypedef) {
664 var innerList = []; 619 var innerList = [];
665 mirror.typeArguments.forEach((e) { 620 mirror.typeArguments.forEach((e) {
666 innerList.add(new Type(docName(e), _typeGenerics(e))); 621 innerList.add(new Type(docName(e), _typeGenerics(e)));
667 }); 622 });
668 return innerList; 623 return innerList;
669 } 624 }
670 return []; 625 return [];
671 } 626 }
672 627
673 /** 628 /// Writes text to a file in the 'docs' directory.
674 * Writes text to a file in the 'docs' directory.
675 */
676 void _writeToFile(String text, String filename, {bool append: false}) { 629 void _writeToFile(String text, String filename, {bool append: false}) {
677 Directory dir = new Directory('docs'); 630 Directory dir = new Directory('docs');
678 if (!dir.existsSync()) { 631 if (!dir.existsSync()) {
679 dir.createSync(); 632 dir.createSync();
680 } 633 }
681 // We assume there's a single extra level of directory structure for packages. 634 // We assume there's a single extra level of directory structure for packages.
682 if (path.split(filename).length > 1) { 635 if (path.split(filename).length > 1) {
683 var subdir = new Directory(path.join('docs', path.dirname(filename))); 636 var subdir = new Directory(path.join('docs', path.dirname(filename)));
684 if (!subdir.existsSync()) { 637 if (!subdir.existsSync()) {
685 subdir.createSync(); 638 subdir.createSync();
686 } 639 }
687 } 640 }
688 641
689 File file = new File('docs/$filename'); 642 File file = new File('docs/$filename');
690 if (!file.existsSync()) { 643 if (!file.existsSync()) {
691 file.createSync(); 644 file.createSync();
692 } 645 }
693 file.writeAsStringSync(text, mode: append ? FileMode.APPEND : FileMode.WRITE); 646 file.writeAsStringSync(text, mode: append ? FileMode.APPEND : FileMode.WRITE);
694 } 647 }
695 648
696 /** 649 /// Transforms the map by calling toMap on each value in it.
697 * Transforms the map by calling toMap on each value in it.
698 */
699 Map recurseMap(Map inputMap) { 650 Map recurseMap(Map inputMap) {
700 var outputMap = {}; 651 var outputMap = {};
701 inputMap.forEach((key, value) { 652 inputMap.forEach((key, value) {
702 if (value is Map) { 653 if (value is Map) {
703 outputMap[key] = recurseMap(value); 654 outputMap[key] = recurseMap(value);
704 } else { 655 } else {
705 outputMap[key] = value.toMap(); 656 outputMap[key] = value.toMap();
706 } 657 }
707 }); 658 });
708 return outputMap; 659 return outputMap;
709 } 660 }
710 661
711 /** 662 /// A class representing all programming constructs, like library or class.
712 * A class representing all programming constructs, like library or class.
713 */
714 class Indexable { 663 class Indexable {
715 String name; 664 String name;
716 String get qualifiedName => fileName; 665 String get qualifiedName => fileName;
717 bool isPrivate; 666 bool isPrivate;
718 667
719 // The qualified name (for URL purposes) and the file name are the same, 668 // The qualified name (for URL purposes) and the file name are the same,
720 // of the form packageName/ClassName or packageName/ClassName.methodName. 669 // of the form packageName/ClassName or packageName/ClassName.methodName.
721 // This defines both the URL and the directory structure. 670 // This defines both the URL and the directory structure.
722 String get fileName => packagePrefix + ownerPrefix + name; 671 String get fileName => packagePrefix + ownerPrefix + name;
723 672
(...skipping 11 matching lines...) Expand all
735 684
736 /// Qualified Name of the owner of this Indexable Item. 685 /// Qualified Name of the owner of this Indexable Item.
737 /// For Library, owner will be ""; 686 /// For Library, owner will be "";
738 String owner; 687 String owner;
739 688
740 Indexable(this.name, this.comment, this.isPrivate, this.owner); 689 Indexable(this.name, this.comment, this.isPrivate, this.owner);
741 690
742 /// The type of this member to be used in index.txt. 691 /// The type of this member to be used in index.txt.
743 String get typeName => ''; 692 String get typeName => '';
744 693
745 /** 694 /// Creates a [Map] with this [Indexable]'s name and a preview comment.
746 * Creates a [Map] with this [Indexable]'s name and a preview comment.
747 */
748 Map get previewMap { 695 Map get previewMap {
749 var finalMap = { 'name' : name, 'qualifiedName' : qualifiedName }; 696 var finalMap = { 'name' : name, 'qualifiedName' : qualifiedName };
750 if (comment != '') { 697 if (comment != '') {
751 var index = comment.indexOf('</p>'); 698 var index = comment.indexOf('</p>');
752 finalMap['preview'] = '${comment.substring(0, index)}</p>'; 699 finalMap['preview'] = '${comment.substring(0, index)}</p>';
753 } 700 }
754 return finalMap; 701 return finalMap;
755 } 702 }
756 703
757 /// Return an informative [Object.toString] for debugging. 704 /// Return an informative [Object.toString] for debugging.
758 String toString() => "${super.toString()}(${name.toString()})"; 705 String toString() => "${super.toString()}(${name.toString()})";
759 706
760 /// Return a map representation of this type. 707 /// Return a map representation of this type.
761 Map toMap() {} 708 Map toMap() {}
762 } 709 }
763 710
764 /** 711 /// A class containing contents of a Dart library.
765 * A class containing contents of a Dart library.
766 */
767 class Library extends Indexable { 712 class Library extends Indexable {
768 713
769 /// Top-level variables in the library. 714 /// Top-level variables in the library.
770 Map<String, Variable> variables; 715 Map<String, Variable> variables;
771 716
772 /// Top-level functions in the library. 717 /// Top-level functions in the library.
773 MethodGroup functions; 718 MethodGroup functions;
774 719
775 /// Classes defined within the library 720 /// Classes defined within the library
776 ClassGroup classes; 721 ClassGroup classes;
(...skipping 27 matching lines...) Expand all
804 'variables': recurseMap(variables), 749 'variables': recurseMap(variables),
805 'functions': functions.toMap(), 750 'functions': functions.toMap(),
806 'classes': classes.toMap(), 751 'classes': classes.toMap(),
807 'packageName': packageName, 752 'packageName': packageName,
808 'packageIntro' : packageIntro 753 'packageIntro' : packageIntro
809 }; 754 };
810 755
811 String get typeName => 'library'; 756 String get typeName => 'library';
812 } 757 }
813 758
814 /** 759 /// A class containing contents of a Dart class.
815 * A class containing contents of a Dart class.
816 */
817 class Class extends Indexable { 760 class Class extends Indexable {
818 761
819 /// List of the names of interfaces that this class implements. 762 /// List of the names of interfaces that this class implements.
820 List<Class> interfaces = []; 763 List<Class> interfaces = [];
821 764
822 /// Names of classes that extends or implements this class. 765 /// Names of classes that extends or implements this class.
823 Set<String> subclasses = new Set<String>(); 766 Set<String> subclasses = new Set<String>();
824 767
825 /// Top-level variables in the class. 768 /// Top-level variables in the class.
826 Map<String, Variable> variables; 769 Map<String, Variable> variables;
(...skipping 18 matching lines...) Expand all
845 788
846 Class(String name, this.superclass, String comment, this.interfaces, 789 Class(String name, this.superclass, String comment, this.interfaces,
847 this.variables, this.methods, this.annotations, this.generics, 790 this.variables, this.methods, this.annotations, this.generics,
848 String qualifiedName, bool isPrivate, String owner, this.isAbstract) 791 String qualifiedName, bool isPrivate, String owner, this.isAbstract)
849 : super(name, comment, isPrivate, owner) { 792 : super(name, comment, isPrivate, owner) {
850 _mdnComment(this); 793 _mdnComment(this);
851 } 794 }
852 795
853 String get typeName => 'class'; 796 String get typeName => 'class';
854 797
855 /** 798 /// Returns a list of all the parent classes.
856 * Returns a list of all the parent classes.
857 */
858 List<Class> parent() { 799 List<Class> parent() {
859 var parent = superclass == null ? [] : [superclass]; 800 var parent = superclass == null ? [] : [superclass];
860 parent.addAll(interfaces); 801 parent.addAll(interfaces);
861 return parent; 802 return parent;
862 } 803 }
863 804
864 /** 805 /// Add all inherited variables and methods from the provided superclass.
865 * Add all inherited variables and methods from the provided superclass. 806 /// If [_includePrivate] is true, it also adds the variables and methods from
866 * If [_includePrivate] is true, it also adds the variables and methods from 807 /// the superclass.
867 * the superclass.
868 */
869 void addInherited(Class superclass) { 808 void addInherited(Class superclass) {
870 inheritedVariables.addAll(superclass.inheritedVariables); 809 inheritedVariables.addAll(superclass.inheritedVariables);
871 inheritedVariables.addAll(superclass.variables); 810 inheritedVariables.addAll(superclass.variables);
872 inheritedMethods.addInherited(superclass); 811 inheritedMethods.addInherited(superclass);
873 } 812 }
874 813
875 /** 814 /// Add the subclass to the class.
876 * Add the subclass to the class. 815 ///
877 * 816 /// If [this] is private, it will add the subclass to the list of subclasses i n
878 * If [this] is private, it will add the subclass to the list of subclasses in 817 /// the superclasses.
879 * the superclasses.
880 */
881 void addSubclass(Class subclass) { 818 void addSubclass(Class subclass) {
882 if (!_includePrivate && isPrivate) { 819 if (!_includePrivate && isPrivate) {
883 if (superclass != null) superclass.addSubclass(subclass); 820 if (superclass != null) superclass.addSubclass(subclass);
884 interfaces.forEach((interface) { 821 interfaces.forEach((interface) {
885 interface.addSubclass(subclass); 822 interface.addSubclass(subclass);
886 }); 823 });
887 } else { 824 } else {
888 subclasses.add(subclass.qualifiedName); 825 subclasses.add(subclass.qualifiedName);
889 } 826 }
890 } 827 }
891 828
892 /** 829 /// Check if this [Class] is an error or exception.
893 * Check if this [Class] is an error or exception.
894 */
895 bool isError() { 830 bool isError() {
896 if (qualifiedName == 'dart-core.Error' || 831 if (qualifiedName == 'dart-core.Error' ||
897 qualifiedName == 'dart-core.Exception') 832 qualifiedName == 'dart-core.Exception')
898 return true; 833 return true;
899 for (var interface in interfaces) { 834 for (var interface in interfaces) {
900 if (interface.isError()) return true; 835 if (interface.isError()) return true;
901 } 836 }
902 if (superclass == null) return false; 837 if (superclass == null) return false;
903 return superclass.isError(); 838 return superclass.isError();
904 } 839 }
905 840
906 /** 841 /// Check that the class exists in the owner library.
907 * Check that the class exists in the owner library. 842 ///
908 * 843 /// If it does not exist in the owner library, it is a mixin applciation and
909 * If it does not exist in the owner library, it is a mixin applciation and 844 /// should be removed.
910 * should be removed.
911 */
912 void makeValid() { 845 void makeValid() {
913 var library = entityMap[owner]; 846 var library = entityMap[owner];
914 if (library != null && !library.classes.containsKey(name)) { 847 if (library != null && !library.classes.containsKey(name)) {
915 this.isPrivate = true; 848 this.isPrivate = true;
916 // Since we are now making the mixin a private class, make all elements 849 // Since we are now making the mixin a private class, make all elements
917 // with the mixin as an owner private too. 850 // with the mixin as an owner private too.
918 entityMap.values.where((e) => e.owner == qualifiedName) 851 entityMap.values.where((e) => e.owner == qualifiedName)
919 .forEach((element) => element.isPrivate = true); 852 .forEach((element) => element.isPrivate = true);
920 // Move the subclass up to the next public superclass 853 // Move the subclass up to the next public superclass
921 subclasses.forEach((subclass) => addSubclass(entityMap[subclass])); 854 subclasses.forEach((subclass) => addSubclass(entityMap[subclass]));
922 } 855 }
923 } 856 }
924 857
925 /** 858 /// Makes sure that all methods with inherited equivalents have comments.
926 * Makes sure that all methods with inherited equivalents have comments.
927 */
928 void ensureComments() { 859 void ensureComments() {
929 inheritedMethods.forEach((qualifiedName, inheritedMethod) { 860 inheritedMethods.forEach((qualifiedName, inheritedMethod) {
930 var method = methods[qualifiedName]; 861 var method = methods[qualifiedName];
931 if (method != null) method.ensureCommentFor(inheritedMethod); 862 if (method != null) method.ensureCommentFor(inheritedMethod);
932 }); 863 });
933 } 864 }
934 865
935 /** 866 /// If a class extends a private superclass, find the closest public superclas s
936 * If a class extends a private superclass, find the closest public superclass 867 /// of the private superclass.
937 * of the private superclass.
938 */
939 String validSuperclass() { 868 String validSuperclass() {
940 if (superclass == null) return 'dart.core.Object'; 869 if (superclass == null) return 'dart.core.Object';
941 if (_isVisible(superclass)) return superclass.qualifiedName; 870 if (_isVisible(superclass)) return superclass.qualifiedName;
942 return superclass.validSuperclass(); 871 return superclass.validSuperclass();
943 } 872 }
944 873
945 /// Generates a map describing the [Class] object. 874 /// Generates a map describing the [Class] object.
946 Map toMap() => { 875 Map toMap() => {
947 'name': name, 876 'name': name,
948 'qualifiedName': qualifiedName, 877 'qualifiedName': qualifiedName,
949 'comment': comment, 878 'comment': comment,
950 'isAbstract' : isAbstract, 879 'isAbstract' : isAbstract,
951 'superclass': validSuperclass(), 880 'superclass': validSuperclass(),
952 'implements': interfaces.where(_isVisible) 881 'implements': interfaces.where(_isVisible)
953 .map((e) => e.qualifiedName).toList(), 882 .map((e) => e.qualifiedName).toList(),
954 'subclass': subclasses.toList(), 883 'subclass': subclasses.toList(),
955 'variables': recurseMap(variables), 884 'variables': recurseMap(variables),
956 'inheritedVariables': recurseMap(inheritedVariables), 885 'inheritedVariables': recurseMap(inheritedVariables),
957 'methods': methods.toMap(), 886 'methods': methods.toMap(),
958 'inheritedMethods': inheritedMethods.toMap(), 887 'inheritedMethods': inheritedMethods.toMap(),
959 'annotations': annotations.map((a) => a.toMap()).toList(), 888 'annotations': annotations.map((a) => a.toMap()).toList(),
960 'generics': recurseMap(generics) 889 'generics': recurseMap(generics)
961 }; 890 };
962 } 891 }
963 892
964 /** 893 /// A container to categorize classes into the following groups: abstract
965 * A container to categorize classes into the following groups: abstract 894 /// classes, regular classes, typedefs, and errors.
966 * classes, regular classes, typedefs, and errors.
967 */
968 class ClassGroup { 895 class ClassGroup {
969 Map<String, Class> classes = {}; 896 Map<String, Class> classes = {};
970 Map<String, Typedef> typedefs = {}; 897 Map<String, Typedef> typedefs = {};
971 Map<String, Class> errors = {}; 898 Map<String, Class> errors = {};
972 899
973 void addClass(ClassMirror mirror) { 900 void addClass(ClassMirror mirror) {
974 _currentClass = mirror; 901 _currentClass = mirror;
975 if (mirror.isTypedef) { 902 if (mirror.isTypedef) {
976 // This is actually a Dart2jsTypedefMirror, and it does define value, 903 // This is actually a Dart2jsTypedefMirror, and it does define value,
977 // but we don't have visibility to that type. 904 // but we don't have visibility to that type.
(...skipping 21 matching lines...) Expand all
999 if (clazz.isError()) { 926 if (clazz.isError()) {
1000 errors[mirror.simpleName] = clazz; 927 errors[mirror.simpleName] = clazz;
1001 } else if (mirror.isClass) { 928 } else if (mirror.isClass) {
1002 classes[mirror.simpleName] = clazz; 929 classes[mirror.simpleName] = clazz;
1003 } else { 930 } else {
1004 throw new ArgumentError('${mirror.simpleName} - no class type match. '); 931 throw new ArgumentError('${mirror.simpleName} - no class type match. ');
1005 } 932 }
1006 } 933 }
1007 } 934 }
1008 935
1009 /** 936 /// Checks if the given name is a key for any of the Class Maps.
1010 * Checks if the given name is a key for any of the Class Maps.
1011 */
1012 bool containsKey(String name) { 937 bool containsKey(String name) {
1013 return classes.containsKey(name) || errors.containsKey(name); 938 return classes.containsKey(name) || errors.containsKey(name);
1014 } 939 }
1015 940
1016 Map toMap() => { 941 Map toMap() => {
1017 'class': classes.values.where(_isVisible) 942 'class': classes.values.where(_isVisible)
1018 .map((e) => e.previewMap).toList(), 943 .map((e) => e.previewMap).toList(),
1019 'typedef': recurseMap(typedefs), 944 'typedef': recurseMap(typedefs),
1020 'error': errors.values.where(_isVisible) 945 'error': errors.values.where(_isVisible)
1021 .map((e) => e.previewMap).toList() 946 .map((e) => e.previewMap).toList()
(...skipping 22 matching lines...) Expand all
1044 'comment': comment, 969 'comment': comment,
1045 'return': returnType, 970 'return': returnType,
1046 'parameters': recurseMap(parameters), 971 'parameters': recurseMap(parameters),
1047 'annotations': annotations.map((a) => a.toMap()).toList(), 972 'annotations': annotations.map((a) => a.toMap()).toList(),
1048 'generics': recurseMap(generics) 973 'generics': recurseMap(generics)
1049 }; 974 };
1050 975
1051 String get typeName => 'typedef'; 976 String get typeName => 'typedef';
1052 } 977 }
1053 978
1054 /** 979 /// A class containing properties of a Dart variable.
1055 * A class containing properties of a Dart variable.
1056 */
1057 class Variable extends Indexable { 980 class Variable extends Indexable {
1058 981
1059 bool isFinal; 982 bool isFinal;
1060 bool isStatic; 983 bool isStatic;
1061 bool isConst; 984 bool isConst;
1062 Type type; 985 Type type;
1063 986
1064 /// List of the meta annotations on the variable. 987 /// List of the meta annotations on the variable.
1065 List<Annotation> annotations; 988 List<Annotation> annotations;
1066 989
(...skipping 11 matching lines...) Expand all
1078 'final': isFinal.toString(), 1001 'final': isFinal.toString(),
1079 'static': isStatic.toString(), 1002 'static': isStatic.toString(),
1080 'constant': isConst.toString(), 1003 'constant': isConst.toString(),
1081 'type': new List.filled(1, type.toMap()), 1004 'type': new List.filled(1, type.toMap()),
1082 'annotations': annotations.map((a) => a.toMap()).toList() 1005 'annotations': annotations.map((a) => a.toMap()).toList()
1083 }; 1006 };
1084 1007
1085 String get typeName => 'property'; 1008 String get typeName => 'property';
1086 } 1009 }
1087 1010
1088 /** 1011 /// A class containing properties of a Dart method.
1089 * A class containing properties of a Dart method.
1090 */
1091 class Method extends Indexable { 1012 class Method extends Indexable {
1092 1013
1093 /// Parameters for this method. 1014 /// Parameters for this method.
1094 Map<String, Parameter> parameters; 1015 Map<String, Parameter> parameters;
1095 1016
1096 bool isStatic; 1017 bool isStatic;
1097 bool isAbstract; 1018 bool isAbstract;
1098 bool isConst; 1019 bool isConst;
1099 bool isConstructor; 1020 bool isConstructor;
1100 bool isGetter; 1021 bool isGetter;
1101 bool isSetter; 1022 bool isSetter;
1102 bool isOperator; 1023 bool isOperator;
1103 Type returnType; 1024 Type returnType;
1104 1025
1105 /// Qualified name to state where the comment is inherited from. 1026 /// Qualified name to state where the comment is inherited from.
1106 String commentInheritedFrom = ""; 1027 String commentInheritedFrom = "";
1107 1028
1108 /// List of the meta annotations on the method. 1029 /// List of the meta annotations on the method.
1109 List<Annotation> annotations; 1030 List<Annotation> annotations;
1110 1031
1111 Method(String name, this.isStatic, this.isAbstract, this.isConst, 1032 Method(String name, this.isStatic, this.isAbstract, this.isConst,
1112 this.returnType, String comment, this.parameters, this.annotations, 1033 this.returnType, String comment, this.parameters, this.annotations,
1113 String qualifiedName, bool isPrivate, String owner, this.isConstructor, 1034 String qualifiedName, bool isPrivate, String owner, this.isConstructor,
1114 this.isGetter, this.isSetter, this.isOperator) 1035 this.isGetter, this.isSetter, this.isOperator)
1115 : super(name, comment, isPrivate, owner) { 1036 : super(name, comment, isPrivate, owner) {
1116 _mdnComment(this); 1037 _mdnComment(this);
1117 } 1038 }
1118 1039
1119 /** 1040 /// Makes sure that the method with an inherited equivalent have comments.
1120 * Makes sure that the method with an inherited equivalent have comments.
1121 */
1122 void ensureCommentFor(Method inheritedMethod) { 1041 void ensureCommentFor(Method inheritedMethod) {
1123 if (comment.isNotEmpty) return; 1042 if (comment.isNotEmpty) return;
1124 (entityMap[inheritedMethod.owner] as Class).ensureComments(); 1043 (entityMap[inheritedMethod.owner] as Class).ensureComments();
1125 comment = inheritedMethod.comment; 1044 comment = inheritedMethod.comment;
1126 commentInheritedFrom = inheritedMethod.commentInheritedFrom == '' ? 1045 commentInheritedFrom = inheritedMethod.commentInheritedFrom == '' ?
1127 inheritedMethod.qualifiedName : inheritedMethod.commentInheritedFrom; 1046 inheritedMethod.qualifiedName : inheritedMethod.commentInheritedFrom;
1128 } 1047 }
1129 1048
1130 /// Generates a map describing the [Method] object. 1049 /// Generates a map describing the [Method] object.
1131 Map toMap() => { 1050 Map toMap() => {
1132 'name': name, 1051 'name': name,
1133 'qualifiedName': qualifiedName, 1052 'qualifiedName': qualifiedName,
1134 'comment': comment, 1053 'comment': comment,
1135 'commentFrom': commentInheritedFrom, 1054 'commentFrom': commentInheritedFrom,
1136 'static': isStatic.toString(), 1055 'static': isStatic.toString(),
1137 'abstract': isAbstract.toString(), 1056 'abstract': isAbstract.toString(),
1138 'constant': isConst.toString(), 1057 'constant': isConst.toString(),
1139 'return': new List.filled(1, returnType.toMap()), 1058 'return': new List.filled(1, returnType.toMap()),
1140 'parameters': recurseMap(parameters), 1059 'parameters': recurseMap(parameters),
1141 'annotations': annotations.map((a) => a.toMap()).toList() 1060 'annotations': annotations.map((a) => a.toMap()).toList()
1142 }; 1061 };
1143 1062
1144 String get typeName => isConstructor ? 'constructor' : 1063 String get typeName => isConstructor ? 'constructor' :
1145 isGetter ? 'getter' : isSetter ? 'setter' : 1064 isGetter ? 'getter' : isSetter ? 'setter' :
1146 isOperator ? 'operator' : 'method'; 1065 isOperator ? 'operator' : 'method';
1147 } 1066 }
1148 1067
1149 /** 1068 /// A container to categorize methods into the following groups: setters,
1150 * A container to categorize methods into the following groups: setters, 1069 /// getters, constructors, operators, regular methods.
1151 * getters, constructors, operators, regular methods.
1152 */
1153 class MethodGroup { 1070 class MethodGroup {
1154 Map<String, Method> setters = {}; 1071 Map<String, Method> setters = {};
1155 Map<String, Method> getters = {}; 1072 Map<String, Method> getters = {};
1156 Map<String, Method> constructors = {}; 1073 Map<String, Method> constructors = {};
1157 Map<String, Method> operators = {}; 1074 Map<String, Method> operators = {};
1158 Map<String, Method> regularMethods = {}; 1075 Map<String, Method> regularMethods = {};
1159 1076
1160 void addMethod(MethodMirror mirror) { 1077 void addMethod(MethodMirror mirror) {
1161 var method = new Method(mirror.simpleName, mirror.isStatic, 1078 var method = new Method(mirror.simpleName, mirror.isStatic,
1162 mirror.isAbstract, mirror.isConstConstructor, _type(mirror.returnType), 1079 mirror.isAbstract, mirror.isConstConstructor, _type(mirror.returnType),
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1211 } 1128 }
1212 1129
1213 void forEach(void f(String key, Method value)) { 1130 void forEach(void f(String key, Method value)) {
1214 setters.forEach(f); 1131 setters.forEach(f);
1215 getters.forEach(f); 1132 getters.forEach(f);
1216 operators.forEach(f); 1133 operators.forEach(f);
1217 regularMethods.forEach(f); 1134 regularMethods.forEach(f);
1218 } 1135 }
1219 } 1136 }
1220 1137
1221 /** 1138 /// A class containing properties of a Dart method/function parameter.
1222 * A class containing properties of a Dart method/function parameter.
1223 */
1224 class Parameter { 1139 class Parameter {
1225 1140
1226 String name; 1141 String name;
1227 bool isOptional; 1142 bool isOptional;
1228 bool isNamed; 1143 bool isNamed;
1229 bool hasDefaultValue; 1144 bool hasDefaultValue;
1230 Type type; 1145 Type type;
1231 String defaultValue; 1146 String defaultValue;
1232 1147
1233 /// List of the meta annotations on the parameter. 1148 /// List of the meta annotations on the parameter.
1234 List<Annotation> annotations; 1149 List<Annotation> annotations;
1235 1150
1236 Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue, 1151 Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue,
1237 this.type, this.defaultValue, this.annotations); 1152 this.type, this.defaultValue, this.annotations);
1238 1153
1239 /// Generates a map describing the [Parameter] object. 1154 /// Generates a map describing the [Parameter] object.
1240 Map toMap() => { 1155 Map toMap() => {
1241 'name': name, 1156 'name': name,
1242 'optional': isOptional.toString(), 1157 'optional': isOptional.toString(),
1243 'named': isNamed.toString(), 1158 'named': isNamed.toString(),
1244 'default': hasDefaultValue.toString(), 1159 'default': hasDefaultValue.toString(),
1245 'type': new List.filled(1, type.toMap()), 1160 'type': new List.filled(1, type.toMap()),
1246 'value': defaultValue, 1161 'value': defaultValue,
1247 'annotations': annotations.map((a) => a.toMap()).toList() 1162 'annotations': annotations.map((a) => a.toMap()).toList()
1248 }; 1163 };
1249 } 1164 }
1250 1165
1251 /** 1166 /// A class containing properties of a Generic.
1252 * A class containing properties of a Generic.
1253 */
1254 class Generic { 1167 class Generic {
1255 String name; 1168 String name;
1256 String type; 1169 String type;
1257 1170
1258 Generic(this.name, this.type); 1171 Generic(this.name, this.type);
1259 1172
1260 Map toMap() => { 1173 Map toMap() => {
1261 'name': name, 1174 'name': name,
1262 'type': type 1175 'type': type
1263 }; 1176 };
1264 } 1177 }
1265 1178
1266 /** 1179 /// Holds the name of a return type, and its generic type parameters.
1267 * Holds the name of a return type, and its generic type parameters. 1180 ///
1268 * 1181 /// Return types are of a form [outer]<[inner]>.
1269 * Return types are of a form [outer]<[inner]>. 1182 /// If there is no [inner] part, [inner] will be an empty list.
1270 * If there is no [inner] part, [inner] will be an empty list. 1183 ///
1271 * 1184 /// For example:
1272 * For example: 1185 /// int size()
1273 * int size() 1186 /// "return" :
1274 * "return" : 1187 /// - "outer" : "dart-core.int"
1275 * - "outer" : "dart-core.int" 1188 /// "inner" :
1276 * "inner" : 1189 ///
1277 * 1190 /// List<String> toList()
1278 * List<String> toList() 1191 /// "return" :
1279 * "return" : 1192 /// - "outer" : "dart-core.List"
1280 * - "outer" : "dart-core.List" 1193 /// "inner" :
1281 * "inner" : 1194 /// - "outer" : "dart-core.String"
1282 * - "outer" : "dart-core.String" 1195 /// "inner" :
1283 * "inner" : 1196 ///
1284 * 1197 /// Map<String, List<int>>
1285 * Map<String, List<int>> 1198 /// "return" :
1286 * "return" : 1199 /// - "outer" : "dart-core.Map"
1287 * - "outer" : "dart-core.Map" 1200 /// "inner" :
1288 * "inner" : 1201 /// - "outer" : "dart-core.String"
1289 * - "outer" : "dart-core.String" 1202 /// "inner" :
1290 * "inner" : 1203 /// - "outer" : "dart-core.List"
1291 * - "outer" : "dart-core.List" 1204 /// "inner" :
1292 * "inner" : 1205 /// - "outer" : "dart-core.int"
1293 * - "outer" : "dart-core.int" 1206 /// "inner" :
1294 * "inner" :
1295 */
1296 class Type { 1207 class Type {
1297 String outer; 1208 String outer;
1298 List<Type> inner; 1209 List<Type> inner;
1299 1210
1300 Type(this.outer, this.inner); 1211 Type(this.outer, this.inner);
1301 1212
1302 Map toMap() => { 1213 Map toMap() => {
1303 'outer': outer, 1214 'outer': outer,
1304 'inner': inner.map((e) => e.toMap()).toList() 1215 'inner': inner.map((e) => e.toMap()).toList()
1305 }; 1216 };
1306 } 1217 }
1307 1218
1308 /** 1219 /// Holds the name of the annotation, and its parameters.
1309 * Holds the name of the annotation, and its parameters.
1310 */
1311 class Annotation { 1220 class Annotation {
1312 String qualifiedName; 1221 String qualifiedName;
1313 List<String> parameters; 1222 List<String> parameters;
1314 1223
1315 Annotation(this.qualifiedName, this.parameters); 1224 Annotation(this.qualifiedName, this.parameters);
1316 1225
1317 Map toMap() => { 1226 Map toMap() => {
1318 'name': qualifiedName, 1227 'name': qualifiedName,
1319 'parameters': parameters 1228 'parameters': parameters
1320 }; 1229 };
1321 } 1230 }
1322 1231
1323 /// Given a mirror, returns its qualified name, but following the conventions 1232 /// Given a mirror, returns its qualified name, but following the conventions
1324 /// we're using in Dartdoc, which is that library names with dots in them 1233 /// we're using in Dartdoc, which is that library names with dots in them
1325 /// have them replaced with hyphens. 1234 /// have them replaced with hyphens.
1326 String docName(DeclarationMirror m) { 1235 String docName(DeclarationMirror m) {
1327 if (m is LibraryMirror) { 1236 if (m is LibraryMirror) {
1328 return (m as LibraryMirror).qualifiedName.replaceAll('.','-'); 1237 return (m as LibraryMirror).qualifiedName.replaceAll('.','-');
1329 } 1238 }
1330 var owner = m.owner; 1239 var owner = m.owner;
1331 if (owner == null) return m.qualifiedName; 1240 if (owner == null) return m.qualifiedName;
1332 // For the unnamed constructor we just return the class name. 1241 // For the unnamed constructor we just return the class name.
1333 if (m.simpleName == '') return docName(owner); 1242 if (m.simpleName == '') return docName(owner);
1334 return docName(owner) + '.' + m.simpleName; 1243 return docName(owner) + '.' + m.simpleName;
1335 } 1244 }
OLDNEW
« pkg/docgen/bin/dartdoc.py ('K') | « pkg/docgen/bin/upload_docgen.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698