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

Side by Side Diff: pkg/polymer/lib/src/compiler.dart

Issue 23898009: Switch polymer's build.dart to use the new linter. This CL does the following (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: addressing john comments (part 2) - renamed files Created 7 years, 3 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 | « pkg/polymer/lib/src/barback_runner.dart ('k') | pkg/polymer/lib/src/compiler_options.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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 library compiler;
6
7 import 'dart:async';
8 import 'dart:collection' show SplayTreeMap;
9
10 import 'package:csslib/visitor.dart' show StyleSheet, treeToDebugString;
11 import 'package:html5lib/dom.dart';
12 import 'package:html5lib/parser.dart';
13
14 import 'analyzer.dart';
15 import 'css_analyzer.dart' show analyzeCss, findUrlsImported,
16 findImportsInStyleSheet, parseCss;
17 import 'css_emitters.dart' show rewriteCssUris,
18 emitComponentStyleSheet, emitOriginalCss, emitStyleSheet;
19 import 'file_system.dart';
20 import 'files.dart';
21 import 'info.dart';
22 import 'messages.dart';
23 import 'compiler_options.dart';
24 import 'utils.dart';
25
26 /**
27 * Parses an HTML file [contents] and returns a DOM-like tree.
28 * Note that [contents] will be a [String] if coming from a browser-based
29 * [FileSystem], or it will be a [List<int>] if running on the command line.
30 *
31 * Adds emitted error/warning to [messages], if [messages] is supplied.
32 */
33 Document parseHtml(contents, String sourcePath, Messages messages,
34 bool checkDocType) {
35 var parser = new HtmlParser(contents, generateSpans: true,
36 sourceUrl: sourcePath);
37 var document = parser.parse();
38
39 // Note: errors aren't fatal in HTML (unless strict mode is on).
40 // So just print them as warnings.
41 for (var e in parser.errors) {
42 if (checkDocType || e.errorCode != 'expected-doctype-but-got-start-tag') {
43 messages.warning(e.message, e.span);
44 }
45 }
46 return document;
47 }
48
49 /** Compiles an application written with Dart web components. */
50 class Compiler {
51 final FileSystem fileSystem;
52 final CompilerOptions options;
53 final List<SourceFile> files = <SourceFile>[];
54
55 String _mainPath;
56 String _packageRoot;
57 String _resetCssFile;
58 StyleSheet _cssResetStyleSheet;
59 Messages _messages;
60
61 FutureGroup _tasks;
62 Set _processed;
63
64 /** Information about source [files] given their href. */
65 final Map<String, FileInfo> info = new SplayTreeMap<String, FileInfo>();
66
67 final GlobalInfo global = new GlobalInfo();
68
69 /** Creates a compiler with [options] using [fileSystem]. */
70 Compiler(this.fileSystem, this.options, this._messages) {
71 _mainPath = options.inputFile;
72 var mainDir = path.dirname(_mainPath);
73 var baseDir = options.baseDir != null ? options.baseDir : mainDir;
74 _packageRoot = options.packageRoot != null ? options.packageRoot
75 : path.join(path.dirname(_mainPath), 'packages');
76
77 if (options.resetCssFile != null) {
78 _resetCssFile = options.resetCssFile;
79 if (path.isRelative(_resetCssFile)) {
80 // If CSS reset file path is relative from our current path.
81 _resetCssFile = path.resolve(_resetCssFile);
82 }
83 }
84
85 // Normalize paths - all should be relative or absolute paths.
86 if (path.isAbsolute(_mainPath) || path.isAbsolute(baseDir)
87 || path.isAbsolute(_packageRoot)) {
88 if (path.isRelative(_mainPath)) _mainPath = path.resolve(_mainPath);
89 if (path.isRelative(baseDir)) baseDir = path.resolve(baseDir);
90 if (path.isRelative(_packageRoot)) {
91 _packageRoot = path.resolve(_packageRoot);
92 }
93 }
94 }
95
96 /** Compile the application starting from the given input file. */
97 Future run() {
98 if (path.basename(_mainPath).endsWith('.dart')) {
99 _messages.error("Please provide an HTML file as your entry point.",
100 null);
101 return new Future.value(null);
102 }
103 return _parseAndDiscover(_mainPath).then((_) {
104 _analyze();
105
106 // Analyze all CSS files.
107 _time('Analyzed Style Sheets', '', () =>
108 analyzeCss(_packageRoot, files, info,
109 global.pseudoElements, _messages,
110 warningsAsErrors: options.warningsAsErrors));
111 });
112 }
113
114 /**
115 * Asynchronously parse [inputFile] and transitively discover web components
116 * to load and parse. Returns a future that completes when all files are
117 * processed.
118 */
119 Future _parseAndDiscover(String inputFile) {
120 _tasks = new FutureGroup();
121 _processed = new Set();
122 _processed.add(inputFile);
123 _tasks.add(_parseHtmlFile(new UrlInfo(inputFile, inputFile, null), true));
124 return _tasks.future;
125 }
126
127 void _processHtmlFile(UrlInfo inputUrl, SourceFile file) {
128 if (file == null) return;
129
130 bool isEntryPoint = _processed.length == 1;
131
132 files.add(file);
133
134 var fileInfo = _time('Analyzed definitions', inputUrl.url, () {
135 return analyzeDefinitions(global, inputUrl, file.document, _packageRoot,
136 _messages);
137 });
138 info[inputUrl.resolvedPath] = fileInfo;
139
140 if (isEntryPoint && _resetCssFile != null) {
141 _processed.add(_resetCssFile);
142 _tasks.add(_parseCssFile(new UrlInfo(_resetCssFile, _resetCssFile,
143 null)));
144 }
145
146 // Load component files referenced by [file].
147 for (var link in fileInfo.componentLinks) {
148 _loadFile(link, _parseHtmlFile);
149 }
150
151 // Load stylesheet files referenced by [file].
152 for (var link in fileInfo.styleSheetHrefs) {
153 _loadFile(link, _parseCssFile);
154 }
155
156 // Process any @imports inside of a <style> tag.
157 var urlInfos = findUrlsImported(fileInfo, fileInfo.inputUrl, _packageRoot,
158 file.document, _messages, options);
159 for (var urlInfo in urlInfos) {
160 _loadFile(urlInfo, _parseCssFile);
161 }
162
163 // Load .dart files being referenced in components.
164 for (var component in fileInfo.declaredComponents) {
165 // Process any @imports inside of the <style> tag in a component.
166 var urlInfos = findUrlsImported(component, fileInfo.inputUrl,
167 _packageRoot, component.element, _messages, options);
168 for (var urlInfo in urlInfos) {
169 _loadFile(urlInfo, _parseCssFile);
170 }
171 }
172 }
173
174 /**
175 * Helper function to load [urlInfo] and parse it using [loadAndParse] if it
176 * hasn't been loaded before.
177 */
178 void _loadFile(UrlInfo urlInfo, Future loadAndParse(UrlInfo inputUrl)) {
179 if (urlInfo == null) return;
180 var resolvedPath = urlInfo.resolvedPath;
181 if (!_processed.contains(resolvedPath)) {
182 _processed.add(resolvedPath);
183 _tasks.add(loadAndParse(urlInfo));
184 }
185 }
186
187 /** Parse an HTML file. */
188 Future _parseHtmlFile(UrlInfo inputUrl, [bool checkDocType = false]) {
189 var filePath = inputUrl.resolvedPath;
190 return fileSystem.readTextOrBytes(filePath)
191 .catchError((e) => _readError(e, inputUrl))
192 .then((source) {
193 if (source == null) return;
194 var file = new SourceFile(filePath);
195 file.document = _time('Parsed', filePath,
196 () => parseHtml(source, filePath, _messages, checkDocType));
197 _processHtmlFile(inputUrl, file);
198 });
199 }
200
201 /** Parse a stylesheet file. */
202 Future _parseCssFile(UrlInfo inputUrl) {
203 if (!options.emulateScopedCss) {
204 return new Future<SourceFile>.value(null);
205 }
206 var filePath = inputUrl.resolvedPath;
207 return fileSystem.readText(filePath)
208 .catchError((e) => _readError(e, inputUrl, isWarning: true))
209 .then((code) {
210 if (code == null) return;
211 var file = new SourceFile(filePath, type: SourceFile.STYLESHEET);
212 file.code = code;
213 _processCssFile(inputUrl, file);
214 });
215 }
216
217
218 SourceFile _readError(error, UrlInfo inputUrl, {isWarning: false}) {
219 var message = 'unable to open file "${inputUrl.resolvedPath}"';
220 if (options.verbose) {
221 message = '$message. original message:\n $error';
222 }
223 if (isWarning) {
224 _messages.warning(message, inputUrl.sourceSpan);
225 } else {
226 _messages.error(message, inputUrl.sourceSpan);
227 }
228 return null;
229 }
230
231 void _processCssFile(UrlInfo inputUrl, SourceFile cssFile) {
232 if (cssFile == null) return;
233
234 files.add(cssFile);
235
236 var fileInfo = new FileInfo(inputUrl);
237 info[inputUrl.resolvedPath] = fileInfo;
238
239 var styleSheet = parseCss(cssFile.code, _messages, options);
240 if (inputUrl.url == _resetCssFile) {
241 _cssResetStyleSheet = styleSheet;
242 } else if (styleSheet != null) {
243 _resolveStyleSheetImports(inputUrl, cssFile.path, styleSheet);
244 fileInfo.styleSheets.add(styleSheet);
245 }
246 }
247
248 /** Load and parse all style sheets referenced with an @imports. */
249 void _resolveStyleSheetImports(UrlInfo inputUrl, String processingFile,
250 StyleSheet styleSheet) {
251 var urlInfos = _time('CSS imports', processingFile, () =>
252 findImportsInStyleSheet(styleSheet, _packageRoot, inputUrl, _messages));
253
254 for (var urlInfo in urlInfos) {
255 if (urlInfo == null) break;
256 // Load any @imported stylesheet files referenced in this style sheet.
257 _loadFile(urlInfo, _parseCssFile);
258 }
259 }
260
261 /** Run the analyzer on every input html file. */
262 void _analyze() {
263 var uniqueIds = new IntIterator();
264 for (var file in files) {
265 if (file.isHtml) {
266 _time('Analyzed contents', file.path, () =>
267 analyzeFile(file, info, uniqueIds, global, _messages,
268 options.emulateScopedCss));
269 }
270 }
271 }
272
273 // TODO(jmesserly): refactor this and other CSS related transforms out of
274 // Compiler.
275 /**
276 * Generate an CSS file for all style sheets (main and components).
277 * Returns true if a file was generated, otherwise false.
278 */
279 bool _emitAllCss() {
280 if (!options.emulateScopedCss) return false;
281
282 var buff = new StringBuffer();
283
284 // Emit all linked style sheet files first.
285 for (var file in files) {
286 var css = new StringBuffer();
287 var fileInfo = info[file.path];
288 if (file.isStyleSheet) {
289 for (var styleSheet in fileInfo.styleSheets) {
290 css.write(
291 '/* Auto-generated from style sheet href = ${file.path} */\n'
292 '/* DO NOT EDIT. */\n\n');
293 css.write(emitStyleSheet(styleSheet, fileInfo));
294 css.write('\n\n');
295 }
296 }
297 }
298
299 // Emit all CSS for each component (style scoped).
300 for (var file in files) {
301 if (file.isHtml) {
302 var fileInfo = info[file.path];
303 for (var component in fileInfo.declaredComponents) {
304 for (var styleSheet in component.styleSheets) {
305 // Translate any URIs in CSS.
306 if (buff.isEmpty) {
307 buff.write(
308 '/* Auto-generated from components style tags. */\n'
309 '/* DO NOT EDIT. */\n\n');
310 }
311 buff.write(
312 '/* ==================================================== \n'
313 ' Component ${component.tagName} stylesheet \n'
314 ' ==================================================== */\n');
315
316 var tagName = component.tagName;
317 if (!component.hasAuthorStyles) {
318 if (_cssResetStyleSheet != null) {
319 // If component doesn't have apply-author-styles then we need to
320 // reset the CSS the styles for the component (if css-reset file
321 // option was passed).
322 buff.write('\n/* Start CSS Reset */\n');
323 var style;
324 if (options.emulateScopedCss) {
325 style = emitComponentStyleSheet(_cssResetStyleSheet, tagName);
326 } else {
327 style = emitOriginalCss(_cssResetStyleSheet);
328 }
329 buff.write(style);
330 buff.write('/* End CSS Reset */\n\n');
331 }
332 }
333 if (options.emulateScopedCss) {
334 buff.write(emitComponentStyleSheet(styleSheet, tagName));
335 } else {
336 buff.write(emitOriginalCss(styleSheet));
337 }
338 buff.write('\n\n');
339 }
340 }
341 }
342 }
343
344 if (buff.isEmpty) return false;
345 return true;
346 }
347
348 _time(String logMessage, String filePath, callback(),
349 {bool printTime: false}) {
350 var message = new StringBuffer();
351 message.write(logMessage);
352 var filename = path.basename(filePath);
353 for (int i = (60 - logMessage.length - filename.length); i > 0 ; i--) {
354 message.write(' ');
355 }
356 message.write(filename);
357 return time(message.toString(), callback,
358 printTime: options.verbose || printTime);
359 }
360 }
OLDNEW
« no previous file with comments | « pkg/polymer/lib/src/barback_runner.dart ('k') | pkg/polymer/lib/src/compiler_options.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698