Skip to content

Commit e6589fe

Browse files
authored
Add support for parsing variable expressions (#2541)
1 parent 2680d5f commit e6589fe

13 files changed

+472
-19
lines changed

pkg/sass-parser/CHANGELOG.md

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

1515
* Add support for parsing unary operation expressions.
1616

17+
* Add support for parsing variable expressions.
18+
1719
## 0.4.15
1820

1921
* Add support for parsing list expressions.

pkg/sass-parser/lib/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ export {
253253
UnaryOperationExpressionProps,
254254
UnaryOperationExpressionRaws,
255255
} from './src/expression/unary-operation';
256+
export {
257+
VariableExpression,
258+
VariableExpressionProps,
259+
VariableExpressionRaws,
260+
} from './src/expression/variable';
256261

257262
/** Options that can be passed to the Sass parsers to control their behavior. */
258263
export type SassParserOptions = Pick<postcss.ProcessOptions, 'from' | 'map'>;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`a variable expression toJSON with a namespace 1`] = `
4+
{
5+
"inputs": [
6+
{
7+
"css": "@#{bar.$foo}",
8+
"hasBOM": false,
9+
"id": "<input css _____>",
10+
},
11+
],
12+
"namespace": "bar",
13+
"raws": {},
14+
"sassType": "variable",
15+
"source": <1:4-1:12 in 0>,
16+
"variableName": "foo",
17+
}
18+
`;
19+
20+
exports[`a variable expression toJSON without a namespace 1`] = `
21+
{
22+
"inputs": [
23+
{
24+
"css": "@#{$foo}",
25+
"hasBOM": false,
26+
"id": "<input css _____>",
27+
},
28+
],
29+
"raws": {},
30+
"sassType": "variable",
31+
"source": <1:4-1:8 in 0>,
32+
"variableName": "foo",
33+
}
34+
`;

pkg/sass-parser/lib/src/expression/convert.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {ParenthesizedExpression} from './parenthesized';
2121
import {SelectorExpression} from './selector';
2222
import {StringExpression} from './string';
2323
import {UnaryOperationExpression} from './unary-operation';
24+
import {VariableExpression} from './variable';
2425

2526
/** The visitor to use to convert internal Sass nodes to JS. */
2627
const visitor = sassInternal.createExpressionVisitor<AnyExpression>({
@@ -55,6 +56,7 @@ const visitor = sassInternal.createExpressionVisitor<AnyExpression>({
5556
}),
5657
visitUnaryOperationExpression: inner =>
5758
new UnaryOperationExpression(undefined, inner),
59+
visitVariableExpression: inner => new VariableExpression(undefined, inner),
5860
});
5961

6062
/** Converts an internal expression AST node into an external one. */

pkg/sass-parser/lib/src/expression/from-props.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {NumberExpression} from './number';
1616
import {ParenthesizedExpression} from './parenthesized';
1717
import {StringExpression} from './string';
1818
import {UnaryOperationExpression} from './unary-operation';
19+
import {VariableExpression} from './variable';
1920

2021
/** Constructs an expression from {@link ExpressionProps}. */
2122
export function fromProps(props: ExpressionProps): AnyExpression {
@@ -25,6 +26,7 @@ export function fromProps(props: ExpressionProps): AnyExpression {
2526
if ('separator' in props) return new ListExpression(props);
2627
if ('nodes' in props) return new MapExpression(props);
2728
if ('inParens' in props) return new ParenthesizedExpression(props);
29+
if ('variableName' in props) return new VariableExpression(props);
2830
if ('name' in props) {
2931
if (typeof props.name === 'string') {
3032
return new FunctionExpression(props as FunctionExpressionProps);

pkg/sass-parser/lib/src/expression/function.test.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,35 @@ describe('a function expression', () => {
162162
}).toString(),
163163
).toBe('foo(bar)'));
164164

165-
it('with a namespace', () =>
166-
expect(
167-
new FunctionExpression({
168-
namespace: 'baz',
169-
name: 'foo',
170-
arguments: [{text: 'bar'}],
171-
}).toString(),
172-
).toBe('baz.foo(bar)'));
165+
describe('with a namespace', () => {
166+
it("that's an identifier", () =>
167+
expect(
168+
new FunctionExpression({
169+
namespace: 'baz',
170+
name: 'foo',
171+
arguments: [{text: 'bar'}],
172+
}).toString(),
173+
).toBe('baz.foo(bar)'));
174+
175+
it("that's not an identifier", () =>
176+
expect(
177+
new FunctionExpression({
178+
namespace: 'b z',
179+
name: 'foo',
180+
arguments: [{text: 'bar'}],
181+
}).toString(),
182+
).toBe('b\\20z.foo(bar)'));
183+
});
173184
});
174185

