| 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 * |
| 11 * $ dart docgen.dart [OPTIONS] [FILE/DIR] | 11 * $ dart docgen.dart [OPTIONS] [FILE/DIR] |
| 12 * | 12 * |
| 13 * This creates files called `docs/<library_name>.yaml` in your current | 13 * This creates files called `docs/<library_name>.yaml` in your current |
| 14 * working directory. | 14 * working directory. |
| 15 */ | 15 */ |
| 16 library docgen; | 16 library docgen; |
| 17 | 17 |
| 18 import 'dart:io'; | 18 import 'dart:io'; |
| 19 import 'dart:json'; | 19 import 'dart:json'; |
| 20 import 'dart:async'; | 20 import 'dart:async'; |
| 21 | 21 |
| 22 import 'package:logging/logging.dart'; | 22 import 'package:logging/logging.dart'; |
| 23 import 'package:markdown/markdown.dart' as markdown; | 23 import 'package:markdown/markdown.dart' as markdown; |
| 24 import 'package:pathos/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'; | 33 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.
dart'; |
| 34 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.
dart'; | 34 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.
dart'; |
| 35 import '../../../sdk/lib/_internal/libraries.dart'; | 35 import '../../../sdk/lib/_internal/libraries.dart'; |
| 36 | 36 |
| 37 var logger = new Logger('Docgen'); | 37 var logger = new Logger('Docgen'); |
| 38 | 38 |
| 39 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] [fooDir/barFile]'; | 39 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] [fooDir/barFile]'; |
| 40 | 40 |
| 41 /// Current library being documented to be used for comment links. | 41 /// Current library being documented to be used for comment links. |
| 42 LibraryMirror _currentLibrary; | 42 LibraryMirror _currentLibrary; |
| 43 | 43 |
| 44 /// Current class being documented to be used for comment links. | 44 /// Current class being documented to be used for comment links. |
| 45 ClassMirror _currentClass; | 45 ClassMirror _currentClass; |
| 46 | 46 |
| 47 /// Current member being documented to be used for comment links. | 47 /// Current member being documented to be used for comment links. |
| 48 MemberMirror _currentMember; | 48 MemberMirror _currentMember; |
| 49 | 49 |
| 50 /// Resolves reference links in doc comments. | 50 /// Resolves reference links in doc comments. |
| 51 markdown.Resolver linkResolver; | 51 markdown.Resolver linkResolver; |
| 52 | 52 |
| 53 /** | 53 /** |
| 54 * Docgen constructor initializes the link resolver for markdown parsing. | 54 * Docgen constructor initializes the link resolver for markdown parsing. |
| 55 * Also initializes the command line arguments. | 55 * Also initializes the command line arguments. |
| 56 * | 56 * |
| 57 * [packageRoot] is the packages directory of the directory being analyzed. | 57 * [packageRoot] is the packages directory of the directory being analyzed. |
| 58 * If [includeSdk] is `true`, then any SDK libraries explicitly imported will | 58 * If [includeSdk] is `true`, then any SDK libraries explicitly imported will |
| 59 * also be documented. | 59 * also be documented. |
| 60 * If [parseSdk] is `true`, then all Dart SDK libraries will be documented. | 60 * If [parseSdk] is `true`, then all Dart SDK libraries will be documented. |
| 61 * This option is useful when only the SDK libraries are needed. | 61 * This option is useful when only the SDK libraries are needed. |
| 62 * | 62 * |
| 63 * Returns `true` if docgen sucessfuly completes. | 63 * Returns `true` if docgen sucessfuly completes. |
| 64 */ | 64 */ |
| 65 Future<bool> docgen(List<String> files, {String packageRoot, | 65 Future<bool> docgen(List<String> files, {String packageRoot, |
| 66 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, | 66 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, |
| 67 bool parseSdk: false}) { | 67 bool parseSdk: false}) { |
| 68 if (packageRoot == null && !parseSdk) { | 68 if (packageRoot == null && !parseSdk) { |
| 69 // TODO(janicejl): At the moment, if a single file is passed it, it is | 69 // TODO(janicejl): At the moment, if a single file is passed it, it is |
| 70 // assumed that it does not have a package root unless it is passed in by | 70 // assumed that it does not have a package root unless it is passed in by |
| 71 // the user. In future, find a better way to find the packageRoot and also | 71 // the user. In future, find a better way to find the packageRoot and also |
| 72 // fully test finding the packageRoot. | 72 // fully test finding the packageRoot. |
| 73 if (FileSystemEntity.typeSync(files.first) | 73 if (FileSystemEntity.typeSync(files.first) |
| 74 == FileSystemEntityType.DIRECTORY) { | 74 == FileSystemEntityType.DIRECTORY) { |
| 75 packageRoot = _findPackageRoot(files.first); | 75 packageRoot = _findPackageRoot(files.first); |
| 76 } | 76 } |
| 77 } | 77 } |
| 78 logger.info('Package Root: ${packageRoot}'); | 78 logger.info('Package Root: ${packageRoot}'); |
| 79 | 79 |
| 80 linkResolver = (name) => | 80 linkResolver = (name) => |
| 81 fixReference(name, _currentLibrary, _currentClass, _currentMember); | 81 fixReference(name, _currentLibrary, _currentClass, _currentMember); |
| 82 | 82 |
| 83 return getMirrorSystem(files, packageRoot, parseSdk: parseSdk) | 83 return getMirrorSystem(files, packageRoot, parseSdk: parseSdk) |
| 84 .then((MirrorSystem mirrorSystem) { | 84 .then((MirrorSystem mirrorSystem) { |
| 85 if (mirrorSystem.libraries.isEmpty) { | 85 if (mirrorSystem.libraries.isEmpty) { |
| 86 throw new StateError('No library mirrors were created.'); | 86 throw new StateError('No library mirrors were created.'); |
| 87 } | 87 } |
| 88 _documentLibraries(mirrorSystem.libraries.values, | 88 _documentLibraries(mirrorSystem.libraries.values, |
| 89 includeSdk: includeSdk, includePrivate: includePrivate, | 89 includeSdk: includeSdk, includePrivate: includePrivate, |
| 90 outputToYaml: outputToYaml); | 90 outputToYaml: outputToYaml); |
| 91 | 91 |
| 92 return true; | 92 return true; |
| 93 }); | 93 }); |
| 94 } | 94 } |
| 95 | 95 |
| 96 List<String> _listLibraries(List<String> args) { | 96 List<String> _listLibraries(List<String> args) { |
| 97 // TODO(janicejl): At the moment, only have support to have either one file, | 97 // TODO(janicejl): At the moment, only have support to have either one file, |
| 98 // or one directory. This is because there can only be one package directory | 98 // or one directory. This is because there can only be one package directory |
| 99 // since only one docgen is created per run. | 99 // since only one docgen is created per run. |
| 100 if (args.length != 1) throw new UnsupportedError(USAGE); | 100 if (args.length != 1) throw new UnsupportedError(USAGE); |
| 101 var libraries = new List<String>(); | 101 var libraries = new List<String>(); |
| 102 var type = FileSystemEntity.typeSync(args[0]); | 102 var type = FileSystemEntity.typeSync(args[0]); |
| 103 | 103 |
| 104 if (type == FileSystemEntityType.FILE) { | 104 if (type == FileSystemEntityType.FILE) { |
| 105 libraries.add(path.absolute(args[0])); | 105 libraries.add(path.absolute(args[0])); |
| 106 logger.info('Added to libraries: ${libraries.last}'); | 106 logger.info('Added to libraries: ${libraries.last}'); |
| 107 } else { | 107 } else { |
| 108 libraries.addAll(_listDartFromDir(args[0])); | 108 libraries.addAll(_listDartFromDir(args[0])); |
| 109 } | 109 } |
| 110 return libraries; | 110 return libraries; |
| 111 } | 111 } |
| 112 | 112 |
| 113 List<String> _listDartFromDir(String args) { | 113 List<String> _listDartFromDir(String args) { |
| 114 var files = listDir(args, recursive: true); | 114 var files = listDir(args, recursive: true); |
| 115 // To avoid anaylzing package files twice, only files with paths not | 115 // To avoid anaylzing package files twice, only files with paths not |
| 116 // containing '/packages' will be added. The only exception is if the file to | 116 // containing '/packages' will be added. The only exception is if the file to |
| 117 // analyze already has a '/package' in its path. | 117 // analyze already has a '/package' in its path. |
| 118 return files.where((f) => f.endsWith('.dart') && | 118 return files.where((f) => f.endsWith('.dart') && |
| 119 (!f.contains('/packages') || args.contains('/packages'))).toList() | 119 (!f.contains('/packages') || args.contains('/packages'))).toList() |
| 120 ..forEach((lib) => logger.info('Added to libraries: $lib')); | 120 ..forEach((lib) => logger.info('Added to libraries: $lib')); |
| 121 } | 121 } |
| 122 | 122 |
| 123 String _findPackageRoot(String directory) { | 123 String _findPackageRoot(String directory) { |
| 124 var files = listDir(directory, recursive: true); | 124 var files = listDir(directory, recursive: true); |
| 125 // Return '' means that there was no pubspec.yaml and therefor no packageRoot.
| 125 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. |
| 126 String packageRoot = files.firstWhere((f) => | 126 String packageRoot = files.firstWhere((f) => |
| 127 f.endsWith('/pubspec.yaml'), orElse: () => ''); | 127 f.endsWith('/pubspec.yaml'), orElse: () => ''); |
| 128 if (packageRoot != '') { | 128 if (packageRoot != '') { |
| 129 packageRoot = path.dirname(packageRoot) + '/packages'; | 129 packageRoot = path.dirname(packageRoot) + '/packages'; |
| 130 } | 130 } |
| 131 return packageRoot; | 131 return packageRoot; |
| 132 } | 132 } |
| 133 | 133 |
| 134 List<String> _listSdk() { | 134 List<String> _listSdk() { |
| 135 var sdk = new List<String>(); | 135 var sdk = new List<String>(); |
| 136 LIBRARIES.forEach((String name, LibraryInfo info) { | 136 LIBRARIES.forEach((String name, LibraryInfo info) { |
| 137 if (info.documented) { | 137 if (info.documented) { |
| 138 sdk.add('dart:$name'); | 138 sdk.add('dart:$name'); |
| 139 logger.info('Add to SDK: ${sdk.last}'); | 139 logger.info('Add to SDK: ${sdk.last}'); |
| 140 } | 140 } |
| 141 }); | 141 }); |
| 142 return sdk; | 142 return sdk; |
| 143 } | 143 } |
| 144 | 144 |
| 145 /** | 145 /** |
| 146 * Analyzes set of libraries by getting a mirror system and triggers the | 146 * Analyzes set of libraries by getting a mirror system and triggers the |
| 147 * documentation of the libraries. | 147 * documentation of the libraries. |
| 148 */ | 148 */ |
| 149 Future<MirrorSystem> getMirrorSystem(List<String> args, String packageRoot, | 149 Future<MirrorSystem> getMirrorSystem(List<String> args, String packageRoot, |
| 150 {bool parseSdk:false}) { | 150 {bool parseSdk:false}) { |
| 151 var libraries = !parseSdk ? _listLibraries(args) : _listSdk(); | 151 var libraries = !parseSdk ? _listLibraries(args) : _listSdk(); |
| 152 if (libraries.isEmpty) throw new StateError('No Libraries.'); | 152 if (libraries.isEmpty) throw new StateError('No Libraries.'); |
| 153 // DART_SDK should be set to the root of the SDK library. | 153 // DART_SDK should be set to the root of the SDK library. |
| 154 var sdkRoot = Platform.environment['DART_SDK']; | 154 var sdkRoot = Platform.environment['DART_SDK']; |
| 155 if (sdkRoot != null) { | 155 if (sdkRoot != null) { |
| 156 logger.info('Using DART_SDK to find SDK at $sdkRoot'); | 156 logger.info('Using DART_SDK to find SDK at $sdkRoot'); |
| 157 } else { | 157 } else { |
| 158 // If DART_SDK is not defined in the environment, | 158 // If DART_SDK is not defined in the environment, |
| 159 // assuming the dart executable is from the Dart SDK folder inside bin. | 159 // assuming the dart executable is from the Dart SDK folder inside bin. |
| 160 sdkRoot = path.dirname(path.dirname(new Options().executable)); | 160 sdkRoot = path.dirname(path.dirname(new Options().executable)); |
| 161 logger.info('SDK Root: ${sdkRoot}'); | 161 logger.info('SDK Root: ${sdkRoot}'); |
| 162 } | 162 } |
| 163 | 163 |
| 164 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot); | 164 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot); |
| 165 } | 165 } |
| 166 | 166 |
| 167 // TODO(janicejl): Should make docgen fail gracefully, or output a friendly | 167 // TODO(janicejl): Should make docgen fail gracefully, or output a friendly |
| 168 // error message letting them know why it is failing to create a mirror system. | 168 // error message letting them know why it is failing to create a mirror system. |
| 169 // If there is conflicting library names, should modify it with a hash at the | 169 // If there is conflicting library names, should modify it with a hash at the |
| 170 // end of it's library name. | 170 // end of it's library name. |
| 171 /** | 171 /** |
| 172 * Analyzes set of libraries and provides a mirror system which can be used | 172 * Analyzes set of libraries and provides a mirror system which can be used |
| 173 * for static inspection of the source code. | 173 * for static inspection of the source code. |
| 174 */ | 174 */ |
| 175 Future<MirrorSystem> _analyzeLibraries(List<String> libraries, | 175 Future<MirrorSystem> _analyzeLibraries(List<String> libraries, |
| 176 String libraryRoot, {String packageRoot}) { | 176 String libraryRoot, {String packageRoot}) { |
| 177 SourceFileProvider provider = new SourceFileProvider(); | 177 SourceFileProvider provider = new SourceFileProvider(); |
| 178 api.DiagnosticHandler diagnosticHandler = | 178 api.DiagnosticHandler diagnosticHandler = |
| 179 new FormattingDiagnosticHandler(provider).diagnosticHandler; | 179 new FormattingDiagnosticHandler(provider).diagnosticHandler; |
| 180 Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot')); | 180 Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot')); |
| 181 Uri packageUri = null; | 181 Uri packageUri = null; |
| 182 if (packageRoot != null) { | 182 if (packageRoot != null) { |
| 183 packageUri = currentDirectory.resolve(appendSlash('$packageRoot')); | 183 packageUri = currentDirectory.resolve(appendSlash('$packageRoot')); |
| 184 } | 184 } |
| 185 List<Uri> librariesUri = <Uri>[]; | 185 List<Uri> librariesUri = <Uri>[]; |
| 186 libraries.forEach((library) { | 186 libraries.forEach((library) { |
| 187 librariesUri.add(currentDirectory.resolve(library)); | 187 librariesUri.add(currentDirectory.resolve(library)); |
| 188 }); | 188 }); |
| 189 return dart2js.analyze(librariesUri, libraryUri, packageUri, | 189 return dart2js.analyze(librariesUri, libraryUri, packageUri, |
| 190 provider.readStringFromUri, diagnosticHandler, | 190 provider.readStringFromUri, diagnosticHandler, |
| 191 ['--preserve-comments', '--categories=Client,Server']) | 191 ['--preserve-comments', '--categories=Client,Server']) |
| 192 ..catchError((error) { | 192 ..catchError((error) { |
| 193 logger.severe('Error: Failed to create mirror system. '); | 193 logger.severe('Error: Failed to create mirror system. '); |
| 194 // TODO(janicejl): Use the stack trace package when bug is resolved. | 194 // TODO(janicejl): Use the stack trace package when bug is resolved. |
| 195 // Currently, a string is thrown when it fails to create a mirror | 195 // Currently, a string is thrown when it fails to create a mirror |
| 196 // system, and it is not possible to use the stack trace. BUG(#11622) | 196 // system, and it is not possible to use the stack trace. BUG(#11622) |
| 197 // To avoid printing the stack trace. | 197 // To avoid printing the stack trace. |
| 198 exit(1); | 198 exit(1); |
| 199 }); | 199 }); |
| 200 } | 200 } |
| 201 | 201 |
| 202 /** | 202 /** |
| 203 * Creates documentation for filtered libraries. | 203 * Creates documentation for filtered libraries. |
| 204 */ | 204 */ |
| 205 void _documentLibraries(List<LibraryMirror> libraries, | 205 void _documentLibraries(List<LibraryMirror> libraries, |
| 206 {bool includeSdk:false, bool includePrivate:false, bool | 206 {bool includeSdk:false, bool includePrivate:false, bool |
| 207 outputToYaml:true}) { | 207 outputToYaml:true}) { |
| 208 libraries.forEach((lib) { | 208 libraries.forEach((lib) { |
| 209 // 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:'. |
| 210 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { | 210 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { |
| 211 var library = generateLibrary(lib, includePrivate: includePrivate); | 211 var library = generateLibrary(lib, includePrivate: includePrivate); |
| 212 _writeLibraryToFile(library, outputToYaml); | 212 _writeLibraryToFile(library, outputToYaml); |
| 213 } | 213 } |
| 214 }); | 214 }); |
| 215 // Outputs a text file with a list of files available after creating all | 215 // Outputs a text file with a list of files available after creating all |
| 216 // the libraries. This will help the viewer know what files are available | 216 // the libraries. This will help the viewer know what files are available |
| 217 // to read in. | 217 // to read in. |
| 218 _writeToFile(listDir('docs').join('\n').replaceAll('docs/', ''), | 218 _writeToFile(listDir('docs').join('\n').replaceAll('docs/', ''), |
| 219 'library_list.txt'); | 219 'library_list.txt'); |
| 220 } | 220 } |
| 221 | 221 |
| 222 Library generateLibrary(dart2js.Dart2JsLibraryMirror library, | 222 Library generateLibrary(dart2js.Dart2JsLibraryMirror library, |
| 223 {bool includePrivate:false}) { | 223 {bool includePrivate:false}) { |
| 224 _currentLibrary = library; | 224 _currentLibrary = library; |
| 225 var result = new Library(library.qualifiedName, _getComment(library), | 225 var result = new Library(library.qualifiedName, _getComment(library), |
| 226 _getVariables(library.variables, includePrivate), | 226 _getVariables(library.variables, includePrivate), |
| 227 _getMethods(library.functions, includePrivate), | 227 _getMethods(library.functions, includePrivate), |
| 228 _getClasses(library.classes, includePrivate)); | 228 _getClasses(library.classes, includePrivate)); |
| 229 logger.fine('Generated library for ${result.name}'); | 229 logger.fine('Generated library for ${result.name}'); |
| 230 return result; | 230 return result; |
| 231 } | 231 } |
| 232 | 232 |
| 233 void _writeLibraryToFile(Library result, bool outputToYaml) { | 233 void _writeLibraryToFile(Library result, bool outputToYaml) { |
| 234 if (outputToYaml) { | 234 if (outputToYaml) { |
| 235 _writeToFile(getYamlString(result.toMap()), '${result.name}.yaml'); | 235 _writeToFile(getYamlString(result.toMap()), '${result.name}.yaml'); |
| 236 } else { | 236 } else { |
| 237 _writeToFile(stringify(result.toMap()), '${result.name}.json'); | 237 _writeToFile(stringify(result.toMap()), '${result.name}.json'); |
| 238 } | 238 } |
| 239 | 239 |
| 240 } | 240 } |
| 241 | 241 |
| 242 /** | 242 /** |
| 243 * Returns a list of meta annotations assocated with a mirror. | 243 * Returns a list of meta annotations assocated with a mirror. |
| 244 */ | 244 */ |
| 245 List<String> _getAnnotations(DeclarationMirror mirror) { | 245 List<String> _getAnnotations(DeclarationMirror mirror) { |
| 246 var annotations = mirror.metadata.where((e) => | 246 var annotations = mirror.metadata.where((e) => |
| 247 e is dart2js.Dart2JsConstructedConstantMirror); | 247 e is dart2js.Dart2JsConstructedConstantMirror); |
| 248 return annotations.map((e) => e.type.qualifiedName).toList(); | 248 return annotations.map((e) => e.type.qualifiedName).toList(); |
| 249 } | 249 } |
| 250 | 250 |
| 251 /** | 251 /** |
| 252 * Returns any documentation comments associated with a mirror with | 252 * Returns any documentation comments associated with a mirror with |
| 253 * simple markdown converted to html. | 253 * simple markdown converted to html. |
| 254 */ | 254 */ |
| 255 String _getComment(DeclarationMirror mirror) { | 255 String _getComment(DeclarationMirror mirror) { |
| 256 String commentText; | 256 String commentText; |
| 257 mirror.metadata.forEach((metadata) { | 257 mirror.metadata.forEach((metadata) { |
| 258 if (metadata is CommentInstanceMirror) { | 258 if (metadata is CommentInstanceMirror) { |
| 259 CommentInstanceMirror comment = metadata; | 259 CommentInstanceMirror comment = metadata; |
| 260 if (comment.isDocComment) { | 260 if (comment.isDocComment) { |
| 261 if (commentText == null) { | 261 if (commentText == null) { |
| 262 commentText = comment.trimmedText; | 262 commentText = comment.trimmedText; |
| 263 } else { | 263 } else { |
| 264 commentText = '$commentText ${comment.trimmedText}'; | 264 commentText = '$commentText ${comment.trimmedText}'; |
| 265 } | 265 } |
| 266 } | 266 } |
| 267 } | 267 } |
| 268 }); | 268 }); |
| 269 commentText = commentText == null ? '' : | 269 commentText = commentText == null ? '' : |
| 270 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver) | 270 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver) |
| 271 .replaceAll('\n', ' '); | 271 .replaceAll('\n', ' '); |
| 272 return commentText; | 272 return commentText; |
| 273 } | 273 } |
| 274 | 274 |
| 275 /** | 275 /** |
| 276 * Converts all [foo] references in comments to <a>libraryName.foo</a>. | 276 * Converts all [foo] references in comments to <a>libraryName.foo</a>. |
| 277 */ | 277 */ |
| 278 markdown.Node fixReference(String name, LibraryMirror currentLibrary, | 278 markdown.Node fixReference(String name, LibraryMirror currentLibrary, |
| 279 ClassMirror currentClass, MemberMirror currentMember) { | 279 ClassMirror currentClass, MemberMirror currentMember) { |
| 280 var reference; | 280 var reference; |
| 281 var memberScope = currentMember == null ? | 281 var memberScope = currentMember == null ? |
| 282 null : currentMember.lookupInScope(name); | 282 null : currentMember.lookupInScope(name); |
| 283 if (memberScope != null) reference = memberScope.qualifiedName; | 283 if (memberScope != null) reference = memberScope.qualifiedName; |
| 284 else { | 284 else { |
| 285 var classScope = currentClass == null ? | 285 var classScope = currentClass == null ? |
| 286 null : currentClass.lookupInScope(name); | 286 null : currentClass.lookupInScope(name); |
| 287 reference = classScope != null ? classScope.qualifiedName : name; | 287 reference = classScope != null ? classScope.qualifiedName : name; |
| 288 } | 288 } |
| 289 return new markdown.Element.text('a', reference); | 289 return new markdown.Element.text('a', reference); |
| 290 } | 290 } |
| 291 | 291 |
| 292 /** | 292 /** |
| 293 * Returns a map of [Variable] objects constructed from inputted mirrors. | 293 * Returns a map of [Variable] objects constructed from inputted mirrors. |
| 294 */ | 294 */ |
| 295 Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap, | 295 Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap, |
| 296 bool includePrivate) { | 296 bool includePrivate) { |
| 297 var data = {}; | 297 var data = {}; |
| 298 // TODO(janicejl): When map to map feature is created, replace the below with | 298 // TODO(janicejl): When map to map feature is created, replace the below with |
| 299 // a filter. Issue(#9590). | 299 // a filter. Issue(#9590). |
| 300 mirrorMap.forEach((String mirrorName, VariableMirror mirror) { | 300 mirrorMap.forEach((String mirrorName, VariableMirror mirror) { |
| 301 if (includePrivate || !mirror.isPrivate) { | 301 if (includePrivate || !mirror.isPrivate) { |
| 302 _currentMember = mirror; | 302 _currentMember = mirror; |
| 303 data[mirrorName] = new Variable(mirrorName, mirror.qualifiedName, | 303 data[mirrorName] = new Variable(mirrorName, mirror.qualifiedName, |
| 304 mirror.isFinal, mirror.isStatic, mirror.type.qualifiedName, | 304 mirror.isFinal, mirror.isStatic, mirror.type.qualifiedName, |
| 305 _getComment(mirror), _getAnnotations(mirror)); | 305 _getComment(mirror), _getAnnotations(mirror)); |
| 306 } | 306 } |
| 307 }); | 307 }); |
| 308 return data; | 308 return data; |
| 309 } | 309 } |
| 310 | 310 |
| 311 /** | 311 /** |
| 312 * Returns a map of [Method] objects constructed from inputted mirrors. | 312 * Returns a map of [Method] objects constructed from inputted mirrors. |
| 313 */ | 313 */ |
| 314 Map<String, Method> _getMethods(Map<String, MethodMirror> mirrorMap, | 314 Map<String, Method> _getMethods(Map<String, MethodMirror> mirrorMap, |
| 315 bool includePrivate) { | 315 bool includePrivate) { |
| 316 var data = {}; | 316 var data = {}; |
| 317 mirrorMap.forEach((String mirrorName, MethodMirror mirror) { | 317 mirrorMap.forEach((String mirrorName, MethodMirror mirror) { |
| 318 if (includePrivate || !mirror.isPrivate) { | 318 if (includePrivate || !mirror.isPrivate) { |
| 319 _currentMember = mirror; | 319 _currentMember = mirror; |
| 320 data[mirrorName] = new Method(mirrorName, mirror.qualifiedName, | 320 data[mirrorName] = new Method(mirrorName, mirror.qualifiedName, |
| 321 mirror.isSetter, mirror.isGetter, mirror.isConstructor, | 321 mirror.isSetter, mirror.isGetter, mirror.isConstructor, |
| 322 mirror.isOperator, mirror.isStatic, mirror.returnType.qualifiedName, | 322 mirror.isOperator, mirror.isStatic, mirror.returnType.qualifiedName, |
| 323 _getComment(mirror), _getParameters(mirror.parameters), | 323 _getComment(mirror), _getParameters(mirror.parameters), |
| 324 _getAnnotations(mirror)); | 324 _getAnnotations(mirror)); |
| 325 } | 325 } |
| 326 }); | 326 }); |
| 327 return data; | 327 return data; |
| 328 } | 328 } |
| 329 | 329 |
| 330 /** | 330 /** |
| 331 * Returns a map of [Class] objects constructed from inputted mirrors. | 331 * Returns a map of [Class] objects constructed from inputted mirrors. |
| 332 */ | 332 */ |
| 333 Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap, | 333 Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap, |
| 334 bool includePrivate) { | 334 bool includePrivate) { |
| 335 var data = {}; | 335 var data = {}; |
| 336 mirrorMap.forEach((String mirrorName, ClassMirror mirror) { | 336 mirrorMap.forEach((String mirrorName, ClassMirror mirror) { |
| 337 if (includePrivate || !mirror.isPrivate) { | 337 if (includePrivate || !mirror.isPrivate) { |
| 338 _currentClass = mirror; | 338 _currentClass = mirror; |
| 339 var superclass = (mirror.superclass != null) ? | 339 var superclass = (mirror.superclass != null) ? |
| 340 mirror.superclass.qualifiedName : ''; | 340 mirror.superclass.qualifiedName : ''; |
| 341 var interfaces = | 341 var interfaces = |
| 342 mirror.superinterfaces.map((interface) => interface.qualifiedName); | 342 mirror.superinterfaces.map((interface) => interface.qualifiedName); |
| 343 data[mirrorName] = new Class(mirrorName, mirror.qualifiedName, | 343 data[mirrorName] = new Class(mirrorName, mirror.qualifiedName, |
| 344 superclass, mirror.isAbstract, mirror.isTypedef, | 344 superclass, mirror.isAbstract, mirror.isTypedef, |
| 345 _getComment(mirror), interfaces.toList(), | 345 _getComment(mirror), interfaces.toList(), |
| 346 _getVariables(mirror.variables, includePrivate), | 346 _getVariables(mirror.variables, includePrivate), |
| 347 _getMethods(mirror.methods, includePrivate), | 347 _getMethods(mirror.methods, includePrivate), |
| 348 _getAnnotations(mirror)); | 348 _getAnnotations(mirror)); |
| 349 } | 349 } |
| 350 }); | 350 }); |
| 351 return data; | 351 return data; |
| 352 } | 352 } |
| 353 | 353 |
| 354 /** | 354 /** |
| 355 * Returns a map of [Parameter] objects constructed from inputted mirrors. | 355 * Returns a map of [Parameter] objects constructed from inputted mirrors. |
| 356 */ | 356 */ |
| 357 Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) { | 357 Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) { |
| 358 var data = {}; | 358 var data = {}; |
| 359 mirrorList.forEach((ParameterMirror mirror) { | 359 mirrorList.forEach((ParameterMirror mirror) { |
| 360 _currentMember = mirror; | 360 _currentMember = mirror; |
| 361 data[mirror.simpleName] = new Parameter(mirror.simpleName, | 361 data[mirror.simpleName] = new Parameter(mirror.simpleName, |
| 362 mirror.qualifiedName, mirror.isOptional, mirror.isNamed, | 362 mirror.qualifiedName, mirror.isOptional, mirror.isNamed, |
| 363 mirror.hasDefaultValue, mirror.type.qualifiedName, | 363 mirror.hasDefaultValue, mirror.type.qualifiedName, |
| 364 mirror.defaultValue, _getAnnotations(mirror)); | 364 mirror.defaultValue, _getAnnotations(mirror)); |
| 365 }); | 365 }); |
| 366 return data; | 366 return data; |
| 367 } | 367 } |
| 368 | 368 |
| 369 /** | 369 /** |
| 370 * Writes text to a file in the 'docs' directory. | 370 * Writes text to a file in the 'docs' directory. |
| 371 */ | 371 */ |
| 372 void _writeToFile(String text, String filename) { | 372 void _writeToFile(String text, String filename) { |
| 373 Directory dir = new Directory('docs'); | 373 Directory dir = new Directory('docs'); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 390 inputMap.forEach((key, value) { | 390 inputMap.forEach((key, value) { |
| 391 outputMap[key] = value.toMap(); | 391 outputMap[key] = value.toMap(); |
| 392 }); | 392 }); |
| 393 return outputMap; | 393 return outputMap; |
| 394 } | 394 } |
| 395 | 395 |
| 396 /** | 396 /** |
| 397 * A class containing contents of a Dart library. | 397 * A class containing contents of a Dart library. |
| 398 */ | 398 */ |
| 399 class Library { | 399 class Library { |
| 400 | 400 |
| 401 /// Documentation comment with converted markdown. | 401 /// Documentation comment with converted markdown. |
| 402 String comment; | 402 String comment; |
| 403 | 403 |
| 404 /// Top-level variables in the library. | 404 /// Top-level variables in the library. |
| 405 Map<String, Variable> variables; | 405 Map<String, Variable> variables; |
| 406 | 406 |
| 407 /// Top-level functions in the library. | 407 /// Top-level functions in the library. |
| 408 Map<String, Method> functions; | 408 Map<String, Method> functions; |
| 409 | 409 |
| 410 /// Classes defined within the library | 410 /// Classes defined within the library |
| 411 Map<String, Class> classes; | 411 Map<String, Class> classes; |
| 412 | 412 |
| 413 String name; | 413 String name; |
| 414 | 414 |
| 415 Library(this.name, this.comment, this.variables, | 415 Library(this.name, this.comment, this.variables, |
| 416 this.functions, this.classes); | 416 this.functions, this.classes); |
| 417 | 417 |
| 418 /// Generates a map describing the [Library] object. | 418 /// Generates a map describing the [Library] object. |
| 419 Map toMap() { | 419 Map toMap() { |
| 420 var libraryMap = {}; | 420 var libraryMap = {}; |
| 421 libraryMap['name'] = name; | 421 libraryMap['name'] = name; |
| 422 libraryMap['comment'] = comment; | 422 libraryMap['comment'] = comment; |
| 423 libraryMap['variables'] = recurseMap(variables); | 423 libraryMap['variables'] = recurseMap(variables); |
| 424 libraryMap['functions'] = recurseMap(functions); | 424 libraryMap['functions'] = recurseMap(functions); |
| 425 libraryMap['classes'] = recurseMap(classes); | 425 libraryMap['classes'] = recurseMap(classes); |
| 426 return libraryMap; | 426 return libraryMap; |
| 427 } | 427 } |
| 428 } | 428 } |
| 429 | 429 |
| 430 /** | 430 /** |
| 431 * A class containing contents of a Dart class. | 431 * A class containing contents of a Dart class. |
| 432 */ | 432 */ |
| 433 // TODO(tmandel): Figure out how to do typedefs (what is needed) | 433 // TODO(tmandel): Figure out how to do typedefs (what is needed) |
| 434 class Class { | 434 class Class { |
| 435 | 435 |
| 436 /// Documentation comment with converted markdown. | 436 /// Documentation comment with converted markdown. |
| 437 String comment; | 437 String comment; |
| 438 | 438 |
| 439 /// List of the names of interfaces that this class implements. | 439 /// List of the names of interfaces that this class implements. |
| 440 List<String> interfaces; | 440 List<String> interfaces; |
| 441 | 441 |
| 442 /// Top-level variables in the class. | 442 /// Top-level variables in the class. |
| 443 Map<String, Variable> variables; | 443 Map<String, Variable> variables; |
| 444 | 444 |
| 445 /// Methods in the class. | 445 /// Methods in the class. |
| 446 Map<String, Method> methods; | 446 Map<String, Method> methods; |
| 447 | 447 |
| 448 String name; | 448 String name; |
| 449 String qualifiedName; | 449 String qualifiedName; |
| 450 String superclass; | 450 String superclass; |
| 451 bool isAbstract; | 451 bool isAbstract; |
| 452 bool isTypedef; | 452 bool isTypedef; |
| 453 | 453 |
| 454 /// List of the meta annotations on the class. | 454 /// List of the meta annotations on the class. |
| 455 List<String> annotations; | 455 List<String> annotations; |
| 456 | 456 |
| 457 Class(this.name, this.qualifiedName, this.superclass, this.isAbstract, | 457 Class(this.name, this.qualifiedName, this.superclass, this.isAbstract, |
| 458 this.isTypedef, this.comment, this.interfaces, this.variables, | 458 this.isTypedef, this.comment, this.interfaces, this.variables, |
| 459 this.methods, this.annotations); | 459 this.methods, this.annotations); |
| 460 | 460 |
| 461 /// Generates a map describing the [Class] object. | 461 /// Generates a map describing the [Class] object. |
| 462 Map toMap() { | 462 Map toMap() { |
| 463 var classMap = {}; | 463 var classMap = {}; |
| 464 classMap['name'] = name; | 464 classMap['name'] = name; |
| 465 classMap['qualifiedname'] = qualifiedName; | 465 classMap['qualifiedname'] = qualifiedName; |
| 466 classMap['comment'] = comment; | 466 classMap['comment'] = comment; |
| 467 classMap['superclass'] = superclass; | 467 classMap['superclass'] = superclass; |
| 468 classMap['abstract'] = isAbstract.toString(); | 468 classMap['abstract'] = isAbstract.toString(); |
| 469 classMap['typedef'] = isTypedef.toString(); | 469 classMap['typedef'] = isTypedef.toString(); |
| 470 classMap['implements'] = new List.from(interfaces); | 470 classMap['implements'] = new List.from(interfaces); |
| 471 classMap['variables'] = recurseMap(variables); | 471 classMap['variables'] = recurseMap(variables); |
| 472 classMap['methods'] = recurseMap(methods); | 472 classMap['methods'] = recurseMap(methods); |
| 473 classMap['annotations'] = new List.from(annotations); | 473 classMap['annotations'] = new List.from(annotations); |
| 474 return classMap; | 474 return classMap; |
| 475 } | 475 } |
| 476 } | 476 } |
| 477 | 477 |
| 478 /** | 478 /** |
| 479 * A class containing properties of a Dart variable. | 479 * A class containing properties of a Dart variable. |
| 480 */ | 480 */ |
| 481 class Variable { | 481 class Variable { |
| 482 | 482 |
| 483 /// Documentation comment with converted markdown. | 483 /// Documentation comment with converted markdown. |
| 484 String comment; | 484 String comment; |
| 485 | 485 |
| 486 String name; | 486 String name; |
| 487 String qualifiedName; | 487 String qualifiedName; |
| 488 bool isFinal; | 488 bool isFinal; |
| 489 bool isStatic; | 489 bool isStatic; |
| 490 String type; | 490 String type; |
| 491 | 491 |
| 492 /// List of the meta annotations on the variable. | 492 /// List of the meta annotations on the variable. |
| 493 List<String> annotations; | 493 List<String> annotations; |
| 494 | 494 |
| 495 Variable(this.name, this.qualifiedName, this.isFinal, this.isStatic, | 495 Variable(this.name, this.qualifiedName, this.isFinal, this.isStatic, |
| 496 this.type, this.comment, this.annotations); | 496 this.type, this.comment, this.annotations); |
| 497 | 497 |
| 498 /// Generates a map describing the [Variable] object. | 498 /// Generates a map describing the [Variable] object. |
| 499 Map toMap() { | 499 Map toMap() { |
| 500 var variableMap = {}; | 500 var variableMap = {}; |
| 501 variableMap['name'] = name; | 501 variableMap['name'] = name; |
| 502 variableMap['qualifiedname'] = qualifiedName; | 502 variableMap['qualifiedname'] = qualifiedName; |
| 503 variableMap['comment'] = comment; | 503 variableMap['comment'] = comment; |
| 504 variableMap['final'] = isFinal.toString(); | 504 variableMap['final'] = isFinal.toString(); |
| 505 variableMap['static'] = isStatic.toString(); | 505 variableMap['static'] = isStatic.toString(); |
| 506 variableMap['type'] = type; | 506 variableMap['type'] = type; |
| 507 variableMap['annotations'] = new List.from(annotations); | 507 variableMap['annotations'] = new List.from(annotations); |
| 508 return variableMap; | 508 return variableMap; |
| 509 } | 509 } |
| 510 } | 510 } |
| 511 | 511 |
| 512 /** | 512 /** |
| 513 * A class containing properties of a Dart method. | 513 * A class containing properties of a Dart method. |
| 514 */ | 514 */ |
| 515 class Method { | 515 class Method { |
| 516 | 516 |
| 517 /// Documentation comment with converted markdown. | 517 /// Documentation comment with converted markdown. |
| 518 String comment; | 518 String comment; |
| 519 | 519 |
| 520 /// Parameters for this method. | 520 /// Parameters for this method. |
| 521 Map<String, Parameter> parameters; | 521 Map<String, Parameter> parameters; |
| 522 | 522 |
| 523 String name; | 523 String name; |
| 524 String qualifiedName; | 524 String qualifiedName; |
| 525 bool isSetter; | 525 bool isSetter; |
| 526 bool isGetter; | 526 bool isGetter; |
| 527 bool isConstructor; | 527 bool isConstructor; |
| 528 bool isOperator; | 528 bool isOperator; |
| 529 bool isStatic; | 529 bool isStatic; |
| 530 String returnType; | 530 String returnType; |
| 531 | 531 |
| 532 /// List of the meta annotations on the method. | 532 /// List of the meta annotations on the method. |
| 533 List<String> annotations; | 533 List<String> annotations; |
| 534 | 534 |
| 535 Method(this.name, this.qualifiedName, this.isSetter, this.isGetter, | 535 Method(this.name, this.qualifiedName, this.isSetter, this.isGetter, |
| 536 this.isConstructor, this.isOperator, this.isStatic, this.returnType, | 536 this.isConstructor, this.isOperator, this.isStatic, this.returnType, |
| 537 this.comment, this.parameters, this.annotations); | 537 this.comment, this.parameters, this.annotations); |
| 538 | 538 |
| 539 /// Generates a map describing the [Method] object. | 539 /// Generates a map describing the [Method] object. |
| 540 Map toMap() { | 540 Map toMap() { |
| 541 var methodMap = {}; | 541 var methodMap = {}; |
| 542 methodMap['name'] = name; | 542 methodMap['name'] = name; |
| 543 methodMap['qualifiedname'] = qualifiedName; | 543 methodMap['qualifiedname'] = qualifiedName; |
| 544 methodMap['comment'] = comment; | 544 methodMap['comment'] = comment; |
| 545 methodMap['type'] = isSetter ? 'setter' : isGetter ? 'getter' : | 545 methodMap['type'] = isSetter ? 'setter' : isGetter ? 'getter' : |
| 546 isOperator ? 'operator' : isConstructor ? 'constructor' : 'method'; | 546 isOperator ? 'operator' : isConstructor ? 'constructor' : 'method'; |
| 547 methodMap['static'] = isStatic.toString(); | 547 methodMap['static'] = isStatic.toString(); |
| 548 methodMap['return'] = returnType; | 548 methodMap['return'] = returnType; |
| 549 methodMap['parameters'] = recurseMap(parameters); | 549 methodMap['parameters'] = recurseMap(parameters); |
| 550 methodMap['annotations'] = new List.from(annotations); | 550 methodMap['annotations'] = new List.from(annotations); |
| 551 return methodMap; | 551 return methodMap; |
| 552 } | 552 } |
| 553 } | 553 } |
| 554 | 554 |
| 555 /** | 555 /** |
| 556 * A class containing properties of a Dart method/function parameter. | 556 * A class containing properties of a Dart method/function parameter. |
| 557 */ | 557 */ |
| 558 class Parameter { | 558 class Parameter { |
| 559 | 559 |
| 560 String name; | 560 String name; |
| 561 String qualifiedName; | 561 String qualifiedName; |
| 562 bool isOptional; | 562 bool isOptional; |
| 563 bool isNamed; | 563 bool isNamed; |
| 564 bool hasDefaultValue; | 564 bool hasDefaultValue; |
| 565 String type; | 565 String type; |
| 566 String defaultValue; | 566 String defaultValue; |
| 567 | 567 |
| 568 /// List of the meta annotations on the parameter. | 568 /// List of the meta annotations on the parameter. |
| 569 List<String> annotations; | 569 List<String> annotations; |
| 570 | 570 |
| 571 Parameter(this.name, this.qualifiedName, this.isOptional, this.isNamed, | 571 Parameter(this.name, this.qualifiedName, this.isOptional, this.isNamed, |
| 572 this.hasDefaultValue, this.type, this.defaultValue, this.annotations); | 572 this.hasDefaultValue, this.type, this.defaultValue, this.annotations); |
| 573 | 573 |
| 574 /// Generates a map describing the [Parameter] object. | 574 /// Generates a map describing the [Parameter] object. |
| 575 Map toMap() { | 575 Map toMap() { |
| 576 var parameterMap = {}; | 576 var parameterMap = {}; |
| 577 parameterMap['name'] = name; | 577 parameterMap['name'] = name; |
| 578 parameterMap['qualifiedname'] = qualifiedName; | 578 parameterMap['qualifiedname'] = qualifiedName; |
| 579 parameterMap['optional'] = isOptional.toString(); | 579 parameterMap['optional'] = isOptional.toString(); |
| 580 parameterMap['named'] = isNamed.toString(); | 580 parameterMap['named'] = isNamed.toString(); |
| 581 parameterMap['default'] = hasDefaultValue.toString(); | 581 parameterMap['default'] = hasDefaultValue.toString(); |
| 582 parameterMap['type'] = type; | 582 parameterMap['type'] = type; |
| 583 parameterMap['value'] = defaultValue; | 583 parameterMap['value'] = defaultValue; |
| 584 parameterMap['annotations'] = new List.from(annotations); | 584 parameterMap['annotations'] = new List.from(annotations); |
| 585 return parameterMap; | 585 return parameterMap; |
| 586 } | 586 } |
| 587 } | 587 } |
| OLD | NEW |