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

Side by Side Diff: lib/dartdoc/dartdoc.dart

Issue 10809035: Several new features and improvements for dartdoc. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated cf. comments Created 8 years, 5 months 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
« no previous file with comments | « lib/crypto/crypto.dart ('k') | lib/dartdoc/static/styles.css » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 * To generate docs for a library, run this script with the path to an 6 * To generate docs for a library, run this script with the path to an
7 * entrypoint .dart file, like: 7 * entrypoint .dart file, like:
8 * 8 *
9 * $ dart dartdoc.dart foo.dart 9 * $ dart dartdoc.dart foo.dart
10 * 10 *
11 * This will create a "docs" directory with the docs for your libraries. To 11 * This will create a "docs" directory with the docs for your libraries. To
12 * create these beautiful docs, dartdoc parses your library and every library 12 * create these beautiful docs, dartdoc parses your library and every library
13 * it imports (recursively). From each library, it parses all classes and 13 * it imports (recursively). From each library, it parses all classes and
14 * members, finds the associated doc comments and builds crosslinked docs from 14 * members, finds the associated doc comments and builds crosslinked docs from
15 * them. 15 * them.
16 */ 16 */
17 #library('dartdoc'); 17 #library('dartdoc');
18 18
19 #import('dart:io'); 19 #import('dart:io');
20 #import('dart:uri'); 20 #import('dart:uri');
21 #import('dart:json'); 21 #import('dart:json');
22 #import('mirrors/mirrors.dart'); 22 #import('mirrors/mirrors.dart');
23 #import('mirrors/mirrors_util.dart'); 23 #import('mirrors/mirrors_util.dart');
24 #import('mirrors/dart2js_mirror.dart', prefix: 'dart2js'); 24 #import('mirrors/dart2js_mirror.dart', prefix: 'dart2js');
25 #import('classify.dart'); 25 #import('classify.dart');
26 #import('markdown.dart', prefix: 'md'); 26 #import('markdown.dart', prefix: 'md');
27 #import('../compiler/implementation/scanner/scannerlib.dart', 27 #import('../compiler/implementation/scanner/scannerlib.dart',
28 prefix: 'dart2js'); 28 prefix: 'dart2js');
29 #import('../compiler/implementation/library_map.dart');
29 30
30 #source('comment_map.dart'); 31 #source('comment_map.dart');
31 #source('utils.dart'); 32 #source('utils.dart');
32 33
33 // TODO(johnniwinther): Note that [IN_SDK] gets initialized to true when this 34 // TODO(johnniwinther): Note that [IN_SDK] gets initialized to true when this
34 // file is modified by the SDK deployment script. If you change, be sure to test 35 // file is modified by the SDK deployment script. If you change, be sure to test
35 // that dartdoc still works when run from the built SDK directory. 36 // that dartdoc still works when run from the built SDK directory.
36 final bool IN_SDK = false; 37 final bool IN_SDK = false;
37 38
38 /** 39 /**
(...skipping 10 matching lines...) Expand all
49 * 50 *
50 * This dramatically reduces the generated size of the HTML since a large 51 * This dramatically reduces the generated size of the HTML since a large
51 * fraction of each static page is just redundant navigation links. 52 * fraction of each static page is just redundant navigation links.
52 * 53 *
53 * In this mode, the browser will do a XHR for nav.json which means that to 54 * In this mode, the browser will do a XHR for nav.json which means that to
54 * preview docs locally, you will need to enable requesting file:// links in 55 * preview docs locally, you will need to enable requesting file:// links in
55 * your browser or run a little local server like `python -m SimpleHTTPServer`. 56 * your browser or run a little local server like `python -m SimpleHTTPServer`.
56 */ 57 */
57 final MODE_LIVE_NAV = 1; 58 final MODE_LIVE_NAV = 1;
58 59
60 final API_LOCATION = 'http://api.dartlang.org/';
61
59 /** 62 /**
60 * Run this from the `lib/dartdoc` directory. 63 * Run this from the `lib/dartdoc` directory.
61 */ 64 */
62 void main() { 65 void main() {
63 final args = new Options().arguments; 66 final args = new Options().arguments;
64 67
65 // Parse the dartdoc options. 68 final dartdoc = new Dartdoc();
66 bool includeSource;
67 int mode;
68 Path outputDir;
69 bool generateAppCache;
70 bool omitGenerationTime;
71 bool verbose;
72 69
73 if (args.isEmpty()) { 70 if (args.isEmpty()) {
74 print('No arguments provided.'); 71 print('No arguments provided.');
75 printUsage(); 72 printUsage();
76 return; 73 return;
77 } 74 }
78 75
79 for (int i = 0; i < args.length - 1; i++) { 76 final entrypoints = <Path>[];
77
78 var i = 0;
79 while (i < args.length) {
80 final arg = args[i]; 80 final arg = args[i];
81 if (!arg.startsWith('--')) {
82 // The remaining arguments must be entry points.
83 break;
84 }
81 85
82 switch (arg) { 86 switch (arg) {
83 case '--no-code': 87 case '--no-code':
84 includeSource = false; 88 dartdoc.includeSource = false;
85 break; 89 break;
86 90
87 case '--mode=static': 91 case '--mode=static':
88 mode = MODE_STATIC; 92 dartdoc.mode = MODE_STATIC;
89 break; 93 break;
90 94
91 case '--mode=live-nav': 95 case '--mode=live-nav':
92 mode = MODE_LIVE_NAV; 96 dartdoc.mode = MODE_LIVE_NAV;
93 break; 97 break;
94 98
95 case '--generate-app-cache': 99 case '--generate-app-cache':
96 case '--generate-app-cache=true': 100 case '--generate-app-cache=true':
97 generateAppCache = true; 101 dartdoc.generateAppCache = true;
98 break; 102 break;
99 103
100 case '--omit-generation-time': 104 case '--omit-generation-time':
101 omitGenerationTime = true; 105 dartdoc.omitGenerationTime = true;
102 break; 106 break;
103 case '--verbose': 107 case '--verbose':
104 verbose = true; 108 dartdoc.verbose = true;
109 break;
110 case '--include-api':
111 dartdoc.includeApi = true;
112 break;
113 case '--link-api':
114 dartdoc.linkToApi = true;
105 break; 115 break;
106 116
107 default: 117 default:
108 if (arg.startsWith('--out=')) { 118 if (arg.startsWith('--out=')) {
109 outputDir = new Path.fromNative(arg.substring('--out='.length)); 119 dartdoc.outputDir =
120 new Path.fromNative(arg.substring('--out='.length));
121 } else if (arg.startsWith('--include-lib=')) {
122 dartdoc.includedLibraries =
123 arg.substring('--include-lib='.length).split(',');
124 } else if (arg.startsWith('--exclude-lib=')) {
125 dartdoc.excludedLibraries =
126 arg.substring('--exclude-lib='.length).split(',');
110 } else { 127 } else {
111 print('Unknown option: $arg'); 128 print('Unknown option: $arg');
112 printUsage(); 129 printUsage();
113 return; 130 return;
114 } 131 }
115 break; 132 break;
116 } 133 }
134 i++;
135 }
136 while (i < args.length) {
137 final arg = args[i];
138 entrypoints.add(new Path.fromNative(arg));
139 i++;
117 } 140 }
118 141
119 final entrypoint = new Path.fromNative(args[args.length - 1]); 142 if (entrypoints.isEmpty()) {
120 143 print('No entrypoints provided.');
121 final dartdoc = new Dartdoc(); 144 printUsage();
122 145 return;
123 if (includeSource != null) dartdoc.includeSource = includeSource;
124 if (mode != null) dartdoc.mode = mode;
125 if (outputDir != null) dartdoc.outputDir = outputDir;
126 if (generateAppCache != null) dartdoc.generateAppCache = generateAppCache;
127 if (omitGenerationTime != null) {
128 dartdoc.omitGenerationTime = omitGenerationTime;
129 } 146 }
130 if (verbose != null) dartdoc.verbose = verbose;
131 147
132 cleanOutputDirectory(dartdoc.outputDir); 148 cleanOutputDirectory(dartdoc.outputDir);
133 149
134 dartdoc.documentEntryPoint(entrypoint, libPath); 150 dartdoc.documentLibraries(entrypoints, libPath);
135 151
136 // Compile the client-side code to JS. 152 // Compile the client-side code to JS.
137 final clientScript = (dartdoc.mode == MODE_STATIC) ? 'static' : 'live-nav'; 153 final clientScript = (dartdoc.mode == MODE_STATIC) ? 'static' : 'live-nav';
138 Future compiled = compileScript( 154 Future compiled = compileScript(
139 scriptDir.append('client-$clientScript.dart'), 155 scriptDir.append('client-$clientScript.dart'),
140 dartdoc.outputDir.append('client-$clientScript.js')); 156 dartdoc.outputDir.append('client-$clientScript.js'));
141 157
142 Future filesCopied = copyDirectory(scriptDir.append('static'), 158 Future filesCopied = copyDirectory(scriptDir.append('static'),
143 dartdoc.outputDir); 159 dartdoc.outputDir);
144 160
145 Futures.wait([compiled, filesCopied]).then((_) { 161 Futures.wait([compiled, filesCopied]).then((_) {
146 print('Documented ${dartdoc._totalLibraries} libraries, ' 162 print('Documented ${dartdoc._totalLibraries} libraries, '
147 '${dartdoc._totalTypes} types, and ' 163 '${dartdoc._totalTypes} types, and '
148 '${dartdoc._totalMembers} members.'); 164 '${dartdoc._totalMembers} members.');
149 }); 165 });
150 } 166 }
151 167
152 void printUsage() { 168 void printUsage() {
153 print(''' 169 print('''
154 Usage dartdoc [options] <entrypoint> 170 Usage dartdoc [options] <entrypoint(s)>
155 [options] include 171 [options] include
156 --no-code Do not include source code in the documentation. 172 --no-code Do not include source code in the documentation.
157 173
158 --mode=static Generates completely static HTML containing 174 --mode=static Generates completely static HTML containing
159 everything you need to browse the docs. The only 175 everything you need to browse the docs. The only
160 client side behavior is trivial stuff like syntax 176 client side behavior is trivial stuff like syntax
161 highlighting code. 177 highlighting code.
162 178
163 --mode=live-nav (default) Generated docs do not include baked HTML 179 --mode=live-nav (default) Generated docs do not include baked HTML
164 navigation. Instead, a single `nav.json` file is 180 navigation. Instead, a single `nav.json` file is
165 created and the appropriate navigation is generated 181 created and the appropriate navigation is generated
166 client-side by parsing that and building HTML. 182 client-side by parsing that and building HTML.
167 This dramatically reduces the generated size of 183 This dramatically reduces the generated size of
168 the HTML since a large fraction of each static page 184 the HTML since a large fraction of each static page
169 is just redundant navigation links. 185 is just redundant navigation links.
170 In this mode, the browser will do a XHR for 186 In this mode, the browser will do a XHR for
171 nav.json which means that to preview docs locally, 187 nav.json which means that to preview docs locally,
172 you will need to enable requesting file:// links in 188 you will need to enable requesting file:// links in
173 your browser or run a little local server like 189 your browser or run a little local server like
174 `python -m SimpleHTTPServer`. 190 `python -m SimpleHTTPServer`.
175 191
176 --generate-app-cache Generates the App Cache manifest file, enabling 192 --generate-app-cache Generates the App Cache manifest file, enabling
177 offline doc viewing. 193 offline doc viewing.
178 194
179 --out=<dir> Generates files into directory <dir>. If omitted 195 --out=<dir> Generates files into directory <dir>. If omitted
180 the files are generated into ./docs/ 196 the files are generated into ./docs/
181 197
198 --link-api Link to the online language API in the generated
199 documentation. The option overrides inclusion
200 through --include-api or --include-lib.
201
202 --include-api Include the used API libraries in the generated
203 documentation. If the --link-api option is used,
204 this option is ignored.
205
206 --include-lib=<libs> Use this option to explicitly specify which
207 libraries to include in the documentation. If
208 omitted, all used libraries are included by
209 default. <libs> is comma-separated list of library
210 names.
211
212 --exclude-lib=<libs> Use this option to explicitly specify which
213 libraries to exclude from the documentation. If
214 omitted, no libraries are excluded. <libs> is
215 comma-separated list of library names.
216
182 --verbose Print verbose information during generation. 217 --verbose Print verbose information during generation.
183 '''); 218 ''');
184 } 219 }
185 220
186 /** 221 /**
187 * Gets the full path to the directory containing the entrypoint of the current 222 * Gets the full path to the directory containing the entrypoint of the current
188 * script. In other words, if you invoked dartdoc, directly, it will be the 223 * script. In other words, if you invoked dartdoc, directly, it will be the
189 * path to the directory containing `dartdoc.dart`. If you're running a script 224 * path to the directory containing `dartdoc.dart`. If you're running a script
190 * that imports dartdoc, it will be the path to that script. 225 * that imports dartdoc, it will be the path to that script.
191 */ 226 */
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 340
306 /** Set this to add content before the footer */ 341 /** Set this to add content before the footer */
307 String preFooterText = ''; 342 String preFooterText = '';
308 343
309 /** Set this to omit generation timestamp from output */ 344 /** Set this to omit generation timestamp from output */
310 bool omitGenerationTime = false; 345 bool omitGenerationTime = false;
311 346
312 /** Set by Dartdoc user to print extra information during generation. */ 347 /** Set by Dartdoc user to print extra information during generation. */
313 bool verbose = false; 348 bool verbose = false;
314 349
315 /** Set this to select the libraries to document */ 350 /** Set this to include API libraries in the documentation. */
316 List<String> libraries = null; 351 bool includeApi = false;
352
353 /** Set this to generate links to the online API. */
354 bool linkToApi = false;
355
356 /** Set this to select the libraries to include in the documentation. */
357 List<String> includedLibraries = const <String>[];
358
359 /** Set this to select the libraries to exclude from the documentation. */
360 List<String> excludedLibraries = const <String>[];
317 361
318 /** 362 /**
319 * This list contains the libraries sorted in by the library name. 363 * This list contains the libraries sorted in by the library name.
320 */ 364 */
321 List<LibraryMirror> _sortedLibraries; 365 List<LibraryMirror> _sortedLibraries;
322 366
323 CommentMap _comments; 367 CommentMap _comments;
324 368
325 /** The library that we're currently generating docs for. */ 369 /** The library that we're currently generating docs for. */
326 LibraryMirror _currentLibrary; 370 LibraryMirror _currentLibrary;
(...skipping 19 matching lines...) Expand all
346 // Patch in support for [:...:]-style code to the markdown parser. 390 // Patch in support for [:...:]-style code to the markdown parser.
347 // TODO(rnystrom): Markdown already has syntax for this. Phase this out? 391 // TODO(rnystrom): Markdown already has syntax for this. Phase this out?
348 md.InlineParser.syntaxes.insertRange(0, 1, 392 md.InlineParser.syntaxes.insertRange(0, 1,
349 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]')); 393 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]'));
350 394
351 md.setImplicitLinkResolver((name) => resolveNameReference(name, 395 md.setImplicitLinkResolver((name) => resolveNameReference(name,
352 currentLibrary: _currentLibrary, currentType: _currentType, 396 currentLibrary: _currentLibrary, currentType: _currentType,
353 currentMember: _currentMember)); 397 currentMember: _currentMember));
354 } 398 }
355 399
356 bool includeLibrary(LibraryMirror library) { 400 /**
357 if (libraries != null) { 401 * Returns `true` if [library] is included in the generated documentation.
358 return libraries.indexOf(library.simpleName()) != -1; 402 */
403 bool shouldIncludeLibrary(LibraryMirror library) {
404 if (shouldLinkToPublicApi(library)) {
405 return false;
359 } 406 }
360 return true; 407 var includeByDefault = true;
408 String libraryName = library.simpleName();
409 if (!includedLibraries.isEmpty()) {
410 includeByDefault = false;
411 if (includedLibraries.indexOf(libraryName) != -1) {
412 return true;
413 }
414 }
415 if (excludedLibraries.indexOf(libraryName) != -1) {
416 return false;
417 }
418 if (libraryName.startsWith('dart:')) {
419 String suffix = libraryName.substring('dart:'.length);
420 LibraryInfo info = DART2JS_LIBRARY_MAP[suffix];
421 if (info != null) {
422 return !info.isInternal && includeApi;
423 }
424 }
425 return includeByDefault;
426 }
427
428 /**
429 * Returns `true` if links to the public API should be generated for
430 * [library].
431 */
432 bool shouldLinkToPublicApi(LibraryMirror library) {
433 if (linkToApi) {
434 String libraryName = library.simpleName();
435 if (libraryName.startsWith('dart:')) {
436 String suffix = libraryName.substring('dart:'.length);
437 LibraryInfo info = DART2JS_LIBRARY_MAP[suffix];
438 if (info != null) {
439 return !info.isInternal;
440 }
441 }
442 }
443 return false;
361 } 444 }
362 445
363 String get footerContent(){ 446 String get footerContent(){
364 var footerItems = []; 447 var footerItems = [];
365 if(!omitGenerationTime) { 448 if(!omitGenerationTime) {
366 footerItems.add("This page was generated at ${new Date.now()}"); 449 footerItems.add("This page was generated at ${new Date.now()}");
367 } 450 }
368 if(footerText != null) { 451 if(footerText != null) {
369 footerItems.add(footerText); 452 footerItems.add(footerText);
370 } 453 }
(...skipping 13 matching lines...) Expand all
384 } 467 }
385 468
386 void documentLibraries(List<Path> libraryList, Path libPath) { 469 void documentLibraries(List<Path> libraryList, Path libPath) {
387 final compilation = new Compilation.library(libraryList, libPath); 470 final compilation = new Compilation.library(libraryList, libPath);
388 _document(compilation); 471 _document(compilation);
389 } 472 }
390 473
391 void _document(Compilation compilation) { 474 void _document(Compilation compilation) {
392 // Sort the libraries by name (not key). 475 // Sort the libraries by name (not key).
393 _sortedLibraries = new List<LibraryMirror>.from( 476 _sortedLibraries = new List<LibraryMirror>.from(
394 compilation.mirrors().libraries().getValues().filter(includeLibrary)); 477 compilation.mirrors().libraries().getValues().filter(
478 shouldIncludeLibrary));
395 _sortedLibraries.sort((x, y) { 479 _sortedLibraries.sort((x, y) {
396 return x.simpleName().toUpperCase().compareTo( 480 return x.simpleName().toUpperCase().compareTo(
397 y.simpleName().toUpperCase()); 481 y.simpleName().toUpperCase());
398 }); 482 });
399 483
400 // Generate the docs. 484 // Generate the docs.
401 if (mode == MODE_LIVE_NAV) docNavigationJson(); 485 if (mode == MODE_LIVE_NAV) docNavigationJson();
402 486
403 docIndex(); 487 docIndex();
404 for (final library in _sortedLibraries) { 488 for (final library in _sortedLibraries) {
(...skipping 869 matching lines...) Expand 10 before | Expand all | Expand 10 after
1274 if (type.isTypeVariable) { 1358 if (type.isTypeVariable) {
1275 // If we're using a type parameter within the body of a generic class then 1359 // If we're using a type parameter within the body of a generic class then
1276 // just link back up to the class. 1360 // just link back up to the class.
1277 write(a(typeUrl(enclosingType), type.simpleName())); 1361 write(a(typeUrl(enclosingType), type.simpleName()));
1278 return; 1362 return;
1279 } 1363 }
1280 1364
1281 assert(type is InterfaceMirror); 1365 assert(type is InterfaceMirror);
1282 1366
1283 // Link to the type. 1367 // Link to the type.
1284 if (includeLibrary(type.library())) { 1368 if (shouldLinkToPublicApi(type.library())) {
1369 write('<a href="$API_LOCATION${typeUrl(type)}">${type.simpleName()}</a>');
1370 } else if (shouldIncludeLibrary(type.library())) {
1285 write(a(typeUrl(type), type.simpleName())); 1371 write(a(typeUrl(type), type.simpleName()));
1286 } else { 1372 } else {
1287 write(type.simpleName()); 1373 write(type.simpleName());
1288 } 1374 }
1289 1375
1290 if (type.isDeclaration) { 1376 if (type.isDeclaration) {
1291 // Avoid calling [:typeArguments():] on a declaration. 1377 // Avoid calling [:typeArguments():] on a declaration.
1292 return; 1378 return;
1293 } 1379 }
1294 1380
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
1498 } 1584 }
1499 1585
1500 /** 1586 /**
1501 * Returns [:true:] if [type] should be regarded as an exception. 1587 * Returns [:true:] if [type] should be regarded as an exception.
1502 */ 1588 */
1503 bool isException(TypeMirror type) { 1589 bool isException(TypeMirror type) {
1504 return type.simpleName().endsWith('Exception'); 1590 return type.simpleName().endsWith('Exception');
1505 } 1591 }
1506 } 1592 }
1507 1593
OLDNEW
« no previous file with comments | « lib/crypto/crypto.dart ('k') | lib/dartdoc/static/styles.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698