Skip to content

Commit 1536dc0

Browse files
authored
Merge pull request #2453 from sass/return
Add sass-parser support for `@return` and `@mixin`
2 parents a74f9c3 + 0918ade commit 1536dc0

26 files changed

+1135
-220
lines changed

CHANGELOG.md

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

37
### Command-Line Interface

lib/src/js/parser.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ void _updateAstPrototypes() {
9393
.defineGetter('arguments', (ArgumentDeclaration self) => self.arguments);
9494
var function = FunctionRule('a', arguments, [], bogusSpan);
9595
getJSClass(function)
96-
.defineGetter('arguments', (FunctionRule self) => self.arguments);
96+
.superclass
97+
.defineGetter('arguments', (CallableDeclaration self) => self.arguments);
9798

9899
_addSupportsConditionToInterpolation();
99100

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.8-dev
2+
3+
Add support for parsing the `@mixin` rule.
4+
5+
Add support for parsing the `@return` rule.
6+
17
## 0.4.7
28

39
* No user-visible changes.

pkg/sass-parser/lib/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ export {
104104
GenericAtRuleProps,
105105
GenericAtRuleRaws,
106106
} from './src/statement/generic-at-rule';
107+
export {
108+
MixinRule,
109+
MixinRuleProps,
110+
MixinRuleRaws,
111+
} from './src/statement/mixin-rule';
112+
export {
113+
ReturnRule,
114+
ReturnRuleProps,
115+
ReturnRuleRaws,
116+
} from './src/statement/return-rule';
107117
export {Root, RootProps, RootRaws} from './src/statement/root';
108118
export {Rule, RuleProps, RuleRaws} from './src/statement/rule';
109119
export {

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

Lines changed: 13 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -25,41 +25,14 @@ describe('a string expression', () => {
2525

2626
describeNode('parsed', () => utils.parseExpression('"foo"'));
2727

28-
describe('constructed manually', () => {
29-
describeNode(
30-
'with explicit text',
31-
() =>
32-
new StringExpression({
33-
quotes: true,
34-
text: new Interpolation({nodes: ['foo']}),
35-
}),
36-
);
37-
38-
describeNode(
39-
'with string text',
40-
() =>
41-
new StringExpression({
42-
quotes: true,
43-
text: 'foo',
44-
}),
45-
);
46-
});
47-
48-
describe('constructed from ExpressionProps', () => {
49-
describeNode('with explicit text', () =>
50-
utils.fromExpressionProps({
51-
quotes: true,
52-
text: new Interpolation({nodes: ['foo']}),
53-
}),
54-
);
55-
56-
describeNode('with string text', () =>
57-
utils.fromExpressionProps({
58-
quotes: true,
59-
text: 'foo',
60-
}),
61-
);
62-
});
28+
describeNode(
29+
'constructed manually',
30+
() => new StringExpression({quotes: true, text: 'foo'}),
31+
);
32+
33+
describeNode('constructed from ExpressionProps', () =>
34+
utils.fromExpressionProps({quotes: true, text: 'foo'}),
35+
);
6336
});
6437

6538
describe('unquoted', () => {
@@ -81,29 +54,14 @@ describe('a string expression', () => {
8154
describeNode('parsed', () => utils.parseExpression('foo'));
8255

8356
describe('constructed manually', () => {
84-
describeNode(
85-
'with explicit text',
86-
() =>
87-
new StringExpression({
88-
text: new Interpolation({nodes: ['foo']}),
89-
}),
90-
);
91-
9257
describeNode(
9358
'with explicit quotes',
94-
() =>
95-
new StringExpression({
96-
quotes: false,
97-
text: 'foo',
98-
}),
59+
() => new StringExpression({quotes: false, text: 'foo'}),
9960
);
10061

10162
describeNode(
102-
'with string text',
103-
() =>
104-
new StringExpression({
105-
text: 'foo',
106-
}),
63+
'with default quotes',
64+
() => new StringExpression({text: 'foo'}),
10765
);
10866
});
10967

@@ -122,9 +80,7 @@ describe('a string expression', () => {
12280
);
12381

12482
describeNode('with string text', () =>
125-
utils.fromExpressionProps({
126-
text: 'foo',
127-
}),
83+
utils.fromExpressionProps({text: 'foo'}),
12884
);
12985
});
13086
});
@@ -145,7 +101,7 @@ describe('a string expression', () => {
145101
});
146102

147103
it('assigns text explicitly', () => {
148-
const text = new Interpolation({nodes: ['zip']});
104+
const text = new Interpolation('zip');
149105
node.text = text;
150106
expect(node.text).toBe(text);
151107
expect(node).toHaveInterpolation('text', 'zip');

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import * as postcss from 'postcss';
66

7-
import {Interpolation} from '../interpolation';
7+
import {Interpolation, InterpolationProps} from '../interpolation';
88
import {LazySource} from '../lazy-source';
99
import type * as sassInternal from '../sass-internal';
1010
import * as utils from '../utils';
@@ -16,7 +16,7 @@ import {Expression} from '.';
1616
* @category Expression
1717
*/
1818
export interface StringExpressionProps {
19-
text: Interpolation | string;
19+
text: Interpolation | InterpolationProps;
2020
quotes?: boolean;
2121
raws?: StringExpressionRaws;
2222
}
@@ -48,10 +48,11 @@ export class StringExpression extends Expression {
4848
get text(): Interpolation {
4949
return this._text;
5050
}
51-
set text(text: Interpolation | string) {
51+
set text(value: Interpolation | InterpolationProps) {
5252
// TODO - postcss/postcss#1957: Mark this as dirty
5353
if (this._text) this._text.parent = undefined;
54-
if (typeof text === 'string') text = new Interpolation({nodes: [text]});
54+
const text =
55+
value instanceof Interpolation ? value : new Interpolation(value);
5556
text.parent = this;
5657
this._text = text;
5758
}

pkg/sass-parser/lib/src/interpolation.test.ts

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,32 @@ describe('an interpolation', () => {
7171
() => (css.parse('@foo').nodes[0] as GenericAtRule).nameInterpolation,
7272
);
7373

74-
describeNode(
75-
'constructed manually',
76-
() => new Interpolation({nodes: ['foo']}),
77-
);
74+
describe('constructed manually', () => {
75+
describeNode('with an object', () => new Interpolation({nodes: ['foo']}));
76+
77+
describeNode('with an array', () => new Interpolation(['foo']));
78+
79+
describeNode('with a string', () => new Interpolation('foo'));
80+
});
81+
82+
describe('constructed from properties', () => {
83+
describeNode(
84+
'with an object',
85+
() =>
86+
new GenericAtRule({nameInterpolation: {nodes: ['foo']}})
87+
.nameInterpolation,
88+
);
89+
90+
describeNode(
91+
'with an array',
92+
() => new GenericAtRule({nameInterpolation: ['foo']}).nameInterpolation,
93+
);
94+
95+
describeNode(
96+
'with a string',
97+
() => new GenericAtRule({nameInterpolation: 'foo'}).nameInterpolation,
98+
);
99+
});
78100
});
79101

80102
describe('with only an expression', () => {
@@ -102,10 +124,30 @@ describe('an interpolation', () => {
102124
() => (scss.parse('@#{foo}').nodes[0] as GenericAtRule).nameInterpolation,
103125
);
104126

105-
describeNode(
106-
'constructed manually',
107-
() => new Interpolation({nodes: [{text: 'foo'}]}),
108-
);
127+
describe('constructed manually', () => {
128+
describeNode(
129+
'with an object',
130+
() => new Interpolation({nodes: [{text: 'foo'}]}),
131+
);
132+
133+
describeNode('with an array', () => new Interpolation([{text: 'foo'}]));
134+
});
135+
136+
describe('constructed from properties', () => {
137+
describeNode(
138+
'with an object',
139+
() =>
140+
new GenericAtRule({nameInterpolation: {nodes: [{text: 'foo'}]}})
141+
.nameInterpolation,
142+
);
143+
144+
describeNode(
145+
'with an array',
146+
() =>
147+
new GenericAtRule({nameInterpolation: [{text: 'foo'}]})
148+
.nameInterpolation,
149+
);
150+
});
109151
});
110152

111153
describe('with mixed text and expressions', () => {
@@ -139,10 +181,34 @@ describe('an interpolation', () => {
139181
.nameInterpolation,
140182
);
141183

142-
describeNode(
143-
'constructed manually',
144-
() => new Interpolation({nodes: ['foo', {text: 'bar'}, 'baz']}),
145-
);
184+
describe('constructed manually', () => {
185+
describeNode(
186+
'with an object',
187+
() => new Interpolation({nodes: ['foo', {text: 'bar'}, 'baz']}),
188+
);
189+
190+
describeNode(
191+
'with an array',
192+
() => new Interpolation(['foo', {text: 'bar'}, 'baz']),
193+
);
194+
});
195+
196+
describe('constructed from properties', () => {
197+
describeNode(
198+
'with an object',
199+
() =>
200+
new GenericAtRule({
201+
nameInterpolation: {nodes: ['foo', {text: 'bar'}, 'baz']},
202+
}).nameInterpolation,
203+
);
204+
205+
describeNode(
206+
'with an array',
207+
() =>
208+
new GenericAtRule({nameInterpolation: ['foo', {text: 'bar'}, 'baz']})
209+
.nameInterpolation,
210+
);
211+
});
146212
});
147213

148214
describe('can add', () => {

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,28 @@ export type NewNodeForInterpolation =
3434
| undefined;
3535

3636
/**
37-
* The initializer properties for {@link Interpolation}
37+
* The initializer properties for {@link Interpolation} passed as an options
38+
* object.
3839
*
3940
* @category Expression
4041
*/
41-
export interface InterpolationProps {
42+
export interface InterpolationObjectProps {
4243
nodes: ReadonlyArray<NewNodeForInterpolation>;
4344
raws?: InterpolationRaws;
4445
}
4546

47+
/**
48+
* The initializer properties for {@link Interpolation} passed.
49+
*
50+
* A plain string is interpreted as a plain-text interpolation.
51+
*
52+
* @category Expression
53+
*/
54+
export type InterpolationProps =
55+
| InterpolationObjectProps
56+
| ReadonlyArray<NewNodeForInterpolation>
57+
| string;
58+
4659
/**
4760
* Raws indicating how to precisely serialize an {@link Interpolation} node.
4861
*
@@ -131,8 +144,14 @@ export class Interpolation
131144
constructor(defaults?: InterpolationProps);
132145
/** @hidden */
133146
constructor(_: undefined, inner: sassInternal.Interpolation);
134-
constructor(defaults?: object, inner?: sassInternal.Interpolation) {
135-
super(defaults);
147+
constructor(defaults?: object | string, inner?: sassInternal.Interpolation) {
148+
super(
149+
typeof defaults === 'string'
150+
? {nodes: [defaults]}
151+
: Array.isArray(defaults)
152+
? {nodes: defaults}
153+
: defaults,
154+
);
136155
if (inner) {
137156
this.source = new LazySource(inner);
138157
// TODO: set lazy raws here to use when stringifying
@@ -146,7 +165,7 @@ export class Interpolation
146165
if (this._nodes === undefined) this._nodes = [];
147166
}
148167

149-
clone(overrides?: Partial<InterpolationProps>): this {
168+
clone(overrides?: Partial<InterpolationObjectProps>): this {
150169
return utils.cloneNode(this, overrides, ['nodes', 'raws']);
151170
}
152171

pkg/sass-parser/lib/src/parameter-list.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export type NewParameters =
3131
* @category Statement
3232
*/
3333
export interface ParameterListObjectProps {
34-
nodes?: ReadonlyArray<ParameterProps>;
34+
nodes?: ReadonlyArray<NewParameters>;
3535
restParameter?: string;
3636
raws?: ParameterListRaws;
3737
}
@@ -43,7 +43,7 @@ export interface ParameterListObjectProps {
4343
*/
4444
export type ParameterListProps =
4545
| ParameterListObjectProps
46-
| ReadonlyArray<ParameterProps>;
46+
| ReadonlyArray<NewParameters>;
4747

4848
/**
4949
* Raws indicating how to precisely serialize a {@link ParameterList} node.

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,15 @@ declare namespace SassInternal {
147147
readonly query: Interpolation;
148148
}
149149

150+
class MixinRule extends ParentStatement<Statement[]> {
151+
readonly name: string;
152+
readonly arguments: ArgumentDeclaration;
153+
}
154+
155+
class ReturnRule extends Statement {
156+
readonly expression: Expression;
157+
}
158+
150159
class SilentComment extends Statement {
151160
readonly text: string;
152161
}
@@ -285,6 +294,8 @@ export type ForwardRule = SassInternal.ForwardRule;
285294
export type FunctionRule = SassInternal.FunctionRule;
286295
export type LoudComment = SassInternal.LoudComment;
287296
export type MediaRule = SassInternal.MediaRule;
297+
export type MixinRule = SassInternal.MixinRule;
298+
export type ReturnRule = SassInternal.ReturnRule;
288299
export type SilentComment = SassInternal.SilentComment;
289300
export type Stylesheet = SassInternal.Stylesheet;
290301
export type StyleRule = SassInternal.StyleRule;
@@ -315,6 +326,8 @@ export interface StatementVisitorObject<T> {
315326
visitFunctionRule(node: FunctionRule): T;
316327
visitLoudComment(node: LoudComment): T;
317328
visitMediaRule(node: MediaRule): T;
329+
visitMixinRule(node: MixinRule): T;
330+
visitReturnRule(node: ReturnRule): T;
318331
visitSilentComment(node: SilentComment): T;
319332
visitStyleRule(node: StyleRule): T;
320333
visitSupportsRule(node: SupportsRule): T;

0 commit comments

Comments
 (0)