Make transitive @extend work.

Loops are still kind of iffy.
This commit is contained in:
Natalie Weizenbaum 2016-09-24 15:42:16 -07:00 committed by Natalie Weizenbaum
parent 9d2d8652dc
commit 9f21fa943e
3 changed files with 25 additions and 18 deletions

View File

@ -26,13 +26,19 @@ class Extender {
static SelectorList extend( static SelectorList extend(
SelectorList selector, SelectorList source, SimpleSelector target) => SelectorList selector, SelectorList source, SimpleSelector target) =>
new Extender()._extendList( new Extender()._extendList(selector, {
selector, {target: new Set()..add(new ExtendSource(source, null))}); target: new Set()
..add(new ExtendSource(new CssValue(source, null), null))
});
static SelectorList replace( static SelectorList replace(
SelectorList selector, SelectorList source, SimpleSelector target) => SelectorList selector, SelectorList source, SimpleSelector target) =>
new Extender()._extendList( new Extender()._extendList(
selector, {target: new Set()..add(new ExtendSource(source, null))}, selector,
{
target: new Set()
..add(new ExtendSource(new CssValue(source, null), null))
},
replace: true); replace: true);
CssStyleRule addSelector(CssValue<SelectorList> selector, FileSpan span) { CssStyleRule addSelector(CssValue<SelectorList> selector, FileSpan span) {
@ -72,19 +78,18 @@ class Extender {
} }
} }
void addExtension( void addExtension(CssValue<SelectorList> extender, SimpleSelector target,
SelectorList sourceList, SimpleSelector target, ExtendRule extend) { ExtendRule extend) {
var source = new ExtendSource(sourceList, extend.span); var source = new ExtendSource(extender, extend.span);
source.isUsed = extend.isOptional; source.isUsed = extend.isOptional;
_extensions.putIfAbsent(target, () => new Set()).add(source); _extensions.putIfAbsent(target, () => new Set()).add(source);
var rules = _selectors[target]; var rules = _selectors[target];
if (rules == null) return; if (rules == null) return;
var extensions = {target: new Set()..add(source)}; var extensions = {target: new Set()..add(source)};
for (var rule in rules) { for (var rule in rules.toList()) {
var list = rule.selector.value; rule.selector.value = _extendList(rule.selector.value, extensions);
rule.selector.value = _extendList(list, extensions); _registerSelector(rule.selector.value, rule);
} }
} }
@ -163,7 +168,7 @@ class Extender {
} }
if (!changed) return null; if (!changed) return null;
return _trim(paths(extendedNotExpanded).map((path) { var result = _trim(paths(extendedNotExpanded).map((path) {
return weave(path.map((complex) => complex.components).toList()) return weave(path.map((complex) => complex.components).toList())
.map((outputComplex) { .map((outputComplex) {
return new ComplexSelector(outputComplex, return new ComplexSelector(outputComplex,
@ -171,6 +176,7 @@ class Extender {
path.any((inputComplex) => inputComplex.lineBreak)); path.any((inputComplex) => inputComplex.lineBreak));
}); });
}).toList()); }).toList());
return result;
} }
List<ComplexSelector> _extendCompound(CompoundSelector compound, List<ComplexSelector> _extendCompound(CompoundSelector compound,
@ -203,9 +209,9 @@ class Extender {
new List<SimpleSelector>(compound.components.length - 1); new List<SimpleSelector>(compound.components.length - 1);
compoundWithoutSimple.setRange(0, i, compound.components); compoundWithoutSimple.setRange(0, i, compound.components);
compoundWithoutSimple.setRange( compoundWithoutSimple.setRange(
i, compound.components.length - 1, compound.components, i); i, compound.components.length - 1, compound.components, i + 1);
for (var source in sources) { for (var source in sources) {
for (var complex in source.extender.components) { for (var complex in source.extender.value.components) {
var extenderBase = complex.components.last as CompoundSelector; var extenderBase = complex.components.last as CompoundSelector;
var unified = compoundWithoutSimple.isEmpty var unified = compoundWithoutSimple.isEmpty
? extenderBase ? extenderBase
@ -246,7 +252,6 @@ class Extender {
List<PseudoSelector> _extendPseudo( List<PseudoSelector> _extendPseudo(
PseudoSelector pseudo, Map<SimpleSelector, Set<ExtendSource>> extensions, PseudoSelector pseudo, Map<SimpleSelector, Set<ExtendSource>> extensions,
{bool replace: false}) { {bool replace: false}) {
// TODO: avoid recursive loops when extending.
var extended = _extendList(pseudo.selector, extensions, replace: replace); var extended = _extendList(pseudo.selector, extensions, replace: replace);
if (extended == null) return null; if (extended == null) return null;

View File

@ -4,10 +4,11 @@
import 'package:source_span/source_span.dart'; import 'package:source_span/source_span.dart';
import '../ast/css.dart';
import '../ast/selector.dart'; import '../ast/selector.dart';
class ExtendSource { class ExtendSource {
final SelectorList extender; final CssValue<SelectorList> extender;
final FileSpan span; final FileSpan span;

View File

@ -263,7 +263,7 @@ class PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
// TODO: recontextualize parse errors. // TODO: recontextualize parse errors.
// TODO: disallow parent selectors. // TODO: disallow parent selectors.
var target = new SimpleSelector.parse(targetText.value.trim()); var target = new SimpleSelector.parse(targetText.value.trim());
_extender.addExtension(_selector.value, target, node); _extender.addExtension(_selector, target, node);
} }
void visitAtRule(AtRule node) { void visitAtRule(AtRule node) {
@ -498,8 +498,9 @@ class PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
var selector = var selector =
new CssValue<SelectorList>(parsedSelector, node.selector.span); new CssValue<SelectorList>(parsedSelector, node.selector.span);
_withParent(_extender.addSelector(selector, node.span), () { var rule = _extender.addSelector(selector, node.span);
_withSelector(selector, () { _withParent(rule, () {
_withSelector(rule.selector, () {
for (var child in node.children) { for (var child in node.children) {
child.accept(this); child.accept(this);
} }