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 library web_components.build.import_crawler; | |
5 | |
6 import 'dart:async'; | |
7 import 'dart:collection' show LinkedHashMap; | |
8 import 'package:code_transformers/assets.dart'; | |
9 import 'package:code_transformers/messages/build_logger.dart'; | |
10 import 'package:barback/barback.dart'; | |
11 import 'package:html/dom.dart' show Document, Element; | |
12 import 'common.dart'; | |
13 import 'messages.dart'; | |
14 | |
15 /// Information about an html import found in a document. | |
16 class ImportData { | |
17 /// The [AssetId] where the html import appeared. | |
18 final AssetId fromId; | |
19 | |
20 /// The [Document] where the html import appeared. | |
21 final Document document; | |
22 | |
23 /// The html import element itself. | |
24 final Element element; | |
25 | |
26 ImportData(this.document, this.element, {this.fromId}); | |
27 } | |
28 | |
29 /// A crawler for html imports. | |
30 class ImportCrawler { | |
31 // Can be either an AggregateTransform or Transform. | |
32 final _transform; | |
33 final BuildLogger _logger; | |
34 final AssetId _primaryInputId; | |
35 | |
36 // Optional parsed document for the primary id if available. | |
37 final Document _primaryDocument; | |
38 | |
39 ImportCrawler(this._transform, this._primaryInputId, this._logger, | |
40 {Document primaryDocument}) | |
41 : _primaryDocument = primaryDocument; | |
42 | |
43 /// Returns a post-ordered map of [AssetId]'s to [ImportData]. The [AssetId]'s | |
44 /// represent an asset which was discovered via an html import, and the | |
45 /// [ImportData] represents the [Document] where it was discovered and the | |
46 /// html import [Element] itself. | |
47 Future<LinkedHashMap<AssetId, ImportData>> crawlImports() { | |
48 var documents = new LinkedHashMap<AssetId, ImportData>(); | |
49 var seen = new Set<AssetId>(); | |
50 | |
51 Future doCrawl(AssetId assetId, | |
52 {Element import, Document document, AssetId from}) { | |
53 if (seen.contains(assetId)) return null; | |
54 seen.add(assetId); | |
55 | |
56 Future crawlImports(Document document) { | |
57 var imports = document | |
58 .querySelectorAll('link[rel="import"]') | |
59 .where((import) => import.attributes['type'] != 'css'); | |
60 var done = Future.forEach(imports, | |
61 (i) => doCrawl(_importId(assetId, i), import: i, from: assetId)); | |
62 | |
63 // Add this document after its dependencies. | |
64 return done.then((_) { | |
65 documents[assetId] = new ImportData(document, import, fromId: from); | |
66 }); | |
67 } | |
68 | |
69 if (document != null) { | |
70 return crawlImports(document); | |
71 } else { | |
72 return _transform.readInputAsString(assetId).then((html) { | |
73 return crawlImports(parseHtml(html, assetId.path)); | |
74 }).catchError((error) { | |
75 var span; | |
76 if (import != null) span = import.sourceSpan; | |
77 _logger.error(inlineImportFail.create({'error': error}), span: span); | |
78 }); | |
79 } | |
80 } | |
81 | |
82 return doCrawl(_primaryInputId, document: _primaryDocument) | |
83 .then((_) => documents); | |
84 } | |
85 | |
86 AssetId _importId(AssetId source, Element import) { | |
87 var url = import.attributes['href']; | |
88 return uriToAssetId(source, url, _transform.logger, import.sourceSpan); | |
89 } | |
90 } | |
OLD | NEW |