| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 dev_compiler.src.codegen.js_printer; | 5 library dev_compiler.src.codegen.js_printer; |
| 6 | 6 |
| 7 import 'dart:convert' show JSON, JsonEncoder; | 7 import 'dart:convert' show JSON, JsonEncoder; |
| 8 import 'dart:io' show Directory, File, Platform, Process; | 8 import 'dart:io' show Directory, File, Platform, Process; |
| 9 | 9 |
| 10 import 'package:analyzer/src/generated/ast.dart'; | 10 import 'package:analyzer/src/generated/ast.dart'; |
| 11 import 'package:path/path.dart' as path; | 11 import 'package:path/path.dart' as path; |
| 12 import 'package:source_maps/source_maps.dart' as srcmaps show Printer; | 12 import 'package:source_maps/source_maps.dart' as srcmaps show Printer; |
| 13 import 'package:source_maps/source_maps.dart' show SourceMapSpan; | 13 import 'package:source_maps/source_maps.dart' show SourceMapSpan; |
| 14 import 'package:source_span/source_span.dart' show SourceLocation; | 14 import 'package:source_span/source_span.dart' show SourceLocation; |
| 15 | 15 |
| 16 import '../js/js_ast.dart' as JS; | 16 import '../js/js_ast.dart' as JS; |
| 17 import '../utils.dart' show computeHash, locationForOffset; | 17 import '../utils.dart' show computeHash, locationForOffset; |
| 18 | 18 |
| 19 import 'js_names.dart' show TemporaryNamer; | 19 import 'js_names.dart' show TemporaryNamer; |
| 20 | 20 |
| 21 String writeJsLibrary(JS.Program jsTree, String outputPath, | 21 String writeJsLibrary( |
| 22 JS.Program jsTree, String outputPath, String inputDir, Uri serverUri, |
| 22 {bool emitSourceMaps: false, bool arrowFnBindThisWorkaround: false}) { | 23 {bool emitSourceMaps: false, bool arrowFnBindThisWorkaround: false}) { |
| 23 var outFilename = path.basename(outputPath); | 24 var outFilename = path.basename(outputPath); |
| 24 var outDir = path.dirname(outputPath); | 25 var outDir = path.dirname(outputPath); |
| 25 new Directory(outDir).createSync(recursive: true); | 26 new Directory(outDir).createSync(recursive: true); |
| 26 | 27 |
| 27 JS.JavaScriptPrintingContext context; | 28 JS.JavaScriptPrintingContext context; |
| 28 if (emitSourceMaps) { | 29 if (emitSourceMaps) { |
| 29 var printer = new srcmaps.Printer(outFilename); | 30 var printer = new srcmaps.Printer(outFilename); |
| 30 context = new SourceMapPrintingContext(printer, outDir); | 31 context = |
| 32 new SourceMapPrintingContext(printer, outDir, inputDir, serverUri); |
| 31 } else { | 33 } else { |
| 32 context = new JS.SimpleJavaScriptPrintingContext(); | 34 context = new JS.SimpleJavaScriptPrintingContext(); |
| 33 } | 35 } |
| 34 | 36 |
| 35 var opts = new JS.JavaScriptPrintingOptions( | 37 var opts = new JS.JavaScriptPrintingOptions( |
| 36 allowKeywordsInProperties: true, | 38 allowKeywordsInProperties: true, |
| 37 allowSingleLineIfStatements: true, | 39 allowSingleLineIfStatements: true, |
| 38 arrowFnBindThisWorkaround: arrowFnBindThisWorkaround); | 40 arrowFnBindThisWorkaround: arrowFnBindThisWorkaround); |
| 39 var jsNamer = new TemporaryNamer(jsTree); | 41 var jsNamer = new TemporaryNamer(jsTree); |
| 40 jsTree.accept(new JS.Printer(opts, context, localNamer: jsNamer)); | 42 jsTree.accept(new JS.Printer(opts, context, localNamer: jsNamer)); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 66 // TODO(jmesserly): should only do this if the input file was executable? | 68 // TODO(jmesserly): should only do this if the input file was executable? |
| 67 if (!Platform.isWindows) Process.runSync('chmod', ['+x', outputPath]); | 69 if (!Platform.isWindows) Process.runSync('chmod', ['+x', outputPath]); |
| 68 } | 70 } |
| 69 | 71 |
| 70 return computeHash(text); | 72 return computeHash(text); |
| 71 } | 73 } |
| 72 | 74 |
| 73 class SourceMapPrintingContext extends JS.JavaScriptPrintingContext { | 75 class SourceMapPrintingContext extends JS.JavaScriptPrintingContext { |
| 74 final srcmaps.Printer printer; | 76 final srcmaps.Printer printer; |
| 75 final String outputDir; | 77 final String outputDir; |
| 78 final String inputDir; |
| 79 |
| 80 // TODO(vsm): we could abstract this out and have a generic Uri mapping |
| 81 // instead of hardcoding a notion of a server uri. |
| 82 final Uri serverUri; |
| 76 | 83 |
| 77 CompilationUnit unit; | 84 CompilationUnit unit; |
| 78 Uri uri; | 85 Uri uri; |
| 79 | 86 |
| 80 SourceMapPrintingContext(this.printer, this.outputDir); | 87 SourceMapPrintingContext( |
| 88 this.printer, this.outputDir, this.inputDir, this.serverUri); |
| 81 | 89 |
| 82 void emit(String string) { | 90 void emit(String string) { |
| 83 printer.add(string); | 91 printer.add(string); |
| 84 } | 92 } |
| 85 | 93 |
| 86 AstNode _currentTopLevelDeclaration; | 94 AstNode _currentTopLevelDeclaration; |
| 87 | 95 |
| 88 void enterNode(JS.Node jsNode) { | 96 void enterNode(JS.Node jsNode) { |
| 89 AstNode node = jsNode.sourceInformation; | 97 AstNode node = jsNode.sourceInformation; |
| 90 if (node == null || node.offset == -1) return; | 98 if (node == null || node.offset == -1) return; |
| 91 if (unit == null) { | 99 if (unit == null) { |
| 92 // This is a top-level declaration. Note: consecutive top-level | 100 // This is a top-level declaration. Note: consecutive top-level |
| 93 // declarations may come from different compilation units due to | 101 // declarations may come from different compilation units due to |
| 94 // parts. | 102 // parts. |
| 95 _currentTopLevelDeclaration = node; | 103 _currentTopLevelDeclaration = node; |
| 96 unit = node.getAncestor((n) => n is CompilationUnit); | 104 unit = node.getAncestor((n) => n is CompilationUnit); |
| 97 uri = _makeRelativeUri(unit.element.source.uri); | 105 uri = _makeRelativeUri(unit.element.source.uri); |
| 98 } | 106 } |
| 107 if (unit == null) return; |
| 99 | 108 |
| 100 assert(unit != null); | 109 assert(unit != null); |
| 101 var loc = _location(node.offset); | 110 var loc = _location(node.offset); |
| 102 var name = _getIdentifier(node); | 111 var name = _getIdentifier(node); |
| 103 if (name != null) { | 112 if (name != null) { |
| 104 // TODO(jmesserly): mark only uses the beginning of the span, but | 113 // TODO(jmesserly): mark only uses the beginning of the span, but |
| 105 // we're required to pass this as a valid span. | 114 // we're required to pass this as a valid span. |
| 106 var end = _location(node.end); | 115 var end = _location(node.end); |
| 107 printer.mark(new SourceMapSpan(loc, end, name, isIdentifier: true)); | 116 printer.mark(new SourceMapSpan(loc, end, name, isIdentifier: true)); |
| 108 } else { | 117 } else { |
| 109 printer.mark(loc); | 118 printer.mark(loc); |
| 110 } | 119 } |
| 111 } | 120 } |
| 112 | 121 |
| 113 SourceLocation _location(int offset) => | 122 SourceLocation _location(int offset) => |
| 114 locationForOffset(unit.lineInfo, uri, offset); | 123 locationForOffset(unit.lineInfo, uri, offset); |
| 115 | 124 |
| 116 Uri _makeRelativeUri(Uri src) { | 125 Uri _makeRelativeUri(Uri src) { |
| 117 return new Uri(path: path.relative(src.path, from: outputDir)); | 126 if (serverUri == null) { |
| 127 return new Uri(path: path.relative(src.path, from: outputDir)); |
| 128 } else { |
| 129 if (src.path.startsWith('/')) { |
| 130 return serverUri.resolve(path.relative(src.path, from: inputDir)); |
| 131 } else { |
| 132 return serverUri.resolve(path.join('packages', src.path)); |
| 133 } |
| 134 } |
| 118 } | 135 } |
| 119 | 136 |
| 120 void exitNode(JS.Node jsNode) { | 137 void exitNode(JS.Node jsNode) { |
| 121 AstNode node = jsNode.sourceInformation; | 138 AstNode node = jsNode.sourceInformation; |
| 122 if (unit == null || node == null || node.offset == -1) return; | 139 if (unit == null || node == null || node.offset == -1) return; |
| 123 | 140 |
| 124 // TODO(jmesserly): in many cases marking the end will be unnecessary. | 141 // TODO(jmesserly): in many cases marking the end will be unnecessary. |
| 125 printer.mark(_location(node.end)); | 142 printer.mark(_location(node.end)); |
| 126 | 143 |
| 127 if (_currentTopLevelDeclaration == node) { | 144 if (_currentTopLevelDeclaration == node) { |
| 128 unit = null; | 145 unit = null; |
| 129 uri = null; | 146 uri = null; |
| 130 _currentTopLevelDeclaration == null; | 147 _currentTopLevelDeclaration == null; |
| 131 return; | 148 return; |
| 132 } | 149 } |
| 133 } | 150 } |
| 134 | 151 |
| 135 String _getIdentifier(AstNode node) { | 152 String _getIdentifier(AstNode node) { |
| 136 if (node is SimpleIdentifier) return node.name; | 153 if (node is SimpleIdentifier) return node.name; |
| 137 return null; | 154 return null; |
| 138 } | 155 } |
| 139 } | 156 } |
| OLD | NEW |