OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 library initialize.plugin_transformer; | |
5 | |
6 import 'dart:async'; | |
7 import 'package:analyzer/analyzer.dart'; | |
8 import 'package:barback/barback.dart'; | |
9 import 'package:source_maps/refactor.dart'; | |
10 import 'package:source_span/source_span.dart'; | |
11 | |
12 /// Abstract transformer which will call [initEntry] for every [InitEntry] | |
13 /// expression found in the bootstrap file. This is used to centralize logic | |
14 /// for initializers which want to do something special at transform time. | |
15 abstract class InitializePluginTransformer extends AggregateTransformer { | |
16 // Path to the bootstrap file created by the initialize transformer. | |
17 final String _bootstrapFile; | |
18 | |
19 // All the extra assets that were found, if child classes override | |
20 // classifyPrimary this lets them get at the other assets easily. | |
21 final allAssets = <Asset>[]; | |
22 | |
23 TransformLogger _logger; | |
24 | |
25 InitializePluginTransformer(this._bootstrapFile); | |
26 | |
27 classifyPrimary(AssetId id) => | |
28 _bootstrapFile == id.path ? _bootstrapFile : null; | |
29 | |
30 Future apply(AggregateTransform transform) { | |
31 _logger = transform.logger; | |
32 var done = new Completer(); | |
33 var listener = transform.primaryInputs.listen((Asset asset) { | |
34 allAssets.add(asset); | |
35 var id = asset.id; | |
36 if (id.path != _bootstrapFile) return; | |
37 // Calls initEntry for each InitEntry expression. | |
38 asset.readAsString().then((dartCode) { | |
39 var url = id.path.startsWith('lib/') | |
40 ? 'package:${id.package}/${id.path.substring(4)}' | |
41 : id.path; | |
42 var source = new SourceFile(dartCode, url: url); | |
43 var transaction = new TextEditTransaction(dartCode, source); | |
44 (parseCompilationUnit(dartCode, | |
45 suppressErrors: true) as dynamic).declarations.firstWhere( | |
46 (d) => d.name.toString() == | |
47 'main').functionExpression.body.block.statements.firstWhere( | |
48 (statement) { | |
49 return statement.expression.target.toString() == 'initializers' && | |
50 statement.expression.methodName.toString() == 'addAll'; | |
51 }).expression.argumentList.arguments[0].elements | |
52 .where((arg) => arg is InstanceCreationExpression) | |
53 .forEach((e) => initEntry(e, transaction)); | |
54 | |
55 // Apply any transformations. | |
56 if (!transaction.hasEdits) { | |
57 transform.addOutput(asset); | |
58 } else { | |
59 var printer = transaction.commit(); | |
60 printer.build(url); | |
61 transform.addOutput(new Asset.fromString(id, printer.text)); | |
62 } | |
63 done.complete(); | |
64 }); | |
65 }); | |
66 | |
67 // Make sure all the assets are read before returning. | |
68 return Future.wait([listener.asFuture(), done.future]); | |
69 } | |
70 | |
71 /// Gets called once for each generated [InitEntry] expression in the | |
72 /// bootstrap file. A [TextEditTransaction] is supplied so that the user can | |
73 /// modify the expression however they see fit. | |
74 void initEntry( | |
75 InstanceCreationExpression expression, TextEditTransaction transaction); | |
76 | |
77 /// Convenience method to delete an Initializer expression completely. | |
78 void removeInitializer( | |
79 InstanceCreationExpression expression, TextEditTransaction transaction) { | |
80 // Delete the entire line. | |
81 var line = transaction.file.getLine(expression.offset); | |
82 transaction.edit(transaction.file.getOffset(line), | |
83 transaction.file.getOffset(line + 1), ''); | |
84 } | |
85 } | |
OLD | NEW |