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:math'); | 20 #import('dart:math'); |
21 #import('dart:uri'); | 21 #import('dart:uri'); |
22 #import('dart:json'); | 22 #import('dart:json'); |
23 #import('mirrors/mirrors.dart'); | 23 |
24 #import('mirrors/mirrors_util.dart'); | 24 // TODO(rnystrom): Use "package:" URL (#4968). |
25 #import('mirrors/dart2js_mirror.dart', prefix: 'dart2js'); | 25 #import('mirrors.dart'); |
| 26 #import('mirrors_util.dart'); |
| 27 #import('src/mirrors/dart2js_mirror.dart', prefix: 'dart2js'); |
26 #import('classify.dart'); | 28 #import('classify.dart'); |
27 #import('markdown.dart', prefix: 'md'); | 29 #import('markdown.dart', prefix: 'md'); |
28 #import('../../lib/compiler/implementation/scanner/scannerlib.dart', | 30 #import('../../../lib/compiler/implementation/scanner/scannerlib.dart', |
29 prefix: 'dart2js'); | 31 prefix: 'dart2js'); |
30 #import('../../lib/_internal/libraries.dart'); | 32 #import('../../../lib/_internal/libraries.dart'); |
31 | 33 |
32 #source('comment_map.dart'); | 34 // TODO(rnystrom): Use "package:" URL (#4968). |
33 #source('nav.dart'); | 35 #source('src/dartdoc/comment_map.dart'); |
34 #source('utils.dart'); | 36 #source('src/dartdoc/nav.dart'); |
35 | 37 #source('src/dartdoc/utils.dart'); |
36 // TODO(johnniwinther): Note that [IN_SDK] gets initialized to true when this | |
37 // file is modified by the SDK deployment script. If you change, be sure to test | |
38 // that dartdoc still works when run from the built SDK directory. | |
39 const bool IN_SDK = false; | |
40 | 38 |
41 /** | 39 /** |
42 * Generates completely static HTML containing everything you need to browse | 40 * Generates completely static HTML containing everything you need to browse |
43 * the docs. The only client side behavior is trivial stuff like syntax | 41 * the docs. The only client side behavior is trivial stuff like syntax |
44 * highlighting code. | 42 * highlighting code. |
45 */ | 43 */ |
46 const MODE_STATIC = 0; | 44 const MODE_STATIC = 0; |
47 | 45 |
48 /** | 46 /** |
49 * Generated docs do not include baked HTML navigation. Instead, a single | 47 * Generated docs do not include baked HTML navigation. Instead, a single |
50 * `nav.json` file is created and the appropriate navigation is generated | 48 * `nav.json` file is created and the appropriate navigation is generated |
51 * client-side by parsing that and building HTML. | 49 * client-side by parsing that and building HTML. |
52 * | 50 * |
53 * 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 |
54 * fraction of each static page is just redundant navigation links. | 52 * fraction of each static page is just redundant navigation links. |
55 * | 53 * |
56 * 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 |
57 * 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 |
58 * 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`. |
59 */ | 57 */ |
60 const MODE_LIVE_NAV = 1; | 58 const MODE_LIVE_NAV = 1; |
61 | 59 |
62 const API_LOCATION = 'http://api.dartlang.org/'; | 60 const API_LOCATION = 'http://api.dartlang.org/'; |
63 | 61 |
64 /** | 62 /** |
65 * Run this from the `pkg/dartdoc` directory. | |
66 */ | |
67 void main() { | |
68 final args = new Options().arguments; | |
69 | |
70 final dartdoc = new Dartdoc(); | |
71 | |
72 if (args.isEmpty()) { | |
73 print('No arguments provided.'); | |
74 printUsage(); | |
75 return; | |
76 } | |
77 | |
78 final entrypoints = <Path>[]; | |
79 | |
80 var i = 0; | |
81 while (i < args.length) { | |
82 final arg = args[i]; | |
83 if (!arg.startsWith('--')) { | |
84 // The remaining arguments must be entry points. | |
85 break; | |
86 } | |
87 | |
88 switch (arg) { | |
89 case '--no-code': | |
90 dartdoc.includeSource = false; | |
91 break; | |
92 | |
93 case '--mode=static': | |
94 dartdoc.mode = MODE_STATIC; | |
95 break; | |
96 | |
97 case '--mode=live-nav': | |
98 dartdoc.mode = MODE_LIVE_NAV; | |
99 break; | |
100 | |
101 case '--generate-app-cache': | |
102 case '--generate-app-cache=true': | |
103 dartdoc.generateAppCache = true; | |
104 break; | |
105 | |
106 case '--omit-generation-time': | |
107 dartdoc.omitGenerationTime = true; | |
108 break; | |
109 case '--verbose': | |
110 dartdoc.verbose = true; | |
111 break; | |
112 case '--include-api': | |
113 dartdoc.includeApi = true; | |
114 break; | |
115 case '--link-api': | |
116 dartdoc.linkToApi = true; | |
117 break; | |
118 | |
119 default: | |
120 if (arg.startsWith('--out=')) { | |
121 dartdoc.outputDir = | |
122 new Path.fromNative(arg.substring('--out='.length)); | |
123 } else if (arg.startsWith('--include-lib=')) { | |
124 dartdoc.includedLibraries = | |
125 arg.substring('--include-lib='.length).split(','); | |
126 } else if (arg.startsWith('--exclude-lib=')) { | |
127 dartdoc.excludedLibraries = | |
128 arg.substring('--exclude-lib='.length).split(','); | |
129 } else { | |
130 print('Unknown option: $arg'); | |
131 printUsage(); | |
132 return; | |
133 } | |
134 break; | |
135 } | |
136 i++; | |
137 } | |
138 while (i < args.length) { | |
139 final arg = args[i]; | |
140 entrypoints.add(new Path.fromNative(arg)); | |
141 i++; | |
142 } | |
143 | |
144 if (entrypoints.isEmpty()) { | |
145 print('No entrypoints provided.'); | |
146 printUsage(); | |
147 return; | |
148 } | |
149 | |
150 cleanOutputDirectory(dartdoc.outputDir); | |
151 | |
152 dartdoc.documentLibraries(entrypoints, libPath); | |
153 | |
154 // Compile the client-side code to JS. | |
155 final clientScript = (dartdoc.mode == MODE_STATIC) ? 'static' : 'live-nav'; | |
156 Future compiled = compileScript( | |
157 scriptDir.append('client-$clientScript.dart'), | |
158 dartdoc.outputDir.append('client-$clientScript.js')); | |
159 | |
160 Future filesCopied = copyDirectory(scriptDir.append('static'), | |
161 dartdoc.outputDir); | |
162 | |
163 Futures.wait([compiled, filesCopied]).then((_) { | |
164 dartdoc.cleanup(); | |
165 print('Documented ${dartdoc._totalLibraries} libraries, ' | |
166 '${dartdoc._totalTypes} types, and ' | |
167 '${dartdoc._totalMembers} members.'); | |
168 }); | |
169 } | |
170 | |
171 void printUsage() { | |
172 print(''' | |
173 Usage dartdoc [options] <entrypoint(s)> | |
174 [options] include | |
175 --no-code Do not include source code in the documentation. | |
176 | |
177 --mode=static Generates completely static HTML containing | |
178 everything you need to browse the docs. The only | |
179 client side behavior is trivial stuff like syntax | |
180 highlighting code. | |
181 | |
182 --mode=live-nav (default) Generated docs do not include baked HTML | |
183 navigation. Instead, a single `nav.json` file is | |
184 created and the appropriate navigation is generated | |
185 client-side by parsing that and building HTML. | |
186 This dramatically reduces the generated size of | |
187 the HTML since a large fraction of each static page | |
188 is just redundant navigation links. | |
189 In this mode, the browser will do a XHR for | |
190 nav.json which means that to preview docs locally, | |
191 you will need to enable requesting file:// links in | |
192 your browser or run a little local server like | |
193 `python -m SimpleHTTPServer`. | |
194 | |
195 --generate-app-cache Generates the App Cache manifest file, enabling | |
196 offline doc viewing. | |
197 | |
198 --out=<dir> Generates files into directory <dir>. If omitted | |
199 the files are generated into ./docs/ | |
200 | |
201 --link-api Link to the online language API in the generated | |
202 documentation. The option overrides inclusion | |
203 through --include-api or --include-lib. | |
204 | |
205 --include-api Include the used API libraries in the generated | |
206 documentation. If the --link-api option is used, | |
207 this option is ignored. | |
208 | |
209 --include-lib=<libs> Use this option to explicitly specify which | |
210 libraries to include in the documentation. If | |
211 omitted, all used libraries are included by | |
212 default. <libs> is comma-separated list of library | |
213 names. | |
214 | |
215 --exclude-lib=<libs> Use this option to explicitly specify which | |
216 libraries to exclude from the documentation. If | |
217 omitted, no libraries are excluded. <libs> is | |
218 comma-separated list of library names. | |
219 | |
220 --verbose Print verbose information during generation. | |
221 '''); | |
222 } | |
223 | |
224 /** | |
225 * Gets the full path to the directory containing the entrypoint of the current | 63 * Gets the full path to the directory containing the entrypoint of the current |
226 * script. In other words, if you invoked dartdoc, directly, it will be the | 64 * script. In other words, if you invoked dartdoc, directly, it will be the |
227 * path to the directory containing `dartdoc.dart`. If you're running a script | 65 * path to the directory containing `dartdoc.dart`. If you're running a script |
228 * that imports dartdoc, it will be the path to that script. | 66 * that imports dartdoc, it will be the path to that script. |
229 */ | 67 */ |
230 // TODO(johnniwinther): Convert to final (lazily initialized) variables when | 68 // TODO(johnniwinther): Convert to final (lazily initialized) variables when |
231 // the feature is supported. | 69 // the feature is supported. |
232 Path get scriptDir => | 70 Path get scriptDir => |
233 new Path.fromNative(new Options().script).directoryPath; | 71 new Path.fromNative(new Options().script).directoryPath; |
234 | 72 |
235 // TODO(johnniwinther): Trailing slashes matter due to the use of [libPath] as | |
236 // a base URI with [Uri.resolve]. | |
237 /// Relative path to the library in which dart2js resides. | |
238 Path get libPath => IN_SDK | |
239 ? scriptDir.append('../../lib/dart2js/') | |
240 : scriptDir.append('../../'); | |
241 | |
242 /** | 73 /** |
243 * Deletes and recreates the output directory at [path] if it exists. | 74 * Deletes and recreates the output directory at [path] if it exists. |
244 */ | 75 */ |
245 void cleanOutputDirectory(Path path) { | 76 void cleanOutputDirectory(Path path) { |
246 final outputDir = new Directory.fromPath(path); | 77 final outputDir = new Directory.fromPath(path); |
247 if (outputDir.existsSync()) { | 78 if (outputDir.existsSync()) { |
248 outputDir.deleteRecursivelySync(); | 79 outputDir.deleteRecursivelySync(); |
249 } | 80 } |
250 | 81 |
251 try { | 82 try { |
(...skipping 25 matching lines...) Expand all Loading... |
277 | 108 |
278 File fromFile = new File(path); | 109 File fromFile = new File(path); |
279 File toFile = new File.fromPath(to.append(name)); | 110 File toFile = new File.fromPath(to.append(name)); |
280 fromFile.openInputStream().pipe(toFile.openOutputStream()); | 111 fromFile.openInputStream().pipe(toFile.openOutputStream()); |
281 }; | 112 }; |
282 lister.onDone = (done) => completer.complete(true); | 113 lister.onDone = (done) => completer.complete(true); |
283 return completer.future; | 114 return completer.future; |
284 } | 115 } |
285 | 116 |
286 /** | 117 /** |
287 * Compiles the given Dart script to a JavaScript file at [jsPath] using the | 118 * Compiles the dartdoc client-side code to JavaScript using Dart2js. |
288 * Dart2js compiler. | |
289 */ | 119 */ |
290 Future<bool> compileScript(Path dartPath, Path jsPath) { | 120 Future<bool> compileScript(int mode, Path outputDir, Path libPath) { |
| 121 var clientScript = (mode == MODE_STATIC) ? 'static' : 'live-nav'; |
| 122 var dartPath = libPath.append( |
| 123 'pkg/dartdoc/lib/src/client/client-$clientScript.dart'); |
| 124 var jsPath = outputDir.append('client-$clientScript.js'); |
| 125 |
291 var completer = new Completer<bool>(); | 126 var completer = new Completer<bool>(); |
292 var compilation = new Compilation(dartPath, libPath); | 127 var compilation = new Compilation(dartPath, libPath); |
293 Future<String> result = compilation.compileToJavaScript(); | 128 Future<String> result = compilation.compileToJavaScript(); |
294 result.then((jsCode) { | 129 result.then((jsCode) { |
295 writeString(new File.fromPath(jsPath), jsCode); | 130 writeString(new File.fromPath(jsPath), jsCode); |
296 completer.complete(true); | 131 completer.complete(true); |
297 }); | 132 }); |
298 result.handleException((e) => completer.completeException(e)); | 133 result.handleException((e) => completer.completeException(e)); |
299 return completer.future; | 134 return completer.future; |
300 } | 135 } |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 /** The path to the file currently being written to, relative to [outdir]. */ | 220 /** The path to the file currently being written to, relative to [outdir]. */ |
386 Path _filePath; | 221 Path _filePath; |
387 | 222 |
388 /** The file currently being written to. */ | 223 /** The file currently being written to. */ |
389 StringBuffer _file; | 224 StringBuffer _file; |
390 | 225 |
391 int _totalLibraries = 0; | 226 int _totalLibraries = 0; |
392 int _totalTypes = 0; | 227 int _totalTypes = 0; |
393 int _totalMembers = 0; | 228 int _totalMembers = 0; |
394 | 229 |
| 230 int get totalLibraries => _totalLibraries; |
| 231 int get totalTypes => _totalTypes; |
| 232 int get totalMembers => _totalMembers; |
| 233 |
395 Dartdoc() | 234 Dartdoc() |
396 : _comments = new CommentMap(), | 235 : _comments = new CommentMap(), |
397 dartdocPath = scriptDir { | 236 dartdocPath = scriptDir { |
398 // Patch in support for [:...:]-style code to the markdown parser. | 237 // Patch in support for [:...:]-style code to the markdown parser. |
399 // TODO(rnystrom): Markdown already has syntax for this. Phase this out? | 238 // TODO(rnystrom): Markdown already has syntax for this. Phase this out? |
400 md.InlineParser.syntaxes.insertRange(0, 1, | 239 md.InlineParser.syntaxes.insertRange(0, 1, |
401 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]')); | 240 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]')); |
402 | 241 |
403 md.setImplicitLinkResolver((name) => resolveNameReference(name, | 242 md.setImplicitLinkResolver((name) => resolveNameReference(name, |
404 currentLibrary: _currentLibrary, currentType: _currentType, | 243 currentLibrary: _currentLibrary, currentType: _currentType, |
(...skipping 1324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1729 | 1568 |
1730 /** | 1569 /** |
1731 * Used to report an unexpected error in the DartDoc tool or the | 1570 * Used to report an unexpected error in the DartDoc tool or the |
1732 * underlying data | 1571 * underlying data |
1733 */ | 1572 */ |
1734 class InternalError { | 1573 class InternalError { |
1735 final String message; | 1574 final String message; |
1736 const InternalError(this.message); | 1575 const InternalError(this.message); |
1737 String toString() => "InternalError: '$message'"; | 1576 String toString() => "InternalError: '$message'"; |
1738 } | 1577 } |
OLD | NEW |