Skip to content

Commit 0918ade

Browse files
committed
Add sass-parser support for @return and @mixin
1 parent 93e6c2e commit 0918ade

18 files changed

+978
-66
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/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;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`a @mixin rule toJSON 1`] = `
4+
{
5+
"inputs": [
6+
{
7+
"css": "@mixin foo($bar) {}",
8+
"hasBOM": false,
9+
"id": "<input css _____>",
10+
},
11+
],
12+
"mixinName": "foo",
13+
"name": "mixin",
14+
"nodes": [],
15+
"parameters": <($bar)>,
16+
"raws": {},
17+
"sassType": "mixin-rule",
18+
"source": <1:1-1:20 in 0>,
19+
"type": "atrule",
20+
}
21+
`;
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 @return rule toJSON 1`] = `
4+
{
5+
"inputs": [
6+
{
7+
"css": "@function x() {@return foo}",
8+
"hasBOM": false,
9+
"id": "<input css _____>",
10+
},
11+
],
12+
"name": "return",
13+
"params": "foo",
14+
"raws": {},
15+
"returnExpression": <foo>,
16+
"sassType": "return-rule",
17+
"source": <1:16-1:27 in 0>,
18+
"type": "atrule",
19+
}
20+
`;

pkg/sass-parser/lib/src/statement/function-rule.test.ts

Lines changed: 62 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +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 {FunctionRule, ParameterList, sass, scss} from '../..';
5+
import {FunctionRule, ParameterList, ReturnRule, sass, scss} from '../..';
66
import * as utils from '../../../test/utils';
77

88
describe('a @function rule', () => {
@@ -49,60 +49,67 @@ describe('a @function rule', () => {
4949
);
5050
});
5151

52-
// TODO(nweiz): Enable this when we parse ReturnRule.
53-
//
54-
// describe('with a child', () => {
55-
// function describeNode(description: string, create: () => FunctionRule): void {
56-
// describe(description, () => {
57-
// beforeEach(() => void (node = create()));
58-
//
59-
// it('has a name', () => expect(node.name.toString()).toBe('function'));
60-
//
61-
// it('has a function name', () => expect(node.functionName.toString()).toBe('foo'));
62-
//
63-
// it('has a parameter', () =>
64-
// expect(node.parameters.nodes[0].name).toEqual('bar'));
65-
//
66-
// it('has matching params', () =>
67-
// expect(node.params).toBe('foo($bar)'));
68-
//
69-
// it('has a child node', () => {
70-
// expect(node.nodes).toHaveLength(1);
71-
// expect(node.nodes[0]).toBeInstanceOf(ReturnRule);
72-
// expect(node.nodes[0]).toHaveStringExpression('returnExpression', 'baz');
73-
// });
74-
// });
75-
// }
76-
//
77-
// describeNode(
78-
// 'parsed as SCSS',
79-
// () => scss.parse('@function foo($bar) {@return "baz"}').nodes[0] as FunctionRule,
80-
// );
81-
//
82-
// describeNode(
83-
// 'parsed as Sass',
84-
// () =>
85-
// sass.parse('@function foo($bar)\n @return "baz"').nodes[0] as FunctionRule,
86-
// );
87-
//
88-
// describeNode(
89-
// 'constructed manually',
90-
// () =>
91-
// new FunctionRule({
92-
// name: 'foo',
93-
// parameters: ['bar'],
94-
// nodes: [{returnExpression: 'child'}],
95-
// }),
96-
// );
97-
//
98-
// describeNode('constructed from ChildProps', () =>
99-
// utils.fromChildProps({
100-
// name: 'foo',
101-
// parameters: ['bar'],
102-
// nodes: [{returnExpression: 'child'}],
103-
// }),
104-
// );
105-
// });
52+
describe('with a child', () => {
53+
function describeNode(
54+
description: string,
55+
create: () => FunctionRule,
56+
): void {
57+
describe(description, () => {
58+
beforeEach(() => void (node = create()));
59+
60+
it('has a name', () => expect(node.name.toString()).toBe('function'));
61+
62+
it('has a function name', () =>
63+
expect(node.functionName.toString()).toBe('foo'));
64+
65+
it('has a parameter', () =>
66+
expect(node.parameters.nodes[0].name).toEqual('bar'));
67+
68+
it('has matching params', () => expect(node.params).toBe('foo($bar)'));
69+
70+
it('has a child node', () => {
71+
expect(node.nodes).toHaveLength(1);
72+
expect(node.nodes[0]).toBeInstanceOf(ReturnRule);
73+
expect(node.nodes[0]).toHaveStringExpression(
74+
'returnExpression',
75+
'baz',
76+
);
77+
});
78+
});
79+
}
80+
81+
describeNode(
82+
'parsed as SCSS',
83+
() =>
84+
scss.parse('@function foo($bar) {@return "baz"}')
85+
.nodes[0] as FunctionRule,
86+
);
87+
88+
describeNode(
89+
'parsed as Sass',
90+
() =>
91+
sass.parse('@function foo($bar)\n @return "baz"')
92+
.nodes[0] as FunctionRule,
93+
);
94+
95+
describeNode(
96+
'constructed manually',
97+
() =>
98+
new FunctionRule({
99+
functionName: 'foo',
100+
parameters: ['bar'],
101+
nodes: [{returnExpression: {text: 'baz'}}],
102+
}),
103+
);
104+
105+
describeNode('constructed from ChildProps', () =>
106+
utils.fromChildProps({
107+
functionName: 'foo',
108+
parameters: ['bar'],
109+
nodes: [{returnExpression: {text: 'baz'}}],
110+
}),
111+
);
112+
});
106113

107114
describe('throws an error when assigned a new', () => {
108115
beforeEach(

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

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {ErrorRule, ErrorRuleProps} from './error-rule';
1818
import {ForRule, ForRuleProps} from './for-rule';
1919
import {ForwardRule, ForwardRuleProps} from './forward-rule';
2020
import {FunctionRule, FunctionRuleProps} from './function-rule';
21+
import {MixinRule, MixinRuleProps} from './mixin-rule';
22+
import {ReturnRule, ReturnRuleProps} from './return-rule';
2123
import {Root} from './root';
2224
import {Rule, RuleProps} from './rule';
2325
import {UseRule, UseRuleProps} from './use-rule';
@@ -55,12 +57,14 @@ export type StatementType =
5557
| 'comment'
5658
| 'debug-rule'
5759
| 'each-rule'
60+
| 'error-rule'
5861
| 'for-rule'
5962
| 'forward-rule'
6063
| 'function-rule'
61-
| 'error-rule'
62-
| 'use-rule'
64+
| 'mixin-rule'
65+
| 'return-rule'
6366
| 'sass-comment'
67+
| 'use-rule'
6468
| 'variable-declaration'
6569
| 'warn-rule'
6670
| 'while-rule';
@@ -78,6 +82,8 @@ export type AtRule =
7882
| ForwardRule
7983
| FunctionRule
8084
| GenericAtRule
85+
| MixinRule
86+
| ReturnRule
8187
| UseRule
8288
| WarnRule
8389
| WhileRule;
@@ -115,6 +121,8 @@ export type ChildProps =
115121
| ForwardRuleProps
116122
| FunctionRuleProps
117123
| GenericAtRuleProps
124+
| MixinRuleProps
125+
| ReturnRuleProps
118126
| RuleProps
119127
| SassCommentChildProps
120128
| UseRuleProps
@@ -195,6 +203,8 @@ const visitor = sassInternal.createStatementVisitor<Statement>({
195203
appendInternalChildren(rule, inner.children);
196204
return rule;
197205
},
206+
visitMixinRule: inner => new MixinRule(undefined, inner),
207+
visitReturnRule: inner => new ReturnRule(undefined, inner),
198208
visitSilentComment: inner => new SassComment(undefined, inner),
199209
visitStyleRule: inner => new Rule(undefined, inner),
200210
visitSupportsRule: inner => {
@@ -319,18 +329,22 @@ export function normalize(
319329
result.push(new DebugRule(node));
320330
} else if ('eachExpression' in node) {
321331
result.push(new EachRule(node));
332+
} else if ('errorExpression' in node) {
333+
result.push(new ErrorRule(node));
322334
} else if ('fromExpression' in node) {
323335
result.push(new ForRule(node));
324336
} else if ('forwardUrl' in node) {
325337
result.push(new ForwardRule(node));
326338
} else if ('functionName' in node) {
327339
result.push(new FunctionRule(node));
328-
} else if ('errorExpression' in node) {
329-
result.push(new ErrorRule(node));
330-
} else if ('text' in node || 'textInterpolation' in node) {
331-
result.push(new CssComment(node as CssCommentProps));
340+
} else if ('mixinName' in node) {
341+
result.push(new MixinRule(node));
342+
} else if ('returnExpression' in node) {
343+
result.push(new ReturnRule(node));
332344
} else if ('silentText' in node) {
333345
result.push(new SassComment(node));
346+
} else if ('text' in node || 'textInterpolation' in node) {
347+
result.push(new CssComment(node as CssCommentProps));
334348
} else if ('useUrl' in node) {
335349
result.push(new UseRule(node));
336350
} else if ('variableName' in node) {

0 commit comments

Comments
 (0)