Skip to content

Commit 83c39fe

Browse files
authored
Support the top-level parent selector (#2758)
1 parent ec85871 commit 83c39fe

3 files changed

Lines changed: 31 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
## 1.99.0
22

3+
* Add support for parent selectors (`&`) at the root of the document. These are
4+
emitted as-is in the CSS output, where they're interpreted as [the scoping
5+
root].
6+
7+
[the scoping root]: https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/Nesting_selector#using_outside_nested_rule
8+
39
* User-defined functions named `calc` or `clamp` are no longer forbidden. If
410
such a function exists without a namespace in the current module, it will be
511
used instead of the built-in `calc()` or `clamp()` function.

lib/src/ast/selector/list.dart

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,18 @@ final class SelectorList extends Selector {
120120
}) {
121121
if (parent == null) {
122122
if (preserveParentSelectors) return this;
123-
var parentSelector = accept(const _ParentSelectorVisitor());
124-
if (parentSelector == null) return this;
125-
throw SassException(
126-
'Top-level selectors may not contain the parent selector "&".',
127-
parentSelector.span,
128-
);
123+
if (accept(const _ParentSelectorVisitor())
124+
case ParentSelector(
125+
suffix: var _?,
126+
:var span,
127+
)) {
128+
throw SassException(
129+
'A top-level selector may not contain a parent selector with a '
130+
'suffix.',
131+
span,
132+
);
133+
}
134+
return this;
129135
}
130136

131137
return SelectorList(

lib/src/functions/selector.dart

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,19 @@ final module = BuiltInModule(
4141
],
4242
);
4343

44-
final _nest = _function("nest", r"$selectors...", (arguments) {
45-
var selectors = arguments[0].asList;
46-
if (selectors.isEmpty) {
47-
throw SassScriptException(
48-
"\$selectors: At least one selector must be passed.",
49-
);
50-
}
51-
52-
var first = true;
53-
return selectors
54-
.map((selector) {
55-
var result = selector.assertSelector(allowParent: !first);
56-
first = false;
57-
return result;
58-
})
59-
.reduce((parent, child) => child.nestWithin(parent))
60-
.asSassList;
61-
});
44+
final _nest = _function(
45+
"nest",
46+
r"$selectors...",
47+
(arguments) =>
48+
arguments[0]
49+
.asList
50+
.map((selector) => selector.assertSelector(allowParent: true))
51+
.fold<SelectorList?>(
52+
null, (parent, child) => child.nestWithin(parent))
53+
?.asSassList ??
54+
(throw SassScriptException(
55+
"\$selectors: At least one selector must be passed.",
56+
)));
6257

6358
final _append = _function("append", r"$selectors...", (arguments) {
6459
var selectors = arguments[0].asList;

0 commit comments

Comments
 (0)