fix(css/parser): Fix parsing of nested rules (#6563)

This commit is contained in:
Alexander Akait 2022-12-02 06:52:54 +03:00 committed by GitHub
parent 92877096fe
commit a1fe9076c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 557 additions and 31 deletions

View File

@ -456,7 +456,6 @@ where
}
_ => {
let ctx = Ctx {
is_top_level: false,
in_container_at_rule: true,
..self.ctx
};
@ -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();
@ -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
};
@ -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();
@ -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();
@ -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();
@ -934,7 +916,7 @@ where
return Err(Error::new(
span,
ErrorKind::Expected("ident or percentage token"),
ErrorKind::Expected("'from', 'to' or percentage"),
));
}
}

View File

@ -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.
@ -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)),
@ -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);
}

View File

@ -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 {

View File

@ -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 {

View File

@ -36,3 +36,9 @@ a {
color: red;
}
}
@keyframes box {
<!-- -->
50% { left: 0; }
90% { left: 300px; }
}

View File

@ -2,7 +2,7 @@
"type": "Stylesheet",
"span": {
"start": 1,
"end": 227,
"end": 306,
"ctxt": 0
},
"rules": [
@ -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
}
]
}
}
]
}
}
]
}

View File

@ -1,4 +1,12 @@
x Expected 'from', 'to' or percentage
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | <!-- -->
: ^^^^
42 | 50% { left: 0; }
`----
x Expected '{'
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:19:1]
19 |

View File

@ -38,7 +38,13 @@
35 | | <!-- .class {
36 | | color: red;
37 | | }
38 | `-> }
38 | | }
39 | |
40 | | @keyframes box {
41 | | <!-- -->
42 | | 50% { left: 0; }
43 | | 90% { left: 300px; }
44 | `-> }
`----
x Rule
@ -1311,3 +1317,289 @@
: ^^^
37 | }
`----
x Rule
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:39:1]
39 |
40 | ,-> @keyframes box {
41 | | <!-- -->
42 | | 50% { left: 0; }
43 | | 90% { left: 300px; }
44 | `-> }
`----
x AtRule
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:39:1]
39 |
40 | ,-> @keyframes box {
41 | | <!-- -->
42 | | 50% { left: 0; }
43 | | 90% { left: 300px; }
44 | `-> }
`----
x AtRuleName
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:39:1]
39 |
40 | @keyframes box {
: ^^^^^^^^^
41 | <!-- -->
`----
x Ident
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:39:1]
39 |
40 | @keyframes box {
: ^^^^^^^^^
41 | <!-- -->
`----
x CustomIdent
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:39:1]
39 |
40 | @keyframes box {
: ^^^
41 | <!-- -->
`----
x SimpleBlock
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:39:1]
39 |
40 | ,-> @keyframes box {
41 | | <!-- -->
42 | | 50% { left: 0; }
43 | | 90% { left: 300px; }
44 | `-> }
`----
x LBrace
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:39:1]
39 |
40 | @keyframes box {
: ^
41 | <!-- -->
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | ,-> <!-- -->
42 | `-> 50% { left: 0; }
43 | 90% { left: 300px; }
`----
x Rule
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | ,-> <!-- -->
42 | `-> 50% { left: 0; }
43 | 90% { left: 300px; }
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | <!-- -->
: ^^^^
42 | 50% { left: 0; }
`----
x CDO
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | <!-- -->
: ^^^^
42 | 50% { left: 0; }
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | <!-- -->
: ^
42 | 50% { left: 0; }
`----
x WhiteSpace { value: " " }
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | <!-- -->
: ^
42 | 50% { left: 0; }
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | <!-- -->
: ^^^
42 | 50% { left: 0; }
`----
x CDC
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | <!-- -->
: ^^^
42 | 50% { left: 0; }
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | ,-> <!-- -->
42 | `-> 50% { left: 0; }
43 | 90% { left: 300px; }
`----
x WhiteSpace { value: "\n " }
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:40:1]
40 | @keyframes box {
41 | ,-> <!-- -->
42 | `-> 50% { left: 0; }
43 | 90% { left: 300px; }
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:41:1]
41 | <!-- -->
42 | 50% { left: 0; }
: ^^^
43 | 90% { left: 300px; }
`----
x Percentage { value: 50.0, raw: "50" }
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:41:1]
41 | <!-- -->
42 | 50% { left: 0; }
: ^^^
43 | 90% { left: 300px; }
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:41:1]
41 | <!-- -->
42 | 50% { left: 0; }
: ^
43 | 90% { left: 300px; }
`----
x WhiteSpace { value: " " }
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:41:1]
41 | <!-- -->
42 | 50% { left: 0; }
: ^
43 | 90% { left: 300px; }
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^^^^^^^^^^^^^^^^^^
44 | }
`----
x Percentage
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^
44 | }
`----
x Number
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^
44 | }
`----
x SimpleBlock
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^^^^^^^^^^^^^^
44 | }
`----
x LBrace
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^
44 | }
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^^^^^^^^^
44 | }
`----
x Declaration
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^^^^^^^^^
44 | }
`----
x DeclarationName
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^^
44 | }
`----
x Ident
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^^
44 | }
`----
x ComponentValue
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^^^
44 | }
`----
x Dimension
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^^^
44 | }
`----
x Length
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^^^
44 | }
`----
x Number
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^^
44 | }
`----
x Ident
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:42:1]
42 | 50% { left: 0; }
43 | 90% { left: 300px; }
: ^^
44 | }
`----