Skip to content

Commit 9417b6e

Browse files
authored
Track original source spans for selectors (#1903)
Closes #1783
1 parent 434f2b9 commit 9417b6e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1187
-756
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
* Improve error messages for invalid CSS values passed to plain CSS functions.
77

8+
* Improve error messages involving selectors.
9+
810
### Embedded Sass
911

1012
* Improve the performance of starting up a compilation.

lib/src/ast/css/media_query.dart

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

5+
import '../../interpolation_map.dart';
56
import '../../logger.dart';
67
import '../../parse/media_query.dart';
78
import '../../utils.dart';
@@ -43,8 +44,10 @@ class CssMediaQuery {
4344
///
4445
/// Throws a [SassFormatException] if parsing fails.
4546
static List<CssMediaQuery> parseList(String contents,
46-
{Object? url, Logger? logger}) =>
47-
MediaQueryParser(contents, url: url, logger: logger).parse();
47+
{Object? url, Logger? logger, InterpolationMap? interpolationMap}) =>
48+
MediaQueryParser(contents,
49+
url: url, logger: logger, interpolationMap: interpolationMap)
50+
.parse();
4851

4952
/// Creates a media query specifies a type and, optionally, conditions.
5053
///

lib/src/ast/css/modifiable.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,3 @@ export 'modifiable/node.dart';
1212
export 'modifiable/style_rule.dart';
1313
export 'modifiable/stylesheet.dart';
1414
export 'modifiable/supports_rule.dart';
15-
export 'modifiable/value.dart';

lib/src/ast/css/modifiable/style_rule.dart

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,35 @@
44

55
import 'package:source_span/source_span.dart';
66

7+
import '../../../util/box.dart';
78
import '../../../visitor/interface/modifiable_css.dart';
89
import '../../selector.dart';
910
import '../style_rule.dart';
1011
import 'node.dart';
11-
import 'value.dart';
1212

1313
/// A modifiable version of [CssStyleRule] for use in the evaluation step.
1414
class ModifiableCssStyleRule extends ModifiableCssParentNode
1515
implements CssStyleRule {
16-
final ModifiableCssValue<SelectorList> selector;
16+
SelectorList get selector => _selector.value;
17+
18+
/// A reference to the modifiable selector list provided by the extension
19+
/// store, which may update it over time as new extensions are applied.
20+
final Box<SelectorList> _selector;
21+
1722
final SelectorList originalSelector;
1823
final FileSpan span;
1924

2025
/// Creates a new [ModifiableCssStyleRule].
2126
///
22-
/// If [originalSelector] isn't passed, it defaults to [selector.value].
23-
ModifiableCssStyleRule(this.selector, this.span,
27+
/// If [originalSelector] isn't passed, it defaults to [_selector.value].
28+
ModifiableCssStyleRule(this._selector, this.span,
2429
{SelectorList? originalSelector})
25-
: originalSelector = originalSelector ?? selector.value;
30+
: originalSelector = originalSelector ?? _selector.value;
2631

2732
T accept<T>(ModifiableCssVisitor<T> visitor) =>
2833
visitor.visitCssStyleRule(this);
2934

3035
ModifiableCssStyleRule copyWithoutChildren() =>
31-
ModifiableCssStyleRule(selector, span,
36+
ModifiableCssStyleRule(_selector, span,
3237
originalSelector: originalSelector);
3338
}

lib/src/ast/css/modifiable/value.dart

Lines changed: 0 additions & 17 deletions
This file was deleted.

lib/src/ast/css/node.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class _IsInvisibleVisitor with EveryCssVisitor {
8282

8383
bool visitCssStyleRule(CssStyleRule rule) =>
8484
(includeBogus
85-
? rule.selector.value.isInvisible
86-
: rule.selector.value.isInvisibleOtherThanBogusCombinators) ||
85+
? rule.selector.isInvisible
86+
: rule.selector.isInvisibleOtherThanBogusCombinators) ||
8787
super.visitCssStyleRule(rule);
8888
}

lib/src/ast/css/style_rule.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import '../../visitor/interface/css.dart';
66
import '../selector.dart';
77
import 'node.dart';
8-
import 'value.dart';
98

109
/// A plain CSS style rule.
1110
///
@@ -14,7 +13,7 @@ import 'value.dart';
1413
/// contain placeholder selectors.
1514
abstract class CssStyleRule extends CssParentNode {
1615
/// The selector for this rule.
17-
CssValue<SelectorList> get selector;
16+
SelectorList get selector;
1817

1918
/// The selector for this rule, before any extensions were applied.
2019
SelectorList get originalSelector;

lib/src/ast/css/value.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import '../node.dart';
99
/// A value in a plain CSS tree.
1010
///
1111
/// This is used to associate a span with a value that doesn't otherwise track
12-
/// its span.
12+
/// its span. It has value equality semantics.
1313
class CssValue<T extends Object> implements AstNode {
1414
/// The value.
1515
final T value;
@@ -19,5 +19,10 @@ class CssValue<T extends Object> implements AstNode {
1919

2020
CssValue(this.value, this.span);
2121

22+
bool operator ==(Object other) =>
23+
other is CssValue<T> && other.value == value;
24+
25+
int get hashCode => value.hashCode;
26+
2227
String toString() => value.toString();
2328
}

lib/src/ast/sass/at_root_query.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:meta/meta.dart';
66
import 'package:collection/collection.dart';
77

88
import '../../exception.dart';
9+
import '../../interpolation_map.dart';
910
import '../../logger.dart';
1011
import '../../parse/at_root_query.dart';
1112
import '../css.dart';
@@ -53,8 +54,12 @@ class AtRootQuery {
5354
///
5455
/// If passed, [url] is the name of the file from which [contents] comes.
5556
///
57+
/// If passed, [interpolationMap] maps the text of [contents] back to the
58+
/// original location of the selector in the source file.
59+
///
5660
/// Throws a [SassFormatException] if parsing fails.
57-
factory AtRootQuery.parse(String contents, {Object? url, Logger? logger}) =>
61+
factory AtRootQuery.parse(String contents,
62+
{Object? url, Logger? logger, InterpolationMap? interpolationMap}) =>
5863
AtRootQueryParser(contents, url: url, logger: logger).parse();
5964

6065
/// Returns whether [this] excludes [node].

lib/src/ast/selector.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
// https://opensource.org/licenses/MIT.
44

55
import 'package:meta/meta.dart';
6+
import 'package:source_span/source_span.dart';
67

78
import '../evaluation_context.dart';
89
import '../exception.dart';
910
import '../visitor/any_selector.dart';
1011
import '../visitor/interface/selector.dart';
1112
import '../visitor/serialize.dart';
13+
import 'node.dart';
1214
import 'selector/complex.dart';
1315
import 'selector/list.dart';
1416
import 'selector/placeholder.dart';
@@ -38,7 +40,7 @@ export 'selector/universal.dart';
3840
/// Selectors have structural equality semantics.
3941
///
4042
/// {@category AST}
41-
abstract class Selector {
43+
abstract class Selector implements AstNode {
4244
/// Whether this selector, and complex selectors containing it, should not be
4345
/// emitted.
4446
///
@@ -76,10 +78,14 @@ abstract class Selector {
7678
@internal
7779
bool get isUseless => accept(const _IsUselessVisitor());
7880

81+
final FileSpan span;
82+
83+
Selector(this.span);
84+
7985
/// Prints a warning if [this] is a bogus selector.
8086
///
8187
/// This may only be called from within a custom Sass function. This will
82-
/// throw a [SassScriptException] in Dart Sass 2.0.0.
88+
/// throw a [SassException] in Dart Sass 2.0.0.
8389
void assertNotBogus({String? name}) {
8490
if (!isBogus) return;
8591
warn(

0 commit comments

Comments
 (0)