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 * |
(...skipping 10 matching lines...) Expand all Loading... | |
21 #import('../../frog/lang.dart'); | 21 #import('../../frog/lang.dart'); |
22 #import('../../frog/file_system.dart'); | 22 #import('../../frog/file_system.dart'); |
23 #import('../../frog/file_system_vm.dart'); | 23 #import('../../frog/file_system_vm.dart'); |
24 #import('classify.dart'); | 24 #import('classify.dart'); |
25 #import('markdown.dart', prefix: 'md'); | 25 #import('markdown.dart', prefix: 'md'); |
26 | 26 |
27 #source('comment_map.dart'); | 27 #source('comment_map.dart'); |
28 #source('utils.dart'); | 28 #source('utils.dart'); |
29 | 29 |
30 /** | 30 /** |
31 * Generates completely static HTML containing everything you need to browse | |
32 * the docs. The only client side behavior is trivial stuff like syntax | |
33 * highlighting code. | |
34 */ | |
35 final MODE_STATIC = 0; | |
36 | |
37 /** | |
38 * Generated docs do not include baked HTML navigation. Instead, a single | |
39 * `nav.json` file is created and the appropriate navigation is generated | |
40 * client-side by parsing that and building HTML. | |
41 * | |
42 * This dramatically reduces the generated size of the HTML since a large | |
43 * fraction of each static page is just redundant navigation links. | |
44 * | |
45 * In this mode, the browser will do a XHR for nav.json which means that to | |
46 * preview docs locally, you will need to enable requesting file:// links in | |
47 * your browser or run a little local server like `python -m SimpleHTTPServer`. | |
48 */ | |
49 final MODE_LIVE_NAV = 1; | |
50 | |
51 /** | |
52 * Run this from the `lib/dartdoc` directory. | 31 * Run this from the `lib/dartdoc` directory. |
53 */ | 32 */ |
54 void main() { | 33 void main() { |
55 final args = new Options().arguments; | 34 final args = new Options().arguments; |
56 | 35 |
57 // Parse the dartdoc options. | 36 // Parse the dartdoc options. |
58 bool includeSource; | 37 bool includeSource; |
59 String mode; | 38 int mode; |
60 String outputDir; | 39 String outputDir; |
61 | 40 |
62 for (int i = 0; i < args.length - 1; i++) { | 41 for (int i = 0; i < args.length - 1; i++) { |
63 final arg = args[i]; | 42 final arg = args[i]; |
64 | 43 |
65 switch (arg) { | 44 switch (arg) { |
66 case '--no-code': | 45 case '--no-code': |
67 includeSource = false; | 46 includeSource = false; |
68 break; | 47 break; |
69 | 48 |
70 case '--mode=static': | 49 case '--mode=static': |
71 mode = MODE_STATIC; | 50 mode = Dartdoc.MODE_STATIC; |
72 break; | 51 break; |
73 | 52 |
74 case '--mode=live-nav': | 53 case '--mode=live-nav': |
75 mode = MODE_LIVE_NAV; | 54 mode = Dartdoc.MODE_LIVE_NAV; |
76 break; | 55 break; |
77 | 56 |
78 default: | 57 default: |
79 if (arg.startsWith('--out=')) { | 58 if (arg.startsWith('--out=')) { |
80 outputDir = arg.substring('--out='.length); | 59 outputDir = arg.substring('--out='.length); |
81 } else { | 60 } else { |
82 print('Unknown option: $arg'); | 61 print('Unknown option: $arg'); |
83 return; | 62 return; |
84 } | 63 } |
85 break; | 64 break; |
(...skipping 17 matching lines...) Expand all Loading... | |
103 | 82 |
104 final dartdoc = new Dartdoc(); | 83 final dartdoc = new Dartdoc(); |
105 | 84 |
106 if (includeSource != null) dartdoc.includeSource = includeSource; | 85 if (includeSource != null) dartdoc.includeSource = includeSource; |
107 if (mode != null) dartdoc.mode = mode; | 86 if (mode != null) dartdoc.mode = mode; |
108 if (outputDir != null) dartdoc.outputDir = outputDir; | 87 if (outputDir != null) dartdoc.outputDir = outputDir; |
109 | 88 |
110 cleanOutputDirectory(dartdoc.outputDir); | 89 cleanOutputDirectory(dartdoc.outputDir); |
111 | 90 |
112 // Compile the client-side code to JS. | 91 // Compile the client-side code to JS. |
113 final clientScript = (dartdoc.mode == MODE_STATIC) ? 'static' : 'live-nav'; | 92 final clientScript = (dartdoc.mode == Dartdoc.MODE_STATIC) ? 'static' : 'live- nav'; |
114 compileScript(compilerPath, libDir, '$scriptDir/client-$clientScript.dart', | 93 compileScript(compilerPath, libDir, '$scriptDir/client-$clientScript.dart', |
115 '${dartdoc.outputDir}/client-$clientScript.js'); | 94 '${dartdoc.outputDir}/client-$clientScript.js'); |
116 | 95 |
117 copyFiles('$scriptDir/static', dartdoc.outputDir); | 96 copyFiles('$scriptDir/static', dartdoc.outputDir); |
118 | 97 |
119 dartdoc.document(entrypoint); | 98 dartdoc.document(entrypoint); |
120 | 99 |
121 print('Documented ${dartdoc._totalLibraries} libraries, ' + | 100 print('Documented ${dartdoc._totalLibraries} libraries, ' + |
122 '${dartdoc._totalTypes} types, and ' + | 101 '${dartdoc._totalTypes} types, and ' + |
123 '${dartdoc._totalMembers} members.'); | 102 '${dartdoc._totalMembers} members.'); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
175 void compileScript(String compilerPath, String libDir, | 154 void compileScript(String compilerPath, String libDir, |
176 String dartPath, String jsPath) { | 155 String dartPath, String jsPath) { |
177 final process = new Process.start(compilerPath, [ | 156 final process = new Process.start(compilerPath, [ |
178 '--libdir=$libDir', '--out=$jsPath', | 157 '--libdir=$libDir', '--out=$jsPath', |
179 '--compile-only', '--enable-type-checks', '--warnings-as-errors', | 158 '--compile-only', '--enable-type-checks', '--warnings-as-errors', |
180 dartPath]); | 159 dartPath]); |
181 | 160 |
182 process.stdout.pipe(stdout, close: false); | 161 process.stdout.pipe(stdout, close: false); |
183 | 162 |
184 process.onError = (error) { | 163 process.onError = (error) { |
185 print('Failed to compile $dartPath. Error:'); | 164 print('Failed to compile $dartPath with $compilerPath. Error:'); |
186 print(error); | 165 print(error); |
187 }; | 166 }; |
188 } | 167 } |
189 | 168 |
190 class Dartdoc { | 169 class Dartdoc { |
170 | |
Bob Nystrom
2012/03/28 20:01:21
Why move these here?
sethladd
2012/03/28 21:52:17
Good question, I think I was trying something else
| |
171 /** | |
172 * Generates completely static HTML containing everything you need to browse | |
173 * the docs. The only client side behavior is trivial stuff like syntax | |
174 * highlighting code. | |
175 */ | |
176 static final MODE_STATIC = 0; | |
177 | |
178 /** | |
179 * Generated docs do not include baked HTML navigation. Instead, a single | |
180 * `nav.json` file is created and the appropriate navigation is generated | |
181 * client-side by parsing that and building HTML. | |
182 * | |
183 * This dramatically reduces the generated size of the HTML since a large | |
184 * fraction of each static page is just redundant navigation links. | |
185 * | |
186 * In this mode, the browser will do a XHR for nav.json which means that to | |
187 * preview docs locally, you will need to enable requesting file:// links in | |
188 * your browser or run a little local server like `python -m SimpleHTTPServer` . | |
189 */ | |
190 static final MODE_LIVE_NAV = 1; | |
191 | |
191 /** Set to `false` to not include the source code in the generated docs. */ | 192 /** Set to `false` to not include the source code in the generated docs. */ |
192 bool includeSource = true; | 193 bool includeSource = true; |
193 | 194 |
194 /** | 195 /** |
195 * Dartdoc can generate docs in a few different ways based on how dynamic you | 196 * Dartdoc can generate docs in a few different ways based on how dynamic you |
196 * want the client-side behavior to be. The value for this should be one of | 197 * want the client-side behavior to be. The value for this should be one of |
197 * the `MODE_` constants. | 198 * the `MODE_` constants. |
198 */ | 199 */ |
199 int mode = MODE_LIVE_NAV; | 200 int mode = MODE_LIVE_NAV; |
200 | 201 |
(...skipping 16 matching lines...) Expand all Loading... | |
217 * this is `null` then no search box will be shown. | 218 * this is `null` then no search box will be shown. |
218 */ | 219 */ |
219 String searchEngineId = null; | 220 String searchEngineId = null; |
220 | 221 |
221 /* The URL that the embedded search results should be displayed on. */ | 222 /* The URL that the embedded search results should be displayed on. */ |
222 String searchResultsUrl = 'results.html'; | 223 String searchResultsUrl = 'results.html'; |
223 | 224 |
224 /** Set this to add footer text to each generated page. */ | 225 /** Set this to add footer text to each generated page. */ |
225 String footerText = ''; | 226 String footerText = ''; |
226 | 227 |
228 /** Set this to add content before the footer */ | |
229 String preFooterText = ''; | |
230 | |
227 /** | 231 /** |
228 * From exposes the set of libraries in `world.libraries`. That maps library | 232 * From exposes the set of libraries in `world.libraries`. That maps library |
229 * *keys* to [Library] objects. The keys are *not* exactly the same as their | 233 * *keys* to [Library] objects. The keys are *not* exactly the same as their |
230 * names. This means if we order by key, we won't actually have them sorted | 234 * names. This means if we order by key, we won't actually have them sorted |
231 * correctly. This list contains the libraries in correct order by their | 235 * correctly. This list contains the libraries in correct order by their |
232 * *name*. | 236 * *name*. |
233 */ | 237 */ |
234 List<Library> _sortedLibraries; | 238 List<Library> _sortedLibraries; |
235 | 239 |
236 CommentMap _comments; | 240 CommentMap _comments; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 | 283 |
280 world.resolveAll(); | 284 world.resolveAll(); |
281 | 285 |
282 // Sort the libraries by name (not key). | 286 // Sort the libraries by name (not key). |
283 _sortedLibraries = world.libraries.getValues(); | 287 _sortedLibraries = world.libraries.getValues(); |
284 _sortedLibraries.sort((a, b) { | 288 _sortedLibraries.sort((a, b) { |
285 return a.name.toUpperCase().compareTo(b.name.toUpperCase()); | 289 return a.name.toUpperCase().compareTo(b.name.toUpperCase()); |
286 }); | 290 }); |
287 | 291 |
288 // Generate the docs. | 292 // Generate the docs. |
289 if (mode == MODE_LIVE_NAV) docNavigationJson(); | 293 if (mode == Dartdoc.MODE_LIVE_NAV) docNavigationJson(); |
290 | 294 |
291 docIndex(); | 295 docIndex(); |
292 for (final library in _sortedLibraries) { | 296 for (final library in _sortedLibraries) { |
293 docLibrary(library); | 297 docLibrary(library); |
294 } | 298 } |
295 } finally { | 299 } finally { |
296 options.dietParse = oldDietParse; | 300 options.dietParse = oldDietParse; |
297 } | 301 } |
298 } | 302 } |
299 | 303 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
386 } | 390 } |
387 | 391 |
388 writeln('</div>'); | 392 writeln('</div>'); |
389 | 393 |
390 docNavigation(); | 394 docNavigation(); |
391 writeln('<div class="content">'); | 395 writeln('<div class="content">'); |
392 } | 396 } |
393 | 397 |
394 String get clientScript() { | 398 String get clientScript() { |
395 switch (mode) { | 399 switch (mode) { |
396 case MODE_STATIC: return 'client-static'; | 400 case Dartdoc.MODE_STATIC: return 'client-static'; |
397 case MODE_LIVE_NAV: return 'client-live-nav'; | 401 case Dartdoc.MODE_LIVE_NAV: return 'client-live-nav'; |
398 default: throw 'Unknown mode $mode.'; | 402 default: throw 'Unknown mode $mode.'; |
399 } | 403 } |
400 } | 404 } |
401 | 405 |
402 void writeHeadContents(String title) { | 406 void writeHeadContents(String title) { |
403 writeln( | 407 writeln( |
404 ''' | 408 ''' |
405 <meta charset="utf-8"> | 409 <meta charset="utf-8"> |
406 <title>$title</title> | 410 <title>$title</title> |
407 <link rel="stylesheet" type="text/css" | 411 <link rel="stylesheet" type="text/css" |
408 href="${relativePath('styles.css')}" /> | 412 href="${relativePath('styles.css')}"> |
409 <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700 ,800" rel="stylesheet" type="text/css"> | 413 <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700 ,800" rel="stylesheet" type="text/css"> |
410 <link rel="shortcut icon" href="${relativePath('favicon.ico')}" /> | 414 <link rel="shortcut icon" href="${relativePath('favicon.ico')}"> |
411 <script src="${relativePath('$clientScript.js')}"></script> | |
412 '''); | 415 '''); |
413 } | 416 } |
414 | 417 |
415 void writeFooter() { | 418 void writeFooter() { |
416 writeln( | 419 writeln( |
417 ''' | 420 ''' |
418 </div> | 421 </div> |
419 <div class="clear"></div> | 422 <div class="clear"></div> |
420 </div> | 423 </div> |
424 ${preFooterText} | |
421 <div class="footer">$footerText</div> | 425 <div class="footer">$footerText</div> |
426 <script async src="${relativePath('$clientScript.js')}"></script> | |
Bob Nystrom
2012/03/28 20:01:21
\o/
sethladd
2012/03/28 21:52:17
Done.
| |
422 </body></html> | 427 </body></html> |
423 '''); | 428 '''); |
424 } | 429 } |
425 | 430 |
426 void docIndex() { | 431 void docIndex() { |
427 startFile('index.html'); | 432 startFile('index.html'); |
428 | 433 |
429 writeHeader(mainTitle, []); | 434 writeHeader(mainTitle, []); |
430 | 435 |
431 writeln('<h2>$mainTitle</h2>'); | 436 writeln('<h2>$mainTitle</h2>'); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
474 | 479 |
475 libraries[library.name] = types; | 480 libraries[library.name] = types; |
476 } | 481 } |
477 | 482 |
478 void docNavigation() { | 483 void docNavigation() { |
479 writeln( | 484 writeln( |
480 ''' | 485 ''' |
481 <div class="nav"> | 486 <div class="nav"> |
482 '''); | 487 '''); |
483 | 488 |
484 if (mode == MODE_STATIC) { | 489 if (mode == Dartdoc.MODE_STATIC) { |
485 for (final library in _sortedLibraries) { | 490 for (final library in _sortedLibraries) { |
486 write('<h2><div class="icon-library"></div>'); | 491 write('<h2><div class="icon-library"></div>'); |
487 | 492 |
488 if ((_currentLibrary == library) && (_currentType == null)) { | 493 if ((_currentLibrary == library) && (_currentType == null)) { |
489 write('<strong>${library.name}</strong>'); | 494 write('<strong>${library.name}</strong>'); |
490 } else { | 495 } else { |
491 write('${a(libraryUrl(library), library.name)}'); | 496 write('${a(libraryUrl(library), library.name)}'); |
492 } | 497 } |
493 write('</h2>'); | 498 write('</h2>'); |
494 | 499 |
(...skipping 777 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1272 | 1277 |
1273 return new md.Element.text('code', name); | 1278 return new md.Element.text('code', name); |
1274 } | 1279 } |
1275 | 1280 |
1276 // TODO(rnystrom): Move into SourceSpan? | 1281 // TODO(rnystrom): Move into SourceSpan? |
1277 int getSpanColumn(SourceSpan span) { | 1282 int getSpanColumn(SourceSpan span) { |
1278 final line = span.file.getLine(span.start); | 1283 final line = span.file.getLine(span.start); |
1279 return span.file.getColumn(line, span.start); | 1284 return span.file.getColumn(line, span.start); |
1280 } | 1285 } |
1281 } | 1286 } |
OLD | NEW |