Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 library pub.dart2js_transformer; | 5 library pub.dart2js_transformer; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'package:analyzer_experimental/analyzer.dart'; | 10 import 'package:analyzer_experimental/analyzer.dart'; |
| 11 import 'package:barback/barback.dart'; | 11 import 'package:barback/barback.dart'; |
| 12 import 'package:path/path.dart' as path; | 12 import 'package:path/path.dart' as path; |
| 13 | 13 |
| 14 import '../../../../compiler/implementation/source_file_provider.dart' | 14 import '../../../../compiler/compiler.dart' as compiler; |
| 15 show SourceFileProvider; | 15 import '../../../../compiler/implementation/dart2js.dart' |
| 16 show AbortLeg; | |
| 16 import '../../../../compiler/implementation/source_file.dart'; | 17 import '../../../../compiler/implementation/source_file.dart'; |
| 17 import '../barback.dart'; | 18 import '../barback.dart'; |
| 18 import '../dart.dart' as dart; | 19 import '../dart.dart' as dart; |
| 19 import '../io.dart'; | 20 import '../io.dart'; |
| 20 import '../package.dart'; | 21 import '../package.dart'; |
| 21 import '../package_graph.dart'; | 22 import '../package_graph.dart'; |
| 22 | 23 |
| 23 /// A [Transformer] that uses dart2js's library API to transform Dart | 24 /// A [Transformer] that uses dart2js's library API to transform Dart |
| 24 /// entrypoints in "web" to JavaScript. | 25 /// entrypoints in "web" to JavaScript. |
| 25 class Dart2JSTransformer extends Transformer { | 26 class Dart2JSTransformer extends Transformer { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 39 stopwatch.start(); | 40 stopwatch.start(); |
| 40 | 41 |
| 41 return transform.primaryInput.readAsString().then((code) { | 42 return transform.primaryInput.readAsString().then((code) { |
| 42 try { | 43 try { |
| 43 if (!dart.isEntrypoint(parseCompilationUnit(code))) return; | 44 if (!dart.isEntrypoint(parseCompilationUnit(code))) return; |
| 44 } on AnalyzerErrorGroup catch (e) { | 45 } on AnalyzerErrorGroup catch (e) { |
| 45 transform.logger.error(e.message); | 46 transform.logger.error(e.message); |
| 46 return; | 47 return; |
| 47 } | 48 } |
| 48 | 49 |
| 49 var provider = new _BarbackSourceFileProvider(_graph, transform); | 50 var provider = new _BarbackInputProvider(_graph, transform); |
| 50 | 51 |
| 51 // Create a "path" to the entrypoint script. The entrypoint may not | 52 // Create a "path" to the entrypoint script. The entrypoint may not |
| 52 // actually be on disk, but this gives dart2js a root to resolve | 53 // actually be on disk, but this gives dart2js a root to resolve |
| 53 // relative paths against. | 54 // relative paths against. |
| 54 var id = transform.primaryInput.id; | 55 var id = transform.primaryInput.id; |
| 55 var entrypoint = path.url.join( | 56 var entrypoint = path.url.join( |
| 56 path.toUri(_graph.packages[id.package].dir).path, | 57 path.toUri(_graph.packages[id.package].dir).path, |
| 57 id.path); | 58 id.path); |
| 58 | 59 |
| 59 var packageRoot = path.join(_graph.entrypoint.root.dir, "packages"); | 60 var packageRoot = path.join(_graph.entrypoint.root.dir, "packages"); |
| 60 | 61 |
| 61 // TODO(rnystrom): Should have more sophisticated error-handling here. | 62 // TODO(rnystrom): Should have more sophisticated error-handling here. |
| 62 // Need to report compile errors to the user in an easily visible way. | 63 // Need to report compile errors to the user in an easily visible way. |
| 63 // Need to make sure paths in errors are mapped to the original source | 64 // Need to make sure paths in errors are mapped to the original source |
| 64 // path so they can understand them. | 65 // path so they can understand them. |
| 65 return dart.compile(entrypoint, | 66 return dart.compile(entrypoint, |
| 66 packageRoot: packageRoot, provider: provider).then((js) { | 67 packageRoot: packageRoot, |
| 68 inputProvider: provider.readStringFromUri, | |
| 69 diagnosticHandler: provider.handleDiagnostic).then((js) { | |
| 67 var id = transform.primaryInput.id.changeExtension(".dart.js"); | 70 var id = transform.primaryInput.id.changeExtension(".dart.js"); |
| 68 transform.addOutput(new Asset.fromString(id, js)); | 71 transform.addOutput(new Asset.fromString(id, js)); |
| 69 | 72 |
| 70 stopwatch.stop(); | 73 stopwatch.stop(); |
| 71 transform.logger.info("Generated $id (${js.length} characters) in " | 74 transform.logger.info("Generated $id (${js.length} characters) in " |
| 72 "${stopwatch.elapsed}"); | 75 "${stopwatch.elapsed}"); |
| 73 }); | 76 }); |
| 74 }); | 77 }); |
| 75 } | 78 } |
| 76 } | 79 } |
| 77 | 80 |
| 78 /// A [SourceFileProvider] that dart2js will use to load files that are | 81 /// Defines methods implementig [CompilerInputProvider] and [DiagnosticHandler] |
| 79 /// produced by Barback. | 82 /// for dart2js to use to load files from Barback and report errors. |
| 80 class _BarbackSourceFileProvider implements SourceFileProvider { | 83 /// |
| 84 /// Note that most of the implementation of diagnostic handling here was | |
| 85 /// copied from dart2js. The primary difference is that it uses barback's | |
|
nweiz
2013/10/03 21:39:14
Copied from where in dart2js in particular?
Bob Nystrom
2013/10/03 21:48:57
Mentioned class.
| |
| 86 /// logging code and, more importantly, it handles missing source files more | |
| 87 /// gracefully. | |
| 88 class _BarbackInputProvider { | |
| 81 final PackageGraph _graph; | 89 final PackageGraph _graph; |
| 82 final Transform _transform; | 90 final Transform _transform; |
| 83 | 91 |
| 92 var _isAborting = false; | |
|
nweiz
2013/10/03 21:39:14
Document this. Just saying it's copied from dart2j
Bob Nystrom
2013/10/03 21:48:57
Done.
| |
| 93 | |
| 84 /// The map of previously loaded files. | 94 /// The map of previously loaded files. |
| 85 /// | 95 /// |
| 86 /// dart2js uses this to avoid loading the same file multiple times. | 96 /// Used to show where an error occurred in a source file. |
| 87 final sourceFiles = new Map<String, SourceFile>(); | 97 final _sourceFiles = new Map<String, SourceFile>(); |
| 88 | 98 |
| 89 _BarbackSourceFileProvider(this._graph, this._transform); | 99 // TODO(rnystrom): Make these configurable. |
| 100 var _showWarnings = true; | |
| 101 var _showHints = true; | |
| 102 var _verbose = false; | |
| 103 var _throwOnError = false; | |
| 90 | 104 |
| 105 compiler.Diagnostic _lastKind = null; | |
| 106 | |
| 107 static final int _FATAL = | |
| 108 compiler.Diagnostic.CRASH.ordinal | | |
| 109 compiler.Diagnostic.ERROR.ordinal; | |
| 110 static final int _INFO = | |
| 111 compiler.Diagnostic.INFO.ordinal | | |
| 112 compiler.Diagnostic.VERBOSE_INFO.ordinal; | |
| 113 | |
| 114 _BarbackInputProvider(this._graph, this._transform); | |
| 115 | |
| 116 /// A [CompilerInputProvider] for dart2js. | |
| 91 Future<String> readStringFromUri(Uri resourceUri) { | 117 Future<String> readStringFromUri(Uri resourceUri) { |
| 92 // We only expect to get absolute "file:" URLs from dart2js. | 118 // We only expect to get absolute "file:" URLs from dart2js. |
| 93 assert(resourceUri.isAbsolute); | 119 assert(resourceUri.isAbsolute); |
| 94 assert(resourceUri.scheme == "file"); | 120 assert(resourceUri.scheme == "file"); |
| 95 | 121 |
| 96 var sourcePath = path.fromUri(resourceUri); | 122 var sourcePath = path.fromUri(resourceUri); |
| 97 return _readResource(resourceUri).then((source) { | 123 return _readResource(resourceUri).then((source) { |
| 98 sourceFiles[resourceUri.toString()] = | 124 _sourceFiles[resourceUri.toString()] = |
| 99 new SourceFile(path.relative(sourcePath), source); | 125 new SourceFile(path.relative(sourcePath), source); |
| 100 return source; | 126 return source; |
| 101 }); | 127 }); |
| 102 } | 128 } |
| 103 | 129 |
| 104 // The default [SourceFileProvider] does this, so we'll do the same. | 130 /// A [DiagnosticHandler] for dart2js, loosely based on |
| 105 Future<String> call(Uri resourceUri) => readStringFromUri(resourceUri); | 131 /// [FormattingDiagnosticHandler]. |
| 132 void handleDiagnostic(Uri uri, int begin, int end, | |
| 133 String message, compiler.Diagnostic kind) { | |
| 134 // TODO(ahe): Remove this when source map is handled differently. | |
| 135 if (kind.name == "source map") return; | |
| 136 | |
| 137 if (_isAborting) return; | |
| 138 _isAborting = (kind == compiler.Diagnostic.CRASH); | |
| 139 | |
| 140 var isInfo = (kind.ordinal & _INFO) != 0; | |
| 141 if (isInfo && uri == null && kind != compiler.Diagnostic.INFO) { | |
| 142 if (!_verbose && kind == compiler.Diagnostic.VERBOSE_INFO) return; | |
| 143 _transform.logger.info(message); | |
| 144 return; | |
| 145 } | |
| 146 | |
| 147 // [_lastKind] records the previous non-INFO kind we saw. | |
| 148 // This is used to suppress info about a warning when warnings are | |
| 149 // suppressed, and similar for hints. | |
| 150 if (kind != compiler.Diagnostic.INFO) _lastKind = kind; | |
| 151 | |
| 152 var logFn; | |
| 153 if (kind == compiler.Diagnostic.ERROR) { | |
| 154 logFn = _transform.logger.error; | |
| 155 } else if (kind == compiler.Diagnostic.WARNING) { | |
| 156 if (!_showWarnings) return; | |
| 157 logFn = _transform.logger.warning; | |
| 158 } else if (kind == compiler.Diagnostic.HINT) { | |
| 159 if (!_showHints) return; | |
| 160 logFn = _transform.logger.warning; | |
| 161 } else if (kind == compiler.Diagnostic.CRASH) { | |
| 162 logFn = _transform.logger.error; | |
| 163 } else if (kind == compiler.Diagnostic.INFO) { | |
| 164 if (_lastKind == compiler.Diagnostic.WARNING && !_showWarnings) return; | |
| 165 if (_lastKind == compiler.Diagnostic.HINT && !_showHints) return; | |
| 166 logFn = _transform.logger.info; | |
| 167 } else { | |
| 168 throw 'Unknown kind: $kind (${kind.ordinal})'; | |
|
nweiz
2013/10/03 21:39:14
Don't throw a raw string.
Bob Nystrom
2013/10/03 21:48:57
Done.
| |
| 169 } | |
| 170 | |
| 171 var fatal = (kind.ordinal & _FATAL) != 0; | |
| 172 if (uri == null) { | |
| 173 assert(fatal); | |
| 174 logFn(message); | |
| 175 } else { | |
| 176 SourceFile file = _sourceFiles[uri.toString()]; | |
| 177 if (file == null) { | |
| 178 // We got a message before loading the file, so just report the message | |
| 179 // itself. | |
| 180 logFn('$uri: $message'); | |
| 181 } else { | |
| 182 logFn(file.getLocationMessage(message, begin, end, true, (i) => i)); | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 if (fatal && _throwOnError) { | |
| 187 _isAborting = true; | |
| 188 throw new AbortLeg(message); | |
| 189 } | |
| 190 } | |
| 106 | 191 |
| 107 Future<String> _readResource(Uri url) { | 192 Future<String> _readResource(Uri url) { |
| 108 // See if the path is within a package. If so, use Barback so we can use | 193 // See if the path is within a package. If so, use Barback so we can use |
| 109 // generated Dart assets. | 194 // generated Dart assets. |
| 110 var id = _sourceUrlToId(url); | 195 var id = _sourceUrlToId(url); |
| 111 if (id != null) return _transform.readInputAsString(id); | 196 if (id != null) return _transform.readInputAsString(id); |
| 112 | 197 |
| 113 // If we get here, the path doesn't appear to be in a package, so we'll | 198 // If we get here, the path doesn't appear to be in a package, so we'll |
| 114 // skip Barback and just hit the file system. This will occur at the very | 199 // skip Barback and just hit the file system. This will occur at the very |
| 115 // least for dart2js's implementations of the core libraries. | 200 // least for dart2js's implementations of the core libraries. |
| 116 var sourcePath = path.fromUri(url); | 201 var sourcePath = path.fromUri(url); |
| 117 return new File(sourcePath).readAsString(); | 202 return new File(sourcePath).readAsString(); |
| 118 } | 203 } |
| 119 | 204 |
| 120 AssetId _sourceUrlToId(Uri url) { | 205 AssetId _sourceUrlToId(Uri url) { |
| 121 // See if it's a special path with "packages" or "assets" in it. | 206 // See if it's a special path with "packages" or "assets" in it. |
| 122 var id = specialUrlToId(url); | 207 var id = specialUrlToId(url); |
| 123 if (id != null) return id; | 208 if (id != null) return id; |
| 124 | 209 |
| 125 // See if it's a path within the root package. | 210 // See if it's a path within the root package. |
| 126 var rootDir = _graph.entrypoint.root.dir; | 211 var rootDir = _graph.entrypoint.root.dir; |
| 127 var sourcePath = path.fromUri(url); | 212 var sourcePath = path.fromUri(url); |
| 128 if (isBeneath(sourcePath, rootDir)) { | 213 if (isBeneath(sourcePath, rootDir)) { |
| 129 var relative = path.relative(sourcePath, from: rootDir); | 214 var relative = path.relative(sourcePath, from: rootDir); |
| 130 return new AssetId(_graph.entrypoint.root.name, relative); | 215 return new AssetId(_graph.entrypoint.root.name, relative); |
| 131 } | 216 } |
| 132 | 217 |
| 133 return null; | 218 return null; |
| 134 } | 219 } |
| 135 | |
| 136 // TODO(rnystrom): These are in the public SourceFileProvider interface, but | |
| 137 // aren't actually used by dart2js. Ideally, these would be taken out of | |
| 138 // SourceFileProvider (#13671). Until then, just shut up the warnings. | |
| 139 bool get isWindows => _notSupported(); | |
| 140 set isWindows(value) => _notSupported(); | |
| 141 Uri get cwd => _notSupported(); | |
| 142 set cwd(value) => _notSupported(); | |
| 143 int get dartCharactersRead => _notSupported(); | |
| 144 set dartCharactersRead(value) => _notSupported(); | |
| 145 set sourceFiles(value) => _notSupported(); | |
| 146 | |
| 147 _notSupported() => throw new UnsupportedError( | |
| 148 "This should be private in SourceFileProvider."); | |
| 149 } | 220 } |
| OLD | NEW |