Skip to content

feat(css_formatter): improve SCSS map formatting parity - #10076

Merged
denbezrukov merged 8 commits into
mainfrom
db/prettier-compare
Apr 22, 2026
Merged

denbezrukov merged 8 commits into
mainfrom
db/prettier-compare

Conversation

@denbezrukov

Copy link
Copy Markdown
Contributor

This PR was created with AI assistance (Codex).

Summary

Improve SCSS map formatting parity with Prettier by refactoring map formatting around shared SCSS map context.

Concrete output changes:

  • Inline single-pair map keys now stay compact:
$map: (
  ("key": "value"): "hello world",
);
  • Nested maps used as values now expand more like Prettier:
$map: (
  key: (
    other-key: other-other-value,
  ),
);
  • Trailing block comments after the last map comma are preserved in place:
    $map: (
      a: b, /* end */
    );

Test Plan

cargo test -p biome_css_formatter

@changeset-bot

changeset-bot Bot commented Apr 21, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 5b66817

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-Formatter Area: formatter L-CSS Language: CSS and super languages labels Apr 21, 2026
@denbezrukov denbezrukov changed the title Db/prettier compare feat(css_formatter): improve SCSS map formatting parity Apr 21, 2026
@coderabbitai

coderabbitai Bot commented Apr 21, 2026 •

Copy link
Copy Markdown
Contributor

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
  • ✅ Review completed - (🔄 Check again to review again)

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1bc6294d-d98f-4764-951b-2693391aabde

📥 Commits

Reviewing files that changed from the base of the PR and between 65295a6 and 5b66817.

📒 Files selected for processing (1)
  • crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs

Walkthrough

Adds SCSS-map-aware utilities and context queries, a ScssMapLayout helper with a stable GroupId to control grouping, expansion, trailing-comma and dangling-comment placement for SCSS map expressions, and updates list/map/parenthesized formatters to use that context for breaking and trailing-comma behaviour. Adds a specialised comment-placement handler to attach inline/trailing comments in ScssMapExpression while preserving already-correct attachments. Adds multiple SCSS test fixtures exercising map comments, contexts, expansion and values.

Possibly related PRs

Suggested reviewers

  • ematipico
  • dyc3
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarises the main change: improving SCSS map formatting alignment with Prettier through refactoring around shared map context.
Description check ✅ Passed The description is directly related to the changeset, providing concrete examples of formatting improvements, explaining the refactoring strategy, and specifying the test plan.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch db/prettier-compare

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (6)
crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs (2)

32-33: Tiny nit: redundant conjunct.

is_outer_parenthesized_map_value is true iff outer_payload_kind.is_some(), so is_outer_parenthesized_map_value && outer_payload_kind == Some(Map) simplifies to the second check alone. Same redundancy on line 49.

♻️ Proposed simplification
-        let should_expand = is_outer_parenthesized_map_value
-            && outer_payload_kind == Some(ScssMapOuterParenthesizedValuePayloadKind::Map);
+        let should_expand =
+            outer_payload_kind == Some(ScssMapOuterParenthesizedValuePayloadKind::Map);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs`
around lines 32 - 33, The boolean expression setting should_expand is redundant:
remove the unnecessary is_outer_parenthesized_map_value conjunct and replace the
conjunction with a direct comparison of outer_payload_kind to
Some(ScssMapOuterParenthesizedValuePayloadKind::Map) (i.e., set should_expand =
outer_payload_kind == Some(...)); apply the identical simplification to the
other occurrence that currently combines is_outer_parenthesized_map_value with
outer_payload_kind == Some(...).

32-59: Trailing comma block is unreachable — intentional, but could simplify.

Your analysis is spot on: given only three ScssMapOuterParenthesizedValuePayloadKind variants (Scalar, List, Map), every case blocks should_print_trailing_comma:

  • Scalar → blocked by outer_payload_kind != Some(Scalar)
  • List/Map → blocked by inner_expression_owns_trailing_comma

The comments (lines 35–40) make clear this is intentional: Scalar payloads must never gain a trailing comma (singleton list semantics), and List/Map handle their own trailing commas elsewhere. So the trailing_comma block and if_group_breaks machinery are dead code.

If this is scaffolding for a future variant, a brief note would help. Otherwise, consider removing the trailing_comma block or simplifying the condition for clarity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs`
around lines 32 - 59, The trailing-comma branch is unreachable given the three
ScssMapOuterParenthesizedValuePayloadKind variants; remove the dead
`trailing_comma` block (and its use of `if_group_breaks`/`with_group_id`) or
replace it with a single-line explanatory comment to indicate this is
intentional scaffolding; update or remove the `should_print_trailing_comma`
and/or `inner_expression_owns_trailing_comma` locals as needed to avoid unused
variable warnings and keep references to
`ScssMapOuterParenthesizedValuePayloadKind`,
`inner_expression_owns_trailing_comma`, `should_print_trailing_comma`, and
`trailing_comma` to locate the code to change.
crates/biome_css_formatter/src/scss/auxiliary/map_expression_pair.rs (1)

