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

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, 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)
254 ..code = code.trim())
Siggi Cherem (dart-lang) 2013/03/08 21:57:52 Maybe remove 'trim' here? You are also trimming t
terry 2013/03/08 22:42:23 I like it _parseCss only. On 2013/03/08 21:57:52,
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.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 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 if (newUri != null) { 441 if (newUri != null) {
408 directive.uri = createStringLiteral(newUri); 442 directive.uri = createStringLiteral(newUri);
409 } 443 }
410 } 444 }
411 } 445 }
412 446
413 /** Run the analyzer on every input html file. */ 447 /** Run the analyzer on every input html file. */
414 void _analyze() { 448 void _analyze() {
415 var uniqueIds = new IntIterator(); 449 var uniqueIds = new IntIterator();
416 for (var file in files) { 450 for (var file in files) {
417 if (file.isDart) continue; 451 var fileInfo = info[file.path];
Siggi Cherem (dart-lang) 2013/03/08 21:57:52 delete this unused variable
terry 2013/03/08 22:42:23 Done.
418 _time('Analyzed contents', file.path, () => 452 if (file.isHtml) {
419 analyzeFile(file, info, uniqueIds, _messages)); 453 _time('Analyzed contents', file.path, () =>
454 analyzeFile(file, info, uniqueIds, _messages));
455 }
420 } 456 }
421 } 457 }
422 458
423 /** Emit the generated code corresponding to each input file. */ 459 /** Emit the generated code corresponding to each input file. */
424 void _emit() { 460 void _emit() {
425 for (var file in files) { 461 for (var file in files) {
426 if (file.isDart) continue; 462 if (file.isDart || file.isStyleSheet) continue;
427 _time('Codegen', file.path, () { 463 _time('Codegen', file.path, () {
428 var fileInfo = info[file.path]; 464 var fileInfo = info[file.path];
429 cleanHtmlNodes(fileInfo); 465 cleanHtmlNodes(fileInfo);
430 _processStylesheet(fileInfo, options: options); 466 if (!fileInfo.isEntryPoint) {
Siggi Cherem (dart-lang) 2013/03/08 21:57:52 && options.processCss
terry 2013/03/08 22:42:23 I'm not sure this is right. Don't we want to supp
Siggi Cherem (dart-lang) 2013/03/09 01:32:10 my understanding was that 'processCss' is not just
467 // Check all components files for <style> tags and parse the CSS.
468 var uriVisitor = new UriVisitor(_pathInfo, _mainPath, fileInfo.path);
469 _processStylesheet(uriVisitor, fileInfo, options: options);
470 }
431 fixupHtmlCss(fileInfo, options); 471 fixupHtmlCss(fileInfo, options);
432 _emitComponents(fileInfo); 472 _emitComponents(fileInfo);
433 if (fileInfo.isEntryPoint) { 473 if (fileInfo.isEntryPoint) {
434 _emitMainDart(file); 474 _emitMainDart(file);
435 _emitMainHtml(file); 475 _emitMainHtml(file);
436 } 476 }
437 }); 477 });
438 } 478 }
479
480 if (options.processCss) {
481 _emitAllCss();
482 }
439 } 483 }
440 484
441 /** Emit the main .dart file. */ 485 /** Emit the main .dart file. */
442 void _emitMainDart(SourceFile file) { 486 void _emitMainDart(SourceFile file) {
443 var fileInfo = info[file.path]; 487 var fileInfo = info[file.path];
444 var printer = new MainPageEmitter(fileInfo) 488 var printer = new MainPageEmitter(fileInfo, options.processCss)
445 .run(file.document, _pathInfo, _edits[fileInfo.userCode], 489 .run(file.document, _pathInfo, _edits[fileInfo.userCode],
446 options.rewriteUrls); 490 options.rewriteUrls);
447 _emitFileAndSourceMaps(fileInfo, printer, fileInfo.inputPath); 491 _emitFileAndSourceMaps(fileInfo, printer, fileInfo.inputPath);
448 } 492 }
449 493
450 /** Generate an html file with the (trimmed down) main html page. */ 494 /** Generate an html file with the (trimmed down) main html page. */
451 void _emitMainHtml(SourceFile file) { 495 void _emitMainHtml(SourceFile file) {
452 var fileInfo = info[file.path]; 496 var fileInfo = info[file.path];
453 497
454 var bootstrapName = '${file.path.filename}_bootstrap.dart'; 498 var bootstrapName = '${file.path.filename}_bootstrap.dart';
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 if (link.attributes["rel"] == "components") { 530 if (link.attributes["rel"] == "components") {
487 link.remove(); 531 link.remove();
488 } 532 }
489 } 533 }
490 534
491 _addAutoGeneratedComment(file); 535 _addAutoGeneratedComment(file);
492 output.add(new OutputFile(_pathInfo.outputPath(file.path, '.html'), 536 output.add(new OutputFile(_pathInfo.outputPath(file.path, '.html'),
493 document.outerHtml, source: file.path)); 537 document.outerHtml, source: file.path));
494 } 538 }
495 539
540 /** Generate an CSS file for all style sheets (main and components). */
541 void _emitAllCss() {
542 StringBuffer allCssBuff = new StringBuffer();
Siggi Cherem (dart-lang) 2013/03/08 21:57:52 style nit: use var
terry 2013/03/08 22:42:23 Done.
543
Siggi Cherem (dart-lang) 2013/03/08 21:57:52 style nit, delete empty line
terry 2013/03/08 22:42:23 Done.
544 var mainFile;
545
546 // Emit all linked style sheet files first.
547 for (var file in files) {
548 var fileInfo = info[file.path];
549 if (fileInfo.isEntryPoint) mainFile = file;
550 if (file.isStyleSheet) {
551 for (var styleSheet in fileInfo.styleSheets) {
552 allCssBuff.write(
553 '/* ==================================================== */\n'
554 '/* Linked style sheet href = ${file.path.filename} */\n'
555 '/* ==================================================== */\n');
556 allCssBuff.write(emitStyleSheet(styleSheet));
557 allCssBuff.write('\n\n');
558 }
559 }
560 }
561
562 // Emit all CSS in each component (style scoped).
563 for (var file in files) {
564 var fileInfo = info[file.path];
Siggi Cherem (dart-lang) 2013/03/08 21:57:52 move this down inside the next if
terry 2013/03/08 22:42:23 Done.
565 if (!file.isStyleSheet) {
Siggi Cherem (dart-lang) 2013/03/08 21:57:52 !file.isStylesheet => file.isHtml (skip dart files
terry 2013/03/08 22:42:23 Right should only be isHtml (dart and stylesheets
566 for (var component in fileInfo.declaredComponents) {
567 for (var styleSheet in component.styleSheets) {
568 allCssBuff.write(
569 '/* ==================================================== */\n'
570 '/* Component ${component.tagName} stylesheet */\n'
571 '/* ==================================================== */\n');
572 allCssBuff.write(emitStyleSheet(styleSheet, component.tagName));
573 allCssBuff.write('\n\n');
574 }
575 }
576 }
577 }
578
579 assert(mainFile != null);
580
581 var allCss = allCssBuff.toString();
582 if (!allCss.isEmpty) {
583 var allCssFile = '${mainFile.path.filename}.css';
584 var allCssPath = mainFile.path.directoryPath.append(allCssFile);
585 var allCssOutPath = _pathInfo.outputPath(allCssPath, '');
586 output.add(new OutputFile(allCssOutPath, allCss));
587 }
588 }
589
496 /** Emits the Dart code for all components in [fileInfo]. */ 590 /** Emits the Dart code for all components in [fileInfo]. */
497 void _emitComponents(FileInfo fileInfo) { 591 void _emitComponents(FileInfo fileInfo) {
498 for (var component in fileInfo.declaredComponents) { 592 for (var component in fileInfo.declaredComponents) {
593 // TODO(terry): Handle one stylesheet per component see fixupHtmlCss.
594 if (component.styleSheets.length > 1) {
Siggi Cherem (dart-lang) 2013/03/08 21:57:52 && options.processCss
terry 2013/03/08 22:42:23 Done.
terry 2013/03/08 22:42:23 Done.
595 _messages.warning(
596 'Component has more than one stylesheet'
597 ' - first stylesheet used.', null, file: component.externalFile);
598 }
499 var printer = new WebComponentEmitter(fileInfo, _messages) 599 var printer = new WebComponentEmitter(fileInfo, _messages)
500 .run(component, _pathInfo, _edits[component.userCode]); 600 .run(component, _pathInfo, _edits[component.userCode]);
501 _emitFileAndSourceMaps(component, printer, component.externalFile); 601 _emitFileAndSourceMaps(component, printer, component.externalFile);
502 } 602 }
503 } 603 }
504 604
505 /** 605 /**
506 * Emits a file that was created using [CodePrinter] and it's corresponding 606 * Emits a file that was created using [CodePrinter] and it's corresponding
507 * source map file. 607 * source map file.
508 */ 608 */
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 'See http://www.w3.org/TR/html5-diff/#doctype', 658 'See http://www.w3.org/TR/html5-diff/#doctype',
559 doctype.sourceSpan, file: file.path); 659 doctype.sourceSpan, file: file.path);
560 } 660 }
561 } 661 }
562 document.nodes.insertAt(commentIndex, parseFragment( 662 document.nodes.insertAt(commentIndex, parseFragment(
563 '\n<!-- This file was auto-generated from ${file.path}. -->\n')); 663 '\n<!-- This file was auto-generated from ${file.path}. -->\n'));
564 } 664 }
565 } 665 }
566 666
567 /** Parse all stylesheet for polyfilling assciated with [info]. */ 667 /** Parse all stylesheet for polyfilling assciated with [info]. */
568 void _processStylesheet(info, {CompilerOptions options : null}) { 668 void _processStylesheet(uriVisitor, info, {CompilerOptions options : null}) {
569 new _ProcessCss(options).visit(info); 669 new _ProcessCss(uriVisitor, options).visit(info);
670 }
671
672 StyleSheet _parseCss(String src, String content, UriVisitor uriVisitor,
673 CompilerOptions options) {
674 if (!content.trim().isEmpty) {
675 // TODO(terry): Add --checked when fully implemented and error handling.
676 var styleSheet = css.parse(content, options:
677 [options.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
678 uriVisitor.visitTree(styleSheet);
679 if (options.debugCss) {
680 print('\nCSS source: $src');
681 print('==========\n');
682 print(treeToDebugString(styleSheet));
683 }
684 return styleSheet;
685 }
570 } 686 }
571 687
572 /** Post-analysis of style sheet; parsed ready for emitting with polyfill. */ 688 /** Post-analysis of style sheet; parsed ready for emitting with polyfill. */
573 class _ProcessCss extends InfoVisitor { 689 class _ProcessCss extends InfoVisitor {
690 final UriVisitor uriVisitor;
574 final CompilerOptions options; 691 final CompilerOptions options;
692 ComponentInfo component;
575 693
576 _ProcessCss(this.options); 694 _ProcessCss(this.uriVisitor, this.options);
577
578 // TODO(terry): Add --checked when fully implemented and error handling too.
579 StyleSheet _parseCss(String cssInput, CompilerOptions option) =>
580 css.parse(cssInput, options:
581 [option.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
582 695
583 void visitComponentInfo(ComponentInfo info) { 696 void visitComponentInfo(ComponentInfo info) {
584 if (!info.cssSource.isEmpty) { 697 var oldComponent = component;
585 info.styleSheet = _parseCss(info.cssSource.toString(), options); 698 component = info;
586 info.cssSource = null; // Once CSS parsed original not needed.
587 699
588 if (options.debugCss) { 700 super.visitComponentInfo(info);
589 print('\nComponent: ${info.tagName}'); 701
590 print('==========\n'); 702 component = oldComponent;
591 print(treeToDebugString(info.styleSheet)); 703 }
704
705 void visitElementInfo(ElementInfo info) {
706 if (component != null) {
707 var node = info.node;
708 if (node.tagName == 'style' && node.attributes.containsKey("scoped")) {
709 // Get contents of style tag.
710 var content = node.nodes.single.value.toString();
Siggi Cherem (dart-lang) 2013/03/08 21:57:52 do we need a 'toString'? I'm not sure what's the t
terry 2013/03/08 22:42:23 Yep only need .value On 2013/03/08 21:57:52, Sigg
711 var styleSheet = _parseCss(component.tagName, content, uriVisitor,
712 options);
713 if (styleSheet != null) {
714 component.styleSheets.add(styleSheet);
715 }
592 } 716 }
593 } 717 }
594 718
595 super.visitComponentInfo(info); 719 super.visitElementInfo(info);
596 } 720 }
597 } 721 }
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