Skip to content

Commit 477b596

Browse files
authored
Merge pull request #2403 from sass/parser-variable
Add sass-parser support for variable declarations and `@warn` rules
2 parents 20397ef + fd5cff0 commit 477b596

22 files changed

+1401
-22
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.80.5-dev
2+
3+
* No user-visible changes.
4+
15
## 1.80.4
26

37
* No user-visible changes.

lib/src/ast/sass/statement/stylesheet.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ final class Stylesheet extends ParentStatement<List<Statement>> {
5353
@internal
5454
final List<ParseTimeWarning> parseTimeWarnings;
5555

56+
/// The set of (normalized) global variable names defined by this stylesheet
57+
/// to the spans where they're defined.
58+
@internal
59+
final Map<String, FileSpan> globalVariables;
60+
5661
Stylesheet(Iterable<Statement> children, FileSpan span)
5762
: this.internal(children, span, []);
5863

@@ -62,8 +67,11 @@ final class Stylesheet extends ParentStatement<List<Statement>> {
6267
@internal
6368
Stylesheet.internal(Iterable<Statement> children, this.span,
6469
List<ParseTimeWarning> parseTimeWarnings,
65-
{this.plainCss = false})
70+
{this.plainCss = false, Map<String, FileSpan>? globalVariables})
6671
: parseTimeWarnings = UnmodifiableListView(parseTimeWarnings),
72+
globalVariables = globalVariables == null
73+
? const {}
74+
: Map.unmodifiable(globalVariables),
6775
super(List.unmodifiable(children)) {
6876
loop:
6977
for (var child in this.children) {

lib/src/parse/stylesheet.dart

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ abstract class StylesheetParser extends Parser {
6161
var _inExpression = false;
6262

6363
/// A map from all variable names that are assigned with `!global` in the
64-
/// current stylesheet to the nodes where they're defined.
64+
/// current stylesheet to the spans where they're defined.
6565
///
6666
/// These are collected at parse time because they affect the variables
6767
/// exposed by the module generated for this stylesheet, *even if they aren't
6868
/// evaluated*. This allows us to ensure that the stylesheet always exposes
6969
/// the same set of variable names no matter how it's evaluated.
70-
final _globalVariables = <String, VariableDeclaration>{};
70+
final _globalVariables = <String, FileSpan>{};
7171

7272
/// Warnings discovered while parsing that should be emitted during
7373
/// evaluation once a proper logger is available.
@@ -100,15 +100,8 @@ abstract class StylesheetParser extends Parser {
100100
});
101101
scanner.expectDone();
102102

103-
/// Ensure that all global variable assignments produce a variable in this
104-
/// stylesheet, even if they aren't evaluated. See sass/language#50.
105-
statements.addAll(_globalVariables.values.map((declaration) =>
106-
VariableDeclaration(declaration.name,
107-
NullExpression(declaration.expression.span), declaration.span,
108-
guarded: true)));
109-
110103
return Stylesheet.internal(statements, scanner.spanFrom(start), warnings,
111-
plainCss: plainCss);
104+
plainCss: plainCss, globalVariables: _globalVariables);
112105
});
113106
}
114107

@@ -288,7 +281,7 @@ abstract class StylesheetParser extends Parser {
288281
guarded: guarded,
289282
global: global,
290283
comment: precedingComment);
291-
if (global) _globalVariables.putIfAbsent(name, () => declaration);
284+
if (global) _globalVariables.putIfAbsent(name, () => declaration.span);
292285
return declaration;
293286
}
294287

lib/src/visitor/async_evaluate.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,14 @@ final class _EvaluateVisitor
10051005
for (var child in node.children) {
10061006
await child.accept(this);
10071007
}
1008+
1009+
// Make sure all global variables declared in a module always appear in the
1010+
// module's definition, even if their assignments aren't reached.
1011+
for (var (name, span) in node.globalVariables.pairs) {
1012+
visitVariableDeclaration(
1013+
VariableDeclaration(name, NullExpression(span), span, guarded: true));
1014+
}
1015+
10081016
return null;
10091017
}
10101018

lib/src/visitor/evaluate.dart

Lines changed: 9 additions & 1 deletion
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: e7260fedcd4f374ba517a93d038c3c53586c9622
8+
// Checksum: 396c8f169d95c601598b8c3be1f4b948ca22effa
99
//
1010
// ignore_for_file: unused_import
1111

