Chromium Code Reviews| 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 | 7 |
| 8 // TODO(terry): Detect invalid directive usage. All @imports must occur before | 8 // TODO(terry): Detect invalid directive usage. All @imports must occur before |
| 9 // all rules other than @charset directive. Any @import directive | 9 // all rules other than @charset directive. Any @import directive |
| 10 // after any non @charset or @import directive are ignored. e.g., | 10 // after any non @charset or @import directive are ignored. e.g., |
| 11 // @import "a.css"; | 11 // @import "a.css"; |
| 12 // div { color: red; } | 12 // div { color: red; } |
| 13 // @import "b.css"; | 13 // @import "b.css"; |
| 14 // becomes: | 14 // becomes: |
| 15 // @import "a.css"; | 15 // @import "a.css"; |
| 16 // div { color: red; } | 16 // div { color: red; } |
| 17 // <http://www.w3.org/TR/css3-syntax/#at-rules> | 17 // <http://www.w3.org/TR/css3-syntax/#at-rules> |
| 18 | 18 |
| 19 /** | 19 /** |
| 20 * Analysis phase will validate/fixup any new CSS feature or any SASS style | 20 * Analysis phase will validate/fixup any new CSS feature or any SASS style |
| 21 * feature. | 21 * feature. |
| 22 */ | 22 */ |
| 23 class Analyzer { | 23 class Analyzer { |
| 24 final List<StyleSheet> _styleSheets; | 24 final List<StyleSheet> _styleSheets; |
| 25 final Messages _messages; | 25 final Messages _messages; |
| 26 MixinDefinitions mixinDefs; | |
| 26 VarDefinitions varDefs; | 27 VarDefinitions varDefs; |
| 27 | 28 |
| 28 Analyzer(this._styleSheets, this._messages); | 29 Analyzer(this._styleSheets, this._messages); |
| 29 | 30 |
| 30 void run() { | 31 void run() { |
| 32 mixinDefs = new MixinDefinitions(_styleSheets); | |
|
nweiz
2013/09/18 22:40:54
It's not correct to locate all mixin definitions b
terry
2013/10/09 03:40:33
Yeah, I liked the idea of hoisting like a class bu
| |
| 33 | |
| 34 // Any mixin cycles? | |
| 35 var mixinCycles = findAllMixinCycles(); | |
| 36 for (var cycle in mixinCycles) { | |
| 37 _messages.warning("mixin cycle detected @mixin ${cycle.def.name}", | |
|
nweiz
2013/09/18 22:40:54
"Mixin cycle detected for @mixin ${cycle.def.name}
terry
2013/10/09 03:40:33
Without hoisting cycle detection is removed.
On 20
| |
| 38 cycle.def.span); | |
| 39 // TODO(terry): What if no mixin definition for a @include an error? | |
|
nweiz
2013/09/18 22:40:54
"What if there are no mixin definitions for an @in
| |
| 40 } | |
| 41 | |
| 31 varDefs = new VarDefinitions(_styleSheets); | 42 varDefs = new VarDefinitions(_styleSheets); |
| 32 | 43 |
| 33 // Any cycles? | 44 // Any var cycles? |
| 34 var cycles = findAllCycles(); | 45 var varCycles = findAllVarCycles(); |
|
nweiz
2013/09/18 22:40:54
Variables should be eagerly evaluated, so cycle de
terry
2013/10/09 03:40:33
Yes also removed variable hoisting.
On 2013/09/18
| |
| 35 for (var cycle in cycles) { | 46 for (var cycle in varCycles) { |
| 36 _messages.warning("var cycle detected var-${cycle.definedName}", | 47 _messages.warning("var cycle detected var-${cycle.definedName}", |
| 37 cycle.span); | 48 cycle.span); |
| 38 // TODO(terry): What if no var definition for a var usage an error? | 49 // TODO(terry): What if no var definition for a var usage an error? |
| 39 // TODO(terry): Ensure a var definition imported from a different style | 50 // TODO(terry): Ensure a var definition imported from a different style |
| 40 // sheet works. | 51 // sheet works. |
| 41 } | 52 } |
| 42 | 53 |
| 43 // Remove any var definition from the stylesheet that has a cycle. | 54 // Remove any var definition from the stylesheet that has a cycle. |
| 44 _styleSheets.forEach((styleSheet) => | 55 _styleSheets.forEach((styleSheet) => |
| 45 new RemoveVarDefinitions(cycles).visitStyleSheet(styleSheet)); | 56 new RemoveVarDefinitions(varCycles).visitStyleSheet(styleSheet)); |
| 57 | |
| 58 // Expand top-level @include. | |
| 59 _styleSheets.forEach((styleSheet) => | |
| 60 new ExpandTopLevelIncludes(mixinDefs, _messages) | |
| 61 ..visitStyleSheet(styleSheet)); | |
|
nweiz
2013/09/18 22:40:54
Running separate visitors for all of these seems i
terry
2013/10/09 03:40:33
Yes, for now that is the mode we've taken in the d
| |
| 62 | |
| 63 // Expand @include in declarations. | |
|
nweiz
2013/09/18 22:40:54
Nit: extra space before "@include".
terry
2013/10/09 03:40:33
Done.
| |
| 64 _styleSheets.forEach((styleSheet) => | |
| 65 new ExpandDeclarationIncludes(styleSheet, mixinDefs, _messages) | |
| 66 ..visitStyleSheet(styleSheet)); | |
| 67 | |
| 68 // Any missing @mixins only check if everything is good up to this point. | |
|
nweiz
2013/09/18 22:40:54
I don't understand what this comment means.
terry
2013/10/09 03:40:33
Functionality removed when hoisting of mixin remov
| |
| 69 if (_messages.messages.isEmpty) { | |
| 70 _styleSheets.forEach((styleSheet) => | |
| 71 new IncludesMissingMixins(mixinDefs, this._messages) | |
| 72 ..visitStyleSheet(styleSheet)); | |
| 73 } | |
| 74 | |
| 75 // Remove all @mixin and @include | |
| 76 _styleSheets.forEach((styleSheet) => | |
| 77 new RemoveMixinsAndIncludes()..visitStyleSheet(styleSheet)); | |
|
nweiz
2013/09/18 22:40:54
Style nit: indent +2 spaces.
terry
2013/10/09 03:40:33
Code removed.
On 2013/09/18 22:40:54, nweiz wrote:
| |
| 46 | 78 |
| 47 // Expand any nested selectors using selector desendant combinator to | 79 // Expand any nested selectors using selector desendant combinator to |
| 48 // signal CSS inheritance notation. | 80 // signal CSS inheritance notation. |
| 49 _styleSheets.forEach((styleSheet) => new ExpandNestedSelectors() | 81 _styleSheets.forEach((styleSheet) => new ExpandNestedSelectors() |
| 50 ..visitStyleSheet(styleSheet) | 82 ..visitStyleSheet(styleSheet) |
| 51 ..flatten(styleSheet)); | 83 ..flatten(styleSheet)); |
| 52 } | 84 } |
| 53 | 85 |
| 54 List<VarDefinition> findAllCycles() { | 86 List<MixinDefinition> findAllMixinCycles() { |
| 87 var cycles = []; | |
| 88 | |
| 89 mixinDefs.map.values.forEach((value) { | |
|
nweiz
2013/09/18 22:40:54
As John's mentioned elsewhere, use a for loop rath
terry
2013/10/09 03:40:33
Cycle code removed.
On 2013/09/18 22:40:54, nweiz
| |
| 90 if (hasMixinCycle(value.includes)) cycles.add(value); | |
| 91 }); | |
| 92 | |
| 93 // Update our local list of known mixinDefinitions remove any mixins with a | |
| 94 // cycle. So the same mixin cycle isn't reported for each style sheet | |
| 95 // processed. | |
| 96 for (var cycle in cycles) { | |
| 97 mixinDefs.map.remove(cycle.def.name); | |
| 98 } | |
| 99 | |
| 100 return cycles; | |
| 101 } | |
| 102 | |
| 103 /** | |
| 104 * [includes] list of IncludeDirective or IncludeMixinAtDeclaration. | |
|
nweiz
2013/09/18 22:40:54
If you're going to include a doc comment, it shoul
terry
2013/10/09 03:40:33
Cycle code removed.
On 2013/09/18 22:40:54, nweiz
| |
| 105 */ | |
| 106 bool hasMixinCycle(List includes, {Set<String> visiting, | |
| 107 Set<String> visited}) { | |
| 108 if (visiting == null) visiting = new Set(); | |
| 109 if (visited == null) visited = new Set(); | |
|
nweiz
2013/09/18 22:40:54
Explain the function of [visited] and how it diffe
terry
2013/10/09 03:40:33
cycle code removed.
On 2013/09/18 22:40:54, nweiz
| |
| 110 | |
| 111 bool cycleDetected = false; | |
| 112 | |
| 113 var name; | |
| 114 for (var include in includes) { | |
| 115 if (include is IncludeMixinAtDeclaration) { | |
| 116 // Get to the IncludeDirective. | |
| 117 name = include.include.name; | |
| 118 } else { | |
| 119 name = include.name; | |
| 120 } | |
| 121 | |
| 122 if (visiting.contains(name)) { | |
| 123 cycleDetected = true; | |
| 124 break; | |
| 125 } | |
| 126 if (!visited.contains(name)) { | |
| 127 visiting.add(name); | |
| 128 visited.add(name); | |
| 129 } | |
| 130 if (mixinDefs.map[name] != null) { | |
| 131 if (hasMixinCycle(mixinDefs.map[name].includes, visiting: visiting, | |
| 132 visited: visited)) { | |
| 133 cycleDetected = true; | |
| 134 break; | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 | |
| 139 | |
| 140 /* | |
|
Jennifer Messerly
2013/09/18 06:44:15
remove?
terry
2013/10/09 03:40:33
entire function removed.
On 2013/09/18 06:44:15, J
| |
| 141 for (var usage in mixinInclude(mixinDefs.map[name].includes)) { | |
| 142 if (hasMixinCycle(usage.name, visiting: visiting, visited: visited)) { | |
| 143 cycleDetected = true; | |
| 144 break; | |
| 145 } | |
| 146 } | |
| 147 */ | |
| 148 visiting.remove(include); | |
| 149 } | |
| 150 | |
| 151 return cycleDetected; | |
| 152 } | |
| 153 | |
| 154 // TODO(terry): Only checks @includes in declarations not ruleset top-level. | |
| 155 Iterable<IncludeDirective> mixinInclude(List includes) => | |
| 156 includes.where((e) => e is IncludeMixinAtDeclaration); | |
| 157 | |
| 158 // ===================== | |
| 159 // Var cycles functions: | |
| 160 // ===================== | |
| 161 | |
| 162 List<VarDefinition> findAllVarCycles() { | |
| 55 var cycles = []; | 163 var cycles = []; |
| 56 | 164 |
| 57 varDefs.map.values.forEach((value) { | 165 varDefs.map.values.forEach((value) { |
| 58 if (hasCycle(value.property)) cycles.add(value); | 166 if (hasCycle(value.property)) cycles.add(value); |
| 59 }); | 167 }); |
| 60 | 168 |
| 61 // Update our local list of known varDefs remove any varDefs with a cycle. | 169 // Update our local list of known varDefs remove any varDefs with a cycle. |
| 62 // So the same varDef cycle isn't reported for each style sheet processed. | 170 // So the same varDef cycle isn't reported for each style sheet processed. |
| 63 for (var cycle in cycles) { | 171 for (var cycle in cycles) { |
| 64 varDefs.map.remove(cycle.property); | 172 varDefs.map.remove(cycle.property); |
| (...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 504 _MediaRulesReplacer(this._ruleSet, this._newRules); | 612 _MediaRulesReplacer(this._ruleSet, this._newRules); |
| 505 | 613 |
| 506 visitMediaDirective(MediaDirective node) { | 614 visitMediaDirective(MediaDirective node) { |
| 507 var index = node.rulesets.indexOf(_ruleSet); | 615 var index = node.rulesets.indexOf(_ruleSet); |
| 508 if (index != -1) { | 616 if (index != -1) { |
| 509 node.rulesets.insertAll(index + 1, _newRules); | 617 node.rulesets.insertAll(index + 1, _newRules); |
| 510 _foundAndReplaced = true; | 618 _foundAndReplaced = true; |
| 511 } | 619 } |
| 512 } | 620 } |
| 513 } | 621 } |
| 622 | |
| 623 class MixinDef { | |
| 624 MixinDefinition def; | |
| 625 List<IncludeDirective> includes; | |
| 626 | |
| 627 MixinDef(this.def, this.includes); | |
| 628 } | |
| 629 | |
| 630 /** Find all mixin definitions from a list of stylesheets. */ | |
| 631 class MixinDefinitions extends Visitor { | |
| 632 /** Map of variable name key to it's definition. */ | |
| 633 final Map<String, MixinDef> map = new Map<String, MixinDef>(); | |
|
nweiz
2013/09/18 22:40:54
This type declaration is unnecessary. The type is
terry
2013/10/09 03:40:33
Yep but editor code completion didn't work w/o it
| |
| 634 | |
| 635 var _includes = []; | |
| 636 | |
| 637 MixinDefinitions(List<StyleSheet> styleSheets) { | |
| 638 for (var styleSheet in styleSheets) { | |
| 639 visitTree(styleSheet); | |
| 640 } | |
| 641 } | |
| 642 | |
| 643 void visitIncludeDirective(IncludeDirective node) { | |
| 644 _includes.add(node); | |
| 645 } | |
| 646 | |
| 647 void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) { | |
| 648 _includes.add(node); | |
| 649 } | |
| 650 | |
| 651 void visitMixinRulesetDirective(MixinRulesetDirective node) { | |
| 652 _includes = []; | |
| 653 | |
| 654 super.visitMixinRulesetDirective(node); | |
| 655 | |
| 656 // Replace with latest top-level mixin definition. | |
| 657 map[node.name] = new MixinDef(node, _includes); | |
| 658 _includes = []; | |
| 659 } | |
| 660 | |
| 661 void visitMixinDeclarationDirective(MixinDeclarationDirective node) { | |
| 662 _includes = []; | |
| 663 | |
| 664 super.visitMixinDeclarationDirective(node); | |
| 665 | |
| 666 // Replace with latest mixin definition. | |
| 667 map[node.name] = new MixinDef(node, _includes); | |
| 668 _includes = []; | |
| 669 } | |
| 670 } | |
| 671 | |
| 672 /** | |
| 673 * Expand all @include at the top-level the ruleset(s) associated with the | |
| 674 * mixin. | |
| 675 */ | |
| 676 class ExpandTopLevelIncludes extends Visitor { | |
| 677 StyleSheet _styleSheet; | |
| 678 final MixinDefinitions defs; | |
| 679 final Messages _messages; | |
| 680 | |
| 681 ExpandTopLevelIncludes(this.defs, this._messages); | |
| 682 | |
| 683 void visitStyleSheet(StyleSheet ss) { | |
| 684 _styleSheet = ss; | |
| 685 super.visitStyleSheet(ss); | |
| 686 _styleSheet = null; | |
| 687 } | |
| 688 | |
| 689 void visitIncludeDirective(IncludeDirective node) { | |
| 690 if (defs.map.containsKey(node.name)) { | |
| 691 var mixinDef = defs.map[node.name].def; | |
| 692 if (mixinDef is MixinRulesetDirective) { | |
| 693 _TopLevelIncludeReplacer.replace(_styleSheet, node, mixinDef.rulesets); | |
| 694 } | |
| 695 } | |
| 696 super.visitIncludeDirective(node); | |
| 697 } | |
| 698 } | |
| 699 | |
| 700 /** @include as a top-level with ruleset(s). */ | |
| 701 class _TopLevelIncludeReplacer extends Visitor { | |
| 702 final IncludeDirective _include; | |
| 703 final List<RuleSet> _newRules; | |
| 704 bool _foundAndReplaced = false; | |
| 705 | |
| 706 /** | |
| 707 * Look for the [ruleSet] inside of an @media directive; if found then replace | |
| 708 * with the [newRules]. If [ruleSet] is found and replaced return true. | |
| 709 */ | |
| 710 static bool replace(StyleSheet styleSheet, IncludeDirective include, | |
|
nweiz
2013/09/18 22:40:54
You have three different ways of invoking a visito
terry
2013/10/09 03:40:33
Function was re-written this no longer exist.
On 2
| |
| 711 List<RuleSet>newRules) { | |
| 712 var visitor = new _TopLevelIncludeReplacer(include, newRules); | |
| 713 visitor.visitStyleSheet(styleSheet); | |
| 714 return visitor._foundAndReplaced; | |
|
nweiz
2013/09/18 22:40:54
This value is never used.
terry
2013/10/09 03:40:33
function re-written not an issue now.
On 2013/09/1
| |
| 715 } | |
| 716 | |
| 717 _TopLevelIncludeReplacer(this._include, this._newRules); | |
| 718 | |
| 719 visitStyleSheet(StyleSheet node) { | |
| 720 var index = node.topLevels.indexOf(_include); | |
| 721 if (index != -1) { | |
| 722 node.topLevels.insertAll(index + 1, _newRules); | |
| 723 node.topLevels.replaceRange(index, index + 1, [new NoOp()]); | |
| 724 _foundAndReplaced = true; | |
| 725 } | |
| 726 super.visitStyleSheet(node); | |
| 727 } | |
| 728 | |
| 729 void visitMixinRulesetDirective(MixinRulesetDirective node) { | |
| 730 var index = node.rulesets.indexOf(_include as dynamic); | |
|
nweiz
2013/09/18 22:40:54
What is "as dynamic" doing here?
terry
2013/10/09 03:40:33
_include can be different either declarative vs/ r
| |
| 731 if (index != -1) { | |
| 732 node.rulesets.insertAll(index + 1, _newRules); | |
| 733 node.rulesets.replaceRange(index, index + 1, [new NoOp()]); | |
|
nweiz
2013/09/18 22:40:54
Why aren't you replacing the include with _newRule
terry
2013/10/09 03:40:33
Only the resolve the @include once.
On 2013/09/18
| |
| 734 _foundAndReplaced = true; | |
| 735 } | |
| 736 super.visitMixinRulesetDirective(node); | |
| 737 } | |
| 738 } | |
| 739 | |
| 740 /** Expand all @include inside of a declaration associated with a mixin. */ | |
| 741 class ExpandDeclarationIncludes extends Visitor { | |
| 742 final StyleSheet _styleSheet; | |
| 743 final MixinDefinitions defs; | |
| 744 final Messages _messages; | |
| 745 | |
| 746 ExpandDeclarationIncludes(this._styleSheet, this.defs, this._messages); | |
| 747 | |
| 748 bool _allIncludes(rulesets) => | |
| 749 rulesets.every((rule) => rule is IncludeDirective || rule is NoOp); | |
| 750 | |
| 751 void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) { | |
| 752 if (defs.map.containsKey(node.include.name)) { | |
|
nweiz
2013/09/18 22:40:54
Short-circuit if this is false to avoid extra nest
terry
2013/10/09 03:40:33
Really, seems clunky to call super for the short-c
| |
| 753 var mixinDef = defs.map[node.include.name].def; | |
| 754 if (mixinDef is MixinDeclarationDirective) { | |
| 755 _IncludeReplacer.replace(_styleSheet, node, | |
| 756 mixinDef.declarations.declarations); | |
| 757 } else if (mixinDef is MixinRulesetDirective) { | |
| 758 // We're a list of @include(s) inside of a mixin ruleset if so then | |
| 759 // we'll convert to a list of IncludeMixinAtDeclaration(s). | |
|
nweiz
2013/09/18 22:40:54
It doesn't make sense to say "We're X. If so, ..."
terry
2013/10/09 03:40:33
yep, changed.
On 2013/09/18 22:40:54, nweiz wrote:
| |
| 760 var orgRulesets = mixinDef.rulesets; | |
|
nweiz
2013/09/18 22:40:54
What does "org" mean?
terry
2013/10/09 03:40:33
original - missing 'i' origRulesets
On 2013/09/18
| |
| 761 var rulesets = []; | |
| 762 if (orgRulesets.every((ruleset) => ruleset is IncludeDirective)) { | |
| 763 orgRulesets.forEach((ruleset) { | |
| 764 rulesets.add(new IncludeMixinAtDeclaration(ruleset, ruleset.span)); | |
| 765 }); | |
| 766 _IncludeReplacer.replace(_styleSheet, node, rulesets); | |
| 767 } else { | |
| 768 _messages.warning( | |
| 769 "Trying to use top-level ruleset in a declaration - " | |
| 770 "@include ${node.include.name}", | |
| 771 node.span); | |
| 772 } | |
| 773 } | |
| 774 } | |
| 775 | |
| 776 super.visitIncludeMixinAtDeclaration(node); | |
| 777 } | |
| 778 } | |
| 779 | |
| 780 /** @include as a top-level with ruleset(s). */ | |
| 781 class _IncludeReplacer extends Visitor { | |
| 782 final _include; | |
| 783 final List<Declaration> _newDeclarations; | |
| 784 bool _foundAndReplaced = false; | |
| 785 | |
| 786 /** | |
| 787 * Look for the [ruleSet] inside of an @media directive; if found then replace | |
|
nweiz
2013/09/18 22:40:54
"a @media"
terry
2013/10/09 03:40:33
Done.
| |
| 788 * with the [newRules]. If [ruleSet] is found and replaced return true. | |
| 789 */ | |
| 790 static bool replace(StyleSheet ss, var include, | |
| 791 List<Declaration> newDeclarations) { | |
| 792 var visitor = new _IncludeReplacer(include, newDeclarations); | |
| 793 visitor.visitStyleSheet(ss); | |
| 794 return visitor._foundAndReplaced; | |
|
nweiz
2013/09/18 22:40:54
This is also never used.
terry
2013/10/09 03:40:33
Done.
| |
| 795 } | |
| 796 | |
| 797 _IncludeReplacer(this._include, this._newDeclarations); | |
| 798 | |
| 799 void visitDeclarationGroup(DeclarationGroup node) { | |
| 800 var index = -1; | |
| 801 var i = 0; | |
| 802 for (var decl in node.declarations) { | |
| 803 if (decl == _include) { | |
| 804 index = i; | |
| 805 break; | |
| 806 } else if (decl is IncludeMixinAtDeclaration) { | |
| 807 if (decl.include == _include) { | |
|
nweiz
2013/09/18 22:40:54
Use "&&" rather than nested if statements.
terry
2013/10/09 03:40:33
While re-writing not an issue anymore.
On 2013/09/
| |
| 808 index = i; | |
| 809 break; | |
| 810 } | |
| 811 } | |
| 812 i++; | |
| 813 } | |
|
nweiz
2013/09/18 22:40:54
This i++/for/break stuff is really complicated and
terry
2013/10/09 03:40:33
ditto on re-write.On 2013/09/18 22:40:54, nweiz wr
| |
| 814 | |
| 815 if (index != -1) { | |
|
nweiz
2013/09/18 22:40:54
Use null rather than -1 as a flag value.
terry
2013/10/09 03:40:33
ditto re-wrote not an issue.
On 2013/09/18 22:40:5
| |
| 816 node.declarations.insertAll(index + 1, _newDeclarations); | |
| 817 // Change @include to NoOp so it's processed only once. | |
| 818 node.declarations.replaceRange(index, index + 1, [new NoOp()]); | |
| 819 _foundAndReplaced = true; | |
| 820 } | |
| 821 super.visitDeclarationGroup(node); | |
| 822 } | |
| 823 } | |
| 824 | |
| 825 class IncludesMissingMixins extends Visitor { | |
| 826 final MixinDefinitions defs; | |
| 827 final Messages _messages; | |
| 828 | |
| 829 IncludesMissingMixins(this.defs, this._messages); | |
| 830 | |
| 831 void visitIncludeDirective(IncludeDirective node) { | |
| 832 if (!defs.map.containsKey(node.name)) { | |
| 833 // @mixin is undefined | |
| 834 _messages.warning("@mixin ${node.name} is undefined.", node.span); | |
|
nweiz
2013/09/18 22:40:54
This should be an error.
terry
2013/10/09 03:40:33
Class removed.
On 2013/09/18 22:40:54, nweiz wrote
| |
| 835 } | |
| 836 | |
| 837 super.visitIncludeDirective(node); | |
| 838 } | |
| 839 } | |
| 840 | |
| 841 /** | |
| 842 * Remove all @mixin and @include and any NoOp used as placeholder for @include. | |
| 843 */ | |
| 844 class RemoveMixinsAndIncludes extends Visitor { | |
|
nweiz
2013/09/18 22:40:54
Don't the other visitors remove the mixins and inc
terry
2013/10/09 03:40:33
class was eliminated when cycles removed.
On 2013/
| |
| 845 RemoveMixinsAndIncludes(); | |
| 846 | |
| 847 bool _nodesToRemove(node) => | |
|
nweiz
2013/09/18 22:40:54
This name sounds like a variable, not a function.
| |
| 848 node is IncludeDirective || node is MixinDefinition || node is NoOp; | |
| 849 | |
| 850 void visitStyleSheet(StyleSheet ss) { | |
| 851 var index = ss.topLevels.length; | |
| 852 while (--index >= 0) { | |
|
nweiz
2013/09/18 22:40:54
It's never clearer to use "--variable" in an expre
| |
| 853 if (_nodesToRemove(ss.topLevels[index])) { | |
| 854 ss.topLevels.removeAt(index); | |
| 855 } | |
| 856 } | |
| 857 | |
| 858 super.visitStyleSheet(ss); | |
| 859 } | |
| 860 | |
| 861 void visitDeclarationGroup(DeclarationGroup node) { | |
| 862 var index = node.declarations.length; | |
| 863 while (--index >= 0) { | |
| 864 if (_nodesToRemove(node.declarations[index])) { | |
| 865 node.declarations.removeAt(index); | |
| 866 } | |
| 867 } | |
| 868 | |
| 869 super.visitDeclarationGroup(node); | |
| 870 } | |
| 871 } | |
| OLD | NEW |