Skip to content

Commit

Permalink
fix(css/parser): Fix parsing of nested rules (#6563)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait authored Dec 2, 2022
1 parent 9287709 commit a1fe907
Show file tree
Hide file tree
Showing 8 changed files with 557 additions and 31 deletions.
28 changes: 5 additions & 23 deletions crates/swc_css_parser/src/parser/at_rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,6 @@ where
}
_ => {
let ctx = Ctx {
is_top_level: false,
in_container_at_rule: true,
..self.ctx
};
Expand Down Expand Up @@ -493,11 +492,7 @@ where
style_blocks
}
_ => {
let ctx = Ctx {
is_top_level: false,
..self.ctx
};
let rule_list = self.with_ctx(ctx).parse_as::<Vec<Rule>>()?;
let rule_list = self.parse_as::<Vec<Rule>>()?;
let rule_list: Vec<ComponentValue> =
rule_list.into_iter().map(ComponentValue::Rule).collect();

Expand Down Expand Up @@ -565,7 +560,6 @@ where
| js_word!("-ms-keyframes") => {
let ctx = Ctx {
block_contents_grammar: BlockContentsGrammar::RuleList,
is_top_level: false,
in_keyframes_at_rule: true,
..self.ctx
};
Expand Down Expand Up @@ -636,11 +630,7 @@ where
rule_list
}
js_word!("layer") => {
let ctx = Ctx {
is_top_level: false,
..self.ctx
};
let rule_list = self.with_ctx(ctx).parse_as::<Vec<Rule>>()?;
let rule_list = self.parse_as::<Vec<Rule>>()?;
let rule_list: Vec<ComponentValue> =
rule_list.into_iter().map(ComponentValue::Rule).collect();

Expand All @@ -657,11 +647,7 @@ where
style_blocks
}
_ => {
let ctx = Ctx {
is_top_level: false,
..self.ctx
};
let rule_list = self.with_ctx(ctx).parse_as::<Vec<Rule>>()?;
let rule_list = self.parse_as::<Vec<Rule>>()?;
let rule_list: Vec<ComponentValue> =
rule_list.into_iter().map(ComponentValue::Rule).collect();

Expand Down Expand Up @@ -742,11 +728,7 @@ where
style_blocks
}
_ => {
let ctx = Ctx {
is_top_level: false,
..self.ctx
};
let rule_list = self.with_ctx(ctx).parse_as::<Vec<Rule>>()?;
let rule_list = self.parse_as::<Vec<Rule>>()?;
let rule_list: Vec<ComponentValue> =
rule_list.into_iter().map(ComponentValue::Rule).collect();

Expand Down Expand Up @@ -934,7 +916,7 @@ where

return Err(Error::new(
span,
ErrorKind::Expected("ident or percentage token"),
ErrorKind::Expected("'from', 'to' or percentage"),
));
}
}
Expand Down
22 changes: 18 additions & 4 deletions crates/swc_css_parser/src/parser/syntax/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ where
let mut rules = vec![];

// Repeatedly consume the next input token:

