Skip to content

Commit 00619b1

Browse files
authoredJan 24, 2024
feat(css/parser): Implement error reporting for @value of CSS Modules (#8547)
1 parent c3fd9d0 commit 00619b1

File tree

6 files changed

+492
-0
lines changed

6 files changed

+492
-0
lines changed
 

‎crates/swc_css_parser/src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ impl Error {
7272
format!("{} is not valid name for keyframes", s).into()
7373
}
7474
ErrorKind::InvalidScopeAtRule => "Invalid @scope at-rule".into(),
75+
ErrorKind::ValueAtRule => "@value at-rule is deprecated".into(),
7576
}
7677
}
7778

@@ -119,4 +120,6 @@ pub enum ErrorKind {
119120
InvalidScopeAtRule,
120121

121122
UnknownAtRuleNotTerminated,
123+
124+
ValueAtRule,
122125
}

‎crates/swc_css_parser/src/parser/at_rules/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,19 @@ where
419419

420420
Some(prelude)
421421
}
422+
423+
"value" => {
424+
if self.config.css_modules {
425+
let span = self.input.cur_span();
426+
let _: ComponentValue = self.parse()?;
427+
428+
self.errors.push(Error::new(span, ErrorKind::ValueAtRule));
429+
430+
self.input.skip_ws();
431+
}
432+
433+
return Err(Error::new(Default::default(), ErrorKind::Ignore));
434+
}
422435
_ => {
423436
return Err(Error::new(Default::default(), ErrorKind::Ignore));
424437
}

‎crates/swc_css_parser/tests/fixture.rs

+18
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,24 @@ fn recovery(input: PathBuf) {
628628
stylesheet_recovery_test_tokens(input, Default::default());
629629
}
630630

