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 @JS() | 4 @JS() |
| 5 library dev_compiler.web.web_command; | 5 library dev_compiler.web.web_command; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:convert'; | |
| 8 import 'dart:html' show HttpRequest; | 9 import 'dart:html' show HttpRequest; |
| 9 import 'dart:convert' show BASE64; | |
| 10 | 10 |
| 11 import 'package:analyzer/dart/element/element.dart' | |
| 12 show | |
| 13 LibraryElement, | |
| 14 ImportElement, | |
| 15 ShowElementCombinator, | |
| 16 HideElementCombinator; | |
| 11 import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver; | 17 import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver; |
| 12 import 'package:analyzer/file_system/memory_file_system.dart' | 18 import 'package:analyzer/file_system/memory_file_system.dart' |
| 13 show MemoryResourceProvider; | 19 show MemoryResourceProvider; |
| 14 import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl; | 20 import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl; |
| 15 import 'package:analyzer/src/generated/source.dart' show DartUriResolver; | 21 import 'package:analyzer/src/generated/source.dart' show DartUriResolver; |
| 16 import 'package:analyzer/src/summary/idl.dart' show PackageBundle; | 22 import 'package:analyzer/src/summary/idl.dart' show PackageBundle; |
| 17 import 'package:analyzer/src/summary/package_bundle_reader.dart' | 23 import 'package:analyzer/src/summary/package_bundle_reader.dart' |
| 18 show | 24 show |
| 19 SummaryDataStore, | 25 SummaryDataStore, |
| 20 InSummaryUriResolver, | 26 InSummaryUriResolver, |
| 21 InputPackagesResultProvider, | 27 InputPackagesResultProvider, |
| 22 InSummarySource; | 28 InSummarySource; |
| 29 import 'package:analyzer/src/dart/resolver/scope.dart' show Scope; | |
| 23 import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk; | 30 import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk; |
| 24 | 31 |
| 25 import 'package:args/command_runner.dart'; | 32 import 'package:args/command_runner.dart'; |
| 26 | 33 |
| 27 import 'package:dev_compiler/src/analyzer/context.dart' show AnalyzerOptions; | 34 import 'package:dev_compiler/src/analyzer/context.dart' show AnalyzerOptions; |
| 28 import 'package:dev_compiler/src/compiler/compiler.dart' | 35 import 'package:dev_compiler/src/compiler/compiler.dart' |
| 29 show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler; | 36 show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler; |
| 30 | 37 |
| 31 import 'package:dev_compiler/src/compiler/module_builder.dart'; | 38 import 'package:dev_compiler/src/compiler/module_builder.dart'; |
| 32 import 'package:js/js.dart'; | 39 import 'package:js/js.dart'; |
| 40 import 'package:path/path.dart' as path; | |
| 33 | 41 |
| 34 typedef void MessageHandler(Object message); | 42 typedef void MessageHandler(Object message); |
| 35 | 43 |
| 36 @JS() | 44 @JS() |
| 37 @anonymous | 45 @anonymous |
| 38 class CompileResult { | 46 class CompileResult { |
| 39 external factory CompileResult( | 47 external factory CompileResult( |
| 40 {String code, List<String> errors, bool isValid}); | 48 {String code, List<String> errors, bool isValid}); |
| 41 } | 49 } |
| 42 | 50 |
| 43 typedef CompileResult CompileModule( | 51 typedef CompileModule(String imports, String body, String libraryName, |
| 44 String code, String libraryName, String fileName); | 52 String existingLibrary, String fileName); |
| 45 | 53 |
| 46 /// The command for invoking the modular compiler. | 54 /// The command for invoking the modular compiler. |
| 47 class WebCompileCommand extends Command { | 55 class WebCompileCommand extends Command { |
| 48 get name => 'compile'; | 56 get name => 'compile'; |
| 49 | 57 |
| 50 get description => 'Compile a set of Dart files into a JavaScript module.'; | 58 get description => 'Compile a set of Dart files into a JavaScript module.'; |
| 51 final MessageHandler messageHandler; | 59 final MessageHandler messageHandler; |
| 52 | 60 |
| 53 WebCompileCommand({MessageHandler messageHandler}) | 61 WebCompileCommand({MessageHandler messageHandler}) |
| 54 : this.messageHandler = messageHandler ?? print { | 62 : this.messageHandler = messageHandler ?? print { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 95 true, packageBundle, resourceProvider); | 103 true, packageBundle, resourceProvider); |
| 96 var sdkResolver = new DartUriResolver(webDartSdk); | 104 var sdkResolver = new DartUriResolver(webDartSdk); |
| 97 | 105 |
| 98 var summaryDataStore = new SummaryDataStore([]); | 106 var summaryDataStore = new SummaryDataStore([]); |
| 99 for (var i = 0; i < summaryBytes.length; i++) { | 107 for (var i = 0; i < summaryBytes.length; i++) { |
| 100 var bytes = summaryBytes[i]; | 108 var bytes = summaryBytes[i]; |
| 101 var url = summaryUrls[i]; | 109 var url = summaryUrls[i]; |
| 102 var summaryBundle = new PackageBundle.fromBuffer(bytes); | 110 var summaryBundle = new PackageBundle.fromBuffer(bytes); |
| 103 summaryDataStore.addBundle(url, summaryBundle); | 111 summaryDataStore.addBundle(url, summaryBundle); |
| 104 } | 112 } |
| 105 var summaryResolver = new InSummaryUriResolver(resourceProvider, summaryData Store); | 113 var summaryResolver = |
| 114 new InSummaryUriResolver(resourceProvider, summaryDataStore); | |
| 106 | 115 |
| 107 var fileResolvers = [summaryResolver, resourceUriResolver]; | 116 var fileResolvers = [summaryResolver, resourceUriResolver]; |
| 108 | 117 |
| 109 var compiler = new ModuleCompiler( | 118 var compiler = new ModuleCompiler( |
| 110 new AnalyzerOptions(dartSdkPath: '/dart-sdk'), | 119 new AnalyzerOptions(dartSdkPath: '/dart-sdk'), |
| 111 sdkResolver: sdkResolver, | 120 sdkResolver: sdkResolver, |
| 112 fileResolvers: fileResolvers, | 121 fileResolvers: fileResolvers, |
| 113 resourceProvider: resourceProvider); | 122 resourceProvider: resourceProvider); |
| 114 | 123 |
| 115 (compiler.context as AnalysisContextImpl).resultProvider = | 124 var context = compiler.context as AnalysisContextImpl; |
| 125 context.resultProvider = | |
| 116 new InputPackagesResultProvider(compiler.context, summaryDataStore); | 126 new InputPackagesResultProvider(compiler.context, summaryDataStore); |
| 117 | 127 |
| 118 var compilerOptions = new CompilerOptions.fromArguments(argResults); | 128 var compilerOptions = new CompilerOptions.fromArguments(argResults); |
| 119 | 129 |
| 120 CompileModule compileFn = | 130 CompileModule compileFn = (String imports, String body, String libraryName, |
| 121 (String sourceCode, String libraryName, String fileName) { | 131 String existingLibrary, String fileName) { |
| 122 // Create a new virtual File that contains the given Dart source. | 132 // Create a new virtual File that contains the given Dart source. |
| 123 resourceProvider.newFile("/$fileName", sourceCode); | 133 String sourceCode; |
| 134 if (existingLibrary == null) { | |
| 135 sourceCode = imports + body; | |
| 136 } else { | |
| 137 var dir = path.dirname(existingLibrary); | |
| 138 // Need to pull in all the imports from the existing library and | |
| 139 // re-export all privates as privates in this library. | |
| 140 var source = context.sourceFactory.forUri(existingLibrary); | |
| 141 if (source == null) { | |
| 142 throw "Unable to load source for library $existingLibrary"; | |
| 143 } | |
| 124 | 144 |
| 125 var unit = new BuildUnit( | 145 LibraryElement libraryElement = context.computeLibraryElement(source); |
| 126 libraryName, "", ["file:///$fileName"], _moduleForLibrary); | 146 if (libraryElement == null) { |
| 147 throw "Unable to get library element."; | |
|
Jennifer Messerly
2016/10/18 18:46:01
do you know in what context this actually happens?
| |
| 148 } | |
| 149 var sb = new StringBuffer(imports); | |
| 150 sb.write('\n'); | |
| 151 | |
| 152 // We set the private name prefix for scope resolution to an invalid | |
| 153 // character code so that the analyzer ignores normal Dart private | |
| 154 // scoping rules for top level names allowing REPL users to access | |
| 155 // privates in arbitrary libraries. The downside of this scheme is it is | |
| 156 // possible to get errors if privates in the current library and | |
| 157 // imported libraries happen to have exactly the same name. | |
| 158 Scope.PRIVATE_NAME_PREFIX = -1; | |
|
Jennifer Messerly
2016/10/18 18:46:01
Interesting. It seems better to add a feature expl
Brian Wilkerson
2016/10/18 19:16:44
I agree, this seems brittle. (I can't even guarant
| |
| 159 | |
| 160 // We emulate running code in the context of an existing library by | |
| 161 // importing that library and all libraries it imports. | |
| 162 sb.write('import ${JSON.encode(existingLibrary)};\n'); | |
| 163 | |
| 164 for (ImportElement importElement in libraryElement.imports) { | |
| 165 if (importElement.uri == null) continue; | |
| 166 var uri = importElement.uri; | |
| 167 // dart: and package: uris are not relative but the path package | |
| 168 // thinks they are. We have to provide absolute uris as our library | |
| 169 // has a different directory than the library we are pretending to be. | |
|
Brian Wilkerson
2016/10/18 19:16:44
It might be better to get the URI of the imported
| |
| 170 if (path.isRelative(uri) && | |
| 171 !uri.startsWith('package:') && | |
| 172 !uri.startsWith('dart:')) { | |
| 173 uri = path.normalize(path.join(dir, uri)); | |
| 174 } | |
| 175 sb.write('import ${JSON.encode(uri)}'); | |
| 176 if (importElement.prefix != null) | |
| 177 sb.write(' as ${importElement.prefix.name}'); | |
| 178 for (var combinator in importElement.combinators) { | |
| 179 if (combinator is ShowElementCombinator) { | |
| 180 sb.write(' show ${combinator.shownNames.join(', ')}'); | |
| 181 } else if (combinator is HideElementCombinator) { | |
| 182 sb.write(' hide ${combinator.hiddenNames.join(', ')}'); | |
| 183 } else { | |
| 184 throw 'Unexpected element combinator'; | |
| 185 } | |
| 186 } | |
| 187 sb.write(';\n'); | |
| 188 } | |
| 189 sb.write(body); | |
| 190 sourceCode = sb.toString(); | |
| 191 } | |
| 192 resourceProvider.newFile(fileName, sourceCode); | |
| 193 | |
| 194 var unit = new BuildUnit(libraryName, "", [fileName], _moduleForLibrary); | |
| 127 | 195 |
| 128 JSModuleFile module = compiler.compile(unit, compilerOptions); | 196 JSModuleFile module = compiler.compile(unit, compilerOptions); |
| 129 | 197 |
| 130 var moduleCode = module.isValid | 198 var moduleCode = module.isValid |
| 131 ? module | 199 ? module |
| 132 .getCode(ModuleFormat.legacy, false, unit.name, unit.name + '.map' ) | 200 .getCode(ModuleFormat.legacy, true, unit.name, unit.name + '.map') |
| 133 .code | 201 .code |
| 134 : ''; | 202 : ''; |
| 135 | 203 |
| 136 return new CompileResult( | 204 return new CompileResult( |
| 137 code: moduleCode, isValid: module.isValid, errors: module.errors); | 205 code: moduleCode, isValid: module.isValid, errors: module.errors); |
| 138 }; | 206 }; |
| 139 | 207 |
| 140 return allowInterop(compileFn); | 208 return allowInterop(compileFn); |
| 141 } | 209 } |
| 142 } | 210 } |
| 143 | 211 |
| 144 // Given path, determine corresponding dart library. | 212 // Given path, determine corresponding dart library. |
| 145 String _moduleForLibrary(source) { | 213 String _moduleForLibrary(source) { |
| 146 if (source is InSummarySource) { | 214 if (source is InSummarySource) { |
| 147 return source.summaryPath.substring(1).replaceAll('.api.ds', ''); | 215 return source.summaryPath.substring(1).replaceAll('.api.ds', ''); |
| 148 } | 216 } |
| 149 return source.toString().substring(1).replaceAll('.dart', ''); | 217 return source.toString().substring(1).replaceAll('.dart', ''); |
| 150 } | 218 } |
| 151 | 219 |
| 152 /// Thrown when the input source code has errors. | 220 /// Thrown when the input source code has errors. |
| 153 class CompileErrorException implements Exception { | 221 class CompileErrorException implements Exception { |
| 154 toString() => '\nPlease fix all errors before compiling (warnings are okay).'; | 222 toString() => '\nPlease fix all errors before compiling (warnings are okay).'; |
| 155 } | 223 } |
| OLD | NEW |