Skip to content

Commit 3b8afa2

Browse files
authored
Fix top-level nesting selectors in loaded plain CSS (#2560)
See sass/sass#4055
1 parent 087a685 commit 3b8afa2

File tree

7 files changed

+49
-10
lines changed

7 files changed

+49
-10
lines changed

Diff for: CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 1.87.0
2+
3+
* **Potentially breaking bug fix:** When a plain CSS file with a top-level
4+
nesting selector `&` is loaded into a nested Sass context via
5+
`meta.load-css()` or `@import`, Sass now emits plain CSS nesting rather than
6+
incorrectly combining it with the parent selector using a descendant
7+
combinator.
8+
19
## 1.86.3
210

311
* Fix a bug introduced in 1.86.1 where Sass fails to resolve paths starting with

Diff for: lib/src/ast/selector.dart

+16-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import '../visitor/serialize.dart';
1414
import 'node.dart';
1515
import 'selector/complex.dart';
1616
import 'selector/list.dart';
17+
import 'selector/parent.dart';
1718
import 'selector/placeholder.dart';
1819
import 'selector/pseudo.dart';
1920

@@ -49,6 +50,13 @@ abstract base class Selector implements AstNode {
4950
@internal
5051
bool get isInvisible => accept(const _IsInvisibleVisitor(includeBogus: true));
5152

53+
/// Whether this selector contains a [ParentSelector].
54+
///
55+
/// @nodoc
56+
@internal
57+
bool get containsParentSelector =>
58+
accept(const _ContainsParentSelectorVisitor());
59+
5260
// Whether this selector would be invisible even if it didn't have bogus
5361
// combinators.
5462
///
@@ -169,7 +177,7 @@ class _IsBogusVisitor with AnySelectorVisitor {
169177
}
170178
}
171179

172-
/// The visitor used to implement [Selector.isUseless]
180+
/// The visitor used to implement [Selector.isUseless].
173181
class _IsUselessVisitor with AnySelectorVisitor {
174182
const _IsUselessVisitor();
175183

@@ -182,3 +190,10 @@ class _IsUselessVisitor with AnySelectorVisitor {
182190

183191
bool visitPseudoSelector(PseudoSelector pseudo) => pseudo.isBogus;
184192
}
193+
194+
/// The visitor used to implement [Selector.containsParentSelector].
195+
class _ContainsParentSelectorVisitor with AnySelectorVisitor {
196+
const _ContainsParentSelectorVisitor();
197+
198+
bool visitParentSelector(ParentSelector _) => true;
199+
}

Diff for: lib/src/visitor/async_evaluate.dart

+10-2
Original file line numberDiff line numberDiff line change
@@ -2373,7 +2373,11 @@ final class _EvaluateVisitor
23732373
plainCss: _stylesheet.plainCss,
23742374
);
23752375

2376-
var nest = !(_styleRule?.fromPlainCss ?? false);
2376+
var nest = switch (_styleRule) {
2377+
null => true,
2378+
CssStyleRule(fromPlainCss: true) => false,
2379+
_ => !(_stylesheet.plainCss && parsedSelector.containsParentSelector)
2380+
};
23772381
if (nest) {
23782382
if (_stylesheet.plainCss) {
23792383
for (var complex in parsedSelector.components) {
@@ -4071,7 +4075,11 @@ final class _EvaluateVisitor
40714075
}
40724076

40734077
var styleRule = _styleRule;
4074-
var nest = !(_styleRule?.fromPlainCss ?? false);
4078+
var nest = switch (_styleRule) {
4079+
null => true,
4080+
CssStyleRule(fromPlainCss: true) => false,
4081+
_ => !(node.fromPlainCss && node.selector.containsParentSelector)
4082+
};
40754083
var originalSelector = nest
40764084
? node.selector.nestWithin(
40774085
styleRule?.originalSelector,

Diff for: lib/src/visitor/evaluate.dart

+11-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// DO NOT EDIT. This file was generated from async_evaluate.dart.
66
// See tool/grind/synchronize.dart for details.
77
//
8-
// Checksum: 25aa2d050126950ea37dc1c53539f0b041356e8e
8+
// Checksum: 607745b48d0737b3be112d0a8753dd87492fcc31
99
//
1010
// ignore_for_file: unused_import
1111

@@ -2380,7 +2380,11 @@ final class _EvaluateVisitor
23802380
plainCss: _stylesheet.plainCss,
23812381
);
23822382

2383-
var nest = !(_styleRule?.fromPlainCss ?? false);
2383+
var nest = switch (_styleRule) {
2384+
null => true,
2385+
CssStyleRule(fromPlainCss: true) => false,
2386+
_ => !(_stylesheet.plainCss && parsedSelector.containsParentSelector)
2387+
};
23842388
if (nest) {
23852389
if (_stylesheet.plainCss) {
23862390
for (var complex in parsedSelector.components) {
@@ -4072,7 +4076,11 @@ final class _EvaluateVisitor
40724076
}
40734077

40744078
var styleRule = _styleRule;
4075-
var nest = !(_styleRule?.fromPlainCss ?? false);
4079+
var nest = switch (_styleRule) {
4080+
null => true,
4081+
CssStyleRule(fromPlainCss: true) => false,
4082+
_ => !(node.fromPlainCss && node.selector.containsParentSelector)
4083+
};
40764084
var originalSelector = nest
40774085
? node.selector.nestWithin(
40784086
styleRule?.originalSelector,

Diff for: pkg/sass_api/CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 15.3.3
1+
## 15.4.0
22

33
* No user-visible changes.
44

Diff for: pkg/sass_api/pubspec.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ name: sass_api
22
# Note: Every time we add a new Sass AST node, we need to bump the *major*
33
# version because it's a breaking change for anyone who's implementing the
44
# visitor interface(s).
5-
version: 15.3.3
5+
version: 15.4.0
66
description: Additional APIs for Dart Sass.
77
homepage: https://github.com/sass/dart-sass
88

99
environment:
1010
sdk: ">=3.6.0 <4.0.0"
1111

1212
dependencies:
13-
sass: 1.86.3
13+
sass: 1.87.0
1414

1515
dev_dependencies:
1616
dartdoc: ^8.0.14

Diff for: pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: sass
2-
version: 1.86.3
2+
version: 1.87.0
33
description: A Sass implementation in Dart.
44
homepage: https://github.com/sass/dart-sass
55

0 commit comments

Comments
 (0)