Skip to content

Commit fd4c50c

Browse files
authored
Expose selector APIs through sass_api (#1741)
1 parent f611b06 commit fd4c50c

22 files changed

+310
-82
lines changed

Diff for: lib/sass.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export 'src/exception.dart' show SassException;
2626
export 'src/importer.dart';
2727
export 'src/logger.dart';
2828
export 'src/syntax.dart';
29-
export 'src/value.dart' hide ColorFormat, SassApiColor, SpanColorFormat;
29+
export 'src/value.dart' hide ColorFormat, SassApiColor, SassApiValue, SpanColorFormat;
3030
export 'src/visitor/serialize.dart' show OutputStyle;
3131
export 'src/evaluation_context.dart' show warn;
3232

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

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
44

5+
import 'package:meta/meta.dart';
6+
57
import '../visitor/interface/selector.dart';
68
import '../visitor/serialize.dart';
79

@@ -25,9 +27,12 @@ export 'selector/universal.dart';
2527
/// [ParentSelector] or a [PlaceholderSelector].
2628
///
2729
/// Selectors have structural equality semantics.
30+
///
31+
/// {@category Selector}
2832
abstract class Selector {
2933
/// Whether this selector, and complex selectors containing it, should not be
3034
/// emitted.
35+
@internal
3136
bool get isInvisible => false;
3237

3338
/// Calls the appropriate visit method on [visitor].

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

+5
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
44

5+
import 'package:meta/meta.dart';
6+
57
import '../../visitor/interface/selector.dart';
68
import '../selector.dart';
79

810
/// An attribute selector.
911
///
1012
/// This selects for elements with the given attribute, and optionally with a
1113
/// value matching certain conditions as well.
14+
///
15+
/// {@category Selector}
16+
@sealed
1217
class AttributeSelector extends SimpleSelector {
1318
/// The name of the attribute being selected for.
1419
final QualifiedName name;

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

+7
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
44

5+
import 'package:meta/meta.dart';
6+
57
import '../../visitor/interface/selector.dart';
68
import '../selector.dart';
79

810
/// A class selector.
911
///
1012
/// This selects elements whose `class` attribute contains an identifier with
1113
/// the given name.
14+
///
15+
/// {@category Selector}
16+
@sealed
1217
class ClassSelector extends SimpleSelector {
1318
/// The class name this selects for.
1419
final String name;
@@ -20,6 +25,8 @@ class ClassSelector extends SimpleSelector {
2025

2126
T accept<T>(SelectorVisitor<T> visitor) => visitor.visitClassSelector(this);
2227

28+
/// @nodoc
29+
@internal
2330
ClassSelector addSuffix(String suffix) => ClassSelector(name + suffix);
2431

2532
int get hashCode => name.hashCode;

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

+30
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
44

5+
import 'package:meta/meta.dart';
6+
57
import '../../extend/functions.dart';
8+
import '../../logger.dart';
9+
import '../../parse/selector.dart';
610
import '../../utils.dart';
711
import '../../visitor/interface/selector.dart';
812
import '../selector.dart';
@@ -11,6 +15,9 @@ import '../selector.dart';
1115
///
1216
/// A complex selector is composed of [CompoundSelector]s separated by
1317
/// [Combinator]s. It selects elements based on their parent selectors.
18+
///
19+
/// {@category Selector}
20+
@sealed
1421
class ComplexSelector extends Selector {
1522
/// The components of this selector.
1623
///
@@ -25,6 +32,9 @@ class ComplexSelector extends Selector {
2532
final List<ComplexSelectorComponent> components;
2633

2734
/// Whether a line break should be emitted *before* this selector.
35+
///
36+
/// @nodoc
37+
@internal
2838
final bool lineBreak;
2939

3040
/// The minimum possible specificity that this selector can have.
@@ -49,6 +59,8 @@ class ComplexSelector extends Selector {
4959

5060
int? _maxSpecificity;
5161

62+
/// @nodoc
63+
@internal
5264
late final bool isInvisible = components.any(
5365
(component) => component is CompoundSelector && component.isInvisible);
5466

@@ -60,6 +72,19 @@ class ComplexSelector extends Selector {
6072
}
6173
}
6274

75+
/// Parses a complex selector from [contents].
76+
///
77+
/// If passed, [url] is the name of the file from which [contents] comes.
78+
/// [allowParent] controls whether a [ParentSelector] is allowed in this
79+
/// selector.
80+
///
81+
/// Throws a [SassFormatException] if parsing fails.
82+
factory ComplexSelector.parse(String contents,
83+
{Object? url, Logger? logger, bool allowParent = true}) =>
84+
SelectorParser(contents,
85+
url: url, logger: logger, allowParent: allowParent)
86+
.parseComplexSelector();
87+
6388
T accept<T>(SelectorVisitor<T> visitor) => visitor.visitComplexSelector(this);
6489

6590
/// Whether this is a superselector of [other].
@@ -92,10 +117,15 @@ class ComplexSelector extends Selector {
92117
/// A component of a [ComplexSelector].
93118
///
94119
/// This is either a [CompoundSelector] or a [Combinator].
120+
///
121+
/// {@category Selector}
95122
abstract class ComplexSelectorComponent {}
96123

97124
/// A combinator that defines the relationship between selectors in a
98125
/// [ComplexSelector].
126+
///
127+
/// {@category Selector}
128+
@sealed
99129
class Combinator implements ComplexSelectorComponent {
100130
/// Matches the right-hand selector if it's immediately adjacent to the
101131
/// left-hand selector in the DOM tree.

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

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
44

5+
import 'package:meta/meta.dart';
6+
57
import '../../extend/functions.dart';
68
import '../../logger.dart';
79
import '../../parse/selector.dart';
@@ -13,6 +15,9 @@ import '../selector.dart';
1315
///
1416
/// A compound selector is composed of [SimpleSelector]s. It matches an element
1517
/// that matches all of the component simple selectors.
18+
///
19+
/// {@category Selector}
20+
@sealed
1621
class CompoundSelector extends Selector implements ComplexSelectorComponent {
1722
/// The components of this selector.
1823
///
@@ -41,6 +46,8 @@ class CompoundSelector extends Selector implements ComplexSelectorComponent {
4146

4247
int? _maxSpecificity;
4348

49+
/// @nodoc
50+
@internal
4451
bool get isInvisible => components.any((component) => component.isInvisible);
4552

4653
CompoundSelector(Iterable<SimpleSelector> components)

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

+9
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@
44

55
import 'dart:math' as math;
66

7+
import 'package:meta/meta.dart';
8+
79
import '../../visitor/interface/selector.dart';
810
import '../selector.dart';
911

1012
/// An ID selector.
1113
///
1214
/// This selects elements whose `id` attribute exactly matches the given name.
15+
///
16+
/// {@category Selector}
17+
@sealed
1318
class IDSelector extends SimpleSelector {
1419
/// The ID name this selects for.
1520
final String name;
@@ -20,8 +25,12 @@ class IDSelector extends SimpleSelector {
2025

2126
T accept<T>(SelectorVisitor<T> visitor) => visitor.visitIDSelector(this);
2227

28+
/// @nodoc
29+
@internal
2330
IDSelector addSuffix(String suffix) => IDSelector(name + suffix);
2431

32+
/// @nodoc
33+
@internal
2534
List<SimpleSelector>? unify(List<SimpleSelector> compound) {
2635
// A given compound selector may only contain one ID.
2736
if (compound.any((simple) => simple is IDSelector && simple != this)) {

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
44

5+
import 'package:meta/meta.dart';
6+
57
import '../../extend/functions.dart';
68
import '../../logger.dart';
79
import '../../parse/selector.dart';
@@ -13,8 +15,11 @@ import '../selector.dart';
1315

1416
/// A selector list.
1517
///
16-
/// A selector list is composed of [ComplexSelector]s. It matches an element
18+
/// A selector list is composed of [ComplexSelector]s. It matches any element
1719
/// that matches any of the component selectors.
20+
///
21+
/// {@category Selector}
22+
@sealed
1823
class SelectorList extends Selector {
1924
/// The components of this selector.
2025
///
@@ -25,6 +30,8 @@ class SelectorList extends Selector {
2530
bool get _containsParentSelector =>
2631
components.any(_complexContainsParentSelector);
2732

33+
/// @nodoc
34+
@internal
2835
bool get isInvisible => components.every((complex) => complex.isInvisible);
2936

3037
/// Returns a SassScript list that represents this selector.

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

+7
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
44

5+
import 'package:meta/meta.dart';
6+
57
import '../../visitor/interface/selector.dart';
68
import '../selector.dart';
79

810
/// A selector that matches the parent in the Sass stylesheet.
911
///
1012
/// This is not a plain CSS selector—it should be removed before emitting a CSS
1113
/// document.
14+
///
15+
/// {@category Selector}
16+
@sealed
1217
class ParentSelector extends SimpleSelector {
1318
/// The suffix that will be added to the parent selector after it's been
1419
/// resolved.
@@ -21,6 +26,8 @@ class ParentSelector extends SimpleSelector {
2126

2227
T accept<T>(SelectorVisitor<T> visitor) => visitor.visitParentSelector(this);
2328

29+
/// @nodoc
30+
@internal
2431
List<SimpleSelector> unify(List<SimpleSelector> compound) =>
2532
throw UnsupportedError("& doesn't support unification.");
2633
}

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

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
44

5+
import 'package:meta/meta.dart';
6+
57
import '../../util/character.dart' as character;
68
import '../../visitor/interface/selector.dart';
79
import '../selector.dart';
@@ -11,10 +13,15 @@ import '../selector.dart';
1113
/// This doesn't match any elements. It's intended to be extended using
1214
/// `@extend`. It's not a plain CSS selector—it should be removed before
1315
/// emitting a CSS document.
16+
///
17+
/// {@category Selector}
18+
@sealed
1419
class PlaceholderSelector extends SimpleSelector {
1520
/// The name of the placeholder.
1621
final String name;
1722

23+
/// @nodoc
24+
@internal
1825
bool get isInvisible => true;
1926

2027
/// Returns whether this is a private selector (that is, whether it begins
@@ -26,6 +33,8 @@ class PlaceholderSelector extends SimpleSelector {
2633
T accept<T>(SelectorVisitor<T> visitor) =>
2734
visitor.visitPlaceholderSelector(this);
2835

36+
/// @nodoc
37+
@internal
2938
PlaceholderSelector addSuffix(String suffix) =>
3039
PlaceholderSelector(name + suffix);
3140

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

+16
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,17 @@ import '../selector.dart';
1717
/// selectors take arguments, including other selectors. Sass manually encodes
1818
/// logic for each pseudo selector that takes a selector as an argument, to
1919
/// ensure that extension and other selector operations work properly.
20+
///
21+
/// {@category Selector}
22+
@sealed
2023
class PseudoSelector extends SimpleSelector {
2124
/// The name of this selector.
2225
final String name;
2326

2427
/// Like [name], but without any vendor prefixes.
28+
///
29+
/// @nodoc
30+
@internal
2531
final String normalizedName;
2632

2733
/// Whether this is a pseudo-class selector.
@@ -49,10 +55,14 @@ class PseudoSelector extends SimpleSelector {
4955
bool get isSyntacticElement => !isSyntacticClass;
5056

5157
/// Whether this is a valid `:host` selector.
58+
///
59+
/// @nodoc
5260
@internal
5361
bool get isHost => isClass && name == 'host';
5462

5563
/// Whether this is a valid `:host-context` selector.
64+
///
65+
/// @nodoc
5666
@internal
5767
bool get isHostContext =>
5868
isClass && name == 'host-context' && selector != null;
@@ -83,6 +93,8 @@ class PseudoSelector extends SimpleSelector {
8393

8494
int? _maxSpecificity;
8595

96+
/// @nodoc
97+
@internal
8698
bool get isInvisible {
8799
var selector = this.selector;
88100
if (selector == null) return false;
@@ -128,11 +140,15 @@ class PseudoSelector extends SimpleSelector {
128140
PseudoSelector withSelector(SelectorList selector) => PseudoSelector(name,
129141
element: isElement, argument: argument, selector: selector);
130142

143+
/// @nodoc
144+
@internal
131145
PseudoSelector addSuffix(String suffix) {
132146
if (argument != null || selector != null) super.addSuffix(suffix);
133147
return PseudoSelector(name + suffix, element: isElement);
134148
}
135149

150+
/// @nodoc
151+
@internal
136152
List<SimpleSelector>? unify(List<SimpleSelector> compound) {
137153
if (name == 'host' || name == 'host-context') {
138154
if (!compound.every((simple) =>

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
44

5-
/// A [qualified name][].
5+
import 'package:meta/meta.dart';
6+
7+
/// A [qualified name].
68
///
79
/// [qualified name]: https://www.w3.org/TR/css3-namespace/#css-qnames
10+
///
11+
/// {@category Selector}
12+
@sealed
813
class QualifiedName {
914
/// The identifier name.
1015
final String name;

0 commit comments

Comments
 (0)