Support full dart2js output for dartdoc/apidoc.

Review URL: https://codereview.chromium.org//12446003

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@19537 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
johnniwinther@google.com 2013-03-06 08:43:33 +00:00
parent 9032ee670f
commit 43d6b6a84b
7 changed files with 176 additions and 218 deletions

View file

@ -9,7 +9,7 @@ import 'dart:collection' show LinkedHashMap;
import 'dart:io';
import 'dart:uri';
import '../../compiler.dart' as diagnostics;
import '../../compiler.dart' as api;
import '../elements/elements.dart';
import '../resolution/resolution.dart' show ResolverTask, ResolverVisitor;
import '../apiimpl.dart' show Compiler;
@ -84,8 +84,6 @@ Dart2JsTypeMirror _convertTypeToTypeMirror(
// TODO(johnniwinther): We need a mirror on malformed types.
return system.dynamicType;
}
_diagnosticListener.internalError(
"Unexpected type $type of kind ${type.kind}");
system.compiler.internalError("Unexpected type $type of kind ${type.kind}");
}
@ -193,113 +191,95 @@ String _getOperatorFromOperatorName(String name) {
return newName;
}
DiagnosticListener get _diagnosticListener {
return const Dart2JsDiagnosticListener();
}
class Dart2JsDiagnosticListener implements DiagnosticListener {
const Dart2JsDiagnosticListener();
void cancel(String reason, {node, token, instruction, element}) {
print(reason);
}
void log(message) {
print(message);
}
void internalError(String message,
{Node node, Token token, HInstruction instruction,
Element element}) {
cancel('Internal error: $message', node: node, token: token,
instruction: instruction, element: element);
}
void internalErrorOnElement(Element element, String message) {
internalError(message, element: element);
}
SourceSpan spanFromSpannable(Node node, [Uri uri]) {
// TODO(johnniwinther): implement this.
throw 'unimplemented';
}
void reportMessage(SourceSpan span, Diagnostic message,
diagnostics.Diagnostic kind) {
// TODO(johnniwinther): implement this.
throw 'unimplemented';
}
bool onDeprecatedFeature(Spannable span, String feature) {
// TODO(johnniwinther): implement this?
throw 'unimplemented';
}
}
//------------------------------------------------------------------------------
// Compilation implementation
//------------------------------------------------------------------------------
// TODO(johnniwinther): Support client configurable handlers/providers.
class Dart2JsCompilation implements Compilation {
Compiler _compiler;
final Uri cwd;
final SourceFileProvider provider;
// TODO(johnniwinther): Support client configurable providers.
Dart2JsCompilation(Path script, Path libraryRoot,
[Path packageRoot, List<String> opts = const <String>[]])
: cwd = getCurrentDirectory(),
provider = new SourceFileProvider() {
var handler = new FormattingDiagnosticHandler(provider);
var libraryUri = cwd.resolve('${libraryRoot}/');
var packageUri;
if (packageRoot != null) {
packageUri = cwd.resolve('${packageRoot}/');
} else {
packageUri = libraryUri;
}
_compiler = new Compiler(provider.readStringFromUri,
null,
handler.diagnosticHandler,
libraryUri, packageUri, opts);
var scriptUri = cwd.resolve(script.toString());
// TODO(johnniwinther): Detect file not found
_compiler.run(scriptUri);
/**
* Returns a future that completes to a non-null String when [script]
* has been successfully compiled.
*
* TODO(johnniwinther): The method is deprecated but here to support [Path]
* which is used through dartdoc.
*/
Future<String> compile(Path script,
Path libraryRoot,
{Path packageRoot,
List<String> options: const <String>[],
api.DiagnosticHandler diagnosticHandler}) {
Uri cwd = getCurrentDirectory();
SourceFileProvider provider = new SourceFileProvider();
if (diagnosticHandler == null) {
diagnosticHandler =
new FormattingDiagnosticHandler(provider).diagnosticHandler;
}
Dart2JsCompilation.library(List<Path> libraries, Path libraryRoot,
[Path packageRoot, List<String> opts = const <String>[]])
: cwd = getCurrentDirectory(),
provider = new SourceFileProvider() {
var libraryUri = cwd.resolve('${libraryRoot}/');
var packageUri;
if (packageRoot != null) {
packageUri = cwd.resolve('${packageRoot}/');
} else {
packageUri = libraryUri;
}
opts = new List<String>.from(opts);
opts.add('--analyze-signatures-only');
opts.add('--analyze-all');
_compiler = new Compiler(provider.readStringFromUri,
null,
silentDiagnosticHandler,
libraryUri, packageUri, opts);
var librariesUri = <Uri>[];
for (Path library in libraries) {
librariesUri.add(cwd.resolve(library.toString()));
// TODO(johnniwinther): Detect file not found
}
_compiler.librariesToAnalyzeWhenRun = librariesUri;
_compiler.run(null);
Uri scriptUri = cwd.resolve(script.toString());
Uri libraryUri = cwd.resolve('${libraryRoot}/');
Uri packageUri = null;
if (packageRoot != null) {
packageUri = cwd.resolve('${packageRoot}/');
}
MirrorSystem get mirrors => new Dart2JsMirrorSystem(_compiler);
Future<String> compileToJavaScript() =>
new Future<String>.immediate(_compiler.assembledCode);
return api.compile(scriptUri, libraryUri, packageUri,
provider.readStringFromUri, diagnosticHandler, options);
}
/**
* Analyzes set of libraries and provides a mirror system which can be used for
* static inspection of the source code.
*/
Future<MirrorSystem> analyze(List<Path> libraries,
Path libraryRoot,
{Path packageRoot,
List<String> options: const <String>[],
api.DiagnosticHandler diagnosticHandler}) {
Uri cwd = getCurrentDirectory();
SourceFileProvider provider = new SourceFileProvider();
if (diagnosticHandler == null) {
diagnosticHandler =
new FormattingDiagnosticHandler(provider).diagnosticHandler;
}
Uri libraryUri = cwd.resolve('${libraryRoot}/');
Uri packageUri = null;
if (packageRoot != null) {
packageUri = cwd.resolve('${packageRoot}/');
}
options = new List<String>.from(options);
options.add('--analyze-only');
options.add('--analyze-signatures-only');
options.add('--analyze-all');
bool compilationFailed = false;
void internalDiagnosticHandler(Uri uri, int begin, int end,
String message, api.Diagnostic kind) {
if (kind == api.Diagnostic.ERROR ||
kind == api.Diagnostic.CRASH) {
compilationFailed = true;
}
diagnosticHandler(uri, begin, end, message, kind);
}
// TODO(johnniwinther): Extract the following as an [analyze] method in
// [:compiler/compiler.dart:].
Compiler compiler = new Compiler(provider.readStringFromUri,
null,
internalDiagnosticHandler,
libraryUri, packageUri, options);
List<Uri> librariesUri = <Uri>[];
for (Path library in libraries) {
librariesUri.add(cwd.resolve(library.toString()));
}
compiler.librariesToAnalyzeWhenRun = librariesUri;
bool success = compiler.run(null);
if (success && !compilationFailed) {
return new Future<MirrorSystem>.immediate(
new Dart2JsMirrorSystem(compiler));
} else {
return new Future<MirrorSystem>.immediateError(
'Failed to create mirror system.');
}
}
//------------------------------------------------------------------------------
// Dart2Js specific extensions of mirror interfaces

View file

@ -11,44 +11,6 @@ import 'dart:uri';
// TODO(rnystrom): Use "package:" URL (#4968).
import 'dart2js_mirror.dart';
/**
* [Compilation] encapsulates the compilation of a program.
*/
abstract class Compilation {
/**
* Creates a new compilation which has [script] as its entry point.
*/
factory Compilation(Path script,
Path libraryRoot,
[Path packageRoot,
List<String> opts = const <String>[]]) {
return new Dart2JsCompilation(script, libraryRoot, packageRoot, opts);
}
/**
* Creates a new compilation which consists of a set of libraries, but which
* has no entry point. This compilation cannot generate output but can only
* be used for static inspection of the source code.
*/
factory Compilation.library(List<Path> libraries,
Path libraryRoot,
[Path packageRoot,
List<String> opts = const []]) {
return new Dart2JsCompilation.library(libraries, libraryRoot,
packageRoot, opts);
}
/**
* Returns the mirror system for this compilation.
*/
final MirrorSystem mirrors;
/**
* Returns a future for the compiled JavaScript code.
*/
Future<String> compileToJavaScript();
}
/**
* The main interface for the whole mirror system.
*/

35
sdk/lib/_internal/dartdoc/bin/dartdoc.dart Executable file → Normal file
View file

@ -232,23 +232,28 @@ main() {
cleanOutputDirectory(dartdoc.outputDir);
dartdoc.documentLibraries(entrypoints, libPath, pkgPath);
print('Analyzing sources');
Future documented = dartdoc.documentLibraries(entrypoints, libPath, pkgPath);
Future compiled = compileScript(dartdoc.mode, dartdoc.outputDir, libPath);
Future filesCopied = copyDirectory(scriptDir.append('../static'),
dartdoc.outputDir);
documented.then((_) {
Future compiled = compileScript(dartdoc.mode, dartdoc.outputDir, libPath);
Future filesCopied = copyDirectory(scriptDir.append('../static'),
dartdoc.outputDir);
Future.wait([compiled, filesCopied]).then((futureStatus) {
Future.wait([compiled, filesCopied]).then((_) {
dartdoc.cleanup();
if (dartdoc.totalLibraries + dartdoc.totalTypes +
dartdoc.totalMembers == 0) {
print('Nothing was documented!');
exit(1);
} else {
print('Documented ${dartdoc.totalLibraries} libraries, '
'${dartdoc.totalTypes} types, and ${dartdoc.totalMembers} '
'members.');
}
});
}, onError: (AsyncError asyncError) {
print('Generation failed: ${asyncError.error}');
dartdoc.cleanup();
if (dartdoc.totalLibraries + dartdoc.totalTypes +
dartdoc.totalMembers == 0) {
print('Nothing was documented!');
exit(1);
} else {
print('Documented ${dartdoc.totalLibraries} libraries, '
'${dartdoc.totalTypes} types, and ${dartdoc.totalMembers} '
'members.');
}
});
}

View file

@ -29,7 +29,6 @@ import 'classify.dart';
import 'universe_serializer.dart';
import 'markdown.dart' as md;
import 'src/json_serializer.dart' as json_serializer;
import '../../compiler/implementation/scanner/scannerlib.dart' as dart2js;
import '../../libraries.dart';
import 'src/dartdoc/nav.dart';
@ -133,13 +132,16 @@ Future compileScript(int mode, Path outputDir, Path libPath) {
'lib/_internal/dartdoc/lib/src/client/client-$clientScript.dart');
var jsPath = outputDir.append('client-$clientScript.js');
var compilation = new Compilation(
dartPath, libPath, null, const <String>['--categories=Client,Server']);
return compilation.compileToJavaScript().then((jsCode) {
writeString(new File.fromPath(jsPath), jsCode);
return null;
var completer = new Completer<bool>();
Future<String> result = dart2js.compile(
dartPath, libPath, options: const <String>['--categories=Client,Server']);
result.then((jsCode) {
if (jsCode != null) {
writeString(new File.fromPath(jsPath), jsCode);
}
completer.complete(jsCode != null);
});
return completer.future;
}
/**
@ -369,22 +371,27 @@ class Dartdoc {
return content;
}
void documentEntryPoint(Path entrypoint, Path libPath, Path pkgPath) {
final compilation = new Compilation(entrypoint, libPath, pkgPath,
COMPILER_OPTIONS);
_document(compilation);
Future documentEntryPoint(Path entrypoint, Path libPath, Path pkgPath) {
return documentLibraries(<Path>[entrypoint], libPath, pkgPath);
}
void documentLibraries(List<Path> libraryList, Path libPath, Path pkgPath) {
final compilation = new Compilation.library(libraryList, libPath, pkgPath,
COMPILER_OPTIONS);
_document(compilation);
Future documentLibraries(List<Path> libraryList, Path libPath, Path pkgPath) {
Completer completer = new Completer();
Future<MirrorSystem> result = dart2js.analyze(libraryList, libPath,
packageRoot: pkgPath, options: COMPILER_OPTIONS);
result.then((MirrorSystem mirrors) {
_document(mirrors);
completer.complete(true);
}, onError: (AsyncError error) {
completer.completeError(error.error);
});
return completer.future;
}
void _document(Compilation compilation) {
void _document(MirrorSystem mirrors) {
// Sort the libraries by name (not key).
_sortedLibraries = new List<LibraryMirror>.from(
compilation.mirrors.libraries.values.where(shouldIncludeLibrary));
mirrors.libraries.values.where(shouldIncludeLibrary));
_sortedLibraries.sort((x, y) {
return displayName(x).toUpperCase().compareTo(
displayName(y).toUpperCase());
@ -441,7 +448,7 @@ class Dartdoc {
write(json_serializer.serialize(packageManifest));
endFile();
}
MdnComment lookupMdnComment(Mirror mirror) => null;
void startFile(String path) {

View file

@ -4,6 +4,7 @@
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
import 'dart:io';
@ -38,11 +39,14 @@ main() {
var dirPath = scriptPath.directoryPath;
var libPath = dirPath.join(new Path('../../../sdk/'));
var inputPath = dirPath.join(new Path('mirrors_helper.dart'));
var compilation = new Compilation.library([inputPath], libPath, null,
<String>['--preserve-comments']);
Expect.isNotNull(compilation, "No compilation created");
var result = analyze([inputPath], libPath,
options: <String>['--preserve-comments']);
result.then((MirrorSystem mirrors) {
test(mirrors);
});
}
var mirrors = compilation.mirrors;
void test(MirrorSystem mirrors) {
Expect.isNotNull(mirrors, "No mirror system returned from compilation");
var libraries = mirrors.libraries;

View file

@ -35,7 +35,7 @@ void main() {
List<String> excludedLibraries = <String>[];
List<String> includedLibraries = <String>[];
var pkgPath;
Path pkgPath;
String version;
// Parse the command-line arguments.
@ -63,7 +63,7 @@ void main() {
} else if (arg.startsWith('--out=')) {
outputDir = new Path(arg.substring('--out='.length));
} else if (arg.startsWith('--pkg=')) {
pkgPath = arg.substring('--pkg='.length);
pkgPath = new Path(arg.substring('--pkg='.length));
} else if (arg.startsWith('--version=')) {
version = arg.substring('--version='.length);
} else {
@ -93,9 +93,8 @@ void main() {
final mdn = json.parse(mdnFile.readAsStringSync());
print('Cross-referencing dart:html...');
HtmlDiff.initialize(libPath);
_diff = new HtmlDiff(printWarnings:false);
_diff.run();
Future htmlDiff = _diff.run(libPath);
// Process libraries.
@ -147,12 +146,18 @@ void main() {
apidoc.includeApi = true;
apidoc.includedLibraries = includedLibraries;
Future.wait([copiedStatic, copiedApiDocStatic]).then((_) {
apidoc.documentLibraries(apidocLibraries, libPath, pkgPath);
Future.wait([copiedStatic, copiedApiDocStatic, htmlDiff]).then((_) {
Future<bool> documented =
apidoc.documentLibraries(apidocLibraries, libPath, pkgPath);
final compiled = doc.compileScript(mode, outputDir, libPath);
documented.then((_) {
final compiled = doc.compileScript(mode, outputDir, libPath);
Future.wait([compiled, copiedStatic, copiedApiDocStatic]).then((_) {
Future.wait([compiled]).then((_) {
apidoc.cleanup();
});
}, onError: (AsyncError asyncError) {
print('Generation failed: ${asyncError.error}');
apidoc.cleanup();
});
});
@ -328,7 +333,7 @@ class Apidoc extends doc.Dartdoc {
}
}
doc.MdnComment lookupMdnComment(Mirror mirror) {
doc.MdnComment lookupMdnComment(Mirror mirror) {
if (mirror is TypeMirror) {
return includeMdnTypeComment(mirror);
} else if (mirror is MemberMirror) {
@ -383,7 +388,7 @@ class Apidoc extends doc.Dartdoc {
* Gets the MDN-scraped docs for [member], or `null` if this type isn't
* scraped from MDN.
*/
MdnComment includeMdnMemberComment(MemberMirror member) {
doc.MdnComment includeMdnMemberComment(MemberMirror member) {
var library = findLibrary(member);
var memberString = '';
if (HTML_LIBRARY_NAMES.contains(doc.displayName(library))) {

View file

@ -17,6 +17,7 @@ import 'lib/metadata.dart';
import '../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart';
import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
import '../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
// TODO(amouravski): There is currently magic that looks at dart:* libraries
// rather than the declared library names. This changed due to recent syntax
@ -69,23 +70,8 @@ class HtmlDiff {
/** If true, then print warning messages. */
final bool _printWarnings;
static Compilation _compilation;
static MirrorSystem _mirrors;
static LibraryMirror dom;
/**
* Perform static initialization of [world]. This should be run before
* calling [HtmlDiff.run].
*/
static void initialize(Path libDir) {
var paths = <Path>[];
for (var libraryName in HTML_LIBRARY_NAMES) {
paths.add(new Path(libraryName));
}
_compilation = new Compilation.library(paths, libDir);
_mirrors = _compilation.mirrors;
}
HtmlDiff({bool printWarnings: false}) :
_printWarnings = printWarnings,
htmlToDom = new Map<String, Set<String>>(),
@ -103,24 +89,33 @@ class HtmlDiff {
* should be initialized (via [parseOptions] and [initializeWorld]) and
* [HtmlDiff.initialize] should be called.
*/
void run() {
for (var libraryName in HTML_DECLARED_NAMES) {
var library = _mirrors.libraries[libraryName];
if (library == null) {
warn('Could not find $libraryName');
return;
}
for (ClassMirror type in library.classes.values) {
final domTypes = htmlToDomTypes(type);
if (domTypes.isEmpty) continue;
htmlTypesToDom.putIfAbsent(type.qualifiedName,
() => new Set()).addAll(domTypes);
type.members.forEach(
(_, m) => _addMemberDiff(m, domTypes, library.simpleName));
}
Future run(Path libDir) {
var result = new Completer();
var paths = <Path>[];
for (var libraryName in HTML_LIBRARY_NAMES) {
paths.add(new Path(libraryName));
}
analyze(paths, libDir).then((MirrorSystem mirrors) {
for (var libraryName in HTML_DECLARED_NAMES) {
var library = mirrors.libraries[libraryName];
if (library == null) {
warn('Could not find $libraryName');
result.complete(false);
}
for (ClassMirror type in library.classes.values) {
final domTypes = htmlToDomTypes(type);
if (domTypes.isEmpty) continue;
htmlTypesToDom.putIfAbsent(type.qualifiedName,
() => new Set()).addAll(domTypes);
type.members.forEach(
(_, m) => _addMemberDiff(m, domTypes, library.simpleName));
}
}
result.complete(true);
});
return result.future;
}
/**