Skip to content

feat(css): support SCSS qualified names in values and function calls#9096

Merged
denbezrukov merged 3 commits intonextfrom
db/scss-qualified-names-dedicated
Feb 17, 2026
Merged

feat(css): support SCSS qualified names in values and function calls#9096
denbezrukov merged 3 commits intonextfrom
db/scss-qualified-names-dedicated

Conversation

@denbezrukov
Copy link
Contributor

@denbezrukov denbezrukov commented Feb 16, 2026

This PR was prepared with AI assistance (Codex/ChatGPT) for planning and PR text
drafting. I reviewed the final code and test changes manually.

Summary

Added support for SCSS qualified names in values and function names.

This slice introduces parsing/formatting support for patterns like:

  • math.div(10px, 2)
  • map.get($map, a)
  • map.$default

I intentionally kept ScssQualifiedName separate from ScssNamespacedIdentifier instead
of reusing one node for both forms.

They represent different syntax roles:

  • ScssNamespacedIdentifier models declaration names like ns.$var (SCSS declaration
    context, $ member only).
  • ScssQualifiedName models value/function qualified names like math.div, map.get,
    and map.$default (value/function context, member can be either CssIdentifier or
    ScssIdentifier).

Test Plan

Green CI

@changeset-bot
Copy link

changeset-bot bot commented Feb 16, 2026

⚠️ No Changeset found

Latest commit: 1727bae

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions bot added A-Linter Area: linter A-Parser Area: parser A-Formatter Area: formatter A-Tooling Area: internal tools L-CSS Language: CSS L-Grit Language: GritQL labels Feb 16, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds SCSS qualified-name support and wires it through parser, formatter, lints, tests and GRIT mappings. Introduces ScssQualifiedName and AnyCssFunctionName grammar nodes, updates CSS function parsing to accept SCSS-qualified names, adjusts lint code to extract function-name tokens via identifier variants, generates formatters and generated.rs wiring for the new nodes, adds SCSS tests for qualified names, and updates kind-by-name mappings.

Possibly related PRs

Suggested reviewers

  • ematipico
  • dyc3
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (20 files):

⚔️ crates/biome_css_analyze/src/lint/correctness/no_unknown_function.rs (content)
⚔️ crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs (content)
⚔️ crates/biome_css_factory/src/generated/node_factory.rs (content)
⚔️ crates/biome_css_factory/src/generated/syntax_factory.rs (content)
⚔️ crates/biome_css_formatter/src/css/any/mod.rs (content)
⚔️ crates/biome_css_formatter/src/css/any/value.rs (content)
⚔️ crates/biome_css_formatter/src/generated.rs (content)
⚔️ crates/biome_css_formatter/src/scss/any/mod.rs (content)
⚔️ crates/biome_css_formatter/src/scss/auxiliary/mod.rs (content)
⚔️ crates/biome_css_formatter/tests/specs/css/scss/declaration/mixed.scss.snap (content)
⚔️ crates/biome_css_parser/src/syntax/mod.rs (content)
⚔️ crates/biome_css_parser/src/syntax/scss/mod.rs (content)
⚔️ crates/biome_css_parser/src/syntax/value/function.rs (content)
⚔️ crates/biome_css_syntax/src/generated/kind.rs (content)
⚔️ crates/biome_css_syntax/src/generated/macros.rs (content)
⚔️ crates/biome_css_syntax/src/generated/nodes.rs (content)
⚔️ crates/biome_css_syntax/src/generated/nodes_mut.rs (content)
⚔️ crates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rs (content)
⚔️ xtask/codegen/css.ungram (content)
⚔️ xtask/codegen/src/css_kinds_src.rs (content)

These conflicts must be resolved before merging into next.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding SCSS qualified name support in values and function calls, which is the primary objective of this changeset.
Description check ✅ Passed The description is directly related to the changeset, explaining the feature additions, design decisions (keeping ScssQualifiedName separate from ScssNamespacedIdentifier), and test coverage approach.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch db/scss-qualified-names-dedicated

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
crates/biome_css_analyze/src/lint/correctness/no_unknown_function.rs (1)

81-84: SCSS qualified function names are silently skipped.