631+
#[testing::fixture("tests/recovery-cssmodules/**/input.css")]
632+
fn recovery_2(input: PathBuf) {
633+
stylesheet_recovery_test(
634+
input.clone(),
635+
ParserConfig {
636+
css_modules: true,
637+
..Default::default()
638+
},
639+
);
640+
stylesheet_recovery_test_tokens(
641+
input,
642+
ParserConfig {
643+
css_modules: true,
644+
..Default::default()
645+
},
646+
);
647+
}
648+
631649
#[testing::fixture("tests/fixture/**/input.css")]
632650
#[testing::fixture("tests/recovery/**/input.css")]
633651
fn span_visualizer(input: PathBuf) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@value blue: #0c77f8;
2+
@value red: #ff0000;
3+
@value green: #aaf200;
4+
5+
.button {
6+
color: blue;
7+
display: inline-block;
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,428 @@
1+
{
2+
"type": "Stylesheet",
3+
"span": {
4+
"start": 1,
5+
"end": 119,
6+
"ctxt": 0
7+
},
8+
"rules": [
9+
{
10+
"type": "AtRule",
11+
"span": {
12+
"start": 1,
13+
"end": 22,
14+
"ctxt": 0
15+
},
16+
"name": {
17+
"type": "Ident",
18+
"span": {
19+
"start": 2,
20+
"end": 7,
21+
"ctxt": 0
22+
},
23+
"value": "value",
24+
"raw": "value"
25+
},
26+
"prelude": {
27+
"type": "ListOfComponentValues",
28+
"span": {
29+
"start": 7,
30+
"end": 21,
31+
"ctxt": 0
32+
},
33+
"children": [
34+
{
35+
"type": "PreservedToken",
36+
"span": {
37+
"start": 7,
38+
"end": 8,
39+
"ctxt": 0
40+
},
41+
"token": {
42+
"WhiteSpace": {
43+
"value": " "
44+
}
45+
}
46+
},
47+
{
48+
"type": "PreservedToken",
49+
"span": {
50+
"start": 8,
51+
"end": 12,
52+
"ctxt": 0
53+
},
54+
"token": {
55+
"Ident": {
56+
"value": "blue",
57+
"raw": "blue"
58+
}
59+
}
60+
},
61+
{
62+
"type": "PreservedToken",
63+
"span": {
64+
"start": 12,
65+
"end": 13,
66+
"ctxt": 0
67+
},
68+
"token": "Colon"
69+
},
70+
{
71+
"type": "PreservedToken",
72+
"span": {
73+
"start": 13,
74+
"end": 14,
75+
"ctxt": 0
76+
},
77+
"token": {
78+
"WhiteSpace": {
79+
"value": " "
80+
}
81+
}
82+
},
83+
{
84+
"type": "PreservedToken",
85+
"span": {
86+
"start": 14,
87+
"end": 21,
88+
"ctxt": 0
89+
},
90+
"token": {
91+
"Hash": {
92+
"is_id": false,
93+
"value": "0c77f8",
94+
"raw": "0c77f8"
95+
}
96+
}
97+
}
98+
]
99+
},
100+
"block": null
101+
},
102+
{
103+
"type": "AtRule",
104+
"span": {
105+
"start": 23,
106+
"end": 43,
107+
"ctxt": 0
108+
},
109+
"name": {
110+
"type": "Ident",
111+
"span": {
112+
"start": 24,
113+
"end": 29,
114+
"ctxt": 0
115+
},
116+
"value": "value",
117+
"raw": "value"
118+
},
119+
"prelude": {
120+
"type": "ListOfComponentValues",
121+
"span": {
122+
"start": 29,
123+
"end": 42,
124+
"ctxt": 0
125+
},
126+
"children": [
127+
{
128+
"type": "PreservedToken",
129+
"span": {
130+
"start": 29,
131+
"end": 30,
132+
"ctxt": 0
133+
},
134+
"token": {
135+
"WhiteSpace": {
136+
"value": " "
137+
}
138+
}
139+
},
140+
{
141+
"type": "PreservedToken",
142+
"span": {
143+
"start": 30,
144+
"end": 33,
145+
"ctxt": 0
146+
},
147+
"token": {
148+
"Ident": {
149+
"value": "red",
150+
"raw": "red"
151+
}
152+
}
153+
},
154+
{
155+
"type": "PreservedToken",
156+
"span": {
157+
"start": 33,
158+
"end": 34,
159+
"ctxt": 0
160+
},
161+
"token": "Colon"
162+
},
163+
{
164+
"type": "PreservedToken",
165+
"span": {
166+
"start": 34,
167+
"end": 35,
168+
"ctxt": 0
169+
},
170+
"token": {
171+
"WhiteSpace": {
172+
"value": " "
173+
}
174+
}
175+
},
176+
{
177+
"type": "PreservedToken",
178+
"span": {
179+
"start": 35,
180+
"end": 42,
181+
"ctxt": 0
182+
},
183+
"token": {
184+
"Hash": {
185+
"is_id": true,
186+
"value": "ff0000",
187+
"raw": "ff0000"
188+
}
189+
}
190+
}
191+
]
192+
},
193+
"block": null
194+
},
195+
{
196+
"type": "AtRule",
197+
"span": {
198+
"start": 44,
199+
"end": 66,
200+
"ctxt": 0
201+
},
202+
"name": {
203+
"type": "Ident",
204+
"span": {
205+
"start": 45,
206+
"end": 50,
207+
"ctxt": 0
208+
},
209+
"value": "value",
210+
"raw": "value"
211+
},
212+
"prelude": {
213+
"type": "ListOfComponentValues",
214+
"span": {
215+
"start": 50,
216+
"end": 65,
217+
"ctxt": 0
218+
},
219+
"children": [
220+
{
221+
"type": "PreservedToken",
222+
"span": {
223+
"start": 50,
224+
"end": 51,
225+
"ctxt": 0
226+
},
227+
"token": {
228+
"WhiteSpace": {
229+
"value": " "
230+
}
231+
}
232+
},
233+
{
234+
"type": "PreservedToken",
235+
"span": {
236+
"start": 51,
237+
"end": 56,
238+
"ctxt": 0
239+
},
240+
"token": {
241+
"Ident": {
242+
"value": "green",
243+
"raw": "green"
244+
}
245+
}
246+
},
247+
{
248+
"type": "PreservedToken",
249+
"span": {
250+
"start": 56,
251+
"end": 57,
252+
"ctxt": 0
253+
},
254+
"token": "Colon"
255+
},
256+
{
257+
"type": "PreservedToken",
258+
"span": {
259+
"start": 57,
260+
"end": 58,
261+
"ctxt": 0
262+
},
263+
"token": {
264+
"WhiteSpace": {
265+
"value": " "
266+
}
267+
}
268+
},
269+
{
270+
"type": "PreservedToken",
271+
"span": {
272+
"start": 58,
273+
"end": 65,
274+
"ctxt": 0
275+
},
276+
"token": {
277+
"Hash": {
278+
"is_id": true,
279+
"value": "aaf200",
280+
"raw": "aaf200"
281+
}
282+
}
283+
}
284+
]
285+
},
286+
"block": null
287+
},
288+
{
289+
"type": "QualifiedRule",
290+
"span": {
291+
"start": 68,
292+
"end": 119,
293+
"ctxt": 0
294+
},
295+
"prelude": {
296+
"type": "SelectorList",
297+
"span": {
298+
"start": 68,
299+
"end": 75,
300+
"ctxt": 0
301+
},
302+
"children": [
303+
{
304+
"type": "ComplexSelector",
305+
"span": {
306+
"start": 68,
307+
"end": 75,
308+
"ctxt": 0
309+
},
310+
"children": [
311+
{
312+
"type": "CompoundSelector",
313+
"span": {
314+
"start": 68,
315+
"end": 75,
316+
"ctxt": 0
317+
},
318+
"nestingSelector": null,
319+
"typeSelector": null,
320+
"subclassSelectors": [
321+
{
322+
"type": "ClassSelector",
323+
"span": {
324+
"start": 68,
325+
"end": 75,
326+
"ctxt": 0
327+
},
328+
"text": {
329+
"type": "Ident",
330+
"span": {
331+
"start": 69,
332+
"end": 75,
333+
"ctxt": 0
334+
},
335+
"value": "button",
336+
"raw": "button"
337+
}
338+
}
339+
]
340+
}
341+
]
342+
}
343+
]
344+
},
345+
"block": {
346+
"type": "SimpleBlock",
347+
"span": {
348+
"start": 76,
349+
"end": 119,
350+
"ctxt": 0
351+
},
352+
"name": {
353+
"type": "PreservedToken",
354+
"span": {
355+
"start": 76,
356+
"end": 77,
357+
"ctxt": 0
358+
},
359+
"token": "LBrace"
360+
},
361+
"value": [
362+
{
363+
"type": "Declaration",
364+
"span": {
365+
"start": 80,
366+
"end": 91,
367+
"ctxt": 0
368+
},
369+
"name": {
370+
"type": "Ident",
371+
"span": {
372+
"start": 80,
373+
"end": 85,
374+
"ctxt": 0
375+
},
376+
"value": "color",
377+
"raw": "color"
378+
},
379+
"value": [
380+
{
381+
"type": "Ident",
382+
"span": {
383+
"start": 87,
384+
"end": 91,
385+
"ctxt": 0
386+
},
387+
"value": "blue",
388+
"raw": "blue"
389+
}
390+
],
391+
"important": null
392+
},
393+
{
394+
"type": "Declaration",
395+
"span": {
396+
"start": 95,
397+
"end": 116,
398+
"ctxt": 0
399+
},
400+
"name": {
401+
"type": "Ident",
402+
"span": {
403+
"start": 95,
404+
"end": 102,
405+
"ctxt": 0
406+
},
407+
"value": "display",
408+
"raw": "display"
409+
},
410+
"value": [
411+
{
412+
"type": "Ident",
413+
"span": {
414+
"start": 104,
415+
"end": 116,
416+
"ctxt": 0
417+
},
418+
"value": "inline-block",
419+
"raw": "inline-block"
420+
}
421+
],
422+
"important": null
423+
}
424+
]
425+
}
426+
}
427+
]
428+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
x @value at-rule is deprecated
3+
,-[$DIR/tests/recovery-cssmodules/value/input.css:1:1]
4+
1 | @value blue: #0c77f8;
5+
: ^
6+
2 | @value red: #ff0000;
7+
`----
8+
9+
x @value at-rule is deprecated
10+
,-[$DIR/tests/recovery-cssmodules/value/input.css:1:1]
11+
1 | @value blue: #0c77f8;
12+
2 | @value red: #ff0000;
13+
: ^
14+
3 | @value green: #aaf200;
15+
`----
16+
17+
x @value at-rule is deprecated
18+
,-[$DIR/tests/recovery-cssmodules/value/input.css:2:1]
19+
2 | @value red: #ff0000;
20+
3 | @value green: #aaf200;
21+
: ^
22+
`----

0 commit comments

Comments
 (0)
Please sign in to comment.