OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * **docgen** is a tool for creating machine readable representations of Dart | 6 * **docgen** is a tool for creating machine readable representations of Dart |
7 * code metadata, including: classes, members, comments and annotations. | 7 * code metadata, including: classes, members, comments and annotations. |
8 * | 8 * |
9 * docgen is run on a `.dart` file or a directory containing `.dart` files. | 9 * docgen is run on a `.dart` file or a directory containing `.dart` files. |
10 * | 10 * |
(...skipping 12 matching lines...) Expand all Loading... |
23 import 'package:markdown/markdown.dart' as markdown; | 23 import 'package:markdown/markdown.dart' as markdown; |
24 import 'package:path/path.dart' as path; | 24 import 'package:path/path.dart' as path; |
25 | 25 |
26 import 'dart2yaml.dart'; | 26 import 'dart2yaml.dart'; |
27 import 'src/io.dart'; | 27 import 'src/io.dart'; |
28 import '../../../sdk/lib/_internal/compiler/compiler.dart' as api; | 28 import '../../../sdk/lib/_internal/compiler/compiler.dart' as api; |
29 import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart'; | 29 import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart'; |
30 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro
r.dart' | 30 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro
r.dart' |
31 as dart2js; | 31 as dart2js; |
32 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart'
; | 32 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart'
; |
33 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.
dart'; | |
34 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.
dart'; | 33 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.
dart'; |
35 import '../../../sdk/lib/_internal/libraries.dart'; | 34 import '../../../sdk/lib/_internal/libraries.dart'; |
36 | 35 |
37 var logger = new Logger('Docgen'); | 36 var logger = new Logger('Docgen'); |
38 | 37 |
39 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] [fooDir/barFile]'; | 38 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] [fooDir/barFile]'; |
40 | 39 |
41 /// Current library being documented to be used for comment links. | 40 /// Current library being documented to be used for comment links. |
42 LibraryMirror _currentLibrary; | 41 LibraryMirror _currentLibrary; |
43 | 42 |
44 /// Current class being documented to be used for comment links. | 43 /// Current class being documented to be used for comment links. |
45 ClassMirror _currentClass; | 44 ClassMirror _currentClass; |
46 | 45 |
47 /// Current member being documented to be used for comment links. | 46 /// Current member being documented to be used for comment links. |
48 MemberMirror _currentMember; | 47 MemberMirror _currentMember; |
49 | 48 |
50 /// Support for [:foo:]-style code comments to the markdown parser. | 49 /// Support for [:foo:]-style code comments to the markdown parser. |
51 List<markdown.InlineSyntax> markdownSyntaxes = | 50 List<markdown.InlineSyntax> markdownSyntaxes = |
52 [new markdown.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')]; | 51 [new markdown.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')]; |
53 | 52 |
54 /// Resolves reference links in doc comments. | 53 /// Resolves reference links in doc comments. |
55 markdown.Resolver linkResolver; | 54 markdown.Resolver linkResolver; |
56 | 55 |
57 /// Index of all indexable items. This also ensures that no class is | 56 /// Index of all indexable items. This also ensures that no class is |
58 /// created more than once. | 57 /// created more than once. |
59 Map<String, Indexable> entityMap = new Map<String, Indexable>(); | 58 Map<String, Indexable> entityMap = new Map<String, Indexable>(); |
60 | 59 |
61 /// This is set from the command line arguments flag --include-private | 60 /// This is set from the command line arguments flag --include-private |
62 bool _includePrivate = false; | 61 bool _includePrivate = false; |
63 | 62 |
64 /** | 63 /** |
65 * Docgen constructor initializes the link resolver for markdown parsing. | 64 * Docgen constructor initializes the link resolver for markdown parsing. |
66 * Also initializes the command line arguments. | 65 * Also initializes the command line arguments. |
67 * | 66 * |
68 * [packageRoot] is the packages directory of the directory being analyzed. | 67 * [packageRoot] is the packages directory of the directory being analyzed. |
69 * If [includeSdk] is `true`, then any SDK libraries explicitly imported will | 68 * If [includeSdk] is `true`, then any SDK libraries explicitly imported will |
70 * also be documented. | 69 * also be documented. |
71 * If [parseSdk] is `true`, then all Dart SDK libraries will be documented. | 70 * If [parseSdk] is `true`, then all Dart SDK libraries will be documented. |
72 * This option is useful when only the SDK libraries are needed. | 71 * This option is useful when only the SDK libraries are needed. |
73 * | 72 * |
74 * Returns `true` if docgen sucessfuly completes. | 73 * Returns `true` if docgen sucessfuly completes. |
75 */ | 74 */ |
76 Future<bool> docgen(List<String> files, {String packageRoot, | 75 Future<bool> docgen(List<String> files, {String packageRoot, |
77 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, | 76 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, |
78 bool parseSdk: false, bool append: false}) { | 77 bool parseSdk: false, bool append: false}) { |
79 _includePrivate = includePrivate; | 78 _includePrivate = includePrivate; |
80 if (!append) { | 79 if (!append) { |
81 var dir = new Directory('docs'); | 80 var dir = new Directory('docs'); |
82 if (dir.existsSync()) dir.deleteSync(recursive: true); | 81 if (dir.existsSync()) dir.deleteSync(recursive: true); |
83 } | 82 } |
84 | 83 |
85 if (packageRoot == null && !parseSdk) { | 84 if (packageRoot == null && !parseSdk) { |
86 var type = FileSystemEntity.typeSync(files.first); | 85 var type = FileSystemEntity.typeSync(files.first); |
87 if (type == FileSystemEntityType.DIRECTORY) { | 86 if (type == FileSystemEntityType.DIRECTORY) { |
88 packageRoot = _findPackageRoot(files.first); | 87 packageRoot = _findPackageRoot(files.first); |
89 } else if (type == FileSystemEntityType.FILE) { | 88 } else if (type == FileSystemEntityType.FILE) { |
90 logger.warning('WARNING: No package root defined. If Docgen fails, try ' | 89 logger.warning('WARNING: No package root defined. If Docgen fails, try ' |
91 'again by setting the --package-root option.'); | 90 'again by setting the --package-root option.'); |
92 } | 91 } |
93 } | 92 } |
94 logger.info('Package Root: ${packageRoot}'); | 93 logger.info('Package Root: ${packageRoot}'); |
(...skipping 26 matching lines...) Expand all Loading... |
121 } | 120 } |
122 return libraries; | 121 return libraries; |
123 } | 122 } |
124 | 123 |
125 List<String> _listDartFromDir(String args) { | 124 List<String> _listDartFromDir(String args) { |
126 var files = listDir(args, recursive: true); | 125 var files = listDir(args, recursive: true); |
127 // To avoid anaylzing package files twice, only files with paths not | 126 // To avoid anaylzing package files twice, only files with paths not |
128 // containing '/packages' will be added. The only exception is if the file to | 127 // containing '/packages' will be added. The only exception is if the file to |
129 // analyze already has a '/package' in its path. | 128 // analyze already has a '/package' in its path. |
130 return files.where((f) => f.endsWith('.dart') && | 129 return files.where((f) => f.endsWith('.dart') && |
131 (!f.contains('${path.separator}packages') || | 130 (!f.contains('${path.separator}packages') || |
132 args.contains('${path.separator}packages'))).toList() | 131 args.contains('${path.separator}packages'))).toList() |
133 ..forEach((lib) => logger.info('Added to libraries: $lib')); | 132 ..forEach((lib) => logger.info('Added to libraries: $lib')); |
134 } | 133 } |
135 | 134 |
136 String _findPackageRoot(String directory) { | 135 String _findPackageRoot(String directory) { |
137 var files = listDir(directory, recursive: true); | 136 var files = listDir(directory, recursive: true); |
138 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. | 137 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. |
139 String packageRoot = files.firstWhere((f) => | 138 String packageRoot = files.firstWhere((f) => |
140 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => ''); | 139 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => ''); |
141 if (packageRoot != '') { | 140 if (packageRoot != '') { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 * for static inspection of the source code. | 174 * for static inspection of the source code. |
176 */ | 175 */ |
177 Future<MirrorSystem> _analyzeLibraries(List<String> libraries, | 176 Future<MirrorSystem> _analyzeLibraries(List<String> libraries, |
178 String libraryRoot, {String packageRoot}) { | 177 String libraryRoot, {String packageRoot}) { |
179 SourceFileProvider provider = new SourceFileProvider(); | 178 SourceFileProvider provider = new SourceFileProvider(); |
180 api.DiagnosticHandler diagnosticHandler = | 179 api.DiagnosticHandler diagnosticHandler = |
181 new FormattingDiagnosticHandler(provider).diagnosticHandler; | 180 new FormattingDiagnosticHandler(provider).diagnosticHandler; |
182 Uri libraryUri = new Uri(scheme: 'file', path: appendSlash(libraryRoot)); | 181 Uri libraryUri = new Uri(scheme: 'file', path: appendSlash(libraryRoot)); |
183 Uri packageUri = null; | 182 Uri packageUri = null; |
184 if (packageRoot != null) { | 183 if (packageRoot != null) { |
185 packageUri = new Uri(scheme: 'file', path: appendSlash(packageRoot)); | 184 packageUri = new Uri(scheme: 'file', path: appendSlash(packageRoot)); |
186 } | 185 } |
187 List<Uri> librariesUri = <Uri>[]; | 186 List<Uri> librariesUri = <Uri>[]; |
188 libraries.forEach((library) { | 187 libraries.forEach((library) { |
189 librariesUri.add(currentDirectory.resolve(library)); | 188 librariesUri.add(currentDirectory.resolve(library)); |
190 }); | 189 }); |
191 return dart2js.analyze(librariesUri, libraryUri, packageUri, | 190 return dart2js.analyze(librariesUri, libraryUri, packageUri, |
192 provider.readStringFromUri, diagnosticHandler, | 191 provider.readStringFromUri, diagnosticHandler, |
193 ['--preserve-comments', '--categories=Client,Server']) | 192 ['--preserve-comments', '--categories=Client,Server']) |
194 ..catchError((error) { | 193 ..catchError((error) { |
195 logger.severe('Error: Failed to create mirror system. '); | 194 logger.severe('Error: Failed to create mirror system. '); |
(...skipping 11 matching lines...) Expand all Loading... |
207 void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false, | 206 void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false, |
208 bool outputToYaml: true, bool append: false, bool parseSdk: false}) { | 207 bool outputToYaml: true, bool append: false, bool parseSdk: false}) { |
209 libs.forEach((lib) { | 208 libs.forEach((lib) { |
210 // Files belonging to the SDK have a uri that begins with 'dart:'. | 209 // Files belonging to the SDK have a uri that begins with 'dart:'. |
211 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { | 210 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { |
212 var library = generateLibrary(lib); | 211 var library = generateLibrary(lib); |
213 entityMap[library.qualifiedName] = library; | 212 entityMap[library.qualifiedName] = library; |
214 } | 213 } |
215 }); | 214 }); |
216 // After everything is created, do a pass through all classes to make sure no | 215 // After everything is created, do a pass through all classes to make sure no |
217 // intermediate classes created by mixins are included. | 216 // intermediate classes created by mixins are included. |
218 entityMap.values.where((e) => e is Class).forEach((c) => c.makeValid()); | 217 entityMap.values.where((e) => e is Class).forEach((c) => c.makeValid()); |
219 // Everything is a subclass of Object, therefore empty the list to avoid a | 218 // Everything is a subclass of Object, therefore empty the list to avoid a |
220 // giant list of subclasses to be printed out. | 219 // giant list of subclasses to be printed out. |
221 if (parseSdk) entityMap['dart.core.Object'].subclasses.clear(); | 220 if (parseSdk) entityMap['dart.core.Object'].subclasses.clear(); |
222 | 221 |
223 var filteredEntities = entityMap.values.where(_isVisible); | 222 var filteredEntities = entityMap.values.where(_isVisible); |
224 // Output libraries and classes to file after all information is generated. | 223 // Output libraries and classes to file after all information is generated. |
225 filteredEntities.where((e) => e is Class || e is Library).forEach((output) { | 224 filteredEntities.where((e) => e is Class || e is Library).forEach((output) { |
226 _writeIndexableToFile(output, outputToYaml); | 225 _writeIndexableToFile(output, outputToYaml); |
227 }); | 226 }); |
228 // Outputs a text file with a list of libraries available after creating all | 227 // Outputs a text file with a list of libraries available after creating all |
229 // the libraries. This will help the viewer know what libraries are available | 228 // the libraries. This will help the viewer know what libraries are available |
230 // to read in. | 229 // to read in. |
231 _writeToFile(filteredEntities.where((e) => e is Library) | 230 _writeToFile(filteredEntities.where((e) => e is Library) |
232 .map((e) => e.qualifiedName).join('\n'), 'library_list.txt', | 231 .map((e) => e.qualifiedName).join('\n'), 'library_list.txt', |
233 append: append); | 232 append: append); |
234 // Outputs all the qualified names documented. This will help generate search | 233 // Outputs all the qualified names documented. This will help generate search |
235 // results. | 234 // results. |
236 _writeToFile(filteredEntities.map((e) => e.qualifiedName).join('\n'), | 235 _writeToFile(filteredEntities.map((e) => e.qualifiedName).join('\n'), |
237 'index.txt', append: append); | 236 'index.txt', append: append); |
238 } | 237 } |
239 | 238 |
240 Library generateLibrary(dart2js.Dart2JsLibraryMirror library) { | 239 Library generateLibrary(dart2js.Dart2JsLibraryMirror library) { |
241 _currentLibrary = library; | 240 _currentLibrary = library; |
242 var result = new Library(library.qualifiedName, _commentToHtml(library), | 241 var result = new Library(library.qualifiedName, _commentToHtml(library), |
243 _variables(library.variables), | 242 _variables(library.variables), |
244 _methods(library.functions), | 243 _methods(library.functions), |
245 _classes(library.classes), _isHidden(library)); | 244 _classes(library.classes), _isHidden(library)); |
246 logger.fine('Generated library for ${result.name}'); | 245 logger.fine('Generated library for ${result.name}'); |
247 return result; | 246 return result; |
248 } | 247 } |
249 | 248 |
250 void _writeIndexableToFile(Indexable result, bool outputToYaml) { | 249 void _writeIndexableToFile(Indexable result, bool outputToYaml) { |
251 if (outputToYaml) { | 250 if (outputToYaml) { |
252 _writeToFile(getYamlString(result.toMap()), '${result.qualifiedName}.yaml'); | 251 _writeToFile(getYamlString(result.toMap()), '${result.qualifiedName}.yaml'); |
253 } else { | 252 } else { |
254 _writeToFile(stringify(result.toMap()), '${result.qualifiedName}.json'); | 253 _writeToFile(stringify(result.toMap()), '${result.qualifiedName}.json'); |
255 } | 254 } |
256 } | 255 } |
257 | 256 |
258 /** | 257 /** |
259 * Returns true if a library name starts with an underscore, and false | 258 * Returns true if a library name starts with an underscore, and false |
260 * otherwise. | 259 * otherwise. |
261 * | 260 * |
262 * An example that starts with _ is _js_helper. | 261 * An example that starts with _ is _js_helper. |
263 * An example that contains ._ is dart._collection.dev | 262 * An example that contains ._ is dart._collection.dev |
264 */ | 263 */ |
265 // This is because LibraryMirror.isPrivate returns `false` all the time. | 264 // This is because LibraryMirror.isPrivate returns `false` all the time. |
266 bool _isLibraryPrivate(LibraryMirror mirror) { | 265 bool _isLibraryPrivate(LibraryMirror mirror) { |
267 if (mirror.simpleName.startsWith('_') || mirror.simpleName.contains('._')) { | 266 if (mirror.simpleName.startsWith('_') || mirror.simpleName.contains('._')) { |
268 return true; | 267 return true; |
269 } | 268 } |
270 return false; | 269 return false; |
271 } | 270 } |
272 | 271 |
273 /** | 272 /** |
274 * A declaration is private if itself is private, or the owner is private. | 273 * A declaration is private if itself is private, or the owner is private. |
275 */ | 274 */ |
276 // Issue(12202) - A declaration is public even if it's owner is private. | 275 // Issue(12202) - A declaration is public even if it's owner is private. |
277 bool _isHidden(DeclarationMirror mirror) { | 276 bool _isHidden(DeclarationMirror mirror) { |
278 if (mirror is LibraryMirror) { | 277 if (mirror is LibraryMirror) { |
279 return _isLibraryPrivate(mirror); | 278 return _isLibraryPrivate(mirror); |
280 } else if (mirror.owner is LibraryMirror) { | 279 } else if (mirror.owner is LibraryMirror) { |
281 return (mirror.isPrivate || _isLibraryPrivate(mirror.owner)); | 280 return (mirror.isPrivate || _isLibraryPrivate(mirror.owner)); |
282 } else { | 281 } else { |
283 return (mirror.isPrivate || _isHidden(mirror.owner)); | 282 return (mirror.isPrivate || _isHidden(mirror.owner)); |
284 } | 283 } |
285 } | 284 } |
286 | 285 |
287 bool _isVisible(Indexable item) { | 286 bool _isVisible(Indexable item) { |
288 return _includePrivate || !item.isPrivate; | 287 return _includePrivate || !item.isPrivate; |
289 } | 288 } |
290 | 289 |
291 /** | 290 /** |
292 * Returns a list of meta annotations assocated with a mirror. | 291 * Returns a list of meta annotations assocated with a mirror. |
(...skipping 25 matching lines...) Expand all Loading... |
318 CommentInstanceMirror comment = metadata; | 317 CommentInstanceMirror comment = metadata; |
319 if (comment.isDocComment) { | 318 if (comment.isDocComment) { |
320 if (commentText == null) { | 319 if (commentText == null) { |
321 commentText = comment.trimmedText; | 320 commentText = comment.trimmedText; |
322 } else { | 321 } else { |
323 commentText = '$commentText ${comment.trimmedText}'; | 322 commentText = '$commentText ${comment.trimmedText}'; |
324 } | 323 } |
325 } | 324 } |
326 } | 325 } |
327 }); | 326 }); |
328 | 327 |
329 commentText = commentText == null ? '' : | 328 commentText = commentText == null ? '' : |
330 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver, | 329 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver, |
331 inlineSyntaxes: markdownSyntaxes); | 330 inlineSyntaxes: markdownSyntaxes); |
332 return commentText; | 331 return commentText; |
333 } | 332 } |
334 | 333 |
335 /** | 334 /** |
336 * Converts all [foo] references in comments to <a>libraryName.foo</a>. | 335 * Converts all [foo] references in comments to <a>libraryName.foo</a>. |
337 */ | 336 */ |
338 markdown.Node fixReference(String name, LibraryMirror currentLibrary, | 337 markdown.Node fixReference(String name, LibraryMirror currentLibrary, |
339 ClassMirror currentClass, MemberMirror currentMember) { | 338 ClassMirror currentClass, MemberMirror currentMember) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 * Returns a map of [Method] objects constructed from [mirrorMap]. | 379 * Returns a map of [Method] objects constructed from [mirrorMap]. |
381 */ | 380 */ |
382 MethodGroup _methods(Map<String, MethodMirror> mirrorMap) { | 381 MethodGroup _methods(Map<String, MethodMirror> mirrorMap) { |
383 var group = new MethodGroup(); | 382 var group = new MethodGroup(); |
384 mirrorMap.forEach((String mirrorName, MethodMirror mirror) { | 383 mirrorMap.forEach((String mirrorName, MethodMirror mirror) { |
385 if (_includePrivate || !_isHidden(mirror)) { | 384 if (_includePrivate || !_isHidden(mirror)) { |
386 group.addMethod(mirror); | 385 group.addMethod(mirror); |
387 } | 386 } |
388 }); | 387 }); |
389 return group; | 388 return group; |
390 } | 389 } |
391 | 390 |
392 /** | 391 /** |
393 * Returns the [Class] for the given [mirror] has already been created, and if | 392 * Returns the [Class] for the given [mirror] has already been created, and if |
394 * it does not exist, creates it. | 393 * it does not exist, creates it. |
395 */ | 394 */ |
396 Class _class(ClassMirror mirror) { | 395 Class _class(ClassMirror mirror) { |
397 var clazz = entityMap[mirror.qualifiedName]; | 396 var clazz = entityMap[mirror.qualifiedName]; |
398 if (clazz == null) { | 397 if (clazz == null) { |
399 var superclass = mirror.superclass != null ? | 398 var superclass = mirror.superclass != null ? |
400 _class(mirror.superclass) : null; | 399 _class(mirror.superclass) : null; |
401 var interfaces = | 400 var interfaces = |
402 mirror.superinterfaces.map((interface) => _class(interface)); | 401 mirror.superinterfaces.map((interface) => _class(interface)); |
403 clazz = new Class(mirror.simpleName, superclass, _commentToHtml(mirror), | 402 clazz = new Class(mirror.simpleName, superclass, _commentToHtml(mirror), |
404 interfaces.toList(), _variables(mirror.variables), | 403 interfaces.toList(), _variables(mirror.variables), |
405 _methods(mirror.methods), _annotations(mirror), _generics(mirror), | 404 _methods(mirror.methods), _annotations(mirror), _generics(mirror), |
406 mirror.qualifiedName, _isHidden(mirror), mirror.owner.qualifiedName); | 405 mirror.qualifiedName, _isHidden(mirror), mirror.owner.qualifiedName); |
407 entityMap[mirror.qualifiedName] = clazz; | 406 entityMap[mirror.qualifiedName] = clazz; |
408 } | 407 } |
409 return clazz; | 408 return clazz; |
410 } | 409 } |
411 | 410 |
412 /** | 411 /** |
413 * Returns a map of [Class] objects constructed from [mirrorMap]. | 412 * Returns a map of [Class] objects constructed from [mirrorMap]. |
414 */ | 413 */ |
415 ClassGroup _classes(Map<String, ClassMirror> mirrorMap) { | 414 ClassGroup _classes(Map<String, ClassMirror> mirrorMap) { |
416 var group = new ClassGroup(); | 415 var group = new ClassGroup(); |
417 mirrorMap.forEach((String mirrorName, ClassMirror mirror) { | 416 mirrorMap.forEach((String mirrorName, ClassMirror mirror) { |
418 group.addClass(mirror); | 417 group.addClass(mirror); |
419 }); | 418 }); |
420 return group; | 419 return group; |
421 } | 420 } |
422 | 421 |
423 /** | 422 /** |
424 * Returns a map of [Parameter] objects constructed from [mirrorList]. | 423 * Returns a map of [Parameter] objects constructed from [mirrorList]. |
425 */ | 424 */ |
426 Map<String, Parameter> _parameters(List<ParameterMirror> mirrorList) { | 425 Map<String, Parameter> _parameters(List<ParameterMirror> mirrorList) { |
427 var data = {}; | 426 var data = {}; |
428 mirrorList.forEach((ParameterMirror mirror) { | 427 mirrorList.forEach((ParameterMirror mirror) { |
429 _currentMember = mirror; | 428 _currentMember = mirror; |
430 data[mirror.simpleName] = new Parameter(mirror.simpleName, | 429 data[mirror.simpleName] = new Parameter(mirror.simpleName, |
431 mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue, | 430 mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue, |
432 _type(mirror.type), mirror.defaultValue, | 431 _type(mirror.type), mirror.defaultValue, |
433 _annotations(mirror)); | 432 _annotations(mirror)); |
434 }); | 433 }); |
435 return data; | 434 return data; |
436 } | 435 } |
437 | 436 |
438 /** | 437 /** |
439 * Returns a map of [Generic] objects constructed from the class mirror. | 438 * Returns a map of [Generic] objects constructed from the class mirror. |
440 */ | 439 */ |
441 Map<String, Generic> _generics(ClassMirror mirror) { | 440 Map<String, Generic> _generics(ClassMirror mirror) { |
442 return new Map.fromIterable(mirror.typeVariables, | 441 return new Map.fromIterable(mirror.typeVariables, |
443 key: (e) => e.toString(), | 442 key: (e) => e.toString(), |
444 value: (e) => new Generic(e.toString(), e.upperBound.qualifiedName)); | 443 value: (e) => new Generic(e.toString(), e.upperBound.qualifiedName)); |
445 } | 444 } |
446 | 445 |
447 /** | 446 /** |
448 * Returns a single [Type] object constructed from the Method.returnType | 447 * Returns a single [Type] object constructed from the Method.returnType |
449 * Type mirror. | 448 * Type mirror. |
450 */ | 449 */ |
451 Type _type(TypeMirror mirror) { | 450 Type _type(TypeMirror mirror) { |
452 return new Type(mirror.qualifiedName, _typeGenerics(mirror)); | 451 return new Type(mirror.qualifiedName, _typeGenerics(mirror)); |
453 } | 452 } |
454 | 453 |
455 /** | 454 /** |
456 * Returns a list of [Type] objects constructed from TypeMirrors. | 455 * Returns a list of [Type] objects constructed from TypeMirrors. |
457 */ | 456 */ |
458 List<Type> _typeGenerics(TypeMirror mirror) { | 457 List<Type> _typeGenerics(TypeMirror mirror) { |
459 if (mirror is ClassMirror && !mirror.isTypedef) { | 458 if (mirror is ClassMirror && !mirror.isTypedef) { |
460 var innerList = []; | 459 var innerList = []; |
461 mirror.typeArguments.forEach((e) { | 460 mirror.typeArguments.forEach((e) { |
462 innerList.add(new Type(e.qualifiedName, _typeGenerics(e))); | 461 innerList.add(new Type(e.qualifiedName, _typeGenerics(e))); |
463 }); | 462 }); |
464 return innerList; | 463 return innerList; |
465 } | 464 } |
466 return []; | 465 return []; |
(...skipping 23 matching lines...) Expand all Loading... |
490 if (value is Map) { | 489 if (value is Map) { |
491 outputMap[key] = recurseMap(value); | 490 outputMap[key] = recurseMap(value); |
492 } else { | 491 } else { |
493 outputMap[key] = value.toMap(); | 492 outputMap[key] = value.toMap(); |
494 } | 493 } |
495 }); | 494 }); |
496 return outputMap; | 495 return outputMap; |
497 } | 496 } |
498 | 497 |
499 bool isError(String qualifiedName) { | 498 bool isError(String qualifiedName) { |
500 return qualifiedName.toLowerCase().contains('error') || | 499 return qualifiedName.toLowerCase().contains('error') || |
501 qualifiedName.toLowerCase().contains('exception'); | 500 qualifiedName.toLowerCase().contains('exception'); |
502 } | 501 } |
503 | 502 |
504 /** | 503 /** |
505 * A class representing all programming constructs, like library or class. | 504 * A class representing all programming constructs, like library or class. |
506 */ | 505 */ |
507 class Indexable { | 506 class Indexable { |
508 String name; | 507 String name; |
509 String qualifiedName; | 508 String qualifiedName; |
510 bool isPrivate; | 509 bool isPrivate; |
511 | 510 |
512 /// Documentation comment with converted markdown. | 511 /// Documentation comment with converted markdown. |
513 String comment; | 512 String comment; |
514 | 513 |
515 /// Qualified Name of the owner of this Indexable Item. | 514 /// Qualified Name of the owner of this Indexable Item. |
516 /// For Library, owner will be ""; | 515 /// For Library, owner will be ""; |
517 String owner; | 516 String owner; |
518 | 517 |
519 Indexable(this.name, this.comment, this.qualifiedName, this.isPrivate, | 518 Indexable(this.name, this.comment, this.qualifiedName, this.isPrivate, |
520 this.owner); | 519 this.owner); |
521 } | 520 } |
522 | 521 |
523 /** | 522 /** |
524 * A class containing contents of a Dart library. | 523 * A class containing contents of a Dart library. |
525 */ | 524 */ |
526 class Library extends Indexable { | 525 class Library extends Indexable { |
527 | 526 |
528 /// Top-level variables in the library. | 527 /// Top-level variables in the library. |
529 Map<String, Variable> variables; | 528 Map<String, Variable> variables; |
530 | 529 |
531 /// Top-level functions in the library. | 530 /// Top-level functions in the library. |
532 MethodGroup functions; | 531 MethodGroup functions; |
533 | 532 |
534 /// Classes defined within the library | 533 /// Classes defined within the library |
535 ClassGroup classes; | 534 ClassGroup classes; |
536 | 535 |
537 Library(String name, String comment, this.variables, | 536 Library(String name, String comment, this.variables, |
538 this.functions, this.classes, bool isPrivate) : super(name, comment, | 537 this.functions, this.classes, bool isPrivate) : super(name, comment, |
539 name, isPrivate, "") {} | 538 name, isPrivate, "") {} |
540 | 539 |
541 /// Generates a map describing the [Library] object. | 540 /// Generates a map describing the [Library] object. |
542 Map toMap() => { | 541 Map toMap() => { |
543 'name': name, | 542 'name': name, |
544 'qualifiedname': qualifiedName, | 543 'qualifiedname': qualifiedName, |
545 'comment': comment, | 544 'comment': comment, |
546 'variables': recurseMap(variables), | 545 'variables': recurseMap(variables), |
547 'functions': functions.toMap(), | 546 'functions': functions.toMap(), |
548 'classes': classes.toMap() | 547 'classes': classes.toMap() |
549 }; | 548 }; |
550 } | 549 } |
551 | 550 |
552 /** | 551 /** |
553 * A class containing contents of a Dart class. | 552 * A class containing contents of a Dart class. |
554 */ | 553 */ |
555 class Class extends Indexable { | 554 class Class extends Indexable { |
556 | 555 |
557 /// List of the names of interfaces that this class implements. | 556 /// List of the names of interfaces that this class implements. |
558 List<Class> interfaces = []; | 557 List<Class> interfaces = []; |
559 | 558 |
560 /// Names of classes that extends or implements this class. | 559 /// Names of classes that extends or implements this class. |
561 Set<String> subclasses = new Set<String>(); | 560 Set<String> subclasses = new Set<String>(); |
562 | 561 |
563 /// Top-level variables in the class. | 562 /// Top-level variables in the class. |
564 Map<String, Variable> variables; | 563 Map<String, Variable> variables; |
565 | 564 |
566 /// Inherited variables in the class. | 565 /// Inherited variables in the class. |
567 Map<String, Variable> inheritedVariables = {}; | 566 Map<String, Variable> inheritedVariables = {}; |
568 | 567 |
569 /// Methods in the class. | 568 /// Methods in the class. |
570 MethodGroup methods; | 569 MethodGroup methods; |
571 | 570 |
572 /// Inherited methods in the class. | 571 /// Inherited methods in the class. |
573 MethodGroup inheritedMethods = new MethodGroup(); | 572 MethodGroup inheritedMethods = new MethodGroup(); |
574 | 573 |
575 /// Generic infomation about the class. | 574 /// Generic infomation about the class. |
576 Map<String, Generic> generics; | 575 Map<String, Generic> generics; |
577 | 576 |
578 Class superclass; | 577 Class superclass; |
579 | 578 |
580 /// List of the meta annotations on the class. | 579 /// List of the meta annotations on the class. |
581 List<String> annotations; | 580 List<String> annotations; |
582 | 581 |
583 Class(String name, this.superclass, String comment, this.interfaces, | 582 Class(String name, this.superclass, String comment, this.interfaces, |
584 this.variables, this.methods, this.annotations, this.generics, | 583 this.variables, this.methods, this.annotations, this.generics, |
585 String qualifiedName, bool isPrivate, String owner) : super(name, comment, | 584 String qualifiedName, bool isPrivate, String owner) : super(name, comment, |
586 qualifiedName, isPrivate, owner) {} | 585 qualifiedName, isPrivate, owner) {} |
587 | 586 |
588 /** | 587 /** |
589 * Returns a list of all the parent classes. | 588 * Returns a list of all the parent classes. |
590 */ | 589 */ |
591 List<Class> parent() { | 590 List<Class> parent() { |
592 var parent = superclass == null ? [] : [superclass]; | 591 var parent = superclass == null ? [] : [superclass]; |
593 parent.addAll(interfaces); | 592 parent.addAll(interfaces); |
594 return parent; | 593 return parent; |
595 } | 594 } |
596 | 595 |
597 /** | 596 /** |
598 * Add all inherited variables and methods from the provided superclass. | 597 * Add all inherited variables and methods from the provided superclass. |
599 * If [_includePrivate] is true, it also adds the variables and methods from | 598 * If [_includePrivate] is true, it also adds the variables and methods from |
600 * the superclass. | 599 * the superclass. |
601 */ | 600 */ |
602 void addInherited(Class superclass) { | 601 void addInherited(Class superclass) { |
603 inheritedVariables.addAll(superclass.inheritedVariables); | 602 inheritedVariables.addAll(superclass.inheritedVariables); |
604 if (_isVisible(superclass)) { | 603 if (_isVisible(superclass)) { |
605 inheritedVariables.addAll(superclass.variables); | 604 inheritedVariables.addAll(superclass.variables); |
606 } | 605 } |
607 inheritedMethods.addInherited(superclass); | 606 inheritedMethods.addInherited(superclass); |
608 } | 607 } |
609 | 608 |
610 /** | 609 /** |
611 * Add the subclass to the class. | 610 * Add the subclass to the class. |
612 * | 611 * |
613 * If [this] is private, it will add the subclass to the list of subclasses in | 612 * If [this] is private, it will add the subclass to the list of subclasses in |
614 * the superclasses. | 613 * the superclasses. |
615 */ | 614 */ |
616 void addSubclass(Class subclass) { | 615 void addSubclass(Class subclass) { |
617 if (!_includePrivate && isPrivate) { | 616 if (!_includePrivate && isPrivate) { |
618 if (superclass != null) superclass.addSubclass(subclass); | 617 if (superclass != null) superclass.addSubclass(subclass); |
619 interfaces.forEach((interface) { | 618 interfaces.forEach((interface) { |
620 interface.addSubclass(subclass); | 619 interface.addSubclass(subclass); |
621 }); | 620 }); |
622 } else { | 621 } else { |
623 subclasses.add(subclass.qualifiedName); | 622 subclasses.add(subclass.qualifiedName); |
624 } | 623 } |
625 } | 624 } |
626 | 625 |
627 /** | 626 /** |
628 * Check that the class exists in the owner library. | 627 * Check that the class exists in the owner library. |
629 * | 628 * |
630 * If it does not exist in the owner library, it is a mixin applciation and | 629 * If it does not exist in the owner library, it is a mixin applciation and |
631 * should be removed. | 630 * should be removed. |
632 */ | 631 */ |
633 void makeValid() { | 632 void makeValid() { |
634 var library = entityMap[owner]; | 633 var library = entityMap[owner]; |
635 if (library != null && !library.classes.containsKey(name)) { | 634 if (library != null && !library.classes.containsKey(name)) { |
636 this.isPrivate = true; | 635 this.isPrivate = true; |
637 // Since we are now making the mixin a private class, make all elements | 636 // Since we are now making the mixin a private class, make all elements |
638 // with the mixin as an owner private too. | 637 // with the mixin as an owner private too. |
639 entityMap.values.where((e) => e.owner == qualifiedName) | 638 entityMap.values.where((e) => e.owner == qualifiedName) |
640 .forEach((element) => element.isPrivate = true); | 639 .forEach((element) => element.isPrivate = true); |
641 // Move the subclass up to the next public superclass | 640 // Move the subclass up to the next public superclass |
642 subclasses.forEach((subclass) => addSubclass(entityMap[subclass])); | 641 subclasses.forEach((subclass) => addSubclass(entityMap[subclass])); |
643 } | 642 } |
644 } | 643 } |
645 | 644 |
646 /** | 645 /** |
647 * Makes sure that all methods with inherited equivalents have comments. | 646 * Makes sure that all methods with inherited equivalents have comments. |
648 */ | 647 */ |
649 void ensureComments() { | 648 void ensureComments() { |
650 inheritedMethods.forEach((qualifiedName, inheritedMethod) { | 649 inheritedMethods.forEach((qualifiedName, inheritedMethod) { |
651 var method = methods[qualifiedName]; | 650 var method = methods[qualifiedName]; |
652 if (method != null) method.ensureCommentFor(inheritedMethod); | 651 if (method != null) method.ensureCommentFor(inheritedMethod); |
653 }); | 652 }); |
654 } | 653 } |
655 | 654 |
656 /** | 655 /** |
657 * If a class extends a private superclass, find the closest public superclass | 656 * If a class extends a private superclass, find the closest public superclass |
658 * of the private superclass. | 657 * of the private superclass. |
659 */ | 658 */ |
660 String validSuperclass() { | 659 String validSuperclass() { |
661 if (superclass == null) return 'dart.core.Object'; | 660 if (superclass == null) return 'dart.core.Object'; |
662 if (_isVisible(superclass)) return superclass.qualifiedName; | 661 if (_isVisible(superclass)) return superclass.qualifiedName; |
663 return superclass.validSuperclass(); | 662 return superclass.validSuperclass(); |
664 } | 663 } |
665 | 664 |
666 /// Generates a map describing the [Class] object. | 665 /// Generates a map describing the [Class] object. |
667 Map toMap() => { | 666 Map toMap() => { |
668 'name': name, | 667 'name': name, |
669 'qualifiedname': qualifiedName, | 668 'qualifiedname': qualifiedName, |
670 'comment': comment, | 669 'comment': comment, |
671 'superclass': validSuperclass(), | 670 'superclass': validSuperclass(), |
672 'implements': interfaces.where(_isVisible) | 671 'implements': interfaces.where(_isVisible) |
673 .map((e) => e.qualifiedName).toList(), | 672 .map((e) => e.qualifiedName).toList(), |
674 'subclass': subclasses.toList(), | 673 'subclass': subclasses.toList(), |
675 'variables': recurseMap(variables), | 674 'variables': recurseMap(variables), |
676 'inheritedvariables': recurseMap(inheritedVariables), | 675 'inheritedvariables': recurseMap(inheritedVariables), |
677 'methods': methods.toMap(), | 676 'methods': methods.toMap(), |
678 'inheritedmethods': inheritedMethods.toMap(), | 677 'inheritedmethods': inheritedMethods.toMap(), |
679 'annotations': annotations.map((a) => a.toMap()).toList(), | 678 'annotations': annotations.map((a) => a.toMap()).toList(), |
680 'generics': recurseMap(generics) | 679 'generics': recurseMap(generics) |
681 }; | 680 }; |
682 } | 681 } |
683 | 682 |
684 /** | 683 /** |
685 * A container to categorize classes into the following groups: abstract | 684 * A container to categorize classes into the following groups: abstract |
686 * classes, regular classes, typedefs, and errors. | 685 * classes, regular classes, typedefs, and errors. |
687 */ | 686 */ |
688 class ClassGroup { | 687 class ClassGroup { |
689 Map<String, Class> abstractClasses = {}; | 688 Map<String, Class> abstractClasses = {}; |
690 Map<String, Class> regularClasses = {}; | 689 Map<String, Class> regularClasses = {}; |
691 Map<String, Typedef> typedefs = {}; | 690 Map<String, Typedef> typedefs = {}; |
692 Map<String, Class> errors = {}; | 691 Map<String, Class> errors = {}; |
693 | 692 |
694 void addClass(ClassMirror mirror) { | 693 void addClass(ClassMirror mirror) { |
695 _currentClass = mirror; | 694 _currentClass = mirror; |
696 var clazz = _class(mirror); | 695 var clazz = _class(mirror); |
697 | 696 |
698 // Adding inherited parent variables and methods. | 697 // Adding inherited parent variables and methods. |
699 clazz.parent().forEach((parent) { | 698 clazz.parent().forEach((parent) { |
700 if (_isVisible(clazz)) { | 699 if (_isVisible(clazz)) { |
701 parent.addSubclass(clazz); | 700 parent.addSubclass(clazz); |
702 } | 701 } |
703 clazz.addInherited(parent); | 702 clazz.addInherited(parent); |
704 }); | 703 }); |
705 | 704 |
706 clazz.ensureComments(); | 705 clazz.ensureComments(); |
707 | 706 |
708 if (isError(mirror.qualifiedName)) { | 707 if (isError(mirror.qualifiedName)) { |
709 errors[mirror.simpleName] = clazz; | 708 errors[mirror.simpleName] = clazz; |
710 } else if (mirror.isTypedef) { | 709 } else if (mirror.isTypedef) { |
711 if (_includePrivate || !mirror.isPrivate) { | 710 if (_includePrivate || !mirror.isPrivate) { |
712 entityMap[mirror.qualifiedName] = new Typedef(mirror.simpleName, | 711 entityMap[mirror.qualifiedName] = new Typedef(mirror.simpleName, |
713 mirror.value.returnType.qualifiedName, _commentToHtml(mirror), | 712 mirror.value.returnType.qualifiedName, _commentToHtml(mirror), |
714 _generics(mirror), _parameters(mirror.value.parameters), | 713 _generics(mirror), _parameters(mirror.value.parameters), |
715 _annotations(mirror), mirror.qualifiedName, _isHidden(mirror), | 714 _annotations(mirror), mirror.qualifiedName, _isHidden(mirror), |
716 mirror.owner.qualifiedName); | 715 mirror.owner.qualifiedName); |
717 typedefs[mirror.simpleName] = entityMap[mirror.qualifiedName]; | 716 typedefs[mirror.simpleName] = entityMap[mirror.qualifiedName]; |
718 } | 717 } |
719 } else if (mirror.isAbstract) { | 718 } else if (mirror.isAbstract) { |
720 abstractClasses[mirror.simpleName] = clazz; | 719 abstractClasses[mirror.simpleName] = clazz; |
721 } else if (mirror.isClass) { | 720 } else if (mirror.isClass) { |
722 regularClasses[mirror.simpleName] = clazz; | 721 regularClasses[mirror.simpleName] = clazz; |
723 } else { | 722 } else { |
724 throw new ArgumentError('${mirror.simpleName} - no class type match. '); | 723 throw new ArgumentError('${mirror.simpleName} - no class type match. '); |
725 } | 724 } |
726 } | 725 } |
727 | 726 |
728 /** | 727 /** |
729 * Checks if the given name is a key for any of the Class Maps. | 728 * Checks if the given name is a key for any of the Class Maps. |
730 */ | 729 */ |
731 bool containsKey(String name) { | 730 bool containsKey(String name) { |
732 return abstractClasses.containsKey(name) || | 731 return abstractClasses.containsKey(name) || |
733 regularClasses.containsKey(name) || | 732 regularClasses.containsKey(name) || |
734 errors.containsKey(name); | 733 errors.containsKey(name); |
735 } | 734 } |
736 | 735 |
737 Map toMap() => { | 736 Map toMap() => { |
738 'abstract': abstractClasses.values.where(_isVisible) | 737 'abstract': abstractClasses.values.where(_isVisible) |
739 .map((e) => e.qualifiedName).toList(), | 738 .map((e) => e.qualifiedName).toList(), |
740 'class': regularClasses.values.where(_isVisible) | 739 'class': regularClasses.values.where(_isVisible) |
741 .map((e) => e.qualifiedName).toList(), | 740 .map((e) => e.qualifiedName).toList(), |
742 'typedef': recurseMap(typedefs), | 741 'typedef': recurseMap(typedefs), |
743 'error': errors.values.where(_isVisible) | 742 'error': errors.values.where(_isVisible) |
744 .map((e) => e.qualifiedName).toList() | 743 .map((e) => e.qualifiedName).toList() |
745 }; | 744 }; |
746 } | 745 } |
747 | 746 |
748 class Typedef extends Indexable { | 747 class Typedef extends Indexable { |
749 String returnType; | 748 String returnType; |
750 | 749 |
751 Map<String, Parameter> parameters; | 750 Map<String, Parameter> parameters; |
752 | 751 |
753 /// Generic information about the typedef. | 752 /// Generic information about the typedef. |
754 Map<String, Generic> generics; | 753 Map<String, Generic> generics; |
755 | 754 |
756 /// List of the meta annotations on the typedef. | 755 /// List of the meta annotations on the typedef. |
757 List<String> annotations; | 756 List<String> annotations; |
758 | 757 |
759 Typedef(String name, this.returnType, String comment, this.generics, | 758 Typedef(String name, this.returnType, String comment, this.generics, |
760 this.parameters, this.annotations, | 759 this.parameters, this.annotations, |
761 String qualifiedName, bool isPrivate, String owner) : super(name, comment, | 760 String qualifiedName, bool isPrivate, String owner) : super(name, comment, |
762 qualifiedName, isPrivate, owner) {} | 761 qualifiedName, isPrivate, owner) {} |
763 | 762 |
764 Map toMap() => { | 763 Map toMap() => { |
765 'name': name, | 764 'name': name, |
766 'qualifiedname': qualifiedName, | 765 'qualifiedname': qualifiedName, |
767 'comment': comment, | 766 'comment': comment, |
768 'return': returnType, | 767 'return': returnType, |
769 'parameters': recurseMap(parameters), | 768 'parameters': recurseMap(parameters), |
770 'annotations': annotations.map((a) => a.toMap()).toList(), | 769 'annotations': annotations.map((a) => a.toMap()).toList(), |
771 'generics': recurseMap(generics) | 770 'generics': recurseMap(generics) |
772 }; | 771 }; |
773 } | 772 } |
774 | 773 |
775 /** | 774 /** |
776 * A class containing properties of a Dart variable. | 775 * A class containing properties of a Dart variable. |
777 */ | 776 */ |
778 class Variable extends Indexable { | 777 class Variable extends Indexable { |
779 | 778 |
780 bool isFinal; | 779 bool isFinal; |
781 bool isStatic; | 780 bool isStatic; |
782 bool isConst; | 781 bool isConst; |
783 Type type; | 782 Type type; |
784 | 783 |
785 /// List of the meta annotations on the variable. | 784 /// List of the meta annotations on the variable. |
786 List<String> annotations; | 785 List<String> annotations; |
787 | 786 |
788 Variable(String name, this.isFinal, this.isStatic, this.isConst, this.type, | 787 Variable(String name, this.isFinal, this.isStatic, this.isConst, this.type, |
789 String comment, this.annotations, String qualifiedName, bool isPrivate, | 788 String comment, this.annotations, String qualifiedName, bool isPrivate, |
790 String owner) : super(name, comment, qualifiedName, isPrivate, owner); | 789 String owner) : super(name, comment, qualifiedName, isPrivate, owner); |
791 | 790 |
792 /// Generates a map describing the [Variable] object. | 791 /// Generates a map describing the [Variable] object. |
793 Map toMap() => { | 792 Map toMap() => { |
794 'name': name, | 793 'name': name, |
795 'qualifiedname': qualifiedName, | 794 'qualifiedname': qualifiedName, |
796 'comment': comment, | 795 'comment': comment, |
797 'final': isFinal.toString(), | 796 'final': isFinal.toString(), |
798 'static': isStatic.toString(), | 797 'static': isStatic.toString(), |
799 'constant': isConst.toString(), | 798 'constant': isConst.toString(), |
800 'type': new List.filled(1, type.toMap()), | 799 'type': new List.filled(1, type.toMap()), |
801 'annotations': annotations.map((a) => a.toMap()).toList() | 800 'annotations': annotations.map((a) => a.toMap()).toList() |
802 }; | 801 }; |
803 } | 802 } |
804 | 803 |
805 /** | 804 /** |
806 * A class containing properties of a Dart method. | 805 * A class containing properties of a Dart method. |
807 */ | 806 */ |
808 class Method extends Indexable { | 807 class Method extends Indexable { |
809 | 808 |
810 /// Parameters for this method. | 809 /// Parameters for this method. |
811 Map<String, Parameter> parameters; | 810 Map<String, Parameter> parameters; |
812 | 811 |
813 bool isStatic; | 812 bool isStatic; |
814 bool isAbstract; | 813 bool isAbstract; |
815 bool isConst; | 814 bool isConst; |
816 Type returnType; | 815 Type returnType; |
817 | 816 |
818 /// Qualified name to state where the comment is inherited from. | 817 /// Qualified name to state where the comment is inherited from. |
819 String commentInheritedFrom = ""; | 818 String commentInheritedFrom = ""; |
820 | 819 |
821 /// List of the meta annotations on the method. | 820 /// List of the meta annotations on the method. |
822 List<String> annotations; | 821 List<String> annotations; |
823 | 822 |
824 Method(String name, this.isStatic, this.isAbstract, this.isConst, | 823 Method(String name, this.isStatic, this.isAbstract, this.isConst, |
825 this.returnType, String comment, this.parameters, this.annotations, | 824 this.returnType, String comment, this.parameters, this.annotations, |
826 String qualifiedName, bool isPrivate, String owner) : super(name, comment, | 825 String qualifiedName, bool isPrivate, String owner) : super(name, comment, |
827 qualifiedName, isPrivate, owner); | 826 qualifiedName, isPrivate, owner); |
828 | 827 |
829 /** | 828 /** |
830 * Makes sure that the method with an inherited equivalent have comments. | 829 * Makes sure that the method with an inherited equivalent have comments. |
831 */ | 830 */ |
832 void ensureCommentFor(Method inheritedMethod) { | 831 void ensureCommentFor(Method inheritedMethod) { |
833 if (comment.isNotEmpty) return; | 832 if (comment.isNotEmpty) return; |
834 entityMap[inheritedMethod.owner].ensureComments(); | 833 entityMap[inheritedMethod.owner].ensureComments(); |
835 comment = inheritedMethod.comment; | 834 comment = inheritedMethod.comment; |
836 commentInheritedFrom = inheritedMethod.commentInheritedFrom == '' ? | 835 commentInheritedFrom = inheritedMethod.commentInheritedFrom == '' ? |
837 inheritedMethod.qualifiedName : inheritedMethod.commentInheritedFrom; | 836 inheritedMethod.qualifiedName : inheritedMethod.commentInheritedFrom; |
838 } | 837 } |
839 | 838 |
840 /// Generates a map describing the [Method] object. | 839 /// Generates a map describing the [Method] object. |
841 Map toMap() => { | 840 Map toMap() => { |
842 'name': name, | 841 'name': name, |
843 'qualifiedname': qualifiedName, | 842 'qualifiedname': qualifiedName, |
844 'comment': comment, | 843 'comment': comment, |
845 'commentfrom': commentInheritedFrom, | 844 'commentfrom': commentInheritedFrom, |
846 'static': isStatic.toString(), | 845 'static': isStatic.toString(), |
847 'abstract': isAbstract.toString(), | 846 'abstract': isAbstract.toString(), |
848 'constant': isConst.toString(), | 847 'constant': isConst.toString(), |
849 'return': new List.filled(1, returnType.toMap()), | 848 'return': new List.filled(1, returnType.toMap()), |
850 'parameters': recurseMap(parameters), | 849 'parameters': recurseMap(parameters), |
851 'annotations': annotations.map((a) => a.toMap()).toList() | 850 'annotations': annotations.map((a) => a.toMap()).toList() |
852 }; | 851 }; |
853 } | 852 } |
854 | 853 |
855 /** | 854 /** |
856 * A container to categorize methods into the following groups: setters, | 855 * A container to categorize methods into the following groups: setters, |
857 * getters, constructors, operators, regular methods. | 856 * getters, constructors, operators, regular methods. |
858 */ | 857 */ |
859 class MethodGroup { | 858 class MethodGroup { |
860 Map<String, Method> setters = {}; | 859 Map<String, Method> setters = {}; |
861 Map<String, Method> getters = {}; | 860 Map<String, Method> getters = {}; |
862 Map<String, Method> constructors = {}; | 861 Map<String, Method> constructors = {}; |
863 Map<String, Method> operators = {}; | 862 Map<String, Method> operators = {}; |
864 Map<String, Method> regularMethods = {}; | 863 Map<String, Method> regularMethods = {}; |
865 | 864 |
866 void addMethod(MethodMirror mirror) { | 865 void addMethod(MethodMirror mirror) { |
867 var method = new Method(mirror.simpleName, mirror.isStatic, | 866 var method = new Method(mirror.simpleName, mirror.isStatic, |
868 mirror.isAbstract, mirror.isConstConstructor, _type(mirror.returnType), | 867 mirror.isAbstract, mirror.isConstConstructor, _type(mirror.returnType), |
869 _commentToHtml(mirror), _parameters(mirror.parameters), | 868 _commentToHtml(mirror), _parameters(mirror.parameters), |
870 _annotations(mirror), mirror.qualifiedName, _isHidden(mirror), | 869 _annotations(mirror), mirror.qualifiedName, _isHidden(mirror), |
871 mirror.owner.qualifiedName); | 870 mirror.owner.qualifiedName); |
872 entityMap[mirror.qualifiedName] = method; | 871 entityMap[mirror.qualifiedName] = method; |
873 _currentMember = mirror; | 872 _currentMember = mirror; |
874 if (mirror.isSetter) { | 873 if (mirror.isSetter) { |
875 setters[mirror.simpleName] = method; | 874 setters[mirror.simpleName] = method; |
876 } else if (mirror.isGetter) { | 875 } else if (mirror.isGetter) { |
877 getters[mirror.simpleName] = method; | 876 getters[mirror.simpleName] = method; |
878 } else if (mirror.isConstructor) { | 877 } else if (mirror.isConstructor) { |
879 constructors[mirror.simpleName] = method; | 878 constructors[mirror.simpleName] = method; |
880 } else if (mirror.isOperator) { | 879 } else if (mirror.isOperator) { |
881 operators[mirror.simpleName] = method; | 880 operators[mirror.simpleName] = method; |
882 } else if (mirror.isRegularMethod) { | 881 } else if (mirror.isRegularMethod) { |
883 regularMethods[mirror.simpleName] = method; | 882 regularMethods[mirror.simpleName] = method; |
884 } else { | 883 } else { |
885 throw new ArgumentError('${mirror.simpleName} - no method type match'); | 884 throw new ArgumentError('${mirror.simpleName} - no method type match'); |
886 } | 885 } |
887 } | 886 } |
888 | 887 |
889 void addInherited(Class parent) { | 888 void addInherited(Class parent) { |
890 setters.addAll(parent.inheritedMethods.setters); | 889 setters.addAll(parent.inheritedMethods.setters); |
891 getters.addAll(parent.inheritedMethods.getters); | 890 getters.addAll(parent.inheritedMethods.getters); |
892 operators.addAll(parent.inheritedMethods.operators); | 891 operators.addAll(parent.inheritedMethods.operators); |
893 regularMethods.addAll(parent.inheritedMethods.regularMethods); | 892 regularMethods.addAll(parent.inheritedMethods.regularMethods); |
894 if (_isVisible(parent)) { | 893 if (_isVisible(parent)) { |
895 setters.addAll(parent.methods.setters); | 894 setters.addAll(parent.methods.setters); |
896 getters.addAll(parent.methods.getters); | 895 getters.addAll(parent.methods.getters); |
897 operators.addAll(parent.methods.operators); | 896 operators.addAll(parent.methods.operators); |
898 regularMethods.addAll(parent.methods.regularMethods); | 897 regularMethods.addAll(parent.methods.regularMethods); |
899 } | 898 } |
900 } | 899 } |
901 | 900 |
902 Map toMap() => { | 901 Map toMap() => { |
903 'setters': recurseMap(setters), | 902 'setters': recurseMap(setters), |
904 'getters': recurseMap(getters), | 903 'getters': recurseMap(getters), |
905 'constructors': recurseMap(constructors), | 904 'constructors': recurseMap(constructors), |
906 'operators': recurseMap(operators), | 905 'operators': recurseMap(operators), |
907 'methods': recurseMap(regularMethods) | 906 'methods': recurseMap(regularMethods) |
908 }; | 907 }; |
909 | 908 |
910 Method operator [](String qualifiedName) { | 909 Method operator [](String qualifiedName) { |
911 if (setters.containsKey(qualifiedName)) return setters[qualifiedName]; | 910 if (setters.containsKey(qualifiedName)) return setters[qualifiedName]; |
912 if (getters.containsKey(qualifiedName)) return getters[qualifiedName]; | 911 if (getters.containsKey(qualifiedName)) return getters[qualifiedName]; |
913 if (operators.containsKey(qualifiedName)) return operators[qualifiedName]; | 912 if (operators.containsKey(qualifiedName)) return operators[qualifiedName]; |
914 if (regularMethods.containsKey(qualifiedName)) { | 913 if (regularMethods.containsKey(qualifiedName)) { |
915 return regularMethods[qualifiedName]; | 914 return regularMethods[qualifiedName]; |
916 } | 915 } |
917 return null; | 916 return null; |
918 } | 917 } |
919 | 918 |
920 void forEach(void f(String key, Method value)) { | 919 void forEach(void f(String key, Method value)) { |
921 setters.forEach(f); | 920 setters.forEach(f); |
922 getters.forEach(f); | 921 getters.forEach(f); |
923 operators.forEach(f); | 922 operators.forEach(f); |
924 regularMethods.forEach(f); | 923 regularMethods.forEach(f); |
925 } | 924 } |
926 } | 925 } |
927 | 926 |
928 /** | 927 /** |
929 * A class containing properties of a Dart method/function parameter. | 928 * A class containing properties of a Dart method/function parameter. |
930 */ | 929 */ |
931 class Parameter { | 930 class Parameter { |
932 | 931 |
933 String name; | 932 String name; |
934 bool isOptional; | 933 bool isOptional; |
935 bool isNamed; | 934 bool isNamed; |
936 bool hasDefaultValue; | 935 bool hasDefaultValue; |
937 Type type; | 936 Type type; |
938 String defaultValue; | 937 String defaultValue; |
939 | 938 |
940 /// List of the meta annotations on the parameter. | 939 /// List of the meta annotations on the parameter. |
941 List<String> annotations; | 940 List<String> annotations; |
942 | 941 |
943 Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue, | 942 Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue, |
944 this.type, this.defaultValue, this.annotations); | 943 this.type, this.defaultValue, this.annotations); |
945 | 944 |
946 /// Generates a map describing the [Parameter] object. | 945 /// Generates a map describing the [Parameter] object. |
947 Map toMap() => { | 946 Map toMap() => { |
948 'name': name, | 947 'name': name, |
949 'optional': isOptional.toString(), | 948 'optional': isOptional.toString(), |
950 'named': isNamed.toString(), | 949 'named': isNamed.toString(), |
951 'default': hasDefaultValue.toString(), | 950 'default': hasDefaultValue.toString(), |
952 'type': new List.filled(1, type.toMap()), | 951 'type': new List.filled(1, type.toMap()), |
953 'value': defaultValue, | 952 'value': defaultValue, |
954 'annotations': annotations.map((a) => a.toMap()).toList() | 953 'annotations': annotations.map((a) => a.toMap()).toList() |
955 }; | 954 }; |
956 } | 955 } |
957 | 956 |
958 /** | 957 /** |
959 * A class containing properties of a Generic. | 958 * A class containing properties of a Generic. |
960 */ | 959 */ |
961 class Generic { | 960 class Generic { |
962 String name; | 961 String name; |
963 String type; | 962 String type; |
964 | 963 |
965 Generic(this.name, this.type); | 964 Generic(this.name, this.type); |
966 | 965 |
967 Map toMap() => { | 966 Map toMap() => { |
968 'name': name, | 967 'name': name, |
969 'type': type | 968 'type': type |
970 }; | 969 }; |
971 } | 970 } |
972 | 971 |
973 /** | 972 /** |
974 * Holds the name of a return type, and its generic type parameters. | 973 * Holds the name of a return type, and its generic type parameters. |
975 * | 974 * |
976 * Return types are of a form [outer]<[inner]>. | 975 * Return types are of a form [outer]<[inner]>. |
977 * If there is no [inner] part, [inner] will be an empty list. | 976 * If there is no [inner] part, [inner] will be an empty list. |
978 * | 977 * |
979 * For example: | 978 * For example: |
980 * int size() | 979 * int size() |
981 * "return" : | 980 * "return" : |
982 * - "outer" : "dart.core.int" | 981 * - "outer" : "dart.core.int" |
983 * "inner" : | 982 * "inner" : |
984 * | 983 * |
985 * List<String> toList() | 984 * List<String> toList() |
986 * "return" : | 985 * "return" : |
987 * - "outer" : "dart.core.List" | 986 * - "outer" : "dart.core.List" |
988 * "inner" : | 987 * "inner" : |
989 * - "outer" : "dart.core.String" | 988 * - "outer" : "dart.core.String" |
990 * "inner" : | 989 * "inner" : |
991 * | 990 * |
992 * Map<String, List<int>> | 991 * Map<String, List<int>> |
993 * "return" : | 992 * "return" : |
994 * - "outer" : "dart.core.Map" | 993 * - "outer" : "dart.core.Map" |
995 * "inner" : | 994 * "inner" : |
996 * - "outer" : "dart.core.String" | 995 * - "outer" : "dart.core.String" |
997 * "inner" : | 996 * "inner" : |
998 * - "outer" : "dart.core.List" | 997 * - "outer" : "dart.core.List" |
999 * "inner" : | 998 * "inner" : |
1000 * - "outer" : "dart.core.int" | 999 * - "outer" : "dart.core.int" |
1001 * "inner" : | 1000 * "inner" : |
1002 */ | 1001 */ |
1003 class Type { | 1002 class Type { |
1004 String outer; | 1003 String outer; |
1005 List<Type> inner; | 1004 List<Type> inner; |
1006 | 1005 |
1007 Type(this.outer, this.inner); | 1006 Type(this.outer, this.inner); |
1008 | 1007 |
1009 Map toMap() => { | 1008 Map toMap() => { |
1010 'outer': outer, | 1009 'outer': outer, |
1011 'inner': inner.map((e) => e.toMap()).toList() | 1010 'inner': inner.map((e) => e.toMap()).toList() |
1012 }; | 1011 }; |
1013 } | 1012 } |
1014 | 1013 |
1015 /** | 1014 /** |
1016 * Holds the name of the annotation, and its parameters. | 1015 * Holds the name of the annotation, and its parameters. |
1017 */ | 1016 */ |
1018 class Annotation { | 1017 class Annotation { |
1019 String qualifiedName; | 1018 String qualifiedName; |
1020 List<String> parameters; | 1019 List<String> parameters; |
1021 | 1020 |
1022 Annotation(this.qualifiedName, this.parameters); | 1021 Annotation(this.qualifiedName, this.parameters); |
1023 | 1022 |
1024 Map toMap() => { | 1023 Map toMap() => { |
1025 'name': qualifiedName, | 1024 'name': qualifiedName, |
1026 'parameters': parameters | 1025 'parameters': parameters |
1027 }; | 1026 }; |
1028 } | 1027 } |
OLD | NEW |