OLD | NEW |
---|---|
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 Loading... | |
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 List<Path> entrypoints = new List<Path>(); |
Bob Nystrom
2012/07/23 17:04:31
final entrypoints = <Path>[];
Johnni Winther
2012/07/24 08:49:16
Done.
| |
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; | |
Bob Nystrom
2012/07/23 17:04:31
Should be "includeApi".
Johnni Winther
2012/07/24 08:49:16
Done.
| |
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.includeLibraries = | |
123 arg.substring('--include-lib='.length).split(','); | |
124 } else if (arg.startsWith('--exclude-lib=')) { | |
125 dartdoc.excludeLibraries = | |
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 Loading... | |
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 link to the online API. */ | |
floitsch
2012/07/23 10:43:56
links
Johnni Winther
2012/07/24 08:49:16
Done.
| |
354 bool linkToApi = false; | |
355 | |
356 /** Set this to select the libraries to include in the documentation */ | |
floitsch
2012/07/23 10:43:56
documentation.
Johnni Winther
2012/07/24 08:49:16
Done.
| |
357 List<String> includeLibraries = null; | |
floitsch
2012/07/23 10:43:56
Wouldn't it be easier, if you initialized this wit
Bob Nystrom
2012/07/23 17:04:31
+1.
Also, I would name it "includedLibraries", or
Johnni Winther
2012/07/24 08:49:16
Done.
Johnni Winther
2012/07/24 08:49:16
Done.
| |
358 | |
359 /** Set this to select the libraries to exclude from the documentation */ | |
floitsch
2012/07/23 10:43:56
documentation.
Johnni Winther
2012/07/24 08:49:16
Done.
| |
360 List<String> excludeLibraries = null; | |
floitsch
2012/07/23 10:43:56
ditto (empty list).
Bob Nystrom
2012/07/23 17:04:31
"excludedLibraries"
Johnni Winther
2012/07/24 08:49:16
Done.
Johnni Winther
2012/07/24 08:49:16
Done.
| |
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 Loading... | |
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 bool includeLibrary(LibraryMirror library) { |
floitsch
2012/07/23 10:43:56
not a boolean name.
shouldIncludeLibrary?
Bob Nystrom
2012/07/23 17:04:31
+1. Also, needs a doc comment.
| |
357 if (libraries != null) { | 401 if (linkLibrary(library)) { |
Bob Nystrom
2012/07/23 17:04:31
It's up to you, but if you like, the style guide d
| |
358 return libraries.indexOf(library.simpleName()) != -1; | 402 return false; |
403 } | |
404 String libraryName = library.simpleName(); | |
405 if (includeLibraries != null) { | |
406 if (includeLibraries.indexOf(libraryName) != -1) { | |
407 return true; | |
408 } | |
409 } | |
410 if (excludeLibraries != null) { | |
411 if (excludeLibraries.indexOf(libraryName) != -1) { | |
412 return false; | |
413 } | |
414 } | |
415 if (libraryName.startsWith('dart:')) { | |
416 String suffix = libraryName.substring('dart:'.length); | |
floitsch
2012/07/23 10:43:56
This code is duplicated here and below. Maybe crea
Johnni Winther
2012/07/24 08:49:16
They are slightly different.
| |
417 LibraryInfo info = DART2JS_LIBRARY_MAP[suffix]; | |
418 if (info != null) { | |
419 return !info.internal && includeAPI; | |
420 } | |
359 } | 421 } |
360 return true; | 422 return true; |
361 } | 423 } |
362 | 424 |
425 bool linkLibrary(LibraryMirror library) { | |
floitsch
2012/07/23 10:43:56
that's not a boolean name.
shouldLinkToPublicApi ?
Johnni Winther
2012/07/24 08:49:16
Done.
| |
426 if (linkToApi) { | |
427 String libraryName = library.simpleName(); | |
428 if (libraryName.startsWith('dart:')) { | |
429 String suffix = libraryName.substring('dart:'.length); | |
430 LibraryInfo info = DART2JS_LIBRARY_MAP[suffix]; | |
431 if (info != null) { | |
432 return !info.internal; | |
433 } | |
434 } | |
435 } | |
436 return false; | |
437 } | |
438 | |
363 String get footerContent(){ | 439 String get footerContent(){ |
364 var footerItems = []; | 440 var footerItems = []; |
365 if(!omitGenerationTime) { | 441 if(!omitGenerationTime) { |
366 footerItems.add("This page was generated at ${new Date.now()}"); | 442 footerItems.add("This page was generated at ${new Date.now()}"); |
367 } | 443 } |
368 if(footerText != null) { | 444 if(footerText != null) { |
369 footerItems.add(footerText); | 445 footerItems.add(footerText); |
370 } | 446 } |
371 var content = ''; | 447 var content = ''; |
372 for (int i = 0; i < footerItems.length; i++) { | 448 for (int i = 0; i < footerItems.length; i++) { |
(...skipping 901 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1274 if (type.isTypeVariable) { | 1350 if (type.isTypeVariable) { |
1275 // If we're using a type parameter within the body of a generic class then | 1351 // If we're using a type parameter within the body of a generic class then |
1276 // just link back up to the class. | 1352 // just link back up to the class. |
1277 write(a(typeUrl(enclosingType), type.simpleName())); | 1353 write(a(typeUrl(enclosingType), type.simpleName())); |
1278 return; | 1354 return; |
1279 } | 1355 } |
1280 | 1356 |
1281 assert(type is InterfaceMirror); | 1357 assert(type is InterfaceMirror); |
1282 | 1358 |
1283 // Link to the type. | 1359 // Link to the type. |
1284 if (includeLibrary(type.library())) { | 1360 if (linkLibrary(type.library())) { |
1361 write('<a href="$API_LOCATION${typeUrl(type)}">${type.simpleName()}</a>'); | |
1362 } else if (includeLibrary(type.library())) { | |
1285 write(a(typeUrl(type), type.simpleName())); | 1363 write(a(typeUrl(type), type.simpleName())); |
1286 } else { | 1364 } else { |
1287 write(type.simpleName()); | 1365 write(type.simpleName()); |
1288 } | 1366 } |
1289 | 1367 |
1290 if (type.isDeclaration) { | 1368 if (type.isDeclaration) { |
1291 // Avoid calling [:typeArguments():] on a declaration. | 1369 // Avoid calling [:typeArguments():] on a declaration. |
1292 return; | 1370 return; |
1293 } | 1371 } |
1294 | 1372 |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1498 } | 1576 } |
1499 | 1577 |
1500 /** | 1578 /** |
1501 * Returns [:true:] if [type] should be regarded as an exception. | 1579 * Returns [:true:] if [type] should be regarded as an exception. |
1502 */ | 1580 */ |
1503 bool isException(TypeMirror type) { | 1581 bool isException(TypeMirror type) { |
1504 return type.simpleName().endsWith('Exception'); | 1582 return type.simpleName().endsWith('Exception'); |
1505 } | 1583 } |
1506 } | 1584 } |
1507 | 1585 |
OLD | NEW |