| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library dev_compiler.src.transformer.transformer; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 import 'dart:io'; | |
| 9 | |
| 10 import 'package:barback/barback.dart'; | |
| 11 import 'package:analyzer/src/generated/engine.dart' | |
| 12 show AnalysisEngine, AnalysisOptionsImpl; | |
| 13 import 'package:path/path.dart' as path; | |
| 14 | |
| 15 import 'asset_universe.dart'; | |
| 16 import 'error_listener.dart'; | |
| 17 import 'uri_resolver.dart' show assetIdToUri, createSourceFactory; | |
| 18 import '../compiler.dart'; | |
| 19 import '../options.dart'; | |
| 20 import '../utils.dart'; | |
| 21 import 'package:analyzer/src/generated/engine.dart'; | |
| 22 | |
| 23 const String _fakeRuntimeDir = "<runtime>"; | |
| 24 | |
| 25 /// Disclaimer: this transformer is experimental and not optimized. It may run | |
| 26 /// out of memory for large applications: please use DDC's command-line runner | |
| 27 /// instead whenever possible. | |
| 28 class DdcTransformer extends AggregateTransformer { | |
| 29 final List<String> _ddcArgs; | |
| 30 | |
| 31 DdcTransformer.asPlugin(BarbackSettings settings) | |
| 32 : _ddcArgs = settings.configuration['args'] ?? []; | |
| 33 | |
| 34 @override | |
| 35 apply(AggregateTransform transform) async { | |
| 36 var inputs = await transform.primaryInputs.toList(); | |
| 37 | |
| 38 // The analyzer's source factory mechanism is synchronous, so we can't | |
| 39 // have it wait upon transform.getInput. Instead, we build the whole | |
| 40 // universe (scanning transitive dependencies and reading their sources), | |
| 41 // so as to get a non-async source getter. | |
| 42 // Note: This means we use a lot of memory: one way to fix it would be to | |
| 43 // propagate asynchonous calls throughout the analyzer. | |
| 44 var universe = new AssetUniverse(); | |
| 45 await Future.wait( | |
| 46 inputs.map((a) => universe.scanSources(a.id, transform.getInput))); | |
| 47 | |
| 48 // TODO(ochafik): invesigate the us of createAnalysisContextWithSources | |
| 49 // instead. | |
| 50 var context = AnalysisEngine.instance.createAnalysisContext(); | |
| 51 context.analysisOptions = _makeAnalysisOptions(); | |
| 52 context.sourceFactory = createSourceFactory(universe.getAssetSource); | |
| 53 | |
| 54 // Virtual file system that writes into the transformer's outputs. | |
| 55 var fileSystem = new _TransformerFileSystem( | |
| 56 transform.logger, transform.package, transform.addOutput, | |
| 57 // Seed the runtime files into our file system: | |
| 58 inputs: await _readRuntimeFiles(transform.getInput)); | |
| 59 | |
| 60 var compiler = new BatchCompiler( | |
| 61 context, | |
| 62 // Note that the output directory needs not exist, and the runtime | |
| 63 // directory is a special value that corresponds to the seeding of | |
| 64 // runtimeFiles above. | |
| 65 parseOptions([] | |
| 66 ..addAll(_ddcArgs) | |
| 67 ..addAll([ | |
| 68 '-o', | |
| 69 fileSystem.outputDir.path, | |
| 70 '--runtime-dir', | |
| 71 _fakeRuntimeDir | |
| 72 ])), | |
| 73 reporter: new TransformAnalysisErrorListener(transform.logger, context), | |
| 74 fileSystem: fileSystem); | |
| 75 | |
| 76 for (var asset in inputs) { | |
| 77 compiler.compileFromUriString(assetIdToUri(asset.id)); | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 // TODO(ochafik): Provide more control over these options. | |
| 82 AnalysisOptions _makeAnalysisOptions() => new AnalysisOptionsImpl() | |
| 83 ..cacheSize = 256 // # of sources to cache ASTs for. | |
| 84 ..preserveComments = true | |
| 85 ..analyzeFunctionBodies = true | |
| 86 ..strongMode = true; | |
| 87 | |
| 88 /// Read the runtime files from the transformer (they're available as | |
| 89 /// resources of package:dev_compiler), | |
| 90 Future<Map<String, String>> _readRuntimeFiles( | |
| 91 Future<Asset> getInput(AssetId id)) async { | |
| 92 var runtimeFiles = <String, String>{}; | |
| 93 for (var file in defaultRuntimeFiles) { | |
| 94 var asset = | |
| 95 await getInput(new AssetId('dev_compiler', 'lib/runtime/$file')); | |
| 96 runtimeFiles[path.join(_fakeRuntimeDir, file)] = | |
| 97 await asset.readAsString(); | |
| 98 } | |
| 99 return runtimeFiles; | |
| 100 } | |
| 101 | |
| 102 /// We just transform all .dart and .html files in one go. | |
| 103 @override | |
| 104 classifyPrimary(AssetId id) => | |
| 105 id.extension == '.dart' || id.extension == '.html' ? '<dart>' : null; | |
| 106 } | |
| 107 | |
| 108 /// Type of [Transform.addOutput] and [AggregateTransform.addOutput]. | |
| 109 typedef void AssetOutputAdder(Asset asset); | |
| 110 | |
| 111 /// Virtual file system that outputs files into a transformer. | |
| 112 class _TransformerFileSystem implements FileSystem { | |
| 113 final String _package; | |
| 114 final Directory outputDir = Directory.current; | |
| 115 final String outputPrefix; | |
| 116 final AssetOutputAdder _addOutput; | |
| 117 final Map<String, String> inputs; | |
| 118 final TransformLogger _logger; | |
| 119 _TransformerFileSystem(this._logger, this._package, this._addOutput, | |
| 120 {this.inputs, this.outputPrefix: 'web/'}); | |
| 121 | |
| 122 @override | |
| 123 void writeAsStringSync(String file, String contents) { | |
| 124 var id = new AssetId( | |
| 125 _package, outputPrefix + path.relative(file, from: outputDir.path)); | |
| 126 _logger.fine('Adding output $id'); | |
| 127 _addOutput(new Asset.fromString(id, contents)); | |
| 128 } | |
| 129 | |
| 130 @override | |
| 131 void copySync(String src, String dest) { | |
| 132 writeAsStringSync(dest, inputs[src] ?? new File(src).readAsStringSync()); | |
| 133 } | |
| 134 } | |
| OLD | NEW |