feat(css): support preserved SCSS custom property - #11029
Conversation
|
✅ Organic activityNo automation signals detected in the analyzed events. This is an automated analysis by AgentScan |
c1627f4 to
a0df8e1
Compare
Parser conformance results onjs/262
jsx/babel
markdown/commonmark
symbols/microsoft
ts/babel
ts/microsoft
|
Merging this PR will not alter performance
Comparing Footnotes
|
WalkthroughThe change adds structured parsing and formatting for raw CSS and SCSS custom-property values, including nested containers, delimiters, interpolation, comments, URLs, and Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ 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 (2)
crates/biome_css_parser/src/lexer/scan_cursor.rs (1)
509-518: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winThird copy of the CSS-whitespace byte set — worth a shared helper.
b'\t' | b' ' | b'\n' | b'\r' | 0x0Cnow shows up inskip_whitespace(new) and inis_scss_raw_url_body's whitespace branch (new), on top of the pre-existing copy inconsume_escape_sequence. Three copies of a spec-defined character class is asking for silent drift the next time someone tweaks whitespace handling.♻️ Proposed helper
+#[inline] +fn is_css_whitespace_byte(byte: u8) -> bool { + matches!(byte, b'\t' | b' ' | b'\n' | b'\r' | 0x0C) +} + fn skip_whitespace(&mut self) { - while self - .current_byte() - .is_some_and(|byte| matches!(byte, b'\t' | b' ' | b'\n' | b'\r' | 0x0C)) - { + while self.current_byte().is_some_and(is_css_whitespace_byte) { self.advance(1); } }Also applies to: 1007-1041
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/biome_css_parser/src/lexer/scan_cursor.rs` around lines 509 - 518, Introduce a shared helper for the CSS-whitespace byte set and reuse it in skip_whitespace, is_scss_raw_url_body, and consume_escape_sequence. Remove the duplicated inline matches while preserving each caller’s existing whitespace-handling behavior.crates/biome_css_parser/src/syntax/at_rule/supports/mod.rs (1)
371-377: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExplain why a preceding block comment waives the empty-value diagnostic.
The
!p.source().has_preceding_block_comment()guard is non-obvious — worth a//comment stating why a comment-only value (e.g.@supports (--foo: /* note */)) shouldn't getexpected_component_value, so nobody "simplifies" this away later.Based on path instructions:
**/*.rs: "//provides rationale; do not narrate change history or address reviewers."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/biome_css_parser/src/syntax/at_rule/supports/mod.rs` around lines 371 - 377, In the empty-value diagnostic condition within the supports at-rule parser, add a concise // comment explaining that a preceding block comment represents a comment-only value, such as `@supports` (--foo: /* note */), and therefore must suppress expected_component_value. Keep the !p.source().has_preceding_block_comment() guard unchanged.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@crates/biome_css_parser/src/lexer/scan_cursor.rs`:
- Around line 509-518: Introduce a shared helper for the CSS-whitespace byte set
and reuse it in skip_whitespace, is_scss_raw_url_body, and
consume_escape_sequence. Remove the duplicated inline matches while preserving
each caller’s existing whitespace-handling behavior.
In `@crates/biome_css_parser/src/syntax/at_rule/supports/mod.rs`:
- Around line 371-377: In the empty-value diagnostic condition within the
supports at-rule parser, add a concise // comment explaining that a preceding
block comment represents a comment-only value, such as `@supports` (--foo: /* note
*/), and therefore must suppress expected_component_value. Keep the
!p.source().has_preceding_block_comment() guard unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0160c680-b2ff-4aeb-a640-6bb37dd052d3
⛔ Files ignored due to path filters (28)
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/prettier/scss/comments/custom-properties.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/prettier/scss/variables/apply-rule.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/prettier/scss/variables/postcss-8-improment.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/scss/declaration/interpolated-custom-property-nested-properties.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_formatter/tests/specs/scss/declaration/raw-custom-property-values.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/property/scss_exclusive_values.css.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/supports-custom-property-missing-value.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/supports-interpolated-property-missing-value.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/interpolated-custom-property-unclosed.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/raw-custom-property-recovery.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/error/scss/value/if-disambiguation-recovery.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/declaration-block-interpolation.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/page.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/supports-expression.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/interpolated-custom-property-nested-properties.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/interpolated-custom-property-values.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/interpolation.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/raw-custom-property-values.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/valid-modern-values.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/value/css-if-function.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/value/if-disambiguation.scss.snapis excluded by!**/*.snapand included by**crates/biome_css_parser/tests/css_test_suite/ok/scss/value/interpolated-value-boundary.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 (56)
crates/biome_css_analyze/src/lint/a11y/use_generic_font_names.rscrates/biome_css_analyze/src/lint/correctness/no_invalid_grid_areas.rscrates/biome_css_analyze/src/lint/suspicious/no_duplicate_font_names.rscrates/biome_css_formatter/src/comments.rscrates/biome_css_formatter/src/css/any/custom_property_component.rscrates/biome_css_formatter/src/css/any/generic_property_value_or_expression.rscrates/biome_css_formatter/src/css/any/mod.rscrates/biome_css_formatter/src/css/auxiliary/custom_property_braced_block.rscrates/biome_css_formatter/src/css/auxiliary/custom_property_bracketed_block.rscrates/biome_css_formatter/src/css/auxiliary/custom_property_delimiter.rscrates/biome_css_formatter/src/css/auxiliary/custom_property_function.rscrates/biome_css_formatter/src/css/auxiliary/custom_property_parenthesized_block.rscrates/biome_css_formatter/src/css/auxiliary/custom_property_value.rscrates/biome_css_formatter/src/css/auxiliary/mod.rscrates/biome_css_formatter/src/css/lists/custom_property_component_list.rscrates/biome_css_formatter/src/css/lists/mod.rscrates/biome_css_formatter/src/css/properties/generic_property.rscrates/biome_css_formatter/src/css/value/number.rscrates/biome_css_formatter/src/css/value/regular_dimension.rscrates/biome_css_formatter/src/css/value/unknown_dimension.rscrates/biome_css_formatter/src/generated.rscrates/biome_css_formatter/src/utils/custom_property.rscrates/biome_css_formatter/src/utils/mod.rscrates/biome_css_formatter/tests/specs/scss/declaration/interpolated-custom-property-nested-properties.scsscrates/biome_css_formatter/tests/specs/scss/declaration/raw-custom-property-values.scsscrates/biome_css_parser/src/lexer/mod.rscrates/biome_css_parser/src/lexer/scan_cursor.rscrates/biome_css_parser/src/lexer/tests.rscrates/biome_css_parser/src/syntax/at_rule/keyframes.rscrates/biome_css_parser/src/syntax/at_rule/supports/mod.rscrates/biome_css_parser/src/syntax/mod.rscrates/biome_css_parser/src/syntax/property/custom.rscrates/biome_css_parser/src/syntax/property/mod.rscrates/biome_css_parser/src/syntax/scss/at_rule/import_at_rule.rscrates/biome_css_parser/src/syntax/scss/declaration/nesting.rscrates/biome_css_parser/src/syntax/scss/expression/interpolation.rscrates/biome_css_parser/src/syntax/scss/value/any.rscrates/biome_css_parser/src/syntax/scss/value/interpolated_string.rscrates/biome_css_parser/src/syntax/scss/value/interpolated_value.rscrates/biome_css_parser/src/syntax/selector/attribute.rscrates/biome_css_parser/src/syntax/selector/pseudo_class/function_value_list.rscrates/biome_css_parser/src/syntax/value/dimension.rscrates/biome_css_parser/src/syntax/value/function/call.rscrates/biome_css_parser/src/syntax/value/url.rscrates/biome_css_parser/src/token_source.rscrates/biome_css_parser/tests/css_test_suite/error/scss/at-rule/supports-custom-property-missing-value.scsscrates/biome_css_parser/tests/css_test_suite/error/scss/declaration/raw-custom-property-recovery.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/interpolated-custom-property-nested-properties.scsscrates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/raw-custom-property-values.scsscrates/biome_css_semantic/src/events.rscrates/biome_css_semantic/src/semantic_model/mod.rscrates/biome_css_semantic/src/semantic_model/model.rscrates/biome_css_semantic/src/tests/eq.rscrates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rsxtask/codegen/css.ungramxtask/codegen/src/css_kinds_src.rs
Summary
Adds structured parsing and formatting for preserved SCSS custom-property values.
Custom-property values remain CSS text instead of being parsed as SassScript. Only interpolation evaluates Sass expressions:
The new syntax model supports identifiers, numbers, dimensions, delimiters, strings, URLs, interpolation, functions, balanced blocks, comments, and
!important. It is also used for custom properties in@supports.The formatter preserves source-sensitive raw content, while the semantic model compares the structured values correctly.
Test Plan