mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 15:21:54 +00:00
Revert "Revert "Attempt to re-commit Dartdoc exports.""
This reverts commit 1340ca938883c2810fbc4e6d4ed4c52b68694faf. Review URL: https://codereview.chromium.org//14194003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@21320 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
f9bc3af4b9
commit
f9e2907a23
|
@ -23,4 +23,4 @@ if test -f "$BIN_DIR/../lib/_internal/dartdoc/bin/dartdoc.dart.snapshot"; then
|
|||
echo Using snapshot "$BIN_DIR/../lib/_internal/dartdoc/bin/dartdoc.dart.snapshot" 1>&2
|
||||
SNAPSHOT="--use-script-snapshot=$BIN_DIR/../lib/_internal/dartdoc/bin/dartdoc.dart.snapshot"
|
||||
fi
|
||||
exec "$BIN_DIR"/dart --heap_growth_rate=32 "--package-root=$BIN_DIR/../packages/" $SNAPSHOT "$BIN_DIR/../lib/_internal/dartdoc/bin/dartdoc.dart" $COLORS "$@"
|
||||
exec "$BIN_DIR"/dart --heap_growth_rate=32 "--package-root=$BIN_DIR/../packages/" $SNAPSHOT "$BIN_DIR/../lib/_internal/dartdoc/bin/dartdoc.dart" "--package-root=$BIN_DIR/../packages/" $COLORS "$@"
|
||||
|
|
|
@ -18,9 +18,11 @@ library dartdoc;
|
|||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:uri';
|
||||
|
||||
// TODO(rnystrom): Use "package:" URL (#4968).
|
||||
import '../lib/dartdoc.dart';
|
||||
import '../lib/src/dartdoc/utils.dart';
|
||||
import 'package:args/args.dart';
|
||||
import 'package:pathos/path.dart' as path;
|
||||
|
||||
|
@ -39,7 +41,7 @@ main() {
|
|||
|
||||
final Path libPath = scriptDir.append('../../../../');
|
||||
|
||||
Path packageRoot;
|
||||
String packageRoot;
|
||||
|
||||
argParser.addFlag('no-code',
|
||||
help: 'Do not include source code in the documentation.',
|
||||
|
@ -166,7 +168,7 @@ main() {
|
|||
' the entrypoint.',
|
||||
callback: (packageDir) {
|
||||
if(packageDir != null) {
|
||||
packageRoot = new Path(packageDir);
|
||||
packageRoot = packageDir;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -175,7 +177,7 @@ main() {
|
|||
help: 'Deprecated: same as --package-root.',
|
||||
callback: (packageDir) {
|
||||
if(packageDir != null) {
|
||||
packageRoot = new Path(packageDir);
|
||||
packageRoot = packageDir;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -188,21 +190,22 @@ main() {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
final entrypoints = <Path>[];
|
||||
final entrypoints = <Uri>[];
|
||||
try {
|
||||
final option = argParser.parse(args);
|
||||
|
||||
// This checks to see if the root of all entrypoints is the same.
|
||||
// If it is not, then we display a warning, as package imports might fail.
|
||||
var entrypointRoot;
|
||||
for(final arg in option.rest) {
|
||||
var entrypoint = new Path(arg);
|
||||
entrypoints.add(entrypoint);
|
||||
for (final entrypoint in option.rest) {
|
||||
var uri = Uri.parse(entrypoint);
|
||||
if (uri.scheme == '') uri = pathToFileUri(entrypoint);
|
||||
entrypoints.add(uri);
|
||||
|
||||
if (uri.scheme != 'file') continue;
|
||||
if (entrypointRoot == null) {
|
||||
entrypointRoot = entrypoint.directoryPath;
|
||||
} else if (entrypointRoot.toNativePath() !=
|
||||
entrypoint.directoryPath.toNativePath()) {
|
||||
entrypointRoot = path.dirname(entrypoint);
|
||||
} else if (entrypointRoot != path.dirname(entrypoint)) {
|
||||
print('Warning: entrypoints are at different directories. "package:"'
|
||||
' imports may fail.');
|
||||
}
|
||||
|
@ -220,40 +223,18 @@ main() {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (packageRoot == null) {
|
||||
// Check if there's a `packages` directory in the entry point directory.
|
||||
var script = path.normalize(path.absolute(entrypoints[0].toNativePath()));
|
||||
var dir = path.join(path.dirname(script), 'packages/');
|
||||
if (new Directory(dir).existsSync()) {
|
||||
// TODO(amouravski): convert all of dartdoc to use pathos.
|
||||
packageRoot = new Path(dir);
|
||||
} else {
|
||||
// If there is not, then check if the entrypoint is somewhere in a `lib`
|
||||
// directory.
|
||||
dir = path.dirname(script);
|
||||
var parts = path.split(dir);
|
||||
var libDir = parts.lastIndexOf('lib');
|
||||
if (libDir > 0) {
|
||||
packageRoot = new Path(path.join(path.joinAll(parts.take(libDir)),
|
||||
'packages'));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packageRoot == null) packageRoot = _getPackageRoot(entrypoints);
|
||||
|
||||
cleanOutputDirectory(dartdoc.outputDir);
|
||||
|
||||
// Start the analysis and documentation.
|
||||
dartdoc.documentLibraries(entrypoints, libPath, packageRoot)
|
||||
.then((_) {
|
||||
print('Copying static files...');
|
||||
Future.wait([
|
||||
// Prepare the dart2js script code and copy static resources.
|
||||
// TODO(amouravski): move compileScript out and pre-generate the client
|
||||
// scripts. This takes a long time and the js hardly ever changes.
|
||||
compileScript(dartdoc.mode, dartdoc.outputDir, libPath),
|
||||
copyDirectory(scriptDir.append('../static'), dartdoc.outputDir)
|
||||
]);
|
||||
})
|
||||
// Prepare the dart2js script code and copy static resources.
|
||||
// TODO(amouravski): move compileScript out and pre-generate the client
|
||||
// scripts. This takes a long time and the js hardly ever changes.
|
||||
.then((_) => compileScript(dartdoc.mode, dartdoc.outputDir, libPath))
|
||||
.then((_) => copyDirectory(scriptDir.append('../static'),
|
||||
dartdoc.outputDir))
|
||||
.then((_) {
|
||||
print(dartdoc.status);
|
||||
if (dartdoc.totals == 0) {
|
||||
|
@ -267,3 +248,25 @@ main() {
|
|||
})
|
||||
.whenComplete(() => dartdoc.cleanup());
|
||||
}
|
||||
|
||||
String _getPackageRoot(List<Uri> entrypoints) {
|
||||
// Check if there's a `packages` directory in the entry point directory.
|
||||
var fileEntrypoint = entrypoints.firstWhere(
|
||||
(entrypoint) => entrypoint.scheme == 'file',
|
||||
orElse: () => null);
|
||||
if (fileEntrypoint == null) return;
|
||||
|
||||
var script = path.normalize(path.absolute(fileUriToPath(fileEntrypoint)));
|
||||
var dir = path.join(path.dirname(script), 'packages/');
|
||||
if (new Directory(dir).existsSync()) return dir;
|
||||
|
||||
// If there is not, then check if the entrypoint is somewhere in a `lib`
|
||||
// directory.
|
||||
var parts = path.split(path.dirname(script));
|
||||
var libDir = parts.lastIndexOf('lib');
|
||||
if (libDir > 0) {
|
||||
return path.join(path.joinAll(parts.take(libDir)), 'packages');
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,20 @@ library dartdoc;
|
|||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'dart:json' as json;
|
||||
import 'dart:math';
|
||||
import 'dart:uri';
|
||||
|
||||
import 'package:pathos/path.dart' as pathos;
|
||||
|
||||
import 'classify.dart';
|
||||
import 'markdown.dart' as md;
|
||||
import 'universe_serializer.dart';
|
||||
|
||||
import 'src/dartdoc/nav.dart';
|
||||
import 'src/dartdoc/utils.dart';
|
||||
import 'src/export_map.dart';
|
||||
import 'src/json_serializer.dart' as json_serializer;
|
||||
|
||||
// TODO(rnystrom): Use "package:" URL (#4968).
|
||||
|
@ -35,8 +40,6 @@ import '../../compiler/implementation/mirrors/mirrors.dart';
|
|||
import '../../compiler/implementation/mirrors/mirrors_util.dart';
|
||||
import '../../libraries.dart';
|
||||
|
||||
part 'src/dartdoc/utils.dart';
|
||||
|
||||
/**
|
||||
* Generates completely static HTML containing everything you need to browse
|
||||
* the docs. The only client side behavior is trivial stuff like syntax
|
||||
|
@ -107,6 +110,7 @@ String displayName(LibraryMirror library) {
|
|||
* event loop has had a chance to pump (i.e. after `main()` has returned).
|
||||
*/
|
||||
Future copyDirectory(Path from, Path to) {
|
||||
print('Copying static files...');
|
||||
final completer = new Completer();
|
||||
final fromDir = new Directory.fromPath(from);
|
||||
fromDir.list(recursive: false).listen(
|
||||
|
@ -131,16 +135,38 @@ Future copyDirectory(Path from, Path to) {
|
|||
*/
|
||||
Future compileScript(int mode, Path outputDir, Path libPath) {
|
||||
print('Compiling client JavaScript...');
|
||||
var clientScript = (mode == MODE_STATIC) ? 'static' : 'live-nav';
|
||||
var dartPath = libPath.append(
|
||||
'lib/_internal/dartdoc/lib/src/client/client-$clientScript.dart');
|
||||
var jsPath = outputDir.append('client-$clientScript.js');
|
||||
|
||||
return dart2js.compile(dartPath, libPath,
|
||||
options: const <String>['--categories=Client,Server'])
|
||||
.then((jsCode) {
|
||||
writeString(new File.fromPath(jsPath), jsCode);
|
||||
// TODO(nweiz): don't run this in an isolate when issue 9815 is fixed.
|
||||
return spawnFunction(_compileScript).call({
|
||||
'mode': mode,
|
||||
'outputDir': outputDir.toNativePath(),
|
||||
'libPath': libPath.toNativePath()
|
||||
}).then((result) {
|
||||
if (result.first == 'success') return;
|
||||
throw new AsyncError(result[1], result[2]);
|
||||
});
|
||||
}
|
||||
|
||||
void _compileScript() {
|
||||
port.receive((message, replyTo) {
|
||||
new Future.of(() {
|
||||
var clientScript = (message['mode'] == MODE_STATIC) ?
|
||||
'static' : 'live-nav';
|
||||
var dartPath = pathos.join(message['libPath'], 'lib', '_internal',
|
||||
'dartdoc', 'lib', 'src', 'client', 'client-$clientScript.dart');
|
||||
var jsPath = pathos.join(message['outputDir'], 'client-$clientScript.js');
|
||||
|
||||
return dart2js.compile(
|
||||
new Path(dartPath), new Path(message['libPath']),
|
||||
options: const <String>['--categories=Client,Server']).then((jsCode) {
|
||||
writeString(new File(jsPath), jsCode);
|
||||
});
|
||||
}).then((_) {
|
||||
replyTo.send(['success']);
|
||||
}).catchError((e) {
|
||||
replyTo.send(['error', e.error.toString(), e.stackTrace.toString()]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -261,11 +287,30 @@ class Dartdoc {
|
|||
/** Set this to select the libraries to exclude from the documentation. */
|
||||
List<String> excludedLibraries = const <String>[];
|
||||
|
||||
/** The package root for `package:` imports. */
|
||||
String _packageRoot;
|
||||
|
||||
/** The map containing all the exports for each library. */
|
||||
ExportMap _exports;
|
||||
|
||||
/**
|
||||
* This list contains the libraries sorted in by the library name.
|
||||
*/
|
||||
List<LibraryMirror> _sortedLibraries;
|
||||
|
||||
/** A map from absolute paths of libraries to the libraries at those paths. */
|
||||
Map<String, LibraryMirror> _librariesByPath;
|
||||
|
||||
/**
|
||||
* A map from absolute paths of hidden libraries to lists of [Export]s that
|
||||
* export those libraries from visible libraries. This is used to determine
|
||||
* what public library any given entity belongs to.
|
||||
*
|
||||
* The lists of exports are sorted so that exports that hide the fewest number
|
||||
* of members come first.
|
||||
*/
|
||||
Map<String, List<Export>> _hiddenLibraryExports;
|
||||
|
||||
/** The library that we're currently generating docs for. */
|
||||
LibraryMirror _currentLibrary;
|
||||
|
||||
|
@ -403,16 +448,25 @@ class Dartdoc {
|
|||
return content;
|
||||
}
|
||||
|
||||
Future documentEntryPoint(Path entrypoint, Path libPath, Path packageRoot) {
|
||||
return documentLibraries(<Path>[entrypoint], libPath, packageRoot);
|
||||
}
|
||||
Future documentLibraries(List<Uri> libraryList, Path libPath,
|
||||
String packageRoot) {
|
||||
_packageRoot = packageRoot;
|
||||
_exports = new ExportMap.parse(libraryList, packageRoot);
|
||||
var librariesToAnalyze = _exports.allExportedFiles.toList();
|
||||
librariesToAnalyze.addAll(libraryList.map((uri) {
|
||||
if (uri.scheme == 'file') return fileUriToPath(uri);
|
||||
// dart2js takes "dart:*" URIs as Path objects for some reason.
|
||||
return uri.toString();
|
||||
}));
|
||||
|
||||
var packageRootPath = packageRoot == null ? null : new Path(packageRoot);
|
||||
|
||||
Future documentLibraries(List<Path> libraryList, Path libPath, Path packageRoot) {
|
||||
// TODO(amouravski): make all of these print statements into logging
|
||||
// statements.
|
||||
print('Analyzing libraries...');
|
||||
return dart2js.analyze(libraryList, libPath, packageRoot: packageRoot,
|
||||
options: COMPILER_OPTIONS)
|
||||
return dart2js.analyze(
|
||||
librariesToAnalyze.map((path) => new Path(path)).toList(), libPath,
|
||||
packageRoot: packageRootPath, options: COMPILER_OPTIONS)
|
||||
.then((MirrorSystem mirrors) {
|
||||
print('Generating documentation...');
|
||||
_document(mirrors);
|
||||
|
@ -430,6 +484,16 @@ class Dartdoc {
|
|||
displayName(y).toUpperCase());
|
||||
});
|
||||
|
||||
_librariesByPath = <String, LibraryMirror>{};
|
||||
for (var library in mirrors.libraries.values) {
|
||||
var path = _libraryPath(library);
|
||||
if (path == null) continue;
|
||||
path = pathos.normalize(pathos.absolute(path));
|
||||
_librariesByPath[path] = library;
|
||||
}
|
||||
|
||||
_hiddenLibraryExports = _generateHiddenLibraryExports();
|
||||
|
||||
// Generate the docs.
|
||||
if (mode == MODE_LIVE_NAV) {
|
||||
docNavigationJson();
|
||||
|
@ -446,6 +510,7 @@ class Dartdoc {
|
|||
generateAppCacheManifest();
|
||||
}
|
||||
|
||||
// TODO(nweiz): properly handle exports when generating JSON.
|
||||
// TODO(jacobr): handle arbitrary pub packages rather than just the system
|
||||
// libraries.
|
||||
var revision = '0';
|
||||
|
@ -484,6 +549,63 @@ class Dartdoc {
|
|||
_finished = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate [_hiddenLibraryExports] from [_exports] and [_librariesByPath].
|
||||
*/
|
||||
Map<String, List<Export>> _generateHiddenLibraryExports() {
|
||||
// First generate a map `exported path => exporter path => Export`. The
|
||||
// inner map makes it easier to merge multiple exports of the same library
|
||||
// by the same exporter.
|
||||
var hiddenLibraryExportMaps = <String, Map<String, Export>>{};
|
||||
_exports.exports.forEach((exporter, exports) {
|
||||
var library = _librariesByPath[exporter];
|
||||
// TODO(nweiz): remove this check when issue 9645 is fixed.
|
||||
if (library == null) return;
|
||||
if (!shouldIncludeLibrary(library)) return;
|
||||
for (var export in exports) {
|
||||
var library = _librariesByPath[export.path];
|
||||
// TODO(nweiz): remove this check when issue 9645 is fixed.
|
||||
if (library == null) continue;
|
||||
if (shouldIncludeLibrary(library)) continue;
|
||||
|
||||
var hiddenExports = _exports.transitiveExports(export.path)
|
||||
.map((transitiveExport) => export.compose(transitiveExport))
|
||||
.toList();
|
||||
hiddenExports.add(export);
|
||||
|
||||
for (var hiddenExport in hiddenExports) {
|
||||
var exportsByExporterPath = hiddenLibraryExportMaps
|
||||
.putIfAbsent(hiddenExport.path, () => <String, Export>{});
|
||||
addOrMergeExport(exportsByExporterPath, exporter, hiddenExport);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Now sort the values of the inner maps of `hiddenLibraryExportMaps` to get
|
||||
// the final value of `_hiddenLibraryExports`.
|
||||
var hiddenLibraryExports = <String, List<Export>>{};
|
||||
hiddenLibraryExportMaps.forEach((exporteePath, exportsByExporterPath) {
|
||||
int rank(Export export) {
|
||||
if (export.show.isEmpty && export.hide.isEmpty) return 0;
|
||||
if (export.show.isEmpty) return export.hide.length;
|
||||
// Multiply by 1000 to ensure this sorts after an export with hides.
|
||||
return 1000 * export.show.length;
|
||||
}
|
||||
|
||||
var exports = exportsByExporterPath.values.toList();
|
||||
exports.sort((export1, export2) {
|
||||
var comparison = Comparable.compare(rank(export1), rank(export2));
|
||||
if (comparison != 0) return comparison;
|
||||
|
||||
var library1 = _librariesByPath[export1.exporter];
|
||||
var library2 = _librariesByPath[export2.exporter];
|
||||
return Comparable.compare(library1.displayName, library2.displayName);
|
||||
});
|
||||
hiddenLibraryExports[exporteePath] = exports;
|
||||
});
|
||||
return hiddenLibraryExports;
|
||||
}
|
||||
|
||||
MdnComment lookupMdnComment(Mirror mirror) => null;
|
||||
|
||||
void startFile(String path) {
|
||||
|
@ -868,6 +990,9 @@ class Dartdoc {
|
|||
writeln('<div class="doc">${comment.html}</div>');
|
||||
}
|
||||
|
||||
// Document the visible libraries exported by this library.
|
||||
docExports(library);
|
||||
|
||||
// Document the top-level members.
|
||||
docMembers(library);
|
||||
|
||||
|
@ -878,7 +1003,8 @@ class Dartdoc {
|
|||
final typedefs = <TypedefMirror>[];
|
||||
final exceptions = <ClassMirror>[];
|
||||
|
||||
for (ClassMirror type in orderByName(library.classes.values)) {
|
||||
var allClasses = _libraryClasses(library);
|
||||
for (ClassMirror type in orderByName(allClasses)) {
|
||||
if (!showPrivate && type.isPrivate) continue;
|
||||
|
||||
if (isException(type)) {
|
||||
|
@ -907,7 +1033,7 @@ class Dartdoc {
|
|||
writeFooter();
|
||||
endFile();
|
||||
|
||||
for (final type in library.classes.values) {
|
||||
for (final type in allClasses) {
|
||||
if (!showPrivate && type.isPrivate) continue;
|
||||
|
||||
docType(type);
|
||||
|
@ -955,8 +1081,9 @@ class Dartdoc {
|
|||
|
||||
final typeTitle =
|
||||
'${typeName(type)} ${kind}';
|
||||
writeHeader('$typeTitle / ${displayName(type.library)} Library',
|
||||
[displayName(type.library), libraryUrl(type.library),
|
||||
var library = _libraryFor(type);
|
||||
writeHeader('$typeTitle / ${displayName(library)} Library',
|
||||
[displayName(library), libraryUrl(library),
|
||||
typeName(type), typeUrl(type)]);
|
||||
writeln(
|
||||
'''
|
||||
|
@ -1148,6 +1275,40 @@ class Dartdoc {
|
|||
return map;
|
||||
}();
|
||||
|
||||
void docExports(LibraryMirror library) {
|
||||
// TODO(nweiz): show `dart:` library exports.
|
||||
var exportLinks = _exports.transitiveExports(_libraryPath(library))
|
||||
.map((export) {
|
||||
var library = _librariesByPath[export.path];
|
||||
// TODO(nweiz): remove this check when issue 9645 is fixed.
|
||||
if (library == null) return null;
|
||||
// Only link to publically visible libraries.
|
||||
if (!shouldIncludeLibrary(library)) return null;
|
||||
|
||||
var memberNames = export.show.isEmpty ? export.hide : export.show;
|
||||
var memberLinks = memberNames.map((name) {
|
||||
return md.renderToHtml([resolveNameReference(
|
||||
name, currentLibrary: library)]);
|
||||
}).join(', ');
|
||||
var combinator = '';
|
||||
if (!export.show.isEmpty) {
|
||||
combinator = ' show $memberLinks';
|
||||
} else if (!export.hide.isEmpty) {
|
||||
combinator = ' hide $memberLinks';
|
||||
}
|
||||
|
||||
return '<ul>${a(libraryUrl(library), displayName(library))}'
|
||||
'$combinator</ul>';
|
||||
}).where((link) => link != null);
|
||||
|
||||
if (!exportLinks.isEmpty) {
|
||||
writeln('<h3>Exports</h3>');
|
||||
writeln('<ul>');
|
||||
writeln(exportLinks.join('\n'));
|
||||
writeln('</ul>');
|
||||
}
|
||||
}
|
||||
|
||||
void docMembers(ContainerMirror host) {
|
||||
// Collect the different kinds of members.
|
||||
final staticMethods = [];
|
||||
|
@ -1160,8 +1321,10 @@ class Dartdoc {
|
|||
final instanceSetters = new Map<String,MemberMirror>();
|
||||
final constructors = [];
|
||||
|
||||
host.members.forEach((_, MemberMirror member) {
|
||||
if (!showPrivate && member.isPrivate) return;
|
||||
var hostMembers = host is LibraryMirror ?
|
||||
_libraryMembers(host) : host.members.values;
|
||||
for (var member in hostMembers) {
|
||||
if (!showPrivate && member.isPrivate) continue;
|
||||
if (host is LibraryMirror || member.isStatic) {
|
||||
if (member is MethodMirror) {
|
||||
if (member.isGetter) {
|
||||
|
@ -1175,7 +1338,7 @@ class Dartdoc {
|
|||
staticGetters[member.displayName] = member;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (host is ClassMirror) {
|
||||
var iterable = new HierarchyIterable(host, includeType: true);
|
||||
|
@ -1219,28 +1382,28 @@ class Dartdoc {
|
|||
if (member is MethodMirror) {
|
||||
if (member.isGetter) {
|
||||
instanceGetters[member.displayName] = member;
|
||||
if (member.owner == host) {
|
||||
if (_ownerFor(member) == host) {
|
||||
allPropertiesInherited = false;
|
||||
}
|
||||
} else if (member.isSetter) {
|
||||
instanceSetters[member.displayName] = member;
|
||||
if (member.owner == host) {
|
||||
if (_ownerFor(member) == host) {
|
||||
allPropertiesInherited = false;
|
||||
}
|
||||
} else if (member.isOperator) {
|
||||
instanceOperators.add(member);
|
||||
if (member.owner == host) {
|
||||
if (_ownerFor(member) == host) {
|
||||
allOperatorsInherited = false;
|
||||
}
|
||||
} else {
|
||||
instanceMethods.add(member);
|
||||
if (member.owner == host) {
|
||||
if (_ownerFor(member) == host) {
|
||||
allMethodsInherited = false;
|
||||
}
|
||||
}
|
||||
} else if (member is VariableMirror) {
|
||||
instanceGetters[member.displayName] = member;
|
||||
if (member.owner == host) {
|
||||
if (_ownerFor(member) == host) {
|
||||
allPropertiesInherited = false;
|
||||
}
|
||||
}
|
||||
|
@ -1305,7 +1468,7 @@ class Dartdoc {
|
|||
} else {
|
||||
DocComment getterComment = getMemberComment(getter);
|
||||
DocComment setterComment = getMemberComment(setter);
|
||||
if (getter.owner != setter.owner ||
|
||||
if (_ownerFor(getter) != _ownerFor(setter) ||
|
||||
getterComment != null && setterComment != null) {
|
||||
// Both have comments or are not declared in the same class
|
||||
// => Documents separately.
|
||||
|
@ -1376,7 +1539,7 @@ class Dartdoc {
|
|||
}
|
||||
|
||||
bool showCode = includeSource && !isAbstract;
|
||||
bool inherited = host != member.owner;
|
||||
bool inherited = host != member.owner && member.owner is! LibraryMirror;
|
||||
|
||||
writeln('<div class="method${inherited ? ' inherited': ''}">'
|
||||
'<h4 id="${memberAnchor(member)}">');
|
||||
|
@ -1467,7 +1630,7 @@ class Dartdoc {
|
|||
_totalMembers++;
|
||||
_currentMember = getter;
|
||||
|
||||
bool inherited = host != getter.owner;
|
||||
bool inherited = host != getter.owner && getter.owner is! LibraryMirror;
|
||||
|
||||
writeln('<div class="field${inherited ? ' inherited' : ''}">'
|
||||
'<h4 id="${memberAnchor(getter)}">');
|
||||
|
@ -1674,13 +1837,13 @@ class Dartdoc {
|
|||
// Always get the generic type to strip off any type parameters or
|
||||
// arguments. If the type isn't generic, genericType returns `this`, so it
|
||||
// works for non-generic types too.
|
||||
return '${sanitize(displayName(type.library))}/'
|
||||
return '${sanitize(displayName(_libraryFor(type)))}/'
|
||||
'${type.originalDeclaration.simpleName}.html';
|
||||
}
|
||||
|
||||
/** Gets the URL for the documentation for [member]. */
|
||||
String memberUrl(MemberMirror member) {
|
||||
String url = typeUrl(member.owner);
|
||||
String url = typeUrl(_ownerFor(member));
|
||||
return '$url#${memberAnchor(member)}';
|
||||
}
|
||||
|
||||
|
@ -1759,9 +1922,10 @@ class Dartdoc {
|
|||
assert(type is ClassMirror);
|
||||
|
||||
// Link to the type.
|
||||
if (shouldLinkToPublicApi(type.library)) {
|
||||
var library = _libraryFor(type);
|
||||
if (shouldLinkToPublicApi(library)) {
|
||||
write('<a href="$API_LOCATION${typeUrl(type)}">${type.simpleName}</a>');
|
||||
} else if (shouldIncludeLibrary(type.library)) {
|
||||
} else if (shouldIncludeLibrary(library)) {
|
||||
write(a(typeUrl(type), type.simpleName));
|
||||
} else {
|
||||
write(type.simpleName);
|
||||
|
@ -1979,6 +2143,86 @@ class Dartdoc {
|
|||
return type.simpleName.endsWith('Exception') ||
|
||||
type.simpleName.endsWith('Error');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute path to [library] on the filesystem, or `null` if the
|
||||
* library doesn't exist on the local filesystem.
|
||||
*/
|
||||
String _libraryPath(LibraryMirror library) =>
|
||||
importUriToPath(library.uri, packageRoot: _packageRoot);
|
||||
|
||||
/**
|
||||
* Returns a list of classes in [library], including classes it exports from
|
||||
* hidden libraries.
|
||||
*/
|
||||
List<ClassMirror> _libraryClasses(LibraryMirror library) =>
|
||||
_libraryContents(library, (lib) => lib.classes.values);
|
||||
|
||||
/**
|
||||
* Returns a list of top-level members in [library], including members it
|
||||
* exports from hidden libraries.
|
||||
*/
|
||||
List<MemberMirror> _libraryMembers(LibraryMirror library) =>
|
||||
_libraryContents(library, (lib) => lib.members.values);
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of elements in [library], including elements it exports from
|
||||
* hidden libraries. [fn] should return the element list for a single library,
|
||||
* which will then be merged across all exported libraries.
|
||||
*/
|
||||
List<DeclarationMirror> _libraryContents(LibraryMirror library,
|
||||
List<DeclarationMirror> fn(LibraryMirror)) {
|
||||
var contents = fn(library).toList();
|
||||
var path = _libraryPath(library);
|
||||
if (path == null || _exports.exports[path] == null) return contents;
|
||||
|
||||
|
||||
contents.addAll(_exports.exports[path].expand((export) {
|
||||
var exportedLibrary = _librariesByPath[export.path];
|
||||
// TODO(nweiz): remove this check when issue 9645 is fixed.
|
||||
if (exportedLibrary == null) return [];
|
||||
if (shouldIncludeLibrary(exportedLibrary)) return [];
|
||||
return fn(exportedLibrary).where((declaration) =>
|
||||
export.isMemberVisible(declaration.displayName));
|
||||
}));
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the library in which [type] was defined. If [type] was defined in a
|
||||
* hidden library that was exported by another library, this returns the
|
||||
* exporter.
|
||||
*/
|
||||
LibraryMirror _libraryFor(TypeMirror type) =>
|
||||
_visibleLibrary(type.library, type.displayName);
|
||||
|
||||
/**
|
||||
* Returns the owner of [declaration]. If [declaration]'s owner is a hidden
|
||||
* library that was exported by another library, this returns the exporter.
|
||||
*/
|
||||
DeclarationMirror _ownerFor(DeclarationMirror declaration) {
|
||||
var owner = declaration.owner;
|
||||
if (owner is! LibraryMirror) return owner;
|
||||
return _visibleLibrary(owner, declaration.displayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the best visible library that exports [name] from [library]. If
|
||||
* [library] is public, it will be returned.
|
||||
*/
|
||||
LibraryMirror _visibleLibrary(LibraryMirror library, String name) {
|
||||
if (library == null) return null;
|
||||
|
||||
var exports = _hiddenLibraryExports[_libraryPath(library)];
|
||||
if (exports == null) return library;
|
||||
|
||||
var export = exports.firstWhere(
|
||||
(exp) => exp.isMemberVisible(name),
|
||||
orElse: () => null);
|
||||
if (export == null) return library;
|
||||
return _librariesByPath[export.exporter];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,9 +2,18 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
part of dartdoc;
|
||||
|
||||
// Generic utility functions.
|
||||
library utils;
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:uri';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:pathos/path.dart' as pathos;
|
||||
|
||||
import '../../../../compiler/implementation/mirrors/mirrors.dart';
|
||||
|
||||
import '../export_map.dart';
|
||||
|
||||
/** Turns [name] into something that's safe to use as a file name. */
|
||||
String sanitize(String name) => name.replaceAll(':', '_').replaceAll('/', '_');
|
||||
|
@ -40,7 +49,7 @@ String repeat(String text, int count, {String separator}) {
|
|||
/** Removes up to [indentation] leading whitespace characters from [text]. */
|
||||
String unindent(String text, int indentation) {
|
||||
var start;
|
||||
for (start = 0; start < min(indentation, text.length); start++) {
|
||||
for (start = 0; start < math.min(indentation, text.length); start++) {
|
||||
// Stop if we hit a non-whitespace character.
|
||||
if (text[start] != ' ') break;
|
||||
}
|
||||
|
@ -77,3 +86,76 @@ void writeString(File file, String text) {
|
|||
randomAccessFile.writeStringSync(text);
|
||||
randomAccessFile.closeSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts [uri], which should come from a Dart import or export, to a local
|
||||
* filesystem path. [basePath] is the base directory to use when converting
|
||||
* relative URIs; without it, relative URIs will not be converted. [packageRoot]
|
||||
* is the `packages` directory to use when converting `package:` URIs; without
|
||||
* it, `package:` URIs will not be converted.
|
||||
*
|
||||
* If a URI cannot be converted, this will return `null`.
|
||||
*/
|
||||
String importUriToPath(Uri uri, {String basePath, String packageRoot}) {
|
||||
if (uri.scheme == 'file') return fileUriToPath(uri);
|
||||
|
||||
if (basePath != null && uri.scheme == '') {
|
||||
return pathos.normalize(pathos.absolute(pathos.join(basePath, uri.path)));
|
||||
}
|
||||
|
||||
if (packageRoot != null && uri.scheme == 'package') {
|
||||
return pathos.normalize(pathos.absolute(
|
||||
pathos.join(packageRoot, uri.path)));
|
||||
}
|
||||
|
||||
// Ignore unsupported schemes.
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Converts a `file:` [Uri] to a local path string. */
|
||||
String fileUriToPath(Uri uri) {
|
||||
if (uri.scheme != 'file') {
|
||||
throw new ArgumentError("Uri $uri must have scheme 'file:'.");
|
||||
}
|
||||
if (Platform.operatingSystem != 'windows') return pathos.normalize(uri.path);
|
||||
return pathos.normalize(uri.path.replaceFirst("/", "").replaceAll("/", "\\"));
|
||||
}
|
||||
|
||||
/** Converts a local path string to a `file:` [Uri]. */
|
||||
Uri pathToFileUri(String path) {
|
||||
path = pathos.absolute(path);
|
||||
if (Platform.operatingSystem != 'windows') {
|
||||
return Uri.parse('file://$path');
|
||||
} else {
|
||||
return Uri.parse('file:///${path.replaceAll("\\", "/")}');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If [map] contains an [Export] under [key], this merges that with [export].
|
||||
* Otherwise, it sets [key] to [export].
|
||||
*/
|
||||
void addOrMergeExport(Map<String, Export> map, String key, Export export) {
|
||||
if (map.containsKey(key)) {
|
||||
map[key] = map[key].merge(export);
|
||||
} else {
|
||||
map[key] = export;
|
||||
}
|
||||
}
|
||||
|
||||
/// A pair of values.
|
||||
class Pair<E, F> {
|
||||
E first;
|
||||
F last;
|
||||
|
||||
Pair(this.first, this.last);
|
||||
|
||||
String toString() => '($first, $last)';
|
||||
|
||||
bool operator==(other) {
|
||||
if (other is! Pair) return false;
|
||||
return other.first == first && other.last == last;
|
||||
}
|
||||
|
||||
int get hashCode => first.hashCode ^ last.hashCode;
|
||||
}
|
||||
|
|
342
sdk/lib/_internal/dartdoc/lib/src/export_map.dart
Normal file
342
sdk/lib/_internal/dartdoc/lib/src/export_map.dart
Normal file
|
@ -0,0 +1,342 @@
|
|||
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
/// This library uses the Dart analyzer to find the exports for a set of
|
||||
/// libraries. It stores these exports in an [ExportMap]. This is used to
|
||||
/// display exported members as part of the exporting library, since dart2js
|
||||
/// doesn't provide this information itself.
|
||||
library export_map;
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:uri';
|
||||
|
||||
import 'package:analyzer_experimental/src/generated/ast.dart';
|
||||
import 'package:analyzer_experimental/src/generated/error.dart';
|
||||
import 'package:analyzer_experimental/src/generated/parser.dart';
|
||||
import 'package:analyzer_experimental/src/generated/scanner.dart';
|
||||
import 'package:analyzer_experimental/src/generated/source.dart';
|
||||
import 'package:pathos/path.dart' as pathos;
|
||||
|
||||
import 'dartdoc/utils.dart';
|
||||
|
||||
/// A class that tracks which libraries export which other libraries.
|
||||
class ExportMap {
|
||||
/// A map from libraries to their [Export]s.
|
||||
///
|
||||
/// Each key is the absolute path of a library on the filesystem, and each
|
||||
/// value is a list of [Export]s for that library. There's guaranteed to be
|
||||
/// only one [Export] of a given library in a given list.
|
||||
final Map<String, List<Export>> exports;
|
||||
|
||||
/// A cache of the transitive exports for each library. The keys are paths to
|
||||
/// libraries. The values are maps from the exported path to the [Export]
|
||||
/// objects, to make it easier to merge multiple exports of the same library.
|
||||
final _transitiveExportsByPath = <String, Map<String, Export>>{};
|
||||
|
||||
/// Parse an export map from a set of [libraries], which should be Dart import
|
||||
/// [Uri]s. [packageRoot] should be the path to the `packages` directory to
|
||||
/// use when resolving `package:` imports and libraries. Libraries that are
|
||||
/// not available on the local machine will be ignored.
|
||||
///
|
||||
/// In addition to parsing the exports in [libraries], this will parse the
|
||||
/// exports in all libraries transitively reachable from [libraries] via
|
||||
/// `import` or `export`.
|
||||
factory ExportMap.parse(Iterable<Uri> libraries, String packageRoot) {
|
||||
var exports = <String, List<Export>>{};
|
||||
|
||||
void traverse(String path) {
|
||||
if (exports.containsKey(path)) return;
|
||||
|
||||
var importsAndExports;
|
||||
try {
|
||||
importsAndExports = _importsAndExportsForFile(path, packageRoot);
|
||||
} on FileIOException catch (_) {
|
||||
// Ignore unreadable/nonexistent files.
|
||||
return;
|
||||
}
|
||||
|
||||
var exportsForLibrary = <String, Export>{};
|
||||
for (var export in importsAndExports.last) {
|
||||
addOrMergeExport(exportsForLibrary, export.path, export);
|
||||
}
|
||||
exports[path] = new List.from(exportsForLibrary.values);
|
||||
exports[path].map((directive) => directive.path).forEach(traverse);
|
||||
importsAndExports.first.forEach(traverse);
|
||||
}
|
||||
|
||||
for (var library in libraries) {
|
||||
var path = importUriToPath(library, packageRoot: packageRoot);
|
||||
if (path != null) traverse(path);
|
||||
}
|
||||
|
||||
return new ExportMap._(exports);
|
||||
}
|
||||
|
||||
ExportMap._(this.exports);
|
||||
|
||||
/// Returns a list of all the paths of exported libraries that [this] is aware
|
||||
/// of.
|
||||
List<String> get allExportedFiles => exports.values.expand((e) => e)
|
||||
.map((directive) => directive.path).toList();
|
||||
|
||||
/// Returns a list of all exports that [library] transitively exports. This
|
||||
/// means that if [library] exports another library that in turn exports a
|
||||
/// third, the third library will be included in the returned list.
|
||||
///
|
||||
/// This will automatically handle nested `hide` and `show` directives on the
|
||||
/// exports, as well as merging multiple exports of the same library.
|
||||
List<Export> transitiveExports(String library) {
|
||||
Map<String, Export> _getTransitiveExportsByPath(String path) {
|
||||
if (_transitiveExportsByPath.containsKey(path)) {
|
||||
return _transitiveExportsByPath[path];
|
||||
}
|
||||
|
||||
var exportsByPath = <String, Export>{};
|
||||
_transitiveExportsByPath[path] = exportsByPath;
|
||||
if (exports[path] == null) return exportsByPath;
|
||||
|
||||
for (var export in exports[path]) {
|
||||
exportsByPath[export.path] = export;
|
||||
}
|
||||
|
||||
for (var export in exports[path]) {
|
||||
for (var subExport in _getTransitiveExportsByPath(export.path).values) {
|
||||
subExport = export.compose(subExport);
|
||||
if (exportsByPath.containsKey(subExport.path)) {
|
||||
subExport = subExport.merge(exportsByPath[subExport.path]);
|
||||
}
|
||||
exportsByPath[subExport.path] = subExport;
|
||||
}
|
||||
}
|
||||
return exportsByPath;
|
||||
}
|
||||
|
||||
var path = pathos.normalize(pathos.absolute(library));
|
||||
return _getTransitiveExportsByPath(path).values.toList();
|
||||
}
|
||||
}
|
||||
|
||||
/// A class that represents one library exporting another.
|
||||
class Export {
|
||||
/// The absolute path of the library that contains this export.
|
||||
final String exporter;
|
||||
|
||||
/// The absolute path of the library being exported.
|
||||
final String path;
|
||||
|
||||
/// The set of identifiers that are explicitly being exported. If this is
|
||||
/// non-empty, no identifiers other than these will be visible.
|
||||
///
|
||||
/// One or both of [show] and [hide] will always be empty.
|
||||
Set<String> get show => _show;
|
||||
Set<String> _show;
|
||||
|
||||
/// The set of identifiers that are not exported.
|
||||
///
|
||||
/// One or both of [show] and [hide] will always be empty.
|
||||
Set<String> get hide => _hide;
|
||||
Set<String> _hide;
|
||||
|
||||
/// Whether or not members exported are hidden by default.
|
||||
bool get _hideByDefault => !show.isEmpty;
|
||||
|
||||
/// Creates a new export.
|
||||
///
|
||||
/// This will normalize [show] and [hide] so that if both are non-empty, only
|
||||
/// [show] will be set.
|
||||
Export(this.exporter, this.path, {Iterable<String> show,
|
||||
Iterable<String> hide}) {
|
||||
_show = new Set<String>.from(show == null ? [] : show);
|
||||
_hide = new Set<String>.from(hide == null ? [] : hide);
|
||||
|
||||
if (!_show.isEmpty) {
|
||||
_show.removeAll(_hide);
|
||||
_hide = new Set<String>();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new [Export] that represents [this] composed with [nested], as
|
||||
/// though [this] was used to export a library that in turn exported [nested].
|
||||
Export compose(Export nested) {
|
||||
var show = new Set<String>();
|
||||
var hide = new Set<String>();
|
||||
|
||||
if (this._hideByDefault) {
|
||||
show.addAll(this.show);
|
||||
if (nested._hideByDefault) {
|
||||
show.retainAll(nested.show);
|
||||
} else {
|
||||
show.removeAll(nested.hide);
|
||||
}
|
||||
} else if (nested._hideByDefault) {
|
||||
show.addAll(nested.show);
|
||||
show.removeAll(this.hide);
|
||||
} else {
|
||||
hide.addAll(this.hide);
|
||||
hide.addAll(nested.hide);
|
||||
}
|
||||
|
||||
return new Export(this.exporter, nested.path, show: show, hide: hide);
|
||||
}
|
||||
|
||||
/// Returns a new [Export] that merges [this] with [nested], as though both
|
||||
/// exports were included in the same library.
|
||||
///
|
||||
/// [this] and [other] must have the same values for [exporter] and [path].
|
||||
Export merge(Export other) {
|
||||
if (this.path != other.path) {
|
||||
throw new ArgumentError("Can't merge two Exports with different paths: "
|
||||
"export '$path' from '$exporter' and export '${other.path}' from "
|
||||
"'${other.exporter}'.");
|
||||
} if (this.exporter != other.exporter) {
|
||||
throw new ArgumentError("Can't merge two Exports with different "
|
||||
"exporters: export '$path' from '$exporter' and export "
|
||||
"'${other.path}' from '${other.exporter}'.");
|
||||
}
|
||||
|
||||
var show = new Set<String>();
|
||||
var hide = new Set<String>();
|
||||
|
||||
if (this._hideByDefault) {
|
||||
if (other._hideByDefault) {
|
||||
show.addAll(this.show);
|
||||
show.addAll(other.show);
|
||||
} else {
|
||||
hide.addAll(other.hide);
|
||||
hide.removeAll(this.show);
|
||||
}
|
||||
} else {
|
||||
hide.addAll(this.hide);
|
||||
if (other._hideByDefault) {
|
||||
hide.removeAll(other.show);
|
||||
} else {
|
||||
hide.retainAll(other.hide);
|
||||
}
|
||||
}
|
||||
|
||||
return new Export(exporter, path, show: show, hide: hide);
|
||||
}
|
||||
|
||||
/// Returns whether or not a member named [name] is visible through this
|
||||
/// import, as goverend by [show] and [hide].
|
||||
bool isMemberVisible(String name) =>
|
||||
_hideByDefault ? show.contains(name) : !hide.contains(name);
|
||||
|
||||
bool operator==(other) => other is Export && other.exporter == exporter &&
|
||||
other.path == path && show.containsAll(other.show) &&
|
||||
other.show.containsAll(show) && hide.containsAll(other.hide) &&
|
||||
other.hide.containsAll(hide);
|
||||
|
||||
int get hashCode {
|
||||
var hashCode = exporter.hashCode ^ path.hashCode;
|
||||
hashCode = show.reduce(hashCode, (hash, name) => hash ^ name.hashCode);
|
||||
return hide.reduce(hashCode, (hash, name) => hash ^ name.hashCode);
|
||||
}
|
||||
|
||||
String toString() {
|
||||
var combinator = '';
|
||||
if (!show.isEmpty) {
|
||||
combinator = ' show ${show.join(', ')}';
|
||||
} else if (!hide.isEmpty) {
|
||||
combinator = ' hide ${hide.join(', ')}';
|
||||
}
|
||||
return "export '$path'$combinator (from $exporter)";
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a list of imports and a list of exports for the dart library at
|
||||
/// [file]. [packageRoot] is used to resolve `package:` URLs.
|
||||
///
|
||||
/// The imports are a list of absolute paths, while the exports are [Export]
|
||||
/// objects.
|
||||
Pair<List<String>, List<Export>> _importsAndExportsForFile(String file,
|
||||
String packageRoot) {
|
||||
var collector = new _ImportExportCollector();
|
||||
_parseFile(file).accept(collector);
|
||||
|
||||
var imports = collector.imports.map((import) {
|
||||
return _pathForDirective(import, pathos.dirname(file), packageRoot);
|
||||
}).where((import) => import != null).toList();
|
||||
|
||||
var exports = collector.exports.map((export) {
|
||||
var path = _pathForDirective(export, pathos.dirname(file), packageRoot);
|
||||
if (path == null) return null;
|
||||
|
||||
path = pathos.normalize(pathos.absolute(path));
|
||||
var show = export.combinators
|
||||
.where((combinator) => combinator is ShowCombinator)
|
||||
.expand((combinator) => combinator.shownNames.map((name) => name.name));
|
||||
var hide = export.combinators
|
||||
.where((combinator) => combinator is HideCombinator)
|
||||
.expand((combinator) =>
|
||||
combinator.hiddenNames.map((name) => name.name));
|
||||
|
||||
return new Export(file, path, show: show, hide: hide);
|
||||
}).where((export) => export != null).toList();
|
||||
|
||||
return new Pair<List<String>, List<Export>>(imports, exports);
|
||||
}
|
||||
|
||||
/// Returns the absolute path to the library imported by [directive], or `null`
|
||||
/// if it doesn't refer to a file on the local filesystem.
|
||||
///
|
||||
/// [basePath] is the path from which relative imports should be resolved.
|
||||
/// [packageRoot] is the path from which `package:` imports should be resolved.
|
||||
String _pathForDirective(NamespaceDirective directive, String basePath,
|
||||
String packageRoot) {
|
||||
var uri = Uri.parse(_stringLiteralToString(directive.uri));
|
||||
var path = importUriToPath(uri, basePath: basePath, packageRoot: packageRoot);
|
||||
if (path == null) return null;
|
||||
return pathos.normalize(pathos.absolute(path));
|
||||
}
|
||||
|
||||
/// Parses a Dart file into an AST.
|
||||
CompilationUnit _parseFile(String path) {
|
||||
var contents = new File(path).readAsStringSync();
|
||||
var errorCollector = new _ErrorCollector();
|
||||
var scanner = new StringScanner(null, contents, errorCollector);
|
||||
var token = scanner.tokenize();
|
||||
var parser = new Parser(null, errorCollector);
|
||||
var unit = parser.parseCompilationUnit(token);
|
||||
unit.lineInfo = new LineInfo(scanner.lineStarts);
|
||||
|
||||
if (!errorCollector.errors.isEmpty) {
|
||||
throw new FormatException(
|
||||
errorCollector.errors.map((e) => e.toString()).join("\n"));
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
/// A simple error listener that collects errors into a list.
|
||||
class _ErrorCollector extends AnalysisErrorListener {
|
||||
final errors = <AnalysisError>[];
|
||||
|
||||
_ErrorCollector();
|
||||
|
||||
void onError(AnalysisError error) => errors.add(error);
|
||||
}
|
||||
|
||||
/// A simple visitor that collects import and export nodes.
|
||||
class _ImportExportCollector extends GeneralizingASTVisitor {
|
||||
final imports = <ImportDirective>[];
|
||||
final exports = <ExportDirective>[];
|
||||
|
||||
_ImportExportCollector();
|
||||
|
||||
visitImportDirective(ImportDirective node) => imports.add(node);
|
||||
visitExportDirective(ExportDirective node) => exports.add(node);
|
||||
}
|
||||
|
||||
// TODO(nweiz): fold this into the analyzer (issue 9781).
|
||||
/// Converts an AST node representing a string literal into a [String].
|
||||
String _stringLiteralToString(StringLiteral literal) {
|
||||
if (literal is AdjacentStrings) {
|
||||
return literal.strings.map(_stringLiteralToString).join();
|
||||
} else if (literal is SimpleStringLiteral) {
|
||||
return literal.value;
|
||||
} else {
|
||||
throw new ArgumentError('Unknown string type for $literal');
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ description: >
|
|||
Libraries for generating documentation from Dart source code.
|
||||
|
||||
dependencies:
|
||||
analyzer_experimental: ">=0.4.5 <1.0.0"
|
||||
args: ">=0.4.2 <1.0.0"
|
||||
pathos: ">=0.4.2 <1.0.0"
|
||||
|
||||
|
|
|
@ -17,42 +17,6 @@ import '../lib/markdown.dart';
|
|||
import 'markdown_test.dart';
|
||||
|
||||
main() {
|
||||
group('countOccurrences', () {
|
||||
test('empty text returns 0', () {
|
||||
expect(dd.countOccurrences('', 'needle'), equals(0));
|
||||
});
|
||||
|
||||
test('one occurrence', () {
|
||||
expect(dd.countOccurrences('bananarama', 'nara'), equals(1));
|
||||
});
|
||||
|
||||
test('multiple occurrences', () {
|
||||
expect(dd.countOccurrences('bananarama', 'a'), equals(5));
|
||||
});
|
||||
|
||||
test('overlapping matches do not count', () {
|
||||
expect(dd.countOccurrences('bananarama', 'ana'), equals(1));
|
||||
});
|
||||
});
|
||||
|
||||
group('repeat', () {
|
||||
test('zero times returns an empty string', () {
|
||||
expect(dd.repeat('ba', 0), isEmpty);
|
||||
});
|
||||
|
||||
test('one time returns the string', () {
|
||||
expect(dd.repeat('ba', 1), equals('ba'));
|
||||
});
|
||||
|
||||
test('multiple times', () {
|
||||
expect(dd.repeat('ba', 3), equals('bababa'));
|
||||
});
|
||||
|
||||
test('multiple times with a separator', () {
|
||||
expect(dd.repeat('ba', 3, separator: ' '), equals('ba ba ba'));
|
||||
});
|
||||
});
|
||||
|
||||
group('isAbsolute', () {
|
||||
final doc = new dd.Dartdoc();
|
||||
|
||||
|
|
400
sdk/lib/_internal/dartdoc/test/export_map_test.dart
Normal file
400
sdk/lib/_internal/dartdoc/test/export_map_test.dart
Normal file
|
@ -0,0 +1,400 @@
|
|||
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:uri';
|
||||
|
||||
import 'package:pathos/path.dart' as pathos;
|
||||
import 'package:unittest/unittest.dart';
|
||||
|
||||
import '../lib/src/export_map.dart';
|
||||
import '../lib/src/dartdoc/utils.dart';
|
||||
|
||||
String tempDir;
|
||||
|
||||
main() {
|
||||
group('ExportMap', () {
|
||||
setUp(createTempDir);
|
||||
tearDown(deleteTempDir);
|
||||
|
||||
test('with an empty library', () {
|
||||
createLibrary('lib.dart');
|
||||
var map = parse(['lib.dart']);
|
||||
|
||||
var expectedExports = {};
|
||||
expectedExports[libPath('lib.dart')] = [];
|
||||
expect(map.exports, equals(expectedExports));
|
||||
expect(map.allExportedFiles, isEmpty);
|
||||
expect(map.transitiveExports(libPath('lib.dart')), isEmpty);
|
||||
expect(map.transitiveExports(libPath('nonexistent.dart')), isEmpty);
|
||||
});
|
||||
|
||||
test('with one library with one export', () {
|
||||
createLibrary('a.dart', 'export "b.dart";');
|
||||
createLibrary('b.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart'))
|
||||
]));
|
||||
|
||||
expect(map.transitiveExports(libPath('a.dart')), unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart'))
|
||||
]));
|
||||
|
||||
expect(map.allExportedFiles, unorderedEquals([libPath('b.dart')]));
|
||||
|
||||
expect(map.exports[libPath('b.dart')], isEmpty);
|
||||
expect(map.transitiveExports(libPath('b.dart')), isEmpty);
|
||||
});
|
||||
|
||||
test('with one library with multiple exports', () {
|
||||
createLibrary('a.dart', 'export "b.dart";\nexport "c.dart";');
|
||||
createLibrary('b.dart');
|
||||
createLibrary('c.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart')),
|
||||
new Export(libPath('a.dart'), libPath('c.dart'))
|
||||
]));
|
||||
|
||||
expect(map.transitiveExports(libPath('a.dart')), unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart')),
|
||||
new Export(libPath('a.dart'), libPath('c.dart'))
|
||||
]));
|
||||
|
||||
expect(map.allExportedFiles, unorderedEquals([
|
||||
libPath('b.dart'), libPath('c.dart')
|
||||
]));
|
||||
|
||||
expect(map.exports[libPath('b.dart')], isEmpty);
|
||||
expect(map.transitiveExports(libPath('b.dart')), isEmpty);
|
||||
expect(map.exports[libPath('c.dart')], isEmpty);
|
||||
expect(map.transitiveExports(libPath('c.dart')), isEmpty);
|
||||
});
|
||||
|
||||
test('with two libraries each with one export', () {
|
||||
createLibrary('a.dart', 'export "a_export.dart";');
|
||||
createLibrary('b.dart', 'export "b_export.dart";');
|
||||
createLibrary('a_export.dart');
|
||||
createLibrary('b_export.dart');
|
||||
var map = parse(['a.dart', 'b.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('a_export.dart')),
|
||||
]));
|
||||
expect(map.transitiveExports(libPath('a.dart')), unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('a_export.dart')),
|
||||
]));
|
||||
|
||||
expect(map.transitiveExports(libPath('b.dart')), unorderedEquals([
|
||||
new Export(libPath('b.dart'), libPath('b_export.dart')),
|
||||
]));
|
||||
expect(map.exports[libPath('b.dart')], unorderedEquals([
|
||||
new Export(libPath('b.dart'), libPath('b_export.dart'))
|
||||
]));
|
||||
|
||||
expect(map.allExportedFiles, unorderedEquals([
|
||||
libPath('a_export.dart'), libPath('b_export.dart')
|
||||
]));
|
||||
|
||||
expect(map.exports[libPath('a_export.dart')], isEmpty);
|
||||
expect(map.transitiveExports(libPath('a_export.dart')), isEmpty);
|
||||
expect(map.exports[libPath('b_export.dart')], isEmpty);
|
||||
expect(map.transitiveExports(libPath('b_export.dart')), isEmpty);
|
||||
});
|
||||
|
||||
test('with a transitive export', () {
|
||||
createLibrary('a.dart', 'export "b.dart";');
|
||||
createLibrary('b.dart', 'export "c.dart";');
|
||||
createLibrary('c.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart')),
|
||||
]));
|
||||
expect(map.transitiveExports(libPath('a.dart')), unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart')),
|
||||
new Export(libPath('a.dart'), libPath('c.dart')),
|
||||
]));
|
||||
|
||||
expect(map.exports[libPath('b.dart')], unorderedEquals([
|
||||
new Export(libPath('b.dart'), libPath('c.dart')),
|
||||
]));
|
||||
expect(map.transitiveExports(libPath('b.dart')), unorderedEquals([
|
||||
new Export(libPath('b.dart'), libPath('c.dart')),
|
||||
]));
|
||||
|
||||
expect(map.allExportedFiles, unorderedEquals([
|
||||
libPath('b.dart'), libPath('c.dart')
|
||||
]));
|
||||
|
||||
expect(map.exports[libPath('c.dart')], isEmpty);
|
||||
expect(map.transitiveExports(libPath('c.dart')), isEmpty);
|
||||
});
|
||||
|
||||
test('with an export through an import', () {
|
||||
createLibrary('a.dart', 'import "b.dart";');
|
||||
createLibrary('b.dart', 'export "c.dart";');
|
||||
createLibrary('c.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('b.dart')], unorderedEquals([
|
||||
new Export(libPath('b.dart'), libPath('c.dart')),
|
||||
]));
|
||||
expect(map.transitiveExports(libPath('b.dart')), unorderedEquals([
|
||||
new Export(libPath('b.dart'), libPath('c.dart')),
|
||||
]));
|
||||
|
||||
expect(map.allExportedFiles, unorderedEquals([libPath('c.dart')]));
|
||||
|
||||
expect(map.exports[libPath('a.dart')], isEmpty);
|
||||
expect(map.exports[libPath('c.dart')], isEmpty);
|
||||
expect(map.transitiveExports(libPath('a.dart')), isEmpty);
|
||||
expect(map.transitiveExports(libPath('c.dart')), isEmpty);
|
||||
});
|
||||
|
||||
test('with an export with a show combinator', () {
|
||||
createLibrary('a.dart', 'export "b.dart" show x, y;');
|
||||
createLibrary('b.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart'), show: ['x', 'y'])
|
||||
]));
|
||||
});
|
||||
|
||||
test('with an export with a hide combinator', () {
|
||||
createLibrary('a.dart', 'export "b.dart" hide x, y;');
|
||||
createLibrary('b.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart'), hide: ['x', 'y'])
|
||||
]));
|
||||
});
|
||||
|
||||
test('with an export with a show and a hide combinator', () {
|
||||
createLibrary('a.dart', 'export "b.dart" show x, y hide y, z;');
|
||||
createLibrary('b.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart'), show: ['x'])
|
||||
]));
|
||||
});
|
||||
|
||||
test('composes transitive exports', () {
|
||||
createLibrary('a.dart', 'export "b.dart" hide x;');
|
||||
createLibrary('b.dart', 'export "c.dart" hide y;');
|
||||
createLibrary('c.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.transitiveExports(libPath('a.dart')), unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart'), hide: ['x']),
|
||||
new Export(libPath('a.dart'), libPath('c.dart'), hide: ['x', 'y'])
|
||||
]));
|
||||
});
|
||||
|
||||
test('merges adjacent exports', () {
|
||||
createLibrary('a.dart', '''
|
||||
export "b.dart" show x, y;
|
||||
export "b.dart" hide y, z;
|
||||
''');
|
||||
createLibrary('b.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart'), hide: ['z']),
|
||||
]));
|
||||
expect(map.transitiveExports(libPath('a.dart')), unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart'), hide: ['z']),
|
||||
]));
|
||||
});
|
||||
|
||||
test('merges adjacent exports transitively', () {
|
||||
createLibrary('a.dart', 'export "b.dart";\nexport "c.dart";');
|
||||
createLibrary('b.dart', 'export "d.dart" show x, y;');
|
||||
createLibrary('c.dart', 'export "d.dart" hide y, z;');
|
||||
createLibrary('d.dart');
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart')),
|
||||
new Export(libPath('a.dart'), libPath('c.dart')),
|
||||
]));
|
||||
expect(map.transitiveExports(libPath('a.dart')), unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath('b.dart')),
|
||||
new Export(libPath('a.dart'), libPath('c.dart')),
|
||||
new Export(libPath('a.dart'), libPath('d.dart'), hide: ['z']),
|
||||
]));
|
||||
});
|
||||
|
||||
test('resolves package: exports', () {
|
||||
createLibrary('a.dart', 'export "package:b/b.dart";');
|
||||
var bPath = pathos.join('packages', 'b', 'b.dart');
|
||||
createLibrary(bPath);
|
||||
var map = parse(['a.dart']);
|
||||
|
||||
expect(map.exports[libPath('a.dart')], unorderedEquals([
|
||||
new Export(libPath('a.dart'), libPath(bPath))
|
||||
]));
|
||||
});
|
||||
|
||||
test('ignores dart: exports', () {
|
||||
createLibrary('a.dart', 'export "dart:async";');
|
||||
var map = parse(['a.dart']);
|
||||
expect(map.exports[libPath('a.dart')], isEmpty);
|
||||
});
|
||||
|
||||
test('.parse() resolves package: imports', () {
|
||||
var aPath = pathos.join('packages', 'a', 'a.dart');
|
||||
createLibrary(aPath, 'export "package:b/b.dart";');
|
||||
var bPath = pathos.join('packages', 'b', 'b.dart');
|
||||
createLibrary(bPath);
|
||||
var map = new ExportMap.parse(
|
||||
[Uri.parse('package:a/a.dart')],
|
||||
pathos.join(tempDir, 'packages'));
|
||||
|
||||
expect(map.exports[libPath(aPath)], unorderedEquals([
|
||||
new Export(libPath(aPath), libPath(bPath))
|
||||
]));
|
||||
});
|
||||
|
||||
test('.parse() ignores dart: imports', () {
|
||||
var map = new ExportMap.parse(
|
||||
[Uri.parse('dart:async')],
|
||||
pathos.join(tempDir, 'packages'));
|
||||
expect(map.exports, isEmpty);
|
||||
});
|
||||
});
|
||||
|
||||
group('Export', () {
|
||||
test('normalizes hide and show', () {
|
||||
expect(new Export('', '', show: ['x', 'y'], hide: ['y', 'z']),
|
||||
equals(new Export('', '', show: ['x'])));
|
||||
});
|
||||
|
||||
test("doesn't care about the order of show or hide", () {
|
||||
expect(new Export('', '', show: ['x', 'y']),
|
||||
equals(new Export('', '', show: ['y', 'x'])));
|
||||
expect(new Export('', '', hide: ['x', 'y']),
|
||||
equals(new Export('', '', hide: ['y', 'x'])));
|
||||
});
|
||||
|
||||
test('with no combinators considers anything visible', () {
|
||||
var export = new Export('', '');
|
||||
expect(export.isMemberVisible('x'), isTrue);
|
||||
expect(export.isMemberVisible('y'), isTrue);
|
||||
expect(export.isMemberVisible('z'), isTrue);
|
||||
});
|
||||
|
||||
test('with hide combinators considers anything not hidden visible', () {
|
||||
var export = new Export('', '', hide: ['x', 'y']);
|
||||
expect(export.isMemberVisible('x'), isFalse);
|
||||
expect(export.isMemberVisible('y'), isFalse);
|
||||
expect(export.isMemberVisible('z'), isTrue);
|
||||
});
|
||||
|
||||
test('with show combinators considers anything not shown invisible', () {
|
||||
var export = new Export('', '', show: ['x', 'y']);
|
||||
expect(export.isMemberVisible('x'), isTrue);
|
||||
expect(export.isMemberVisible('y'), isTrue);
|
||||
expect(export.isMemberVisible('z'), isFalse);
|
||||
});
|
||||
|
||||
test('composing uses the parent exporter and child path', () {
|
||||
expect(new Export('exporter1.dart', 'path1.dart')
|
||||
.compose(new Export('exporter2.dart', 'path2.dart')),
|
||||
equals(new Export('exporter1.dart', 'path2.dart')));
|
||||
});
|
||||
|
||||
test('composing show . show takes the intersection', () {
|
||||
expect(new Export('', '', show: ['x', 'y'])
|
||||
.compose(new Export('', '', show: ['y', 'z'])),
|
||||
equals(new Export('', '', show: ['y'])));
|
||||
});
|
||||
|
||||
test('composing show . hide takes the difference', () {
|
||||
expect(new Export('', '', show: ['x', 'y'])
|
||||
.compose(new Export('', '', hide: ['y', 'z'])),
|
||||
equals(new Export('', '', show: ['x'])));
|
||||
});
|
||||
|
||||
test('composing hide . show takes the reverse difference', () {
|
||||
expect(new Export('', '', hide: ['x', 'y'])
|
||||
.compose(new Export('', '', show: ['y', 'z'])),
|
||||
equals(new Export('', '', show: ['z'])));
|
||||
});
|
||||
|
||||
test('composing hide . hide takes the union', () {
|
||||
expect(new Export('', '', hide: ['x', 'y'])
|
||||
.compose(new Export('', '', hide: ['y', 'z'])),
|
||||
equals(new Export('', '', hide: ['x', 'y', 'z'])));
|
||||
});
|
||||
|
||||
test('merging requires identical exporters and paths', () {
|
||||
expect(() => new Export('exporter1.dart', '')
|
||||
.merge(new Export('exporter2.dart', '')),
|
||||
throwsA(isArgumentError));
|
||||
expect(() => new Export('', 'path1.dart')
|
||||
.merge(new Export('', 'path2.dart')),
|
||||
throwsA(isArgumentError));
|
||||
expect(new Export('', '').merge(new Export('', '')),
|
||||
equals(new Export('', '')));
|
||||
});
|
||||
|
||||
test('merging show + show takes the union', () {
|
||||
expect(new Export('', '', show: ['x', 'y'])
|
||||
.merge(new Export('', '', show: ['y', 'z'])),
|
||||
equals(new Export('', '', show: ['x', 'y', 'z'])));
|
||||
});
|
||||
|
||||
test('merging show + hide takes the difference', () {
|
||||
expect(new Export('', '', show: ['x', 'y'])
|
||||
.merge(new Export('', '', hide: ['y', 'z'])),
|
||||
equals(new Export('', '', hide: ['z'])));
|
||||
});
|
||||
|
||||
test('merging hide + show takes the difference', () {
|
||||
expect(new Export('', '', hide: ['x', 'y'])
|
||||
.merge(new Export('', '', show: ['y', 'z'])),
|
||||
equals(new Export('', '', hide: ['x'])));
|
||||
});
|
||||
|
||||
test('merging hide + hide takes the intersection', () {
|
||||
expect(new Export('', '', hide: ['x', 'y'])
|
||||
.merge(new Export('', '', hide: ['y', 'z'])),
|
||||
equals(new Export('', '', hide: ['y'])));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ExportMap parse(List<String> libraries) {
|
||||
return new ExportMap.parse(
|
||||
libraries.map(libPath)
|
||||
.map(pathToFileUri),
|
||||
pathos.join(tempDir, 'packages'));
|
||||
}
|
||||
|
||||
void createLibrary(String name, [String contents]) {
|
||||
if (contents == null) contents = '';
|
||||
new Directory(pathos.dirname(libPath(name))).createSync(recursive: true);
|
||||
new File(libPath(name)).writeAsStringSync('''
|
||||
library ${pathos.basename(name)};
|
||||
$contents
|
||||
''');
|
||||
}
|
||||
|
||||
String libPath(String name) => pathos.normalize(pathos.join(tempDir, name));
|
||||
|
||||
void createTempDir() {
|
||||
tempDir = new Directory('').createTempSync().path;
|
||||
new Directory(pathos.join(tempDir, 'packages')).createSync();
|
||||
}
|
||||
|
||||
void deleteTempDir() {
|
||||
new Directory(tempDir).deleteSync(recursive: true);
|
||||
}
|
45
sdk/lib/_internal/dartdoc/test/utils_test.dart
Normal file
45
sdk/lib/_internal/dartdoc/test/utils_test.dart
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:unittest/unittest.dart';
|
||||
|
||||
import '../lib/src/dartdoc/utils.dart';
|
||||
|
||||
void main() {
|
||||
group('countOccurrences', () {
|
||||
test('empty text returns 0', () {
|
||||
expect(countOccurrences('', 'needle'), equals(0));
|
||||
});
|
||||
|
||||
test('one occurrence', () {
|
||||
expect(countOccurrences('bananarama', 'nara'), equals(1));
|
||||
});
|
||||
|
||||
test('multiple occurrences', () {
|
||||
expect(countOccurrences('bananarama', 'a'), equals(5));
|
||||
});
|
||||
|
||||
test('overlapping matches do not count', () {
|
||||
expect(countOccurrences('bananarama', 'ana'), equals(1));
|
||||
});
|
||||
});
|
||||
|
||||
group('repeat', () {
|
||||
test('zero times returns an empty string', () {
|
||||
expect(repeat('ba', 0), isEmpty);
|
||||
});
|
||||
|
||||
test('one time returns the string', () {
|
||||
expect(repeat('ba', 1), equals('ba'));
|
||||
});
|
||||
|
||||
test('multiple times', () {
|
||||
expect(repeat('ba', 3), equals('bababa'));
|
||||
});
|
||||
|
||||
test('multiple times with a separator', () {
|
||||
expect(repeat('ba', 3, separator: ' '), equals('ba ba ba'));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -17,6 +17,7 @@ library apidoc;
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:json' as json;
|
||||
import 'dart:uri';
|
||||
|
||||
import 'html_diff.dart';
|
||||
|
||||
|
@ -25,6 +26,7 @@ import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
|
|||
import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
|
||||
import '../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart';
|
||||
import '../../sdk/lib/_internal/libraries.dart';
|
||||
import 'package:pathos/path.dart' as pathos;
|
||||
|
||||
HtmlDiff _diff;
|
||||
|
||||
|
@ -37,7 +39,7 @@ void main() {
|
|||
|
||||
List<String> excludedLibraries = <String>[];
|
||||
List<String> includedLibraries = <String>[];
|
||||
Path packageRoot;
|
||||
String packageRoot;
|
||||
String version;
|
||||
|
||||
// Parse the command-line arguments.
|
||||
|
@ -65,7 +67,7 @@ void main() {
|
|||
} else if (arg.startsWith('--out=')) {
|
||||
outputDir = new Path(arg.substring('--out='.length));
|
||||
} else if (arg.startsWith('--package-root=')) {
|
||||
packageRoot = new Path(arg.substring('--package-root='.length));
|
||||
packageRoot = arg.substring('--package-root='.length);
|
||||
} else if (arg.startsWith('--version=')) {
|
||||
version = arg.substring('--version='.length);
|
||||
} else {
|
||||
|
@ -104,10 +106,10 @@ void main() {
|
|||
// TODO(johnniwinther): Libraries for the compilation seem to be more like
|
||||
// URIs. Perhaps Path should have a toURI() method.
|
||||
// Add all of the core libraries.
|
||||
final apidocLibraries = <Path>[];
|
||||
final apidocLibraries = <Uri>[];
|
||||
LIBRARIES.forEach((String name, LibraryInfo info) {
|
||||
if (info.documented) {
|
||||
apidocLibraries.add(new Path('dart:$name'));
|
||||
apidocLibraries.add(Uri.parse('dart:$name'));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -130,7 +132,7 @@ void main() {
|
|||
}
|
||||
|
||||
if (new File.fromPath(libPath).existsSync()) {
|
||||
apidocLibraries.add(libPath);
|
||||
apidocLibraries.add(_pathToFileUri(libPath.toNativePath()));
|
||||
includedLibraries.add(libName);
|
||||
} else {
|
||||
print('Warning: could not find package at $path');
|
||||
|
@ -147,7 +149,7 @@ void main() {
|
|||
|
||||
// TODO(amouravski): make apidoc use roughly the same flow as bin/dartdoc.
|
||||
Future.wait([copiedStatic, copiedApiDocStatic, htmlDiff])
|
||||
.then((_) => apidoc.documentLibraries( apidocLibraries, libPath,
|
||||
.then((_) => apidoc.documentLibraries(apidocLibraries, libPath,
|
||||
packageRoot))
|
||||
.then((_) => compileScript(mode, outputDir, libPath))
|
||||
.then((_) => print(apidoc.status))
|
||||
|
@ -447,3 +449,14 @@ class Apidoc extends Dartdoc {
|
|||
return a(memberUrl(member), memberName);
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts a local path string to a `file:` [Uri]. */
|
||||
Uri _pathToFileUri(String path) {
|
||||
path = pathos.absolute(path);
|
||||
if (Platform.operatingSystem != 'windows') {
|
||||
return Uri.parse('file://$path');
|
||||
} else {
|
||||
return Uri.parse('file:///${path.replaceAll("\\", "/")}');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue