| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 /** Portion of the analyzer dealing with CSS sources. */ | 5 /** Portion of the analyzer dealing with CSS sources. */ |
| 6 library polymer.src.css_analyzer; | 6 library polymer.src.css_analyzer; |
| 7 | 7 |
| 8 import 'package:csslib/parser.dart' as css; | 8 import 'package:csslib/parser.dart' as css; |
| 9 import 'package:csslib/visitor.dart'; | 9 import 'package:csslib/visitor.dart'; |
| 10 import 'package:html5lib/dom.dart'; | 10 import 'package:html5lib/dom.dart'; |
| 11 import 'package:html5lib/dom_parsing.dart'; | 11 import 'package:html5lib/dom_parsing.dart'; |
| 12 | 12 |
| 13 import 'info.dart'; | 13 import 'info.dart'; |
| 14 import 'files.dart' show SourceFile; | 14 import 'files.dart' show SourceFile; |
| 15 import 'messages.dart'; | 15 import 'messages.dart'; |
| 16 import 'compiler_options.dart'; | 16 import 'compiler_options.dart'; |
| 17 | 17 |
| 18 void analyzeCss(String packageRoot, List<SourceFile> files, | 18 void analyzeCss(List<SourceFile> files, |
| 19 Map<String, FileInfo> info, Map<String, String> pseudoElements, | 19 Map<String, FileInfo> info, Map<String, String> pseudoElements, |
| 20 Messages messages, {warningsAsErrors: false}) { | 20 Messages messages, {warningsAsErrors: false}) { |
| 21 var analyzer = new _AnalyzerCss(packageRoot, info, pseudoElements, messages, | 21 var analyzer = new _AnalyzerCss(info, pseudoElements, messages, |
| 22 warningsAsErrors); | 22 warningsAsErrors); |
| 23 for (var file in files) analyzer.process(file); | 23 for (var file in files) analyzer.process(file); |
| 24 analyzer.normalize(); | 24 analyzer.normalize(); |
| 25 } | 25 } |
| 26 | 26 |
| 27 class _AnalyzerCss { | 27 class _AnalyzerCss { |
| 28 final String packageRoot; | |
| 29 final Map<String, FileInfo> info; | 28 final Map<String, FileInfo> info; |
| 30 final Map<String, String> _pseudoElements; | 29 final Map<String, String> _pseudoElements; |
| 31 final Messages _messages; | 30 final Messages _messages; |
| 32 final bool _warningsAsErrors; | 31 final bool _warningsAsErrors; |
| 33 | 32 |
| 34 Set<StyleSheet> allStyleSheets = new Set<StyleSheet>(); | 33 Set<StyleSheet> allStyleSheets = new Set<StyleSheet>(); |
| 35 | 34 |
| 36 /** | 35 /** |
| 37 * [_pseudoElements] list of known pseudo attributes found in HTML, any | 36 * [_pseudoElements] list of known pseudo attributes found in HTML, any |
| 38 * CSS pseudo-elements 'name::custom-element' is mapped to the manged name | 37 * CSS pseudo-elements 'name::custom-element' is mapped to the manged name |
| 39 * associated with the pseudo-element key. | 38 * associated with the pseudo-element key. |
| 40 */ | 39 */ |
| 41 _AnalyzerCss(this.packageRoot, this.info, this._pseudoElements, | 40 _AnalyzerCss(this.info, this._pseudoElements, |
| 42 this._messages, this._warningsAsErrors); | 41 this._messages, this._warningsAsErrors); |
| 43 | 42 |
| 44 /** | 43 /** |
| 45 * Run the analyzer on every file that is a style sheet or any component that | 44 * Run the analyzer on every file that is a style sheet or any component that |
| 46 * has a style tag. | 45 * has a style tag. |
| 47 */ | 46 */ |
| 48 void process(SourceFile file) { | 47 void process(SourceFile file) { |
| 49 var fileInfo = info[file.path]; | 48 var fileInfo = info[file.path]; |
| 50 if (file.isStyleSheet || fileInfo.styleSheets.length > 0) { | 49 if (file.isStyleSheet || fileInfo.styleSheets.length > 0) { |
| 51 var styleSheets = processVars(fileInfo); | 50 var styleSheets = processVars(fileInfo); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 if (!seen.contains(styleSheet)) { | 129 if (!seen.contains(styleSheet)) { |
| 131 // TODO(terry): VM uses expandos to implement hashes. Currently, it's a | 130 // TODO(terry): VM uses expandos to implement hashes. Currently, it's a |
| 132 // linear (not constant) time cost (see dartbug.com/5746). | 131 // linear (not constant) time cost (see dartbug.com/5746). |
| 133 // If this bug isn't fixed and performance show's this a | 132 // If this bug isn't fixed and performance show's this a |
| 134 // a problem we'll need to implement our own hashCode or | 133 // a problem we'll need to implement our own hashCode or |
| 135 // use a different key for better perf. | 134 // use a different key for better perf. |
| 136 // Add the stylesheet. | 135 // Add the stylesheet. |
| 137 seen.add(styleSheet); | 136 seen.add(styleSheet); |
| 138 | 137 |
| 139 // Any other imports in this stylesheet? | 138 // Any other imports in this stylesheet? |
| 140 var urlInfos = findImportsInStyleSheet(styleSheet, packageRoot, | 139 var urlInfos = findImportsInStyleSheet(styleSheet, inputUrl, _messages); |
| 141 inputUrl, _messages); | |
| 142 | 140 |
| 143 // Process other imports in this stylesheets. | 141 // Process other imports in this stylesheets. |
| 144 for (var importSS in urlInfos) { | 142 for (var importSS in urlInfos) { |
| 145 var importInfo = info[importSS.resolvedPath]; | 143 var importInfo = info[importSS.resolvedPath]; |
| 146 if (importInfo != null) { | 144 if (importInfo != null) { |
| 147 // Add all known stylesheets processed. | 145 // Add all known stylesheets processed. |
| 148 seen.addAll(importInfo.styleSheets); | 146 seen.addAll(importInfo.styleSheets); |
| 149 // Find dependencies for stylesheet referenced with a | 147 // Find dependencies for stylesheet referenced with a |
| 150 // @import | 148 // @import |
| 151 for (var ss in importInfo.styleSheets) { | 149 for (var ss in importInfo.styleSheets) { |
| 152 var urls = findImportsInStyleSheet(ss, packageRoot, inputUrl, | 150 var urls = findImportsInStyleSheet(ss, inputUrl, _messages); |
| 153 _messages); | |
| 154 for (var url in urls) { | 151 for (var url in urls) { |
| 155 _dependencies(info[url.resolvedPath], seen: seen); | 152 _dependencies(info[url.resolvedPath], seen: seen); |
| 156 } | 153 } |
| 157 } | 154 } |
| 158 } | 155 } |
| 159 } | 156 } |
| 160 } | 157 } |
| 161 } | 158 } |
| 162 | 159 |
| 163 return seen; | 160 return seen; |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 css.TokenKind.COMBINATOR_GREATER); | 349 css.TokenKind.COMBINATOR_GREATER); |
| 353 selectors.insert(++index, | 350 selectors.insert(++index, |
| 354 new SimpleSelectorSequence(attrSelector, span)); | 351 new SimpleSelectorSequence(attrSelector, span)); |
| 355 } | 352 } |
| 356 } | 353 } |
| 357 } | 354 } |
| 358 } | 355 } |
| 359 } | 356 } |
| 360 | 357 |
| 361 List<UrlInfo> findImportsInStyleSheet(StyleSheet styleSheet, | 358 List<UrlInfo> findImportsInStyleSheet(StyleSheet styleSheet, |
| 362 String packageRoot, UrlInfo inputUrl, Messages messages) { | 359 UrlInfo inputUrl, Messages messages) { |
| 363 var visitor = new _CssImports(packageRoot, inputUrl, messages); | 360 var visitor = new _CssImports(inputUrl, messages); |
| 364 visitor.visitTree(styleSheet); | 361 visitor.visitTree(styleSheet); |
| 365 return visitor.urlInfos; | 362 return visitor.urlInfos; |
| 366 } | 363 } |
| 367 | 364 |
| 368 /** | 365 /** |
| 369 * Find any imports in the style sheet; normalize the style sheet href and | 366 * Find any imports in the style sheet; normalize the style sheet href and |
| 370 * return a list of all fully qualified CSS files. | 367 * return a list of all fully qualified CSS files. |
| 371 */ | 368 */ |
| 372 class _CssImports extends Visitor { | 369 class _CssImports extends Visitor { |
| 373 final String packageRoot; | |
| 374 | |
| 375 /** Input url of the css file, used to normalize relative import urls. */ | 370 /** Input url of the css file, used to normalize relative import urls. */ |
| 376 final UrlInfo inputUrl; | 371 final UrlInfo inputUrl; |
| 377 | 372 |
| 378 /** List of all imported style sheets. */ | 373 /** List of all imported style sheets. */ |
| 379 final List<UrlInfo> urlInfos = []; | 374 final List<UrlInfo> urlInfos = []; |
| 380 | 375 |
| 381 final Messages _messages; | 376 final Messages _messages; |
| 382 | 377 |
| 383 _CssImports(this.packageRoot, this.inputUrl, this._messages); | 378 _CssImports(this.inputUrl, this._messages); |
| 384 | 379 |
| 385 void visitTree(StyleSheet tree) { | 380 void visitTree(StyleSheet tree) { |
| 386 visitStyleSheet(tree); | 381 visitStyleSheet(tree); |
| 387 } | 382 } |
| 388 | 383 |
| 389 void visitImportDirective(ImportDirective node) { | 384 void visitImportDirective(ImportDirective node) { |
| 390 var urlInfo = UrlInfo.resolve(node.import, inputUrl, | 385 var urlInfo = UrlInfo.resolve(node.import, inputUrl, |
| 391 node.span, packageRoot, _messages, ignoreAbsolute: true); | 386 node.span, _messages, ignoreAbsolute: true); |
| 392 if (urlInfo == null) return; | 387 if (urlInfo == null) return; |
| 393 urlInfos.add(urlInfo); | 388 urlInfos.add(urlInfo); |
| 394 } | 389 } |
| 395 } | 390 } |
| 396 | 391 |
| 397 StyleSheet parseCss(String content, Messages messages, | 392 StyleSheet parseCss(String content, Messages messages, |
| 398 CompilerOptions options) { | 393 CompilerOptions options) { |
| 399 if (content.trim().isEmpty) return null; | 394 if (content.trim().isEmpty) return null; |
| 400 | 395 |
| 401 var errors = []; | 396 var errors = []; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 | 444 |
| 450 /** | 445 /** |
| 451 * Find urls imported inside style tags under [info]. If [info] is a FileInfo | 446 * Find urls imported inside style tags under [info]. If [info] is a FileInfo |
| 452 * then process only style tags in the body (don't process any style tags in a | 447 * then process only style tags in the body (don't process any style tags in a |
| 453 * component). If [info] is a ComponentInfo only process style tags inside of | 448 * component). If [info] is a ComponentInfo only process style tags inside of |
| 454 * the element are processed. For an [info] of type FileInfo [node] is the | 449 * the element are processed. For an [info] of type FileInfo [node] is the |
| 455 * file's document and for an [info] of type ComponentInfo then [node] is the | 450 * file's document and for an [info] of type ComponentInfo then [node] is the |
| 456 * component's element tag. | 451 * component's element tag. |
| 457 */ | 452 */ |
| 458 List<UrlInfo> findUrlsImported(LibraryInfo info, UrlInfo inputUrl, | 453 List<UrlInfo> findUrlsImported(LibraryInfo info, UrlInfo inputUrl, |
| 459 String packageRoot, Node node, Messages messages, CompilerOptions options) { | 454 Node node, Messages messages, CompilerOptions options) { |
| 460 // Process any @imports inside of the <style> tag. | 455 // Process any @imports inside of the <style> tag. |
| 461 var styleProcessor = | 456 var styleProcessor = |
| 462 new _CssStyleTag(packageRoot, info, inputUrl, messages, options); | 457 new _CssStyleTag(info, inputUrl, messages, options); |
| 463 styleProcessor.visit(node); | 458 styleProcessor.visit(node); |
| 464 return styleProcessor.imports; | 459 return styleProcessor.imports; |
| 465 } | 460 } |
| 466 | 461 |
| 467 /* Process CSS inside of a style tag. */ | 462 /* Process CSS inside of a style tag. */ |
| 468 class _CssStyleTag extends TreeVisitor { | 463 class _CssStyleTag extends TreeVisitor { |
| 469 final String _packageRoot; | |
| 470 | |
| 471 /** Either a FileInfo or ComponentInfo. */ | 464 /** Either a FileInfo or ComponentInfo. */ |
| 472 final LibraryInfo _info; | 465 final LibraryInfo _info; |
| 473 final Messages _messages; | 466 final Messages _messages; |
| 474 final CompilerOptions _options; | 467 final CompilerOptions _options; |
| 475 | 468 |
| 476 /** | 469 /** |
| 477 * Path of the declaring file, for a [_info] of type FileInfo it's the file's | 470 * Path of the declaring file, for a [_info] of type FileInfo it's the file's |
| 478 * path for a type ComponentInfo it's the declaring file path. | 471 * path for a type ComponentInfo it's the declaring file path. |
| 479 */ | 472 */ |
| 480 final UrlInfo _inputUrl; | 473 final UrlInfo _inputUrl; |
| 481 | 474 |
| 482 /** List of @imports found. */ | 475 /** List of @imports found. */ |
| 483 List<UrlInfo> imports = []; | 476 List<UrlInfo> imports = []; |
| 484 | 477 |
| 485 _CssStyleTag(this._packageRoot, this._info, this._inputUrl, this._messages, | 478 _CssStyleTag(this._info, this._inputUrl, this._messages, |
| 486 this._options); | 479 this._options); |
| 487 | 480 |
| 488 void visitElement(Element node) { | 481 void visitElement(Element node) { |
| 489 // Don't process any style tags inside of element if we're processing a | 482 // Don't process any style tags inside of element if we're processing a |
| 490 // FileInfo. The style tags inside of a component defintion will be | 483 // FileInfo. The style tags inside of a component defintion will be |
| 491 // processed when _info is a ComponentInfo. | 484 // processed when _info is a ComponentInfo. |
| 492 if (node.tagName == 'polymer-element' && _info is FileInfo) return; | 485 if (node.tagName == 'polymer-element' && _info is FileInfo) return; |
| 493 if (node.tagName == 'style') { | 486 if (node.tagName == 'style') { |
| 494 // Parse the contents of the scoped style tag. | 487 // Parse the contents of the scoped style tag. |
| 495 var styleSheet = parseCss(node.nodes.single.value, _messages, _options); | 488 var styleSheet = parseCss(node.nodes.single.value, _messages, _options); |
| 496 if (styleSheet != null) { | 489 if (styleSheet != null) { |
| 497 _info.styleSheets.add(styleSheet); | 490 _info.styleSheets.add(styleSheet); |
| 498 | 491 |
| 499 // Find all imports return list of @imports in this style tag. | 492 // Find all imports return list of @imports in this style tag. |
| 500 var urlInfos = findImportsInStyleSheet(styleSheet, _packageRoot, | 493 var urlInfos = findImportsInStyleSheet(styleSheet, |
| 501 _inputUrl, _messages); | 494 _inputUrl, _messages); |
| 502 imports.addAll(urlInfos); | 495 imports.addAll(urlInfos); |
| 503 } | 496 } |
| 504 } | 497 } |
| 505 super.visitElement(node); | 498 super.visitElement(node); |
| 506 } | 499 } |
| 507 } | 500 } |
| OLD | NEW |