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

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: merged 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, fileType: 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((linkedCssContent) =>
253 new SourceFile(path, fileType: SourceFile.STYLESHEET)
254 ..linkedCssContent = linkedCssContent.trim())
255 .catchError((e) => _readError(e, path));
256 }
257
258 void _processStyleSheetFile(SourceFile cssFile) {
259 if (!_shouldProcessFile(cssFile)) return;
260
261 files.add(cssFile);
262
263 var fileInfo = new FileInfo(cssFile.path);
264 info[cssFile.path] = fileInfo;
265
266 var uriVisitor = new UriVisitor(_pathInfo, _mainPath, fileInfo.path);
267 var styleSheet = _parseCSS(cssFile.path.toString(),
268 cssFile.linkedCssContent, 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 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 } 438 }
405 if (newUri != null) { 439 if (newUri != null) {
406 directive.uri = createStringLiteral(newUri); 440 directive.uri = createStringLiteral(newUri);
407 } 441 }
408 } 442 }
409 } 443 }
410 444
411 /** Run the analyzer on every input html file. */ 445 /** Run the analyzer on every input html file. */
412 void _analyze() { 446 void _analyze() {
413 var uniqueIds = new IntIterator(); 447 var uniqueIds = new IntIterator();
448 var uriVisitor;
414 for (var file in files) { 449 for (var file in files) {
415 if (file.isDart) continue; 450 var fileInfo = info[file.path];
416 _time('Analyzed contents', file.path, () => 451 if (file.isHtml) {
417 analyzeFile(file, info, uniqueIds, _messages)); 452 if (fileInfo.isEntryPoint) {
453 assert(uriVisitor == null);
454 uriVisitor = new UriVisitor(_pathInfo, _mainPath, fileInfo.path);
455 }
456 _time('Analyzed contents', file.path, () =>
457 analyzeFile(file, info, uniqueIds, _messages));
458 } else if (file.isStyleSheet) {
459 // Parse each linked style sheet.
460 assert(uriVisitor != null);
461 _processStylesheet(uriVisitor, fileInfo, options: options);
Siggi Cherem (dart-lang) 2013/03/07 22:14:20 seems like something is broken here? the parameter
terry 2013/03/08 20:11:24 The name in processStylesheet was pathInfo (it's s
462 }
418 } 463 }
419 } 464 }
420 465
421 /** Emit the generated code corresponding to each input file. */ 466 /** Emit the generated code corresponding to each input file. */
422 void _emit() { 467 void _emit() {
423 for (var file in files) { 468 for (var file in files) {
424 if (file.isDart) continue; 469 if (file.isDart) continue;
425 _time('Codegen', file.path, () { 470 _time('Codegen', file.path, () {
426 var fileInfo = info[file.path]; 471 var fileInfo = info[file.path];
427 cleanHtmlNodes(fileInfo); 472 cleanHtmlNodes(fileInfo);
428 _processStylesheet(fileInfo, options: options); 473 var uriVisitor = new UriVisitor(_pathInfo, _mainPath, fileInfo.path);
474 _processStylesheet(uriVisitor, fileInfo, options: options);
Siggi Cherem (dart-lang) 2013/03/07 22:14:20 remove the uri visitor here?
terry 2013/03/08 20:11:24 This is the UriVisitor for each component to handl
429 fixupHtmlCss(fileInfo, options); 475 fixupHtmlCss(fileInfo, options);
430 _emitComponents(fileInfo); 476 _emitComponents(fileInfo);
431 if (fileInfo.isEntryPoint) { 477 if (fileInfo.isEntryPoint) {
432 _emitMainDart(file); 478 _emitMainDart(file);
433 _emitMainHtml(file); 479 _emitMainHtml(file);
434 } 480 }
435 }); 481 });
436 } 482 }
483
484 _emitAllCss();
437 } 485 }
438 486
439 /** Emit the main .dart file. */ 487 /** Emit the main .dart file. */
440 void _emitMainDart(SourceFile file) { 488 void _emitMainDart(SourceFile file) {
441 var fileInfo = info[file.path]; 489 var fileInfo = info[file.path];
442 var printer = new MainPageEmitter(fileInfo) 490 var printer = new MainPageEmitter(fileInfo)
443 .run(file.document, _pathInfo, _edits[fileInfo.userCode], 491 .run(file.document, _pathInfo, _edits[fileInfo.userCode],
444 options.rewriteUrls); 492 options.rewriteUrls);
445 _emitFileAndSourceMaps(fileInfo, printer, fileInfo.inputPath); 493 _emitFileAndSourceMaps(fileInfo, printer, fileInfo.inputPath);
446 } 494 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 if (link.attributes["rel"] == "components") { 532 if (link.attributes["rel"] == "components") {
485 link.remove(); 533 link.remove();
486 } 534 }
487 } 535 }
488 536
489 _addAutoGeneratedComment(file); 537 _addAutoGeneratedComment(file);
490 output.add(new OutputFile(_pathInfo.outputPath(file.path, '.html'), 538 output.add(new OutputFile(_pathInfo.outputPath(file.path, '.html'),
491 document.outerHtml, source: file.path)); 539 document.outerHtml, source: file.path));
492 } 540 }
493 541
542 /** Generate an CSS file for all style sheets (main and components). */
543 void _emitAllCss() {
544 StringBuffer allCssBuff = new StringBuffer();
545
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 var fileInfo = info[file.path];
567 if (!file.isStyleSheet) {
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);
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
494 /** Emits the Dart code for all components in [fileInfo]. */ 592 /** Emits the Dart code for all components in [fileInfo]. */
495 void _emitComponents(FileInfo fileInfo) { 593 void _emitComponents(FileInfo fileInfo) {
496 for (var component in fileInfo.declaredComponents) { 594 for (var component in fileInfo.declaredComponents) {
497 var printer = new WebComponentEmitter(fileInfo, _messages) 595 var printer = new WebComponentEmitter(fileInfo, _messages)
498 .run(component, _pathInfo, _edits[component.userCode]); 596 .run(component, _pathInfo, _edits[component.userCode]);
499 _emitFileAndSourceMaps(component, printer, component.externalFile); 597 _emitFileAndSourceMaps(component, printer, component.externalFile);
500 } 598 }
501 } 599 }
502 600
503 /** 601 /**
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 'See http://www.w3.org/TR/html5-diff/#doctype', 651 'See http://www.w3.org/TR/html5-diff/#doctype',
554 doctype.sourceSpan, file: file.path); 652 doctype.sourceSpan, file: file.path);
555 } 653 }
556 } 654 }
557 document.nodes.insertAt(commentIndex, parseFragment( 655 document.nodes.insertAt(commentIndex, parseFragment(
558 '\n<!-- This file was auto-generated from ${file.path}. -->\n')); 656 '\n<!-- This file was auto-generated from ${file.path}. -->\n'));
559 } 657 }
560 } 658 }
561 659
562 /** Parse all stylesheet for polyfilling assciated with [info]. */ 660 /** Parse all stylesheet for polyfilling assciated with [info]. */
563 void _processStylesheet(info, {CompilerOptions options : null}) { 661 void _processStylesheet(pathInfo, info, {CompilerOptions options : null}) {
564 new _ProcessCss(options).visit(info); 662 new _ProcessCss(pathInfo, options).visit(info);
663 }
664
665 StyleSheet _parseCSS(String src, String content, UriVisitor uriVisitor,
Siggi Cherem (dart-lang) 2013/03/07 22:14:20 style nit: change to _parseCss (3 letter acronym c
terry 2013/03/08 20:11:24 Done.
666 CompilerOptions options) {
667 if (!content.trim().isEmpty) {
668 // TODO(terry): Add --checked when fully implemented and error handling.
669 var styleSheet = css.parse(content, options:
670 [options.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
671 uriVisitor.visitTree(styleSheet);
672 if (options.debugCss) {
673 print('\nCSS source: $src');
674 print('==========\n');
675 print(treeToDebugString(styleSheet));
676 }
677 return styleSheet;
678 }
565 } 679 }
566 680
567 /** Post-analysis of style sheet; parsed ready for emitting with polyfill. */ 681 /** Post-analysis of style sheet; parsed ready for emitting with polyfill. */
568 class _ProcessCss extends InfoVisitor { 682 class _ProcessCss extends InfoVisitor {
683 final UriVisitor uriVisitor;
569 final CompilerOptions options; 684 final CompilerOptions options;
685 ComponentInfo component;
570 686
571 _ProcessCss(this.options); 687 _ProcessCss(this.uriVisitor, this.options);
572
573 // TODO(terry): Add --checked when fully implemented and error handling too.
574 StyleSheet _parseCss(String cssInput, CompilerOptions option) =>
575 css.parse(cssInput, options:
576 [option.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
577 688
578 void visitComponentInfo(ComponentInfo info) { 689 void visitComponentInfo(ComponentInfo info) {
579 if (!info.cssSource.isEmpty) { 690 var oldComponent = component;
580 info.styleSheet = _parseCss(info.cssSource.toString(), options); 691 component = info;
581 info.cssSource = null; // Once CSS parsed original not needed.
582 692
583 if (options.debugCss) { 693 super.visitComponentInfo(info);
584 print('\nComponent: ${info.tagName}'); 694
585 print('==========\n'); 695 component = oldComponent;
586 print(treeToDebugString(info.styleSheet)); 696 }
697
698 void visitElementInfo(ElementInfo info) {
699 if (component != null) {
700 var node = info.node;
701 if (node.tagName == 'style' && node.attributes.containsKey("scoped")) {
702 // Get contents of style tag.
703 var content = node.nodes.single.value.toString();
704 var styleSheet = _parseCSS(component.tagName, content, uriVisitor,
705 options);
706 if (styleSheet != null) {
707 component.styleSheets.add(styleSheet);
708 }
587 } 709 }
588 } 710 }
589 711
590 super.visitComponentInfo(info); 712 super.visitElementInfo(info);
591 } 713 }
592 } 714 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698