| 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 /** | 51 /** |
| 52 * Run this from the `lib/dartdoc` directory. | 52 * Run this from the `lib/dartdoc` directory. |
| 53 */ | 53 */ |
| 54 void main() { | 54 void main() { |
| 55 final args = new Options().arguments; | 55 final args = new Options().arguments; |
| 56 | 56 |
| 57 // Parse the dartdoc options. | 57 // Parse the dartdoc options. |
| 58 bool includeSource; | 58 bool includeSource; |
| 59 int mode; | 59 int mode; |
| 60 String outputDir; | 60 String outputDir; |
| 61 bool generateAppCache; |
| 61 | 62 |
| 62 for (int i = 0; i < args.length - 1; i++) { | 63 for (int i = 0; i < args.length - 1; i++) { |
| 63 final arg = args[i]; | 64 final arg = args[i]; |
| 64 | 65 |
| 65 switch (arg) { | 66 switch (arg) { |
| 66 case '--no-code': | 67 case '--no-code': |
| 67 includeSource = false; | 68 includeSource = false; |
| 68 break; | 69 break; |
| 69 | 70 |
| 70 case '--mode=static': | 71 case '--mode=static': |
| 71 mode = MODE_STATIC; | 72 mode = MODE_STATIC; |
| 72 break; | 73 break; |
| 73 | 74 |
| 74 case '--mode=live-nav': | 75 case '--mode=live-nav': |
| 75 mode = MODE_LIVE_NAV; | 76 mode = MODE_LIVE_NAV; |
| 76 break; | 77 break; |
| 77 | 78 |
| 79 case '--generate-app-cache': |
| 80 case '--generate-app-cache=true': |
| 81 generateAppCache = true; |
| 82 break; |
| 83 |
| 78 default: | 84 default: |
| 79 if (arg.startsWith('--out=')) { | 85 if (arg.startsWith('--out=')) { |
| 80 outputDir = arg.substring('--out='.length); | 86 outputDir = arg.substring('--out='.length); |
| 81 } else { | 87 } else { |
| 82 print('Unknown option: $arg'); | 88 print('Unknown option: $arg'); |
| 83 return; | 89 return; |
| 84 } | 90 } |
| 85 break; | 91 break; |
| 86 } | 92 } |
| 87 } | 93 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 99 final compilerPath = joinPaths(frogPath, 'minfrog'); | 105 final compilerPath = joinPaths(frogPath, 'minfrog'); |
| 100 | 106 |
| 101 parseOptions(frogPath, ['', '', '--libdir=$libDir'], files); | 107 parseOptions(frogPath, ['', '', '--libdir=$libDir'], files); |
| 102 initializeWorld(files); | 108 initializeWorld(files); |
| 103 | 109 |
| 104 final dartdoc = new Dartdoc(); | 110 final dartdoc = new Dartdoc(); |
| 105 | 111 |
| 106 if (includeSource != null) dartdoc.includeSource = includeSource; | 112 if (includeSource != null) dartdoc.includeSource = includeSource; |
| 107 if (mode != null) dartdoc.mode = mode; | 113 if (mode != null) dartdoc.mode = mode; |
| 108 if (outputDir != null) dartdoc.outputDir = outputDir; | 114 if (outputDir != null) dartdoc.outputDir = outputDir; |
| 115 if (generateAppCache != null) dartdoc.generateAppCache = generateAppCache; |
| 109 | 116 |
| 110 cleanOutputDirectory(dartdoc.outputDir); | 117 cleanOutputDirectory(dartdoc.outputDir); |
| 111 | 118 |
| 112 // Compile the client-side code to JS. | 119 // Compile the client-side code to JS. |
| 113 final clientScript = (dartdoc.mode == MODE_STATIC) ? 'static' : 'live-nav'; | 120 final clientScript = (dartdoc.mode == MODE_STATIC) ? 'static' : 'live-nav'; |
| 114 compileScript(compilerPath, libDir, '$scriptDir/client-$clientScript.dart', | 121 final Future scriptCompiled = compileScript(compilerPath, libDir, |
| 115 '${dartdoc.outputDir}/client-$clientScript.js'); | 122 '$scriptDir/client-$clientScript.dart', |
| 123 '${dartdoc.outputDir}/client-$clientScript.js'); |
| 116 | 124 |
| 117 copyFiles('$scriptDir/static', dartdoc.outputDir); | 125 final Future filesCopied = copyFiles('$scriptDir/static', dartdoc.outputDir); |
| 118 | 126 |
| 119 dartdoc.document(entrypoint); | 127 Futures.wait([scriptCompiled, filesCopied]).then((_) { |
| 128 dartdoc.document(entrypoint); |
| 129 }); |
| 120 | 130 |
| 121 print('Documented ${dartdoc._totalLibraries} libraries, ' + | 131 print('Documented ${dartdoc._totalLibraries} libraries, ' + |
| 122 '${dartdoc._totalTypes} types, and ' + | 132 '${dartdoc._totalTypes} types, and ' + |
| 123 '${dartdoc._totalMembers} members.'); | 133 '${dartdoc._totalMembers} members.'); |
| 124 } | 134 } |
| 125 | 135 |
| 126 /** | 136 /** |
| 127 * Gets the full path to the directory containing the entrypoint of the current | 137 * Gets the full path to the directory containing the entrypoint of the current |
| 128 * script. In other words, if you invoked dartdoc, directly, it will be the | 138 * script. In other words, if you invoked dartdoc, directly, it will be the |
| 129 * path to the directory containing `dartdoc.dart`. If you're running a script | 139 * path to the directory containing `dartdoc.dart`. If you're running a script |
| (...skipping 15 matching lines...) Expand all Loading... |
| 145 outputDir.createSync(); | 155 outputDir.createSync(); |
| 146 } | 156 } |
| 147 | 157 |
| 148 /** | 158 /** |
| 149 * Copies all of the files in the directory [from] to [to]. Does *not* | 159 * Copies all of the files in the directory [from] to [to]. Does *not* |
| 150 * recursively copy subdirectories. | 160 * recursively copy subdirectories. |
| 151 * | 161 * |
| 152 * Note: runs asynchronously, so you won't see any files copied until after the | 162 * Note: runs asynchronously, so you won't see any files copied until after the |
| 153 * event loop has had a chance to pump (i.e. after `main()` has returned). | 163 * event loop has had a chance to pump (i.e. after `main()` has returned). |
| 154 */ | 164 */ |
| 155 void copyFiles(String from, String to) { | 165 Future copyFiles(String from, String to) { |
| 166 final completer = new Completer(); |
| 156 final fromDir = new Directory(from); | 167 final fromDir = new Directory(from); |
| 157 fromDir.onFile = (path) { | 168 fromDir.onFile = (path) { |
| 158 final name = basename(path); | 169 final name = basename(path); |
| 159 // TODO(rnystrom): Hackish. Ignore 'hidden' files like .DS_Store. | 170 // TODO(rnystrom): Hackish. Ignore 'hidden' files like .DS_Store. |
| 160 if (name.startsWith('.')) return; | 171 if (name.startsWith('.')) return; |
| 161 | 172 |
| 162 new File(path).readAsBytes((bytes) { | 173 new File(path).readAsBytes((bytes) { |
| 163 final outFile = new File('$to/$name'); | 174 final outFile = new File('$to/$name'); |
| 164 final stream = outFile.openOutputStream(FileMode.WRITE); | 175 final stream = outFile.openOutputStream(FileMode.WRITE); |
| 165 stream.write(bytes, copyBuffer: false); | 176 stream.write(bytes, copyBuffer: false); |
| 166 stream.close(); | 177 stream.close(); |
| 167 }); | 178 }); |
| 168 }; | 179 }; |
| 180 fromDir.onDone = (done) => completer.complete(true); |
| 169 fromDir.list(recursive: false); | 181 fromDir.list(recursive: false); |
| 182 return completer.future; |
| 170 } | 183 } |
| 171 | 184 |
| 172 /** | 185 /** |
| 173 * Compiles the given Dart script to a JavaScript file at [jsPath] using the | 186 * Compiles the given Dart script to a JavaScript file at [jsPath] using the |
| 174 * Dart-to-JS compiler located at [compilerPath]. | 187 * Dart-to-JS compiler located at [compilerPath]. |
| 175 */ | 188 */ |
| 176 void compileScript(String compilerPath, String libDir, | 189 Future compileScript(String compilerPath, String libDir, |
| 177 String dartPath, String jsPath) { | 190 String dartPath, String jsPath) { |
| 191 final completer = new Completer(); |
| 178 onExit(int exitCode, String stdout, String stderr) { | 192 onExit(int exitCode, String stdout, String stderr) { |
| 179 if (exitCode != 0) { | 193 if (exitCode != 0) { |
| 180 final message = 'Non-zero exit code from $compilerPath'; | 194 final message = 'Non-zero exit code from $compilerPath'; |
| 181 print('$message.'); | 195 print('$message.'); |
| 182 print(stdout); | 196 print(stdout); |
| 183 print(stderr); | 197 print(stderr); |
| 184 throw message; | 198 throw message; |
| 185 } | 199 } |
| 200 completer.complete(true); |
| 186 } | 201 } |
| 187 | 202 |
| 188 onError(error) { | 203 onError(error) { |
| 189 final message = 'Error trying to execute $compilerPath. Error: $error'; | 204 final message = 'Error trying to execute $compilerPath. Error: $error'; |
| 190 print('$message.'); | 205 print('$message.'); |
| 191 throw message; | 206 throw message; |
| 192 } | 207 } |
| 193 | 208 |
| 194 print('Compiling $dartPath to $jsPath'); | 209 print('Compiling $dartPath to $jsPath'); |
| 195 new Process.run(compilerPath, [ | 210 new Process.run(compilerPath, [ |
| 196 '--libdir=$libDir', '--out=$jsPath', | 211 '--libdir=$libDir', '--out=$jsPath', |
| 197 '--compile-only', '--enable-type-checks', '--warnings-as-errors', | 212 '--compile-only', '--enable-type-checks', '--warnings-as-errors', |
| 198 dartPath], null, onExit).onError = onError; | 213 dartPath], null, onExit).onError = onError; |
| 214 return completer.future; |
| 199 } | 215 } |
| 200 | 216 |
| 201 class Dartdoc { | 217 class Dartdoc { |
| 202 | 218 |
| 203 /** Set to `false` to not include the source code in the generated docs. */ | 219 /** Set to `false` to not include the source code in the generated docs. */ |
| 204 bool includeSource = true; | 220 bool includeSource = true; |
| 205 | 221 |
| 206 /** | 222 /** |
| 207 * Dartdoc can generate docs in a few different ways based on how dynamic you | 223 * Dartdoc can generate docs in a few different ways based on how dynamic you |
| 208 * want the client-side behavior to be. The value for this should be one of | 224 * want the client-side behavior to be. The value for this should be one of |
| 209 * the `MODE_` constants. | 225 * the `MODE_` constants. |
| 210 */ | 226 */ |
| 211 int mode = MODE_LIVE_NAV; | 227 int mode = MODE_LIVE_NAV; |
| 212 | 228 |
| 229 /** |
| 230 * Generates the App Cache manifest file, enabling offline doc viewing. |
| 231 */ |
| 232 bool generateAppCache = false; |
| 233 |
| 213 /** Path to generate HTML files into. */ | 234 /** Path to generate HTML files into. */ |
| 214 String outputDir = 'docs'; | 235 String outputDir = 'docs'; |
| 215 | 236 |
| 216 /** | 237 /** |
| 217 * The title used for the overall generated output. Set this to change it. | 238 * The title used for the overall generated output. Set this to change it. |
| 218 */ | 239 */ |
| 219 String mainTitle = 'Dart Documentation'; | 240 String mainTitle = 'Dart Documentation'; |
| 220 | 241 |
| 221 /** | 242 /** |
| 222 * The URL that the Dart logo links to. Defaults "index.html", the main | 243 * The URL that the Dart logo links to. Defaults "index.html", the main |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 return a.name.toUpperCase().compareTo(b.name.toUpperCase()); | 321 return a.name.toUpperCase().compareTo(b.name.toUpperCase()); |
| 301 }); | 322 }); |
| 302 | 323 |
| 303 // Generate the docs. | 324 // Generate the docs. |
| 304 if (mode == MODE_LIVE_NAV) docNavigationJson(); | 325 if (mode == MODE_LIVE_NAV) docNavigationJson(); |
| 305 | 326 |
| 306 docIndex(); | 327 docIndex(); |
| 307 for (final library in _sortedLibraries) { | 328 for (final library in _sortedLibraries) { |
| 308 docLibrary(library); | 329 docLibrary(library); |
| 309 } | 330 } |
| 331 |
| 332 if (generateAppCache) { |
| 333 generateAppCacheManifest(); |
| 334 } |
| 310 } finally { | 335 } finally { |
| 311 options.dietParse = oldDietParse; | 336 options.dietParse = oldDietParse; |
| 312 } | 337 } |
| 313 } | 338 } |
| 314 | 339 |
| 315 void startFile(String path) { | 340 void startFile(String path) { |
| 316 _filePath = path; | 341 _filePath = path; |
| 317 _file = new StringBuffer(); | 342 _file = new StringBuffer(); |
| 318 } | 343 } |
| 319 | 344 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 343 * breadcrumbs are an interleaved list of links and titles. If a link is null, | 368 * breadcrumbs are an interleaved list of links and titles. If a link is null, |
| 344 * then no link will be generated. For example, given: | 369 * then no link will be generated. For example, given: |
| 345 * | 370 * |
| 346 * ['foo', 'foo.html', 'bar', null] | 371 * ['foo', 'foo.html', 'bar', null] |
| 347 * | 372 * |
| 348 * It will output: | 373 * It will output: |
| 349 * | 374 * |
| 350 * <a href="foo.html">foo</a> › bar | 375 * <a href="foo.html">foo</a> › bar |
| 351 */ | 376 */ |
| 352 void writeHeader(String title, List<String> breadcrumbs) { | 377 void writeHeader(String title, List<String> breadcrumbs) { |
| 378 final htmlAttributes = generateAppCache ? |
| 379 'manifest="/appcache.manifest"' : ''; |
| 380 |
| 353 write( | 381 write( |
| 354 ''' | 382 ''' |
| 355 <!DOCTYPE html> | 383 <!DOCTYPE html> |
| 356 <html> | 384 <html${htmlAttributes == '' ? '' : ' $htmlAttributes'}> |
| 357 <head> | 385 <head> |
| 358 '''); | 386 '''); |
| 359 writeHeadContents(title); | 387 writeHeadContents(title); |
| 360 | 388 |
| 361 // Add data attributes describing what the page documents. | 389 // Add data attributes describing what the page documents. |
| 362 var data = ''; | 390 var data = ''; |
| 363 if (_currentLibrary != null) { | 391 if (_currentLibrary != null) { |
| 364 data += ' data-library="${md.escapeHtml(_currentLibrary.name)}"'; | 392 data += ' data-library="${md.escapeHtml(_currentLibrary.name)}"'; |
| 365 } | 393 } |
| 366 | 394 |
| (...skipping 922 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1289 // * Type parameters of the enclosing type. | 1317 // * Type parameters of the enclosing type. |
| 1290 | 1318 |
| 1291 return new md.Element.text('code', name); | 1319 return new md.Element.text('code', name); |
| 1292 } | 1320 } |
| 1293 | 1321 |
| 1294 // TODO(rnystrom): Move into SourceSpan? | 1322 // TODO(rnystrom): Move into SourceSpan? |
| 1295 int getSpanColumn(SourceSpan span) { | 1323 int getSpanColumn(SourceSpan span) { |
| 1296 final line = span.file.getLine(span.start); | 1324 final line = span.file.getLine(span.start); |
| 1297 return span.file.getColumn(line, span.start); | 1325 return span.file.getColumn(line, span.start); |
| 1298 } | 1326 } |
| 1327 |
| 1328 generateAppCacheManifest() { |
| 1329 print('Generating app cache manifest from output $outputDir'); |
| 1330 startFile('appcache.manifest'); |
| 1331 write("CACHE MANIFEST\n\n"); |
| 1332 write("# VERSION: ${new Date.now()}\n\n"); |
| 1333 write("NETWORK:\n*\n\n"); |
| 1334 write("CACHE:\n"); |
| 1335 var toCache = new Directory(outputDir); |
| 1336 var pathPrefix = new File(outputDir).fullPathSync(); |
| 1337 var pathPrefixLength = pathPrefix.length; |
| 1338 toCache.onFile = (filename) { |
| 1339 if (filename.endsWith('appcache.manifest')) { |
| 1340 return; |
| 1341 } |
| 1342 var relativePath = filename.substring(pathPrefixLength + 1); |
| 1343 write("$relativePath\n"); |
| 1344 }; |
| 1345 toCache.onDone = (done) => endFile(); |
| 1346 toCache.list(recursive: true); |
| 1347 } |
| 1299 } | 1348 } |
| OLD | NEW |