@@ -1005,6 +1005,14 @@ final class _EvaluateVisitor
10051005
for (var child in node.children) {
10061006
child.accept(this);
10071007
}
1008+
1009+
// Make sure all global variables declared in a module always appear in the
1010+
// module's definition, even if their assignments aren't reached.
1011+
for (var (name, span) in node.globalVariables.pairs) {
1012+
visitVariableDeclaration(
1013+
VariableDeclaration(name, NullExpression(span), span, guarded: true));
1014+
}
1015+
10081016
return null;
10091017
}
10101018

pkg/sass-parser/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.4.2-dev
2+
3+
* Add support for parsing variable declarations.
4+
5+
* Add support for parsing the `@warn` rule.
6+
17
## 0.4.1
28

39
* Add `BooleanExpression` and `NumberExpression`.

pkg/sass-parser/lib/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ export {
9696
StatementType,
9797
StatementWithChildren,
9898
} from './src/statement';
99+
export {
100+
VariableDeclaration,
101+
VariableDeclarationProps,
102+
VariableDeclarationRaws,
103+
} from './src/statement/variable-declaration';
104+
export {WarnRule, WarnRuleProps, WarnRuleRaws} from './src/statement/warn-rule';
99105

100106
/** Options that can be passed to the Sass parsers to control their behavior. */
101107
export type SassParserOptions = Pick<postcss.ProcessOptions, 'from' | 'map'>;

pkg/sass-parser/lib/src/sass-internal.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,18 @@ declare namespace SassInternal {
180180
readonly configuration: ConfiguredVariable[];
181181
}
182182

183+
class VariableDeclaration extends Statement {
184+
readonly namespace: string | null;
185+
readonly name: string;
186+
readonly expression: Expression;
187+
readonly isGuarded: boolean;
188+
readonly isGlobal: boolean;
189+
}
190+
191+
class WarnRule extends Statement {
192+
readonly expression: Expression;
193+
}
194+
183195
class ConfiguredVariable extends SassNode {
184196
readonly name: string;
185197
readonly expression: Expression;
@@ -238,6 +250,8 @@ export type Stylesheet = SassInternal.Stylesheet;
238250
export type StyleRule = SassInternal.StyleRule;
239251
export type SupportsRule = SassInternal.SupportsRule;
240252
export type UseRule = SassInternal.UseRule;
253+
export type VariableDeclaration = SassInternal.VariableDeclaration;
254+
export type WarnRule = SassInternal.WarnRule;
241255
export type ConfiguredVariable = SassInternal.ConfiguredVariable;
242256
export type Interpolation = SassInternal.Interpolation;
243257
export type Expression = SassInternal.Expression;
@@ -260,6 +274,8 @@ export interface StatementVisitorObject<T> {
260274
visitStyleRule(node: StyleRule): T;
261275
visitSupportsRule(node: SupportsRule): T;
262276
visitUseRule(node: UseRule): T;
277+
visitVariableDeclaration(node: VariableDeclaration): T;
278+
visitWarnRule(node: WarnRule): T;
263279
}
264280

265281
export interface ExpressionVisitorObject<T> {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`a variable declaration toJSON 1`] = `
4+
{
5+
"expression": <"bar">,
6+
"global": false,
7+
"guarded": false,
8+
"inputs": [
9+
{
10+
"css": "baz.$foo: "bar"",
11+
"hasBOM": false,
12+
"id": "<input css _____>",
13+
},
14+
],
15+
"namespace": "baz",
16+
"raws": {},
17+
"sassType": "variable-declaration",
18+
"source": <1:1-1:16 in 0>,
19+
"type": "decl",
20+
"variableName": "foo",
21+
}
22+
`;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`a @warn rule toJSON 1`] = `
4+
{
5+
"inputs": [
6+
{
7+
"css": "@warn foo",
8+
"hasBOM": false,
9+
"id": "<input css _____>",
10+
},
11+
],
12+
"name": "warn",
13+
"params": "foo",
14+
"raws": {},
15+
"sassType": "warn-rule",
16+
"source": <1:1-1:10 in 0>,
17+
"type": "atrule",
18+
"warnExpression": <foo>,
19+
}
20+
`;

0 commit comments

Comments
 (0)