63-77: Nitpick: import AnyScssExpressionItem for readability.

The fully-qualified paths on lines 72-74 are a touch noisy — AnyScssExpression is already imported on line 4, so bringing in AnyScssExpressionItem alongside keeps the match arms tidy.

♻️ Suggestion
-use biome_css_syntax::{AnyScssExpression, ScssMapExpressionPair, ScssMapExpressionPairFields};
+use biome_css_syntax::{
+    AnyScssExpression, AnyScssExpressionItem, ScssMapExpressionPair, ScssMapExpressionPairFields,
+};
@@
-    ) || unwrap_single_expression_item(value).is_some_and(|item| {
-        matches!(
-            item,
-            biome_css_syntax::AnyScssExpressionItem::ScssListExpression(_)
-                | biome_css_syntax::AnyScssExpressionItem::ScssMapExpression(_)
-                | biome_css_syntax::AnyScssExpressionItem::ScssParenthesizedExpression(_)
-        )
-    })
+    ) || unwrap_single_expression_item(value).is_some_and(|item| {
+        matches!(
+            item,
+            AnyScssExpressionItem::ScssListExpression(_)
+                | AnyScssExpressionItem::ScssMapExpression(_)
+                | AnyScssExpressionItem::ScssParenthesizedExpression(_)
+        )
+    })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression_pair.rs` around
lines 63 - 77, Import biome_css_syntax::AnyScssExpressionItem and replace the
fully-qualified uses in value_manages_its_own_breaking (the match inside
unwrap_single_expression_item closure) with the shorter
AnyScssExpressionItem::ScssListExpression, ::ScssMapExpression, and
::ScssParenthesizedExpression variants to improve readability while leaving
logic intact.
crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs (2)

61-69: Nitpick: compute dangling_comments once.

dangling_comments(self.node.syntax()) is called twice in this predicate (plus is_empty() is redundant with the all check — an empty iterator would make all vacuously true, but you already guard with pairs().len() > 0).

♻️ Suggestion
 fn has_inline_closing_comments(&self, f: &CssFormatter) -> bool {
-    self.node.pairs().len() > 0
-        && !f.context().comments().dangling_comments(self.node.syntax()).is_empty()
-        && f.context()
-            .comments()
-            .dangling_comments(self.node.syntax())
-            .iter()
-            .all(|comment| comment.kind().is_inline() && comment.lines_before() == 0)
+    if self.node.pairs().len() == 0 {
+        return false;
+    }
+    let comments = f.context().comments();
+    let dangling = comments.dangling_comments(self.node.syntax());
+    !dangling.is_empty()
+        && dangling
+            .iter()
+            .all(|comment| comment.kind().is_inline() && comment.lines_before() == 0)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs` around lines
61 - 69, In has_inline_closing_comments, avoid calling
f.context().comments().dangling_comments(self.node.syntax()) multiple times and
drop the redundant is_empty() check; compute let dangling =
f.context().comments().dangling_comments(self.node.syntax()) once, then check
self.node.pairs().len() > 0 && dangling.iter().all(|comment|
comment.kind().is_inline() && comment.lines_before() == 0) so the predicate uses
the cached dangling_comments variable (referenced in the
has_inline_closing_comments method and self.node.pairs()).

13-27: Tiny inefficiency: GroupId allocated but unused here.

