Chromium Code Reviews| Index: pkg/dev_compiler/web/web_command.dart |
| diff --git a/pkg/dev_compiler/web/web_command.dart b/pkg/dev_compiler/web/web_command.dart |
| index 5f6514a9b789711f31bc79a99c4919d4e2dfd3c9..44eee3ae48b2d203788ddc77c3d89c05bd4b7c54 100644 |
| --- a/pkg/dev_compiler/web/web_command.dart |
| +++ b/pkg/dev_compiler/web/web_command.dart |
| @@ -5,9 +5,15 @@ |
| library dev_compiler.web.web_command; |
| import 'dart:async'; |
| +import 'dart:convert'; |
| import 'dart:html' show HttpRequest; |
| -import 'dart:convert' show BASE64; |
| +import 'package:analyzer/dart/element/element.dart' |
| + show |
| + LibraryElement, |
| + ImportElement, |
| + ShowElementCombinator, |
| + HideElementCombinator; |
| import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver; |
| import 'package:analyzer/file_system/memory_file_system.dart' |
| show MemoryResourceProvider; |
| @@ -20,6 +26,7 @@ import 'package:analyzer/src/summary/package_bundle_reader.dart' |
| InSummaryUriResolver, |
| InputPackagesResultProvider, |
| InSummarySource; |
| +import 'package:analyzer/src/dart/resolver/scope.dart' show Scope; |
| import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk; |
| import 'package:args/command_runner.dart'; |
| @@ -30,6 +37,7 @@ import 'package:dev_compiler/src/compiler/compiler.dart' |
| import 'package:dev_compiler/src/compiler/module_builder.dart'; |
| import 'package:js/js.dart'; |
| +import 'package:path/path.dart' as path; |
| typedef void MessageHandler(Object message); |
| @@ -40,8 +48,8 @@ class CompileResult { |
| {String code, List<String> errors, bool isValid}); |
| } |
| -typedef CompileResult CompileModule( |
| - String code, String libraryName, String fileName); |
| +typedef CompileModule(String imports, String body, String libraryName, |
| + String existingLibrary, String fileName); |
| /// The command for invoking the modular compiler. |
| class WebCompileCommand extends Command { |
| @@ -102,7 +110,8 @@ class WebCompileCommand extends Command { |
| var summaryBundle = new PackageBundle.fromBuffer(bytes); |
| summaryDataStore.addBundle(url, summaryBundle); |
| } |
| - var summaryResolver = new InSummaryUriResolver(resourceProvider, summaryDataStore); |
| + var summaryResolver = |
| + new InSummaryUriResolver(resourceProvider, summaryDataStore); |
| var fileResolvers = [summaryResolver, resourceUriResolver]; |
| @@ -112,24 +121,83 @@ class WebCompileCommand extends Command { |
| fileResolvers: fileResolvers, |
| resourceProvider: resourceProvider); |
| - (compiler.context as AnalysisContextImpl).resultProvider = |
| + var context = compiler.context as AnalysisContextImpl; |
| + context.resultProvider = |
| new InputPackagesResultProvider(compiler.context, summaryDataStore); |
| var compilerOptions = new CompilerOptions.fromArguments(argResults); |
| - CompileModule compileFn = |
| - (String sourceCode, String libraryName, String fileName) { |
| + CompileModule compileFn = (String imports, String body, String libraryName, |
| + String existingLibrary, String fileName) { |
| // Create a new virtual File that contains the given Dart source. |
| - resourceProvider.newFile("/$fileName", sourceCode); |
| + String sourceCode; |
| + if (existingLibrary == null) { |
| + sourceCode = imports + body; |
| + } else { |
| + var dir = path.dirname(existingLibrary); |
| + // Need to pull in all the imports from the existing library and |
| + // re-export all privates as privates in this library. |
| + var source = context.sourceFactory.forUri(existingLibrary); |
| + if (source == null) { |
| + throw "Unable to load source for library $existingLibrary"; |
| + } |
| + |
| + LibraryElement libraryElement = context.computeLibraryElement(source); |
| + if (libraryElement == null) { |
| + throw "Unable to get library element."; |
|
Jennifer Messerly
2016/10/18 18:46:01
do you know in what context this actually happens?
|
| + } |
| + var sb = new StringBuffer(imports); |
| + sb.write('\n'); |
| + |
| + // We set the private name prefix for scope resolution to an invalid |
| + // character code so that the analyzer ignores normal Dart private |
| + // scoping rules for top level names allowing REPL users to access |
| + // privates in arbitrary libraries. The downside of this scheme is it is |
| + // possible to get errors if privates in the current library and |
| + // imported libraries happen to have exactly the same name. |
| + 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
|
| + |
| + // We emulate running code in the context of an existing library by |
| + // importing that library and all libraries it imports. |
| + sb.write('import ${JSON.encode(existingLibrary)};\n'); |
| + |
| + for (ImportElement importElement in libraryElement.imports) { |
| + if (importElement.uri == null) continue; |
| + var uri = importElement.uri; |
| + // dart: and package: uris are not relative but the path package |
| + // thinks they are. We have to provide absolute uris as our library |
| + // 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
|
| + if (path.isRelative(uri) && |
| + !uri.startsWith('package:') && |
| + !uri.startsWith('dart:')) { |
| + uri = path.normalize(path.join(dir, uri)); |
| + } |
| + sb.write('import ${JSON.encode(uri)}'); |
| + if (importElement.prefix != null) |
| + sb.write(' as ${importElement.prefix.name}'); |
| + for (var combinator in importElement.combinators) { |
| + if (combinator is ShowElementCombinator) { |
| + sb.write(' show ${combinator.shownNames.join(', ')}'); |
| + } else if (combinator is HideElementCombinator) { |
| + sb.write(' hide ${combinator.hiddenNames.join(', ')}'); |
| + } else { |
| + throw 'Unexpected element combinator'; |
| + } |
| + } |
| + sb.write(';\n'); |
| + } |
| + sb.write(body); |
| + sourceCode = sb.toString(); |
| + } |
| + resourceProvider.newFile(fileName, sourceCode); |
| - var unit = new BuildUnit( |
| - libraryName, "", ["file:///$fileName"], _moduleForLibrary); |
| + var unit = new BuildUnit(libraryName, "", [fileName], _moduleForLibrary); |
| JSModuleFile module = compiler.compile(unit, compilerOptions); |
| var moduleCode = module.isValid |
| ? module |
| - .getCode(ModuleFormat.legacy, false, unit.name, unit.name + '.map') |
| + .getCode(ModuleFormat.legacy, true, unit.name, unit.name + '.map') |
| .code |
| : ''; |