When node.name() returns AnyCssFunctionName::ScssQualifiedName, as_css_identifier() returns None, so the rule bails out early. This is a sensible default (e.g., math.div shouldn't be flagged as unknown), but it means all SCSS namespaced functions bypass the check — including genuinely misspelled ones like math.divv(). Worth a follow-up to validate the member portion if you want tighter coverage.

crates/biome_css_parser/src/syntax/scss/mod.rs (1)

65-72: parse_scss_function_name should return ParsedSyntax to match parser conventions.

Every other parse_* function in the codebase returns ParsedSyntax—this is the only one that returns (). Even though the current call site doesn't use the result, it's an easy fix to keep the API consistent and future-proof.

♻️ Suggested change
-pub(crate) fn parse_scss_function_name(p: &mut CssParser) {
+pub(crate) fn parse_scss_function_name(p: &mut CssParser) -> ParsedSyntax {
     if is_at_scss_qualified_name(p) {
-        parse_scss_qualified_name(p).ok();
+        parse_scss_qualified_name(p)
     } else {
-        parse_regular_identifier(p).ok();
+        parse_regular_identifier(p)
     }
 }

@codspeed-hq
Copy link

codspeed-hq bot commented Feb 16, 2026

Merging this PR will not alter performance

✅ 29 untouched benchmarks
⏩ 126 skipped benchmarks1


Comparing db/scss-qualified-names-dedicated (1727bae) with next (4804acf)

Open in CodSpeed

Footnotes

  1. 126 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@denbezrukov denbezrukov force-pushed the db/scss-qualified-names-dedicated branch 2 times, most recently from e619d77 to 24f3296 Compare February 16, 2026 13:03
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@crates/biome_css_parser/src/syntax/scss/mod.rs`:
- Around line 52-63: The branch handling a dollar-sign callable in
is_at_scss_qualified_name_function is dead/unnecessary; after confirming
is_at_scss_qualified_name(p) simply return p.nth_at(3, T!['(']) and remove the
p.nth_at(2, T![$]) conditional and the is_nth_at_identifier(p, 3) check (or
alternately keep the branch but add a clear comment about intentionally allowing
ns.$func() as tolerant error handling); update
is_at_scss_qualified_name_function to only perform the parentheses lookahead so
the redundant ns.$identifier handling is eliminated.
🧹 Nitpick comments (1)
crates/biome_css_parser/src/syntax/scss/mod.rs (1)

65-72: parse_scss_function_name returns () rather than ParsedSyntax.

This works as a fire-and-forget dispatch helper inside parse_function's marker, but it diverges from the project convention that parse helpers return ParsedSyntax. If a future caller needs the result (e.g. for error recovery), it'll require a signature change. Low risk for now, but worth noting.

Based on learnings: "Parse rules must take a mutable reference to the parser as their only parameter and return a ParsedSyntax".

♻️ Optional: return ParsedSyntax for consistency
-pub(crate) fn parse_scss_function_name(p: &mut CssParser) {
+pub(crate) fn parse_scss_function_name(p: &mut CssParser) -> ParsedSyntax {
     if is_at_scss_qualified_name(p) {
-        parse_scss_qualified_name(p).ok();
+        parse_scss_qualified_name(p)
     } else {
-        parse_regular_identifier(p).ok();
+        parse_regular_identifier(p)
     }
 }

Callers that discard the result can still call .ok().

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@crates/biome_css_parser/src/syntax/scss/mod.rs`:
- Around line 65-72: parse_scss_function_name currently returns () while all
other parse_... helpers return ParsedSyntax; update parse_scss_function_name to
return ParsedSyntax and propagate the results of the chosen parser so callers
can detect failures: call is_at_scss_qualified_name(p) and if true return
parse_scss_qualified_name(p) otherwise return parse_regular_identifier(p),
ensuring the function signature and return type use ParsedSyntax and not unit.
Reference: parse_scss_function_name, is_at_scss_qualified_name,
parse_scss_qualified_name, parse_regular_identifier, ParsedSyntax.
🧹 Nitpick comments (1)
crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs (1)

117-139: Minor style inconsistency between the two extraction paths.

Lines 121–122 use .as_css_identifier().and_then(|name| name.value_token().ok())? while Lines 137–138 use .as_css_identifier()?.value_token().ok()?. Both are equivalent, but using the same style would be tidier.

@denbezrukov denbezrukov force-pushed the db/scss-qualified-names-dedicated branch from 24f3296 to 5b46088 Compare February 16, 2026 13:34
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
crates/biome_css_parser/src/syntax/scss/mod.rs (1)

52-55: is_at_scss_qualified_name_function only works for non-$ members — this is fine, but worth a comment.

The lookahead p.nth_at(3, T!['(']) correctly matches module.func( (3 tokens before (), but won't match module.$func( (4 tokens). Since $-prefixed SCSS variables aren't callable, this is correct behaviour. A brief inline comment would prevent future confusion, especially since is_at_scss_qualified_name does match the $ form.

Suggested comment
 #[inline]
 pub(crate) fn is_at_scss_qualified_name_function(p: &mut CssParser) -> bool {
+    // Only matches `module.func(` — the `module.$var` form has 4 tokens
+    // before `(`, but $-prefixed SCSS variables are not callable anyway.
     is_at_scss_qualified_name(p) && p.nth_at(3, T!['('])
 }
crates/biome_css_parser/src/syntax/mod.rs (1)

305-306: Note: inconsistent feature-gating style between is_at_scss_identifier and is_at_scss_qualified_name.

is_at_scss_identifier (line 284) is not gated on CssSyntaxFeatures::Scss — it relies on parse_exclusive_syntax at parse time (line 300). In contrast, is_at_scss_qualified_name is gated at detection and parse time. Both approaches work, but the inconsistency could trip up future contributors. Not blocking — just flagging for awareness.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@crates/biome_css_parser/src/syntax/scss/mod.rs`:
- Around line 31-33: The lookahead in is_at_scss_qualified_name currently allows
`ns.$` because p.nth_at(2, T![$]) doesn't ensure an identifier follows the `$`;
update the condition in is_at_scss_qualified_name so the `$` branch also
requires a trailing identifier (use is_nth_at_identifier with the next offset),
e.g. require p.nth_at(2, T![$]) && is_nth_at_identifier(p, 3), while keeping the
existing identifier branch (is_nth_at_identifier(p, 2)) and the initial
is_at_identifier(p) check.

@denbezrukov denbezrukov merged commit 11784e5 into next Feb 17, 2026
16 checks passed
@denbezrukov denbezrukov deleted the db/scss-qualified-names-dedicated branch February 17, 2026 09:16
denbezrukov added a commit that referenced this pull request Feb 19, 2026
@Netail Netail added the L-SCSS Language: SCSS label Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Formatter Area: formatter A-Linter Area: linter A-Parser Area: parser A-Tooling Area: internal tools L-CSS Language: CSS L-Grit Language: GritQL L-SCSS Language: SCSS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants