| OLD | NEW |
| 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 part of csslib.parser; | 5 part of csslib.parser; |
| 6 | 6 |
| 7 | |
| 8 // TODO(terry): Add optimizing phase to remove duplicated selectors in the same | 7 // TODO(terry): Add optimizing phase to remove duplicated selectors in the same |
| 9 // selector group (e.g., .btn, .btn { color: red; }). Also, look | 8 // selector group (e.g., .btn, .btn { color: red; }). Also, look |
| 10 // at simplifying selectors expressions too (much harder). | 9 // at simplifying selectors expressions too (much harder). |
| 11 // TODO(terry): Detect invalid directive usage. All @imports must occur before | 10 // TODO(terry): Detect invalid directive usage. All @imports must occur before |
| 12 // all rules other than @charset directive. Any @import directive | 11 // all rules other than @charset directive. Any @import directive |
| 13 // after any non @charset or @import directive are ignored. e.g., | 12 // after any non @charset or @import directive are ignored. e.g., |
| 14 // @import "a.css"; | 13 // @import "a.css"; |
| 15 // div { color: red; } | 14 // div { color: red; } |
| 16 // @import "b.css"; | 15 // @import "b.css"; |
| 17 // becomes: | 16 // becomes: |
| 18 // @import "a.css"; | 17 // @import "a.css"; |
| 19 // div { color: red; } | 18 // div { color: red; } |
| 20 // <http://www.w3.org/TR/css3-syntax/#at-rules> | 19 // <http://www.w3.org/TR/css3-syntax/#at-rules> |
| 21 | 20 |
| 22 /** | 21 /** |
| 23 * Analysis phase will validate/fixup any new CSS feature or any SASS style | 22 * Analysis phase will validate/fixup any new CSS feature or any SASS style |
| 24 * feature. | 23 * feature. |
| 25 */ | 24 */ |
| 26 class Analyzer { | 25 class Analyzer { |
| 27 final List<StyleSheet> _styleSheets; | 26 final List<StyleSheet> _styleSheets; |
| 28 final Messages _messages; | 27 final Messages _messages; |
| 29 | 28 |
| 30 Analyzer(this._styleSheets, this._messages); | 29 Analyzer(this._styleSheets, this._messages); |
| 31 | 30 |
| 32 // TODO(terry): Currently each feature walks the AST each time. Once we have | 31 // TODO(terry): Currently each feature walks the AST each time. Once we have |
| 33 // our complete feature set consider benchmarking the cost and | 32 // our complete feature set consider benchmarking the cost and |
| 34 // possibly combine in one walk. | 33 // possibly combine in one walk. |
| 35 void run() { | 34 void run() { |
| 36 // Expand top-level @include. | 35 // Expand top-level @include. |
| 37 _styleSheets.forEach((styleSheet) => | 36 _styleSheets.forEach( |
| 38 TopLevelIncludes.expand(_messages, _styleSheets)); | 37 (styleSheet) => TopLevelIncludes.expand(_messages, _styleSheets)); |
| 39 | 38 |
| 40 // Expand @include in declarations. | 39 // Expand @include in declarations. |
| 41 _styleSheets.forEach((styleSheet) => | 40 _styleSheets.forEach( |
| 42 DeclarationIncludes.expand(_messages, _styleSheets)); | 41 (styleSheet) => DeclarationIncludes.expand(_messages, _styleSheets)); |
| 43 | 42 |
| 44 // Remove all @mixin and @include | 43 // Remove all @mixin and @include |
| 45 _styleSheets.forEach((styleSheet) => MixinsAndIncludes.remove(styleSheet)); | 44 _styleSheets.forEach((styleSheet) => MixinsAndIncludes.remove(styleSheet)); |
| 46 | 45 |
| 47 // Expand any nested selectors using selector desendant combinator to | 46 // Expand any nested selectors using selector desendant combinator to |
| 48 // signal CSS inheritance notation. | 47 // signal CSS inheritance notation. |
| 49 _styleSheets.forEach((styleSheet) => new ExpandNestedSelectors() | 48 _styleSheets.forEach((styleSheet) => new ExpandNestedSelectors() |
| 50 ..visitStyleSheet(styleSheet) | 49 ..visitStyleSheet(styleSheet) |
| 51 ..flatten(styleSheet)); | 50 ..flatten(styleSheet)); |
| 52 | 51 |
| 53 // Expand any @extend. | 52 // Expand any @extend. |
| 54 _styleSheets.forEach((styleSheet) { | 53 _styleSheets.forEach((styleSheet) { |
| 55 var allExtends = new AllExtends()..visitStyleSheet(styleSheet); | 54 var allExtends = new AllExtends()..visitStyleSheet(styleSheet); |
| 56 new InheritExtends(_messages, allExtends)..visitStyleSheet(styleSheet); | 55 new InheritExtends(_messages, allExtends)..visitStyleSheet(styleSheet); |
| 57 }); | 56 }); |
| 58 } | 57 } |
| 59 } | 58 } |
| 60 | 59 |
| 61 /** | 60 /** |
| 62 * Traverse all rulesets looking for nested ones. If a ruleset is in a | 61 * Traverse all rulesets looking for nested ones. If a ruleset is in a |
| 63 * declaration group (implies nested selector) then generate new ruleset(s) at | 62 * declaration group (implies nested selector) then generate new ruleset(s) at |
| 64 * level 0 of CSS using selector inheritance syntax (flattens the nesting). | 63 * level 0 of CSS using selector inheritance syntax (flattens the nesting). |
| 65 * | 64 * |
| 66 * How the AST works for a rule [RuleSet] and nested rules. First of all a | 65 * How the AST works for a rule [RuleSet] and nested rules. First of all a |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 _nestedSelectorGroup = _mergeToFlatten(node); | 207 _nestedSelectorGroup = _mergeToFlatten(node); |
| 209 } | 208 } |
| 210 | 209 |
| 211 _parentRuleSet = node; | 210 _parentRuleSet = node; |
| 212 | 211 |
| 213 super.visitRuleSet(node); | 212 super.visitRuleSet(node); |
| 214 | 213 |
| 215 _parentRuleSet = oldParent; | 214 _parentRuleSet = oldParent; |
| 216 | 215 |
| 217 // Remove nested rules; they're all flatten and in the _expandedRuleSets. | 216 // Remove nested rules; they're all flatten and in the _expandedRuleSets. |
| 218 node.declarationGroup.declarations.removeWhere((declaration) => | 217 node.declarationGroup.declarations |
| 219 declaration is RuleSet); | 218 .removeWhere((declaration) => declaration is RuleSet); |
| 220 | 219 |
| 221 _nestedSelectorGroup = oldNestedSelectorGroups; | 220 _nestedSelectorGroup = oldNestedSelectorGroups; |
| 222 | 221 |
| 223 // If any expandedRuleSets and we're back at the top-level rule set then | 222 // If any expandedRuleSets and we're back at the top-level rule set then |
| 224 // there were nested rule set(s). | 223 // there were nested rule set(s). |
| 225 if (_parentRuleSet == null) { | 224 if (_parentRuleSet == null) { |
| 226 if (!_expandedRuleSets.isEmpty) { | 225 if (!_expandedRuleSets.isEmpty) { |
| 227 // Remember ruleset to replace with these flattened rulesets. | 226 // Remember ruleset to replace with these flattened rulesets. |
| 228 _expansions[node] = _expandedRuleSets; | 227 _expansions[node] = _expandedRuleSets; |
| 229 _expandedRuleSets = []; | 228 _expandedRuleSets = []; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 298 * descendant. Used for nested selectors when the parent selector needs to | 297 * descendant. Used for nested selectors when the parent selector needs to |
| 299 * be prefixed to a nested selector or to substitute the this (&) with the | 298 * be prefixed to a nested selector or to substitute the this (&) with the |
| 300 * parent selector. | 299 * parent selector. |
| 301 */ | 300 */ |
| 302 List<SimpleSelectorSequence> _convertToDescendentSequence( | 301 List<SimpleSelectorSequence> _convertToDescendentSequence( |
| 303 List<SimpleSelectorSequence> sequences) { | 302 List<SimpleSelectorSequence> sequences) { |
| 304 if (sequences.isEmpty) return sequences; | 303 if (sequences.isEmpty) return sequences; |
| 305 | 304 |
| 306 var newSequences = []; | 305 var newSequences = []; |
| 307 var first = sequences.first; | 306 var first = sequences.first; |
| 308 newSequences.add(new SimpleSelectorSequence(first.simpleSelector, | 307 newSequences.add(new SimpleSelectorSequence( |
| 309 first.span, TokenKind.COMBINATOR_DESCENDANT)); | 308 first.simpleSelector, first.span, TokenKind.COMBINATOR_DESCENDANT)); |
| 310 newSequences.addAll(sequences.skip(1)); | 309 newSequences.addAll(sequences.skip(1)); |
| 311 | 310 |
| 312 return newSequences; | 311 return newSequences; |
| 313 } | 312 } |
| 314 | 313 |
| 315 void visitDeclarationGroup(DeclarationGroup node) { | 314 void visitDeclarationGroup(DeclarationGroup node) { |
| 316 var span = node.span; | 315 var span = node.span; |
| 317 | 316 |
| 318 var currentGroup = new DeclarationGroup([], span); | 317 var currentGroup = new DeclarationGroup([], span); |
| 319 | 318 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 | 399 |
| 401 class _MediaRulesReplacer extends Visitor { | 400 class _MediaRulesReplacer extends Visitor { |
| 402 RuleSet _ruleSet; | 401 RuleSet _ruleSet; |
| 403 List<RuleSet> _newRules; | 402 List<RuleSet> _newRules; |
| 404 bool _foundAndReplaced = false; | 403 bool _foundAndReplaced = false; |
| 405 | 404 |
| 406 /** | 405 /** |
| 407 * Look for the [ruleSet] inside of an @media directive; if found then replace | 406 * Look for the [ruleSet] inside of an @media directive; if found then replace |
| 408 * with the [newRules]. If [ruleSet] is found and replaced return true. | 407 * with the [newRules]. If [ruleSet] is found and replaced return true. |
| 409 */ | 408 */ |
| 410 static bool replace(StyleSheet styleSheet, RuleSet ruleSet, | 409 static bool replace( |
| 411 List<RuleSet>newRules) { | 410 StyleSheet styleSheet, RuleSet ruleSet, List<RuleSet> newRules) { |
| 412 var visitor = new _MediaRulesReplacer(ruleSet, newRules); | 411 var visitor = new _MediaRulesReplacer(ruleSet, newRules); |
| 413 visitor.visitStyleSheet(styleSheet); | 412 visitor.visitStyleSheet(styleSheet); |
| 414 return visitor._foundAndReplaced; | 413 return visitor._foundAndReplaced; |
| 415 } | 414 } |
| 416 | 415 |
| 417 _MediaRulesReplacer(this._ruleSet, this._newRules); | 416 _MediaRulesReplacer(this._ruleSet, this._newRules); |
| 418 | 417 |
| 419 visitMediaDirective(MediaDirective node) { | 418 visitMediaDirective(MediaDirective node) { |
| 420 var index = node.rulesets.indexOf(_ruleSet); | 419 var index = node.rulesets.indexOf(_ruleSet); |
| 421 if (index != -1) { | 420 if (index != -1) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 452 void visitStyleSheet(StyleSheet ss) { | 451 void visitStyleSheet(StyleSheet ss) { |
| 453 _styleSheet = ss; | 452 _styleSheet = ss; |
| 454 super.visitStyleSheet(ss); | 453 super.visitStyleSheet(ss); |
| 455 _styleSheet = null; | 454 _styleSheet = null; |
| 456 } | 455 } |
| 457 | 456 |
| 458 void visitIncludeDirective(IncludeDirective node) { | 457 void visitIncludeDirective(IncludeDirective node) { |
| 459 if (map.containsKey(node.name)) { | 458 if (map.containsKey(node.name)) { |
| 460 var mixinDef = map[node.name]; | 459 var mixinDef = map[node.name]; |
| 461 if (mixinDef is MixinRulesetDirective) { | 460 if (mixinDef is MixinRulesetDirective) { |
| 462 _TopLevelIncludeReplacer.replace(_messages, _styleSheet, node, | 461 _TopLevelIncludeReplacer.replace( |
| 463 mixinDef.rulesets); | 462 _messages, _styleSheet, node, mixinDef.rulesets); |
| 464 } else if (currDef is MixinRulesetDirective && _anyRulesets(currDef)) { | 463 } else if (currDef is MixinRulesetDirective && _anyRulesets(currDef)) { |
| 465 // currDef is MixinRulesetDirective | 464 // currDef is MixinRulesetDirective |
| 466 MixinRulesetDirective mixinRuleset = currDef; | 465 MixinRulesetDirective mixinRuleset = currDef; |
| 467 int index = mixinRuleset.rulesets.indexOf(node as dynamic); | 466 int index = mixinRuleset.rulesets.indexOf(node as dynamic); |
| 468 mixinRuleset.rulesets.replaceRange(index, index + 1, [new NoOp()]); | 467 mixinRuleset.rulesets.replaceRange(index, index + 1, [new NoOp()]); |
| 469 _messages.warning( | 468 _messages.warning( |
| 470 'Using declaration mixin ${node.name} as top-level mixin', | 469 'Using declaration mixin ${node.name} as top-level mixin', |
| 471 node.span); | 470 node.span); |
| 472 } | 471 } |
| 473 } else { | 472 } else { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 final Messages _messages; | 511 final Messages _messages; |
| 513 final IncludeDirective _include; | 512 final IncludeDirective _include; |
| 514 final List<RuleSet> _newRules; | 513 final List<RuleSet> _newRules; |
| 515 bool _foundAndReplaced = false; | 514 bool _foundAndReplaced = false; |
| 516 | 515 |
| 517 /** | 516 /** |
| 518 * Look for the [ruleSet] inside of an @media directive; if found then replace | 517 * Look for the [ruleSet] inside of an @media directive; if found then replace |
| 519 * with the [newRules]. If [ruleSet] is found and replaced return true. | 518 * with the [newRules]. If [ruleSet] is found and replaced return true. |
| 520 */ | 519 */ |
| 521 static bool replace(Messages messages, StyleSheet styleSheet, | 520 static bool replace(Messages messages, StyleSheet styleSheet, |
| 522 IncludeDirective include, List<RuleSet>newRules) { | 521 IncludeDirective include, List<RuleSet> newRules) { |
| 523 var visitor = new _TopLevelIncludeReplacer(messages, include, newRules); | 522 var visitor = new _TopLevelIncludeReplacer(messages, include, newRules); |
| 524 visitor.visitStyleSheet(styleSheet); | 523 visitor.visitStyleSheet(styleSheet); |
| 525 return visitor._foundAndReplaced; | 524 return visitor._foundAndReplaced; |
| 526 } | 525 } |
| 527 | 526 |
| 528 _TopLevelIncludeReplacer(this._messages, this._include, this._newRules); | 527 _TopLevelIncludeReplacer(this._messages, this._include, this._newRules); |
| 529 | 528 |
| 530 visitStyleSheet(StyleSheet node) { | 529 visitStyleSheet(StyleSheet node) { |
| 531 var index = node.topLevels.indexOf(_include); | 530 var index = node.topLevels.indexOf(_include); |
| 532 if (index != -1) { | 531 if (index != -1) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 548 super.visitMixinRulesetDirective(node); | 547 super.visitMixinRulesetDirective(node); |
| 549 } | 548 } |
| 550 } | 549 } |
| 551 | 550 |
| 552 /** | 551 /** |
| 553 * Utility function to match an include to a list of either Declarations or | 552 * Utility function to match an include to a list of either Declarations or |
| 554 * RuleSets, depending on type of mixin (ruleset or declaration). The include | 553 * RuleSets, depending on type of mixin (ruleset or declaration). The include |
| 555 * can be an include in a declaration or an include directive (top-level). | 554 * can be an include in a declaration or an include directive (top-level). |
| 556 */ | 555 */ |
| 557 int _findInclude(List list, var node) { | 556 int _findInclude(List list, var node) { |
| 558 IncludeDirective matchNode = (node is IncludeMixinAtDeclaration) ? | 557 IncludeDirective matchNode = |
| 559 node.include : node; | 558 (node is IncludeMixinAtDeclaration) ? node.include : node; |
| 560 | 559 |
| 561 var index = 0; | 560 var index = 0; |
| 562 for (var item in list) { | 561 for (var item in list) { |
| 563 var includeNode = (item is IncludeMixinAtDeclaration) ? | 562 var includeNode = (item is IncludeMixinAtDeclaration) ? item.include : item; |
| 564 item.include : item; | |
| 565 if (includeNode == matchNode) return index; | 563 if (includeNode == matchNode) return index; |
| 566 index++; | 564 index++; |
| 567 } | 565 } |
| 568 return -1; | 566 return -1; |
| 569 } | 567 } |
| 570 | 568 |
| 571 /** | 569 /** |
| 572 * Stamp out a mixin with the defined args substituted with the user's | 570 * Stamp out a mixin with the defined args substituted with the user's |
| 573 * parameters. | 571 * parameters. |
| 574 */ | 572 */ |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 DeclarationIncludes(this._messages, List<StyleSheet> styleSheets) { | 715 DeclarationIncludes(this._messages, List<StyleSheet> styleSheets) { |
| 718 for (var styleSheet in styleSheets) { | 716 for (var styleSheet in styleSheets) { |
| 719 visitTree(styleSheet); | 717 visitTree(styleSheet); |
| 720 } | 718 } |
| 721 } | 719 } |
| 722 | 720 |
| 723 bool _allIncludes(rulesets) => | 721 bool _allIncludes(rulesets) => |
| 724 rulesets.every((rule) => rule is IncludeDirective || rule is NoOp); | 722 rulesets.every((rule) => rule is IncludeDirective || rule is NoOp); |
| 725 | 723 |
| 726 CallMixin _createCallDeclMixin(MixinDefinition mixinDef) { | 724 CallMixin _createCallDeclMixin(MixinDefinition mixinDef) { |
| 727 callMap.putIfAbsent(mixinDef.name, () => | 725 callMap.putIfAbsent(mixinDef.name, |
| 728 callMap[mixinDef.name] = new CallMixin(mixinDef, varDefs)); | 726 () => callMap[mixinDef.name] = new CallMixin(mixinDef, varDefs)); |
| 729 return callMap[mixinDef.name]; | 727 return callMap[mixinDef.name]; |
| 730 } | 728 } |
| 731 | 729 |
| 732 void visitStyleSheet(StyleSheet ss) { | 730 void visitStyleSheet(StyleSheet ss) { |
| 733 _styleSheet = ss; | 731 _styleSheet = ss; |
| 734 super.visitStyleSheet(ss); | 732 super.visitStyleSheet(ss); |
| 735 _styleSheet = null; | 733 _styleSheet = null; |
| 736 } | 734 } |
| 737 | 735 |
| 738 void visitDeclarationGroup(DeclarationGroup node) { | 736 void visitDeclarationGroup(DeclarationGroup node) { |
| 739 currDeclGroup = node; | 737 currDeclGroup = node; |
| 740 super.visitDeclarationGroup(node); | 738 super.visitDeclarationGroup(node); |
| 741 currDeclGroup = null; | 739 currDeclGroup = null; |
| 742 } | 740 } |
| 743 | 741 |
| 744 void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) { | 742 void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) { |
| 745 if (map.containsKey(node.include.name)) { | 743 if (map.containsKey(node.include.name)) { |
| 746 var mixinDef = map[node.include.name]; | 744 var mixinDef = map[node.include.name]; |
| 747 | 745 |
| 748 // Fix up any mixin that is really a Declaration but has includes. | 746 // Fix up any mixin that is really a Declaration but has includes. |
| 749 if (mixinDef is MixinRulesetDirective) { | 747 if (mixinDef is MixinRulesetDirective) { |
| 750 if (!_allIncludes(mixinDef.rulesets) && currDeclGroup != null) { | 748 if (!_allIncludes(mixinDef.rulesets) && currDeclGroup != null) { |
| 751 var index = _findInclude(currDeclGroup.declarations, node); | 749 var index = _findInclude(currDeclGroup.declarations, node); |
| 752 if (index != -1) { | 750 if (index != -1) { |
| 753 currDeclGroup.declarations.replaceRange(index, index + 1, | 751 currDeclGroup.declarations.replaceRange( |
| 754 [new NoOp()]); | 752 index, index + 1, [new NoOp()]); |
| 755 } | 753 } |
| 756 _messages.warning( | 754 _messages.warning( |
| 757 "Using top-level mixin ${node.include.name} as a declaration", | 755 "Using top-level mixin ${node.include.name} as a declaration", |
| 758 node.span); | 756 node.span); |
| 759 } else { | 757 } else { |
| 760 // We're a list of @include(s) inside of a mixin ruleset - convert | 758 // We're a list of @include(s) inside of a mixin ruleset - convert |
| 761 // to a list of IncludeMixinAtDeclaration(s). | 759 // to a list of IncludeMixinAtDeclaration(s). |
| 762 var origRulesets = mixinDef.rulesets; | 760 var origRulesets = mixinDef.rulesets; |
| 763 var rulesets = []; | 761 var rulesets = []; |
| 764 if (origRulesets.every((ruleset) => ruleset is IncludeDirective)) { | 762 if (origRulesets.every((ruleset) => ruleset is IncludeDirective)) { |
| 765 origRulesets.forEach((ruleset) { | 763 origRulesets.forEach((ruleset) { |
| 766 rulesets.add(new IncludeMixinAtDeclaration(ruleset, | 764 rulesets |
| 767 ruleset.span)); | 765 .add(new IncludeMixinAtDeclaration(ruleset, ruleset.span)); |
| 768 }); | 766 }); |
| 769 _IncludeReplacer.replace(_styleSheet, node, rulesets); | 767 _IncludeReplacer.replace(_styleSheet, node, rulesets); |
| 770 } | 768 } |
| 771 } | 769 } |
| 772 } | 770 } |
| 773 | 771 |
| 774 if ( mixinDef.definedArgs.length > 0 && node.include.args.length > 0) { | 772 if (mixinDef.definedArgs.length > 0 && node.include.args.length > 0) { |
| 775 var callMixin = _createCallDeclMixin(mixinDef); | 773 var callMixin = _createCallDeclMixin(mixinDef); |
| 776 mixinDef = callMixin.transform(node.include.args); | 774 mixinDef = callMixin.transform(node.include.args); |
| 777 } | 775 } |
| 778 | 776 |
| 779 if (mixinDef is MixinDeclarationDirective) { | 777 if (mixinDef is MixinDeclarationDirective) { |
| 780 _IncludeReplacer.replace(_styleSheet, node, | 778 _IncludeReplacer.replace( |
| 781 mixinDef.declarations.declarations); | 779 _styleSheet, node, mixinDef.declarations.declarations); |
| 782 } | 780 } |
| 783 } else { | 781 } else { |
| 784 _messages.warning("Undefined mixin ${node.include.name}", node.span); | 782 _messages.warning("Undefined mixin ${node.include.name}", node.span); |
| 785 } | 783 } |
| 786 | 784 |
| 787 super.visitIncludeMixinAtDeclaration(node); | 785 super.visitIncludeMixinAtDeclaration(node); |
| 788 } | 786 } |
| 789 | 787 |
| 790 void visitIncludeDirective(IncludeDirective node) { | 788 void visitIncludeDirective(IncludeDirective node) { |
| 791 if (map.containsKey(node.name)) { | 789 if (map.containsKey(node.name)) { |
| 792 var mixinDef = map[node.name]; | 790 var mixinDef = map[node.name]; |
| 793 if (currDef is MixinDeclarationDirective && | 791 if (currDef is MixinDeclarationDirective && |
| 794 mixinDef is MixinDeclarationDirective) { | 792 mixinDef is MixinDeclarationDirective) { |
| 795 _IncludeReplacer.replace(_styleSheet, node, | 793 _IncludeReplacer.replace( |
| 796 mixinDef.declarations.declarations); | 794 _styleSheet, node, mixinDef.declarations.declarations); |
| 797 } else if (currDef is MixinDeclarationDirective) { | 795 } else if (currDef is MixinDeclarationDirective) { |
| 798 var decls = (currDef as MixinDeclarationDirective) | 796 var decls = |
| 799 .declarations.declarations; | 797 (currDef as MixinDeclarationDirective).declarations.declarations; |
| 800 var index = _findInclude(decls, node); | 798 var index = _findInclude(decls, node); |
| 801 if (index != -1) { | 799 if (index != -1) { |
| 802 decls.replaceRange(index, index + 1, [new NoOp()]); | 800 decls.replaceRange(index, index + 1, [new NoOp()]); |
| 803 } | 801 } |
| 804 } | 802 } |
| 805 } | 803 } |
| 806 | 804 |
| 807 super.visitIncludeDirective(node); | 805 super.visitIncludeDirective(node); |
| 808 } | 806 } |
| 809 | 807 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 828 } | 826 } |
| 829 | 827 |
| 830 void visitVarDefinition(VarDefinition node) { | 828 void visitVarDefinition(VarDefinition node) { |
| 831 // Only record var definitions that have multiple expressions (comma | 829 // Only record var definitions that have multiple expressions (comma |
| 832 // separated for mixin parameter substitution. | 830 // separated for mixin parameter substitution. |
| 833 var exprs = (node.expression as Expressions).expressions; | 831 var exprs = (node.expression as Expressions).expressions; |
| 834 if (exprs.length > 1) { | 832 if (exprs.length > 1) { |
| 835 varDefs[node.definedName] = node; | 833 varDefs[node.definedName] = node; |
| 836 } | 834 } |
| 837 super.visitVarDefinition(node); | 835 super.visitVarDefinition(node); |
| 838 } | 836 } |
| 839 | 837 |
| 840 void visitVarDefinitionDirective(VarDefinitionDirective node) { | 838 void visitVarDefinitionDirective(VarDefinitionDirective node) { |
| 841 visitVarDefinition(node.def); | 839 visitVarDefinition(node.def); |
| 842 } | 840 } |
| 843 } | 841 } |
| 844 | 842 |
| 845 /** @include as a top-level with ruleset(s). */ | 843 /** @include as a top-level with ruleset(s). */ |
| 846 class _IncludeReplacer extends Visitor { | 844 class _IncludeReplacer extends Visitor { |
| 847 final _include; | 845 final _include; |
| 848 final List<Declaration> _newDeclarations; | 846 final List<Declaration> _newDeclarations; |
| 849 bool _foundAndReplaced = false; | 847 bool _foundAndReplaced = false; |
| 850 | 848 |
| 851 /** | 849 /** |
| 852 * Look for the [ruleSet] inside of a @media directive; if found then replace | 850 * Look for the [ruleSet] inside of a @media directive; if found then replace |
| 853 * with the [newRules]. | 851 * with the [newRules]. |
| 854 */ | 852 */ |
| 855 static void replace(StyleSheet ss, var include, | 853 static void replace( |
| 856 List<Declaration> newDeclarations) { | 854 StyleSheet ss, var include, List<Declaration> newDeclarations) { |
| 857 var visitor = new _IncludeReplacer(include, newDeclarations); | 855 var visitor = new _IncludeReplacer(include, newDeclarations); |
| 858 visitor.visitStyleSheet(ss); | 856 visitor.visitStyleSheet(ss); |
| 859 } | 857 } |
| 860 | 858 |
| 861 _IncludeReplacer(this._include, this._newDeclarations); | 859 _IncludeReplacer(this._include, this._newDeclarations); |
| 862 | 860 |
| 863 void visitDeclarationGroup(DeclarationGroup node) { | 861 void visitDeclarationGroup(DeclarationGroup node) { |
| 864 var index = _findInclude(node.declarations, _include); | 862 var index = _findInclude(node.declarations, _include); |
| 865 if (index != -1) { | 863 if (index != -1) { |
| 866 node.declarations.insertAll(index + 1, _newDeclarations); | 864 node.declarations.insertAll(index + 1, _newDeclarations); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 966 /** | 964 /** |
| 967 * Changes any selector that matches @extend. | 965 * Changes any selector that matches @extend. |
| 968 */ | 966 */ |
| 969 class InheritExtends extends Visitor { | 967 class InheritExtends extends Visitor { |
| 970 final Messages _messages; | 968 final Messages _messages; |
| 971 final AllExtends _allExtends; | 969 final AllExtends _allExtends; |
| 972 | 970 |
| 973 InheritExtends(this._messages, this._allExtends); | 971 InheritExtends(this._messages, this._allExtends); |
| 974 | 972 |
| 975 void visitSelectorGroup(SelectorGroup node) { | 973 void visitSelectorGroup(SelectorGroup node) { |
| 976 for (var selectorsIndex = 0; selectorsIndex < node.selectors.length; | 974 for (var selectorsIndex = 0; |
| 975 selectorsIndex < node.selectors.length; |
| 977 selectorsIndex++) { | 976 selectorsIndex++) { |
| 978 var selectors = node.selectors[selectorsIndex]; | 977 var selectors = node.selectors[selectorsIndex]; |
| 979 var isLastNone = false; | 978 var isLastNone = false; |
| 980 var selectorName = ""; | 979 var selectorName = ""; |
| 981 for (var index = 0; index < selectors.simpleSelectorSequences.length; | 980 for (var index = 0; |
| 981 index < selectors.simpleSelectorSequences.length; |
| 982 index++) { | 982 index++) { |
| 983 var simpleSeq = selectors.simpleSelectorSequences[index]; | 983 var simpleSeq = selectors.simpleSelectorSequences[index]; |
| 984 var namePart = simpleSeq.simpleSelector.toString(); | 984 var namePart = simpleSeq.simpleSelector.toString(); |
| 985 selectorName = (isLastNone) ? (selectorName + namePart) : namePart; | 985 selectorName = (isLastNone) ? (selectorName + namePart) : namePart; |
| 986 List<SelectorGroup> matches = _allExtends.inherits[selectorName]; | 986 List<SelectorGroup> matches = _allExtends.inherits[selectorName]; |
| 987 if (matches != null) { | 987 if (matches != null) { |
| 988 for (var match in matches) { | 988 for (var match in matches) { |
| 989 // Create a new group. | 989 // Create a new group. |
| 990 var newSelectors = selectors.clone(); | 990 var newSelectors = selectors.clone(); |
| 991 var newSeq = match.selectors[0].clone(); | 991 var newSeq = match.selectors[0].clone(); |
| 992 if (isLastNone) { | 992 if (isLastNone) { |
| 993 // Add the inherited selector. | 993 // Add the inherited selector. |
| 994 node.selectors.add(newSeq); | 994 node.selectors.add(newSeq); |
| 995 } else { | 995 } else { |
| 996 // Replace the selector sequence to the left of the pseudo class | 996 // Replace the selector sequence to the left of the pseudo class |
| 997 // or pseudo element. | 997 // or pseudo element. |
| 998 | 998 |
| 999 // Make new selector seq combinator the same as the original. | 999 // Make new selector seq combinator the same as the original. |
| 1000 var orgCombinator = | 1000 var orgCombinator = |
| 1001 newSelectors.simpleSelectorSequences[index].combinator; | 1001 newSelectors.simpleSelectorSequences[index].combinator; |
| 1002 newSeq.simpleSelectorSequences[0].combinator = orgCombinator; | 1002 newSeq.simpleSelectorSequences[0].combinator = orgCombinator; |
| 1003 | 1003 |
| 1004 newSelectors.simpleSelectorSequences.replaceRange(index, | 1004 newSelectors.simpleSelectorSequences.replaceRange( |
| 1005 index + 1, newSeq.simpleSelectorSequences); | 1005 index, index + 1, newSeq.simpleSelectorSequences); |
| 1006 node.selectors.add(newSelectors); | 1006 node.selectors.add(newSelectors); |
| 1007 } | 1007 } |
| 1008 isLastNone = false; | 1008 isLastNone = false; |
| 1009 } | 1009 } |
| 1010 } else { | 1010 } else { |
| 1011 isLastNone = simpleSeq.isCombinatorNone; | 1011 isLastNone = simpleSeq.isCombinatorNone; |
| 1012 } | 1012 } |
| 1013 } | 1013 } |
| 1014 } | 1014 } |
| 1015 super.visitSelectorGroup(node); | 1015 super.visitSelectorGroup(node); |
| 1016 } | 1016 } |
| 1017 } | 1017 } |
| OLD | NEW |