Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: sdk/lib/_internal/dartdoc/lib/dartdoc.dart

Issue 14088002: Attempt to re-commit Dartdoc exports. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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:async';
20 import 'dart:io'; 20 import 'dart:io';
21 import 'dart:isolate';
21 import 'dart:json' as json; 22 import 'dart:json' as json;
22 import 'dart:math'; 23 import 'dart:math';
23 import 'dart:uri'; 24 import 'dart:uri';
24 25
26 import 'package:pathos/path.dart' as pathos;
27
25 import 'classify.dart'; 28 import 'classify.dart';
26 import 'markdown.dart' as md; 29 import 'markdown.dart' as md;
27 import 'universe_serializer.dart'; 30 import 'universe_serializer.dart';
28 31
29 import 'src/dartdoc/nav.dart'; 32 import 'src/dartdoc/nav.dart';
33 import 'src/dartdoc/utils.dart';
34 import 'src/export_map.dart';
30 import 'src/json_serializer.dart' as json_serializer; 35 import 'src/json_serializer.dart' as json_serializer;
31 36
32 // TODO(rnystrom): Use "package:" URL (#4968). 37 // TODO(rnystrom): Use "package:" URL (#4968).
33 import '../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js; 38 import '../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js;
34 import '../../compiler/implementation/mirrors/mirrors.dart'; 39 import '../../compiler/implementation/mirrors/mirrors.dart';
35 import '../../compiler/implementation/mirrors/mirrors_util.dart'; 40 import '../../compiler/implementation/mirrors/mirrors_util.dart';
36 import '../../libraries.dart'; 41 import '../../libraries.dart';
37 42
38 part 'src/dartdoc/utils.dart';
39
40 /** 43 /**
41 * Generates completely static HTML containing everything you need to browse 44 * Generates completely static HTML containing everything you need to browse
42 * the docs. The only client side behavior is trivial stuff like syntax 45 * the docs. The only client side behavior is trivial stuff like syntax
43 * highlighting code. 46 * highlighting code.
44 */ 47 */
45 const MODE_STATIC = 0; 48 const MODE_STATIC = 0;
46 49
47 /** 50 /**
48 * Generated docs do not include baked HTML navigation. Instead, a single 51 * Generated docs do not include baked HTML navigation. Instead, a single
49 * `nav.json` file is created and the appropriate navigation is generated 52 * `nav.json` file is created and the appropriate navigation is generated
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 onDone: () => completer.complete(), 127 onDone: () => completer.complete(),
125 onError: (e) => completer.completeError(e.error, e.stackTrace)); 128 onError: (e) => completer.completeError(e.error, e.stackTrace));
126 return completer.future; 129 return completer.future;
127 } 130 }
128 131
129 /** 132 /**
130 * Compiles the dartdoc client-side code to JavaScript using Dart2js. 133 * Compiles the dartdoc client-side code to JavaScript using Dart2js.
131 */ 134 */
132 Future compileScript(int mode, Path outputDir, Path libPath) { 135 Future compileScript(int mode, Path outputDir, Path libPath) {
133 print('Compiling client JavaScript...'); 136 print('Compiling client JavaScript...');
134 var clientScript = (mode == MODE_STATIC) ? 'static' : 'live-nav';
135 var dartPath = libPath.append(
136 'lib/_internal/dartdoc/lib/src/client/client-$clientScript.dart');
137 var jsPath = outputDir.append('client-$clientScript.js');
138 137
139 return dart2js.compile(dartPath, libPath, 138 // TODO(nweiz): don't run this in an isolate when issue 9815 is fixed.
140 options: const <String>['--categories=Client,Server']) 139 return spawnFunction(_compileScript).call({
141 .then((jsCode) { 140 'mode': mode,
142 writeString(new File.fromPath(jsPath), jsCode); 141 'outputDir': outputDir.toNativePath(),
142 'libPath': libPath.toNativePath()
143 }).then((result) {
144 if (result.first == 'success') return;
145 throw new AsyncError(result[1], result[2]);
146 });
147 }
148
149 void _compileScript() {
150 port.receive((message, replyTo) {
151 new Future.of(() {
152 var clientScript = (message['mode'] == MODE_STATIC) ?
153 'static' : 'live-nav';
154 var dartPath = pathos.join(message['libPath'], 'lib', '_internal',
155 'dartdoc', 'lib', 'src', 'client', 'client-$clientScript.dart');
156 var jsPath = pathos.join(message['outputDir'], 'client-$clientScript.js');
157
158 return dart2js.compile(
159 new Path(dartPath), new Path(message['libPath']),
160 options: const <String>['--categories=Client,Server']).then((jsCode) {
161 writeString(new File(jsPath), jsCode);
162 });
163 }).then((_) {
164 replyTo.send(['success']);
165 }).catchError((e) {
166 replyTo.send(['error', e.error.toString(), e.stackTrace.toString()]);
143 }); 167 });
168 });
144 } 169 }
145 170
146 /** 171 /**
147 * Package manifest containing all information required to render the main page 172 * Package manifest containing all information required to render the main page
148 * for a package. 173 * for a package.
149 * 174 *
150 * The manifest specifies where to load the [LibraryElement]s describing each 175 * The manifest specifies where to load the [LibraryElement]s describing each
151 * library rather than including them directly. 176 * library rather than including them directly.
152 * For our purposes we treat the core Dart libraries as a package. 177 * For our purposes we treat the core Dart libraries as a package.
153 */ 178 */
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 279
255 /** Version of the sdk or package docs are being generated for. */ 280 /** Version of the sdk or package docs are being generated for. */
256 String version; 281 String version;
257 282
258 /** Set this to select the libraries to include in the documentation. */ 283 /** Set this to select the libraries to include in the documentation. */
259 List<String> includedLibraries = const <String>[]; 284 List<String> includedLibraries = const <String>[];
260 285
261 /** Set this to select the libraries to exclude from the documentation. */ 286 /** Set this to select the libraries to exclude from the documentation. */
262 List<String> excludedLibraries = const <String>[]; 287 List<String> excludedLibraries = const <String>[];
263 288
289 /** The package root for `package:` imports. */
290 String _packageRoot;
291
292 /** The map containing all the exports for each library. */
293 ExportMap _exports;
294
264 /** 295 /**
265 * This list contains the libraries sorted in by the library name. 296 * This list contains the libraries sorted in by the library name.
266 */ 297 */
267 List<LibraryMirror> _sortedLibraries; 298 List<LibraryMirror> _sortedLibraries;
268 299
300 /** A map from absolute paths of libraries to the libraries at those paths. */
301 Map<String, LibraryMirror> _librariesByPath;
302
303 /**
304 * A map from absolute paths of hidden libraries to lists of [Export]s that
305 * export those libraries from visible libraries. This is used to determine
306 * what public library any given entity belongs to.
307 *
308 * The lists of exports are sorted so that exports that hide the fewest number
309 * of members come first.
310 */
311 Map<String, List<Export>> _hiddenLibraryExports;
312
269 /** The library that we're currently generating docs for. */ 313 /** The library that we're currently generating docs for. */
270 LibraryMirror _currentLibrary; 314 LibraryMirror _currentLibrary;
271 315
272 /** The type that we're currently generating docs for. */ 316 /** The type that we're currently generating docs for. */
273 ClassMirror _currentType; 317 ClassMirror _currentType;
274 318
275 /** The member that we're currently generating docs for. */ 319 /** The member that we're currently generating docs for. */
276 MemberMirror _currentMember; 320 MemberMirror _currentMember;
277 321
278 /** The path to the file currently being written to, relative to [outdir]. */ 322 /** The path to the file currently being written to, relative to [outdir]. */
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 var content = ''; 440 var content = '';
397 for (int i = 0; i < footerItems.length; i++) { 441 for (int i = 0; i < footerItems.length; i++) {
398 if (i > 0) { 442 if (i > 0) {
399 content += '\n'; 443 content += '\n';
400 } 444 }
401 content += '<div>${footerItems[i]}</div>'; 445 content += '<div>${footerItems[i]}</div>';
402 } 446 }
403 return content; 447 return content;
404 } 448 }
405 449
406 Future documentEntryPoint(Path entrypoint, Path libPath, Path packageRoot) { 450 Future documentLibraries(List<Uri> libraryList, Path libPath,
407 return documentLibraries(<Path>[entrypoint], libPath, packageRoot); 451 String packageRoot) {
408 } 452 _packageRoot = packageRoot;
453 _exports = new ExportMap.parse(libraryList, packageRoot);
454 var librariesToAnalyze = _exports.allExportedFiles.toList();
455 librariesToAnalyze.addAll(libraryList.map((uri) {
456 if (uri.scheme == 'file') return fileUriToPath(uri);
457 // dart2js takes "dart:*" URIs as Path objects for some reason.
458 return uri.toString();
459 }));
409 460
410 Future documentLibraries(List<Path> libraryList, Path libPath, Path packageRoo t) { 461 var packageRootPath = packageRoot == null ? null : new Path(packageRoot);
462
411 // TODO(amouravski): make all of these print statements into logging 463 // TODO(amouravski): make all of these print statements into logging
412 // statements. 464 // statements.
413 print('Analyzing libraries...'); 465 print('Analyzing libraries...');
414 return dart2js.analyze(libraryList, libPath, packageRoot: packageRoot, 466 return dart2js.analyze(
415 options: COMPILER_OPTIONS) 467 librariesToAnalyze.map((path) => new Path(path)).toList(), libPath,
468 packageRoot: packageRootPath, options: COMPILER_OPTIONS)
416 .then((MirrorSystem mirrors) { 469 .then((MirrorSystem mirrors) {
417 print('Generating documentation...'); 470 print('Generating documentation...');
418 _document(mirrors); 471 _document(mirrors);
419 }); 472 });
420 } 473 }
421 474
422 void _document(MirrorSystem mirrors) { 475 void _document(MirrorSystem mirrors) {
423 _started = true; 476 _started = true;
424 477
425 // Sort the libraries by name (not key). 478 // Sort the libraries by name (not key).
426 _sortedLibraries = new List<LibraryMirror>.from( 479 _sortedLibraries = new List<LibraryMirror>.from(
427 mirrors.libraries.values.where(shouldIncludeLibrary)); 480 mirrors.libraries.values.where(shouldIncludeLibrary));
428 _sortedLibraries.sort((x, y) { 481 _sortedLibraries.sort((x, y) {
429 return displayName(x).toUpperCase().compareTo( 482 return displayName(x).toUpperCase().compareTo(
430 displayName(y).toUpperCase()); 483 displayName(y).toUpperCase());
431 }); 484 });
432 485
486 _librariesByPath = <String, LibraryMirror>{};
487 for (var library in mirrors.libraries.values) {
488 var path = _libraryPath(library);
489 if (path == null) continue;
490 path = pathos.normalize(pathos.absolute(path));
491 _librariesByPath[path] = library;
492 }
493
494 _hiddenLibraryExports = _generateHiddenLibraryExports();
495
433 // Generate the docs. 496 // Generate the docs.
434 if (mode == MODE_LIVE_NAV) { 497 if (mode == MODE_LIVE_NAV) {
435 docNavigationJson(); 498 docNavigationJson();
436 } else { 499 } else {
437 docNavigationDart(); 500 docNavigationDart();
438 } 501 }
439 502
440 docIndex(); 503 docIndex();
441 for (final library in _sortedLibraries) { 504 for (final library in _sortedLibraries) {
442 docLibrary(library); 505 docLibrary(library);
443 } 506 }
444 507
445 if (generateAppCache) { 508 if (generateAppCache) {
446 generateAppCacheManifest(); 509 generateAppCacheManifest();
447 } 510 }
448 511
512 // TODO(nweiz): properly handle exports when generating JSON.
449 // TODO(jacobr): handle arbitrary pub packages rather than just the system 513 // TODO(jacobr): handle arbitrary pub packages rather than just the system
450 // libraries. 514 // libraries.
451 var revision = '0'; 515 var revision = '0';
452 if (version != null) { 516 if (version != null) {
453 var match = new RegExp(r"_r(\d+)").firstMatch(version); 517 var match = new RegExp(r"_r(\d+)").firstMatch(version);
454 if (match != null) { 518 if (match != null) {
455 revision = match.group(1); 519 revision = match.group(1);
456 } else { 520 } else {
457 print("Warning: could not parse version: $version"); 521 print("Warning: could not parse version: $version");
458 } 522 }
(...skipping 18 matching lines...) Expand all
477 // Write out top level json file with a relative path to the library json 541 // Write out top level json file with a relative path to the library json
478 // files. 542 // files.
479 startFile("apidoc.json"); 543 startFile("apidoc.json");
480 packageManifest.location = revision; 544 packageManifest.location = revision;
481 write(json_serializer.serialize(packageManifest)); 545 write(json_serializer.serialize(packageManifest));
482 endFile(); 546 endFile();
483 547
484 _finished = true; 548 _finished = true;
485 } 549 }
486 550
551 /**
552 * Generate [_hiddenLibraryExports] from [_exports] and [_librariesByPath].
553 */
554 Map<String, List<Export>> _generateHiddenLibraryExports() {
555 // First generate a map `exported path => exporter path => Export`. The
556 // inner map makes it easier to merge multiple exports of the same library
557 // by the same exporter.
558 var hiddenLibraryExportMaps = <String, Map<String, Export>>{};
559 _exports.exports.forEach((exporter, exports) {
560 var library = _librariesByPath[exporter];
561 // TODO(nweiz): remove this check when issue 9645 is fixed.
562 if (library == null) return;
563 if (!shouldIncludeLibrary(library)) return;
564 for (var export in exports) {
565 var library = _librariesByPath[export.path];
566 // TODO(nweiz): remove this check when issue 9645 is fixed.
567 if (library == null) continue;
568 if (shouldIncludeLibrary(library)) continue;
569
570 var hiddenExports = _exports.transitiveExports(export.path)
571 .map((transitiveExport) => export.compose(transitiveExport))
572 .toList();
573 hiddenExports.add(export);
574
575 for (var hiddenExport in hiddenExports) {
576 var exportsByExporterPath = hiddenLibraryExportMaps
577 .putIfAbsent(hiddenExport.path, () => <String, Export>{});
578 addOrMergeExport(exportsByExporterPath, exporter, hiddenExport);
579 }
580 }
581 });
582
583 // Now sort the values of the inner maps of `hiddenLibraryExportMaps` to get
584 // the final value of `_hiddenLibraryExports`.
585 var hiddenLibraryExports = <String, List<Export>>{};
586 hiddenLibraryExportMaps.forEach((exporteePath, exportsByExporterPath) {
587 int rank(Export export) {
588 if (export.show.isEmpty && export.hide.isEmpty) return 0;
589 if (export.show.isEmpty) return export.hide.length;
590 // Multiply by 1000 to ensure this sorts after an export with hides.
591 return 1000 * export.show.length;
592 }
593
594 var exports = exportsByExporterPath.values.toList();
595 exports.sort((export1, export2) {
596 var comparison = Comparable.compare(rank(export1), rank(export2));
597 if (comparison != 0) return comparison;
598
599 var library1 = _librariesByPath[export1.exporter];
600 var library2 = _librariesByPath[export2.exporter];
601 return Comparable.compare(library1.displayName, library2.displayName);
602 });
603 hiddenLibraryExports[exporteePath] = exports;
604 });
605 return hiddenLibraryExports;
606 }
607
487 MdnComment lookupMdnComment(Mirror mirror) => null; 608 MdnComment lookupMdnComment(Mirror mirror) => null;
488 609
489 void startFile(String path) { 610 void startFile(String path) {
490 _filePath = new Path(path); 611 _filePath = new Path(path);
491 _file = new StringBuffer(); 612 _file = new StringBuffer();
492 } 613 }
493 614
494 void endFile() { 615 void endFile() {
495 final outPath = outputDir.join(_filePath); 616 final outPath = outputDir.join(_filePath);
496 final dir = new Directory.fromPath(outPath.directoryPath); 617 final dir = new Directory.fromPath(outPath.directoryPath);
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after
861 writeHeader('${displayName(library)} Library', 982 writeHeader('${displayName(library)} Library',
862 [displayName(library), libraryUrl(library)]); 983 [displayName(library), libraryUrl(library)]);
863 writeln('<h2><strong>${displayName(library)}</strong> library</h2>'); 984 writeln('<h2><strong>${displayName(library)}</strong> library</h2>');
864 985
865 // Look for a comment for the entire library. 986 // Look for a comment for the entire library.
866 final comment = getLibraryComment(library); 987 final comment = getLibraryComment(library);
867 if (comment != null) { 988 if (comment != null) {
868 writeln('<div class="doc">${comment.html}</div>'); 989 writeln('<div class="doc">${comment.html}</div>');
869 } 990 }
870 991
992 // Document the visible libraries exported by this library.
993 docExports(library);
994
871 // Document the top-level members. 995 // Document the top-level members.
872 docMembers(library); 996 docMembers(library);
873 997
874 // Document the types. 998 // Document the types.
875 final interfaces = <ClassMirror>[]; 999 final interfaces = <ClassMirror>[];
876 final abstractClasses = <ClassMirror>[]; 1000 final abstractClasses = <ClassMirror>[];
877 final classes = <ClassMirror>[]; 1001 final classes = <ClassMirror>[];
878 final typedefs = <TypedefMirror>[]; 1002 final typedefs = <TypedefMirror>[];
879 final exceptions = <ClassMirror>[]; 1003 final exceptions = <ClassMirror>[];
880 1004
881 for (ClassMirror type in orderByName(library.classes.values)) { 1005 var allClasses = _libraryClasses(library);
1006 for (ClassMirror type in orderByName(allClasses)) {
882 if (!showPrivate && type.isPrivate) continue; 1007 if (!showPrivate && type.isPrivate) continue;
883 1008
884 if (isException(type)) { 1009 if (isException(type)) {
885 exceptions.add(type); 1010 exceptions.add(type);
886 } else if (type.isClass) { 1011 } else if (type.isClass) {
887 if (type.isAbstract) { 1012 if (type.isAbstract) {
888 abstractClasses.add(type); 1013 abstractClasses.add(type);
889 } else { 1014 } else {
890 classes.add(type); 1015 classes.add(type);
891 } 1016 }
892 } else if (type.isInterface){ 1017 } else if (type.isInterface){
893 interfaces.add(type); 1018 interfaces.add(type);
894 } else if (type is TypedefMirror) { 1019 } else if (type is TypedefMirror) {
895 typedefs.add(type); 1020 typedefs.add(type);
896 } else { 1021 } else {
897 throw new InternalError("internal error: unknown type $type."); 1022 throw new InternalError("internal error: unknown type $type.");
898 } 1023 }
899 } 1024 }
900 1025
901 docTypes(interfaces, 'Interfaces'); 1026 docTypes(interfaces, 'Interfaces');
902 docTypes(abstractClasses, 'Abstract Classes'); 1027 docTypes(abstractClasses, 'Abstract Classes');
903 docTypes(classes, 'Classes'); 1028 docTypes(classes, 'Classes');
904 docTypes(typedefs, 'Typedefs'); 1029 docTypes(typedefs, 'Typedefs');
905 docTypes(exceptions, 'Exceptions'); 1030 docTypes(exceptions, 'Exceptions');
906 1031
907 writeFooter(); 1032 writeFooter();
908 endFile(); 1033 endFile();
909 1034
910 for (final type in library.classes.values) { 1035 for (final type in allClasses) {
911 if (!showPrivate && type.isPrivate) continue; 1036 if (!showPrivate && type.isPrivate) continue;
912 1037
913 docType(type); 1038 docType(type);
914 } 1039 }
915 } 1040 }
916 1041
917 void docTypes(List types, String header) { 1042 void docTypes(List types, String header) {
918 if (types.length == 0) return; 1043 if (types.length == 0) return;
919 1044
920 writeln('<div>'); 1045 writeln('<div>');
(...skipping 27 matching lines...) Expand all
948 } else if (type.isClass) { 1073 } else if (type.isClass) {
949 if (type.isAbstract) { 1074 if (type.isAbstract) {
950 kind = 'abstract class'; 1075 kind = 'abstract class';
951 } else { 1076 } else {
952 kind = 'class'; 1077 kind = 'class';
953 } 1078 }
954 } 1079 }
955 1080
956 final typeTitle = 1081 final typeTitle =
957 '${typeName(type)} ${kind}'; 1082 '${typeName(type)} ${kind}';
958 writeHeader('$typeTitle / ${displayName(type.library)} Library', 1083 var library = _libraryFor(type);
959 [displayName(type.library), libraryUrl(type.library), 1084 writeHeader('$typeTitle / ${displayName(library)} Library',
1085 [displayName(library), libraryUrl(library),
960 typeName(type), typeUrl(type)]); 1086 typeName(type), typeUrl(type)]);
961 writeln( 1087 writeln(
962 ''' 1088 '''
963 <h2><strong>${typeName(type, showBounds: true)}</strong> 1089 <h2><strong>${typeName(type, showBounds: true)}</strong>
964 $kind 1090 $kind
965 </h2> 1091 </h2>
966 '''); 1092 ''');
967 writeln('<button id="show-inherited" class="show-inherited">' 1093 writeln('<button id="show-inherited" class="show-inherited">'
968 'Hide inherited</button>'); 1094 'Hide inherited</button>');
969 1095
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1141 1267
1142 static final Map<String, int> operatorOrderMap = (){ 1268 static final Map<String, int> operatorOrderMap = (){
1143 var map = new Map<String, int>(); 1269 var map = new Map<String, int>();
1144 var index = 0; 1270 var index = 0;
1145 for (String operator in operatorOrder) { 1271 for (String operator in operatorOrder) {
1146 map[operator] = index++; 1272 map[operator] = index++;
1147 } 1273 }
1148 return map; 1274 return map;
1149 }(); 1275 }();
1150 1276
1277 void docExports(LibraryMirror library) {
1278 // TODO(nweiz): show `dart:` library exports.
1279 var exportLinks = _exports.transitiveExports(_libraryPath(library))
1280 .map((export) {
1281 var library = _librariesByPath[export.path];
1282 // TODO(nweiz): remove this check when issue 9645 is fixed.
1283 if (library == null) return null;
1284 // Only link to publically visible libraries.
1285 if (!shouldIncludeLibrary(library)) return null;
1286
1287 var memberNames = export.show.isEmpty ? export.hide : export.show;
1288 var memberLinks = memberNames.map((name) {
1289 return md.renderToHtml([resolveNameReference(
1290 name, currentLibrary: library)]);
1291 }).join(', ');
1292 var combinator = '';
1293 if (!export.show.isEmpty) {
1294 combinator = ' show $memberLinks';
1295 } else if (!export.hide.isEmpty) {
1296 combinator = ' hide $memberLinks';
1297 }
1298
1299 return '<ul>${a(libraryUrl(library), displayName(library))}'
1300 '$combinator</ul>';
1301 }).where((link) => link != null);
1302
1303 if (!exportLinks.isEmpty) {
1304 writeln('<h3>Exports</h3>');
1305 writeln('<ul>');
1306 writeln(exportLinks.join('\n'));
1307 writeln('</ul>');
1308 }
1309 }
1310
1151 void docMembers(ContainerMirror host) { 1311 void docMembers(ContainerMirror host) {
1152 // Collect the different kinds of members. 1312 // Collect the different kinds of members.
1153 final staticMethods = []; 1313 final staticMethods = [];
1154 final staticGetters = new Map<String,MemberMirror>(); 1314 final staticGetters = new Map<String,MemberMirror>();
1155 final staticSetters = new Map<String,MemberMirror>(); 1315 final staticSetters = new Map<String,MemberMirror>();
1156 final memberMap = new Map<String,MemberMirror>(); 1316 final memberMap = new Map<String,MemberMirror>();
1157 final instanceMethods = []; 1317 final instanceMethods = [];
1158 final instanceOperators = []; 1318 final instanceOperators = [];
1159 final instanceGetters = new Map<String,MemberMirror>(); 1319 final instanceGetters = new Map<String,MemberMirror>();
1160 final instanceSetters = new Map<String,MemberMirror>(); 1320 final instanceSetters = new Map<String,MemberMirror>();
1161 final constructors = []; 1321 final constructors = [];
1162 1322
1163 host.members.forEach((_, MemberMirror member) { 1323 var hostMembers = host is LibraryMirror ?
1164 if (!showPrivate && member.isPrivate) return; 1324 _libraryMembers(host) : host.members.values;
1325 for (var member in hostMembers) {
1326 if (!showPrivate && member.isPrivate) continue;
1165 if (host is LibraryMirror || member.isStatic) { 1327 if (host is LibraryMirror || member.isStatic) {
1166 if (member is MethodMirror) { 1328 if (member is MethodMirror) {
1167 if (member.isGetter) { 1329 if (member.isGetter) {
1168 staticGetters[member.displayName] = member; 1330 staticGetters[member.displayName] = member;
1169 } else if (member.isSetter) { 1331 } else if (member.isSetter) {
1170 staticSetters[member.displayName] = member; 1332 staticSetters[member.displayName] = member;
1171 } else { 1333 } else {
1172 staticMethods.add(member); 1334 staticMethods.add(member);
1173 } 1335 }
1174 } else if (member is VariableMirror) { 1336 } else if (member is VariableMirror) {
1175 staticGetters[member.displayName] = member; 1337 staticGetters[member.displayName] = member;
1176 } 1338 }
1177 } 1339 }
1178 }); 1340 }
1179 1341
1180 if (host is ClassMirror) { 1342 if (host is ClassMirror) {
1181 var iterable = new HierarchyIterable(host, includeType: true); 1343 var iterable = new HierarchyIterable(host, includeType: true);
1182 for (ClassMirror type in iterable) { 1344 for (ClassMirror type in iterable) {
1183 if (!host.isObject && !inheritFromObject && type.isObject) continue; 1345 if (!host.isObject && !inheritFromObject && type.isObject) continue;
1184 1346
1185 type.members.forEach((_, MemberMirror member) { 1347 type.members.forEach((_, MemberMirror member) {
1186 if (member.isStatic) return; 1348 if (member.isStatic) return;
1187 if (!showPrivate && member.isPrivate) return; 1349 if (!showPrivate && member.isPrivate) return;
1188 1350
(...skipping 23 matching lines...) Expand all
1212 } 1374 }
1213 } 1375 }
1214 1376
1215 bool allMethodsInherited = true; 1377 bool allMethodsInherited = true;
1216 bool allPropertiesInherited = true; 1378 bool allPropertiesInherited = true;
1217 bool allOperatorsInherited = true; 1379 bool allOperatorsInherited = true;
1218 memberMap.forEach((_, MemberMirror member) { 1380 memberMap.forEach((_, MemberMirror member) {
1219 if (member is MethodMirror) { 1381 if (member is MethodMirror) {
1220 if (member.isGetter) { 1382 if (member.isGetter) {
1221 instanceGetters[member.displayName] = member; 1383 instanceGetters[member.displayName] = member;
1222 if (member.owner == host) { 1384 if (_ownerFor(member) == host) {
1223 allPropertiesInherited = false; 1385 allPropertiesInherited = false;
1224 } 1386 }
1225 } else if (member.isSetter) { 1387 } else if (member.isSetter) {
1226 instanceSetters[member.displayName] = member; 1388 instanceSetters[member.displayName] = member;
1227 if (member.owner == host) { 1389 if (_ownerFor(member) == host) {
1228 allPropertiesInherited = false; 1390 allPropertiesInherited = false;
1229 } 1391 }
1230 } else if (member.isOperator) { 1392 } else if (member.isOperator) {
1231 instanceOperators.add(member); 1393 instanceOperators.add(member);
1232 if (member.owner == host) { 1394 if (_ownerFor(member) == host) {
1233 allOperatorsInherited = false; 1395 allOperatorsInherited = false;
1234 } 1396 }
1235 } else { 1397 } else {
1236 instanceMethods.add(member); 1398 instanceMethods.add(member);
1237 if (member.owner == host) { 1399 if (_ownerFor(member) == host) {
1238 allMethodsInherited = false; 1400 allMethodsInherited = false;
1239 } 1401 }
1240 } 1402 }
1241 } else if (member is VariableMirror) { 1403 } else if (member is VariableMirror) {
1242 instanceGetters[member.displayName] = member; 1404 instanceGetters[member.displayName] = member;
1243 if (member.owner == host) { 1405 if (_ownerFor(member) == host) {
1244 allPropertiesInherited = false; 1406 allPropertiesInherited = false;
1245 } 1407 }
1246 } 1408 }
1247 }); 1409 });
1248 1410
1249 instanceOperators.sort((MethodMirror a, MethodMirror b) { 1411 instanceOperators.sort((MethodMirror a, MethodMirror b) {
1250 return operatorOrderMap[a.simpleName].compareTo( 1412 return operatorOrderMap[a.simpleName].compareTo(
1251 operatorOrderMap[b.simpleName]); 1413 operatorOrderMap[b.simpleName]);
1252 }); 1414 });
1253 1415
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1298 assert(getter is MethodMirror); 1460 assert(getter is MethodMirror);
1299 docProperty(host, getter, null); 1461 docProperty(host, getter, null);
1300 } 1462 }
1301 } else if (getter == null) { 1463 } else if (getter == null) {
1302 // We only have a setter => Document as a method. 1464 // We only have a setter => Document as a method.
1303 assert(setter is MethodMirror); 1465 assert(setter is MethodMirror);
1304 docMethod(host, setter); 1466 docMethod(host, setter);
1305 } else { 1467 } else {
1306 DocComment getterComment = getMemberComment(getter); 1468 DocComment getterComment = getMemberComment(getter);
1307 DocComment setterComment = getMemberComment(setter); 1469 DocComment setterComment = getMemberComment(setter);
1308 if (getter.owner != setter.owner || 1470 if (_ownerFor(getter) != _ownerFor(setter) ||
1309 getterComment != null && setterComment != null) { 1471 getterComment != null && setterComment != null) {
1310 // Both have comments or are not declared in the same class 1472 // Both have comments or are not declared in the same class
1311 // => Documents separately. 1473 // => Documents separately.
1312 if (getter is VariableMirror) { 1474 if (getter is VariableMirror) {
1313 // Document field as a getter (setter is inherited). 1475 // Document field as a getter (setter is inherited).
1314 docField(host, getter, asGetter: true); 1476 docField(host, getter, asGetter: true);
1315 } else { 1477 } else {
1316 docMethod(host, getter); 1478 docMethod(host, getter);
1317 } 1479 }
1318 if (setter is VariableMirror) { 1480 if (setter is VariableMirror) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1369 if (member.isGetter) { 1531 if (member.isGetter) {
1370 // Getter. 1532 // Getter.
1371 name = 'get $name'; 1533 name = 'get $name';
1372 } else if (member.isSetter) { 1534 } else if (member.isSetter) {
1373 // Setter. 1535 // Setter.
1374 name = 'set $name'; 1536 name = 'set $name';
1375 } 1537 }
1376 } 1538 }
1377 1539
1378 bool showCode = includeSource && !isAbstract; 1540 bool showCode = includeSource && !isAbstract;
1379 bool inherited = host != member.owner; 1541 bool inherited = host != member.owner && member.owner is! LibraryMirror;
1380 1542
1381 writeln('<div class="method${inherited ? ' inherited': ''}">' 1543 writeln('<div class="method${inherited ? ' inherited': ''}">'
1382 '<h4 id="${memberAnchor(member)}">'); 1544 '<h4 id="${memberAnchor(member)}">');
1383 1545
1384 if (showCode) { 1546 if (showCode) {
1385 writeln('<button class="show-code">Code</button>'); 1547 writeln('<button class="show-code">Code</button>');
1386 } 1548 }
1387 1549
1388 if (member is MethodMirror) { 1550 if (member is MethodMirror) {
1389 if (member.isConstructor) { 1551 if (member.isConstructor) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1460 * [host]. If [getter] is a [FieldMirror], [setter] must be [:null:]. 1622 * [host]. If [getter] is a [FieldMirror], [setter] must be [:null:].
1461 * Otherwise, if [getter] is a [MethodMirror], the property is considered 1623 * Otherwise, if [getter] is a [MethodMirror], the property is considered
1462 * final if [setter] is [:null:]. 1624 * final if [setter] is [:null:].
1463 */ 1625 */
1464 void docProperty(ContainerMirror host, 1626 void docProperty(ContainerMirror host,
1465 MemberMirror getter, MemberMirror setter) { 1627 MemberMirror getter, MemberMirror setter) {
1466 assert(getter != null); 1628 assert(getter != null);
1467 _totalMembers++; 1629 _totalMembers++;
1468 _currentMember = getter; 1630 _currentMember = getter;
1469 1631
1470 bool inherited = host != getter.owner; 1632 bool inherited = host != getter.owner && getter.owner is! LibraryMirror;
1471 1633
1472 writeln('<div class="field${inherited ? ' inherited' : ''}">' 1634 writeln('<div class="field${inherited ? ' inherited' : ''}">'
1473 '<h4 id="${memberAnchor(getter)}">'); 1635 '<h4 id="${memberAnchor(getter)}">');
1474 1636
1475 if (includeSource) { 1637 if (includeSource) {
1476 writeln('<button class="show-code">Code</button>'); 1638 writeln('<button class="show-code">Code</button>');
1477 } 1639 }
1478 1640
1479 bool isConst = false; 1641 bool isConst = false;
1480 bool isFinal; 1642 bool isFinal;
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
1667 String typeUrl(ContainerMirror type) { 1829 String typeUrl(ContainerMirror type) {
1668 if (type is LibraryMirror) { 1830 if (type is LibraryMirror) {
1669 return '${sanitize(type.simpleName)}.html'; 1831 return '${sanitize(type.simpleName)}.html';
1670 } 1832 }
1671 if (type.library == null) { 1833 if (type.library == null) {
1672 return ''; 1834 return '';
1673 } 1835 }
1674 // Always get the generic type to strip off any type parameters or 1836 // Always get the generic type to strip off any type parameters or
1675 // arguments. If the type isn't generic, genericType returns `this`, so it 1837 // arguments. If the type isn't generic, genericType returns `this`, so it
1676 // works for non-generic types too. 1838 // works for non-generic types too.
1677 return '${sanitize(displayName(type.library))}/' 1839 return '${sanitize(displayName(_libraryFor(type)))}/'
1678 '${type.originalDeclaration.simpleName}.html'; 1840 '${type.originalDeclaration.simpleName}.html';
1679 } 1841 }
1680 1842
1681 /** Gets the URL for the documentation for [member]. */ 1843 /** Gets the URL for the documentation for [member]. */
1682 String memberUrl(MemberMirror member) { 1844 String memberUrl(MemberMirror member) {
1683 String url = typeUrl(member.owner); 1845 String url = typeUrl(_ownerFor(member));
1684 return '$url#${memberAnchor(member)}'; 1846 return '$url#${memberAnchor(member)}';
1685 } 1847 }
1686 1848
1687 /** Gets the anchor id for the document for [member]. */ 1849 /** Gets the anchor id for the document for [member]. */
1688 String memberAnchor(MemberMirror member) { 1850 String memberAnchor(MemberMirror member) {
1689 return member.simpleName; 1851 return member.simpleName;
1690 } 1852 }
1691 1853
1692 /** 1854 /**
1693 * Creates a hyperlink. Handles turning the [href] into an appropriate 1855 * Creates a hyperlink. Handles turning the [href] into an appropriate
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1752 if (type.isTypeVariable) { 1914 if (type.isTypeVariable) {
1753 // If we're using a type parameter within the body of a generic class then 1915 // If we're using a type parameter within the body of a generic class then
1754 // just link back up to the class. 1916 // just link back up to the class.
1755 write(a(typeUrl(enclosingType), type.simpleName)); 1917 write(a(typeUrl(enclosingType), type.simpleName));
1756 return; 1918 return;
1757 } 1919 }
1758 1920
1759 assert(type is ClassMirror); 1921 assert(type is ClassMirror);
1760 1922
1761 // Link to the type. 1923 // Link to the type.
1762 if (shouldLinkToPublicApi(type.library)) { 1924 var library = _libraryFor(type);
1925 if (shouldLinkToPublicApi(library)) {
1763 write('<a href="$API_LOCATION${typeUrl(type)}">${type.simpleName}</a>'); 1926 write('<a href="$API_LOCATION${typeUrl(type)}">${type.simpleName}</a>');
1764 } else if (shouldIncludeLibrary(type.library)) { 1927 } else if (shouldIncludeLibrary(library)) {
1765 write(a(typeUrl(type), type.simpleName)); 1928 write(a(typeUrl(type), type.simpleName));
1766 } else { 1929 } else {
1767 write(type.simpleName); 1930 write(type.simpleName);
1768 } 1931 }
1769 1932
1770 if (type.isOriginalDeclaration) { 1933 if (type.isOriginalDeclaration) {
1771 // Avoid calling [:typeArguments():] on a declaration. 1934 // Avoid calling [:typeArguments():] on a declaration.
1772 return; 1935 return;
1773 } 1936 }
1774 1937
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
1972 onDone: () => endFile()); 2135 onDone: () => endFile());
1973 } 2136 }
1974 2137
1975 /** 2138 /**
1976 * Returns [:true:] if [type] should be regarded as an exception. 2139 * Returns [:true:] if [type] should be regarded as an exception.
1977 */ 2140 */
1978 bool isException(TypeMirror type) { 2141 bool isException(TypeMirror type) {
1979 return type.simpleName.endsWith('Exception') || 2142 return type.simpleName.endsWith('Exception') ||
1980 type.simpleName.endsWith('Error'); 2143 type.simpleName.endsWith('Error');
1981 } 2144 }
2145
2146 /**
2147 * Returns the absolute path to [library] on the filesystem, or `null` if the
2148 * library doesn't exist on the local filesystem.
2149 */
2150 String _libraryPath(LibraryMirror library) =>
2151 importUriToPath(library.uri, packageRoot: _packageRoot);
2152
2153 /**
2154 * Returns a list of classes in [library], including classes it exports from
2155 * hidden libraries.
2156 */
2157 List<ClassMirror> _libraryClasses(LibraryMirror library) =>
2158 _libraryContents(library, (lib) => lib.classes.values);
2159
2160 /**
2161 * Returns a list of top-level members in [library], including members it
2162 * exports from hidden libraries.
2163 */
2164 List<MemberMirror> _libraryMembers(LibraryMirror library) =>
2165 _libraryContents(library, (lib) => lib.members.values);
2166
2167
2168 /**
2169 * Returns a list of elements in [library], including elements it exports from
2170 * hidden libraries. [fn] should return the element list for a single library,
2171 * which will then be merged across all exported libraries.
2172 */
2173 List<DeclarationMirror> _libraryContents(LibraryMirror library,
2174 List<DeclarationMirror> fn(LibraryMirror)) {
2175 var contents = fn(library).toList();
2176 var path = _libraryPath(library);
2177 if (path == null || _exports.exports[path] == null) return contents;
2178
2179
2180 contents.addAll(_exports.exports[path].expand((export) {
2181 var exportedLibrary = _librariesByPath[export.path];
2182 // TODO(nweiz): remove this check when issue 9645 is fixed.
2183 if (exportedLibrary == null) return [];
2184 if (shouldIncludeLibrary(exportedLibrary)) return [];
2185 return fn(exportedLibrary).where((declaration) =>
2186 export.isMemberVisible(declaration.displayName));
2187 }));
2188 return contents;
2189 }
2190
2191 /**
2192 * Returns the library in which [type] was defined. If [type] was defined in a
2193 * hidden library that was exported by another library, this returns the
2194 * exporter.
2195 */
2196 LibraryMirror _libraryFor(TypeMirror type) =>
2197 _visibleLibrary(type.library, type.displayName);
2198
2199 /**
2200 * Returns the owner of [declaration]. If [declaration]'s owner is a hidden
2201 * library that was exported by another library, this returns the exporter.
2202 */
2203 DeclarationMirror _ownerFor(DeclarationMirror declaration) {
2204 var owner = declaration.owner;
2205 if (owner is! LibraryMirror) return owner;
2206 return _visibleLibrary(owner, declaration.displayName);
2207 }
2208
2209 /**
2210 * Returns the best visible library that exports [name] from [library]. If
2211 * [library] is public, it will be returned.
2212 */
2213 LibraryMirror _visibleLibrary(LibraryMirror library, String name) {
2214 if (library == null) return null;
2215
2216 var exports = _hiddenLibraryExports[_libraryPath(library)];
2217 if (exports == null) return library;
2218
2219 var export = exports.firstWhere(
2220 (exp) => exp.isMemberVisible(name),
2221 orElse: () => null);
2222 if (export == null) return library;
2223 return _librariesByPath[export.exporter];
2224 }
1982 } 2225 }
1983 2226
1984 /** 2227 /**
1985 * Used to report an unexpected error in the DartDoc tool or the 2228 * Used to report an unexpected error in the DartDoc tool or the
1986 * underlying data 2229 * underlying data
1987 */ 2230 */
1988 class InternalError { 2231 class InternalError {
1989 final String message; 2232 final String message;
1990 const InternalError(this.message); 2233 const InternalError(this.message);
1991 String toString() => "InternalError: '$message'"; 2234 String toString() => "InternalError: '$message'";
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
2069 return ''' 2312 return '''
2070 <div class="mdn"> 2313 <div class="mdn">
2071 $mdnComment 2314 $mdnComment
2072 <div class="mdn-note"><a href="$mdnUrl">from MDN</a></div> 2315 <div class="mdn-note"><a href="$mdnUrl">from MDN</a></div>
2073 </div> 2316 </div>
2074 '''; 2317 ''';
2075 } 2318 }
2076 2319
2077 String toString() => mdnComment; 2320 String toString() => mdnComment;
2078 } 2321 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/dartdoc/bin/dartdoc.dart ('k') | sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698