Chromium Code Reviews| Index: lib/build/html_import_annotation_inliner.dart |
| diff --git a/lib/build/html_import_annotation_inliner.dart b/lib/build/html_import_annotation_inliner.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ffb6668079f3db48793a8e2800b5c7ddc895b5d5 |
| --- /dev/null |
| +++ b/lib/build/html_import_annotation_inliner.dart |
| @@ -0,0 +1,97 @@ |
| +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| +library web_components.build.html_import_annotation_inliner; |
| + |
| +import 'dart:async'; |
| +import 'package:barback/barback.dart'; |
| +import 'package:html5lib/dom.dart' as dom; |
| +import 'package:html5lib/parser.dart'; |
| +import '../src/normalize_path.dart'; |
| + |
| +/// Given an html entry point with a single dart bootstrap file created by the |
| +/// `initialize` transformer, this will open that dart file and remove all |
| +/// `HtmlImport` initializers from it. Then it appends those imports to the head |
| +/// of the html entry point. |
| +/// Note: Does not inline the import, it just puts the <link rel="import"> tag. |
| +class HtmlImportAnnotationInliner extends AggregateTransformer { |
| + final String _bootstrapFile; |
| + final String _htmlEntryPoint; |
| + TransformLogger _logger; |
| + |
| + HtmlImportAnnotationInliner(this._bootstrapFile, this._htmlEntryPoint); |
| + |
| + factory HtmlImportAnnotationInliner.asPlugin(BarbackSettings settings) { |
| + var bootstrapFile = settings.configuration['bootstrap_file']; |
| + if (bootstrapFile is! String || !bootstrapFile.endsWith('.dart')) { |
| + throw new ArgumentError( |
| + '`bootstrap_file` should be a string path to a dart file'); |
| + } |
| + var htmlEntryPoint = settings.configuration['html_entry_point']; |
| + if (htmlEntryPoint is! String || !htmlEntryPoint.endsWith('.html')) { |
| + throw new ArgumentError( |
| + '`html_entry_point` should be a string path to an html file'); |
| + } |
| + return new HtmlImportAnnotationInliner(bootstrapFile, htmlEntryPoint); |
| + } |
| + |
| + classifyPrimary(AssetId id) { |
| + if (_bootstrapFile == id.path || _htmlEntryPoint == id.path) return ' '; |
| + return null; |
| + } |
| + |
| + Future apply(AggregateTransform transform) { |
| + _logger = transform.logger; |
| + Asset dartEntryPoint; |
| + Asset htmlEntryPoint; |
| + return transform.primaryInputs.take(2).listen((Asset asset) { |
| + if (asset.id.path == _bootstrapFile) dartEntryPoint = asset; |
| + if (asset.id.path == _htmlEntryPoint) htmlEntryPoint = asset; |
| + }).asFuture().then((_) { |
| + // Will be populated with all import paths found in HtmlImport |
| + // constructors. |
| + var importPaths; |
| + return dartEntryPoint.readAsString().then((dartCode) { |
| + var matches = _htmlImportWithRawString.allMatches(dartCode); |
| + importPaths = new Set.from(matches.map((match) => |
| + normalizeHtmlImportPath( |
| + match.group(1), |
| + match.group(2) == 'null' ? null : match.group(2), |
| + match.group(3)))); |
| + |
| + var newDartCode = dartCode.replaceAll(_htmlImportWithRawString, ''); |
| + var leftoverMatches = _htmlImportGeneral.allMatches(newDartCode); |
| + for (var match in leftoverMatches) { |
| + _logger.warning('Found HtmlImport constructor which was supplied an ' |
| + 'expression. Only raw strings are currently supported for the ' |
| + 'transformer, so ${match.group(1)} will be injected dynamically'); |
| + } |
| + transform.addOutput( |
| + new Asset.fromString(dartEntryPoint.id, newDartCode)); |
| + }).then((_) => htmlEntryPoint.readAsString()).then((html) { |
| + var doc = parse(html); |
| + for (var importPath in importPaths) { |
| + var import = new dom.Element.tag('link')..attributes = { |
| + 'rel': 'import', |
| + 'href': importPath, |
| + }; |
| + doc.head.append(import); |
| + } |
| + transform.addOutput( |
| + new Asset.fromString(htmlEntryPoint.id, doc.outerHtml)); |
| + }); |
| + }); |
| + } |
| + |
| + // Matches HtmlImport constructors which are supplied a raw string. These are |
| + // the only ones currently supported for inlining. |
| + final RegExp _htmlImportWithRawString = new RegExp( |
|
Jennifer Messerly
2015/01/29 21:32:37
this is vaguely terrifying :)
although it gives m
jakemac
2015/02/02 20:55:57
Done, now using InitializerPluginTransformer which
|
| + r"\n\s*new InitEntry\(const i[\d]*\.HtmlImport\('([\w\d\/\.:]*\.html)'\)," |
| + r"\sconst\sLibraryIdentifier\(#[\w\.]*, '?([\w_]*)'?, '([\w\d\/\.]*)'\)\)" |
| + r","); |
| + |
| + // Matches HtmlImport initializers which are supplied any arguments. This |
| + // is used to detect if any were left over and not inlined. |
| + final RegExp _htmlImportGeneral = new RegExp( |
| + r"\n\s*new InitEntry\(const i[\d]*\.HtmlImport\(([\w\d\.]*)\),\s.*\),"); |
| +} |