handles_dangling_comments never touches self.group_id, yet fmt_dangling_comments still allocates one via f.group_id(...). Not a bug, but a new ScssMapLayout constructor (or free function) that takes only the node would avoid the churn.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs` around lines
13 - 27, The call in fmt_dangling_comments creates a GroupId via f.group_id(...)
only to pass it into ScssMapLayout::new even though handles_dangling_comments
does not use that GroupId; change ScssMapLayout API or call site so no GroupId
is allocated: add a constructor or helper like
ScssMapLayout::new_from_node(node) or ScssMapLayout::for_node(node) (or a free
function) that accepts only &ScssMapExpression and use that in
fmt_dangling_comments when invoking handles_dangling_comments, leaving the
existing GroupId-taking constructor for callers that need grouping.
crates/biome_css_formatter/src/comments.rs (1)

101-120: Optional: dedupe the three-identical-dispatch-arms.

All three text-position arms run the exact same handler chain. Since this file already had the pattern, it's no regression, but the duplication grows with every new handler. A tiny refactor would pay off next time someone adds one.

♻️ Suggestion
// Outside the match, or via a single arm:
match comment.text_position() {
    CommentTextPosition::EndOfLine
    | CommentTextPosition::OwnLine
    | CommentTextPosition::SameLine => handle_scss_map_trailing_separator_comment(comment)
        .or_else(handle_function_comment)
        .or_else(handle_generic_property_comment)
        .or_else(handle_declaration_name_comment)
        .or_else(handle_complex_selector_comment)
        .or_else(handle_global_suppression),
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/comments.rs` around lines 101 - 120, The three
match arms for comment.text_position() (CommentTextPosition::EndOfLine,
::OwnLine, ::SameLine) all invoke the same handler chain
(handle_scss_map_trailing_separator_comment, handle_function_comment,
handle_generic_property_comment, handle_declaration_name_comment,
handle_complex_selector_comment, handle_global_suppression); refactor by
collapsing those three arms into a single pattern (e.g.,
CommentTextPosition::EndOfLine | CommentTextPosition::OwnLine |
CommentTextPosition::SameLine) that calls the shared chain, or alternatively
assign the chain to a local variable or helper function and call it from the
single arm to avoid duplication while preserving the same behavior.
🤖 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_formatter/src/comments.rs`:
- Around line 101-120: The three match arms for comment.text_position()
(CommentTextPosition::EndOfLine, ::OwnLine, ::SameLine) all invoke the same
handler chain (handle_scss_map_trailing_separator_comment,
handle_function_comment, handle_generic_property_comment,
handle_declaration_name_comment, handle_complex_selector_comment,
handle_global_suppression); refactor by collapsing those three arms into a
single pattern (e.g., CommentTextPosition::EndOfLine |
CommentTextPosition::OwnLine | CommentTextPosition::SameLine) that calls the
shared chain, or alternatively assign the chain to a local variable or helper
function and call it from the single arm to avoid duplication while preserving
the same behavior.

In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression_pair.rs`:
- Around line 63-77: Import biome_css_syntax::AnyScssExpressionItem and replace
the fully-qualified uses in value_manages_its_own_breaking (the match inside
unwrap_single_expression_item closure) with the shorter
AnyScssExpressionItem::ScssListExpression, ::ScssMapExpression, and
::ScssParenthesizedExpression variants to improve readability while leaving
logic intact.

