feat(css): parse scss interpolated selector names#9486
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 SCSS interpolated identifier support across parser, formatter and codegen. New AST types and unions (ScssInterpolatedIdentifier, part list, AnyCssSelectorIdentifier, AnyCssSelectorCustomIdentifier) are introduced; parser helpers for selector-mode interpolations and selector-aware identifier parsing were added; formatter implementations and wiring for the new nodes were generated; several selector/identifier code paths were tightened to use as_css_identifier() before value_token(); tests for SCSS selector interpolation and error cases were added or updated. 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)
📝 Coding Plan
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 Tip CodeRabbit can use Trivy to scan for security misconfigurations and secrets in Infrastructure as Code files.Add a .trivyignore file to your project to customize which findings Trivy reports. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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_parser/src/syntax/scss/identifiers/interpolated_identifier.rs`:
- Around line 45-58: The loop that folds fragments into a
ScssInterpolatedIdentifier (starting after first_fragment.precede(p)) only
checks token kinds and therefore glues fragments across comments/trivia; update
the loop that uses is_at_scss_interpolated_identifier(p) and parse_fragment(p)
to first verify there is no intervening leading trivia/comments between the
previous fragment end and the next fragment start (i.e., ensure adjacency)
before calling parse_fragment and extending the list; use the parser
position/offset or trivia APIs available on p to detect leading comments and
bail out (break) if any leading trivia exists so fragments separated by comments
are not merged.
In `@crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/extend.scss`:
- Line 21: Add a one-line Stylelint suppression immediately before the `@extend`
statement to disable the scss/at-extend-no-missing-placeholder rule for that
line: target the `@extend` .icon-#{$name}; statement and insert a next-line
disable comment for scss/at-extend-no-missing-placeholder so the fixture remains
valid for parser tests without failing lint in CI.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5575d074-cfbc-49f2-89d0-c3f321e31bef
⛔ Files ignored due to path filters (12)
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/extend.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/css/scss/selector/interpolation.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/selector/interpolation.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/extend.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/complex-expressions.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/selector/interpolation.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 (31)
crates/biome_css_analyze/src/lint/correctness/no_unknown_type_selector.rscrates/biome_css_formatter/src/css/any/mod.rscrates/biome_css_formatter/src/css/any/selector_custom_identifier.rscrates/biome_css_formatter/src/css/any/selector_identifier.rscrates/biome_css_formatter/src/css/lists/relative_selector_list.rscrates/biome_css_formatter/src/css/lists/selector_list.rscrates/biome_css_formatter/src/css/selectors/complex_selector.rscrates/biome_css_formatter/src/generated.rscrates/biome_css_formatter/src/scss/any/interpolated_identifier_part.rscrates/biome_css_formatter/src/scss/any/mod.rscrates/biome_css_formatter/src/scss/lists/interpolated_identifier_part_list.rscrates/biome_css_formatter/src/scss/lists/mod.rscrates/biome_css_formatter/src/scss/value/interpolated_identifier.rscrates/biome_css_formatter/src/scss/value/mod.rscrates/biome_css_formatter/tests/specs/css/scss/at-rule/extend.scsscrates/biome_css_formatter/tests/specs/css/scss/selector/interpolation.scsscrates/biome_css_parser/src/syntax/scss/expression/interpolation.rscrates/biome_css_parser/src/syntax/scss/expression/mod.rscrates/biome_css_parser/src/syntax/scss/identifiers/interpolated_identifier.rscrates/biome_css_parser/src/syntax/scss/identifiers/interpolated_selector.rscrates/biome_css_parser/src/syntax/scss/identifiers/mod.rscrates/biome_css_parser/src/syntax/scss/mod.rscrates/biome_css_parser/src/syntax/scss/selector.rscrates/biome_css_parser/src/syntax/selector/mod.rscrates/biome_css_parser/tests/css_test_suite/error/scss/selector/interpolation.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/extend.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/expression/complex-expressions.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/selector/interpolation.scsscrates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rsxtask/codegen/css.ungramxtask/codegen/src/css_kinds_src.rs
crates/biome_css_parser/src/syntax/scss/identifiers/interpolated_identifier.rs
Show resolved
Hide resolved
crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/extend.scss
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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_parser/src/syntax/selector/mod.rs`:
- Around line 544-556: The pseudo-element and pseudo-class parsers should use
the fragment-only parser to ensure they produce a plain CssIdentifier rather
than an ScssInterpolatedIdentifier: replace calls to parse_selector_identifier
with parse_selector_identifier_fragment inside parse_pseudo_element_identifier
and parse_pseudo_class_identifier so they no longer return SCSS interpolation
variants (ScssInterpolatedIdentifier) or AnyCssSelectorCustomIdentifier,
preserving the grammar's requirement of name: CssIdentifier.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 562afba1-e165-465c-bc7b-6952912d27ff
📒 Files selected for processing (5)
crates/biome_css_parser/src/syntax/scss/expression/interpolation.rscrates/biome_css_parser/src/syntax/scss/identifiers/interpolated_selector.rscrates/biome_css_parser/src/syntax/scss/identifiers/mod.rscrates/biome_css_parser/src/syntax/scss/mod.rscrates/biome_css_parser/src/syntax/selector/mod.rs
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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_parser/src/syntax/selector/pseudo_class/identifier.rs`:
- Line 4: The pseudo-class identifier code is calling the plain
parse_selector_identifier_fragment (losing SCSS interpolation support); replace
that call and import with the SCSS-aware identifier parser (the function used
elsewhere for SCSS parsing, e.g., parse_selector_identifier_fragment_scss or the
project’s SCSS-aware variant) so pseudo-class identifiers again accept
interpolation and emit the correct CST shape; update the use line to import the
SCSS-aware function and change the call in identifier.rs (the invocation on line
with parse_selector_identifier_fragment) to that SCSS-aware function.
In `@crates/biome_css_parser/src/syntax/selector/pseudo_element.rs`:
- Around line 7-8: The code currently calls parse_selector_identifier_fragment
for pseudo-element identifiers (referenced as
parse_selector_identifier_fragment) which bypasses SCSS interpolation handling;
update the pseudo-element parsing to use the SCSS-aware parse path (e.g., call
parse_selector or the SCSS-aware selector parser used elsewhere) instead of
parse_selector_identifier_fragment so interpolation tokens are recognized and
recovered correctly (adjust any surrounding token handling like
eat_or_recover_selector_function_close_token and
recover_selector_function_parameter as needed to fit the new parser call).
In
`@crates/biome_css_parser/tests/css_test_suite/ok/scss/selector/interpolation.scss`:
- Around line 33-35: The SCSS rule with selector ".foo-#{$name} #{$second}"
contains an empty block which triggers the block-no-empty rule; add a meaningful
placeholder declaration (for example a harmless property like `/* keep */` is
not allowed as code here, so add a real declaration such as `display: block;` or
another non-breaking property) inside the rule block to avoid an empty rule
while preserving selector intent; update the rule in the test fixture containing
the selector ".foo-#{$name} #{$second}" to include the declaration so the test
no longer trips block-no-empty.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 42fe258c-dfb2-4e9e-83a4-fc18bb2f92a7
⛔ Files ignored due to path filters (3)
crates/biome_css_formatter/tests/specs/css/scss/selector/interpolation.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/selector/interpolation.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/selector/interpolation.scss.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (5)
crates/biome_css_formatter/tests/specs/css/scss/selector/interpolation.scsscrates/biome_css_parser/src/syntax/selector/pseudo_class/identifier.rscrates/biome_css_parser/src/syntax/selector/pseudo_element.rscrates/biome_css_parser/tests/css_test_suite/error/scss/selector/interpolation.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/selector/interpolation.scss
🚧 Files skipped from review as they are similar to previous changes (1)
- crates/biome_css_formatter/tests/specs/css/scss/selector/interpolation.scss
Summary
Adds a focused first slice of SCSS selector interpolation support to the CSS parser and
formatter.
This PR is intentionally scoped to selector names and selector-boundary behavior rather than full
SCSS interpolation support.
Test Plan