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

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: 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';
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. Set from the command line option
80 /// --exclude-lib
Bob Nystrom 2013/11/14 22:43:04 "." Also, current doc comment convention is that
Alan Knight 2013/11/15 18:49:56 Done.
81 List<String> _excluded;
82
77 // TODO(janicejl): Make MDN content generic or pluggable. Maybe move 83 // 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? 84 // 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. 85 /// Map of all the comments for dom elements from MDN.
80 Map _mdn; 86 Map _mdn;
81 87
82 /// Docgen constructor initializes the link resolver for markdown parsing. 88 /// Docgen constructor initializes the link resolver for markdown parsing.
83 /// Also initializes the command line arguments. 89 /// Also initializes the command line arguments.
84 /// 90 ///
85 /// [packageRoot] is the packages directory of the directory being analyzed. 91 /// [packageRoot] is the packages directory of the directory being analyzed.
86 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will 92 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will
87 /// also be documented. 93 /// also be documented.
88 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented. 94 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented.
89 /// This option is useful when only the SDK libraries are needed. 95 /// This option is useful when only the SDK libraries are needed.
90 /// 96 ///
91 /// Returned Future completes with true if document generation is successful. 97 /// Returned Future completes with true if document generation is successful.
92 Future<bool> docgen(List<String> files, {String packageRoot, 98 Future<bool> docgen(List<String> files, {String packageRoot,
93 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, 99 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false,
94 bool parseSdk: false, bool append: false, String introduction: ''}) { 100 bool parseSdk: false, bool append: false, String introduction: '',
101 out: 'docs', List<String> excludeLibraries}) {
102 _excluded = excludeLibraries;
95 _includePrivate = includePrivate; 103 _includePrivate = includePrivate;
104 outputDirectory = out;
96 if (!append) { 105 if (!append) {
97 var dir = new Directory('docs'); 106 var dir = new Directory(outputDirectory);
98 if (dir.existsSync()) dir.deleteSync(recursive: true); 107 if (dir.existsSync()) dir.deleteSync(recursive: true);
99 } 108 }
100 109
101 if (packageRoot == null && !parseSdk) { 110 if (packageRoot == null && !parseSdk) {
102 var type = FileSystemEntity.typeSync(files.first); 111 var type = FileSystemEntity.typeSync(files.first);
103 if (type == FileSystemEntityType.DIRECTORY) { 112 if (type == FileSystemEntityType.DIRECTORY) {
104 packageRoot = _findPackageRoot(files.first); 113 packageRoot = _findPackageRoot(files.first);
105 } else if (type == FileSystemEntityType.FILE) { 114 } else if (type == FileSystemEntityType.FILE) {
106 logger.warning('WARNING: No package root defined. If Docgen fails, try ' 115 logger.warning('WARNING: No package root defined. If Docgen fails, try '
107 'again by setting the --package-root option.'); 116 'again by setting the --package-root option.');
108 } 117 }
109 } 118 }
110 logger.info('Package Root: ${packageRoot}'); 119 logger.info('Package Root: ${packageRoot}');
111 linkResolver = (name) => 120 linkResolver = (name) =>
112 fixReference(name, _currentLibrary, _currentClass, _currentMember); 121 fixReference(name, _currentLibrary, _currentClass, _currentMember);
122 var librariesWeAskedFor = !parseSdk ? _listLibraries(files) : _listSdk();
Bob Nystrom 2013/11/14 22:43:04 "We" seems funny to me. How about "requestedLibrar
Alan Knight 2013/11/15 18:49:56 Done.
113 123
114 return getMirrorSystem(files, packageRoot: packageRoot, parseSdk: parseSdk) 124 return getMirrorSystem(librariesWeAskedFor, packageRoot: packageRoot,
125 parseSdk: parseSdk)
115 .then((MirrorSystem mirrorSystem) { 126 .then((MirrorSystem mirrorSystem) {
116 if (mirrorSystem.libraries.isEmpty) { 127 if (mirrorSystem.libraries.isEmpty) {
117 throw new StateError('No library mirrors were created.'); 128 throw new StateError('No library mirrors were created.');
118 } 129 }
119 var librariesWeAskedFor = _listLibraries(files);
120 var librariesWeGot = mirrorSystem.libraries.values.where( 130 var librariesWeGot = mirrorSystem.libraries.values.where(
121 (each) => each.uri.scheme == 'file'); 131 (each) => each.uri.scheme == 'file');
122 _sdkLibraries = mirrorSystem.libraries.values.where( 132 _sdkLibraries = mirrorSystem.libraries.values.where(
123 (each) => each.uri.scheme == 'dart'); 133 (each) => each.uri.scheme == 'dart');
124 _coreLibrary = _sdkLibraries.singleWhere((lib) => 134 _coreLibrary = _sdkLibraries.singleWhere((lib) =>
125 lib.uri.toString().startsWith('dart:core')); 135 lib.uri.toString().startsWith('dart:core'));
126 var librariesWeGotByPath = new Map.fromIterables( 136 var librariesWeGotByPath = new Map.fromIterables(
127 librariesWeGot.map((each) => each.uri.toFilePath()), 137 librariesWeGot.map((each) => each.uri.toFilePath()),
128 librariesWeGot); 138 librariesWeGot);
129 var librariesToDocument = librariesWeAskedFor.map( 139 var librariesToDocument = librariesWeAskedFor.map(
130 (each) => librariesWeGotByPath.putIfAbsent(each, 140 (each) => librariesWeGotByPath.putIfAbsent(each,
131 () => throw "Missing library $each")).toList(); 141 () => throw "Missing library $each")).toList();
132 librariesToDocument.addAll((includeSdk || parseSdk) ? _sdkLibraries : []); 142 librariesToDocument.addAll((includeSdk || parseSdk) ? _sdkLibraries : []);
143 librariesToDocument.removeWhere((x) => _excluded.contains(x.simpleName));
133 _documentLibraries(librariesToDocument, includeSdk: includeSdk, 144 _documentLibraries(librariesToDocument, includeSdk: includeSdk,
134 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk, 145 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk,
135 introduction: introduction); 146 introduction: introduction);
136 return true; 147 return true;
137 }); 148 });
138 } 149 }
139 150
140 /// For a library's [mirror], determine the name of the package (if any) we 151 /// For a library's [mirror], determine the name of the package (if any) we
141 /// believe it came from (because of its file URI). 152 /// believe it came from (because of its file URI).
142 /// 153 ///
(...skipping 28 matching lines...) Expand all
171 if (readmes.isEmpty) return ''; 182 if (readmes.isEmpty) return '';
172 // If there are multiples, pick the shortest name. 183 // If there are multiples, pick the shortest name.
173 readmes.sort((a, b) => a.length.compareTo(b.length)); 184 readmes.sort((a, b) => a.length.compareTo(b.length));
174 var readme = readmes.first; 185 var readme = readmes.first;
175 var contents = markdown.markdownToHtml(readme 186 var contents = markdown.markdownToHtml(readme
176 .readAsStringSync(), linkResolver: linkResolver, 187 .readAsStringSync(), linkResolver: linkResolver,
177 inlineSyntaxes: markdownSyntaxes); 188 inlineSyntaxes: markdownSyntaxes);
178 return contents; 189 return contents;
179 } 190 }
180 191
181
182 List<String> _listLibraries(List<String> args) { 192 List<String> _listLibraries(List<String> args) {
183 var libraries = new List<String>(); 193 var libraries = new List<String>();
184 for (var arg in args) { 194 for (var arg in args) {
185 var type = FileSystemEntity.typeSync(arg); 195 var type = FileSystemEntity.typeSync(arg);
186 196
187 if (type == FileSystemEntityType.FILE) { 197 if (type == FileSystemEntityType.FILE) {
188 if (arg.endsWith('.dart')) { 198 if (arg.endsWith('.dart')) {
189 libraries.add(path.absolute(arg)); 199 libraries.add(path.absolute(arg));
190 logger.info('Added to libraries: ${libraries.last}'); 200 logger.info('Added to libraries: ${libraries.last}');
191 } 201 }
(...skipping 19 matching lines...) Expand all
211 // Only add the file if it does not contain 'part of' 221 // Only add the file if it does not contain 'part of'
212 // TODO(janicejl): Remove when Issue(12406) is resolved. 222 // TODO(janicejl): Remove when Issue(12406) is resolved.
213 var contents = new File(f).readAsStringSync(); 223 var contents = new File(f).readAsStringSync();
214 if (!(contents.contains(new RegExp('\npart of ')) || 224 if (!(contents.contains(new RegExp('\npart of ')) ||
215 contents.startsWith(new RegExp('part of ')))) { 225 contents.startsWith(new RegExp('part of ')))) {
216 libraries.add(f); 226 libraries.add(f);
217 logger.info('Added to libraries: $f'); 227 logger.info('Added to libraries: $f');
218 } 228 }
219 } 229 }
220 }); 230 });
221 return libraries; 231 return libraries.map((each) => path.normalize(path.absolute(each))).toList();
Bob Nystrom 2013/11/14 22:43:04 Could also do: libraries.map(path.absolute).map(p
Alan Knight 2013/11/15 18:49:56 I like yours better. Done.
222 } 232 }
223 233
224 String _findPackageRoot(String directory) { 234 String _findPackageRoot(String directory) {
225 var files = listDir(directory, recursive: true); 235 var files = listDir(directory, recursive: true);
226 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. 236 // Return '' means that there was no pubspec.yaml and therefor no packageRoot.
227 String packageRoot = files.firstWhere((f) => 237 String packageRoot = files.firstWhere((f) =>
228 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => ''); 238 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => '');
229 if (packageRoot != '') { 239 if (packageRoot != '') {
230 packageRoot = path.join(path.dirname(packageRoot), 'packages'); 240 packageRoot = path.join(path.dirname(packageRoot), 'packages');
231 } 241 }
(...skipping 15 matching lines...) Expand all
247 if (info.documented) { 257 if (info.documented) {
248 sdk.add('dart:$name'); 258 sdk.add('dart:$name');
249 logger.info('Add to SDK: ${sdk.last}'); 259 logger.info('Add to SDK: ${sdk.last}');
250 } 260 }
251 }); 261 });
252 return sdk; 262 return sdk;
253 } 263 }
254 264
255 /// Analyzes set of libraries by getting a mirror system and triggers the 265 /// Analyzes set of libraries by getting a mirror system and triggers the
256 /// documentation of the libraries. 266 /// documentation of the libraries.
257 Future<MirrorSystem> getMirrorSystem(List<String> args, {String packageRoot, 267 Future<MirrorSystem> getMirrorSystem(List<String> libraries,
258 bool parseSdk: false}) { 268 {String packageRoot, bool parseSdk: false}) {
259 var libraries = !parseSdk ? _listLibraries(args) : _listSdk();
260 if (libraries.isEmpty) throw new StateError('No Libraries.'); 269 if (libraries.isEmpty) throw new StateError('No Libraries.');
261 // Finds the root of SDK library based off the location of docgen. 270 // Finds the root of SDK library based off the location of docgen.
262 271
263 var root = findRootDirectory(); 272 var root = findRootDirectory();
264 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk'))); 273 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk')));
265 logger.info('SDK Root: ${sdkRoot}'); 274 logger.info('SDK Root: ${sdkRoot}');
266 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot); 275 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot);
267 } 276 }
268 277
269 String findRootDirectory() { 278 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 333 // Everything is a subclass of Object, therefore empty the list to avoid a
325 // giant list of subclasses to be printed out. 334 // giant list of subclasses to be printed out.
326 if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear(); 335 if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear();
327 336
328 var filteredEntities = entityMap.values.where(_isVisible); 337 var filteredEntities = entityMap.values.where(_isVisible);
329 338
330 // Outputs a JSON file with all libraries and their preview comments. 339 // 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. 340 // This will help the viewer know what libraries are available to read in.
332 var libraryMap; 341 var libraryMap;
333 if (append) { 342 if (append) {
334 var docsDir = listDir('docs'); 343 var docsDir = listDir(outputDirectory);
335 if (!docsDir.contains('docs/library_list.json')) { 344 if (!docsDir.contains('$outputDirectory/library_list.json')) {
336 throw new StateError('No library_list.json'); 345 throw new StateError('No library_list.json');
337 } 346 }
338 libraryMap = 347 libraryMap =
339 JSON.decode(new File('docs/library_list.json').readAsStringSync()); 348 JSON.decode(new File('$outputDirectory/library_list.json').readAsStringS ync());
340 libraryMap['libraries'].addAll(filteredEntities 349 libraryMap['libraries'].addAll(filteredEntities
341 .where((e) => e is Library) 350 .where((e) => e is Library)
342 .map((e) => e.previewMap)); 351 .map((e) => e.previewMap));
343 if (introduction.isNotEmpty) { 352 if (introduction.isNotEmpty) {
344 var intro = libraryMap['introduction']; 353 var intro = libraryMap['introduction'];
345 if (intro.isNotEmpty) intro += '<br/><br/>'; 354 if (intro.isNotEmpty) intro += '<br/><br/>';
346 intro += markdown.markdownToHtml( 355 intro += markdown.markdownToHtml(
347 new File(introduction).readAsStringSync(), 356 new File(introduction).readAsStringSync(),
348 linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes); 357 linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes);
349 libraryMap['introduction'] = intro; 358 libraryMap['introduction'] = intro;
(...skipping 20 matching lines...) Expand all
370 // Outputs all the qualified names documented with their type. 379 // Outputs all the qualified names documented with their type.
371 // This will help generate search results. 380 // This will help generate search results.
372 _writeToFile(filteredEntities.map((e) => 381 _writeToFile(filteredEntities.map((e) =>
373 '${e.qualifiedName} ${e.typeName}').join('\n') + '\n', 382 '${e.qualifiedName} ${e.typeName}').join('\n') + '\n',
374 'index.txt', append: append); 383 'index.txt', append: append);
375 var index = new Map.fromIterables( 384 var index = new Map.fromIterables(
376 filteredEntities.map((e) => e.qualifiedName), 385 filteredEntities.map((e) => e.qualifiedName),
377 filteredEntities.map((e) => e.typeName)); 386 filteredEntities.map((e) => e.typeName));
378 if (append) { 387 if (append) {
379 var previousIndex = 388 var previousIndex =
380 JSON.decode(new File('docs/index.json').readAsStringSync()); 389 JSON.decode(new File('$outputDirectory/index.json').readAsStringSync());
381 index.addAll(previousIndex); 390 index.addAll(previousIndex);
382 } 391 }
383 _writeToFile(JSON.encode(index), 'index.json'); 392 _writeToFile(JSON.encode(index), 'index.json');
384 } 393 }
385 394
386 Library generateLibrary(dart2js.Dart2JsLibraryMirror library) { 395 Library generateLibrary(dart2js.Dart2JsLibraryMirror library) {
387 _currentLibrary = library; 396 _currentLibrary = library;
388 var result = new Library(docName(library), _commentToHtml(library), 397 var result = new Library(docName(library), _commentToHtml(library),
389 _classes(library.classes), 398 _classes(library.classes),
390 _methods(library.functions), 399 _methods(library.functions),
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after
765 if (mirror is ClassMirror && !mirror.isTypedef) { 774 if (mirror is ClassMirror && !mirror.isTypedef) {
766 var innerList = []; 775 var innerList = [];
767 mirror.typeArguments.forEach((e) { 776 mirror.typeArguments.forEach((e) {
768 innerList.add(new Type(docName(e), _typeGenerics(e))); 777 innerList.add(new Type(docName(e), _typeGenerics(e)));
769 }); 778 });
770 return innerList; 779 return innerList;
771 } 780 }
772 return []; 781 return [];
773 } 782 }
774 783
775 /// Writes text to a file in the 'docs' directory. 784 /// Writes text to a file in the output directory.
776 void _writeToFile(String text, String filename, {bool append: false}) { 785 void _writeToFile(String text, String filename, {bool append: false}) {
777 Directory dir = new Directory('docs'); 786 Directory dir = new Directory(outputDirectory);
778 if (!dir.existsSync()) { 787 if (!dir.existsSync()) {
779 dir.createSync(); 788 dir.createSync();
780 } 789 }
781 // We assume there's a single extra level of directory structure for packages. 790 // We assume there's a single extra level of directory structure for packages.
782 if (path.split(filename).length > 1) { 791 if (path.split(filename).length > 1) {
783 var subdir = new Directory(path.join('docs', path.dirname(filename))); 792 var subdir = new Directory(path.join(outputDirectory, path.dirname(filename) ));
784 if (!subdir.existsSync()) { 793 if (!subdir.existsSync()) {
785 subdir.createSync(); 794 subdir.createSync();
786 } 795 }
787 } 796 }
788 797
789 File file = new File('docs/$filename'); 798 File file = new File('$outputDirectory/$filename');
Bob Nystrom 2013/11/14 22:43:04 Since you're using path.join() a few lines up, let
Alan Knight 2013/11/15 18:49:56 Done.
790 if (!file.existsSync()) { 799 if (!file.existsSync()) {
791 file.createSync(); 800 file.createSync();
792 } 801 }
793 file.writeAsStringSync(text, mode: append ? FileMode.APPEND : FileMode.WRITE); 802 file.writeAsStringSync(text, mode: append ? FileMode.APPEND : FileMode.WRITE);
794 } 803 }
795 804
796 /// Transforms the map by calling toMap on each value in it. 805 /// Transforms the map by calling toMap on each value in it.
797 Map recurseMap(Map inputMap) { 806 Map recurseMap(Map inputMap) {
798 var outputMap = {}; 807 var outputMap = {};
799 inputMap.forEach((key, value) { 808 inputMap.forEach((key, value) {
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after
1396 /// Remove statics from the map of inherited items before adding them. 1405 /// Remove statics from the map of inherited items before adding them.
1397 Map _filterStatics(Map items) { 1406 Map _filterStatics(Map items) {
1398 var result = {}; 1407 var result = {};
1399 items.forEach((name, item) { 1408 items.forEach((name, item) {
1400 if (!item.isStatic) { 1409 if (!item.isStatic) {
1401 result[name] = item; 1410 result[name] = item;
1402 } 1411 }
1403 }); 1412 });
1404 return result; 1413 return result;
1405 } 1414 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698