Skip to content

Commit da94771

Browse files
committed
Drop support for bogus combinators
This also improves the way SassExceptions thrown from within custom functions are handled. If the wrapped exception already has a span, it's turned into a MultiSpanSassException with an additional span pointing to the function invocation.
1 parent fdf31ad commit da94771

22 files changed

+963
-790
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
parsing associated with it. It is now parsed like any other unknown plain CSS
55
at-rule, where Sass features are only allowed within `#{}` interpolation.
66

7+
### Dart API
8+
9+
* Remove `Value.assertSelector()`, `.assertSimpleSelector()`,
10+
`.assertCompoundSelector()`, and `.assertComplexSelector()`. This is now only
11+
available through the expanded `sass_api` package, since that package also
12+
exposes the selector AST that it returns.
13+
714
## 1.85.2-dev
815

916
* No user-visible changes.

lib/src/ast/css/node.dart

+1-14
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,6 @@ abstract class CssNode implements AstNode {
3535
const _IsInvisibleVisitor(includeBogus: true, includeComments: false),
3636
);
3737

38-
// Whether this node would be invisible even if style rule selectors within it
39-
// didn't have bogus combinators.
40-
///
41-
/// Note that this doesn't consider nodes that contain loud comments to be
42-
/// invisible even though they're omitted in compressed mode.
43-
@internal
44-
bool get isInvisibleOtherThanBogusCombinators => accept(
45-
const _IsInvisibleVisitor(includeBogus: false, includeComments: false),
46-
);
47-
4838
// Whether this node will be invisible when loud comments are stripped.
4939
@internal
5040
bool get isInvisibleHidingComments => accept(
@@ -92,8 +82,5 @@ class _IsInvisibleVisitor with EveryCssVisitor {
9282
includeComments && !comment.isPreserved;
9383

9484
bool visitCssStyleRule(CssStyleRule rule) =>
95-
(includeBogus
96-
? rule.selector.isInvisible
97-
: rule.selector.isInvisibleOtherThanBogusCombinators) ||
98-
super.visitCssStyleRule(rule);
85+
rule.selector.isInvisible || super.visitCssStyleRule(rule);
9986
}

lib/src/ast/sass/parameter_list.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import '../../utils.dart';
1212
import 'parameter.dart';
1313
import 'node.dart';
1414

15-
/// An parameter declaration, as for a function or mixin definition.
15+
/// A parameter declaration, as for a function or mixin definition.
1616
///
1717
/// {@category AST}
1818
/// {@category Parsing}

lib/src/ast/selector.dart

+3-109
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@
55
import 'package:meta/meta.dart';
66
import 'package:source_span/source_span.dart';
77

8-
import '../deprecation.dart';
9-
import '../evaluation_context.dart';
10-
import '../exception.dart';
118
import '../visitor/any_selector.dart';
129
import '../visitor/interface/selector.dart';
1310
import '../visitor/serialize.dart';
1411
import 'node.dart';
15-
import 'selector/complex.dart';
1612
import 'selector/list.dart';
1713
import 'selector/placeholder.dart';
1814
import 'selector/pseudo.dart';
@@ -47,58 +43,12 @@ abstract base class Selector implements AstNode {
4743
///
4844
/// @nodoc
4945
@internal
50-
bool get isInvisible => accept(const _IsInvisibleVisitor(includeBogus: true));
51-
52-
// Whether this selector would be invisible even if it didn't have bogus
53-
// combinators.
54-
///
55-
/// @nodoc
56-
@internal
57-
bool get isInvisibleOtherThanBogusCombinators =>
58-
accept(const _IsInvisibleVisitor(includeBogus: false));
59-
60-
/// Whether this selector is not valid CSS.
61-
///
62-
/// This includes both selectors that are useful exclusively for build-time
63-
/// nesting (`> .foo)` and selectors with invalid combiantors that are still
64-
/// supported for backwards-compatibility reasons (`.foo + ~ .bar`).
65-
bool get isBogus =>
66-
accept(const _IsBogusVisitor(includeLeadingCombinator: true));
67-
68-
/// Whether this selector is bogus other than having a leading combinator.
69-
///
70-
/// @nodoc
71-
@internal
72-
bool get isBogusOtherThanLeadingCombinator =>
73-
accept(const _IsBogusVisitor(includeLeadingCombinator: false));
74-
75-
/// Whether this is a useless selector (that is, it's bogus _and_ it can't be
76-
/// transformed into valid CSS by `@extend` or nesting).
77-
///
78-
/// @nodoc
79-
@internal
80-
bool get isUseless => accept(const _IsUselessVisitor());
46+
bool get isInvisible => accept(const _IsInvisibleVisitor());
8147

8248
final FileSpan span;
8349

8450
Selector(this.span);
8551

86-
/// Prints a warning if `this` is a bogus selector.
87-
///
88-
/// This may only be called from within a custom Sass function. This will
89-
/// throw a [SassException] in Dart Sass 2.0.0.
90-
void assertNotBogus({String? name}) {
91-
if (!isBogus) return;
92-
warnForDeprecation(
93-
(name == null ? '' : '\$$name: ') +
94-
'$this is not valid CSS.\n'
95-
'This will be an error in Dart Sass 2.0.0.\n'
96-
'\n'
97-
'More info: https://sass-lang.com/d/bogus-combinators',
98-
Deprecation.bogusCombinators,
99-
);
100-
}
101-
10252
/// Calls the appropriate visit method on [visitor].
10353
T accept<T>(SelectorVisitor<T> visitor);
10454

@@ -107,18 +57,11 @@ abstract base class Selector implements AstNode {
10757

10858
/// The visitor used to implement [Selector.isInvisible].
10959
class _IsInvisibleVisitor with AnySelectorVisitor {
110-
/// Whether to consider selectors with bogus combinators invisible.
111-
final bool includeBogus;
112-
113-
const _IsInvisibleVisitor({required this.includeBogus});
60+
const _IsInvisibleVisitor();
11461

11562
bool visitSelectorList(SelectorList list) =>
11663
list.components.every(visitComplexSelector);
11764

118-
bool visitComplexSelector(ComplexSelector complex) =>
119-
super.visitComplexSelector(complex) ||
120-
(includeBogus && complex.isBogusOtherThanLeadingCombinator);
121-
12265
bool visitPlaceholderSelector(PlaceholderSelector placeholder) => true;
12366

12467
bool visitPseudoSelector(PseudoSelector pseudo) {
@@ -127,58 +70,9 @@ class _IsInvisibleVisitor with AnySelectorVisitor {
12770
// it means "doesn't match this selector that matches nothing", so it's
12871
// equivalent to *. If the entire compound selector is composed of `:not`s
12972
// with invisible lists, the serializer emits it as `*`.
130-
return pseudo.name == 'not'
131-
? (includeBogus && selector.isBogus)
132-
: selector.accept(this);
73+
return pseudo.name != 'not' && selector.accept(this);
13374
} else {
13475
return false;
13576
}
13677
}
13778
}
138-
139-
/// The visitor used to implement [Selector.isBogus].
140-
class _IsBogusVisitor with AnySelectorVisitor {
141-
/// Whether to consider selectors with leading combinators as bogus.
142-
final bool includeLeadingCombinator;
143-
144-
const _IsBogusVisitor({required this.includeLeadingCombinator});
145-
146-
bool visitComplexSelector(ComplexSelector complex) {
147-
if (complex.components.isEmpty) {
148-
return complex.leadingCombinators.isNotEmpty;
149-
} else {
150-
return complex.leadingCombinators.length >
151-
(includeLeadingCombinator ? 0 : 1) ||
152-
complex.components.last.combinators.isNotEmpty ||
153-
complex.components.any(
154-
(component) =>
155-
component.combinators.length > 1 ||
156-
component.selector.accept(this),
157-
);
158-
}
159-
}
160-
161-
bool visitPseudoSelector(PseudoSelector pseudo) {
162-
var selector = pseudo.selector;
163-
if (selector == null) return false;
164-
165-
// The CSS spec specifically allows leading combinators in `:has()`.
166-
return pseudo.name == 'has'
167-
? selector.isBogusOtherThanLeadingCombinator
168-
: selector.isBogus;
169-
}
170-
}
171-
172-
/// The visitor used to implement [Selector.isUseless]
173-
class _IsUselessVisitor with AnySelectorVisitor {
174-
const _IsUselessVisitor();
175-
176-
bool visitComplexSelector(ComplexSelector complex) =>
177-
complex.leadingCombinators.length > 1 ||
178-
complex.components.any(
179-
(component) =>
180-
component.combinators.length > 1 || component.selector.accept(this),
181-
);
182-
183-
bool visitPseudoSelector(PseudoSelector pseudo) => pseudo.isBogus;
184-
}

0 commit comments

Comments
 (0)