In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs`:
- Around line 61-69: In has_inline_closing_comments, avoid calling
f.context().comments().dangling_comments(self.node.syntax()) multiple times and
drop the redundant is_empty() check; compute let dangling =
f.context().comments().dangling_comments(self.node.syntax()) once, then check
self.node.pairs().len() > 0 && dangling.iter().all(|comment|
comment.kind().is_inline() && comment.lines_before() == 0) so the predicate uses
the cached dangling_comments variable (referenced in the
has_inline_closing_comments method and self.node.pairs()).
- Around line 13-27: The call in fmt_dangling_comments creates a GroupId via
f.group_id(...) only to pass it into ScssMapLayout::new even though
handles_dangling_comments does not use that GroupId; change ScssMapLayout API or
call site so no GroupId is allocated: add a constructor or helper like
ScssMapLayout::new_from_node(node) or ScssMapLayout::for_node(node) (or a free
function) that accepts only &ScssMapExpression and use that in
fmt_dangling_comments when invoking handles_dangling_comments, leaving the
existing GroupId-taking constructor for callers that need grouping.

In `@crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs`:
- Around line 32-33: The boolean expression setting should_expand is redundant:
remove the unnecessary is_outer_parenthesized_map_value conjunct and replace the
conjunction with a direct comparison of outer_payload_kind to
Some(ScssMapOuterParenthesizedValuePayloadKind::Map) (i.e., set should_expand =
outer_payload_kind == Some(...)); apply the identical simplification to the
other occurrence that currently combines is_outer_parenthesized_map_value with
outer_payload_kind == Some(...).
- Around line 32-59: The trailing-comma branch is unreachable given the three
ScssMapOuterParenthesizedValuePayloadKind variants; remove the dead
`trailing_comma` block (and its use of `if_group_breaks`/`with_group_id`) or
replace it with a single-line explanatory comment to indicate this is
intentional scaffolding; update or remove the `should_print_trailing_comma`
and/or `inner_expression_owns_trailing_comma` locals as needed to avoid unused
variable warnings and keep references to
`ScssMapOuterParenthesizedValuePayloadKind`,
`inner_expression_owns_trailing_comma`, `should_print_trailing_comma`, and
`trailing_comma` to locate the code to change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2c8e8c50-368f-44bf-b026-e58d432ed4f4

📥 Commits

Reviewing files that changed from the base of the PR and between f785e8c and 71e1826.

⛔ Files ignored due to path filters (6)
  • crates/biome_css_formatter/tests/specs/prettier/scss/map/comment.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/prettier/scss/map/keys.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/scss/expression/map-comments.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/scss/expression/map-context.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/scss/expression/map-expansion.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/scss/expression/map-values.scss.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (13)
  • crates/biome_css_formatter/src/comments.rs
  • crates/biome_css_formatter/src/scss/auxiliary/list_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/map_expression_pair.rs
  • crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs
  • crates/biome_css_formatter/src/scss/lists/map_expression_pair_list.rs
  • crates/biome_css_formatter/src/utils/mod.rs
  • crates/biome_css_formatter/src/utils/scss_expression.rs
  • crates/biome_css_formatter/src/utils/scss_map.rs
  • crates/biome_css_formatter/tests/specs/scss/expression/map-comments.scss
  • crates/biome_css_formatter/tests/specs/scss/expression/map-context.scss
  • crates/biome_css_formatter/tests/specs/scss/expression/map-expansion.scss
  • crates/biome_css_formatter/tests/specs/scss/expression/map-values.scss

@codspeed

codspeed Bot commented Apr 21, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 29 untouched benchmarks
⏩ 227 skipped benchmarks1


Comparing db/prettier-compare (5b66817) with main (295f97f)2

Open in CodSpeed

Footnotes

  1. 227 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. ↩

  2. No successful run was found on main (acd7841) during the generation of this report, so 295f97f was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs (2)

66-78: Two dangling_comments lookups where one will do.

is_empty() followed by iter().all(..) fetches the dangling slice twice. Bind once:

♻️ Optional tidy
-    fn has_inline_closing_comments(&self, f: &CssFormatter) -> bool {
-        self.node.pairs().len() > 0
-            && !f
-                .context()
-                .comments()
-                .dangling_comments(self.node.syntax())
-                .is_empty()
-            && f.context()
-                .comments()
-                .dangling_comments(self.node.syntax())
-                .iter()
-                .all(|comment| comment.kind().is_inline() && comment.lines_before() == 0)
-    }
+    fn has_inline_closing_comments(&self, f: &CssFormatter) -> bool {
+        if self.node.pairs().len() == 0 {
+            return false;
+        }
+        let dangling = f.context().comments().dangling_comments(self.node.syntax());
+        !dangling.is_empty()
+            && dangling
+                .iter()
+                .all(|c| c.kind().is_inline() && c.lines_before() == 0)
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs` around lines
66 - 78, In has_inline_closing_comments, avoid calling
f.context().comments().dangling_comments(self.node.syntax()) twice: store that
slice in a local let (e.g., let dangling =
f.context().comments().dangling_comments(self.node.syntax())) and then use
dangling.is_empty() and dangling.iter().all(...) so the dangling_comments lookup
only occurs once; update the function body to reference that local variable
instead of repeating the call.

9-27: Double ScssMapLayout::new — tiny redundancy.

