Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(383)

Side by Side Diff: pkg/polymer/lib/src/build/import_inliner.dart

Issue 159353005: code refactoring in import_inliner (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** Transfomer that inlines polymer-element definitions from html imports. */ 5 /** Transfomer that inlines polymer-element definitions from html imports. */
6 library polymer.src.build.import_inliner; 6 library polymer.src.build.import_inliner;
7 7
8 import 'dart:async'; 8 import 'dart:async';
9 import 'dart:convert'; 9 import 'dart:convert';
10 10
(...skipping 20 matching lines...) Expand all
31 final TransformOptions options; 31 final TransformOptions options;
32 32
33 ImportInliner(this.options); 33 ImportInliner(this.options);
34 34
35 /** Only run on entry point .html files. */ 35 /** Only run on entry point .html files. */
36 Future<bool> isPrimary(Asset input) => 36 Future<bool> isPrimary(Asset input) =>
37 new Future.value(options.isHtmlEntryPoint(input.id)); 37 new Future.value(options.isHtmlEntryPoint(input.id));
38 38
39 Future apply(Transform transform) { 39 Future apply(Transform transform) {
40 var logger = transform.logger; 40 var logger = transform.logger;
41 var seen = new Set<AssetId>();
42 var documents = [];
43 var id = transform.primaryInput.id; 41 var id = transform.primaryInput.id;
44 seen.add(id); 42 var seen = new Set<AssetId>()..add(id);
45 return readPrimaryAsHtml(transform).then((document) { 43 var scriptIds = [];
46 var future = _visitImports(document, id, transform, seen, documents); 44 var imported = new DocumentFragment();
47 return future.then((importsFound) { 45 Document document;
48 // We produce a secondary asset with extra information for later phases.
49 var secondaryId = id.addExtension('.scriptUrls');
50 if (!importsFound) {
51 transform.addOutput(transform.primaryInput);
52 transform.addOutput(new Asset.fromString(secondaryId, '[]'));
53 return;
54 }
55 46
56 // Split Dart script tags from all the other elements. Now that Dartium 47 return readPrimaryAsHtml(transform).then((doc) {
57 // only allows a single script tag per page, we can't inline script 48 document = doc;
58 // tags. Instead, we collect the urls of each script tag so we import 49 return _visitImports(doc, id, transform, seen, imported, scriptIds);
59 // them directly from the Dart bootstrap code. 50 }).then((importsFound) {
60 var scripts = [];
61 51
62 var fragment = new DocumentFragment(); 52 if (importsFound) {
63 for (var importedDoc in documents) { 53 document.body.insertBefore(imported, document.body.firstChild);
64 bool first = true; 54 transform.addOutput(new Asset.fromString(id, document.outerHtml));
65 for (var e in importedDoc.queryAll('script')) { 55 } else {
66 if (e.attributes['type'] == 'application/dart') { 56 transform.addOutput(transform.primaryInput);
67 e.remove(); 57 }
68 58
69 // only one Dart script per document is supported in Dartium. 59 // We produce a secondary asset with extra information for later phases.
70 if (first) { 60 transform.addOutput(new Asset.fromString(id.addExtension('.scriptUrls'),
71 first = false; 61 JSON.encode(scriptIds, toEncodable: (id) => id.serialize())));
72 scripts.add(e); 62 });
73 } else { 63 }
74 // TODO(jmesserly): remove this when we are running linter.
75 logger.warning('more than one Dart script per HTML document is '
76 'not supported. Script will be ignored.',
77 span: e.sourceSpan);
78 }
79 }
80 }
81 64
82 // TODO(jmesserly): should we merge the head too? 65 /**
83 fragment.nodes.addAll(importedDoc.body.nodes); 66 * Visits imports in [document] and add the imported documents to [documents].
84 } 67 * Documents are added in the order they appear, transitive imports are added
68 * first.
69 */
70 Future<bool> _visitImports(Document document, AssetId sourceId,
71 Transform transform, Set<AssetId> seen, DocumentFragment imported,
72 List<AssetId> scripts) {
85 73
86 document.body.insertBefore(fragment, document.body.firstChild); 74 bool hasImports = false;
87 75
88 for (var tag in document.queryAll('link')) { 76 // Note: we need to preserve the import order in the generated output.
89 if (tag.attributes['rel'] == 'import') tag.remove(); 77 return Future.forEach(document.queryAll('link'), (tag) {
Jennifer Messerly 2014/02/12 00:50:39 it occurs to me that pulling this forEach outside
90 } 78 if (tag.attributes['rel'] != 'import') return null;
79 var href = tag.attributes['href'];
80 var id = resolve(sourceId, href, transform.logger, tag.sourceSpan);
81 hasImports = true;
91 82
92 transform.addOutput(new Asset.fromString(id, document.outerHtml)); 83 tag.remove();
84 if (id == null || !seen.add(id) ||
85 (id.package == 'polymer' && id.path == 'lib/init.html')) return null;
93 86
94 var scriptIds = []; 87 // Loads an asset identified by [id], visits its imports and collects its
95 for (var script in scripts) { 88 // html imports. Then inlines it into the main document.
89 Document importedDoc;
90 return readAsHtml(id, transform).then((doc) {
91 // Visit transitive imports first.
92 importedDoc = doc;
93 return _visitImports(doc, id, transform, seen, imported, scripts);
94 }).then((_) {
95 new _UrlNormalizer(transform, id).visit(importedDoc);
96
97 // Note: use sourceId since we just normalized these above.
98 _extractScripts(sourceId, transform.logger, importedDoc, scripts);
99
100 // TODO(jmesserly): figure out how this is working in vulcanizer.
101 // Do they produce a <body> tag with a <head> and <body> inside?
102 imported.nodes
103 ..addAll(importedDoc.head.nodes)
104 ..addAll(importedDoc.body.nodes);
105 });
106 }).then((_) => hasImports);
107 }
108
109 /**
110 * Split Dart script tags from all the other elements. Now that Dartium
111 * only allows a single script tag per page, we can't inline script
112 * tags. Instead, we collect the urls of each script tag so we import
113 * them directly from the Dart bootstrap code.
114 */
115 static void _extractScripts(id, logger, document, List scriptIds) {
116 bool first = true;
117 for (var script in document.queryAll('script')) {
118 if (script.attributes['type'] == 'application/dart') {
119 script.remove();
120
121 // only one Dart script per document is supported in Dartium.
122 if (first) {
123 first = false;
124
96 var src = script.attributes['src']; 125 var src = script.attributes['src'];
97 if (src == null) { 126 if (src == null) {
98 logger.warning('unexpected script without a src url. The ' 127 logger.warning('unexpected script without a src url. The '
99 'ImportInliner transformer should run after running the ' 128 'ImportInliner transformer should run after running the '
100 'InlineCodeExtractor', span: script.sourceSpan); 129 'InlineCodeExtractor', span: script.sourceSpan);
101 continue; 130 continue;
102 } 131 }
103 scriptIds.add(resolve(id, src, logger, script.sourceSpan)); 132 scriptIds.add(resolve(id, src, logger, script.sourceSpan));
133
134 } else {
135 // TODO(jmesserly): remove this when we are running linter.
136 logger.warning('more than one Dart script per HTML '
137 'document is not supported. Script will be ignored.',
138 span: script.sourceSpan);
104 } 139 }
105 transform.addOutput(new Asset.fromString(secondaryId, 140 }
106 JSON.encode(scriptIds, toEncodable: (id) => id.serialize())));
107 });
108 });
109 }
110
111 /**
112 * Visits imports in [document] and add their polymer-element and script tags
113 * to [elements], unless they have already been [seen]. Elements are added in
114 * the order they appear, transitive imports are added first.
115 */
116 Future<bool> _visitImports(Document document, AssetId sourceId,
117 Transform transform, Set<AssetId> seen, List<Document> documents) {
118 var importIds = [];
119 bool hasImports = false;
120 for (var tag in document.queryAll('link')) {
121 if (tag.attributes['rel'] != 'import') continue;
122 var href = tag.attributes['href'];
123 var id = resolve(sourceId, href, transform.logger, tag.sourceSpan);
124 hasImports = true;
125 if (id == null || seen.contains(id) ||
126 (id.package == 'polymer' && id.path == 'lib/init.html')) continue;
127 importIds.add(id);
128 } 141 }
129
130 if (importIds.isEmpty) return new Future.value(hasImports);
131
132 // Note: we need to preserve the import order in the generated output.
133 return Future.forEach(importIds, (id) {
134 if (seen.contains(id)) return new Future.value(null);
135 seen.add(id);
136 return _collectImportedDocuments(id, transform, seen, documents);
137 }).then((_) => true);
138 }
139
140 /**
141 * Loads an asset identified by [id], visits its imports and collects it's
142 * polymer-element definitions and script tags.
143 */
144 Future _collectImportedDocuments(AssetId id, Transform transform,
145 Set<AssetId> seen, List documents) {
146 return readAsHtml(id, transform).then((document) {
147 return _visitImports(document, id, transform, seen, documents).then((_) {
148 new _UrlNormalizer(transform, id).visit(document);
149 documents.add(document);
150 });
151 });
152 } 142 }
153 } 143 }
154 144
145
155 /** Internally adjusts urls in the html that we are about to inline. */ 146 /** Internally adjusts urls in the html that we are about to inline. */
156 class _UrlNormalizer extends TreeVisitor { 147 class _UrlNormalizer extends TreeVisitor {
157 final Transform transform; 148 final Transform transform;
158 149
159 /** Asset where the original content (and original url) was found. */ 150 /** Asset where the original content (and original url) was found. */
160 final AssetId sourceId; 151 final AssetId sourceId;
161 152
162 _UrlNormalizer(this.transform, this.sourceId); 153 _UrlNormalizer(this.transform, this.sourceId);
163 154
164 visitElement(Element node) { 155 visitElement(Element node) {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 'cite', // in blockquote, del, ins, q 210 'cite', // in blockquote, del, ins, q
220 'data', // in object 211 'data', // in object
221 'formaction', // in button, input 212 'formaction', // in button, input
222 'href', // in a, area, link, base, command 213 'href', // in a, area, link, base, command
223 'icon', // in command 214 'icon', // in command
224 'manifest', // in html 215 'manifest', // in html
225 'poster', // in video 216 'poster', // in video
226 'src', // in audio, embed, iframe, img, input, script, source, track, 217 'src', // in audio, embed, iframe, img, input, script, source, track,
227 // video 218 // video
228 ]; 219 ];
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698