From 73be343be56c29fd3b70822c8520574d57f5aba4 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 3 Feb 2017 16:15:15 -0800 Subject: [PATCH 1/3] Fix a selector pseudo superselector edge case. --- CHANGELOG.md | 3 +++ lib/src/extend/functions.dart | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 199bbf9a..353dd764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,9 @@ * Error out if a function is passed an unknown named parameter. +* Don't consider browser-prefixed selector pseudos to be superselectors of + differently- or non-prefixed selector pseudos with the same base name. + ## 1.0.0-alpha.8 * Add the `content-exists()` function. diff --git a/lib/src/extend/functions.dart b/lib/src/extend/functions.dart index 259b53ce..75580d54 100644 --- a/lib/src/extend/functions.dart +++ b/lib/src/extend/functions.dart @@ -711,7 +711,7 @@ bool _selectorPseudoIsSuperselector( switch (pseudo1.normalizedName) { case 'matches': case 'any': - var pseudos = _selectorPseudosNamed(compound2, pseudo1.normalizedName); + var pseudos = _selectorPseudosNamed(compound2, pseudo1.name); return pseudos.any((pseudo2) { return pseudo1.selector.isSuperselector(pseudo2.selector); }) || @@ -724,7 +724,7 @@ bool _selectorPseudoIsSuperselector( case 'has': case 'host': case 'host-context': - return _selectorPseudosNamed(compound2, pseudo1.normalizedName) + return _selectorPseudosNamed(compound2, pseudo1.name) .any((pseudo2) => pseudo1.selector.isSuperselector(pseudo2.selector)); case 'not': @@ -775,4 +775,4 @@ Iterable _selectorPseudosNamed( simple is PseudoSelector && simple.isClass && simple.selector != null && - simple.normalizedName == name)); + simple.name == name)); From b32e5f96ceb76b9be1d28860066ebdfda29c7a8c Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 3 Feb 2017 16:49:55 -0800 Subject: [PATCH 2/3] Fix a multi-combinator extend edge case. --- CHANGELOG.md | 2 ++ lib/src/extend/functions.dart | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 353dd764..7c2c2837 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,8 @@ * Don't consider browser-prefixed selector pseudos to be superselectors of differently- or non-prefixed selector pseudos with the same base name. +* Fix an `@extend` edge case involving multiple combinators in a row. + ## 1.0.0-alpha.8 * Add the `content-exists()` function. diff --git a/lib/src/extend/functions.dart b/lib/src/extend/functions.dart index 75580d54..51f00d12 100644 --- a/lib/src/extend/functions.dart +++ b/lib/src/extend/functions.dart @@ -302,9 +302,9 @@ List>> _mergeFinalCombinators( // is a supersequence of the other, use that, otherwise give up. var lcs = longestCommonSubsequence(combinators1, combinators2); if (listEquals(lcs, combinators1)) { - result.add([new List.from(combinators2.reversed)]); + result.addFirst([new List.from(combinators2.reversed)]); } else if (listEquals(lcs, combinators2)) { - result.add([new List.from(combinators1.reversed)]); + result.addFirst([new List.from(combinators1.reversed)]); } return result; } From 79261fee8e3a5a37fb0f2a3a2c1b28a6c9ca13c0 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 3 Feb 2017 17:37:54 -0800 Subject: [PATCH 3/3] Add boolean short-circuiting. --- CHANGELOG.md | 2 ++ lib/src/value.dart | 6 ------ lib/src/value/boolean.dart | 4 ---- lib/src/value/null.dart | 4 ---- lib/src/visitor/perform.dart | 30 +++++++++++++++++++++++++++--- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c2c2837..3a269cf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ * Properly handle placeholder selectors in selector pseudos. +* Properly short-circuit the `or` and `and` operators. + * Support `--$variable`. * Don't consider unitless numbers equal to numbers with units. diff --git a/lib/src/value.dart b/lib/src/value.dart index acd15907..4fdd13fd 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -235,12 +235,6 @@ abstract class Value { Value singleEquals(Value other) => new SassString("${toCssString()}=${other.toCssString()}"); - /// The SassScript `or` operation. - Value or(Value other) => this; - - /// The SassScript `and` operation. - Value and(Value other) => other; - /// The SassScript `>` operation. SassBoolean greaterThan(Value other) => throw new SassScriptException('Undefined operation "$this > $other".'); diff --git a/lib/src/value/boolean.dart b/lib/src/value/boolean.dart index 189607fe..6929164e 100644 --- a/lib/src/value/boolean.dart +++ b/lib/src/value/boolean.dart @@ -31,9 +31,5 @@ class SassBoolean extends Value { SassBoolean assertBoolean([String name]) => this; - Value or(Value other) => value ? this : other; - - Value and(Value other) => value ? other : this; - Value unaryNot() => value ? sassFalse : sassTrue; } diff --git a/lib/src/value/null.dart b/lib/src/value/null.dart index 6d50186f..6db8ca26 100644 --- a/lib/src/value/null.dart +++ b/lib/src/value/null.dart @@ -20,9 +20,5 @@ class SassNull extends Value { /*=T*/ accept/**/(ValueVisitor/**/ visitor) => visitor.visitNull(this); - Value or(Value other) => other; - - Value and(Value other) => this; - Value unaryNot() => sassTrue; } diff --git a/lib/src/visitor/perform.dart b/lib/src/visitor/perform.dart index 796fe30d..030691d1 100644 --- a/lib/src/visitor/perform.dart +++ b/lib/src/visitor/perform.dart @@ -964,33 +964,55 @@ class _PerformVisitor Value visitBinaryOperationExpression(BinaryOperationExpression node) { return _addExceptionSpan(node.span, () { var left = node.left.accept(this); - var right = node.right.accept(this); switch (node.operator) { case BinaryOperator.singleEquals: + var right = node.right.accept(this); return left.singleEquals(right); + case BinaryOperator.or: - return left.or(right); + return left.isTruthy ? left : node.right.accept(this); + case BinaryOperator.and: - return left.and(right); + return left.isTruthy ? node.right.accept(this) : left; + case BinaryOperator.equals: + var right = node.right.accept(this); return new SassBoolean(left == right); + case BinaryOperator.notEquals: + var right = node.right.accept(this); return new SassBoolean(left != right); + case BinaryOperator.greaterThan: + var right = node.right.accept(this); return left.greaterThan(right); + case BinaryOperator.greaterThanOrEquals: + var right = node.right.accept(this); return left.greaterThanOrEquals(right); + case BinaryOperator.lessThan: + var right = node.right.accept(this); return left.lessThan(right); + case BinaryOperator.lessThanOrEquals: + var right = node.right.accept(this); return left.lessThanOrEquals(right); + case BinaryOperator.plus: + var right = node.right.accept(this); return left.plus(right); + case BinaryOperator.minus: + var right = node.right.accept(this); return left.minus(right); + case BinaryOperator.times: + var right = node.right.accept(this); return left.times(right); + case BinaryOperator.dividedBy: + var right = node.right.accept(this); var result = left.dividedBy(right); if (node.allowsSlash && left is SassNumber && right is SassNumber) { var leftSlash = left.asSlash ?? _toCss(left, node.left.span); @@ -1000,7 +1022,9 @@ class _PerformVisitor return result; } break; + case BinaryOperator.modulo: + var right = node.right.accept(this); return left.modulo(right); default: return null;