186+
it("with a name that's not an identifier", () =>
187+
expect(
188+
new FunctionExpression({
189+
name: 'f o',
190+
arguments: [{text: 'bar'}],
191+
}).toString(),
192+
).toBe('f\\20o(bar)'));
193+
175194
it('with matching namespace', () =>
176195
expect(
177196
new FunctionExpression({

pkg/sass-parser/lib/src/expression/function.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {ArgumentList, ArgumentListProps} from '../argument-list';
88
import {LazySource} from '../lazy-source';
99
import {NodeProps} from '../node';
1010
import {RawWithValue} from '../raw-with-value';
11-
import type * as sassInternal from '../sass-internal';
11+
import * as sassInternal from '../sass-internal';
1212
import * as utils from '../utils';
1313
import {Expression} from '.';
1414

@@ -34,7 +34,7 @@ export interface FunctionExpressionRaws {
3434
* The function's namespace.
3535
*
3636
* This may be different than {@link FunctionExpression.namespace} if the
37-
* namespace contains escape codes or underscores.
37+
* namespace contains escape codes.
3838
*/
3939
namespace?: RawWithValue<string>;
4040

@@ -59,8 +59,8 @@ export class FunctionExpression extends Expression {
5959
/**
6060
* This function's namespace.
6161
*
62-
* This is the parsed and normalized value, with underscores converted to
63-
* hyphens and escapes resolved to the characters they represent.
62+
* This is the parsed and normalized value, with escapes resolved to the
63+
* characters they represent.
6464
*/
6565
get namespace(): string | undefined {
6666
return this._namespace;
@@ -136,9 +136,11 @@ export class FunctionExpression extends Expression {
136136
(this.namespace
137137
? (this.raws.namespace?.value === this.namespace
138138
? this.raws.namespace.raw
139-
: this.namespace) + '.'
139+
: sassInternal.toCssIdentifier(this.namespace)) + '.'
140140
: '') +
141-
(this.raws.name?.value === this.name ? this.raws.name.raw : this.name) +
141+
(this.raws.name?.value === this.name
142+
? this.raws.name.raw
143+
: sassInternal.toCssIdentifier(this.name)) +
142144
this.arguments
143145
);
144146
}

pkg/sass-parser/lib/src/expression/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
UnaryOperationExpression,
2929
UnaryOperationExpressionProps,
3030
} from './unary-operation';
31+
import type {VariableExpression, VariableExpressionProps} from './variable';
3132

3233
/**
3334
* The union type of all Sass expressions.
@@ -47,7 +48,8 @@ export type AnyExpression =
4748
| ParenthesizedExpression
4849
| SelectorExpression
4950
| StringExpression
50-
| UnaryOperationExpression;
51+
| UnaryOperationExpression
52+
| VariableExpression;
5153

5254
/**
5355
* Sass expression types.
@@ -67,7 +69,8 @@ export type ExpressionType =
6769
| 'parenthesized'
6870
| 'selector-expr'
6971
| 'string'
70-
| 'unary-operation';
72+
| 'unary-operation'
73+
| 'variable';
7174

7275
/**
7376
* The union type of all properties that can be used to construct Sass
@@ -87,7 +90,8 @@ export type ExpressionProps =
8790
| NumberExpressionProps
8891
| ParenthesizedExpressionProps
8992
| StringExpressionProps
90-
| UnaryOperationExpressionProps;
93+
| UnaryOperationExpressionProps
94+
| VariableExpressionProps;
9195

9296
/**
9397
* The superclass of Sass expression nodes.

0 commit comments

Comments
 (0)