| 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 // 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 |
| 8 // selector group (e.g., .btn, .btn { color: red; }). Also, look | 8 // selector group (e.g., .btn, .btn { color: red; }). Also, look |
| 9 // at simplifying selectors expressions too (much harder). | 9 // at simplifying selectors expressions too (much harder). |
| 10 // TODO(terry): Detect invalid directive usage. All @imports must occur before | 10 // TODO(terry): Detect invalid directive usage. All @imports must occur before |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 * Build up the list of all inherited sequences from the parent selector | 236 * Build up the list of all inherited sequences from the parent selector |
| 237 * [node] is the current nested selector and it's parent is the last entry in | 237 * [node] is the current nested selector and it's parent is the last entry in |
| 238 * the [_nestedSelectorGroup]. | 238 * the [_nestedSelectorGroup]. |
| 239 */ | 239 */ |
| 240 SelectorGroup _mergeToFlatten(RuleSet node) { | 240 SelectorGroup _mergeToFlatten(RuleSet node) { |
| 241 // Create a new SelectorGroup for this nesting level. | 241 // Create a new SelectorGroup for this nesting level. |
| 242 var nestedSelectors = _nestedSelectorGroup.selectors; | 242 var nestedSelectors = _nestedSelectorGroup.selectors; |
| 243 var selectors = node.selectorGroup.selectors; | 243 var selectors = node.selectorGroup.selectors; |
| 244 | 244 |
| 245 // Create a merged set of previous parent selectors and current selectors. | 245 // Create a merged set of previous parent selectors and current selectors. |
| 246 var newSelectors = []; | 246 var newSelectors = <Selector>[]; |
| 247 for (Selector selector in selectors) { | 247 for (Selector selector in selectors) { |
| 248 for (Selector nestedSelector in nestedSelectors) { | 248 for (Selector nestedSelector in nestedSelectors) { |
| 249 var seq = _mergeNestedSelector(nestedSelector.simpleSelectorSequences, | 249 var seq = _mergeNestedSelector(nestedSelector.simpleSelectorSequences, |
| 250 selector.simpleSelectorSequences); | 250 selector.simpleSelectorSequences); |
| 251 newSelectors.add(new Selector(seq, node.span)); | 251 newSelectors.add(new Selector(seq, node.span)); |
| 252 } | 252 } |
| 253 } | 253 } |
| 254 | 254 |
| 255 return new SelectorGroup(newSelectors, node.span); | 255 return new SelectorGroup(newSelectors, node.span); |
| 256 } | 256 } |
| 257 | 257 |
| 258 /** | 258 /** |
| 259 * Merge the nested selector sequences [current] to the [parent] sequences or | 259 * Merge the nested selector sequences [current] to the [parent] sequences or |
| 260 * substitue any & with the parent selector. | 260 * substitue any & with the parent selector. |
| 261 */ | 261 */ |
| 262 List<SimpleSelectorSequence> _mergeNestedSelector( | 262 List<SimpleSelectorSequence> _mergeNestedSelector( |
| 263 List<SimpleSelectorSequence> parent, | 263 List<SimpleSelectorSequence> parent, |
| 264 List<SimpleSelectorSequence> current) { | 264 List<SimpleSelectorSequence> current) { |
| 265 | 265 |
| 266 // If any & operator then the parent selector will be substituted otherwise | 266 // If any & operator then the parent selector will be substituted otherwise |
| 267 // the parent selector is pre-pended to the current selector. | 267 // the parent selector is pre-pended to the current selector. |
| 268 var hasThis = current.any((s) => s.simpleSelector.isThis); | 268 var hasThis = current.any((s) => s.simpleSelector.isThis); |
| 269 | 269 |
| 270 var newSequence = []; | 270 var newSequence = <SimpleSelectorSequence>[]; |
| 271 | 271 |
| 272 if (!hasThis) { | 272 if (!hasThis) { |
| 273 // If no & in the sector group then prefix with the parent selector. | 273 // If no & in the sector group then prefix with the parent selector. |
| 274 newSequence.addAll(parent); | 274 newSequence.addAll(parent); |
| 275 newSequence.addAll(_convertToDescendentSequence(current)); | 275 newSequence.addAll(_convertToDescendentSequence(current)); |
| 276 } else { | 276 } else { |
| 277 for (var sequence in current) { | 277 for (var sequence in current) { |
| 278 if (sequence.simpleSelector.isThis) { | 278 if (sequence.simpleSelector.isThis) { |
| 279 // Substitue the & with the parent selector and only use a combinator | 279 // Substitue the & with the parent selector and only use a combinator |
| 280 // descendant if & is prefix by a sequence with an empty name e.g., | 280 // descendant if & is prefix by a sequence with an empty name e.g., |
| (...skipping 14 matching lines...) Expand all Loading... |
| 295 /** | 295 /** |
| 296 * Return selector sequences with first sequence combinator being a | 296 * Return selector sequences with first sequence combinator being a |
| 297 * descendant. Used for nested selectors when the parent selector needs to | 297 * descendant. Used for nested selectors when the parent selector needs to |
| 298 * 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 |
| 299 * parent selector. | 299 * parent selector. |
| 300 */ | 300 */ |
| 301 List<SimpleSelectorSequence> _convertToDescendentSequence( | 301 List<SimpleSelectorSequence> _convertToDescendentSequence( |
| 302 List<SimpleSelectorSequence> sequences) { | 302 List<SimpleSelectorSequence> sequences) { |
| 303 if (sequences.isEmpty) return sequences; | 303 if (sequences.isEmpty) return sequences; |
| 304 | 304 |
| 305 var newSequences = []; | 305 var newSequences = <SimpleSelectorSequence>[]; |
| 306 var first = sequences.first; | 306 var first = sequences.first; |
| 307 newSequences.add(new SimpleSelectorSequence( | 307 newSequences.add(new SimpleSelectorSequence( |
| 308 first.simpleSelector, first.span, TokenKind.COMBINATOR_DESCENDANT)); | 308 first.simpleSelector, first.span, TokenKind.COMBINATOR_DESCENDANT)); |
| 309 newSequences.addAll(sequences.skip(1)); | 309 newSequences.addAll(sequences.skip(1)); |
| 310 | 310 |
| 311 return newSequences; | 311 return newSequences; |
| 312 } | 312 } |
| 313 | 313 |
| 314 void visitDeclarationGroup(DeclarationGroup node) { | 314 void visitDeclarationGroup(DeclarationGroup node) { |
| 315 var span = node.span; | 315 var span = node.span; |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 visitMixinRulesetDirective(mixinDef); | 585 visitMixinRulesetDirective(mixinDef); |
| 586 } else { | 586 } else { |
| 587 visitMixinDeclarationDirective(mixinDef); | 587 visitMixinDeclarationDirective(mixinDef); |
| 588 } | 588 } |
| 589 } | 589 } |
| 590 | 590 |
| 591 /** | 591 /** |
| 592 * Given a mixin's defined arguments return a cloned mixin defintion that has | 592 * Given a mixin's defined arguments return a cloned mixin defintion that has |
| 593 * replaced all defined arguments with user's supplied VarUsages. | 593 * replaced all defined arguments with user's supplied VarUsages. |
| 594 */ | 594 */ |
| 595 MixinDefinition transform(List callArgs) { | 595 MixinDefinition transform(List<List<Expression>> callArgs) { |
| 596 // TODO(terry): Handle default arguments and varArgs. | 596 // TODO(terry): Handle default arguments and varArgs. |
| 597 // Transform mixin with callArgs. | 597 // Transform mixin with callArgs. |
| 598 for (var index = 0; index < _definedArgs.length; index++) { | 598 for (var index = 0; index < _definedArgs.length; index++) { |
| 599 var definedArg = _definedArgs[index]; | 599 var definedArg = _definedArgs[index]; |
| 600 VarDefinition varDef; | 600 VarDefinition varDef; |
| 601 if (definedArg is VarDefinition) { | 601 if (definedArg is VarDefinition) { |
| 602 varDef = definedArg; | 602 varDef = definedArg; |
| 603 } else if (definedArg is VarDefinitionDirective) { | 603 } else if (definedArg is VarDefinitionDirective) { |
| 604 VarDefinitionDirective varDirective = definedArg; | 604 VarDefinitionDirective varDirective = definedArg; |
| 605 varDef = varDirective.def; | 605 varDef = varDirective.def; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 621 k.expressions.replaceRange(usagesIndex, usagesIndex + 1, callArg); | 621 k.expressions.replaceRange(usagesIndex, usagesIndex + 1, callArg); |
| 622 } | 622 } |
| 623 }); | 623 }); |
| 624 } | 624 } |
| 625 | 625 |
| 626 // Clone the mixin | 626 // Clone the mixin |
| 627 return mixinDef.clone(); | 627 return mixinDef.clone(); |
| 628 } | 628 } |
| 629 | 629 |
| 630 /** Rip apart var def with multiple parameters. */ | 630 /** Rip apart var def with multiple parameters. */ |
| 631 List<List<TreeNode>> _varDefsAsCallArgs(var callArg) { | 631 List<List<Expression>> _varDefsAsCallArgs(var callArg) { |
| 632 var defArgs = []; | 632 var defArgs = <List<Expression>>[]; |
| 633 if (callArg is List && callArg[0] is VarUsage) { | 633 if (callArg is List && callArg[0] is VarUsage) { |
| 634 var varDef = varDefs[callArg[0].name]; | 634 var varDef = varDefs[callArg[0].name]; |
| 635 var expressions = varDef.expression.expressions; | 635 var expressions = (varDef.expression as Expressions).expressions; |
| 636 assert(expressions.length > 1); | 636 assert(expressions.length > 1); |
| 637 for (var expr in expressions) { | 637 for (var expr in expressions) { |
| 638 if (expr is! OperatorComma) { | 638 if (expr is! OperatorComma) { |
| 639 defArgs.add([expr]); | 639 defArgs.add([expr]); |
| 640 } | 640 } |
| 641 } | 641 } |
| 642 } | 642 } |
| 643 return defArgs; | 643 return defArgs; |
| 644 } | 644 } |
| 645 | 645 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 currDeclGroup.declarations.replaceRange( | 749 currDeclGroup.declarations.replaceRange( |
| 750 index, index + 1, [new NoOp()]); | 750 index, index + 1, [new NoOp()]); |
| 751 } | 751 } |
| 752 _messages.warning( | 752 _messages.warning( |
| 753 "Using top-level mixin ${node.include.name} as a declaration", | 753 "Using top-level mixin ${node.include.name} as a declaration", |
| 754 node.span); | 754 node.span); |
| 755 } else { | 755 } else { |
| 756 // We're a list of @include(s) inside of a mixin ruleset - convert | 756 // We're a list of @include(s) inside of a mixin ruleset - convert |
| 757 // to a list of IncludeMixinAtDeclaration(s). | 757 // to a list of IncludeMixinAtDeclaration(s). |
| 758 var origRulesets = mixinDef.rulesets; | 758 var origRulesets = mixinDef.rulesets; |
| 759 var rulesets = []; | 759 var rulesets = <Declaration>[]; |
| 760 if (origRulesets.every((ruleset) => ruleset is IncludeDirective)) { | 760 if (origRulesets.every((ruleset) => ruleset is IncludeDirective)) { |
| 761 origRulesets.forEach((ruleset) { | 761 origRulesets.forEach((ruleset) { |
| 762 rulesets | 762 rulesets.add(new IncludeMixinAtDeclaration( |
| 763 .add(new IncludeMixinAtDeclaration(ruleset, ruleset.span)); | 763 ruleset as IncludeDirective, ruleset.span)); |
| 764 }); | 764 }); |
| 765 _IncludeReplacer.replace(_styleSheet, node, rulesets); | 765 _IncludeReplacer.replace(_styleSheet, node, rulesets); |
| 766 } | 766 } |
| 767 } | 767 } |
| 768 } | 768 } |
| 769 | 769 |
| 770 if (mixinDef.definedArgs.length > 0 && node.include.args.length > 0) { | 770 if (mixinDef.definedArgs.length > 0 && node.include.args.length > 0) { |
| 771 var callMixin = _createCallDeclMixin(mixinDef); | 771 var callMixin = _createCallDeclMixin(mixinDef); |
| 772 mixinDef = callMixin.transform(node.include.args); | 772 mixinDef = callMixin.transform(node.include.args); |
| 773 } | 773 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 834 } | 834 } |
| 835 | 835 |
| 836 void visitVarDefinitionDirective(VarDefinitionDirective node) { | 836 void visitVarDefinitionDirective(VarDefinitionDirective node) { |
| 837 visitVarDefinition(node.def); | 837 visitVarDefinition(node.def); |
| 838 } | 838 } |
| 839 } | 839 } |
| 840 | 840 |
| 841 /** @include as a top-level with ruleset(s). */ | 841 /** @include as a top-level with ruleset(s). */ |
| 842 class _IncludeReplacer extends Visitor { | 842 class _IncludeReplacer extends Visitor { |
| 843 final _include; | 843 final _include; |
| 844 final List<Declaration> _newDeclarations; | 844 final List<TreeNode> _newDeclarations; |
| 845 bool _foundAndReplaced = false; | 845 bool _foundAndReplaced = false; |
| 846 | 846 |
| 847 /** | 847 /** |
| 848 * Look for the [ruleSet] inside of a @media directive; if found then replace | 848 * Look for the [ruleSet] inside of a @media directive; if found then replace |
| 849 * with the [newRules]. | 849 * with the [newRules]. |
| 850 */ | 850 */ |
| 851 static void replace( | 851 static void replace( |
| 852 StyleSheet ss, var include, List<Declaration> newDeclarations) { | 852 StyleSheet ss, var include, List<TreeNode> newDeclarations) { |
| 853 var visitor = new _IncludeReplacer(include, newDeclarations); | 853 var visitor = new _IncludeReplacer(include, newDeclarations); |
| 854 visitor.visitStyleSheet(ss); | 854 visitor.visitStyleSheet(ss); |
| 855 } | 855 } |
| 856 | 856 |
| 857 _IncludeReplacer(this._include, this._newDeclarations); | 857 _IncludeReplacer(this._include, this._newDeclarations); |
| 858 | 858 |
| 859 void visitDeclarationGroup(DeclarationGroup node) { | 859 void visitDeclarationGroup(DeclarationGroup node) { |
| 860 var index = _findInclude(node.declarations, _include); | 860 var index = _findInclude(node.declarations, _include); |
| 861 if (index != -1) { | 861 if (index != -1) { |
| 862 node.declarations.insertAll(index + 1, _newDeclarations); | 862 node.declarations.insertAll(index + 1, _newDeclarations); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1005 isLastNone = false; | 1005 isLastNone = false; |
| 1006 } | 1006 } |
| 1007 } else { | 1007 } else { |
| 1008 isLastNone = simpleSeq.isCombinatorNone; | 1008 isLastNone = simpleSeq.isCombinatorNone; |
| 1009 } | 1009 } |
| 1010 } | 1010 } |
| 1011 } | 1011 } |
| 1012 super.visitSelectorGroup(node); | 1012 super.visitSelectorGroup(node); |
| 1013 } | 1013 } |
| 1014 } | 1014 } |
| OLD | NEW |