OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013, 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 /** Transfomer that inlines polymer-element definitions from html imports. */ |
| 6 library polymer.src.transform.import_inliner; |
| 7 |
| 8 import 'dart:async'; |
| 9 |
| 10 import 'package:barback/barback.dart'; |
| 11 import 'package:html5lib/dom.dart' show Document, Node, DocumentFragment; |
| 12 import 'common.dart'; |
| 13 |
| 14 /** Recursively inlines polymer-element definitions from html imports. */ |
| 15 // TODO(sigmund): make sure we match semantics of html-imports for tags other |
| 16 // than polymer-element (see dartbug.com/12613). |
| 17 class ImportedElementInliner extends Transformer { |
| 18 Future<bool> isPrimary(Asset input) => |
| 19 new Future.value(input.id.extension == ".html"); |
| 20 |
| 21 Future apply(Transform transform) { |
| 22 var seen = new Set<AssetId>(); |
| 23 var elements = []; |
| 24 var id = transform.primaryId; |
| 25 seen.add(id); |
| 26 return getPrimaryContent(transform).then((content) { |
| 27 var document = parseHtml(content, id.path, transform.logger); |
| 28 var future = _visitImports(document, id, transform, seen, elements); |
| 29 return future.then((importsFound) { |
| 30 if (!importsFound) { |
| 31 transform.addOutput(new Asset.fromString(id, content)); |
| 32 return; |
| 33 } |
| 34 |
| 35 for (var tag in document.queryAll('link')) { |
| 36 if (tag.attributes['rel'] == 'import') { |
| 37 tag.remove(); |
| 38 } |
| 39 } |
| 40 var fragment = new DocumentFragment()..nodes.addAll(elements); |
| 41 document.body.insertBefore(fragment, |
| 42 //TODO(jmesserly): add Node.firstChild to html5lib |
| 43 document.body.nodes.length == 0 ? null : document.body.nodes[0]); |
| 44 transform.addOutput(new Asset.fromString(id, document.outerHtml)); |
| 45 }); |
| 46 }); |
| 47 } |
| 48 |
| 49 /** |
| 50 * Visits imports in [document] and add their polymer-element definitions to |
| 51 * [elements], unless they have already been [seen]. Elements are added in the |
| 52 * order they appear, transitive imports are added first. |
| 53 */ |
| 54 Future<bool> _visitImports(Document document, AssetId sourceId, |
| 55 Transform transform, Set<AssetId> seen, List<Node> elements) { |
| 56 var importIds = []; |
| 57 bool hasImports = false; |
| 58 for (var tag in document.queryAll('link')) { |
| 59 if (tag.attributes['rel'] != 'import') continue; |
| 60 var href = tag.attributes['href']; |
| 61 var id = resolve(sourceId, href, transform.logger, tag.sourceSpan); |
| 62 hasImports = true; |
| 63 if (id == null || seen.contains(id)) continue; |
| 64 importIds.add(id); |
| 65 } |
| 66 |
| 67 if (importIds.isEmpty) return new Future.value(hasImports); |
| 68 |
| 69 // Note: we need to preserve the import order in the generated output. |
| 70 return Future.forEach(importIds, (id) { |
| 71 if (seen.contains(id)) return new Future.value(null); |
| 72 seen.add(id); |
| 73 return _collectPolymerElements(id, transform, seen, elements); |
| 74 }).then((_) => true); |
| 75 } |
| 76 |
| 77 /** |
| 78 * Loads an asset identified by [id], visits its imports and collects it's |
| 79 * polymer-element definitions. |
| 80 */ |
| 81 Future _collectPolymerElements( |
| 82 AssetId id, Transform transform, Set<AssetId> seen, List elements) { |
| 83 return getContent(transform, id) |
| 84 .then((content) => parseHtml( |
| 85 content, id.path, transform.logger, checkDocType: false)) |
| 86 .then((document) { |
| 87 return _visitImports(document, id, transform, seen, elements) |
| 88 .then((_) => elements.addAll(document.queryAll('polymer-element'))); |
| 89 }); |
| 90 } |
| 91 } |
OLD | NEW |