Skip to content

feat(formatter): add delimiterSpacing option#8966

Closed
luisherranz wants to merge 21 commits intobiomejs:nextfrom
luisherranz:feat/delimiter-spacing-option
Closed

feat(formatter): add delimiterSpacing option#8966
luisherranz wants to merge 21 commits intobiomejs:nextfrom
luisherranz:feat/delimiter-spacing-option

Conversation

@luisherranz
Copy link
Copy Markdown

@luisherranz luisherranz commented Feb 4, 2026

Huge kudos to @orballo for doing most of the work in discovering which parts of the Biome formatter needed to be changed to add this option in his proof of concept: orballo#1

Summary

This PR adds a new delimiterSpacing formatter option that inserts spaces inside delimiters (parentheses, square brackets, TS angle brackets, and JSX curly braces).

Closes #4607

When enabled, this input:

function id<TypeArg>(x: TypeArg): TypeArg {
  return x;
}
const arr = [1, 2, 3];
if (id(true)) {
  // …
}

Is formatted as:

function id< TypeArg >( x: TypeArg ): TypeArg {
  return x;
}
const arr = [ 1, 2, 3 ];
if ( id( true ) ) {
  // …
}

The option is available for:

  • JavaScript/TypeScript: Parentheses (), square brackets [], TS angle brackets <>, and JSX curly braces {}
  • JSON: Square brackets []
  • CSS: Parentheses () and square brackets []

Configuration example:

{
  "formatter": {
    "delimiterSpacing": true
  }
}

Or per-language:

{
  "javascript": {
    "formatter": {
      "delimiterSpacing": true
    }
  }
}

See #2360 (comment).

AI usage

As the Gutenberg project is using a non-official fork of Prettier, I run @orballo's Biome version in the Gutenberg repository and used AI to extract all the tests and edge cases. Then the AI assisted me in converting the changes made by @orballo's proof of concept to changes in the current formatter.

Test Plan

  • Added snapshot tests for all supported languages
  • Updated existing formatter snapshots to include the new option

Website

Website docs and playground integration PR in this website repo PR:

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 4, 2026

🦋 Changeset detected

Latest commit: 40d1732

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

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

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-CLI Area: CLI A-Project Area: project A-Formatter Area: formatter L-JavaScript Language: JavaScript and super languages L-CSS Language: CSS and super languages L-JSON Language: JSON and super languages labels Feb 4, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 4, 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 a new formatter option delimiterSpacing (public type DelimiterSpacing) with global and per-language configuration fields and CLI/serde plumbing. The option is threaded into JS/TS/CSS formatter contexts and formatter internals to conditionally insert spaces inside delimiters ((), [], <>, {}). New tests and CSS/JS fixtures for delimiter-spacing were added and migration metadata updated to reference the option.

Possibly related PRs

Suggested labels

A-Linter

Suggested reviewers

  • dyc3
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: introducing a new delimiterSpacing formatter option.
Description check ✅ Passed The description is comprehensive and directly addresses the changeset, providing clear examples, configuration details, and test coverage information.
Linked Issues check ✅ Passed All code changes fully implement the requirements from issue #4607: the option adds spacing inside delimiters (parentheses, brackets, angle brackets, curly braces) across JavaScript/TypeScript, JSON, and CSS formatters.
Out of Scope Changes check ✅ Passed All changes directly support the delimiterSpacing feature implementation. Configuration additions, formatter logic, test files, and unsupported rules metadata updates are all in scope.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

You can get early access to new features in CodeRabbit.

Enable the early_access setting to enable early access features such as new models, tools, and more.

Copy link
Copy Markdown
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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
crates/biome_js_formatter/src/js/bindings/parameters.rs (1)

98-115: ⚠️ Potential issue | 🟠 Major

Add a trailing space before ) for Default layout when delimiterSpacing is on.
Default layout currently inserts only the leading space, so single-line params become ( a, b) rather than ( a, b ).

