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:async'; |
19 import 'dart:io'; | 20 import 'dart:io'; |
20 import 'dart:math'; | 21 import 'dart:math'; |
21 import 'dart:uri'; | 22 import 'dart:uri'; |
22 import 'dart:json'; | 23 import 'dart:json' as json; |
23 | 24 |
24 import '../../compiler/implementation/mirrors/mirrors.dart'; | 25 import '../../compiler/implementation/mirrors/mirrors.dart'; |
25 import '../../compiler/implementation/mirrors/mirrors_util.dart'; | 26 import '../../compiler/implementation/mirrors/mirrors_util.dart'; |
26 import '../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js; | 27 import '../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js; |
27 import 'classify.dart'; | 28 import 'classify.dart'; |
28 import 'universe_serializer.dart'; | 29 import 'universe_serializer.dart'; |
29 import 'markdown.dart' as md; | 30 import 'markdown.dart' as md; |
30 import 'src/json_serializer.dart' as json_serializer; | 31 import 'src/json_serializer.dart' as json_serializer; |
31 import '../../compiler/implementation/scanner/scannerlib.dart' as dart2js; | 32 import '../../compiler/implementation/scanner/scannerlib.dart' as dart2js; |
32 import '../../libraries.dart'; | 33 import '../../libraries.dart'; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 'lib/_internal/dartdoc/lib/src/client/client-$clientScript.dart'); | 134 'lib/_internal/dartdoc/lib/src/client/client-$clientScript.dart'); |
134 var jsPath = outputDir.append('client-$clientScript.js'); | 135 var jsPath = outputDir.append('client-$clientScript.js'); |
135 | 136 |
136 var completer = new Completer<bool>(); | 137 var completer = new Completer<bool>(); |
137 var compilation = new Compilation(dartPath, libPath); | 138 var compilation = new Compilation(dartPath, libPath); |
138 Future<String> result = compilation.compileToJavaScript(); | 139 Future<String> result = compilation.compileToJavaScript(); |
139 result.then((jsCode) { | 140 result.then((jsCode) { |
140 writeString(new File.fromPath(jsPath), jsCode); | 141 writeString(new File.fromPath(jsPath), jsCode); |
141 completer.complete(true); | 142 completer.complete(true); |
142 }); | 143 }); |
143 result.handleException((e) => completer.completeException(e)); | 144 result.catchError((e) => completer.completeError(e.error, e.stackTrace)); |
144 return completer.future; | 145 return completer.future; |
145 } | 146 } |
146 | 147 |
147 class Dartdoc { | 148 class Dartdoc { |
148 | 149 |
149 /** Set to `false` to not include the source code in the generated docs. */ | 150 /** Set to `false` to not include the source code in the generated docs. */ |
150 bool includeSource = true; | 151 bool includeSource = true; |
151 | 152 |
152 /** | 153 /** |
153 * Dartdoc can generate docs in a few different ways based on how dynamic you | 154 * Dartdoc can generate docs in a few different ways based on how dynamic you |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 } | 330 } |
330 | 331 |
331 void documentLibraries(List<Path> libraryList, Path libPath, Path pkgPath) { | 332 void documentLibraries(List<Path> libraryList, Path libPath, Path pkgPath) { |
332 final compilation = new Compilation.library(libraryList, libPath, pkgPath); | 333 final compilation = new Compilation.library(libraryList, libPath, pkgPath); |
333 _document(compilation); | 334 _document(compilation); |
334 } | 335 } |
335 | 336 |
336 void _document(Compilation compilation) { | 337 void _document(Compilation compilation) { |
337 // Sort the libraries by name (not key). | 338 // Sort the libraries by name (not key). |
338 _sortedLibraries = new List<LibraryMirror>.from( | 339 _sortedLibraries = new List<LibraryMirror>.from( |
339 compilation.mirrors.libraries.values.filter( | 340 compilation.mirrors.libraries.values.where(shouldIncludeLibrary)); |
340 shouldIncludeLibrary)); | |
341 _sortedLibraries.sort((x, y) { | 341 _sortedLibraries.sort((x, y) { |
342 return displayName(x).toUpperCase().compareTo( | 342 return displayName(x).toUpperCase().compareTo( |
343 displayName(y).toUpperCase()); | 343 displayName(y).toUpperCase()); |
344 }); | 344 }); |
345 | 345 |
346 // Generate the docs. | 346 // Generate the docs. |
347 if (mode == MODE_LIVE_NAV) { | 347 if (mode == MODE_LIVE_NAV) { |
348 docNavigationJson(); | 348 docNavigationJson(); |
349 } else { | 349 } else { |
350 docNavigationDart(); | 350 docNavigationDart(); |
351 } | 351 } |
352 | 352 |
353 docIndex(); | 353 docIndex(); |
354 for (final library in _sortedLibraries) { | 354 for (final library in _sortedLibraries) { |
355 docLibrary(library); | 355 docLibrary(library); |
356 } | 356 } |
357 | 357 |
358 if (generateAppCache) { | 358 if (generateAppCache) { |
359 generateAppCacheManifest(); | 359 generateAppCacheManifest(); |
360 } | 360 } |
361 | 361 |
362 startFile("apidoc.json"); | 362 startFile("apidoc.json"); |
363 var libraries = _sortedLibraries.map( | 363 var libraries = _sortedLibraries.mappedBy( |
364 (lib) => new LibraryElement(lib.qualifiedName, lib, _comments)); | 364 (lib) => new LibraryElement(lib.qualifiedName, lib, _comments)) |
| 365 .toList(); |
365 write(json_serializer.serialize(libraries)); | 366 write(json_serializer.serialize(libraries)); |
366 endFile(); | 367 endFile(); |
367 } | 368 } |
368 | 369 |
369 void startFile(String path) { | 370 void startFile(String path) { |
370 _filePath = new Path(path); | 371 _filePath = new Path(path); |
371 _file = new StringBuffer(); | 372 _file = new StringBuffer(); |
372 } | 373 } |
373 | 374 |
374 void endFile() { | 375 void endFile() { |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 void docIndexLibrary(LibraryMirror library) { | 538 void docIndexLibrary(LibraryMirror library) { |
538 writeln('<h4>${a(libraryUrl(library), displayName(library))}</h4>'); | 539 writeln('<h4>${a(libraryUrl(library), displayName(library))}</h4>'); |
539 } | 540 } |
540 | 541 |
541 /** | 542 /** |
542 * Walks the libraries and creates a JSON object containing the data needed | 543 * Walks the libraries and creates a JSON object containing the data needed |
543 * to generate navigation for them. | 544 * to generate navigation for them. |
544 */ | 545 */ |
545 void docNavigationJson() { | 546 void docNavigationJson() { |
546 startFile('nav.json'); | 547 startFile('nav.json'); |
547 writeln(JSON.stringify(createNavigationInfo())); | 548 writeln(json.stringify(createNavigationInfo())); |
548 endFile(); | 549 endFile(); |
549 } | 550 } |
550 | 551 |
551 void docNavigationDart() { | 552 void docNavigationDart() { |
552 final dir = new Directory.fromPath(tmpPath); | 553 final dir = new Directory.fromPath(tmpPath); |
553 if (!dir.existsSync()) { | 554 if (!dir.existsSync()) { |
554 // TODO(3914): Hack to avoid 'file already exists' exception | 555 // TODO(3914): Hack to avoid 'file already exists' exception |
555 // thrown due to invalid result from dir.existsSync() (probably due to | 556 // thrown due to invalid result from dir.existsSync() (probably due to |
556 // race conditions). | 557 // race conditions). |
557 try { | 558 try { |
558 dir.createSync(); | 559 dir.createSync(); |
559 } on DirectoryIOException catch (e) { | 560 } on DirectoryIOException catch (e) { |
560 // Ignore. | 561 // Ignore. |
561 } | 562 } |
562 } | 563 } |
563 String jsonString = JSON.stringify(createNavigationInfo()); | 564 String jsonString = json.stringify(createNavigationInfo()); |
564 String dartString = jsonString.replaceAll(r"$", r"\$"); | 565 String dartString = jsonString.replaceAll(r"$", r"\$"); |
565 final filePath = tmpPath.append('nav.dart'); | 566 final filePath = tmpPath.append('nav.dart'); |
566 writeString(new File.fromPath(filePath), | 567 writeString(new File.fromPath(filePath), |
567 'get json => $dartString;'); | 568 'get json => $dartString;'); |
568 } | 569 } |
569 | 570 |
570 Path get tmpPath => dartdocPath.append('tmp'); | 571 Path get tmpPath => dartdocPath.append('tmp'); |
571 | 572 |
572 void cleanup() { | 573 void cleanup() { |
573 final dir = new Directory.fromPath(tmpPath); | 574 final dir = new Directory.fromPath(tmpPath); |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 void docInheritance(ClassMirror type) { | 898 void docInheritance(ClassMirror type) { |
898 // Don't show the inheritance details for Object. It doesn't have any base | 899 // Don't show the inheritance details for Object. It doesn't have any base |
899 // class (obviously) and it has too many subclasses to be useful. | 900 // class (obviously) and it has too many subclasses to be useful. |
900 if (type.isObject) return; | 901 if (type.isObject) return; |
901 | 902 |
902 // Writes an unordered list of references to types with an optional header. | 903 // Writes an unordered list of references to types with an optional header. |
903 listTypes(types, header) { | 904 listTypes(types, header) { |
904 if (types == null) return; | 905 if (types == null) return; |
905 | 906 |
906 // Filter out injected types. (JavaScriptIndexingBehavior) | 907 // Filter out injected types. (JavaScriptIndexingBehavior) |
907 types = new List.from(types.filter((t) => t.library != null)); | 908 types = new List.from(types.where((t) => t.library != null)); |
908 | 909 |
909 var publicTypes; | 910 var publicTypes; |
910 if (showPrivate) { | 911 if (showPrivate) { |
911 publicTypes = types; | 912 publicTypes = types; |
912 } else { | 913 } else { |
913 // Skip private types. | 914 // Skip private types. |
914 publicTypes = new List.from(types.filter((t) => !t.isPrivate)); | 915 publicTypes = new List.from(types.where((t) => !t.isPrivate)); |
915 } | 916 } |
916 if (publicTypes.length == 0) return; | 917 if (publicTypes.length == 0) return; |
917 | 918 |
918 writeln('<h3>$header</h3>'); | 919 writeln('<h3>$header</h3>'); |
919 writeln('<p>'); | 920 writeln('<p>'); |
920 bool first = true; | 921 bool first = true; |
921 for (final t in publicTypes) { | 922 for (final t in publicTypes) { |
922 if (!first) write(', '); | 923 if (!first) write(', '); |
923 typeSpan(t); | 924 typeSpan(t); |
924 first = false; | 925 first = false; |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1203 } | 1204 } |
1204 } else { | 1205 } else { |
1205 // Document as field. | 1206 // Document as field. |
1206 docProperty(host, getter, setter); | 1207 docProperty(host, getter, setter); |
1207 } | 1208 } |
1208 } | 1209 } |
1209 } | 1210 } |
1210 writeln('</div>'); | 1211 writeln('</div>'); |
1211 } | 1212 } |
1212 | 1213 |
1213 void docMethods(ContainerMirror host, String title, List<MethodMirror> methods
, | 1214 void docMethods(ContainerMirror host, String title, List<Mirror> methods, |
1214 {bool allInherited}) { | 1215 {bool allInherited}) { |
1215 if (methods.length > 0) { | 1216 if (methods.length > 0) { |
1216 writeln('<div${allInherited ? ' class="inherited"' : ''}>'); | 1217 writeln('<div${allInherited ? ' class="inherited"' : ''}>'); |
1217 writeln('<h3>$title</h3>'); | 1218 writeln('<h3>$title</h3>'); |
1218 for (final method in methods) { | 1219 for (MethodMirror method in methods) { |
1219 docMethod(host, method); | 1220 docMethod(host, method); |
1220 } | 1221 } |
1221 writeln('</div>'); | 1222 writeln('</div>'); |
1222 } | 1223 } |
1223 } | 1224 } |
1224 | 1225 |
1225 /** | 1226 /** |
1226 * Documents the [member] declared in [host]. Handles all kinds of members | 1227 * Documents the [member] declared in [host]. Handles all kinds of members |
1227 * including getters, setters, and constructors. If [member] is a | 1228 * including getters, setters, and constructors. If [member] is a |
1228 * [FieldMirror] it is documented as a getter or setter depending upon the | 1229 * [FieldMirror] it is documented as a getter or setter depending upon the |
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1664 // TODO(rnystrom): Do we need to handle ParameterTypes here like | 1665 // TODO(rnystrom): Do we need to handle ParameterTypes here like |
1665 // annotation() does? | 1666 // annotation() does? |
1666 return a(typeUrl(type), typeName(type), 'crossref'); | 1667 return a(typeUrl(type), typeName(type), 'crossref'); |
1667 } | 1668 } |
1668 | 1669 |
1669 /** Generates a human-friendly string representation for a type. */ | 1670 /** Generates a human-friendly string representation for a type. */ |
1670 typeName(TypeMirror type, {bool showBounds: false}) { | 1671 typeName(TypeMirror type, {bool showBounds: false}) { |
1671 if (type.isVoid) { | 1672 if (type.isVoid) { |
1672 return 'void'; | 1673 return 'void'; |
1673 } | 1674 } |
| 1675 if (type.isDynamic) { |
| 1676 return 'dynamic'; |
| 1677 } |
1674 if (type is TypeVariableMirror) { | 1678 if (type is TypeVariableMirror) { |
1675 return type.simpleName; | 1679 return type.simpleName; |
1676 } | 1680 } |
1677 assert(type is ClassMirror); | 1681 assert(type is ClassMirror); |
1678 | 1682 |
1679 // See if it's a generic type. | 1683 // See if it's a generic type. |
1680 if (type.isOriginalDeclaration) { | 1684 if (type.isOriginalDeclaration) { |
1681 final typeParams = []; | 1685 final typeParams = []; |
1682 for (final typeParam in type.originalDeclaration.typeVariables) { | 1686 for (final typeParam in type.originalDeclaration.typeVariables) { |
1683 if (showBounds && | 1687 if (showBounds && |
1684 (typeParam.upperBound != null) && | 1688 (typeParam.upperBound != null) && |
1685 !typeParam.upperBound.isObject) { | 1689 !typeParam.upperBound.isObject) { |
1686 final bound = typeName(typeParam.upperBound, showBounds: true); | 1690 final bound = typeName(typeParam.upperBound, showBounds: true); |
1687 typeParams.add('${typeParam.simpleName} extends $bound'); | 1691 typeParams.add('${typeParam.simpleName} extends $bound'); |
1688 } else { | 1692 } else { |
1689 typeParams.add(typeParam.simpleName); | 1693 typeParams.add(typeParam.simpleName); |
1690 } | 1694 } |
1691 } | 1695 } |
1692 if (typeParams.isEmpty) { | 1696 if (typeParams.isEmpty) { |
1693 return type.simpleName; | 1697 return type.simpleName; |
1694 } | 1698 } |
1695 final params = Strings.join(typeParams, ', '); | 1699 final params = Strings.join(typeParams, ', '); |
1696 return '${type.simpleName}<$params>'; | 1700 return '${type.simpleName}<$params>'; |
1697 } | 1701 } |
1698 | 1702 |
1699 // See if it's an instantiation of a generic type. | 1703 // See if it's an instantiation of a generic type. |
1700 final typeArgs = type.typeArguments; | 1704 final typeArgs = type.typeArguments; |
1701 if (typeArgs.length > 0) { | 1705 if (typeArgs.length > 0) { |
1702 final args = Strings.join(typeArgs.map((arg) => typeName(arg)), ', '); | 1706 final args = |
| 1707 Strings.join(typeArgs.mappedBy((arg) => typeName(arg)), ', '); |
1703 return '${type.originalDeclaration.simpleName}<$args>'; | 1708 return '${type.originalDeclaration.simpleName}<$args>'; |
1704 } | 1709 } |
1705 | 1710 |
1706 // Regular type. | 1711 // Regular type. |
1707 return type.simpleName; | 1712 return type.simpleName; |
1708 } | 1713 } |
1709 | 1714 |
1710 /** | 1715 /** |
1711 * Remove leading indentation to line up with first line. | 1716 * Remove leading indentation to line up with first line. |
1712 */ | 1717 */ |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1880 final ClassMirror inheritedFrom; | 1885 final ClassMirror inheritedFrom; |
1881 | 1886 |
1882 DocComment(this.text, [this.inheritedFrom = null]) { | 1887 DocComment(this.text, [this.inheritedFrom = null]) { |
1883 assert(text != null && !text.trim().isEmpty); | 1888 assert(text != null && !text.trim().isEmpty); |
1884 } | 1889 } |
1885 | 1890 |
1886 String get html => md.markdownToHtml(text); | 1891 String get html => md.markdownToHtml(text); |
1887 | 1892 |
1888 String toString() => text; | 1893 String toString() => text; |
1889 } | 1894 } |
OLD | NEW |