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

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

Issue 23224003: move polymer.dart into dart svn (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: add --deploy to todomvc sample Created 7 years, 4 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/analyzer.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 import 'dart:json' as json;
10
11 import 'package:analyzer_experimental/src/generated/ast.dart' show Directive, Ur iBasedDirective;
12 import 'package:csslib/visitor.dart' show StyleSheet, treeToDebugString;
13 import 'package:html5lib/dom.dart';
14 import 'package:html5lib/parser.dart';
15 import 'package:observe/transform.dart' show transformObservables;
16 import 'package:source_maps/span.dart' show Span;
17 import 'package:source_maps/refactor.dart' show TextEditTransaction;
18 import 'package:source_maps/printer.dart';
19
20 import 'analyzer.dart';
21 import 'css_analyzer.dart' show analyzeCss, findUrlsImported,
22 findImportsInStyleSheet, parseCss;
23 import 'css_emitters.dart' show rewriteCssUris,
24 emitComponentStyleSheet, emitOriginalCss, emitStyleSheet;
25 import 'dart_parser.dart';
26 import 'emitters.dart';
27 import 'file_system.dart';
28 import 'files.dart';
29 import 'info.dart';
30 import 'messages.dart';
31 import 'compiler_options.dart';
32 import 'paths.dart';
33 import 'utils.dart';
34
35 /**
36 * Parses an HTML file [contents] and returns a DOM-like tree.
37 * Note that [contents] will be a [String] if coming from a browser-based
38 * [FileSystem], or it will be a [List<int>] if running on the command line.
39 *
40 * Adds emitted error/warning to [messages], if [messages] is supplied.
41 */
42 Document parseHtml(contents, String sourcePath, Messages messages) {
43 var parser = new HtmlParser(contents, generateSpans: true,
44 sourceUrl: sourcePath);
45 var document = parser.parse();
46
47 // Note: errors aren't fatal in HTML (unless strict mode is on).
48 // So just print them as warnings.
49 for (var e in parser.errors) {
50 messages.warning(e.message, e.span);
51 }
52 return document;
53 }
54
55 /** Compiles an application written with Dart web components. */
56 class Compiler {
57 final FileSystem fileSystem;
58 final CompilerOptions options;
59 final List<SourceFile> files = <SourceFile>[];
60 final List<OutputFile> output = <OutputFile>[];
61
62 String _mainPath;
63 String _resetCssFile;
64 StyleSheet _cssResetStyleSheet;
65 PathMapper _pathMapper;
66 Messages _messages;
67
68 FutureGroup _tasks;
69 Set _processed;
70
71 /** Information about source [files] given their href. */
72 final Map<String, FileInfo> info = new SplayTreeMap<String, FileInfo>();
73 final _edits = new Map<DartCodeInfo, TextEditTransaction>();
74
75 final GlobalInfo global = new GlobalInfo();
76
77 /** Creates a compiler with [options] using [fileSystem]. */
78 Compiler(this.fileSystem, this.options, this._messages) {
79 _mainPath = options.inputFile;
80 var mainDir = path.dirname(_mainPath);
81 var baseDir = options.baseDir != null ? options.baseDir : mainDir;
82 var outputDir = options.outputDir != null ? options.outputDir : mainDir;
83 var packageRoot = options.packageRoot != null ? options.packageRoot
84 : path.join(path.dirname(_mainPath), 'packages');
85
86 if (options.resetCssFile != null) {
87 _resetCssFile = options.resetCssFile;
88 if (path.isRelative(_resetCssFile)) {
89 // If CSS reset file path is relative from our current path.
90 _resetCssFile = path.resolve(_resetCssFile);
91 }
92 }
93
94 // Normalize paths - all should be relative or absolute paths.
95 if (path.isAbsolute(_mainPath) || path.isAbsolute(baseDir) ||
96 path.isAbsolute(outputDir) || path.isAbsolute(packageRoot)) {
97 if (path.isRelative(_mainPath)) _mainPath = path.resolve(_mainPath);
98 if (path.isRelative(baseDir)) baseDir = path.resolve(baseDir);
99 if (path.isRelative(outputDir)) outputDir = path.resolve(outputDir);
100 if (path.isRelative(packageRoot)) {
101 packageRoot = path.resolve(packageRoot);
102 }
103 }
104 _pathMapper = new PathMapper(
105 baseDir, outputDir, packageRoot, options.forceMangle,
106 options.rewriteUrls);
107 }
108
109 /** Compile the application starting from the given input file. */
110 Future run() {
111 if (path.basename(_mainPath).endsWith('.dart')) {
112 _messages.error("Please provide an HTML file as your entry point.",
113 null);
114 return new Future.value(null);
115 }
116 return _parseAndDiscover(_mainPath).then((_) {
117 _analyze();
118
119 // Analyze all CSS files.
120 _time('Analyzed Style Sheets', '', () =>
121 analyzeCss(_pathMapper.packageRoot, files, info,
122 global.pseudoElements, _messages,
123 warningsAsErrors: options.warningsAsErrors));
124
125 // TODO(jmesserly): need to go through our errors, and figure out if some
126 // of them should be warnings instead.
127 if (_messages.hasErrors || options.analysisOnly) return;
128 _transformDart();
129 _emit();
130 });
131 }
132
133 /**
134 * Asynchronously parse [inputFile] and transitively discover web components
135 * to load and parse. Returns a future that completes when all files are
136 * processed.
137 */
138 Future _parseAndDiscover(String inputFile) {
139 _tasks = new FutureGroup();
140 _processed = new Set();
141 _processed.add(inputFile);
142 _tasks.add(_parseHtmlFile(new UrlInfo(inputFile, inputFile, null)));
143 return _tasks.future;
144 }
145
146 void _processHtmlFile(UrlInfo inputUrl, SourceFile file) {
147 if (file == null) return;
148
149 bool isEntryPoint = _processed.length == 1;
150
151 files.add(file);
152
153 var fileInfo = _time('Analyzed definitions', inputUrl.url, () {
154 return analyzeDefinitions(global, inputUrl, file.document,
155 _pathMapper.packageRoot, _messages, isEntryPoint: isEntryPoint);
156 });
157 info[inputUrl.resolvedPath] = fileInfo;
158
159 if (isEntryPoint && _resetCssFile != null) {
160 _processed.add(_resetCssFile);
161 _tasks.add(_parseCssFile(new UrlInfo(_resetCssFile, _resetCssFile,
162 null)));
163 }
164
165 _setOutputFilenames(fileInfo);
166 _processImports(fileInfo);
167
168 // Load component files referenced by [file].
169 for (var link in fileInfo.componentLinks) {
170 _loadFile(link, _parseHtmlFile);
171 }
172
173 // Load stylesheet files referenced by [file].
174 for (var link in fileInfo.styleSheetHrefs) {
175 _loadFile(link, _parseCssFile);
176 }
177
178 // Load .dart files being referenced in the page.
179 _loadFile(fileInfo.externalFile, _parseDartFile);
180
181 // Process any @imports inside of a <style> tag.
182 var urlInfos = findUrlsImported(fileInfo, fileInfo.inputUrl,
183 _pathMapper.packageRoot, file.document, _messages, options);
184 for (var urlInfo in urlInfos) {
185 _loadFile(urlInfo, _parseCssFile);
186 }
187
188 // Load .dart files being referenced in components.
189 for (var component in fileInfo.declaredComponents) {
190 if (component.externalFile != null) {
191 _loadFile(component.externalFile, _parseDartFile);
192 } else if (component.userCode != null) {
193 _processImports(component);
194 }
195
196 // Process any @imports inside of the <style> tag in a component.
197 var urlInfos = findUrlsImported(component,
198 component.declaringFile.inputUrl, _pathMapper.packageRoot,
199 component.element, _messages, options);
200 for (var urlInfo in urlInfos) {
201 _loadFile(urlInfo, _parseCssFile);
202 }
203 }
204 }
205
206 /**
207 * Helper function to load [urlInfo] and parse it using [loadAndParse] if it
208 * hasn't been loaded before.
209 */
210 void _loadFile(UrlInfo urlInfo, Future loadAndParse(UrlInfo inputUrl)) {
211 if (urlInfo == null) return;
212 var resolvedPath = urlInfo.resolvedPath;
213 if (!_processed.contains(resolvedPath)) {
214 _processed.add(resolvedPath);
215 _tasks.add(loadAndParse(urlInfo));
216 }
217 }
218
219 void _setOutputFilenames(FileInfo fileInfo) {
220 var filePath = fileInfo.dartCodeUrl.resolvedPath;
221 fileInfo.outputFilename = _pathMapper.mangle(path.basename(filePath),
222 '.dart', path.extension(filePath) == '.html');
223 for (var component in fileInfo.declaredComponents) {
224 var externalFile = component.externalFile;
225 var name = null;
226 if (externalFile != null) {
227 name = _pathMapper.mangle(
228 path.basename(externalFile.resolvedPath), '.dart');
229 } else {
230 var declaringFile = component.declaringFile;
231 var prefix = path.basename(declaringFile.inputUrl.resolvedPath);
232 if (declaringFile.declaredComponents.length == 1
233 && !declaringFile.codeAttached && !declaringFile.isEntryPoint) {
234 name = _pathMapper.mangle(prefix, '.dart', true);
235 } else {
236 var componentName = component.tagName.replaceAll('-', '_');
237 name = _pathMapper.mangle('${prefix}_$componentName', '.dart', true);
238 }
239 }
240 component.outputFilename = name;
241 }
242 }
243
244 /** Parse an HTML file. */
245 Future _parseHtmlFile(UrlInfo inputUrl) {
246 if (!_pathMapper.checkInputPath(inputUrl, _messages)) {
247 return new Future<SourceFile>.value(null);
248 }
249 var filePath = inputUrl.resolvedPath;
250 return fileSystem.readTextOrBytes(filePath)
251 .catchError((e) => _readError(e, inputUrl))
252 .then((source) {
253 if (source == null) return;
254 var file = new SourceFile(filePath);
255 file.document = _time('Parsed', filePath,
256 () => parseHtml(source, filePath, _messages));
257 _processHtmlFile(inputUrl, file);
258 });
259 }
260
261 /** Parse a Dart file. */
262 Future _parseDartFile(UrlInfo inputUrl) {
263 if (!_pathMapper.checkInputPath(inputUrl, _messages)) {
264 return new Future<SourceFile>.value(null);
265 }
266 var filePath = inputUrl.resolvedPath;
267 return fileSystem.readText(filePath)
268 .catchError((e) => _readError(e, inputUrl))
269 .then((code) {
270 if (code == null) return;
271 var file = new SourceFile(filePath, type: SourceFile.DART);
272 file.code = code;
273 _processDartFile(inputUrl, file);
274 });
275 }
276
277 /** Parse a stylesheet file. */
278 Future _parseCssFile(UrlInfo inputUrl) {
279 if (!options.emulateScopedCss ||
280 !_pathMapper.checkInputPath(inputUrl, _messages)) {
281 return new Future<SourceFile>.value(null);
282 }
283 var filePath = inputUrl.resolvedPath;
284 return fileSystem.readText(filePath)
285 .catchError((e) => _readError(e, inputUrl, isWarning: true))
286 .then((code) {
287 if (code == null) return;
288 var file = new SourceFile(filePath, type: SourceFile.STYLESHEET);
289 file.code = code;
290 _processCssFile(inputUrl, file);
291 });
292 }
293
294
295 SourceFile _readError(error, UrlInfo inputUrl, {isWarning: false}) {
296 var message = 'unable to open file "${inputUrl.resolvedPath}"';
297 if (options.verbose) {
298 message = '$message. original message:\n $error';
299 }
300 if (isWarning) {
301 _messages.warning(message, inputUrl.sourceSpan);
302 } else {
303 _messages.error(message, inputUrl.sourceSpan);
304 }
305 return null;
306 }
307
308 void _processDartFile(UrlInfo inputUrl, SourceFile dartFile) {
309 if (dartFile == null) return;
310
311 files.add(dartFile);
312
313 var resolvedPath = inputUrl.resolvedPath;
314 var fileInfo = new FileInfo(inputUrl);
315 info[resolvedPath] = fileInfo;
316 fileInfo.inlinedCode = parseDartCode(resolvedPath, dartFile.code);
317 fileInfo.outputFilename =
318 _pathMapper.mangle(path.basename(resolvedPath), '.dart', false);
319
320 _processImports(fileInfo);
321 }
322
323 void _processImports(LibraryInfo library) {
324 if (library.userCode == null) return;
325
326 for (var directive in library.userCode.directives) {
327 _loadFile(_getDirectiveUrlInfo(library, directive), _parseDartFile);
328 }
329 }
330
331 void _processCssFile(UrlInfo inputUrl, SourceFile cssFile) {
332 if (cssFile == null) return;
333
334 files.add(cssFile);
335
336 var fileInfo = new FileInfo(inputUrl);
337 info[inputUrl.resolvedPath] = fileInfo;
338
339 var styleSheet = parseCss(cssFile.code, _messages, options);
340 if (inputUrl.url == _resetCssFile) {
341 _cssResetStyleSheet = styleSheet;
342 } else if (styleSheet != null) {
343 _resolveStyleSheetImports(inputUrl, cssFile.path, styleSheet);
344 fileInfo.styleSheets.add(styleSheet);
345 }
346 }
347
348 /** Load and parse all style sheets referenced with an @imports. */
349 void _resolveStyleSheetImports(UrlInfo inputUrl, String processingFile,
350 StyleSheet styleSheet) {
351 var urlInfos = _time('CSS imports', processingFile, () =>
352 findImportsInStyleSheet(styleSheet, _pathMapper.packageRoot, inputUrl,
353 _messages));
354
355 for (var urlInfo in urlInfos) {
356 if (urlInfo == null) break;
357 // Load any @imported stylesheet files referenced in this style sheet.
358 _loadFile(urlInfo, _parseCssFile);
359 }
360 }
361
362 String _directiveUri(Directive directive) {
363 var uriDirective = (directive as UriBasedDirective).uri;
364 return (uriDirective as dynamic).value;
365 }
366
367 UrlInfo _getDirectiveUrlInfo(LibraryInfo library, Directive directive) {
368 var uri = _directiveUri(directive);
369 if (uri.startsWith('dart:')) return null;
370 if (uri.startsWith('package:') && uri.startsWith('package:polymer/')) {
371 // Don't process our own package -- we'll implement @observable manually.
372 return null;
373 }
374
375 var span = library.userCode.sourceFile.span(
376 directive.offset, directive.end);
377 return UrlInfo.resolve(uri, library.dartCodeUrl, span,
378 _pathMapper.packageRoot, _messages);
379 }
380
381 /**
382 * Transform Dart source code.
383 * Currently, the only transformation is [transformObservables].
384 * Calls _emitModifiedDartFiles to write the transformed files.
385 */
386 void _transformDart() {
387 var libraries = _findAllDartLibraries();
388
389 var transformed = [];
390 for (var lib in libraries) {
391 var userCode = lib.userCode;
392 var transaction = transformObservables(userCode.compilationUnit,
393 userCode.sourceFile, userCode.code, _messages);
394 if (transaction != null) {
395 _edits[lib.userCode] = transaction;
396 if (transaction.hasEdits) {
397 transformed.add(lib);
398 } else if (lib.htmlFile != null) {
399 // All web components will be transformed too. Track that.
400 transformed.add(lib);
401 }
402 }
403 }
404
405 _findModifiedDartFiles(libraries, transformed);
406
407 libraries.forEach(_fixImports);
408
409 _emitModifiedDartFiles(libraries);
410 }
411
412 /**
413 * Finds all Dart code libraries.
414 * Each library will have [LibraryInfo.inlinedCode] that is non-null.
415 * Also each inlinedCode will be unique.
416 */
417 List<LibraryInfo> _findAllDartLibraries() {
418 var libs = <LibraryInfo>[];
419 void _addLibrary(LibraryInfo lib) {
420 if (lib.inlinedCode != null) libs.add(lib);
421 }
422
423 for (var sourceFile in files) {
424 var file = info[sourceFile.path];
425 _addLibrary(file);
426 file.declaredComponents.forEach(_addLibrary);
427 }
428
429 // Assert that each file path is unique.
430 assert(_uniquePaths(libs));
431 return libs;
432 }
433
434 bool _uniquePaths(List<LibraryInfo> libs) {
435 var seen = new Set();
436 for (var lib in libs) {
437 if (seen.contains(lib.inlinedCode)) {
438 throw new StateError('internal error: '
439 'duplicate user code for ${lib.dartCodeUrl.resolvedPath}.'
440 ' Files were: $files');
441 }
442 seen.add(lib.inlinedCode);
443 }
444 return true;
445 }
446
447 /**
448 * Queue modified Dart files to be written.
449 * This will not write files that are handled by [WebComponentEmitter] and
450 * [EntryPointEmitter].
451 */
452 void _emitModifiedDartFiles(List<LibraryInfo> libraries) {
453 for (var lib in libraries) {
454 // Components will get emitted by WebComponentEmitter, and the
455 // entry point will get emitted by MainPageEmitter.
456 // So we only need to worry about other .dart files.
457 if (lib.modified && lib is FileInfo &&
458 lib.htmlFile == null && !lib.isEntryPoint) {
459 var transaction = _edits[lib.userCode];
460
461 // Save imports that were modified by _fixImports.
462 for (var d in lib.userCode.directives) {
463 transaction.edit(d.offset, d.end, d.toString());
464 }
465
466 if (!lib.userCode.isPart) {
467 var pos = lib.userCode.firstPartOffset;
468 // Note: we use a different prefix than "autogenerated" to make
469 // ChangeRecord unambiguous. Otherwise it would be imported by this
470 // and polymer, resulting in a collision.
471 // TODO(jmesserly): only generate this for libraries that need it.
472 transaction.edit(pos, pos, "\nimport "
473 "'package:observe/observe.dart' as __observe;\n");
474 }
475 _emitFileAndSourceMaps(lib, transaction.commit(), lib.dartCodeUrl);
476 }
477 }
478 }
479
480 /**
481 * This method computes which Dart files have been modified, starting
482 * from [transformed] and marking recursively through all files that import
483 * the modified files.
484 */
485 void _findModifiedDartFiles(List<LibraryInfo> libraries,
486 List<FileInfo> transformed) {
487
488 if (transformed.length == 0) return;
489
490 // Compute files that reference each file, then use this information to
491 // flip the modified bit transitively. This is a lot simpler than trying
492 // to compute it the other way because of circular references.
493 for (var lib in libraries) {
494 for (var directive in lib.userCode.directives) {
495 var importPath = _getDirectiveUrlInfo(lib, directive);
496 if (importPath == null) continue;
497
498 var importInfo = info[importPath.resolvedPath];
499 if (importInfo != null) {
500 importInfo.referencedBy.add(lib);
501 }
502 }
503 }
504
505 // Propegate the modified bit to anything that references a modified file.
506 void setModified(LibraryInfo library) {
507 if (library.modified) return;
508 library.modified = true;
509 library.referencedBy.forEach(setModified);
510 }
511 transformed.forEach(setModified);
512
513 for (var lib in libraries) {
514 // We don't need this anymore, so free it.
515 lib.referencedBy = null;
516 }
517 }
518
519 void _fixImports(LibraryInfo library) {
520 // Fix imports. Modified files must use the generated path, otherwise
521 // we need to make the path relative to the input.
522 for (var directive in library.userCode.directives) {
523 var importPath = _getDirectiveUrlInfo(library, directive);
524 if (importPath == null) continue;
525 var importInfo = info[importPath.resolvedPath];
526 if (importInfo == null) continue;
527
528 String newUri = null;
529 if (importInfo.modified) {
530 // Use the generated URI for this file.
531 newUri = _pathMapper.importUrlFor(library, importInfo);
532 } else if (options.rewriteUrls) {
533 // Get the relative path to the input file.
534 newUri = _pathMapper.transformUrl(
535 library.dartCodeUrl.resolvedPath, directive.uri.value);
536 }
537 if (newUri != null) {
538 directive.uri = createStringLiteral(newUri);
539 }
540 }
541 }
542
543 /** Run the analyzer on every input html file. */
544 void _analyze() {
545 var uniqueIds = new IntIterator();
546 for (var file in files) {
547 if (file.isHtml) {
548 _time('Analyzed contents', file.path, () =>
549 analyzeFile(file, info, uniqueIds, global, _messages,
550 options.emulateScopedCss));
551 }
552 }
553 }
554
555 /** Emit the generated code corresponding to each input file. */
556 void _emit() {
557 for (var file in files) {
558 if (file.isDart || file.isStyleSheet) continue;
559 _time('Codegen', file.path, () {
560 var fileInfo = info[file.path];
561 _emitComponents(fileInfo);
562 });
563 }
564
565 var entryPoint = files[0];
566 assert(info[entryPoint.path].isEntryPoint);
567 _emitMainDart(entryPoint);
568 _emitMainHtml(entryPoint);
569
570 assert(_unqiueOutputs());
571 }
572
573 bool _unqiueOutputs() {
574 var seen = new Set();
575 for (var file in output) {
576 if (seen.contains(file.path)) {
577 throw new StateError('internal error: '
578 'duplicate output file ${file.path}. Files were: $output');
579 }
580 seen.add(file.path);
581 }
582 return true;
583 }
584
585 /** Emit the main .dart file. */
586 void _emitMainDart(SourceFile file) {
587 var fileInfo = info[file.path];
588
589 var codeInfo = fileInfo.userCode;
590 if (codeInfo != null) {
591 var printer = new NestedPrinter(0);
592 if (codeInfo.libraryName == null) {
593 printer.addLine('library ${fileInfo.libraryName};');
594 }
595 printer.add(codeInfo.code);
596 _emitFileAndSourceMaps(fileInfo, printer, fileInfo.dartCodeUrl);
597 }
598 }
599
600 // TODO(jmesserly): refactor this out of Compiler.
601 /** Generate an html file with the (trimmed down) main html page. */
602 void _emitMainHtml(SourceFile file) {
603 var fileInfo = info[file.path];
604
605 var bootstrapName = '${path.basename(file.path)}_bootstrap.dart';
606 var bootstrapPath = path.join(path.dirname(file.path), bootstrapName);
607 var bootstrapOutPath = _pathMapper.outputPath(bootstrapPath, '');
608 var bootstrapOutName = path.basename(bootstrapOutPath);
609 var bootstrapInfo = new FileInfo(new UrlInfo('', bootstrapPath, null));
610 var printer = generateBootstrapCode(bootstrapInfo, fileInfo, global,
611 _pathMapper, options);
612 printer.build(bootstrapOutPath);
613 output.add(new OutputFile(
614 bootstrapOutPath, printer.text, source: file.path));
615
616 var document = file.document;
617 var hasCss = _emitAllCss();
618 transformMainHtml(document, fileInfo, _pathMapper, hasCss,
619 options.rewriteUrls, _messages, global, bootstrapOutName);
620 output.add(new OutputFile(_pathMapper.outputPath(file.path, '.html'),
621 document.outerHtml, source: file.path));
622 }
623
624 // TODO(jmesserly): refactor this and other CSS related transforms out of
625 // Compiler.
626 /**
627 * Generate an CSS file for all style sheets (main and components).
628 * Returns true if a file was generated, otherwise false.
629 */
630 bool _emitAllCss() {
631 if (!options.emulateScopedCss) return false;
632
633 var buff = new StringBuffer();
634
635 // Emit all linked style sheet files first.
636 for (var file in files) {
637 var css = new StringBuffer();
638 var fileInfo = info[file.path];
639 if (file.isStyleSheet) {
640 for (var styleSheet in fileInfo.styleSheets) {
641 // Translate any URIs in CSS.
642 rewriteCssUris(_pathMapper, fileInfo.inputUrl.resolvedPath,
643 options.rewriteUrls, styleSheet);
644 css.write(
645 '/* Auto-generated from style sheet href = ${file.path} */\n'
646 '/* DO NOT EDIT. */\n\n');
647 css.write(emitStyleSheet(styleSheet, fileInfo));
648 css.write('\n\n');
649 }
650
651 // Emit the linked style sheet in the output directory.
652 if (fileInfo.inputUrl.url != _resetCssFile) {
653 var outCss = _pathMapper.outputPath(fileInfo.inputUrl.resolvedPath,
654 '');
655 output.add(new OutputFile(outCss, css.toString()));
656 }
657 }
658 }
659
660 // Emit all CSS for each component (style scoped).
661 for (var file in files) {
662 if (file.isHtml) {
663 var fileInfo = info[file.path];
664 for (var component in fileInfo.declaredComponents) {
665 for (var styleSheet in component.styleSheets) {
666 // Translate any URIs in CSS.
667 rewriteCssUris(_pathMapper, fileInfo.inputUrl.resolvedPath,
668 options.rewriteUrls, styleSheet);
669
670 if (buff.isEmpty) {
671 buff.write(
672 '/* Auto-generated from components style tags. */\n'
673 '/* DO NOT EDIT. */\n\n');
674 }
675 buff.write(
676 '/* ==================================================== \n'
677 ' Component ${component.tagName} stylesheet \n'
678 ' ==================================================== */\n');
679
680 var tagName = component.tagName;
681 if (!component.hasAuthorStyles) {
682 if (_cssResetStyleSheet != null) {
683 // If component doesn't have apply-author-styles then we need to
684 // reset the CSS the styles for the component (if css-reset file
685 // option was passed).
686 buff.write('\n/* Start CSS Reset */\n');
687 var style;
688 if (options.emulateScopedCss) {
689 style = emitComponentStyleSheet(_cssResetStyleSheet, tagName);
690 } else {
691 style = emitOriginalCss(_cssResetStyleSheet);
692 }
693 buff.write(style);
694 buff.write('/* End CSS Reset */\n\n');
695 }
696 }
697 if (options.emulateScopedCss) {
698 buff.write(emitComponentStyleSheet(styleSheet, tagName));
699 } else {
700 buff.write(emitOriginalCss(styleSheet));
701 }
702 buff.write('\n\n');
703 }
704 }
705 }
706 }
707
708 if (buff.isEmpty) return false;
709
710 var cssPath = _pathMapper.outputPath(_mainPath, '.css', true);
711 output.add(new OutputFile(cssPath, buff.toString()));
712 return true;
713 }
714
715 /** Emits the Dart code for all components in [fileInfo]. */
716 void _emitComponents(FileInfo fileInfo) {
717 for (var component in fileInfo.declaredComponents) {
718 // TODO(terry): Handle more than one stylesheet per component
719 if (component.styleSheets.length > 1 && options.emulateScopedCss) {
720 var span = component.externalFile != null
721 ? component.externalFile.sourceSpan : null;
722 _messages.warning(
723 'Component has more than one stylesheet - first stylesheet used.',
724 span);
725 }
726 var printer = emitPolymerElement(
727 component, _pathMapper, _edits[component.userCode], options);
728 _emitFileAndSourceMaps(component, printer, component.externalFile);
729 }
730 }
731
732 /**
733 * Emits a file that was created using [NestedPrinter] and it's corresponding
734 * source map file.
735 */
736 void _emitFileAndSourceMaps(
737 LibraryInfo lib, NestedPrinter printer, UrlInfo dartCodeUrl) {
738 // Bail if we had an error generating the code for the file.
739 if (printer == null) return;
740
741 var libPath = _pathMapper.outputLibraryPath(lib);
742 var dir = path.dirname(libPath);
743 var filename = path.basename(libPath);
744 printer.add('\n//# sourceMappingURL=$filename.map');
745 printer.build(libPath);
746 var sourcePath = dartCodeUrl != null ? dartCodeUrl.resolvedPath : null;
747 output.add(new OutputFile(libPath, printer.text, source: sourcePath));
748 // Fix-up the paths in the source map file
749 var sourceMap = json.parse(printer.map);
750 var urls = sourceMap['sources'];
751 for (int i = 0; i < urls.length; i++) {
752 urls[i] = path.relative(urls[i], from: dir);
753 }
754 output.add(new OutputFile(path.join(dir, '$filename.map'),
755 json.stringify(sourceMap)));
756 }
757
758 _time(String logMessage, String filePath, callback(),
759 {bool printTime: false}) {
760 var message = new StringBuffer();
761 message.write(logMessage);
762 var filename = path.basename(filePath);
763 for (int i = (60 - logMessage.length - filename.length); i > 0 ; i--) {
764 message.write(' ');
765 }
766 message.write(filename);
767 return time(message.toString(), callback,
768 printTime: options.verbose || printTime);
769 }
770 }
OLDNEW
« no previous file with comments | « pkg/polymer/lib/src/analyzer.dart ('k') | pkg/polymer/lib/src/compiler_options.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698