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

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

Issue 73113002: Generate docgen output along with api_docs as part of the build (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixes from review Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// **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 18 matching lines...) Expand all
29 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro r.dart' 29 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro r.dart'
30 as dart2js; 30 as dart2js;
31 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart' ; 31 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart' ;
32 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util. dart' 32 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util. dart'
33 as dart2js_util; 33 as dart2js_util;
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 var outputDirectory = 'docs';
kustermann 2013/11/18 09:57:08 Why are some other global variables a few lines do
Alan Knight 2013/11/18 20:34:50 Made it private.
40
39 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] fooDir/barFile'; 41 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] fooDir/barFile';
40 42
41 43
42 List<String> skippedAnnotations = const [ 44 List<String> skippedAnnotations = const [
43 'metadata.DocsEditable', '_js_helper.JSName', '_js_helper.Creates', 45 'metadata.DocsEditable', '_js_helper.JSName', '_js_helper.Creates',
44 '_js_helper.Returns']; 46 '_js_helper.Returns'];
45 47
46 /// Set of libraries declared in the SDK, so libraries that can be accessed 48 /// Set of libraries declared in the SDK, so libraries that can be accessed
47 /// when running dart by default. 49 /// when running dart by default.
48 Iterable<LibraryMirror> _sdkLibraries; 50 Iterable<LibraryMirror> _sdkLibraries;
(...skipping 18 matching lines...) Expand all
67 /// Resolves reference links in doc comments. 69 /// Resolves reference links in doc comments.
68 markdown.Resolver linkResolver; 70 markdown.Resolver linkResolver;
69 71
70 /// Index of all indexable items. This also ensures that no class is 72 /// Index of all indexable items. This also ensures that no class is
71 /// created more than once. 73 /// created more than once.
72 Map<String, Indexable> entityMap = new Map<String, Indexable>(); 74 Map<String, Indexable> entityMap = new Map<String, Indexable>();
73 75
74 /// This is set from the command line arguments flag --include-private 76 /// This is set from the command line arguments flag --include-private
75 bool _includePrivate = false; 77 bool _includePrivate = false;
76 78
79 /// Library names to explicitly exclude.
80 ///
81 /// Set from the command line option
82 /// --exclude-lib.
83 List<String> _excluded;
84
77 // TODO(janicejl): Make MDN content generic or pluggable. Maybe move 85 // TODO(janicejl): Make MDN content generic or pluggable. Maybe move
78 // MDN-specific code to its own library that is imported into the default impl? 86 // MDN-specific code to its own library that is imported into the default impl?
79 /// Map of all the comments for dom elements from MDN. 87 /// Map of all the comments for dom elements from MDN.
80 Map _mdn; 88 Map _mdn;
81 89
82 /// Docgen constructor initializes the link resolver for markdown parsing. 90 /// Docgen constructor initializes the link resolver for markdown parsing.
83 /// Also initializes the command line arguments. 91 /// Also initializes the command line arguments.
84 /// 92 ///
85 /// [packageRoot] is the packages directory of the directory being analyzed. 93 /// [packageRoot] is the packages directory of the directory being analyzed.
86 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will 94 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will
87 /// also be documented. 95 /// also be documented.
88 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented. 96 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented.
89 /// This option is useful when only the SDK libraries are needed. 97 /// This option is useful when only the SDK libraries are needed.
90 /// 98 ///
91 /// Returned Future completes with true if document generation is successful. 99 /// Returned Future completes with true if document generation is successful.
92 Future<bool> docgen(List<String> files, {String packageRoot, 100 Future<bool> docgen(List<String> files, {String packageRoot,
93 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, 101 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false,
94 bool parseSdk: false, bool append: false, String introduction: ''}) { 102 bool parseSdk: false, bool append: false, String introduction: '',
103 out: 'docs', List<String> excludeLibraries}) {
kustermann 2013/11/18 09:57:08 It's slightly strange that we have the default val
Alan Knight 2013/11/18 20:34:50 Yes. I can't default the parameter to a variable v
104 _excluded = excludeLibraries;
95 _includePrivate = includePrivate; 105 _includePrivate = includePrivate;
106 outputDirectory = out;
96 if (!append) { 107 if (!append) {
97 var dir = new Directory('docs'); 108 var dir = new Directory(outputDirectory);
98 if (dir.existsSync()) dir.deleteSync(recursive: true); 109 if (dir.existsSync()) dir.deleteSync(recursive: true);
99 } 110 }
100 111
101 if (packageRoot == null && !parseSdk) { 112 if (packageRoot == null && !parseSdk) {
102 var type = FileSystemEntity.typeSync(files.first); 113 var type = FileSystemEntity.typeSync(files.first);
103 if (type == FileSystemEntityType.DIRECTORY) { 114 if (type == FileSystemEntityType.DIRECTORY) {
104 packageRoot = _findPackageRoot(files.first); 115 packageRoot = _findPackageRoot(files.first);
105 } else if (type == FileSystemEntityType.FILE) { 116 } else if (type == FileSystemEntityType.FILE) {
106 logger.warning('WARNING: No package root defined. If Docgen fails, try ' 117 logger.warning('WARNING: No package root defined. If Docgen fails, try '
107 'again by setting the --package-root option.'); 118 'again by setting the --package-root option.');
108 } 119 }
109 } 120 }
110 logger.info('Package Root: ${packageRoot}'); 121 logger.info('Package Root: ${packageRoot}');
111 linkResolver = (name) => 122 linkResolver = (name) =>
112 fixReference(name, _currentLibrary, _currentClass, _currentMember); 123 fixReference(name, _currentLibrary, _currentClass, _currentMember);
124 var requestedLibraries = !parseSdk ? _listLibraries(files) : _listSdk();
113 125
114 return getMirrorSystem(files, packageRoot: packageRoot, parseSdk: parseSdk) 126 return getMirrorSystem(requestedLibraries, packageRoot: packageRoot,
127 parseSdk: parseSdk)
115 .then((MirrorSystem mirrorSystem) { 128 .then((MirrorSystem mirrorSystem) {
116 if (mirrorSystem.libraries.isEmpty) { 129 if (mirrorSystem.libraries.isEmpty) {
117 throw new StateError('No library mirrors were created.'); 130 throw new StateError('No library mirrors were created.');
118 } 131 }
119 var librariesWeAskedFor = _listLibraries(files); 132 var availableLibraries = mirrorSystem.libraries.values.where(
120 var librariesWeGot = mirrorSystem.libraries.values.where(
121 (each) => each.uri.scheme == 'file'); 133 (each) => each.uri.scheme == 'file');
122 _sdkLibraries = mirrorSystem.libraries.values.where( 134 _sdkLibraries = mirrorSystem.libraries.values.where(
123 (each) => each.uri.scheme == 'dart'); 135 (each) => each.uri.scheme == 'dart');
124 _coreLibrary = _sdkLibraries.singleWhere((lib) => 136 _coreLibrary = _sdkLibraries.singleWhere((lib) =>
125 lib.uri.toString().startsWith('dart:core')); 137 lib.uri.toString().startsWith('dart:core'));
126 var librariesWeGotByPath = new Map.fromIterables( 138 var availableLibrariesByPath = new Map.fromIterables(
127 librariesWeGot.map((each) => each.uri.toFilePath()), 139 availableLibraries.map((each) => each.uri.toFilePath()),
128 librariesWeGot); 140 availableLibraries);
129 var librariesToDocument = librariesWeAskedFor.map( 141 var librariesToDocument = requestedLibraries.map(
130 (each) => librariesWeGotByPath.putIfAbsent(each, 142 (each) => availableLibrariesByPath.putIfAbsent(each,
131 () => throw "Missing library $each")).toList(); 143 () => throw "Missing library $each")).toList();
132 librariesToDocument.addAll((includeSdk || parseSdk) ? _sdkLibraries : []); 144 librariesToDocument.addAll((includeSdk || parseSdk) ? _sdkLibraries : []);
145 librariesToDocument.removeWhere((x) => _excluded.contains(x.simpleName));
133 _documentLibraries(librariesToDocument, includeSdk: includeSdk, 146 _documentLibraries(librariesToDocument, includeSdk: includeSdk,
134 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk, 147 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk,
135 introduction: introduction); 148 introduction: introduction);
136 return true; 149 return true;
137 }); 150 });
138 } 151 }
139 152
140 /// For a library's [mirror], determine the name of the package (if any) we 153 /// For a library's [mirror], determine the name of the package (if any) we
141 /// believe it came from (because of its file URI). 154 /// believe it came from (because of its file URI).
142 /// 155 ///
(...skipping 28 matching lines...) Expand all
171 if (readmes.isEmpty) return ''; 184 if (readmes.isEmpty) return '';
172 // If there are multiples, pick the shortest name. 185 // If there are multiples, pick the shortest name.
173 readmes.sort((a, b) => a.length.compareTo(b.length)); 186 readmes.sort((a, b) => a.length.compareTo(b.length));
174 var readme = readmes.first; 187 var readme = readmes.first;
175 var contents = markdown.markdownToHtml(readme 188 var contents = markdown.markdownToHtml(readme
176 .readAsStringSync(), linkResolver: linkResolver, 189 .readAsStringSync(), linkResolver: linkResolver,
177 inlineSyntaxes: markdownSyntaxes); 190 inlineSyntaxes: markdownSyntaxes);
178 return contents; 191 return contents;
179 } 192 }
180 193
181
182 List<String> _listLibraries(List<String> args) { 194 List<String> _listLibraries(List<String> args) {
183 var libraries = new List<String>(); 195 var libraries = new List<String>();
184 for (var arg in args) { 196 for (var arg in args) {
185 var type = FileSystemEntity.typeSync(arg); 197 var type = FileSystemEntity.typeSync(arg);
186 198
187 if (type == FileSystemEntityType.FILE) { 199 if (type == FileSystemEntityType.FILE) {
188 if (arg.endsWith('.dart')) { 200 if (arg.endsWith('.dart')) {
189 libraries.add(path.absolute(arg)); 201 libraries.add(path.absolute(arg));
190 logger.info('Added to libraries: ${libraries.last}'); 202 logger.info('Added to libraries: ${libraries.last}');
191 } 203 }
(...skipping 19 matching lines...) Expand all
211 // Only add the file if it does not contain 'part of' 223 // Only add the file if it does not contain 'part of'
212 // TODO(janicejl): Remove when Issue(12406) is resolved. 224 // TODO(janicejl): Remove when Issue(12406) is resolved.
213 var contents = new File(f).readAsStringSync(); 225 var contents = new File(f).readAsStringSync();
214 if (!(contents.contains(new RegExp('\npart of ')) || 226 if (!(contents.contains(new RegExp('\npart of ')) ||
215 contents.startsWith(new RegExp('part of ')))) { 227 contents.startsWith(new RegExp('part of ')))) {
216 libraries.add(f); 228 libraries.add(f);
217 logger.info('Added to libraries: $f'); 229 logger.info('Added to libraries: $f');
218 } 230 }
219 } 231 }
220 }); 232 });
221 return libraries; 233 return libraries.map(path.absolute).map(path.normalize).toList();
222 } 234 }
223 235
224 String _findPackageRoot(String directory) { 236 String _findPackageRoot(String directory) {
225 var files = listDir(directory, recursive: true); 237 var files = listDir(directory, recursive: true);
226 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. 238 // Return '' means that there was no pubspec.yaml and therefor no packageRoot.
227 String packageRoot = files.firstWhere((f) => 239 String packageRoot = files.firstWhere((f) =>
228 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => ''); 240 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => '');
229 if (packageRoot != '') { 241 if (packageRoot != '') {
230 packageRoot = path.join(path.dirname(packageRoot), 'packages'); 242 packageRoot = path.join(path.dirname(packageRoot), 'packages');
231 } 243 }
(...skipping 15 matching lines...) Expand all
247 if (info.documented) { 259 if (info.documented) {
248 sdk.add('dart:$name'); 260 sdk.add('dart:$name');
249 logger.info('Add to SDK: ${sdk.last}'); 261 logger.info('Add to SDK: ${sdk.last}');
250 } 262 }
251 }); 263 });
252 return sdk; 264 return sdk;
253 } 265 }
254 266
255 /// Analyzes set of libraries by getting a mirror system and triggers the 267 /// Analyzes set of libraries by getting a mirror system and triggers the
256 /// documentation of the libraries. 268 /// documentation of the libraries.
257 Future<MirrorSystem> getMirrorSystem(List<String> args, {String packageRoot, 269 Future<MirrorSystem> getMirrorSystem(List<String> libraries,
258 bool parseSdk: false}) { 270 {String packageRoot, bool parseSdk: false}) {
259 var libraries = !parseSdk ? _listLibraries(args) : _listSdk();
260 if (libraries.isEmpty) throw new StateError('No Libraries.'); 271 if (libraries.isEmpty) throw new StateError('No Libraries.');
261 // Finds the root of SDK library based off the location of docgen. 272 // Finds the root of SDK library based off the location of docgen.
262 273
263 var root = findRootDirectory(); 274 var root = findRootDirectory();
264 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk'))); 275 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk')));
265 logger.info('SDK Root: ${sdkRoot}'); 276 logger.info('SDK Root: ${sdkRoot}');
266 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot); 277 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot);
267 } 278 }
268 279
269 String findRootDirectory() { 280 String findRootDirectory() {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 // Everything is a subclass of Object, therefore empty the list to avoid a 335 // Everything is a subclass of Object, therefore empty the list to avoid a
325 // giant list of subclasses to be printed out. 336 // giant list of subclasses to be printed out.
326 if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear(); 337 if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear();
327 338
328 var filteredEntities = entityMap.values.where(_isVisible); 339 var filteredEntities = entityMap.values.where(_isVisible);
329 340
330 // Outputs a JSON file with all libraries and their preview comments. 341 // Outputs a JSON file with all libraries and their preview comments.
331 // This will help the viewer know what libraries are available to read in. 342 // This will help the viewer know what libraries are available to read in.
332 var libraryMap; 343 var libraryMap;
333 if (append) { 344 if (append) {
334 var docsDir = listDir('docs'); 345 var docsDir = listDir(outputDirectory);
335 if (!docsDir.contains('docs/library_list.json')) { 346 if (!docsDir.contains('$outputDirectory/library_list.json')) {
336 throw new StateError('No library_list.json'); 347 throw new StateError('No library_list.json');
337 } 348 }
338 libraryMap = 349 libraryMap =
339 JSON.decode(new File('docs/library_list.json').readAsStringSync()); 350 JSON.decode(new File('$outputDirectory/library_list.json').readAsStringS ync());
340 libraryMap['libraries'].addAll(filteredEntities 351 libraryMap['libraries'].addAll(filteredEntities
341 .where((e) => e is Library) 352 .where((e) => e is Library)
342 .map((e) => e.previewMap)); 353 .map((e) => e.previewMap));
343 if (introduction.isNotEmpty) { 354 if (introduction.isNotEmpty) {
344 var intro = libraryMap['introduction']; 355 var intro = libraryMap['introduction'];
345 if (intro.isNotEmpty) intro += '<br/><br/>'; 356 if (intro.isNotEmpty) intro += '<br/><br/>';
346 intro += markdown.markdownToHtml( 357 intro += markdown.markdownToHtml(
347 new File(introduction).readAsStringSync(), 358 new File(introduction).readAsStringSync(),
348 linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes); 359 linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes);
349 libraryMap['introduction'] = intro; 360 libraryMap['introduction'] = intro;
(...skipping 20 matching lines...) Expand all
370 // Outputs all the qualified names documented with their type. 381 // Outputs all the qualified names documented with their type.
371 // This will help generate search results. 382 // This will help generate search results.
372 _writeToFile(filteredEntities.map((e) => 383 _writeToFile(filteredEntities.map((e) =>
373 '${e.qualifiedName} ${e.typeName}').join('\n') + '\n', 384 '${e.qualifiedName} ${e.typeName}').join('\n') + '\n',
374 'index.txt', append: append); 385 'index.txt', append: append);
375 var index = new Map.fromIterables( 386 var index = new Map.fromIterables(
376 filteredEntities.map((e) => e.qualifiedName), 387 filteredEntities.map((e) => e.qualifiedName),
377 filteredEntities.map((e) => e.typeName)); 388 filteredEntities.map((e) => e.typeName));
378 if (append) { 389 if (append) {
379 var previousIndex = 390 var previousIndex =
380 JSON.decode(new File('docs/index.json').readAsStringSync()); 391 JSON.decode(new File('$outputDirectory/index.json').readAsStringSync());
381 index.addAll(previousIndex); 392 index.addAll(previousIndex);
382 } 393 }
383 _writeToFile(JSON.encode(index), 'index.json'); 394 _writeToFile(JSON.encode(index), 'index.json');
384 } 395 }
385 396
386 Library generateLibrary(dart2js.Dart2JsLibraryMirror library) { 397 Library generateLibrary(dart2js.Dart2JsLibraryMirror library) {
387 _currentLibrary = library; 398 _currentLibrary = library;
388 var result = new Library(docName(library), _commentToHtml(library), 399 var result = new Library(docName(library), _commentToHtml(library),
389 _classes(library.classes), 400 _classes(library.classes),
390 _methods(library.functions), 401 _methods(library.functions),
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after
765 if (mirror is ClassMirror && !mirror.isTypedef) { 776 if (mirror is ClassMirror && !mirror.isTypedef) {
766 var innerList = []; 777 var innerList = [];
767 mirror.typeArguments.forEach((e) { 778 mirror.typeArguments.forEach((e) {
768 innerList.add(new Type(docName(e), _typeGenerics(e))); 779 innerList.add(new Type(docName(e), _typeGenerics(e)));
769 }); 780 });
770 return innerList; 781 return innerList;
771 } 782 }
772 return []; 783 return [];
773 } 784 }
774 785
775 /// Writes text to a file in the 'docs' directory. 786 /// Writes text to a file in the output directory.
776 void _writeToFile(String text, String filename, {bool append: false}) { 787 void _writeToFile(String text, String filename, {bool append: false}) {
777 Directory dir = new Directory('docs'); 788 if (text == null) return;
789 Directory dir = new Directory(outputDirectory);
778 if (!dir.existsSync()) { 790 if (!dir.existsSync()) {
779 dir.createSync(); 791 dir.createSync();
780 } 792 }
781 // We assume there's a single extra level of directory structure for packages. 793 // We assume there's a single extra level of directory structure for packages.
782 if (path.split(filename).length > 1) { 794 if (path.split(filename).length > 1) {
783 var subdir = new Directory(path.join('docs', path.dirname(filename))); 795 var subdir = new Directory(path.join(outputDirectory, path.dirname(filename) ));
784 if (!subdir.existsSync()) { 796 if (!subdir.existsSync()) {
785 subdir.createSync(); 797 subdir.createSync();
786 } 798 }
787 } 799 }
788 800 File file = new File(path.join(outputDirectory, filename));
789 File file = new File('docs/$filename');
790 if (!file.existsSync()) {
791 file.createSync();
792 }
793 file.writeAsStringSync(text, mode: append ? FileMode.APPEND : FileMode.WRITE); 801 file.writeAsStringSync(text, mode: append ? FileMode.APPEND : FileMode.WRITE);
794 } 802 }
795 803
796 /// Transforms the map by calling toMap on each value in it. 804 /// Transforms the map by calling toMap on each value in it.
797 Map recurseMap(Map inputMap) { 805 Map recurseMap(Map inputMap) {
798 var outputMap = {}; 806 var outputMap = {};
799 inputMap.forEach((key, value) { 807 inputMap.forEach((key, value) {
800 if (value is Map) { 808 if (value is Map) {
801 outputMap[key] = recurseMap(value); 809 outputMap[key] = recurseMap(value);
802 } else { 810 } else {
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after
1396 /// Remove statics from the map of inherited items before adding them. 1404 /// Remove statics from the map of inherited items before adding them.
1397 Map _filterStatics(Map items) { 1405 Map _filterStatics(Map items) {
1398 var result = {}; 1406 var result = {};
1399 items.forEach((name, item) { 1407 items.forEach((name, item) {
1400 if (!item.isStatic) { 1408 if (!item.isStatic) {
1401 result[name] = item; 1409 result[name] = item;
1402 } 1410 }
1403 }); 1411 });
1404 return result; 1412 return result;
1405 } 1413 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698