Chromium Code Reviews| Index: pkg/dev_compiler/lib/src/compiler/compiler.dart |
| diff --git a/pkg/dev_compiler/lib/src/compiler/compiler.dart b/pkg/dev_compiler/lib/src/compiler/compiler.dart |
| index b47ad2505d00328c0b6c2d803c8738dfa042f76b..4b2620cd6321d416c3298b08725906799959d99f 100644 |
| --- a/pkg/dev_compiler/lib/src/compiler/compiler.dart |
| +++ b/pkg/dev_compiler/lib/src/compiler/compiler.dart |
| @@ -3,7 +3,7 @@ |
| // BSD-style license that can be found in the LICENSE file. |
| import 'dart:collection' show HashSet, Queue; |
| -import 'dart:convert' show JSON; |
| +import 'dart:convert' show BASE64, JSON, UTF8; |
| import 'dart:io' show File; |
| import 'package:analyzer/dart/element/element.dart' show LibraryElement; |
| import 'package:analyzer/analyzer.dart' |
| @@ -161,6 +161,14 @@ class CompilerOptions { |
| /// into the output JavaScript module. |
| final bool sourceMapComment; |
| + /// Whether to emit the source mapping file inline as a data url. |
| + final bool inlineSourceMap; |
| + |
| + /// Wrap each module in an JavaScript eval call. |
| + /// This makes debugging concatenated sources more productive due to the eval |
| + /// script sourceURL directive. |
| + final bool wrapInEval; |
| + |
| /// Whether to emit a summary file containing API signatures. |
| /// |
| /// This is required for a modular build process. |
| @@ -208,9 +216,14 @@ class CompilerOptions { |
| // TODO(ochafik): Simplify this code when our target platforms catch up. |
| final bool destructureNamedParams; |
| + /// Mapping from absolte file path to paths to use in source maps. |
| + final Map<String, String> fileMappings; |
| + |
| const CompilerOptions( |
| {this.sourceMap: true, |
| this.sourceMapComment: true, |
| + this.inlineSourceMap: false, |
| + this.wrapInEval: false, |
| this.summarizeApi: true, |
| this.summaryExtension: 'sum', |
| this.unsafeForceCompile: false, |
| @@ -221,11 +234,14 @@ class CompilerOptions { |
| this.hoistSignatureTypes: false, |
| this.nameTypeTests: true, |
| this.hoistTypeTests: true, |
| - this.useAngular2Whitelist: false}); |
| + this.useAngular2Whitelist: false, |
| + this.fileMappings: const {}}); |
| CompilerOptions.fromArguments(ArgResults args) |
| : sourceMap = args['source-map'], |
| sourceMapComment = args['source-map-comment'], |
| + inlineSourceMap = args['inline-source-map'], |
| + wrapInEval = args['wrap-in-eval'], |
| summarizeApi = args['summarize'], |
| summaryExtension = args['summary-extension'], |
| unsafeForceCompile = args['unsafe-force-compile'], |
| @@ -236,7 +252,8 @@ class CompilerOptions { |
| hoistSignatureTypes = args['hoist-signature-types'], |
| nameTypeTests = args['name-type-tests'], |
| hoistTypeTests = args['hoist-type-tests'], |
| - useAngular2Whitelist = args['unsafe-angular2-whitelist']; |
| + useAngular2Whitelist = args['unsafe-angular2-whitelist'], |
| + fileMappings = _parseFileMappings(args['file-mapping']); |
| static void addArguments(ArgParser parser) { |
| parser |
| @@ -251,6 +268,10 @@ class CompilerOptions { |
| 'disable if using X-SourceMap header', |
| defaultsTo: true, |
| hide: true) |
| + ..addFlag('inline-source-map', |
| + help: 'emit source mapping inline', defaultsTo: false) |
| + ..addFlag('wrap-in-eval', |
| + help: 'wrap library definition in eval', defaultsTo: false) |
| ..addFlag('emit-metadata', |
| help: 'emit metadata annotations queriable via mirrors', |
| defaultsTo: false) |
| @@ -276,7 +297,24 @@ class CompilerOptions { |
| help: 'Name types used in type tests', defaultsTo: true, hide: true) |
| ..addFlag('hoist-type-tests', |
| help: 'Hoist types used in type tests', defaultsTo: true, hide: true) |
| - ..addFlag('unsafe-angular2-whitelist', defaultsTo: false, hide: true); |
| + ..addFlag('unsafe-angular2-whitelist', defaultsTo: false, hide: true) |
| + ..addOption('file-mapping', |
|
vsm
2016/09/13 22:08:20
Can you include an example of how this is used (e.
vsm
2016/09/13 22:17:32
This might make more sense as --bazel-mapping. Th
Jennifer Messerly
2016/09/13 22:43:39
yeah ... if some of these options are meant to go
|
| + help: |
| + '--file-mapping=/full/path/to/library.dart,to/library.dart uses\n' |
| + 'to/library.dart as the short_path for library.dart".', |
| + allowMultiple: true, |
| + splitCommas: false); |
| + } |
| + |
| + static Map<String, String> _parseFileMappings(Iterable argument) { |
| + var mappings = <String, String>{}; |
| + for (var mapping in argument) { |
| + var splitMapping = mapping.split(','); |
| + if (splitMapping.length >= 2) { |
| + mappings[path.absolute(splitMapping[0])] = splitMapping[1]; |
| + } |
| + } |
| + return mappings; |
| } |
| } |
| @@ -362,18 +400,29 @@ class JSModuleFile { |
| tree.accept( |
| new JS.Printer(opts, printer, localNamer: new JS.TemporaryNamer(tree))); |
| - if (options.sourceMap && options.sourceMapComment) { |
| - var relativeMapUrl = path |
| - .toUri(path.relative(path.fromUri(mapUrl), from: path.dirname(jsUrl))) |
| - .toString(); |
| - assert(path.dirname(jsUrl) == path.dirname(mapUrl)); |
| - printer.emit('\n//# sourceMappingURL=$relativeMapUrl\n'); |
| - } |
| - |
| Map builtMap; |
| - if (sourceMap != null) { |
| - builtMap = placeSourceMap(sourceMap.build(jsUrl), mapUrl); |
| + if (options.sourceMap && sourceMap != null) { |
| + builtMap = |
| + placeSourceMap(sourceMap.build(jsUrl), mapUrl, options.fileMappings); |
| + |
| + if (options.sourceMapComment) { |
| + var relativeMapUrl = path |
| + .toUri( |
| + path.relative(path.fromUri(mapUrl), from: path.dirname(jsUrl))) |
| + .toString(); |
| + assert(path.dirname(jsUrl) == path.dirname(mapUrl)); |
| + printer.emit('\n//# sourceMappingURL='); |
| + if (options.inlineSourceMap) { |
| + var bytes = UTF8.encode(JSON.encode(builtMap)); |
| + var base64 = BASE64.encode(bytes); |
| + printer..emit('data:application/json;base64,')..emit(base64); |
| + } else { |
| + printer.emit(relativeMapUrl); |
| + } |
| + printer.emit('\n'); |
| + } |
| } |
| + |
| return new JSModuleCode(printer.getText(), builtMap); |
| } |
| @@ -381,11 +430,17 @@ class JSModuleFile { |
| /// |
| /// If [mapPath] is not supplied but [options.sourceMap] is set, mapPath |
| /// will default to [jsPath].map. |
| - void writeCodeSync(ModuleFormat format, String jsPath, [String mapPath]) { |
| - if (mapPath == null) mapPath = jsPath + '.map'; |
| + void writeCodeSync(ModuleFormat format, String jsPath) { |
| + String mapPath = jsPath + '.map'; |
| var code = getCode(format, jsPath, mapPath); |
| - new File(jsPath).writeAsStringSync(code.code); |
| - if (code.sourceMap != null) { |
| + var c = code.code; |
| + if (options.wrapInEval) { |
|
Jennifer Messerly
2016/09/13 23:00:33
this is not the right place for this. I'm not sure
|
| + // Add sourceURL to improve the debugging experience. |
| + c += '\n//# sourceURL=${name}.js\n'; |
| + c = 'eval(${JSON.encode(c)});\n'; |
| + } |
| + new File(jsPath).writeAsStringSync(c); |
| + if (code.sourceMap != null && !options.inlineSourceMap) { |
| new File(mapPath).writeAsStringSync(JSON.encode(code.sourceMap)); |
| } |
| } |
| @@ -411,17 +466,23 @@ class JSModuleCode { |
| /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath], |
| /// and returns the new map. |
| // TODO(jmesserly): find a new home for this. |
| -Map placeSourceMap(Map sourceMap, String sourceMapPath) { |
| +Map placeSourceMap( |
| + Map sourceMap, String sourceMapPath, Map<String, String> fileMappings) { |
| var dir = path.dirname(sourceMapPath); |
| - |
| var map = new Map.from(sourceMap); |
| - List list = new List.from(map['sources']); |
| + var list = new List.from(map['sources']); |
| map['sources'] = list; |
| - String relative(String uri) => |
| - path.toUri(path.relative(path.fromUri(uri), from: dir)).toString(); |
| + String transformUri(String uri) { |
| + var match = fileMappings[path.absolute(uri)]; |
| + if (match != null) return match; |
| + |
| + // Fall back to a relative path. |
| + return path.toUri(path.relative(path.fromUri(uri), from: dir)).toString(); |
| + } |
| + |
| for (int i = 0; i < list.length; i++) { |
| - list[i] = relative(list[i]); |
| + list[i] = transformUri(list[i]); |
| } |
| - map['file'] = relative(map['file']); |
| + map['file'] = transformUri(map['file']); |
| return map; |
| } |