| 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 |