fmt_fields and fmt_dangling_comments both build a fresh ScssMapLayout (and each in turn invokes has_inline_closing_comments, which calls dangling_comments(..) twice). group_id("scss_map_expression") returns the same id, so behaviour is identical — only cosmetic. If you feel like reducing the comment-lookup fan-out, caching the dangling comments once inside a single layout instance would pay for itself.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs` around lines
9 - 27, Both fmt_fields and fmt_dangling_comments recreate ScssMapLayout (via
ScssMapLayout::new(node, f.group_id("scss_map_expression"))) causing duplicate
work and repeated calls to has_inline_closing_comments / dangling_comments; fix
by creating a single ScssMapLayout instance and reusing it (e.g., instantiate
layout = ScssMapLayout::new(node, f.group_id("scss_map_expression")) and use
layout.fmt(f) in fmt_fields and layout.handles_dangling_comments(f) /
layout.fmt(...) in fmt_dangling_comments), or alternatively move the
dangling_comments caching into ScssMapLayout so its dangling_comments() is
computed once and reused by has_inline_closing_comments and other callers.
crates/biome_css_formatter/src/comments.rs (1)

101-121: Tiny tidy: the OwnLine arm never benefits from the new handler.

handle_scss_map_trailing_separator_comment short-circuits to Default whenever comment.text_position().is_own_line() (Line 138), so listing it in the OwnLine arm is a guaranteed no-op. Not a bug — just a bit of sleight of hand that will puzzle the next reader. Feel free to drop it there, or consolidate the three arms since they're now identical anyway.

♻️ Optional tidy
-            CommentTextPosition::EndOfLine => handle_scss_map_trailing_separator_comment(comment)
-                .or_else(handle_function_comment)
-                .or_else(handle_generic_property_comment)
-                .or_else(handle_declaration_name_comment)
-                .or_else(handle_complex_selector_comment)
-                .or_else(handle_global_suppression),
-            CommentTextPosition::OwnLine => handle_scss_map_trailing_separator_comment(comment)
-                .or_else(handle_function_comment)
-                .or_else(handle_generic_property_comment)
-                .or_else(handle_declaration_name_comment)
-                .or_else(handle_complex_selector_comment)
-                .or_else(handle_global_suppression),
-            CommentTextPosition::SameLine => handle_scss_map_trailing_separator_comment(comment)
-                .or_else(handle_function_comment)
-                .or_else(handle_generic_property_comment)
-                .or_else(handle_declaration_name_comment)
-                .or_else(handle_complex_selector_comment)
-                .or_else(handle_global_suppression),
+            CommentTextPosition::EndOfLine
+            | CommentTextPosition::OwnLine
+            | CommentTextPosition::SameLine => {
+                handle_scss_map_trailing_separator_comment(comment)
+                    .or_else(handle_function_comment)
+                    .or_else(handle_generic_property_comment)
+                    .or_else(handle_declaration_name_comment)
+                    .or_else(handle_complex_selector_comment)
+                    .or_else(handle_global_suppression)
+            }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/comments.rs` around lines 101 - 121, The
OwnLine match arm includes handle_scss_map_trailing_separator_comment which
always returns Default for comments where comment.text_position().is_own_line(),
so remove that no-op to avoid confusion: update the match over
comment.text_position() (matching CommentTextPosition::EndOfLine, ::OwnLine,
::SameLine) by either (a) dropping handle_scss_map_trailing_separator_comment
from the CommentTextPosition::OwnLine arm so it mirrors the effective logic of
that position, or (b) consolidate the three arms into a single shared chain of
handlers (handle_scss_map_trailing_separator_comment, handle_function_comment,
handle_generic_property_comment, handle_declaration_name_comment,
handle_complex_selector_comment, handle_global_suppression) to eliminate the
redundant listing; adjust based on preference and ensure behavior of
handle_function_comment, handle_generic_property_comment,
handle_declaration_name_comment, handle_complex_selector_comment, and
handle_global_suppression remains unchanged.
🤖 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_formatter/src/comments.rs`:
- Around line 101-121: The OwnLine match arm includes
handle_scss_map_trailing_separator_comment which always returns Default for
comments where comment.text_position().is_own_line(), so remove that no-op to
avoid confusion: update the match over comment.text_position() (matching
CommentTextPosition::EndOfLine, ::OwnLine, ::SameLine) by either (a) dropping
handle_scss_map_trailing_separator_comment from the CommentTextPosition::OwnLine
arm so it mirrors the effective logic of that position, or (b) consolidate the
three arms into a single shared chain of handlers
(handle_scss_map_trailing_separator_comment, handle_function_comment,
handle_generic_property_comment, handle_declaration_name_comment,
handle_complex_selector_comment, handle_global_suppression) to eliminate the
redundant listing; adjust based on preference and ensure behavior of
handle_function_comment, handle_generic_property_comment,
handle_declaration_name_comment, handle_complex_selector_comment, and
handle_global_suppression remains unchanged.

In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs`:
- Around line 66-78: In has_inline_closing_comments, avoid calling
f.context().comments().dangling_comments(self.node.syntax()) twice: store that
slice in a local let (e.g., let dangling =
f.context().comments().dangling_comments(self.node.syntax())) and then use
dangling.is_empty() and dangling.iter().all(...) so the dangling_comments lookup
only occurs once; update the function body to reference that local variable
instead of repeating the call.
- Around line 9-27: Both fmt_fields and fmt_dangling_comments recreate
ScssMapLayout (via ScssMapLayout::new(node, f.group_id("scss_map_expression")))
causing duplicate work and repeated calls to has_inline_closing_comments /
dangling_comments; fix by creating a single ScssMapLayout instance and reusing
it (e.g., instantiate layout = ScssMapLayout::new(node,
f.group_id("scss_map_expression")) and use layout.fmt(f) in fmt_fields and
layout.handles_dangling_comments(f) / layout.fmt(...) in fmt_dangling_comments),
or alternatively move the dangling_comments caching into ScssMapLayout so its
dangling_comments() is computed once and reused by has_inline_closing_comments
and other callers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0ebdfe1e-0488-4d57-b4f4-024ddc8f7291

