feat(css): add support for SCSS @for at-rule#9421
Conversation
|
Parser conformance results onjs/262
jsx/babel
markdown/commonmark
symbols/microsoft
ts/babel
ts/microsoft
|
Merging this PR will not alter performance
Comparing Footnotes
|
WalkthroughAdds end-to-end support for the SCSS Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/biome_css_parser/src/syntax/scss/at_rule/for_at_rule.rs (1)
36-39: Recover tofromafter a missing binding.If the binding parse fails, Line 37 still runs on the same token, so malformed input like
@for 1 from 2 to 3 {}can stack a secondfromerror and then start the lower-bound parse from the wrong place. A tiny recovery set aroundfrom/{, like the sibling@eachrule uses, would keep the diagnostics much tidier.Based on learnings: "Parse rules must return
ParsedSyntax::Absentif the rule can't predict by the next token(s) if they form the expected node, and must not progress the parser in this case."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_css_parser/src/syntax/scss/at_rule/for_at_rule.rs` around lines 36 - 39, The binding parse (parse_scss_identifier(...).or_add_diagnostic(...)) can fail and leave the parser on the same token, causing p.expect(T![from]) and parse_scss_expression_until(...) to run from the wrong place; capture the result of parse_scss_identifier into a variable, and if it is ParsedSyntax::Absent (i.e. the binding failed) perform a tiny recovery step that advances to the next relevant sync tokens (e.g. a small set containing T![from] and T!['{'] similar to the `@each` rule) before calling p.expect(T![from]) and parse_scss_expression_until(..., SCSS_FOR_LOWER_BOUND_END_SET) so diagnostics and position are correct (use expected_scss_for_binding / expected_scss_expression for diagnostics as currently done).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@crates/biome_css_parser/src/syntax/scss/at_rule/for_at_rule.rs`:
- Around line 36-39: The binding parse
(parse_scss_identifier(...).or_add_diagnostic(...)) can fail and leave the
parser on the same token, causing p.expect(T![from]) and
parse_scss_expression_until(...) to run from the wrong place; capture the result
of parse_scss_identifier into a variable, and if it is ParsedSyntax::Absent
(i.e. the binding failed) perform a tiny recovery step that advances to the next
relevant sync tokens (e.g. a small set containing T![from] and T!['{'] similar
to the `@each` rule) before calling p.expect(T![from]) and
parse_scss_expression_until(..., SCSS_FOR_LOWER_BOUND_END_SET) so diagnostics
and position are correct (use expected_scss_for_binding /
expected_scss_expression for diagnostics as currently done).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9bc46fca-8991-48bf-b834-fd6d166269e5
⛔ Files ignored due to path filters (8)
crates/biome_css_factory/src/generated/node_factory.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_factory/src/generated/syntax_factory.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/for.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/for.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_syntax/src/generated/kind.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_syntax/src/generated/macros.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_syntax/src/generated/nodes.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_syntax/src/generated/nodes_mut.rsis excluded by!**/generated/**,!**/generated/**and included by**
📒 Files selected for processing (16)
crates/biome_css_formatter/src/css/any/at_rule.rscrates/biome_css_formatter/src/generated.rscrates/biome_css_formatter/src/scss/statements/for_at_rule.rscrates/biome_css_formatter/src/scss/statements/mod.rscrates/biome_css_formatter/tests/specs/css/scss/at-rule/for.scsscrates/biome_css_parser/src/lexer/mod.rscrates/biome_css_parser/src/lexer/tests.rscrates/biome_css_parser/src/syntax/at_rule/mod.rscrates/biome_css_parser/src/syntax/scss/at_rule/for_at_rule.rscrates/biome_css_parser/src/syntax/scss/at_rule/mod.rscrates/biome_css_parser/src/syntax/scss/mod.rscrates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/for.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/for.scsscrates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rsxtask/codegen/css.ungramxtask/codegen/src/css_kinds_src.rs
a4db11b to
d361224
Compare
d361224 to
d62cf8e
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/biome_css_parser/src/syntax/scss/at_rule/for_at_rule.rs (1)
53-60: Consider returningParsedSyntaxfor consistency.The
parse_scss_for_range_operatorfunction doesn't return aParsedSyntax, unlike most otherparse_*functions. Whilst it works correctly, returningParsedSyntaxwould allow the caller to use.or_add_diagnostic()uniformly and match the codebase convention.That said, for a simple keyword bump this is a minor stylistic point.
♻️ Optional refactor
#[inline] -fn parse_scss_for_range_operator(p: &mut CssParser) { +fn parse_scss_for_range_operator(p: &mut CssParser) -> ParsedSyntax { if p.at(T![to]) || p.at(T![through]) { + let m = p.start(); p.bump_any(); + Present(m.complete(p, SCSS_FOR_RANGE_OPERATOR)) } else { - p.error(expected_scss_for_range_operator(p, p.cur_range())); + Absent } }Then in the caller:
- parse_scss_for_range_operator(p); + parse_scss_for_range_operator(p).or_add_diagnostic(p, expected_scss_for_range_operator);Based on learnings: "Parse rules must take a mutable reference to the parser as their only parameter and return a
ParsedSyntax".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_css_parser/src/syntax/scss/at_rule/for_at_rule.rs` around lines 53 - 60, parse_scss_for_range_operator currently has no return value; change its signature to return ParsedSyntax and return the bump/error result so callers can chain .or_add_diagnostic(). Specifically, update fn parse_scss_for_range_operator(p: &mut CssParser) to return ParsedSyntax, return the result of p.bump_any() when T![to] or T![through] is present, and return the result of p.error(expected_scss_for_range_operator(p, p.cur_range())) in the else branch; keep the same helper expected_scss_for_range_operator and p.cur_range() usage so callers (e.g., sites that will call .or_add_diagnostic()) can use the normalized ParsedSyntax return value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/biome_css_formatter/src/scss/statements/for_at_rule.rs`:
- Around line 10-35: The code is formatting SyntaxResult<_> fields directly and
can panic on recovered/malformed `@for` nodes; after calling node.as_fields()
(ScssForAtRuleFields), `?`-resolve each SyntaxResult field (e.g., lower_bound,
upper_bound, operator, block, variable, from_token, for_token) into concrete
values before calling write! so any parse errors return early instead of causing
a panic; update the code to bind resolved values (let lower_bound =
lower_bound?; etc.) and then pass those resolved values into the write! call
that formats the for_at_rule.
---
Nitpick comments:
In `@crates/biome_css_parser/src/syntax/scss/at_rule/for_at_rule.rs`:
- Around line 53-60: parse_scss_for_range_operator currently has no return
value; change its signature to return ParsedSyntax and return the bump/error
result so callers can chain .or_add_diagnostic(). Specifically, update fn
parse_scss_for_range_operator(p: &mut CssParser) to return ParsedSyntax, return
the result of p.bump_any() when T![to] or T![through] is present, and return the
result of p.error(expected_scss_for_range_operator(p, p.cur_range())) in the
else branch; keep the same helper expected_scss_for_range_operator and
p.cur_range() usage so callers (e.g., sites that will call .or_add_diagnostic())
can use the normalized ParsedSyntax return value.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 8bce789c-a6be-4a39-b261-b4d5e4418f5c
⛔ Files ignored due to path filters (9)
crates/biome_css_factory/src/generated/node_factory.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_factory/src/generated/syntax_factory.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_formatter/tests/specs/css/scss/at-rule/for.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/for.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/for.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_syntax/src/generated/kind.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_syntax/src/generated/macros.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_syntax/src/generated/nodes.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_css_syntax/src/generated/nodes_mut.rsis excluded by!**/generated/**,!**/generated/**and included by**
📒 Files selected for processing (16)
crates/biome_css_formatter/src/css/any/at_rule.rscrates/biome_css_formatter/src/generated.rscrates/biome_css_formatter/src/scss/statements/for_at_rule.rscrates/biome_css_formatter/src/scss/statements/mod.rscrates/biome_css_formatter/tests/specs/css/scss/at-rule/for.scsscrates/biome_css_parser/src/lexer/mod.rscrates/biome_css_parser/src/lexer/tests.rscrates/biome_css_parser/src/syntax/at_rule/mod.rscrates/biome_css_parser/src/syntax/scss/at_rule/for_at_rule.rscrates/biome_css_parser/src/syntax/scss/at_rule/mod.rscrates/biome_css_parser/src/syntax/scss/mod.rscrates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/for.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/for.scsscrates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rsxtask/codegen/css.ungramxtask/codegen/src/css_kinds_src.rs
🚧 Files skipped from review as they are similar to previous changes (12)
- crates/biome_css_formatter/src/scss/statements/mod.rs
- crates/biome_css_parser/src/lexer/tests.rs
- xtask/codegen/src/css_kinds_src.rs
- crates/biome_css_formatter/tests/specs/css/scss/at-rule/for.scss
- crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/for.scss
- crates/biome_css_parser/src/lexer/mod.rs
- crates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rs
- crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/for.scss
- crates/biome_css_parser/src/syntax/scss/mod.rs
- xtask/codegen/css.ungram
- crates/biome_css_formatter/src/generated.rs
- crates/biome_css_formatter/src/css/any/at_rule.rs
| let ScssForAtRuleFields { | ||
| for_token, | ||
| variable, | ||
| from_token, | ||
| lower_bound, | ||
| operator, | ||
| upper_bound, | ||
| block, | ||
| } = node.as_fields(); | ||
|
|
||
| write!( | ||
| f, | ||
| [ | ||
| for_token.format(), | ||
| space(), | ||
| variable.format(), | ||
| space(), | ||
| from_token.format(), | ||
| space(), | ||
| lower_bound.format(), | ||
| space(), | ||
| operator.format(), | ||
| space(), | ||
| upper_bound.format(), | ||
| space(), | ||
| block.format() |
There was a problem hiding this comment.
Avoid a panic on recovered @for nodes.
Line 23 through Line 35 format SyntaxResult<_> fields directly. If the parser recovers a malformed or incomplete @for, this path can panic instead of returning a normal formatting error. Please resolve the fields with ? before write!.
🩹 Suggested fix
let ScssForAtRuleFields {
for_token,
variable,
from_token,
lower_bound,
operator,
upper_bound,
block,
} = node.as_fields();
+ let for_token = for_token?;
+ let variable = variable?;
+ let from_token = from_token?;
+ let lower_bound = lower_bound?;
+ let operator = operator?;
+ let upper_bound = upper_bound?;
+ let block = block?;
write!(
f,
[
for_token.format(),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let ScssForAtRuleFields { | |
| for_token, | |
| variable, | |
| from_token, | |
| lower_bound, | |
| operator, | |
| upper_bound, | |
| block, | |
| } = node.as_fields(); | |
| write!( | |
| f, | |
| [ | |
| for_token.format(), | |
| space(), | |
| variable.format(), | |
| space(), | |
| from_token.format(), | |
| space(), | |
| lower_bound.format(), | |
| space(), | |
| operator.format(), | |
| space(), | |
| upper_bound.format(), | |
| space(), | |
| block.format() | |
| let ScssForAtRuleFields { | |
| for_token, | |
| variable, | |
| from_token, | |
| lower_bound, | |
| operator, | |
| upper_bound, | |
| block, | |
| } = node.as_fields(); | |
| let for_token = for_token?; | |
| let variable = variable?; | |
| let from_token = from_token?; | |
| let lower_bound = lower_bound?; | |
| let operator = operator?; | |
| let upper_bound = upper_bound?; | |
| let block = block?; | |
| write!( | |
| f, | |
| [ | |
| for_token.format(), | |
| space(), | |
| variable.format(), | |
| space(), | |
| from_token.format(), | |
| space(), | |
| lower_bound.format(), | |
| space(), | |
| operator.format(), | |
| space(), | |
| upper_bound.format(), | |
| space(), | |
| block.format() |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/biome_css_formatter/src/scss/statements/for_at_rule.rs` around lines
10 - 35, The code is formatting SyntaxResult<_> fields directly and can panic on
recovered/malformed `@for` nodes; after calling node.as_fields()
(ScssForAtRuleFields), `?`-resolve each SyntaxResult field (e.g., lower_bound,
upper_bound, operator, block, variable, from_token, for_token) into concrete
values before calling write! so any parse errors return early instead of causing
a panic; update the code to bind resolved values (let lower_bound =
lower_bound?; etc.) and then pass those resolved values into the write! call
that formats the for_at_rule.
Summary
Adds SCSS
@forat-rule support to the CSS parser and formatter.Test Plan
@for@forcargo test -p biome_css_parsercargo test -p biome_css_formatter