Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'dart:collection' show HashSet, Queue; | 5 import 'dart:collection' show HashSet, Queue; |
| 6 import 'dart:convert' show JSON; | 6 import 'dart:convert' show BASE64, JSON, UTF8; |
| 7 import 'dart:io' show File; | 7 import 'dart:io' show File; |
| 8 import 'package:analyzer/dart/element/element.dart' show LibraryElement; | 8 import 'package:analyzer/dart/element/element.dart' show LibraryElement; |
| 9 import 'package:analyzer/analyzer.dart' | 9 import 'package:analyzer/analyzer.dart' |
| 10 show AnalysisError, CompilationUnit, ErrorSeverity; | 10 show AnalysisError, CompilationUnit, ErrorSeverity; |
| 11 import 'package:analyzer/file_system/file_system.dart' show ResourceProvider; | 11 import 'package:analyzer/file_system/file_system.dart' show ResourceProvider; |
| 12 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 12 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 13 import 'package:analyzer/src/generated/source.dart' show DartUriResolver; | 13 import 'package:analyzer/src/generated/source.dart' show DartUriResolver; |
| 14 import 'package:analyzer/src/generated/source_io.dart' | 14 import 'package:analyzer/src/generated/source_io.dart' |
| 15 show Source, SourceKind, UriResolver; | 15 show Source, SourceKind, UriResolver; |
| 16 import 'package:analyzer/src/summary/package_bundle_reader.dart' | 16 import 'package:analyzer/src/summary/package_bundle_reader.dart' |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 /// Whether to emit the source mapping file. | 154 /// Whether to emit the source mapping file. |
| 155 /// | 155 /// |
| 156 /// This supports debugging the original source code instead of the generated | 156 /// This supports debugging the original source code instead of the generated |
| 157 /// code. | 157 /// code. |
| 158 final bool sourceMap; | 158 final bool sourceMap; |
| 159 | 159 |
| 160 /// If [sourceMap] is emitted, this will emit a `sourceMappingUrl` comment | 160 /// If [sourceMap] is emitted, this will emit a `sourceMappingUrl` comment |
| 161 /// into the output JavaScript module. | 161 /// into the output JavaScript module. |
| 162 final bool sourceMapComment; | 162 final bool sourceMapComment; |
| 163 | 163 |
| 164 /// Whether to emit the source mapping file inline as a data url. | |
| 165 final bool inlineSourceMap; | |
| 166 | |
| 167 /// Wrap each module in an JavaScript eval call. | |
| 168 /// This makes debugging concatenated sources more productive due to the eval | |
| 169 /// script sourceURL directive. | |
| 170 final bool wrapInEval; | |
| 171 | |
| 164 /// Whether to emit a summary file containing API signatures. | 172 /// Whether to emit a summary file containing API signatures. |
| 165 /// | 173 /// |
| 166 /// This is required for a modular build process. | 174 /// This is required for a modular build process. |
| 167 final bool summarizeApi; | 175 final bool summarizeApi; |
| 168 | 176 |
| 169 /// The file extension for summaries. | 177 /// The file extension for summaries. |
| 170 final String summaryExtension; | 178 final String summaryExtension; |
| 171 | 179 |
| 172 /// Whether to preserve metdata only accessible via mirrors | 180 /// Whether to preserve metdata only accessible via mirrors |
| 173 final bool emitMetadata; | 181 final bool emitMetadata; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 201 /// Supporting the syntax: | 209 /// Supporting the syntax: |
| 202 /// * Chrome Canary (51) | 210 /// * Chrome Canary (51) |
| 203 /// * Firefox | 211 /// * Firefox |
| 204 /// | 212 /// |
| 205 /// Not yet supporting: | 213 /// Not yet supporting: |
| 206 /// * Atom (1.5.4) | 214 /// * Atom (1.5.4) |
| 207 /// * Electron (0.36.3) | 215 /// * Electron (0.36.3) |
| 208 // TODO(ochafik): Simplify this code when our target platforms catch up. | 216 // TODO(ochafik): Simplify this code when our target platforms catch up. |
| 209 final bool destructureNamedParams; | 217 final bool destructureNamedParams; |
| 210 | 218 |
| 219 /// Mapping from absolte file path to paths to use in source maps. | |
| 220 final Map<String, String> fileMappings; | |
| 221 | |
| 211 const CompilerOptions( | 222 const CompilerOptions( |
| 212 {this.sourceMap: true, | 223 {this.sourceMap: true, |
| 213 this.sourceMapComment: true, | 224 this.sourceMapComment: true, |
| 225 this.inlineSourceMap: false, | |
| 226 this.wrapInEval: false, | |
| 214 this.summarizeApi: true, | 227 this.summarizeApi: true, |
| 215 this.summaryExtension: 'sum', | 228 this.summaryExtension: 'sum', |
| 216 this.unsafeForceCompile: false, | 229 this.unsafeForceCompile: false, |
| 217 this.emitMetadata: false, | 230 this.emitMetadata: false, |
| 218 this.closure: false, | 231 this.closure: false, |
| 219 this.destructureNamedParams: false, | 232 this.destructureNamedParams: false, |
| 220 this.hoistInstanceCreation: true, | 233 this.hoistInstanceCreation: true, |
| 221 this.hoistSignatureTypes: false, | 234 this.hoistSignatureTypes: false, |
| 222 this.nameTypeTests: true, | 235 this.nameTypeTests: true, |
| 223 this.hoistTypeTests: true, | 236 this.hoistTypeTests: true, |
| 224 this.useAngular2Whitelist: false}); | 237 this.useAngular2Whitelist: false, |
| 238 this.fileMappings: const {}}); | |
| 225 | 239 |
| 226 CompilerOptions.fromArguments(ArgResults args) | 240 CompilerOptions.fromArguments(ArgResults args) |
| 227 : sourceMap = args['source-map'], | 241 : sourceMap = args['source-map'], |
| 228 sourceMapComment = args['source-map-comment'], | 242 sourceMapComment = args['source-map-comment'], |
| 243 inlineSourceMap = args['inline-source-map'], | |
| 244 wrapInEval = args['wrap-in-eval'], | |
| 229 summarizeApi = args['summarize'], | 245 summarizeApi = args['summarize'], |
| 230 summaryExtension = args['summary-extension'], | 246 summaryExtension = args['summary-extension'], |
| 231 unsafeForceCompile = args['unsafe-force-compile'], | 247 unsafeForceCompile = args['unsafe-force-compile'], |
| 232 emitMetadata = args['emit-metadata'], | 248 emitMetadata = args['emit-metadata'], |
| 233 closure = args['closure-experimental'], | 249 closure = args['closure-experimental'], |
| 234 destructureNamedParams = args['destructure-named-params'], | 250 destructureNamedParams = args['destructure-named-params'], |
| 235 hoistInstanceCreation = args['hoist-instance-creation'], | 251 hoistInstanceCreation = args['hoist-instance-creation'], |
| 236 hoistSignatureTypes = args['hoist-signature-types'], | 252 hoistSignatureTypes = args['hoist-signature-types'], |
| 237 nameTypeTests = args['name-type-tests'], | 253 nameTypeTests = args['name-type-tests'], |
| 238 hoistTypeTests = args['hoist-type-tests'], | 254 hoistTypeTests = args['hoist-type-tests'], |
| 239 useAngular2Whitelist = args['unsafe-angular2-whitelist']; | 255 useAngular2Whitelist = args['unsafe-angular2-whitelist'], |
| 256 fileMappings = _parseFileMappings(args['file-mapping']); | |
| 240 | 257 |
| 241 static void addArguments(ArgParser parser) { | 258 static void addArguments(ArgParser parser) { |
| 242 parser | 259 parser |
| 243 ..addFlag('summarize', help: 'emit an API summary file', defaultsTo: true) | 260 ..addFlag('summarize', help: 'emit an API summary file', defaultsTo: true) |
| 244 ..addOption('summary-extension', | 261 ..addOption('summary-extension', |
| 245 help: 'file extension for Dart summary files', | 262 help: 'file extension for Dart summary files', |
| 246 defaultsTo: 'sum', | 263 defaultsTo: 'sum', |
| 247 hide: true) | 264 hide: true) |
| 248 ..addFlag('source-map', help: 'emit source mapping', defaultsTo: true) | 265 ..addFlag('source-map', help: 'emit source mapping', defaultsTo: true) |
| 249 ..addFlag('source-map-comment', | 266 ..addFlag('source-map-comment', |
| 250 help: 'adds a sourceMappingURL comment to the end of the JS,\n' | 267 help: 'adds a sourceMappingURL comment to the end of the JS,\n' |
| 251 'disable if using X-SourceMap header', | 268 'disable if using X-SourceMap header', |
| 252 defaultsTo: true, | 269 defaultsTo: true, |
| 253 hide: true) | 270 hide: true) |
| 271 ..addFlag('inline-source-map', | |
| 272 help: 'emit source mapping inline', defaultsTo: false) | |
| 273 ..addFlag('wrap-in-eval', | |
| 274 help: 'wrap library definition in eval', defaultsTo: false) | |
| 254 ..addFlag('emit-metadata', | 275 ..addFlag('emit-metadata', |
| 255 help: 'emit metadata annotations queriable via mirrors', | 276 help: 'emit metadata annotations queriable via mirrors', |
| 256 defaultsTo: false) | 277 defaultsTo: false) |
| 257 ..addFlag('closure-experimental', | 278 ..addFlag('closure-experimental', |
| 258 help: 'emit Closure Compiler-friendly code (experimental)', | 279 help: 'emit Closure Compiler-friendly code (experimental)', |
| 259 defaultsTo: false) | 280 defaultsTo: false) |
| 260 ..addFlag('destructure-named-params', | 281 ..addFlag('destructure-named-params', |
| 261 help: 'Destructure named parameters', defaultsTo: false, hide: true) | 282 help: 'Destructure named parameters', defaultsTo: false, hide: true) |
| 262 ..addFlag('unsafe-force-compile', | 283 ..addFlag('unsafe-force-compile', |
| 263 help: 'Compile code even if it has errors. ಠ_ಠ\n' | 284 help: 'Compile code even if it has errors. ಠ_ಠ\n' |
| 264 'This has undefined behavior!', | 285 'This has undefined behavior!', |
| 265 defaultsTo: false, | 286 defaultsTo: false, |
| 266 hide: true) | 287 hide: true) |
| 267 ..addFlag('hoist-instance-creation', | 288 ..addFlag('hoist-instance-creation', |
| 268 help: 'Hoist the class type from generic instance creations', | 289 help: 'Hoist the class type from generic instance creations', |
| 269 defaultsTo: true, | 290 defaultsTo: true, |
| 270 hide: true) | 291 hide: true) |
| 271 ..addFlag('hoist-signature-types', | 292 ..addFlag('hoist-signature-types', |
| 272 help: 'Hoist types from class signatures', | 293 help: 'Hoist types from class signatures', |
| 273 defaultsTo: false, | 294 defaultsTo: false, |
| 274 hide: true) | 295 hide: true) |
| 275 ..addFlag('name-type-tests', | 296 ..addFlag('name-type-tests', |
| 276 help: 'Name types used in type tests', defaultsTo: true, hide: true) | 297 help: 'Name types used in type tests', defaultsTo: true, hide: true) |
| 277 ..addFlag('hoist-type-tests', | 298 ..addFlag('hoist-type-tests', |
| 278 help: 'Hoist types used in type tests', defaultsTo: true, hide: true) | 299 help: 'Hoist types used in type tests', defaultsTo: true, hide: true) |
| 279 ..addFlag('unsafe-angular2-whitelist', defaultsTo: false, hide: true); | 300 ..addFlag('unsafe-angular2-whitelist', defaultsTo: false, hide: true) |
| 301 ..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
| |
| 302 help: | |
| 303 '--file-mapping=/full/path/to/library.dart,to/library.dart uses\n' | |
| 304 'to/library.dart as the short_path for library.dart".', | |
| 305 allowMultiple: true, | |
| 306 splitCommas: false); | |
| 307 } | |
| 308 | |
| 309 static Map<String, String> _parseFileMappings(Iterable argument) { | |
| 310 var mappings = <String, String>{}; | |
| 311 for (var mapping in argument) { | |
| 312 var splitMapping = mapping.split(','); | |
| 313 if (splitMapping.length >= 2) { | |
| 314 mappings[path.absolute(splitMapping[0])] = splitMapping[1]; | |
| 315 } | |
| 316 } | |
| 317 return mappings; | |
| 280 } | 318 } |
| 281 } | 319 } |
| 282 | 320 |
| 283 /// A unit of Dart code that can be built into a single JavaScript module. | 321 /// A unit of Dart code that can be built into a single JavaScript module. |
| 284 class BuildUnit { | 322 class BuildUnit { |
| 285 /// The name of this module. | 323 /// The name of this module. |
| 286 final String name; | 324 final String name; |
| 287 | 325 |
| 288 /// All library names are relative to this path/prefix. | 326 /// All library names are relative to this path/prefix. |
| 289 final String libraryRoot; | 327 final String libraryRoot; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 355 sourceMap = sourceMapContext.sourceMap; | 393 sourceMap = sourceMapContext.sourceMap; |
| 356 printer = sourceMapContext; | 394 printer = sourceMapContext; |
| 357 } else { | 395 } else { |
| 358 printer = new JS.SimpleJavaScriptPrintingContext(); | 396 printer = new JS.SimpleJavaScriptPrintingContext(); |
| 359 } | 397 } |
| 360 | 398 |
| 361 var tree = transformModuleFormat(format, moduleTree); | 399 var tree = transformModuleFormat(format, moduleTree); |
| 362 tree.accept( | 400 tree.accept( |
| 363 new JS.Printer(opts, printer, localNamer: new JS.TemporaryNamer(tree))); | 401 new JS.Printer(opts, printer, localNamer: new JS.TemporaryNamer(tree))); |
| 364 | 402 |
| 365 if (options.sourceMap && options.sourceMapComment) { | 403 Map builtMap; |
| 366 var relativeMapUrl = path | 404 if (options.sourceMap && sourceMap != null) { |
| 367 .toUri(path.relative(path.fromUri(mapUrl), from: path.dirname(jsUrl))) | 405 builtMap = |
| 368 .toString(); | 406 placeSourceMap(sourceMap.build(jsUrl), mapUrl, options.fileMappings); |
| 369 assert(path.dirname(jsUrl) == path.dirname(mapUrl)); | 407 |
| 370 printer.emit('\n//# sourceMappingURL=$relativeMapUrl\n'); | 408 if (options.sourceMapComment) { |
| 409 var relativeMapUrl = path | |
| 410 .toUri( | |
| 411 path.relative(path.fromUri(mapUrl), from: path.dirname(jsUrl))) | |
| 412 .toString(); | |
| 413 assert(path.dirname(jsUrl) == path.dirname(mapUrl)); | |
| 414 printer.emit('\n//# sourceMappingURL='); | |
| 415 if (options.inlineSourceMap) { | |
| 416 var bytes = UTF8.encode(JSON.encode(builtMap)); | |
| 417 var base64 = BASE64.encode(bytes); | |
| 418 printer..emit('data:application/json;base64,')..emit(base64); | |
| 419 } else { | |
| 420 printer.emit(relativeMapUrl); | |
| 421 } | |
| 422 printer.emit('\n'); | |
| 423 } | |
| 371 } | 424 } |
| 372 | 425 |
| 373 Map builtMap; | |
| 374 if (sourceMap != null) { | |
| 375 builtMap = placeSourceMap(sourceMap.build(jsUrl), mapUrl); | |
| 376 } | |
| 377 return new JSModuleCode(printer.getText(), builtMap); | 426 return new JSModuleCode(printer.getText(), builtMap); |
| 378 } | 427 } |
| 379 | 428 |
| 380 /// Similar to [getCode] but immediately writes the resulting files. | 429 /// Similar to [getCode] but immediately writes the resulting files. |
| 381 /// | 430 /// |
| 382 /// If [mapPath] is not supplied but [options.sourceMap] is set, mapPath | 431 /// If [mapPath] is not supplied but [options.sourceMap] is set, mapPath |
| 383 /// will default to [jsPath].map. | 432 /// will default to [jsPath].map. |
| 384 void writeCodeSync(ModuleFormat format, String jsPath, [String mapPath]) { | 433 void writeCodeSync(ModuleFormat format, String jsPath) { |
| 385 if (mapPath == null) mapPath = jsPath + '.map'; | 434 String mapPath = jsPath + '.map'; |
| 386 var code = getCode(format, jsPath, mapPath); | 435 var code = getCode(format, jsPath, mapPath); |
| 387 new File(jsPath).writeAsStringSync(code.code); | 436 var c = code.code; |
| 388 if (code.sourceMap != null) { | 437 if (options.wrapInEval) { |
|
Jennifer Messerly
2016/09/13 23:00:33
this is not the right place for this. I'm not sure
| |
| 438 // Add sourceURL to improve the debugging experience. | |
| 439 c += '\n//# sourceURL=${name}.js\n'; | |
| 440 c = 'eval(${JSON.encode(c)});\n'; | |
| 441 } | |
| 442 new File(jsPath).writeAsStringSync(c); | |
| 443 if (code.sourceMap != null && !options.inlineSourceMap) { | |
| 389 new File(mapPath).writeAsStringSync(JSON.encode(code.sourceMap)); | 444 new File(mapPath).writeAsStringSync(JSON.encode(code.sourceMap)); |
| 390 } | 445 } |
| 391 } | 446 } |
| 392 } | 447 } |
| 393 | 448 |
| 394 /// The output of compiling a JavaScript module in a particular format. | 449 /// The output of compiling a JavaScript module in a particular format. |
| 395 class JSModuleCode { | 450 class JSModuleCode { |
| 396 /// The JavaScript code for this module. | 451 /// The JavaScript code for this module. |
| 397 /// | 452 /// |
| 398 /// If a [sourceMap] is available, this will include the `sourceMappingURL` | 453 /// If a [sourceMap] is available, this will include the `sourceMappingURL` |
| 399 /// comment at end of the file. | 454 /// comment at end of the file. |
| 400 final String code; | 455 final String code; |
| 401 | 456 |
| 402 /// The JSON of the source map, if generated, otherwise `null`. | 457 /// The JSON of the source map, if generated, otherwise `null`. |
| 403 /// | 458 /// |
| 404 /// The source paths will initially be absolute paths. They can be adjusted | 459 /// The source paths will initially be absolute paths. They can be adjusted |
| 405 /// using [placeSourceMap]. | 460 /// using [placeSourceMap]. |
| 406 final Map sourceMap; | 461 final Map sourceMap; |
| 407 | 462 |
| 408 JSModuleCode(this.code, this.sourceMap); | 463 JSModuleCode(this.code, this.sourceMap); |
| 409 } | 464 } |
| 410 | 465 |
| 411 /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath], | 466 /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath], |
| 412 /// and returns the new map. | 467 /// and returns the new map. |
| 413 // TODO(jmesserly): find a new home for this. | 468 // TODO(jmesserly): find a new home for this. |
| 414 Map placeSourceMap(Map sourceMap, String sourceMapPath) { | 469 Map placeSourceMap( |
| 470 Map sourceMap, String sourceMapPath, Map<String, String> fileMappings) { | |
| 415 var dir = path.dirname(sourceMapPath); | 471 var dir = path.dirname(sourceMapPath); |
| 472 var map = new Map.from(sourceMap); | |
| 473 var list = new List.from(map['sources']); | |
| 474 map['sources'] = list; | |
| 475 String transformUri(String uri) { | |
| 476 var match = fileMappings[path.absolute(uri)]; | |
| 477 if (match != null) return match; | |
| 416 | 478 |
| 417 var map = new Map.from(sourceMap); | 479 // Fall back to a relative path. |
| 418 List list = new List.from(map['sources']); | 480 return path.toUri(path.relative(path.fromUri(uri), from: dir)).toString(); |
| 419 map['sources'] = list; | 481 } |
| 420 String relative(String uri) => | 482 |
| 421 path.toUri(path.relative(path.fromUri(uri), from: dir)).toString(); | |
| 422 for (int i = 0; i < list.length; i++) { | 483 for (int i = 0; i < list.length; i++) { |
| 423 list[i] = relative(list[i]); | 484 list[i] = transformUri(list[i]); |
| 424 } | 485 } |
| 425 map['file'] = relative(map['file']); | 486 map['file'] = transformUri(map['file']); |
| 426 return map; | 487 return map; |
| 427 } | 488 } |
| OLD | NEW |