Chromium Code Reviews| 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 { | |
|
Jennifer Messerly
2015/02/02 21:07:51
nice!
jakemac
2015/02/02 21:53:56
Acknowledged.
| |
| 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 return super.apply(transform).then((_) { | |
| 57 var htmlEntryPoint = | |
| 58 allAssets.firstWhere((asset) => asset.id.path == _htmlEntryPoint); | |
| 59 return htmlEntryPoint.readAsString().then((html) { | |
| 60 var doc = parse(html); | |
| 61 for (var importPath in importPaths) { | |
| 62 var import = new dom.Element.tag('link') | |
| 63 ..attributes = {'rel': 'import', 'href': importPath,}; | |
| 64 doc.head.append(import); | |
| 65 } | |
| 66 transform | |
| 67 .addOutput(new Asset.fromString(htmlEntryPoint.id, doc.outerHtml)); | |
| 68 }); | |
| 69 }); | |
| 70 } | |
| 71 | |
| 72 // Executed for each initializer constructor in the bootstrap file. We filter | |
| 73 // out the HtmlImport ones and inline them. | |
| 74 initEntry( | |
| 75 InstanceCreationExpression expression, TextEditTransaction transaction) { | |
| 76 // Filter out extraneous values. | |
| 77 if (expression is! InstanceCreationExpression) return; | |
| 78 var args = expression.argumentList.arguments; | |
| 79 // Only support InstanceCreationExpressions. Const references to HtmlImport | |
| 80 // annotations can't be cheaply discovered. | |
| 81 if (args[0] is! InstanceCreationExpression) return; | |
| 82 if (!'${args[0].constructorName.type.name}'.contains('.HtmlImport')) return; | |
| 83 | |
| 84 // Grab the raw path supplied to the HtmlImport. Only string literals are | |
| 85 // supported for the transformer. | |
| 86 var originalPath = args[0].argumentList.arguments[0]; | |
| 87 if (originalPath is SimpleStringLiteral) { | |
| 88 originalPath = originalPath.value; | |
| 89 } else { | |
| 90 _logger.warning('Found HtmlImport constructor which was supplied an ' | |
| 91 'expression. Only raw strings are currently supported for the ' | |
| 92 'transformer, so $originalPath will be injected dynamically'); | |
| 93 return; | |
| 94 } | |
| 95 | |
| 96 // Now grab the package from the LibraryIdentifier, we know its either a | |
| 97 // string or null literal. | |
| 98 var package = args[1].argumentList.arguments[1]; | |
| 99 if (package is SimpleStringLiteral) { | |
| 100 package = package.value; | |
| 101 } else if (package is NullLiteral) { | |
| 102 package = null; | |
| 103 } | |
|
Jennifer Messerly
2015/02/02 21:07:51
else log error?
it could happen if someone used ad
jakemac
2015/02/02 21:53:56
These are actually completely autogenerated, but I
| |
| 104 | |
| 105 // And finally get the original dart file path, this is always a string | |
| 106 // literal. | |
| 107 var dartPath = args[1].argumentList.arguments[2].value; | |
| 108 | |
| 109 // Add the normalized path to our list and remove the expression from the | |
| 110 // bootstrap file. | |
| 111 importPaths.add(normalizeHtmlImportPath(originalPath, package, dartPath)); | |
| 112 removeInitializer(expression, transaction); | |
| 113 } | |
| 114 } | |
| OLD | NEW |