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 /// **docgen** is a tool for creating machine readable representations of Dart | 5 /// **docgen** is a tool for creating machine readable representations of Dart |
6 /// code metadata, including: classes, members, comments and annotations. | 6 /// code metadata, including: classes, members, comments and annotations. |
7 /// | 7 /// |
8 /// docgen is run on a `.dart` file or a directory containing `.dart` files. | 8 /// docgen is run on a `.dart` file or a directory containing `.dart` files. |
9 /// | 9 /// |
10 /// $ dart docgen.dart [OPTIONS] [FILE/DIR] | 10 /// $ dart docgen.dart [OPTIONS] [FILE/DIR] |
(...skipping 24 matching lines...) Expand all Loading... | |
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 DEFAULT_OUTPUT_DIRECTORY = 'docs'; | 39 const DEFAULT_OUTPUT_DIRECTORY = 'docs'; |
40 | 40 |
41 var _outputDirectory; | 41 var _outputDirectory; |
42 | 42 |
43 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] fooDir/barFile'; | 43 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] fooDir/barFile'; |
44 | 44 |
45 | |
46 List<String> skippedAnnotations = const [ | 45 List<String> skippedAnnotations = const [ |
47 'metadata.DocsEditable', '_js_helper.JSName', '_js_helper.Creates', | 46 'metadata.DocsEditable', '_js_helper.JSName', '_js_helper.Creates', |
48 '_js_helper.Returns']; | 47 '_js_helper.Returns']; |
49 | 48 |
49 /// If we can't find the SDK introduction text, which will happen if running | |
50 /// from a snapshot and using --parse-sdk or --include-sdk, then use this | |
51 /// hard-coded version. This should be updated to be consistent with the text | |
52 /// in docgen/doc/sdk-introduction.md | |
53 const DEFAULT_SDK_INTRODUCTION = """ | |
54 Welcome to the Dart API reference documentation, | |
55 covering the official Dart API libraries. | |
56 Some of the most fundamental Dart libraries include: | |
57 | |
58 * [dart:core](#dart:core): | |
59 Core functionality such as strings, numbers, collections, errors, | |
60 dates, and URIs. | |
61 * [dart:html](#dart:html): | |
62 DOM manipulation for web apps. | |
63 * [dart:io](#dart:io): | |
64 I/O for command-line apps. | |
65 | |
66 Except for dart:core, you must import a library before you can use it. | |
67 Here's an example of importing dart:html, dart:math, and a | |
68 third popular library called | |
69 [polymer.dart](http://www.dartlang.org/polymer-dart/): | |
70 | |
71 import 'dart:html'; | |
72 import 'dart:math'; | |
73 import 'package:polymer/polymer.dart'; | |
74 | |
75 Polymer.dart is an example of a library that isn't | |
76 included in the Dart download, | |
77 but is easy to get and update using the _pub package manager_. | |
78 For information on finding, using, and publishing libraries (and more) | |
79 with pub, see | |
80 [pub.dartlang.org](http://pub.dartlang.org). | |
81 | |
82 The main site for learning and using Dart is | |
83 [www.dartlang.org](http://www.dartlang.org). | |
84 Check out these pages: | |
85 | |
86 * [Dart homepage](http://www.dartlang.org) | |
87 * [Tutorials](http://www.dartlang.org/docs/tutorials/) | |
88 * [Programmer's Guide](http://www.dartlang.org/docs/) | |
89 * [Samples](http://www.dartlang.org/samples/) | |
90 * [A Tour of the Dart Libraries](http://www.dartlang.org/docs/dart-up-and-runn ing/contents/ch03.html) | |
91 | |
92 This API reference is automatically generated from the source code in the | |
93 [Dart project](https://code.google.com/p/dart/). | |
94 If you'd like to contribute to this documentation, see | |
95 [Contributing](https://code.google.com/p/dart/wiki/Contributing) | |
96 and | |
97 [Writing API Documentation](https://code.google.com/p/dart/wiki/WritingApiDocume ntation). | |
98 """; | |
99 | |
50 /// Set of libraries declared in the SDK, so libraries that can be accessed | 100 /// Set of libraries declared in the SDK, so libraries that can be accessed |
51 /// when running dart by default. | 101 /// when running dart by default. |
52 Iterable<LibraryMirror> _sdkLibraries; | 102 Iterable<LibraryMirror> _sdkLibraries; |
53 | 103 |
54 /// The dart:core library, which contains all types that are always available | 104 /// The dart:core library, which contains all types that are always available |
55 /// without import. | 105 /// without import. |
56 LibraryMirror _coreLibrary; | 106 LibraryMirror _coreLibrary; |
57 | 107 |
58 /// Support for [:foo:]-style code comments to the markdown parser. | 108 /// Support for [:foo:]-style code comments to the markdown parser. |
59 List<markdown.InlineSyntax> markdownSyntaxes = | 109 List<markdown.InlineSyntax> markdownSyntaxes = |
(...skipping 25 matching lines...) Expand all Loading... | |
85 /// | 135 /// |
86 /// [packageRoot] is the packages directory of the directory being analyzed. | 136 /// [packageRoot] is the packages directory of the directory being analyzed. |
87 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will | 137 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will |
88 /// also be documented. | 138 /// also be documented. |
89 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented. | 139 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented. |
90 /// This option is useful when only the SDK libraries are needed. | 140 /// This option is useful when only the SDK libraries are needed. |
91 /// | 141 /// |
92 /// Returned Future completes with true if document generation is successful. | 142 /// Returned Future completes with true if document generation is successful. |
93 Future<bool> docgen(List<String> files, {String packageRoot, | 143 Future<bool> docgen(List<String> files, {String packageRoot, |
94 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, | 144 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, |
95 bool parseSdk: false, bool append: false, String introduction: '', | 145 bool parseSdk: false, bool append: false, String introFileName: '', |
96 out: DEFAULT_OUTPUT_DIRECTORY, List<String> excludeLibraries, | 146 out: DEFAULT_OUTPUT_DIRECTORY, List<String> excludeLibraries, |
97 bool includeDependentPackages}) { | 147 bool includeDependentPackages}) { |
98 _excluded = excludeLibraries; | 148 _excluded = excludeLibraries; |
99 _includePrivate = includePrivate; | 149 _includePrivate = includePrivate; |
100 _outputDirectory = out; | 150 _outputDirectory = out; |
101 _includeDependentPackages = includeDependentPackages; | 151 _includeDependentPackages = includeDependentPackages; |
102 if (!append) { | 152 if (!append) { |
103 var dir = new Directory(_outputDirectory); | 153 var dir = new Directory(_outputDirectory); |
104 if (dir.existsSync()) dir.deleteSync(recursive: true); | 154 if (dir.existsSync()) dir.deleteSync(recursive: true); |
105 } | 155 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
138 var availableLibrariesByPath = new Map.fromIterables( | 188 var availableLibrariesByPath = new Map.fromIterables( |
139 availableLibraries.map((each) => each.uri), | 189 availableLibraries.map((each) => each.uri), |
140 availableLibraries); | 190 availableLibraries); |
141 var librariesToDocument = requestedLibraries.map( | 191 var librariesToDocument = requestedLibraries.map( |
142 (each) => availableLibrariesByPath.putIfAbsent(each, | 192 (each) => availableLibrariesByPath.putIfAbsent(each, |
143 () => throw "Missing library $each")).toList(); | 193 () => throw "Missing library $each")).toList(); |
144 librariesToDocument.addAll((includeSdk || parseSdk) ? _sdkLibraries : []); | 194 librariesToDocument.addAll((includeSdk || parseSdk) ? _sdkLibraries : []); |
145 librariesToDocument.removeWhere((x) => _excluded.contains(x.simpleName)); | 195 librariesToDocument.removeWhere((x) => _excluded.contains(x.simpleName)); |
146 _documentLibraries(librariesToDocument, includeSdk: includeSdk, | 196 _documentLibraries(librariesToDocument, includeSdk: includeSdk, |
147 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk, | 197 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk, |
148 introduction: introduction); | 198 introFileName: introFileName); |
ricow1
2014/01/13 13:14:20
do we ever read this from a file now? if not just
Alan Knight
2014/01/13 17:36:04
We don't in the SDK, but if we're using this to ge
| |
149 return true; | 199 return true; |
150 }); | 200 }); |
151 } | 201 } |
152 | 202 |
153 /// All of the directories for our dependent packages | 203 /// All of the directories for our dependent packages |
154 List<String> allDependentPackageDirs(String packageDirectory) { | 204 List<String> allDependentPackageDirs(String packageDirectory) { |
155 var dependentsJson = Process.runSync('pub', ['list-package-dirs'], | 205 var dependentsJson = Process.runSync('pub', ['list-package-dirs'], |
156 workingDirectory: packageDirectory, runInShell: true); | 206 workingDirectory: packageDirectory, runInShell: true); |
157 if (dependentsJson.exitCode != 0) { | 207 if (dependentsJson.exitCode != 0) { |
158 print(dependentsJson.stderr); | 208 print(dependentsJson.stderr); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
251 } | 301 } |
252 | 302 |
253 String _findPackageRoot(String directory) { | 303 String _findPackageRoot(String directory) { |
254 var files = listDir(directory, recursive: true); | 304 var files = listDir(directory, recursive: true); |
255 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. | 305 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. |
256 String packageRoot = files.firstWhere((f) => | 306 String packageRoot = files.firstWhere((f) => |
257 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => ''); | 307 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => ''); |
258 if (packageRoot != '') { | 308 if (packageRoot != '') { |
259 packageRoot = path.join(path.dirname(packageRoot), 'packages'); | 309 packageRoot = path.join(path.dirname(packageRoot), 'packages'); |
260 } | 310 } |
261 return packageRoot; | 311 return path.normalize(path.absolute(packageRoot)); |
262 } | 312 } |
263 | 313 |
264 /// Read a pubspec and return the library name. | 314 /// Read a pubspec and return the library name. |
265 String _packageName(String pubspecName) { | 315 String _packageName(String pubspecName) { |
266 File pubspec = new File(pubspecName); | 316 File pubspec = new File(pubspecName); |
267 if (!pubspec.existsSync()) return ''; | 317 if (!pubspec.existsSync()) return ''; |
268 var contents = pubspec.readAsStringSync(); | 318 var contents = pubspec.readAsStringSync(); |
269 var spec = loadYaml(contents); | 319 var spec = loadYaml(contents); |
270 return spec["name"]; | 320 return spec["name"]; |
271 } | 321 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
327 // Currently, a string is thrown when it fails to create a mirror | 377 // Currently, a string is thrown when it fails to create a mirror |
328 // system, and it is not possible to use the stack trace. BUG(#11622) | 378 // system, and it is not possible to use the stack trace. BUG(#11622) |
329 // To avoid printing the stack trace. | 379 // To avoid printing the stack trace. |
330 exit(1); | 380 exit(1); |
331 }); | 381 }); |
332 } | 382 } |
333 | 383 |
334 /// Creates documentation for filtered libraries. | 384 /// Creates documentation for filtered libraries. |
335 void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false, | 385 void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false, |
336 bool outputToYaml: true, bool append: false, bool parseSdk: false, | 386 bool outputToYaml: true, bool append: false, bool parseSdk: false, |
337 String introduction: ''}) { | 387 String introFileName: ''}) { |
338 libs.forEach((lib) { | 388 libs.forEach((lib) { |
339 // Files belonging to the SDK have a uri that begins with 'dart:'. | 389 // Files belonging to the SDK have a uri that begins with 'dart:'. |
340 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { | 390 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { |
341 var library = generateLibrary(lib); | 391 var library = generateLibrary(lib); |
342 entityMap[library.name] = library; | 392 entityMap[library.name] = library; |
343 } | 393 } |
344 }); | 394 }); |
345 // After everything is created, do a pass through all classes to make sure no | 395 // After everything is created, do a pass through all classes to make sure no |
346 // intermediate classes created by mixins are included, all the links to | 396 // intermediate classes created by mixins are included, all the links to |
347 // exported members point to the new library. | 397 // exported members point to the new library. |
348 entityMap.values.where((e) => e is Class).forEach( | 398 entityMap.values.where((e) => e is Class).forEach( |
349 (c) => c.updateLinksAndRemoveIntermediaryClasses()); | 399 (c) => c.updateLinksAndRemoveIntermediaryClasses()); |
350 // Everything is a subclass of Object, therefore empty the list to avoid a | 400 // Everything is a subclass of Object, therefore empty the list to avoid a |
351 // giant list of subclasses to be printed out. | 401 // giant list of subclasses to be printed out. |
352 if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear(); | 402 if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear(); |
353 | 403 |
354 var filteredEntities = entityMap.values.where(_isVisible); | 404 var filteredEntities = entityMap.values.where(_isVisible); |
355 | 405 |
356 // Outputs a JSON file with all libraries and their preview comments. | 406 // Outputs a JSON file with all libraries and their preview comments. |
357 // This will help the viewer know what libraries are available to read in. | 407 // This will help the viewer know what libraries are available to read in. |
358 var libraryMap; | 408 var libraryMap; |
359 var linkResolver = (name) => fixReference(name, null, null, null); | 409 var linkResolver = (name) => fixReference(name, null, null, null); |
410 | |
411 String readIntroductionFile(String fileName, includeSdk) { | |
412 var defaultText = includeSdk ? DEFAULT_SDK_INTRODUCTION : ''; | |
413 var introText = defaultText; | |
414 if (fileName.isNotEmpty) { | |
415 var introFile = new File(fileName); | |
416 introText = introFile.existsSync() ? introFile.readAsStringSync() : | |
417 defaultText; | |
418 } | |
419 return markdown.markdownToHtml(introText, | |
420 linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes); | |
421 } | |
422 | |
360 if (append) { | 423 if (append) { |
361 var docsDir = listDir(_outputDirectory); | 424 var docsDir = listDir(_outputDirectory); |
362 if (!docsDir.contains('$_outputDirectory/library_list.json')) { | 425 if (!docsDir.contains('$_outputDirectory/library_list.json')) { |
363 throw new StateError('No library_list.json'); | 426 throw new StateError('No library_list.json'); |
364 } | 427 } |
365 libraryMap = | 428 libraryMap = |
366 JSON.decode(new File( | 429 JSON.decode(new File( |
367 '$_outputDirectory/library_list.json').readAsStringSync()); | 430 '$_outputDirectory/library_list.json').readAsStringSync()); |
368 libraryMap['libraries'].addAll(filteredEntities | 431 libraryMap['libraries'].addAll(filteredEntities |
369 .where((e) => e is Library) | 432 .where((e) => e is Library) |
370 .map((e) => e.previewMap)); | 433 .map((e) => e.previewMap)); |
371 if (introduction.isNotEmpty) { | 434 var intro = libraryMap['introduction']; |
372 var intro = libraryMap['introduction']; | 435 var spacing = intro.isEmpty ? '' : '<br/><br/>'; |
373 if (intro.isNotEmpty) intro += '<br/><br/>'; | 436 libraryMap['introduction'] = |
374 intro += markdown.markdownToHtml( | 437 "$intro$spacing${readIntroductionFile(introFileName, includeSdk)}"; |
375 new File(introduction).readAsStringSync(), | |
376 linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes); | |
377 libraryMap['introduction'] = intro; | |
378 } | |
379 outputToYaml = libraryMap['filetype'] == 'yaml'; | 438 outputToYaml = libraryMap['filetype'] == 'yaml'; |
380 } else { | 439 } else { |
381 libraryMap = { | 440 libraryMap = { |
382 'libraries' : filteredEntities.where((e) => | 441 'libraries' : filteredEntities.where((e) => |
383 e is Library).map((e) => e.previewMap).toList(), | 442 e is Library).map((e) => e.previewMap).toList(), |
384 'introduction' : introduction == '' ? | 443 'introduction' : readIntroductionFile(introFileName, includeSdk), |
385 '' : markdown.markdownToHtml(new File(introduction) | |
386 .readAsStringSync(), linkResolver: linkResolver, | |
387 inlineSyntaxes: markdownSyntaxes), | |
388 'filetype' : outputToYaml ? 'yaml' : 'json' | 444 'filetype' : outputToYaml ? 'yaml' : 'json' |
389 }; | 445 }; |
390 } | 446 } |
391 _writeToFile(JSON.encode(libraryMap), 'library_list.json'); | 447 _writeToFile(JSON.encode(libraryMap), 'library_list.json'); |
392 | 448 |
393 // Output libraries and classes to file after all information is generated. | 449 // Output libraries and classes to file after all information is generated. |
394 filteredEntities.where((e) => e is Class || e is Library).forEach((output) { | 450 filteredEntities.where((e) => e is Class || e is Library).forEach((output) { |
395 _writeIndexableToFile(output, outputToYaml); | 451 _writeIndexableToFile(output, outputToYaml); |
396 }); | 452 }); |
397 | 453 |
(...skipping 1303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1701 /// Remove statics from the map of inherited items before adding them. | 1757 /// Remove statics from the map of inherited items before adding them. |
1702 Map _filterStatics(Map items) { | 1758 Map _filterStatics(Map items) { |
1703 var result = {}; | 1759 var result = {}; |
1704 items.forEach((name, item) { | 1760 items.forEach((name, item) { |
1705 if (!item.isStatic) { | 1761 if (!item.isStatic) { |
1706 result[name] = item; | 1762 result[name] = item; |
1707 } | 1763 } |
1708 }); | 1764 }); |
1709 return result; | 1765 return result; |
1710 } | 1766 } |
OLD | NEW |