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

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

Issue 12474002: Support for parsing all CSS and producing one CSS file (Closed) Base URL: https://github.com/dart-lang/web-ui.git@master
Patch Set: Reworked URI computation and added test for URI fixup. Created 7 years, 9 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
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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 library compiler; 5 library compiler;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection' show SplayTreeMap; 8 import 'dart:collection' show SplayTreeMap;
9 import 'dart:json' as json; 9 import 'dart:json' as json;
10 import 'package:analyzer_experimental/src/generated/ast.dart' show Directive, Ur iBasedDirective; 10 import 'package:analyzer_experimental/src/generated/ast.dart' show Directive, Ur iBasedDirective;
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 _processImports(fileInfo); 156 _processImports(fileInfo);
157 157
158 // Load component files referenced by [file]. 158 // Load component files referenced by [file].
159 for (var href in fileInfo.componentLinks) { 159 for (var href in fileInfo.componentLinks) {
160 if (!_processed.contains(href)) { 160 if (!_processed.contains(href)) {
161 _processed.add(href); 161 _processed.add(href);
162 _tasks.add(_parseHtmlFile(href).then(_processHtmlFile)); 162 _tasks.add(_parseHtmlFile(href).then(_processHtmlFile));
163 } 163 }
164 } 164 }
165 165
166 // Load stylesheet files referenced by [file].
167 for (var href in fileInfo.styleSheetHref) {
168 if (!_processed.contains(href)) {
169 _processed.add(href);
170 _tasks.add(_parseStyleSheetFile(href).then(_processStyleSheetFile));
171 }
172 }
173
166 // Load .dart files being referenced in the page. 174 // Load .dart files being referenced in the page.
167 var src = fileInfo.externalFile; 175 var src = fileInfo.externalFile;
168 if (src != null && !_processed.contains(src)) { 176 if (src != null && !_processed.contains(src)) {
169 _processed.add(src); 177 _processed.add(src);
170 _tasks.add(_parseDartFile(src).then(_processDartFile)); 178 _tasks.add(_parseDartFile(src).then(_processDartFile));
171 } 179 }
172 180
173 // Load .dart files being referenced in components. 181 // Load .dart files being referenced in components.
174 for (var component in fileInfo.declaredComponents) { 182 for (var component in fileInfo.declaredComponents) {
175 var src = component.externalFile; 183 var src = component.externalFile;
(...skipping 13 matching lines...) Expand all
189 file.document = _time('Parsed', path, 197 file.document = _time('Parsed', path,
190 () => parseHtml(source, path, _messages)); 198 () => parseHtml(source, path, _messages));
191 return file; 199 return file;
192 }) 200 })
193 .catchError((e) => _readError(e, path)); 201 .catchError((e) => _readError(e, path));
194 } 202 }
195 203
196 /** Parse [filename] and treat it as a .dart file. */ 204 /** Parse [filename] and treat it as a .dart file. */
197 Future<SourceFile> _parseDartFile(Path path) { 205 Future<SourceFile> _parseDartFile(Path path) {
198 return fileSystem.readText(path) 206 return fileSystem.readText(path)
199 .then((code) => new SourceFile(path, isDart: true)..code = code) 207 .then((code) => new SourceFile(path, type: SourceFile.DART)
208 ..code = code)
200 .catchError((e) => _readError(e, path)); 209 .catchError((e) => _readError(e, path));
201 } 210 }
202 211
203 SourceFile _readError(error, Path path) { 212 SourceFile _readError(error, Path path) {
204 _messages.error('exception while reading file, original message:\n $error', 213 _messages.error('exception while reading file, original message:\n $error',
205 null, file: path); 214 null, file: path);
206 215
207 return null; 216 return null;
208 } 217 }
209 218
(...skipping 20 matching lines...) Expand all
230 if (uri.startsWith('package:web_ui/observe')) { 239 if (uri.startsWith('package:web_ui/observe')) {
231 _useObservers = true; 240 _useObservers = true;
232 } 241 }
233 } else if (!_processed.contains(src)) { 242 } else if (!_processed.contains(src)) {
234 _processed.add(src); 243 _processed.add(src);
235 _tasks.add(_parseDartFile(src).then(_processDartFile)); 244 _tasks.add(_parseDartFile(src).then(_processDartFile));
236 } 245 }
237 } 246 }
238 } 247 }
239 248
249 /** Parse [filename] and treat it as a .dart file. */
250 Future<SourceFile> _parseStyleSheetFile(Path path) {
251 return fileSystem.readText(path)
252 .then((code) =>
253 new SourceFile(path, type: SourceFile.STYLESHEET)..code = code)
254 .catchError((e) => _readError(e, path));
255 }
256
257 void _processStyleSheetFile(SourceFile cssFile) {
258 if (!_shouldProcessFile(cssFile)) return;
259
260 files.add(cssFile);
261
262 var fileInfo = new FileInfo(cssFile.path);
263 info[cssFile.path] = fileInfo;
264
265 var uriVisitor = new UriVisitor(_pathInfo, _mainPath, fileInfo.path,
266 options.rewriteUrls);
267 var styleSheet = _parseCss(cssFile.path.toString(),
268 cssFile.code, uriVisitor, options);
269 if (styleSheet != null) {
270 fileInfo.styleSheets.add(styleSheet);
271 }
272 }
273
240 Path _getDirectivePath(LibraryInfo libInfo, Directive directive) { 274 Path _getDirectivePath(LibraryInfo libInfo, Directive directive) {
241 var uriDirective = (directive as UriBasedDirective).uri; 275 var uriDirective = (directive as UriBasedDirective).uri;
242 var uri = uriDirective.value; 276 var uri = uriDirective.value;
243 if (uri.startsWith('dart:')) return null; 277 if (uri.startsWith('dart:')) return null;
244 278
245 if (uri.startsWith('package:')) { 279 if (uri.startsWith('package:')) {
246 // Don't process our own package -- we'll implement @observable manually. 280 // Don't process our own package -- we'll implement @observable manually.
247 if (uri.startsWith('package:web_ui/')) return null; 281 if (uri.startsWith('package:web_ui/')) return null;
248 282
249 return _pathInfo.packageRoot.join(new Path(uri.substring(8))); 283 return _pathInfo.packageRoot.join(new Path(uri.substring(8)));
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 if (newUri != null) { 444 if (newUri != null) {
411 directive.uri = createStringLiteral(newUri); 445 directive.uri = createStringLiteral(newUri);
412 } 446 }
413 } 447 }
414 } 448 }
415 449
416 /** Run the analyzer on every input html file. */ 450 /** Run the analyzer on every input html file. */
417 void _analyze() { 451 void _analyze() {
418 var uniqueIds = new IntIterator(); 452 var uniqueIds = new IntIterator();
419 for (var file in files) { 453 for (var file in files) {
420 if (file.isDart) continue; 454 if (file.isHtml) {
421 _time('Analyzed contents', file.path, () => 455 _time('Analyzed contents', file.path, () =>
422 analyzeFile(file, info, uniqueIds, _messages)); 456 analyzeFile(file, info, uniqueIds, _messages));
457 }
423 } 458 }
424 } 459 }
425 460
426 /** Emit the generated code corresponding to each input file. */ 461 /** Emit the generated code corresponding to each input file. */
427 void _emit() { 462 void _emit() {
428 for (var file in files) { 463 for (var file in files) {
429 if (file.isDart) continue; 464 if (file.isDart || file.isStyleSheet) continue;
430 _time('Codegen', file.path, () { 465 _time('Codegen', file.path, () {
431 var fileInfo = info[file.path]; 466 var fileInfo = info[file.path];
432 cleanHtmlNodes(fileInfo); 467 cleanHtmlNodes(fileInfo);
433 _processStylesheet(fileInfo, options: options); 468 if (!fileInfo.isEntryPoint) {
469 // Check all components files for <style> tags and parse the CSS.
470 var uriVisitor = new UriVisitor(_pathInfo, _mainPath, fileInfo.path,
471 options.rewriteUrls);
472 _processStylesheet(uriVisitor, fileInfo, options: options);
473 }
434 fixupHtmlCss(fileInfo, options); 474 fixupHtmlCss(fileInfo, options);
435 _emitComponents(fileInfo); 475 _emitComponents(fileInfo);
436 if (fileInfo.isEntryPoint) { 476 if (fileInfo.isEntryPoint) {
437 _emitMainDart(file); 477 _emitMainDart(file);
438 _emitMainHtml(file); 478 _emitMainHtml(file);
439 } 479 }
440 }); 480 });
441 } 481 }
482
483 if (options.processCss) {
484 _emitAllCss();
485 }
442 } 486 }
443 487
444 /** Emit the main .dart file. */ 488 /** Emit the main .dart file. */
445 void _emitMainDart(SourceFile file) { 489 void _emitMainDart(SourceFile file) {
446 var fileInfo = info[file.path]; 490 var fileInfo = info[file.path];
447 var printer = new MainPageEmitter(fileInfo) 491 var printer = new MainPageEmitter(fileInfo, options.processCss)
448 .run(file.document, _pathInfo, _edits[fileInfo.userCode], 492 .run(file.document, _pathInfo, _edits[fileInfo.userCode],
449 options.rewriteUrls); 493 options.rewriteUrls);
450 _emitFileAndSourceMaps(fileInfo, printer, fileInfo.inputPath); 494 _emitFileAndSourceMaps(fileInfo, printer, fileInfo.inputPath);
451 } 495 }
452 496
453 /** Generate an html file with the (trimmed down) main html page. */ 497 /** Generate an html file with the (trimmed down) main html page. */
454 void _emitMainHtml(SourceFile file) { 498 void _emitMainHtml(SourceFile file) {
455 var fileInfo = info[file.path]; 499 var fileInfo = info[file.path];
456 500
457 var bootstrapName = '${file.path.filename}_bootstrap.dart'; 501 var bootstrapName = '${file.path.filename}_bootstrap.dart';
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 if (link.attributes["rel"] == "components") { 533 if (link.attributes["rel"] == "components") {
490 link.remove(); 534 link.remove();
491 } 535 }
492 } 536 }
493 537
494 _addAutoGeneratedComment(file); 538 _addAutoGeneratedComment(file);
495 output.add(new OutputFile(_pathInfo.outputPath(file.path, '.html'), 539 output.add(new OutputFile(_pathInfo.outputPath(file.path, '.html'),
496 document.outerHtml, source: file.path)); 540 document.outerHtml, source: file.path));
497 } 541 }
498 542
543 /** Generate an CSS file for all style sheets (main and components). */
544 void _emitAllCss() {
545 var allCssBuff = new StringBuffer();
546 var mainFile;
547
548 // Emit all linked style sheet files first.
549 for (var file in files) {
550 var fileInfo = info[file.path];
551 if (fileInfo.isEntryPoint) mainFile = file;
552 if (file.isStyleSheet) {
553 for (var styleSheet in fileInfo.styleSheets) {
554 allCssBuff.write(
555 '/* ==================================================== */\n'
556 '/* Linked style sheet href = ${file.path.filename} */\n'
557 '/* ==================================================== */\n');
558 allCssBuff.write(emitStyleSheet(styleSheet));
559 allCssBuff.write('\n\n');
560 }
561 }
562 }
563
564 // Emit all CSS in each component (style scoped).
565 for (var file in files) {
566 if (file.isHtml) {
567 var fileInfo = info[file.path];
568 for (var component in fileInfo.declaredComponents) {
569 for (var styleSheet in component.styleSheets) {
570 allCssBuff.write(
571 '/* ==================================================== */\n'
572 '/* Component ${component.tagName} stylesheet */\n'
573 '/* ==================================================== */\n');
574 allCssBuff.write(emitStyleSheet(styleSheet, component.tagName));
575 allCssBuff.write('\n\n');
576 }
577 }
578 }
579 }
580
581 // assert(mainFile != null);
Siggi Cherem (dart-lang) 2013/03/11 21:13:11 remove commented code?
582
583 var allCss = allCssBuff.toString();
584 if (!allCss.isEmpty) {
585 var allCssFile = '${mainFile.path.filename}.css';
586 var allCssPath = mainFile.path.directoryPath.append(allCssFile);
587 var allCssOutPath = _pathInfo.outputPath(allCssPath, '');
588 output.add(new OutputFile(allCssOutPath, allCss));
589 }
590 }
591
499 /** Emits the Dart code for all components in [fileInfo]. */ 592 /** Emits the Dart code for all components in [fileInfo]. */
500 void _emitComponents(FileInfo fileInfo) { 593 void _emitComponents(FileInfo fileInfo) {
501 for (var component in fileInfo.declaredComponents) { 594 for (var component in fileInfo.declaredComponents) {
595 // TODO(terry): Handle one stylesheet per component see fixupHtmlCss.
596 if (component.styleSheets.length > 1 && options.processCss) {
597 _messages.warning(
598 'Component has more than one stylesheet'
599 ' - first stylesheet used.', null, file: component.externalFile);
600 }
502 var printer = new WebComponentEmitter(fileInfo, _messages) 601 var printer = new WebComponentEmitter(fileInfo, _messages)
503 .run(component, _pathInfo, _edits[component.userCode]); 602 .run(component, _pathInfo, _edits[component.userCode]);
504 _emitFileAndSourceMaps(component, printer, component.externalFile); 603 _emitFileAndSourceMaps(component, printer, component.externalFile);
505 } 604 }
506 } 605 }
507 606
508 /** 607 /**
509 * Emits a file that was created using [CodePrinter] and it's corresponding 608 * Emits a file that was created using [CodePrinter] and it's corresponding
510 * source map file. 609 * source map file.
511 */ 610 */
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 'See http://www.w3.org/TR/html5-diff/#doctype', 660 'See http://www.w3.org/TR/html5-diff/#doctype',
562 doctype.sourceSpan, file: file.path); 661 doctype.sourceSpan, file: file.path);
563 } 662 }
564 } 663 }
565 document.nodes.insertAt(commentIndex, parseFragment( 664 document.nodes.insertAt(commentIndex, parseFragment(
566 '\n<!-- This file was auto-generated from ${file.path}. -->\n')); 665 '\n<!-- This file was auto-generated from ${file.path}. -->\n'));
567 } 666 }
568 } 667 }
569 668
570 /** Parse all stylesheet for polyfilling assciated with [info]. */ 669 /** Parse all stylesheet for polyfilling assciated with [info]. */
571 void _processStylesheet(info, {CompilerOptions options : null}) { 670 void _processStylesheet(uriVisitor, info, {CompilerOptions options : null}) {
572 new _ProcessCss(options).visit(info); 671 new _ProcessCss(uriVisitor, options).visit(info);
672 }
673
674 StyleSheet _parseCss(String src, String content, UriVisitor uriVisitor,
675 CompilerOptions options) {
676 if (!content.trim().isEmpty) {
677 // TODO(terry): Add --checked when fully implemented and error handling.
678 var styleSheet = css.parse(content, options:
679 [options.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
680 uriVisitor.visitTree(styleSheet);
681 if (options.debugCss) {
682 print('\nCSS source: $src');
683 print('==========\n');
684 print(treeToDebugString(styleSheet));
685 }
686 return styleSheet;
687 }
573 } 688 }
574 689
575 /** Post-analysis of style sheet; parsed ready for emitting with polyfill. */ 690 /** Post-analysis of style sheet; parsed ready for emitting with polyfill. */
576 class _ProcessCss extends InfoVisitor { 691 class _ProcessCss extends InfoVisitor {
692 final UriVisitor uriVisitor;
577 final CompilerOptions options; 693 final CompilerOptions options;
694 ComponentInfo component;
578 695
579 _ProcessCss(this.options); 696 _ProcessCss(this.uriVisitor, this.options);
580
581 // TODO(terry): Add --checked when fully implemented and error handling too.
582 StyleSheet _parseCss(String cssInput, CompilerOptions option) =>
583 css.parse(cssInput, options:
584 [option.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
585 697
586 void visitComponentInfo(ComponentInfo info) { 698 void visitComponentInfo(ComponentInfo info) {
587 if (!info.cssSource.isEmpty) { 699 var oldComponent = component;
588 info.styleSheet = _parseCss(info.cssSource.toString(), options); 700 component = info;
589 info.cssSource = null; // Once CSS parsed original not needed.
590 701
591 if (options.debugCss) { 702 super.visitComponentInfo(info);
592 print('\nComponent: ${info.tagName}'); 703
593 print('==========\n'); 704 component = oldComponent;
594 print(treeToDebugString(info.styleSheet)); 705 }
706
707 void visitElementInfo(ElementInfo info) {
708 if (component != null) {
709 var node = info.node;
710 if (node.tagName == 'style' && node.attributes.containsKey("scoped")) {
711 // Get contents of style tag.
712 var content = node.nodes.single.value;
713 var styleSheet = _parseCss(component.tagName, content, uriVisitor,
714 options);
715 if (styleSheet != null) {
716 component.styleSheets.add(styleSheet);
717 }
595 } 718 }
596 } 719 }
597 720
598 super.visitComponentInfo(info); 721 super.visitElementInfo(info);
599 } 722 }
600 } 723 }
OLDNEW
« no previous file with comments | « lib/src/analyzer.dart ('k') | lib/src/emitters.dart » ('j') | lib/src/html_css_fixup.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698