📥 Commits

Reviewing files that changed from the base of the PR and between 71e1826 and e3da532.

📒 Files selected for processing (4)
  • crates/biome_css_formatter/src/comments.rs
  • crates/biome_css_formatter/src/scss/auxiliary/list_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/biome_css_formatter/src/scss/auxiliary/list_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs

@denbezrukov
denbezrukov force-pushed the db/prettier-compare branch from e3da532 to cc12660 Compare April 21, 2026 19:41

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs (1)

13-26: Throwaway group_id in fmt_dangling_comments.

handles_dangling_comments never touches self.group_id, so calling f.group_id("scss_map_expression") here just burns a counter each time. Consider extracting the check as a free function (or associated fn) that takes &ScssMapExpression and &CssFormatter, so only fmt_fields pays for the group-id allocation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs` around lines
13 - 26, The call in fmt_dangling_comments is wasting a group-id by invoking
f.group_id("scss_map_expression") even though handles_dangling_comments doesn't
use the group id; refactor by adding a free function or associated function
(e.g., ScssMapLayout::handles_dangling_comments_for(node: &ScssMapExpression, f:
&CssFormatter) -> bool) that performs the same check without allocating a group
id, update fmt_dangling_comments to call that new function (or pass f directly)
and ensure only fmt_fields (where the group id is actually needed) calls
f.group_id("scss_map_expression") to pay for the allocation.
🤖 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/auxiliary/parenthesized_expression.rs`:
- Around line 22-69: The computed should_print_trailing_comma is unreachable
given outer_payload_kind/inner_expression_owns_trailing_comma logic; remove the
dead trailing_comma/inner_expression_owns_trailing_comma/ group_id machinery or
restore the intended case by changing the predicate. Locate
scss_map_context(...) and the outer_payload_kind usage, then either (A)
simplify: drop inner_expression_owns_trailing_comma, trailing_comma, and
group_id and only keep should_expand and the group(...) call, or (B) implement
the missing payload kind/condition that should make should_print_trailing_comma
true (adjust outer_payload_kind checks to include that kind). Ensure references
to ScssMapOuterParenthesizedValuePayloadKind, should_print_trailing_comma,
trailing_comma, inner_expression_owns_trailing_comma, and group_id are updated
consistently.

---

Nitpick comments:
In `@crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs`:
- Around line 13-26: The call in fmt_dangling_comments is wasting a group-id by
invoking f.group_id("scss_map_expression") even though handles_dangling_comments
doesn't use the group id; refactor by adding a free function or associated
function (e.g., ScssMapLayout::handles_dangling_comments_for(node:
&ScssMapExpression, f: &CssFormatter) -> bool) that performs the same check
without allocating a group id, update fmt_dangling_comments to call that new
function (or pass f directly) and ensure only fmt_fields (where the group id is
actually needed) calls f.group_id("scss_map_expression") to pay for the
allocation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 54862c01-4ada-4181-b2d4-6931e84a1ed7

📥 Commits

