| 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 JSON; |
| 7 import 'dart:io' show File; | 7 import 'dart:io' show File; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' | 9 import 'package:analyzer/analyzer.dart' |
| 10 show AnalysisError, CompilationUnit, ErrorSeverity; | 10 show AnalysisError, CompilationUnit, ErrorSeverity; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 /// If that is not desired, the analysis context must be pre-configured using | 149 /// If that is not desired, the analysis context must be pre-configured using |
| 150 /// summaries before calling this method. | 150 /// summaries before calling this method. |
| 151 JSModuleFile compile(BuildUnit unit, CompilerOptions options) { | 151 JSModuleFile compile(BuildUnit unit, CompilerOptions options) { |
| 152 var trees = <CompilationUnit>[]; | 152 var trees = <CompilationUnit>[]; |
| 153 var errors = <AnalysisError>[]; | 153 var errors = <AnalysisError>[]; |
| 154 | 154 |
| 155 var librariesToCompile = new Queue<LibraryElement>(); | 155 var librariesToCompile = new Queue<LibraryElement>(); |
| 156 | 156 |
| 157 var compilingSdk = false; | 157 var compilingSdk = false; |
| 158 for (var sourcePath in unit.sources) { | 158 for (var sourcePath in unit.sources) { |
| 159 var sourceUri = Uri.parse(sourcePath); | 159 var sourceUri = _sourceToUri(sourcePath); |
| 160 if (sourceUri.scheme == '') { | 160 if (sourceUri.scheme == "dart") { |
| 161 sourceUri = path.toUri(path.absolute(sourcePath)); | |
| 162 } else if (sourceUri.scheme == 'dart') { | |
| 163 compilingSdk = true; | 161 compilingSdk = true; |
| 164 } | 162 } |
| 165 Source source = context.sourceFactory.forUri2(sourceUri); | 163 var source = context.sourceFactory.forUri2(sourceUri); |
| 166 | 164 |
| 167 var fileUsage = 'You need to pass at least one existing .dart file as an' | 165 var fileUsage = 'You need to pass at least one existing .dart file as an' |
| 168 ' argument.'; | 166 ' argument.'; |
| 169 if (source == null) { | 167 if (source == null) { |
| 170 throw new UsageException( | 168 throw new UsageException( |
| 171 'Could not create a source for "$sourcePath". The file name is in' | 169 'Could not create a source for "$sourcePath". The file name is in' |
| 172 ' the wrong format or was not found.', | 170 ' the wrong format or was not found.', |
| 173 fileUsage); | 171 fileUsage); |
| 174 } else if (!source.exists()) { | 172 } else if (!source.exists()) { |
| 175 throw new UsageException( | 173 throw new UsageException( |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 /// complete libraries including all of their parts, as well as all libraries | 418 /// complete libraries including all of their parts, as well as all libraries |
| 421 /// that are part of a library cycle. | 419 /// that are part of a library cycle. |
| 422 final List<String> sources; | 420 final List<String> sources; |
| 423 | 421 |
| 424 /// Given an imported library URI, this will determine to what Dart/JS module | 422 /// Given an imported library URI, this will determine to what Dart/JS module |
| 425 /// it belongs to. | 423 /// it belongs to. |
| 426 // TODO(jmesserly): we should replace this with another way of tracking | 424 // TODO(jmesserly): we should replace this with another way of tracking |
| 427 // build units. | 425 // build units. |
| 428 final Func1<Source, String> libraryToModule; | 426 final Func1<Source, String> libraryToModule; |
| 429 | 427 |
| 430 BuildUnit(this.name, this.libraryRoot, this.sources, this.libraryToModule); | 428 BuildUnit( |
| 429 String modulePath, this.libraryRoot, this.sources, this.libraryToModule) |
| 430 : name = '${path.toUri(modulePath)}'; |
| 431 } | 431 } |
| 432 | 432 |
| 433 /// The output of Dart->JS compilation. | 433 /// The output of Dart->JS compilation. |
| 434 /// | 434 /// |
| 435 /// This contains the file contents of the JS module, as well as a list of | 435 /// This contains the file contents of the JS module, as well as a list of |
| 436 /// Dart libraries that are contained in this module. | 436 /// Dart libraries that are contained in this module. |
| 437 class JSModuleFile { | 437 class JSModuleFile { |
| 438 /// The name of this module. | 438 /// The name of this module. |
| 439 final String name; | 439 final String name; |
| 440 | 440 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 var tree = | 495 var tree = |
| 496 transformModuleFormat(format, moduleTree, singleOutFile: singleOutFile); | 496 transformModuleFormat(format, moduleTree, singleOutFile: singleOutFile); |
| 497 tree.accept( | 497 tree.accept( |
| 498 new JS.Printer(opts, printer, localNamer: new JS.TemporaryNamer(tree))); | 498 new JS.Printer(opts, printer, localNamer: new JS.TemporaryNamer(tree))); |
| 499 | 499 |
| 500 Map builtMap; | 500 Map builtMap; |
| 501 if (options.sourceMap && sourceMap != null) { | 501 if (options.sourceMap && sourceMap != null) { |
| 502 builtMap = | 502 builtMap = |
| 503 placeSourceMap(sourceMap.build(jsUrl), mapUrl, options.bazelMapping); | 503 placeSourceMap(sourceMap.build(jsUrl), mapUrl, options.bazelMapping); |
| 504 if (options.sourceMapComment) { | 504 if (options.sourceMapComment) { |
| 505 var relativeMapUrl = path | 505 var jsDir = path.dirname(path.fromUri(jsUrl)); |
| 506 .toUri( | 506 var relative = path.relative(path.fromUri(mapUrl), from: jsDir); |
| 507 path.relative(path.fromUri(mapUrl), from: path.dirname(jsUrl))) | 507 var relativeMapUrl = path.toUri(relative).toString(); |
| 508 .toString(); | |
| 509 assert(path.dirname(jsUrl) == path.dirname(mapUrl)); | 508 assert(path.dirname(jsUrl) == path.dirname(mapUrl)); |
| 510 printer.emit('\n//# sourceMappingURL='); | 509 printer.emit('\n//# sourceMappingURL='); |
| 511 printer.emit(relativeMapUrl); | 510 printer.emit(relativeMapUrl); |
| 512 printer.emit('\n'); | 511 printer.emit('\n'); |
| 513 } | 512 } |
| 514 } | 513 } |
| 515 | 514 |
| 516 var text = printer.getText(); | 515 var text = printer.getText(); |
| 517 var rawSourceMap = options.inlineSourceMap | 516 var rawSourceMap = options.inlineSourceMap |
| 518 ? js.escapedString(JSON.encode(builtMap), "'").value | 517 ? js.escapedString(JSON.encode(builtMap), "'").value |
| 519 : 'null'; | 518 : 'null'; |
| 520 text = text.replaceFirst(sourceMapHoleID, rawSourceMap); | 519 text = text.replaceFirst(sourceMapHoleID, rawSourceMap); |
| 521 | 520 |
| 522 return new JSModuleCode(text, builtMap); | 521 return new JSModuleCode(text, builtMap); |
| 523 } | 522 } |
| 524 | 523 |
| 525 /// Similar to [getCode] but immediately writes the resulting files. | 524 /// Similar to [getCode] but immediately writes the resulting files. |
| 526 /// | 525 /// |
| 527 /// If [mapPath] is not supplied but [options.sourceMap] is set, mapPath | 526 /// If [mapPath] is not supplied but [options.sourceMap] is set, mapPath |
| 528 /// will default to [jsPath].map. | 527 /// will default to [jsPath].map. |
| 529 void writeCodeSync(ModuleFormat format, String jsPath, | 528 void writeCodeSync(ModuleFormat format, String jsPath, |
| 530 {bool singleOutFile: false}) { | 529 {bool singleOutFile: false}) { |
| 531 String mapPath = jsPath + '.map'; | 530 String mapPath = jsPath + '.map'; |
| 532 var code = getCode(format, jsPath, mapPath, singleOutFile: singleOutFile); | 531 var code = getCode( |
| 532 format, path.toUri(jsPath).toString(), path.toUri(mapPath).toString(), |
| 533 singleOutFile: singleOutFile); |
| 533 var c = code.code; | 534 var c = code.code; |
| 534 if (singleOutFile) { | 535 if (singleOutFile) { |
| 535 // In singleOutFile mode we wrap each module in an eval statement to | 536 // In singleOutFile mode we wrap each module in an eval statement to |
| 536 // leverage sourceURL to improve the debugging experience when source maps | 537 // leverage sourceURL to improve the debugging experience when source maps |
| 537 // are not enabled. | 538 // are not enabled. |
| 538 // | 539 // |
| 539 // Note: We replace all `/` with `.` so that we don't break relative urls | 540 // Note: We replace all `/` with `.` so that we don't break relative urls |
| 540 // to sources in the original sourcemap. The name of this file is bogus | 541 // to sources in the original sourcemap. The name of this file is bogus |
| 541 // anyways, so it has very little effect on things. | 542 // anyways, so it has very little effect on things. |
| 542 c += '\n//# sourceURL=${name.replaceAll("/", ".")}.js\n'; | 543 c += '\n//# sourceURL=${name.replaceAll("/", ".")}.js\n'; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 570 /// The JSON of the source map, if generated, otherwise `null`. | 571 /// The JSON of the source map, if generated, otherwise `null`. |
| 571 /// | 572 /// |
| 572 /// The source paths will initially be absolute paths. They can be adjusted | 573 /// The source paths will initially be absolute paths. They can be adjusted |
| 573 /// using [placeSourceMap]. | 574 /// using [placeSourceMap]. |
| 574 final Map sourceMap; | 575 final Map sourceMap; |
| 575 | 576 |
| 576 JSModuleCode(this.code, this.sourceMap); | 577 JSModuleCode(this.code, this.sourceMap); |
| 577 } | 578 } |
| 578 | 579 |
| 579 /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath], | 580 /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath], |
| 580 /// and returns the new map. | 581 /// and returns the new map. Relative paths are in terms of URIs ('/'), not |
| 582 /// local OS paths (e.g., windows '\'). |
| 581 // TODO(jmesserly): find a new home for this. | 583 // TODO(jmesserly): find a new home for this. |
| 582 Map placeSourceMap( | 584 Map placeSourceMap( |
| 583 Map sourceMap, String sourceMapPath, Map<String, String> bazelMappings) { | 585 Map sourceMap, String sourceMapPath, Map<String, String> bazelMappings) { |
| 584 var dir = path.dirname(sourceMapPath); | |
| 585 var map = new Map.from(sourceMap); | 586 var map = new Map.from(sourceMap); |
| 587 // Convert to a local file path if it's not. |
| 588 sourceMapPath = path.fromUri(_sourceToUri(sourceMapPath)); |
| 589 var sourceMapDir = path.dirname(path.absolute(sourceMapPath)); |
| 586 var list = new List.from(map['sources']); | 590 var list = new List.from(map['sources']); |
| 587 map['sources'] = list; | 591 map['sources'] = list; |
| 588 String transformUri(String uri) { | 592 |
| 589 if (uri.startsWith('dart:')) return uri; | 593 String makeRelative(String sourcePath) { |
| 590 var match = bazelMappings[path.absolute(uri)]; | 594 var uri = _sourceToUri(sourcePath); |
| 595 if (uri.scheme == 'dart' || uri.scheme == 'package') return sourcePath; |
| 596 |
| 597 // Convert to a local file path if it's not. |
| 598 sourcePath = path.absolute(path.fromUri(uri)); |
| 599 |
| 600 // Allow bazel mappings to override. |
| 601 var match = bazelMappings[sourcePath]; |
| 591 if (match != null) return match; | 602 if (match != null) return match; |
| 592 | 603 |
| 593 // Fall back to a relative path. | 604 // Fall back to a relative path against the source map itself. |
| 594 return path.toUri(path.relative(path.fromUri(uri), from: dir)).toString(); | 605 sourcePath = path.relative(sourcePath, from: sourceMapDir); |
| 606 |
| 607 // Convert from relative local path to relative URI. |
| 608 return path.toUri(sourcePath).path; |
| 595 } | 609 } |
| 596 | 610 |
| 597 for (int i = 0; i < list.length; i++) { | 611 for (int i = 0; i < list.length; i++) { |
| 598 list[i] = transformUri(list[i]); | 612 list[i] = makeRelative(list[i]); |
| 599 } | 613 } |
| 600 map['file'] = transformUri(map['file']); | 614 map['file'] = makeRelative(map['file']); |
| 601 return map; | 615 return map; |
| 602 } | 616 } |
| 617 |
| 618 // Convert a source string to a Uri. The [source] may be a Dart URI, a file |
| 619 // URI, or a local win/mac/linux path. |
| 620 Uri _sourceToUri(String source) { |
| 621 var uri = Uri.parse(source); |
| 622 var scheme = uri.scheme; |
| 623 switch (scheme) { |
| 624 case "dart": |
| 625 case "package": |
| 626 case "file": |
| 627 // A valid URI. |
| 628 return uri; |
| 629 default: |
| 630 // Assume a file path. |
| 631 return new Uri.file(path.absolute(source)); |
| 632 } |
| 633 } |
| OLD | NEW |