Skip to content

fix(css/formatter): comment placement in lists#9261

Open
ematipico wants to merge 1 commit intomainfrom
fix/css-comment-placement
Open

fix(css/formatter): comment placement in lists#9261
ematipico wants to merge 1 commit intomainfrom
fix/css-comment-placement

Conversation

@ematipico
Copy link
Member

Summary

Closes #8409

It's a weird issue because it fixes the comment placement, however it introduces a small regression in the printing of the list. It's weird because the fill IR is still the same... I suspect there's some weird bug inside the printer.

We can leave it like this, or I will try to understand if there's a bug in the printer.

Test Plan

Added new tests

Docs

N/A

@changeset-bot
Copy link

changeset-bot bot commented Feb 27, 2026

🦋 Changeset detected

Latest commit: f0bc401

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

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

@github-actions github-actions bot added A-Formatter Area: formatter L-CSS Language: CSS labels Feb 27, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 27, 2026

Walkthrough

This PR fixes a CSS formatter bug where comments after a colon in property declarations were incorrectly positioned before the property name. It introduces new comment handling logic for CSS generic properties, modifies trailing comment formatting in property declarations, and adds a new layout variant for handling dangling comments in value lists. The changes ensure comments remain correctly placed relative to property colons and values.

Possibly related PRs

Suggested labels

A-Formatter, L-CSS

Suggested reviewers

  • dyc3
  • denbezrukov
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main change: fixing comment placement in CSS property lists.
Description check ✅ Passed The description clearly references the issue being fixed (#8409) and acknowledges the testing approach and minor regression.
Linked Issues check ✅ Passed The PR fully addresses issue #8409 by correcting the CSS formatter bug where comments after property colons were incorrectly positioned before property names.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing CSS comment placement in property declarations; no unrelated modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/css-comment-placement

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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
crates/biome_css_formatter/src/css/properties/generic_property.rs (1)

23-28: Semantic naming: using FormatCssLeadingComment for trailing comments.

Using FormatCssLeadingComment to format trailing comments works functionally but is semantically confusing. If the formatting logic is identical for both leading and trailing comments, consider renaming to something generic like FormatCssComment, or add a brief comment explaining the reuse.

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

In `@crates/biome_css_formatter/src/css/properties/generic_property.rs` around
lines 23 - 28, The code uses FormatCssLeadingComment to format trailing_comments
in the loop (see FormatRefWithRule::new(comment,
FormatCssLeadingComment::default()) and comment.mark_formatted()), which is
semantically confusing; rename the formatter to a neutral name (e.g.,
FormatCssComment) or introduce a new alias/type that wraps/re-exports
FormatCssLeadingComment with a clear name, update all references (including
where FormatRefWithRule is constructed for both leading and trailing comments)
to use the new name, or alternatively add a one-line comment above the loop
explaining that the leading-comment formatter is intentionally reused for
trailing comments; ensure the change preserves existing behavior and updates any
imports/uses of FormatCssLeadingComment accordingly.
crates/biome_css_formatter/src/comments.rs (1)

140-147: Consider alternative matching strategy for trivia comparison.

The use of piece.text() == comment_piece.text() is the only text comparison for trivia matching in the codebase. If identical comments appear multiple times in trailing trivia, this could incorrectly match the wrong piece. Explore whether comparing trivia ranges, offsets, or leveraging structural equality would be more robust than text equality.

🤖 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 140 - 147, The
current comparison in the trailing trivia loop (inside the block that calls
name.syntax().last_token()) only checks piece.text() == comment_piece.text(),
which can misidentify identical comment text occurring multiple times; update
the match to use a positional or structural comparison instead—for example
compare the trivia piece's text range/offset (e.g., piece.text_range() or
piece.range()) against comment_piece's range, or use a structural equality
method on TriviaPiece if available, so the loop in comments.rs returns
CommentPlacement::trailing(name.into_syntax(), comment) only when the exact
trivia instance (not just identical text) matches.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/fix-css-comment-placement.md:
- Around line 17-22: The "After" example has inconsistent indentation: the
'sans-serif' token is indented further than 'Hiragino Sans' in the font-family
block for the [lang]:lang(ja) selector; fix by aligning 'sans-serif' to the same
indentation level as 'Hiragino Sans' in .changeset/fix-css-comment-placement.md
(or, if this reflects real formatter output from your CSS formatter, adjust the
formatter/config or add a regression test to ensure comment placement doesn't
change indentation). Ensure the font-family lines under the [lang]:lang(ja)
block use consistent indentation.

In `@crates/biome_css_formatter/src/utils/component_value_list.rs`:
- Around line 197-204: Remove the temporary dbg!() calls left in
component_value_list.rs around the conditional that chooses between
hard_line_break() and space(): delete the dbg!("here1") and dbg!("here2")
invocations so they no longer print to stdout; keep the surrounding logic that
calls write!(f, [hard_line_break()])? and write!(f, [space()])? intact and run
tests/formatting to confirm no behavior change. Use the nearby identifiers
(hard_line_break(), space(), at_group_boundary, and the write!(f, ...) calls) to
locate the exact spots to clean up.

---

Nitpick comments:
In `@crates/biome_css_formatter/src/comments.rs`:
- Around line 140-147: The current comparison in the trailing trivia loop
(inside the block that calls name.syntax().last_token()) only checks
piece.text() == comment_piece.text(), which can misidentify identical comment
text occurring multiple times; update the match to use a positional or
structural comparison instead—for example compare the trivia piece's text
range/offset (e.g., piece.text_range() or piece.range()) against comment_piece's
range, or use a structural equality method on TriviaPiece if available, so the
loop in comments.rs returns CommentPlacement::trailing(name.into_syntax(),
comment) only when the exact trivia instance (not just identical text) matches.

In `@crates/biome_css_formatter/src/css/properties/generic_property.rs`:
- Around line 23-28: The code uses FormatCssLeadingComment to format
trailing_comments in the loop (see FormatRefWithRule::new(comment,
FormatCssLeadingComment::default()) and comment.mark_formatted()), which is
semantically confusing; rename the formatter to a neutral name (e.g.,
FormatCssComment) or introduce a new alias/type that wraps/re-exports
FormatCssLeadingComment with a clear name, update all references (including
where FormatRefWithRule is constructed for both leading and trailing comments)
to use the new name, or alternatively add a one-line comment above the loop
explaining that the leading-comment formatter is intentionally reused for
trailing comments; ensure the change preserves existing behavior and updates any
imports/uses of FormatCssLeadingComment accordingly.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96939c0 and f0bc401.

⛔ Files ignored due to path filters (11)
  • crates/biome_css_formatter/tests/specs/css/atrule/import.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/css/comments/property-value-comment.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/css/scss/declaration/mixed.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-empty-value.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/css/scss/declaration/parent-and-colon-values.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/css/scss/expression/list-map-paren.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/css/scss/expression/precedence.scss.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/css/unary-precedence.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/prettier/css/comments/at-rules.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/prettier/css/comments/custom-properties.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_formatter/tests/specs/prettier/css/comments/declaration.css.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (5)
  • .changeset/fix-css-comment-placement.md
  • crates/biome_css_formatter/src/comments.rs
  • crates/biome_css_formatter/src/css/properties/generic_property.rs
  • crates/biome_css_formatter/src/utils/component_value_list.rs
  • crates/biome_css_formatter/tests/specs/css/comments/property-value-comment.css

Comment on lines +17 to +22
/* After (correct) */
[lang]:lang(ja) {
font-family: /* system-ui,*/
Hiragino Sans,
sans-serif;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent indentation in the "After" example.

Line 21 has extra leading whitespace (sans-serif is indented more than Hiragino Sans). If this reflects actual formatter output, it may indicate the regression mentioned in the PR description. If it's a typo in the changeset, it should be corrected.

📝 If this is a typo, proposed fix
 /* After (correct) */
 [lang]:lang(ja) {
   font-family: /* system-ui,*/
     Hiragino Sans,
-     sans-serif;
+    sans-serif;
 }
📝 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.

Suggested change
/* After (correct) */
[lang]:lang(ja) {
font-family: /* system-ui,*/
Hiragino Sans,
sans-serif;
}
/* After (correct) */
[lang]:lang(ja) {
font-family: /* system-ui,*/
Hiragino Sans,
sans-serif;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/fix-css-comment-placement.md around lines 17 - 22, The "After"
example has inconsistent indentation: the 'sans-serif' token is indented further
than 'Hiragino Sans' in the font-family block for the [lang]:lang(ja) selector;
fix by aligning 'sans-serif' to the same indentation level as 'Hiragino Sans' in
.changeset/fix-css-comment-placement.md (or, if this reflects real formatter
output from your CSS formatter, adjust the formatter/config or add a regression
test to ensure comment placement doesn't change indentation). Ensure the
font-family lines under the [lang]:lang(ja) block use consistent indentation.

Comment on lines +197 to 204
dbg!("here1");
write!(f, [hard_line_break()])?;
} else {
write!(f, [space()])?;
}
} else if at_group_boundary {
dbg!("here2");
write!(f, [hard_line_break()])?;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove debug statements before merge.

These dbg!() calls appear to be temporary debugging hooks left in the code. While the coding guidelines do mention using dbg!() for debugging, these should be removed before the PR is merged to avoid noisy output during formatting.

🧹 Proposed fix
                                if has_leading_newline {
-                                    dbg!("here1");
                                    write!(f, [hard_line_break()])?;
                                } else {
                                    write!(f, [space()])?;
                                }
                            } else if at_group_boundary {
-                                dbg!("here2");
                                write!(f, [hard_line_break()])?;
📝 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.

Suggested change
dbg!("here1");
write!(f, [hard_line_break()])?;
} else {
write!(f, [space()])?;
}
} else if at_group_boundary {
dbg!("here2");
write!(f, [hard_line_break()])?;
write!(f, [hard_line_break()])?;
} else {
write!(f, [space()])?;
}
} else if at_group_boundary {
write!(f, [hard_line_break()])?;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_formatter/src/utils/component_value_list.rs` around lines
197 - 204, Remove the temporary dbg!() calls left in component_value_list.rs
around the conditional that chooses between hard_line_break() and space():
delete the dbg!("here1") and dbg!("here2") invocations so they no longer print
to stdout; keep the surrounding logic that calls write!(f, [hard_line_break()])?
and write!(f, [space()])? intact and run tests/formatting to confirm no behavior
change. Use the nearby identifiers (hard_line_break(), space(),
at_group_boundary, and the write!(f, ...) calls) to locate the exact spots to
clean up.

@codspeed-hq
Copy link

codspeed-hq bot commented Feb 27, 2026

Merging this PR will not alter performance

✅ 29 untouched benchmarks
⏩ 187 skipped benchmarks1


Comparing fix/css-comment-placement (f0bc401) with main (2d0b8e6)

Open in CodSpeed

Footnotes

  1. 187 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.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

📝 partial comment-out of CSS attribute value goes before attribute name

1 participant