// Reset the `is_top_level` value
let ctx = Ctx {
is_top_level: false,
..self.ctx
};
loop {
// <EOF-token>
// Return the list of rules.
Expand All @@ -70,21 +76,28 @@ where
// Otherwise, reconsume the current input token. Consume a qualified rule. If
// anything is returned, append it to the list of rules.
else {
rules.push(Rule::QualifiedRule(self.parse()?));
let qualified_rule = self.with_ctx(ctx).parse_as::<Box<QualifiedRule>>()?;

rules.push(Rule::QualifiedRule(qualified_rule));
}
}
// <at-keyword-token>
// Reconsume the current input token. Consume an at-rule, and append the returned
// value to the list of rules.
tok!("@") => {
rules.push(Rule::AtRule(self.parse()?));
let at_rule = self.with_ctx(ctx).parse_as::<Box<AtRule>>()?;

rules.push(Rule::AtRule(at_rule));
}
// anything else
// Reconsume the current input token. Consume a qualified rule. If anything is
// returned, append it to the list of rules.
//
// For better recovery we parse broken code into the list of component values and
// append it to the list of rules.
_ => {
let state = self.input.state();
let qualified_rule = self.parse();
let qualified_rule = self.with_ctx(ctx).parse_as::<Box<QualifiedRule>>();

match qualified_rule {
Ok(i) => rules.push(Rule::QualifiedRule(i)),
Expand All @@ -99,7 +112,8 @@ where
};

while !is_one_of!(self, EOF) {
let component_value = self.parse_as::<ComponentValue>()?;
let component_value =
self.with_ctx(ctx).parse_as::<ComponentValue>()?;

list_of_component_values.children.push(component_value);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

x Expected ident or percentage token
x Expected 'from', 'to' or percentage
,-[$DIR/tests/recovery/at-rule/keyframes/keyframe-broke-and-normal/input.css:1:1]
1 | @keyframes foo {
2 | 10 {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

x Expected ident or percentage token
x Expected 'from', 'to' or percentage
,-[$DIR/tests/recovery/at-rule/keyframes/keyframe-number/input.css:1:1]
1 | @keyframes foo {
2 | 10 {
Expand Down
6 changes: 6 additions & 0 deletions crates/swc_css_parser/tests/recovery/cdo-and-cdc/input.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ a {
color: red;
}
}

@keyframes box {
<!-- -->
50% { left: 0; }
90% { left: 300px; }
}
226 changes: 225 additions & 1 deletion crates/swc_css_parser/tests/recovery/cdo-and-cdc/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"type": "Stylesheet",
"span": {
"start": 1,
"end": 227,
"end": 306,
"ctxt": 0
},
"rules": [
Expand Down Expand Up @@ -923,6 +923,230 @@
}
]
}
},
{
"type": "AtRule",
"span": {
"start": 228,
"end": 305,
"ctxt": 0
},
"name": {
"type": "Ident",
"span": {
"start": 229,
"end": 238,
"ctxt": 0
},
"value": "keyframes",
"raw": "keyframes"
},
"prelude": {
"type": "CustomIdent",
"span": {
"start": 239,
"end": 242,
"ctxt": 0
},
"value": "box",
"raw": "box"
},
"block": {
"type": "SimpleBlock",
"span": {
"start": 243,
"end": 305,
"ctxt": 0
},
"name": {
"type": "PreservedToken",
"span": {
"start": 243,
"end": 244,
"ctxt": 0
},
"token": "LBrace"
},
"value": [
{
"type": "ListOfComponentValues",
"span": {
"start": 249,
"end": 266,
"ctxt": 0
},
"children": [
{
"type": "PreservedToken",
"span": {
"start": 249,
"end": 253,
"ctxt": 0
},
"token": "CDO"
},
{
"type": "PreservedToken",
"span": {
"start": 253,
"end": 254,
"ctxt": 0
},
"token": {
"WhiteSpace": {
"value": " "
}
}
},
{
"type": "PreservedToken",
"span": {
"start": 254,
"end": 257,
"ctxt": 0
},
"token": "CDC"
},
{
"type": "PreservedToken",
"span": {
"start": 257,
"end": 262,
"ctxt": 0
},
"token": {
"WhiteSpace": {
"value": "\n "
}
}
},
{
"type": "PreservedToken",
"span": {
"start": 262,
"end": 265,
"ctxt": 0
},
"token": {
"Percentage": {
"value": 50.0,
"raw": "50"
}
}
},
{
"type": "PreservedToken",
"span": {
"start": 265,
"end": 266,
"ctxt": 0
},
"token": {
"WhiteSpace": {
"value": " "
}
}
}
]
},
{
"type": "KeyframeBlock",
"span": {
"start": 283,
"end": 303,
"ctxt": 0
},
"prelude": [
{
"type": "Percentage",
"span": {
"start": 283,
"end": 286,
"ctxt": 0
},
"value": {
"type": "Number",
"span": {
"start": 283,
"end": 285,
"ctxt": 0
},
"value": 90.0,
"raw": "90"
}
}
],
"block": {
"type": "SimpleBlock",
"span": {
"start": 287,
"end": 303,
"ctxt": 0
},
"name": {
"type": "PreservedToken",
"span": {
"start": 287,
"end": 288,
"ctxt": 0
},
"token": "LBrace"
},
"value": [
{
"type": "Declaration",
"span": {
"start": 289,
"end": 300,
"ctxt": 0
},
"name": {
"type": "Ident",
"span": {
"start": 289,
"end": 293,
"ctxt": 0
},
"value": "left",
"raw": "left"
},
"value": [
{
"type": "Length",
"span": {
"start": 295,
"end": 300,
"ctxt": 0
},
"value": {
"type": "Number",
"span": {
"start": 295,
"end": 298,
"ctxt": 0
},
"value": 300.0,
"raw": "300"
},
"unit": {
"type": "Ident",
"span": {
"start": 298,
"end": 300,
"ctxt": 0
},
"value": "px",
"raw": "px"
}
}
],
"important": null
}
]
}
}
]
}
}
]
}
Loading

1 comment on commit a1fe907

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: a1fe907 Previous: 49b7e9e Ratio
es/full/bugs-1 359971 ns/iter (± 23019) 422864 ns/iter (± 11280) 0.85
es/full/minify/libraries/antd 2196314594 ns/iter (± 66161949) 2323894819 ns/iter (± 20013410) 0.95
es/full/minify/libraries/d3 493222863 ns/iter (± 18083842) 483346882 ns/iter (± 2805590) 1.02
es/full/minify/libraries/echarts 1907008624 ns/iter (± 131210976) 1979599222 ns/iter (± 63362725) 0.96
es/full/minify/libraries/jquery 136062858 ns/iter (± 7888797) 135925412 ns/iter (± 3365155) 1.00
es/full/minify/libraries/lodash 160811751 ns/iter (± 16879542) 152847897 ns/iter (± 2225906) 1.05
es/full/minify/libraries/moment 81001733 ns/iter (± 3240327) 78125952 ns/iter (± 1218335) 1.04
es/full/minify/libraries/react 27389221 ns/iter (± 3118727) 26838248 ns/iter (± 313151) 1.02
es/full/minify/libraries/terser 405710691 ns/iter (± 22309499) 370734751 ns/iter (± 11264611) 1.09
es/full/minify/libraries/three 739145826 ns/iter (± 36762061) 681259342 ns/iter (± 29553903) 1.08
es/full/minify/libraries/typescript 4313807563 ns/iter (± 110349907) 4323561188 ns/iter (± 498139936) 1.00
es/full/minify/libraries/victory 1077474619 ns/iter (± 56314333) 1020244719 ns/iter (± 22256982) 1.06
es/full/minify/libraries/vue 198380052 ns/iter (± 7685042) 193502239 ns/iter (± 1648757) 1.03
es/full/codegen/es3 37570 ns/iter (± 5536) 40228 ns/iter (± 1253) 0.93
es/full/codegen/es5 36696 ns/iter (± 5204) 40245 ns/iter (± 941) 0.91
es/full/codegen/es2015 38337 ns/iter (± 6759) 40396 ns/iter (± 1005) 0.95
es/full/codegen/es2016 37683 ns/iter (± 5071) 40610 ns/iter (± 1889) 0.93
es/full/codegen/es2017 38927 ns/iter (± 6912) 40382 ns/iter (± 596) 0.96
es/full/codegen/es2018 37625 ns/iter (± 6874) 40306 ns/iter (± 440) 0.93
es/full/codegen/es2019 36869 ns/iter (± 5723) 40558 ns/iter (± 1204) 0.91
es/full/codegen/es2020 35703 ns/iter (± 6496) 40401 ns/iter (± 3637) 0.88
es/full/all/es3 218431113 ns/iter (± 18250701) 230059006 ns/iter (± 9556870) 0.95
es/full/all/es5 211562804 ns/iter (± 21827441) 217676489 ns/iter (± 6298302) 0.97
es/full/all/es2015 165678952 ns/iter (± 15929758) 175986654 ns/iter (± 4728969) 0.94
es/full/all/es2016 162469036 ns/iter (± 12681425) 175797872 ns/iter (± 5283379) 0.92
es/full/all/es2017 164067102 ns/iter (± 24357262) 174446317 ns/iter (± 5959674) 0.94
es/full/all/es2018 153599284 ns/iter (± 10474356) 171502661 ns/iter (± 4854162) 0.90
es/full/all/es2019 192345523 ns/iter (± 23336258) 170950144 ns/iter (± 5509598) 1.13
es/full/all/es2020 158220153 ns/iter (± 16592820) 164553031 ns/iter (± 6041962) 0.96
es/full/parser 818623 ns/iter (± 121234) 865801 ns/iter (± 69938) 0.95
es/full/base/fixer 29346 ns/iter (± 3712) 32351 ns/iter (± 503) 0.91
es/full/base/resolver_and_hygiene 97534 ns/iter (± 19544) 110498 ns/iter (± 2066) 0.88
serialization of ast node 230 ns/iter (± 46) 242 ns/iter (± 8) 0.95
serialization of serde 291 ns/iter (± 53) 259 ns/iter (± 15) 1.12

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.