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 web_components.build.html_import_annotation_inliner; | |
5 | |
6 import 'dart:async'; | |
7 import 'package:analyzer/analyzer.dart'; | |
8 import 'package:barback/barback.dart'; | |
9 import 'package:html5lib/dom.dart' as dom; | |
10 import 'package:html5lib/parser.dart'; | |
11 import 'package:initialize/plugin_transformer.dart'; | |
12 import 'package:source_maps/refactor.dart'; | |
13 import '../src/normalize_path.dart'; | |
14 | |
15 /// Given an html entry point with a single dart bootstrap file created by the | |
16 /// `initialize` transformer, this will open that dart file and remove all | |
17 /// `HtmlImport` initializers from it. Then it appends those imports to the head | |
18 /// of the html entry point. | |
19 /// Notes: Does not inline the import, it just puts the <link rel="import"> tag. | |
20 /// This also has a few limitations, it only supports string literals (to avoid | |
21 /// using the analyzer to resolve references) and doesn't support const | |
22 /// references to HtmlImport annotations (for the same reason). | |
23 class HtmlImportAnnotationInliner extends InitializePluginTransformer { | |
24 final String _bootstrapFile; | |
25 final String _htmlEntryPoint; | |
26 TransformLogger _logger; | |
27 final Set<String> importPaths = new Set(); | |
28 | |
29 HtmlImportAnnotationInliner(String bootstrapFile, this._htmlEntryPoint) | |
30 : super(bootstrapFile), | |
31 _bootstrapFile = bootstrapFile; | |
32 | |
33 factory HtmlImportAnnotationInliner.asPlugin(BarbackSettings settings) { | |
34 var bootstrapFile = settings.configuration['bootstrap_file']; | |
35 if (bootstrapFile is! String || !bootstrapFile.endsWith('.dart')) { | |
36 throw new ArgumentError( | |
37 '`bootstrap_file` should be a string path to a dart file'); | |
38 } | |
39 var htmlEntryPoint = settings.configuration['html_entry_point']; | |
40 if (htmlEntryPoint is! String || !htmlEntryPoint.endsWith('.html')) { | |
41 throw new ArgumentError( | |
42 '`html_entry_point` should be a string path to an html file'); | |
43 } | |
44 return new HtmlImportAnnotationInliner(bootstrapFile, htmlEntryPoint); | |
45 } | |
46 | |
47 classifyPrimary(AssetId id) { | |
48 var superValue = super.classifyPrimary(id); | |
49 if (superValue != null) return superValue; | |
50 // Group it with the bootstrap file. | |
51 if (_htmlEntryPoint == id.path) return _bootstrapFile; | |
52 return null; | |
53 } | |
54 | |
55 apply(AggregateTransform transform) { | |
56 _logger = transform.logger; | |
57 return super.apply(transform).then((_) { | |
58 var htmlEntryPoint = | |
59 allAssets.firstWhere((asset) => asset.id.path == _htmlEntryPoint); | |
60 return htmlEntryPoint.readAsString().then((html) { | |
61 var doc = parse(html); | |
62 for (var importPath in importPaths) { | |
63 var import = new dom.Element.tag('link') | |
64 ..attributes = {'rel': 'import', 'href': importPath,}; | |
Siggi Cherem (dart-lang)
2015/02/12 16:49:44
nit: remove trailing comma `,`?
jakemac
2015/02/12 17:04:09
oh I probably had these on separate lines in which
| |
65 doc.head.append(import); | |
66 } | |
67 transform | |
68 .addOutput(new Asset.fromString(htmlEntryPoint.id, doc.outerHtml)); | |
69 }); | |
70 }); | |
71 } | |
72 | |
73 // Executed for each initializer constructor in the bootstrap file. We filter | |
74 // out the HtmlImport ones and inline them. | |
75 initEntry( | |
76 InstanceCreationExpression expression, TextEditTransaction transaction) { | |
77 // Filter out extraneous values. | |
78 if (expression is! InstanceCreationExpression) return; | |
79 var args = expression.argumentList.arguments; | |
80 // Only support InstanceCreationExpressions. Const references to HtmlImport | |
81 // annotations can't be cheaply discovered. | |
82 if (args[0] is! InstanceCreationExpression) return; | |
83 if (!'${args[0].constructorName.type.name}'.contains('.HtmlImport')) return; | |
84 | |
85 // Grab the raw path supplied to the HtmlImport. Only string literals are | |
86 // supported for the transformer. | |
Siggi Cherem (dart-lang)
2015/02/12 16:49:44
FYI - I opened https://github.com/dart-lang/initia
jakemac
2015/02/12 17:04:09
I replied there, but basically in the new plugin a
| |
87 var originalPath = args[0].argumentList.arguments[0]; | |
88 if (originalPath is SimpleStringLiteral) { | |
89 originalPath = originalPath.value; | |
90 } else { | |
91 _logger.warning('Found HtmlImport constructor which was supplied an ' | |
92 'expression. Only raw strings are currently supported for the ' | |
93 'transformer, so $originalPath will be injected dynamically'); | |
94 return; | |
95 } | |
96 | |
97 // Now grab the package from the LibraryIdentifier, we know its either a | |
98 // string or null literal. | |
99 var package = args[1].argumentList.arguments[1]; | |
100 if (package is SimpleStringLiteral) { | |
101 package = package.value; | |
102 } else if (package is NullLiteral) { | |
103 package = null; | |
104 } else { | |
105 _logger.error('Invalid LibraryIdentifier declaration. The 2nd argument ' | |
106 'be a literal string or null. `${args[1]}`'); | |
107 } | |
108 | |
109 // And finally get the original dart file path, this is always a string | |
110 // literal. | |
111 var dartPath = args[1].argumentList.arguments[2]; | |
112 if (dartPath is SimpleStringLiteral) { | |
113 dartPath = dartPath.value; | |
114 } else { | |
115 _logger.error('Invalid LibraryIdentifier declaration. The 3rd argument ' | |
116 'be a literal string. `${args[1]}`'); | |
117 } | |
118 | |
119 // Add the normalized path to our list and remove the expression from the | |
120 // bootstrap file. | |
121 importPaths.add(normalizeHtmlImportPath(originalPath, package, dartPath)); | |
122 removeInitializer(expression, transaction); | |
123 } | |
124 } | |
OLD | NEW |