Reviewing files that changed from the base of the PR and between e3da532 and cc12660.

⛔ Files ignored due to path filters (6)
  • crates/biome_css_formatter/tests/specs/prettier/scss/map/comment.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/prettier/scss/map/keys.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/scss/expression/map-comments.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/scss/expression/map-context.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/scss/expression/map-expansion.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/scss/expression/map-values.scss.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (13)
  • crates/biome_css_formatter/src/comments.rs
  • crates/biome_css_formatter/src/scss/auxiliary/list_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/map_expression_pair.rs
  • crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs
  • crates/biome_css_formatter/src/scss/lists/map_expression_pair_list.rs
  • crates/biome_css_formatter/src/utils/mod.rs
  • crates/biome_css_formatter/src/utils/scss_expression.rs
  • crates/biome_css_formatter/src/utils/scss_map.rs
  • crates/biome_css_formatter/tests/specs/scss/expression/map-comments.scss
  • crates/biome_css_formatter/tests/specs/scss/expression/map-context.scss
  • crates/biome_css_formatter/tests/specs/scss/expression/map-expansion.scss
  • crates/biome_css_formatter/tests/specs/scss/expression/map-values.scss
✅ Files skipped from review due to trivial changes (6)
  • crates/biome_css_formatter/src/utils/mod.rs
  • crates/biome_css_formatter/tests/specs/scss/expression/map-context.scss
  • crates/biome_css_formatter/tests/specs/scss/expression/map-values.scss
  • crates/biome_css_formatter/tests/specs/scss/expression/map-expansion.scss
  • crates/biome_css_formatter/tests/specs/scss/expression/map-comments.scss
  • crates/biome_css_formatter/src/scss/auxiliary/map_expression_pair.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/biome_css_formatter/src/scss/auxiliary/list_expression.rs
  • crates/biome_css_formatter/src/utils/scss_expression.rs

autofix-ci Bot and others added 2 commits April 21, 2026 19:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/biome_css_formatter/src/comments.rs (1)

108-113: Tiny redundancy: handler is a no-op in the OwnLine arm.

handle_scss_map_trailing_separator_comment bails out early via comment.text_position().is_own_line() at line 138, so chaining it into the OwnLine branch will always fall through to handle_function_comment. Harmless, but you can drop it from that arm (or drop the is_own_line() guard) to avoid misleading readers about where this handler can fire.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/comments.rs` around lines 108 - 113, The
OwnLine match arm currently calls handle_scss_map_trailing_separator_comment
even though handle_scss_map_trailing_separator_comment immediately returns early
when comment.text_position().is_own_line(), so remove that handler from the
CommentTextPosition::OwnLine arm (leaving handle_function_comment,
handle_generic_property_comment, handle_declaration_name_comment,
handle_complex_selector_comment, handle_global_suppression) to avoid the
misleading no-op, or alternatively remove the internal is_own_line() guard
inside handle_scss_map_trailing_separator_comment if the intention is that it
should run for OwnLine; reference CommentTextPosition::OwnLine and
handle_scss_map_trailing_separator_comment when making the change.
🤖 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_formatter/src/comments.rs`:
- Around line 108-113: The OwnLine match arm currently calls
handle_scss_map_trailing_separator_comment even though
handle_scss_map_trailing_separator_comment immediately returns early when
comment.text_position().is_own_line(), so remove that handler from the
CommentTextPosition::OwnLine arm (leaving handle_function_comment,
handle_generic_property_comment, handle_declaration_name_comment,
handle_complex_selector_comment, handle_global_suppression) to avoid the
misleading no-op, or alternatively remove the internal is_own_line() guard
inside handle_scss_map_trailing_separator_comment if the intention is that it
should run for OwnLine; reference CommentTextPosition::OwnLine and
handle_scss_map_trailing_separator_comment when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 81dd1d13-147e-4df4-bbed-1af1ce3159e2

📥 Commits

Reviewing files that changed from the base of the PR and between cc12660 and 65295a6.

📒 Files selected for processing (4)
  • crates/biome_css_formatter/src/comments.rs
  • crates/biome_css_formatter/src/scss/auxiliary/list_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/parenthesized_expression.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/biome_css_formatter/src/scss/auxiliary/list_expression.rs
  • crates/biome_css_formatter/src/scss/auxiliary/map_expression.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Formatter Area: formatter L-CSS Language: CSS and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant