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 |