Skip to content

Commit

Permalink
Improve combinator superselector logic (#1778)
Browse files Browse the repository at this point in the history
Closes #791
  • Loading branch information
nex3 authored Aug 16, 2022
1 parent 6fd25ae commit a987352
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 25 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 1.54.5

* Properly consider `a ~ c` to be a superselector of `a ~ b ~ c` and `a + b +
c`.

* Properly consider `b > c` to be a superselector of `a > b > c`, and similarly
for other combinators.

## 1.54.4

* Improve error messages when passing incorrect units that are also
Expand Down
50 changes: 28 additions & 22 deletions lib/src/extend/functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -646,36 +646,42 @@ bool complexIsSuperselector(List<ComplexSelectorComponent> complex1,
var component2 = complex2[endOfSubselector];
var combinator1 = component1.combinators.firstOrNull;
var combinator2 = component2.combinators.firstOrNull;
if (!_isSupercombinator(combinator1, combinator2)) {
return false;
}

if (combinator1 != null) {
if (combinator2 == null) return false;
i1++;
i2 = endOfSubselector + 1;

// `.foo ~ .bar` is a superselector of `.foo + .bar`, but otherwise the
// combinators must match.
if (complex1.length - i1 == 1) {
if (combinator1 == Combinator.followingSibling) {
if (combinator2 == Combinator.child) return false;
} else if (combinator2 != combinator1) {
return false;
// The selector `.foo ~ .bar` is only a superselector of selectors that
// *exclusively* contain subcombinators of `~`.
if (!complex2
.take(complex2.length - 1)
.skip(i2)
.every((component) => _isSupercombinator(
combinator1, component.combinators.firstOrNull))) {
return false;
}
} else if (combinator1 != null) {
// `.foo > .bar` and `.foo + bar` aren't superselectors of any selectors
// with more than one combinator.
if (complex2.length - i2 > 1) return false;
}

// `.foo > .baz` is not a superselector of `.foo > .bar > .baz` or
// `.foo > .bar .baz`, despite the fact that `.baz` is a superselector of
// `.bar > .baz` and `.bar .baz`. Same goes for `+` and `~`.
if (remaining1 == 2 && remaining2 > 2) return false;

i1++;
i2 = endOfSubselector + 1;
} else if (combinator2 != null) {
if (combinator2 != Combinator.child) return false;
i1++;
i2 = endOfSubselector + 1;
} else {
i1++;
i2 = endOfSubselector + 1;
}
}
}

/// Returns whether [combinator1] is a supercombinator of [combinator2].
///
/// That is, whether `X combinator1 Y` is a superselector of `X combinator2 Y`.
bool _isSupercombinator(Combinator? combinator1, Combinator? combinator2) =>
combinator1 == combinator2 ||
(combinator1 == null && combinator2 == Combinator.child) ||
(combinator1 == Combinator.followingSibling &&
combinator2 == Combinator.nextSibling);

/// Returns whether [compound1] is a superselector of [compound2].
///
/// That is, whether [compound1] matches every element that [compound2] matches, as well
Expand Down
4 changes: 4 additions & 0 deletions pkg/sass_api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.0.5

* No user-visible changes.

## 2.0.4

* No user-visible changes.
Expand Down
4 changes: 2 additions & 2 deletions pkg/sass_api/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ name: sass_api
# Note: Every time we add a new Sass AST node, we need to bump the *major*
# version because it's a breaking change for anyone who's implementing the
# visitor interface(s).
version: 2.0.4
version: 2.0.5
description: Additional APIs for Dart Sass.
homepage: https://github.com/sass/dart-sass

environment:
sdk: ">=2.12.0 <3.0.0"

dependencies:
sass: 1.54.4
sass: 1.54.5

dev_dependencies:
dartdoc: ^5.0.0
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: sass
version: 1.54.4
version: 1.54.5-dev
description: A Sass implementation in Dart.
homepage: https://github.com/sass/dart-sass

Expand Down

0 comments on commit a987352

Please sign in to comment.