Suggested fix
                 write!(
                     f,
                     [soft_block_indent_with_maybe_space(
                         &FormatJsAnyParameterList::with_layout(&list, ParameterLayout::Default,),
                         should_insert_space_around_delimiters
                     )]
                 )?;

                 if !parentheses_not_needed {
+                    if should_insert_space_around_delimiters {
+                        write!(f, [soft_line_break_or_space()])?;
+                    }
                     write!(f, [r_paren_token.format()])?;
                 } else {
crates/biome_js_formatter/src/lib.rs (1)

376-405: ⚠️ Potential issue | 🟡 Minor

Replace hard space() with soft_line_break_or_space() around inserted parentheses.

When delimiter spacing wraps content across lines, hard spaces leave trailing whitespace. Use soft_line_break_or_space() instead, which collapses intelligently when the group breaks—it's already the standard pattern throughout the formatter for this scenario.

Fix
        if needs_parentheses {
            write!(f, [token("(")])?;
            if should_insert_space {
-               write!(f, [space()])?;
+               write!(f, [soft_line_break_or_space()])?;
            }
        }

        if let Some(range) = self.embedded_node_range(node, f) {
            // Tokens that belong to embedded nodes are formatted later on,
            // so we track them, even though they aren't formatted now during this pass.
            let state = f.state_mut();
            for token in node.syntax().tokens() {
                state.track_token(&token);
            }

            f.write_elements(vec![
                FormatElement::Tag(StartEmbedded(range)),
                FormatElement::Tag(EndEmbedded),
            ])?;
        } else {
            self.fmt_fields(node, f)?;
        }

        if needs_parentheses {
            if should_insert_space {
-               write!(f, [space()])?;
+               write!(f, [soft_line_break_or_space()])?;
            }
            write!(f, [token(")")])?;
        }
crates/biome_js_formatter/src/js/declarations/catch_declaration.rs (1)

40-48: ⚠️ Potential issue | 🟡 Minor

Apply delimiter spacing consistently in the breaking path.

The breaking path (lines 40–48) doesn't apply delimiter_spacing, whilst the non-breaking path does. Other formatters in the codebase use soft_block_indent_with_maybe_space for this pattern. The fix is straightforward:

Suggested change
         if leading_comment_with_break || trailing_comment_with_break {
             write!(
                 f,
                 [
                     l_paren_token.format(),
-                    soft_block_indent(&format_args![binding.format(), type_annotation.format()]),
+                    soft_block_indent_with_maybe_space(
+                        &format_args![binding.format(), type_annotation.format()],
+                        should_insert_space_around_delimiters
+                    ),
                     r_paren_token.format()
                 ]
             )
crates/biome_js_formatter/src/js/expressions/call_arguments.rs (1)

848-879: ⚠️ Potential issue | 🟠 Major

Inline call‑argument layout misses the closing‑space.
When the group stays on one line, soft_block_indent_with_maybe_space inserts only the leading space after (; the closing ) stays tight. Add a conditional if_group_fits_on_line(&space()) before self.r_paren when should_insert_space is true.

Suggested fix
-                soft_block_indent_with_maybe_space(
+                soft_block_indent_with_maybe_space(
                     &format_with(|f| {
                         for (index, entry) in self.args.iter().enumerate() {
                             if index > 0 {
                                 match entry.leading_lines() {
                                     0 | 1 => write!(f, [soft_line_break_or_space()])?,
                                     _ => write!(f, [empty_line()])?,
                                 }
                             }
                             write!(f, [entry])?;
                         }
                         if !is_inside_import {
                             write!(f, [FormatTrailingCommas::All])?;
                         }
                         Ok(())
                     }),
                     self.should_insert_space
-                ),
+                ),
+                self.should_insert_space.then_some(if_group_fits_on_line(&space())),
                 self.r_paren,
🤖 Fix all issues with AI agents
In `@crates/biome_js_formatter/src/js/assignments/array_assignment_pattern.rs`:
- Around line 26-33: The empty array pattern isn't honoring delimiterSpacing;
change the formatting in array_assignment_pattern.rs so the delimiter spacing
flag (should_insert_space_around_brackets) is applied even for empty patterns:
ensure the call to soft_block_indent_with_maybe_space(&elements.format(),
should_insert_space_around_brackets) runs when elements are empty (detect via
elements.is_empty() or equivalent) and emit the inner space when delimiter
spacing is true (so empty [] becomes [ ]); update the related test fixture to
expect the spaced empty pattern when delimiterSpacing is enabled.

In `@crates/biome_js_formatter/src/js/classes/setter_class_member.rs`:
- Around line 25-43: The space placement inside the should_insert_space branch
can produce double spaces when a trailing comma is present; adjust the emitter
so spacing is consistent by moving the space() that currently follows
comma_token.format() to instead precede r_paren_token.format(), or conditionally
emit that space only when comma_token is not a trailing-comma token. Locate the
block that builds the sequence (referencing modifiers.format(),
set_token.format(), name.format(), l_paren_token.format(), parameter.format(),
comma_token.format(), r_paren_token.format(), body.format()) and either move the
space() from after comma_token to immediately before r_paren_token.format() or
add a conditional around that space based on whether comma_token represents a
present trailing comma.

In `@crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs`:
- Around line 125-132: Inline sequence-expression parens are missing the
trailing space because soft_block_indent_with_maybe_space only emits the leading
space; update the inline sequence-expression code in
arrow_function_expression.rs to insert if_group_fits_on_line(&space())
immediately before the closing token(")") in both places where
soft_block_indent_with_maybe_space is used (the two inline sequence-expression
paths), so the formatter emits "(a, b )" spacing correctly when the group fits
on one line.

In `@crates/biome_js_formatter/src/js/expressions/unary_expression.rs`:
- Line 5: The unary-operator spacing logic in the JsUnaryExpression formatter is
inserting a space after the logical-not operator, turning "!foo" into "! foo";
update the formatting in the JsUnaryExpression handling so that when the
operator token is the logical-not ('!' or UnaryOp::LogicalNot) you do not emit
an extra space between the '!' operator and its operand — keep '!' glued to the
operand (and likewise preserve '!!a' by not splitting the two '!' tokens); leave
spacing decisions for parentheses to the operand's formatter and only apply
delimiter-interior spacing to other operators as originally intended.

In `@crates/biome_js_formatter/src/js/statements/while_statement.rs`:
- Around line 21-33: The closing parenthesis lacks a symmetric space when
delimiter_spacing is enabled, producing "while ( a)"; update the formatting
block that builds the while statement (around while_token.format(),
l_paren_token.format(),
group(&soft_block_indent_with_maybe_space(&test.format(), should_insert_space)),
r_paren_token.format()) to conditionally insert a space or soft break before
r_paren_token.format() when should_insert_space is true (i.e., use a
space/soft-line-break token analogous to the leading space so output becomes
"while ( a )"); modify the group composition to include that conditional spacer
rather than leaving the trailing side empty.

In `@crates/biome_js_formatter/src/jsx/auxiliary/spread_child.rs`:
- Around line 54-69: When comments are present and delimiter_spacing is true the
group created by group(&soft_block_indent_with_maybe_space(&format_inner, true))
only adds a leading space so the output becomes "{ …}" instead of "{ … }";
update the branch handling f.comments().has_comments(expression.syntax()) to
include a trailing soft space/line-break inside that group (i.e. ensure
soft_block_indent_with_maybe_space or the group call around format_inner appends
a trailing space/soft-break), referencing the existing symbols
delimiter_spacing, format_inner, soft_block_indent_with_maybe_space and group so
the single-line output includes both leading and closing spacing when comments
exist.
🧹 Nitpick comments (6)
crates/biome_js_formatter/tests/specs/js/module/delimiter-spacing/parenthesized.js (1)

31-35: Minor: verify character counts in boundary test comments.

The comments claim specific character counts (78/80 for line 32, 79/81 for line 35), but a quick count suggests these may be off by 1-2 characters. Not a blocker since the test infrastructure will validate the actual formatter output, but accurate comments help future maintainers understand the test's intent.

crates/biome_js_formatter/src/js/classes/setter_class_member.rs (1)

25-61: Consider reducing duplication between the two branches.

Both branches share the same formatting for modifiers, set_token, name, and body. Only the spacing around the parameter differs. A small refactor could reduce the duplication, though this is optional.

♻️ Optional refactor to reduce duplication
let (pre_param_space, post_param_space) = if should_insert_space {
    (space(), space())
} else {
    (empty_element(), empty_element())
};

write![
    f,
    [
        modifiers.format(),
        space(),
        set_token.format(),
        space(),
        name.format(),
        l_paren_token.format(),
        pre_param_space,
        parameter.format(),
        comma_token.format(),
        post_param_space,
        r_paren_token.format(),
        space(),
        body.format(),
    ]
]
crates/biome_css_formatter/src/tailwind/auxiliary/source_inline.rs (1)

18-40: Consider reducing duplication.

The branching duplicates the formatting of inline_token, l_paren_token, content, and r_paren_token. A minor refactor could extract common elements:

♻️ Suggested refactor
-        if should_insert_space {
-            write!(
-                f,
-                [
-                    inline_token.format(),
-                    l_paren_token.format(),
-                    space(),
-                    &content.format(),
-                    space(),
-                    r_paren_token.format(),
-                ]
-            )
-        } else {
-            write!(
-                f,
-                [
-                    inline_token.format(),
-                    l_paren_token.format(),
-                    &content.format(),
-                    r_paren_token.format(),
-                ]
-            )
-        }
+        write!(f, [inline_token.format(), l_paren_token.format()])?;
+        if should_insert_space {
+            write!(f, [space()])?;
+        }
+        write!(f, [&content.format()])?;
+        if should_insert_space {
+            write!(f, [space()])?;
+        }
+        write!(f, [r_paren_token.format()])

Alternatively, if the content doesn't require soft-indent semantics, the current explicit approach is perfectly readable—just a nitpick.

crates/biome_css_formatter/src/css/auxiliary/document_custom_matcher.rs (1)

22-44: Consider reducing duplication with a helper or conditional formatting.

The two branches are nearly identical, differing only by the space() calls. This is functional but could be streamlined. That said, the current approach is clear and readable.

♻️ Optional: Reduce duplication
-        if should_insert_space {
-            write!(
-                f,
-                [
-                    name.format(),
-                    l_paren_token.format(),
-                    space(),
-                    value.format(),
-                    space(),
-                    r_paren_token.format()
-                ]
-            )
-        } else {
-            write!(
-                f,
-                [
-                    name.format(),
-                    l_paren_token.format(),
-                    value.format(),
-                    r_paren_token.format()
-                ]
-            )
-        }
+        write!(f, [name.format(), l_paren_token.format()])?;
+        if should_insert_space {
+            write!(f, [space()])?;
+        }
+        write!(f, [value.format()])?;
+        if should_insert_space {
+            write!(f, [space()])?;
+        }
+        write!(f, [r_paren_token.format()])
crates/biome_js_formatter/src/ts/auxiliary/index_signature_type_member.rs (1)

31-45: Consider using soft_block_indent_with_maybe_space for consistency.

The current implementation adds space() around the soft_block_indent, which may produce unexpected output when the content breaks across lines (e.g., [ \n param\n ]). Other formatters in this PR use soft_block_indent_with_maybe_space which handles this more elegantly.

Suggested refactor
-        if delimiter_spacing {
-            write![
-                f,
-                [
-                    group(&format_args![
-                        l_brack_token.format(),
-                        space(),
-                        soft_block_indent(&format_args![parameter.format()]),
-                        space(),
-                        r_brack_token.format(),
-                    ]),
-                    type_annotation.format(),
-                    FormatTypeMemberSeparator::new(separator_token.as_ref()),
-                ]
-            ]
-        } else {
-            write![
-                f,
-                [
-                    group(&format_args![
-                        l_brack_token.format(),
-                        soft_block_indent(&format_args![parameter.format()]),
-                        r_brack_token.format(),
-                    ]),
-                    type_annotation.format(),
-                    FormatTypeMemberSeparator::new(separator_token.as_ref()),
-                ]
-            ]
-        }
+        write![
+            f,
+            [
+                group(&format_args![
+                    l_brack_token.format(),
+                    soft_block_indent_with_maybe_space(&parameter.format(), delimiter_spacing),
+                    r_brack_token.format(),
+                ]),
+                type_annotation.format(),
+                FormatTypeMemberSeparator::new(separator_token.as_ref()),
+            ]
+        ]
crates/biome_js_formatter/src/ts/types/indexed_access_type.rs (1)

35-44: Minor: consider grouping for consistent breaking behaviour.

The non-spacing branch doesn't use group(), whilst the spacing branch does. This could lead to subtle differences in line-breaking decisions between the two modes. Worth double-checking this is intentional via your test snapshots.

Comment thread crates/biome_js_formatter/src/js/classes/setter_class_member.rs
Comment thread crates/biome_js_formatter/src/js/expressions/unary_expression.rs
Comment thread crates/biome_js_formatter/src/js/statements/while_statement.rs
Comment thread crates/biome_js_formatter/src/jsx/auxiliary/spread_child.rs
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Feb 5, 2026

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 156 skipped benchmarks1


Comparing luisherranz:feat/delimiter-spacing-option (40d1732) with next (0e0dbdf)2

Open in CodSpeed

Footnotes

  1. 156 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 next (4d251d4) during the generation of this report, so 0e0dbdf was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Copy link
Copy Markdown
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_js_formatter/tests/specs/js/module/delimiter-spacing/setters.js`:
- Around line 129-137: The boundary test comments for the setter lines are
incorrect: in class Foo19 (set a with ...uv) update the comment "78+2=80 chars
(fits)" to the correct "76+2=78 chars (fits)"; in class Foo20 (set a with
...uvw) update the comment "79+2=81 chars (breaks)" to "77+2=79 chars (breaks)
so the annotated character counts match the actual line lengths used by the
tests.

@dyc3
Copy link
Copy Markdown
Contributor

dyc3 commented Feb 10, 2026

It would be good to also update some of the rule metadata in crates/biome_cli/src/execute/migrate/unsupported_rules.rs, like for array-bracket-spacing or space-in-parens. There are probably some others.

@luisherranz
Copy link
Copy Markdown
Author

Sure, I'll try to address that as well.

@luisherranz
Copy link
Copy Markdown
Author

@dyc3, there you go: bea1683

Let me know if anything else is needed.

Copy link
Copy Markdown
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/biome_cli/src/execute/migrate/unsupported_rules.rs (1)

245-246: ⚠️ Potential issue | 🟠 Major

Update type-generic-spacing to map to FormatterOption("delimiterSpacing").

The delimiterSpacing option for JavaScript explicitly covers TypeScript angle brackets (<>), which is precisely what type-generic-spacing enforces. This mapping aligns with other delimiter-related rules like array-bracket-spacing, space-in-brackets, and template-curly-spacing, which already map to delimiterSpacing. Change from FormatterCovers to FormatterOption("delimiterSpacing") on line 245.

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

In `@crates/biome_cli/src/execute/migrate/unsupported_rules.rs` around lines 245 -
246, Change the mapping for the ESLint stylistic rule named by
EslintStylistic("type-generic-spacing") so it uses a formatter option instead of
a blanket cover; replace the UnsupportedRule entry that currently pairs
EslintStylistic("type-generic-spacing") with FormatterCovers and map it to
FormatterOption("delimiterSpacing") (i.e., update the UnsupportedRule for
EslintStylistic("type-generic-spacing") to use
FormatterOption("delimiterSpacing") so it aligns with other delimiter rules).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@crates/biome_cli/src/execute/migrate/unsupported_rules.rs`:
- Around line 245-246: Change the mapping for the ESLint stylistic rule named by
EslintStylistic("type-generic-spacing") so it uses a formatter option instead of
a blanket cover; replace the UnsupportedRule entry that currently pairs
EslintStylistic("type-generic-spacing") with FormatterCovers and map it to
FormatterOption("delimiterSpacing") (i.e., update the UnsupportedRule for
EslintStylistic("type-generic-spacing") to use
FormatterOption("delimiterSpacing") so it aligns with other delimiter rules).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 58946b7c-1bcc-402f-ab44-f8c42dc10199

📥 Commits

Reviewing files that changed from the base of the PR and between 2f33fc6 and bea1683.

📒 Files selected for processing (1)
  • crates/biome_cli/src/execute/migrate/unsupported_rules.rs

@luisherranz
Copy link
Copy Markdown
Author

update the UnsupportedRule for
EslintStylistic("type-generic-spacing") to use
FormatterOption("delimiterSpacing") so it aligns with other delimiter rules

@coderabbitai, type-generic-spacing is not affected by delimiterSpacing so it's correct as it is.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 12, 2026

Tip

For best results, initiate chat on the files or code changes.

@luisherranz Thanks for the clarification! You're right — type-generic-spacing enforces consistent spacing around generic type brackets (e.g., Foo<Bar> vs Foo <Bar>), which is a different concern from delimiterSpacing's inside-delimiter spacing. My suggestion was off the mark there.


✏️ Learnings added
Learnt from: luisherranz
URL: https://github.com/biomejs/biome/pull/8966

Timestamp: 2026-03-12T13:36:58.876Z
Learning: In biomejs/biome, `EslintStylistic("type-generic-spacing")` in `crates/biome_cli/src/execute/migrate/unsupported_rules.rs` is NOT related to the `delimiterSpacing` formatter option. It controls spacing around generic type brackets differently and should not be mapped to `FormatterOption("delimiterSpacing")`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-17T19:45:06.423Z
Learning: Applies to crates/biome_analyze/**/*.rs : For rules derived from other linters, use the `sources` metadata with `RuleSource::Eslint` and either `.same()` for identical behavior or `.inspired()` for different behavior/options

Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:27:13.161Z
Learning: In crates/biome_analyze/**/*analyze/src/**/*.rs, the `fix_kind` field in `declare_lint_rule!` should only be specified when the rule implements the `action` function. Rules that only emit diagnostics without providing code fixes should not include `fix_kind` in their metadata.

Learnt from: dyc3
Repo: biomejs/biome PR: 8171
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:125-137
Timestamp: 2025-11-21T01:10:53.059Z
Learning: In the Biome codebase, each lint rule has its own options type declaration (e.g., `type Options = RuleNameOptions`) as part of the codegen process, even if the options struct is empty or unused. This is standard practice and should not be flagged as an issue.

Learnt from: CR
Repo: biomejs/biome PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-06T09:34:07.770Z
Learning: Applies to **/src/*_formatter/**/*.rs : Run `just gen-formatter <lang>` and commit generated files before opening PR when making changes to formatter files in `*_formatter` directories

Copy link
Copy Markdown
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

🤖 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_cli/src/execute/migrate/unsupported_rules.rs`:
- Around line 108-111: Remove the UnsupportedRule entries that map
Eslint("template-curly-spacing") to FormatterOption("delimiterSpacing");
specifically locate the UnsupportedRule(...) instances containing
Eslint("template-curly-spacing") and FormatterOption("delimiterSpacing") and
delete them so the migrator no longer directs users to the incorrect
delimiterSpacing option. Ensure only those three mappings (the ones pairing
template-curly-spacing with delimiterSpacing) are removed and leave other
UnsupportedRule entries untouched.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b1cdde95-7c06-4d72-94ed-b978f80a0ade

📥 Commits

Reviewing files that changed from the base of the PR and between bea1683 and a8764f7.

📒 Files selected for processing (1)
  • crates/biome_cli/src/execute/migrate/unsupported_rules.rs

Comment thread crates/biome_cli/src/execute/migrate/unsupported_rules.rs
@ematipico
Copy link
Copy Markdown
Member

ematipico commented Mar 17, 2026

Thank you for this!

So, this is a massive PR and I wonder why this wasn't split in the first place. It will take us a while to review it, and since we're also working on SCSS, it will take you a lot of work to keep the PR up to date.

Wouldn't be better to implement this by language?

As for docs, I gave it a glance, I already started seeing a problem: they are very generic and repeated. We should aim for preciseness, for users and us. I want to understand the criteria of option, so that if I need to triage a bug, I know what to do.

For example function f() has delimiters, do we place a space between f and (. We should address that.

@luisherranz
Copy link
Copy Markdown
Author

Thanks for taking a look, @ematipico! I really appreciate it.

As for docs, I gave it a glance, I already started seeing a problem: they are very generic and repeated. We should aim for preciseness, for users and us. I want to understand the criteria of option, so that if I need to triage a bug, I know what to do.

I've improved the docs in this commit, but if you still think they are not accurate enough, please give me an example of how you think they should be and I'll try to improve them. Once we have them right, I'll also update the PR on the website.

since we're also working on SCSS, it will take you a lot of work to keep the PR up to date.
Wouldn't be better to implement this by language?

I can split the PR into three or add the option to the SCSS part and keep it up to date, whatever you folks prefer.

@ematipico ematipico self-assigned this Mar 22, 2026
@ematipico ematipico added this to the Biome v2.5 milestone Mar 22, 2026
Copy link
Copy Markdown
Member

I can split the PR into three or add the option to the SCSS part and keep it up to date, whatever you folks prefer.

It would be great if you could split up the PR in multiple PRs (as you see fit). That would help. ,For example I saw a bug but I lost the file because there are too many.

I recall that in foo<T>(), <T> doesn't get the spaces, but I seem to remember that we document that the spaces are applied to angle brackets <>

@luisherranz
Copy link
Copy Markdown
Author

luisherranz commented Mar 24, 2026

It would be great if you could split up the PR in multiple PRs (as you see fit)

I've split the PR into all these branches, but I've just realized that they can't be opened with the correct base if some branches originate from others when all of them are coming from a fork.

What do you want me to do? Should I open them all against upstream:next?

All branches target next. ESLint, JS, CSS, and JSON depend on core. JSX and TS depend on JS.

@ematipico
Copy link
Copy Markdown
Member

ematipico commented Mar 25, 2026

What do you want me to do? Should I open them all against upstream:next?

Yeah, that sounds good! HEADS UP! I just merged a few things around the formatter testing infrastructure. It's now less noisy, and the snapshots are different. You should see different outputs from the snapshots, and less changes. Thankfully, the PR should be more bearable.

I'll help you to bring the PRs to the finish line

@luisherranz
Copy link
Copy Markdown
Author

I just merged a few things around the formatter testing infrastructure. It's now less noisy, and the snapshots are different. You should see different outputs from the snapshots, and less changes. Thankfully, the PR should be more bearable.

Looks great!

However, I see some errors in next right now. One is in JsonAnalyzeServices, which is missing project_layout and preventing the build. Once that's fixed, there are 26 HTML snapshots from Astro, Vue, and Svelte that are not up to date.

Do you want me to open a PR to fix those things before opening mines, or could you let me know when that's resolved? Thank you very much.

@ematipico
Copy link
Copy Markdown
Member

I can fix those, so you can focus on your stuff. If they prevent you from moving forward, feel free to fix them on your branch (the formatting one). I'll help to update the PRs once the fixes are in next

@luisherranz
Copy link
Copy Markdown
Author

Great, thank you very much.

Let me know when next is free of issues and I'll rebase my branches and open all the PRs with all the updated snapshots.

@ematipico
Copy link
Copy Markdown
Member

@luisherranz the next branch should be good to go

@luisherranz
Copy link
Copy Markdown
Author

luisherranz commented Mar 30, 2026

Thanks @ematipico!

I've already opened all the PRs against next. They're still in draft because I wanted to take one last look at them tomorrow, but as soon as I review them, I'll mark them as ready for review.

@luisherranz
Copy link
Copy Markdown
Author

Superseed by #9718.

@luisherranz
Copy link
Copy Markdown
Author

The main branch adding the option and all the JavaScript branches are already ready for review.

Tomorrow or the day after, I'll continue with CSS, JSON, and ESLint.

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

Labels

A-CLI Area: CLI A-Formatter Area: formatter A-Project Area: project L-CSS Language: CSS and super languages L-JavaScript Language: JavaScript and super languages L-JSON Language: JSON and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants