Skip to content

Conversation

@matanshavit
Copy link
Contributor

@matanshavit matanshavit commented Nov 4, 2025

Summary

Fixes #7875, fixes #7960 where whitespace was being incorrectly removed after closing tags of inline elements and around text expressions (e.g., {name} in Astro/Vue/Svelte).

AI assistance notice

I used Claude Code to write most of the code and comments in this pull request. As the human author, I take full responsibility for its contents.

Test Plan

I added snapshot tests for the straightforward and edge cases around preserving whitespace around text expressions and in tags in whitespace-sensitve mode.

Some snapshots that test other things like long tag children needed to be updated, but they appear to be unrelated to whitespace preservation, and can be safely changed without changing the meaning of the tests.

Note - unimplemented nodes/tokens are expected with snapshots of framework tests because of limited support for html-ish languages (compared to support for just html).

…ext expressions

Fixed an issue where whitespace was being incorrectly removed after closing
tags of inline elements and around text expressions (e.g., {name} in
Astro/Vue/Svelte). The formatter now:

- Preserves trailing whitespace after inline element closing tags when in
  whitespace-sensitive mode
- Treats text expressions as whitespace-sensitive elements to maintain
  proper spacing around them

This ensures proper rendering when formatting HTML with inline elements
followed by text, or when using framework-specific text expressions.
@changeset-bot
Copy link

changeset-bot bot commented Nov 4, 2025

⚠️ No Changeset found

Latest commit: 9bfa970

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-HTML Language: HTML and super languages labels Nov 4, 2025
@matanshavit matanshavit marked this pull request as ready for review November 4, 2025 17:15
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

This PR addresses whitespace handling in the HTML formatter, specifically fixing issues where spaces were incorrectly removed after inline closing tags and text expressions. The changes add conditional logic to preserve trailing whitespace after closing angle brackets when whitespace sensitivity is strict, and introduce a new is_text_expression() helper to detect and correctly handle text expressions (like interpolations) as whitespace-sensitive nodes. Several new test cases validate the fixes across different scenarios (strict mode, inline elements, component frameworks) and configuration modes.

Possibly related PRs

  • PR #6907: Introduces parsing and formatter rules for single/double text expression nodes in HTML, which this PR builds upon to properly handle whitespace sensitivity for these newly-supported node types.

Suggested reviewers

  • ematipico
  • dyc3

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the primary fix: preserving whitespace around inline elements and text expressions in the HTML formatter.
Description check ✅ Passed The description clearly relates to the changeset, explaining the issues being fixed (#7875, #7960), the approach taken, and test coverage added.
Linked Issues check ✅ Passed The code changes directly address both linked issues: handling trailing whitespace in closing elements [#7960] and detecting text expressions as whitespace-sensitive [#7875], with comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are scoped to whitespace handling in HTML formatting. Test files added align with the fix objectives; some snapshot updates appear to be expected consequences of the whitespace preservation logic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b28f5f and 9bfa970.

⛔ Files ignored due to path filters (13)
  • crates/biome_html_formatter/tests/specs/html/component-frameworks/astro-expressions-whitespace.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/elements/inline/mixed-expressions-elements.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/elements/inline/nested_inline_expressions.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/elements/inline/tags-hug-content-longer-w-attr.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-after-closing-tag.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/whitespace-after-closing-tag-strict.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/svelte/debug.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/text_expressions/multiple_expressions.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/html/text_expressions/single_expressions_whitespace.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/prettier/html/tags/tags.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_formatter/tests/specs/prettier/html/whitespace/inline-nodes.html.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (13)
  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs (1 hunks)
  • crates/biome_html_formatter/src/utils/metadata.rs (3 hunks)
  • crates/biome_html_formatter/tests/specs/html/component-frameworks/astro-expressions-whitespace.astro (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/elements/inline/mixed-expressions-elements.astro (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/elements/inline/nested_inline_expressions.astro (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-after-closing-tag.html (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/options.json (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/whitespace-after-closing-tag-strict.html (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/options.json (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/text_expressions/multiple_expressions.vue (1 hunks)
  • crates/biome_html_formatter/tests/specs/html/text_expressions/single_expressions_whitespace.vue (1 hunks)
🧰 Additional context used
🧠 Learnings (22)
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/src/lib.rs : Implement FormatLanguage for HtmlFormatLanguage with associated types: SyntaxLanguage=HtmlLanguage, Context=HtmlFormatContext, FormatRule=FormatHtmlSyntaxNode

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs
  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/src/cst.rs : Create FormatHtmlSyntaxNode in cst.rs implementing FormatRule<HtmlSyntaxNode> and AsFormat/IntoFormat for HtmlSyntaxNode using the provided plumbing

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs
  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/src/**/*.rs : After generation, remove usages of `format_verbatim_node` and implement real formatting with biome_formatter utilities

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro
  • crates/biome_html_formatter/src/utils/metadata.rs
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro
📚 Learning: 2025-10-15T09:22:46.002Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:46.002Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : For non-mandatory tokens, use the provided helper constructors (e.g., `token`, `space_token`, `dynamic_token`)

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs
  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:46.002Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:46.002Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : When a token is mandatory and present in the AST, use the AST-provided token (e.g., `node.l_paren_token().format()`) instead of emitting a static token

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs
  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/tests/language.rs : Create tests/language.rs defining `HtmlTestFormatLanguage` and implement the TestFormatLanguage trait

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/whitespace-after-closing-tag-strict.html
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/options.json
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro
  • crates/biome_html_formatter/src/utils/metadata.rs
  • crates/biome_html_formatter/tests/specs/html/component-frameworks/astro-expressions-whitespace.astro
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/options.json
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/src/comments.rs : Define HtmlCommentStyle implementing CommentStyle in comments.rs

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs
  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:46.002Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:46.002Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Do not attempt to fix code; if a mandatory token/node is missing, return `None` instead

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/src/comments.rs : Expose a public HtmlComments type alias: `pub type HtmlComments = Comments<HtmlLanguage>;`

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/closing_element.rs
  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/tests/specs/html/**/*.html : Place HTML test cases under tests/specs/html as .html files discovered by the test macro

Applied to files:

  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/whitespace-after-closing-tag-strict.html
  • crates/biome_html_formatter/tests/specs/html/text_expressions/multiple_expressions.vue
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-after-closing-tag.html
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/options.json
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro
  • crates/biome_html_formatter/tests/specs/html/elements/inline/nested_inline_expressions.astro
  • crates/biome_html_formatter/tests/specs/html/component-frameworks/astro-expressions-whitespace.astro
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/options.json
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro
  • crates/biome_html_formatter/tests/specs/html/text_expressions/single_expressions_whitespace.vue
  • crates/biome_html_formatter/tests/specs/html/elements/inline/mixed-expressions-elements.astro
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/tests/spec_tests.rs : In tests/spec_tests.rs, generate tests with `tests_macros::gen_tests! {"tests/specs/html/**/*.html", crate::spec_test::run, ""}`

Applied to files:

  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/whitespace-after-closing-tag-strict.html
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-after-closing-tag.html
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/options.json
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro
  • crates/biome_html_formatter/tests/specs/html/elements/inline/nested_inline_expressions.astro
  • crates/biome_html_formatter/tests/specs/html/component-frameworks/astro-expressions-whitespace.astro
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/options.json
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/tests/** : Create a tests directory containing a specs subfolder and the files spec_test.rs, spec_tests.rs, and language.rs

Applied to files:

  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/whitespace-after-closing-tag-strict.html
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/options.json
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro
  • crates/biome_html_formatter/tests/specs/html/component-frameworks/astro-expressions-whitespace.astro
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/options.json
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/tests/specs/**/options.json : Use options.json files colocated with test inputs to override formatting options for all files in that folder

Applied to files:

  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/options.json
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/options.json
📚 Learning: 2025-08-05T14:43:29.581Z
Learnt from: dyc3
Repo: biomejs/biome PR: 7081
File: packages/@biomejs/biome/configuration_schema.json:7765-7781
Timestamp: 2025-08-05T14:43:29.581Z
Learning: The file `packages/biomejs/biome/configuration_schema.json` is auto-generated and should not be manually edited or reviewed for schema issues; any changes should be made at the code generation source.

Applied to files:

  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/options.json
  • crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/options.json
📚 Learning: 2025-10-15T09:25:05.698Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:25:05.698Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Place watcher tests related to workspace methods in src/workspace/watcher.tests.rs

Applied to files:

  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro
📚 Learning: 2025-10-15T09:25:05.698Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:25:05.698Z
Learning: Applies to crates/biome_service/../biome_lsp/src/server.tests.rs : Keep end-to-end LSP tests in ../biome_lsp/src/server.tests.rs

Applied to files:

  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro
  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro
📚 Learning: 2025-10-15T09:22:46.002Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:46.002Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Import and use the `FormatNode` trait for AST nodes

Applied to files:

  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/src/context.rs : Create HtmlFormatContext in context.rs with comments and source_map fields and implement FormatContext and CstFormatContext

Applied to files:

  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/src/lib.rs : Define the HtmlFormatter type alias: `type HtmlFormatter<'buf> = Formatter<'buf, HtmlFormatContext>;`

Applied to files:

  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/src/lib.rs : Expose a documented public function `format_node(options: HtmlFormatOptions, root: &HtmlSyntaxNode) -> FormatResult<Formatted<HtmlFormatContext>>` delegating to `biome_formatter::format_node`

Applied to files:

  • crates/biome_html_formatter/src/utils/metadata.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/tests/spec_test.rs : Implement a `run` function in tests/spec_test.rs that wires SpecSnapshot and includes!("language.rs") as shown

Applied to files:

  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro
📚 Learning: 2025-10-15T09:24:31.042Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:24:31.042Z
Learning: Applies to crates/biome_parser/crates/biome_*_{syntax,factory}/** : Create per-language crates biome_<lang>_syntax and biome_<lang>_factory under crates/

Applied to files:

  • crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro
🧬 Code graph analysis (1)
crates/biome_html_formatter/src/html/auxiliary/closing_element.rs (1)
crates/biome_formatter/src/builders.rs (1)
  • space (606-608)
🔇 Additional comments (15)
crates/biome_html_formatter/tests/specs/html/text_expressions/single_expressions_whitespace.vue (1)

1-5: LGTM!

Test fixture appropriately covers single text expressions with surrounding whitespace across different elements.

crates/biome_html_formatter/tests/specs/html/text_expressions/multiple_expressions.vue (1)

1-5: LGTM!

Excellent coverage of edge cases including consecutive expressions with varying whitespace patterns.

crates/biome_html_formatter/tests/specs/html/elements/inline/mixed-expressions-elements.astro (1)

1-5: LGTM!

Test fixture correctly exercises the key scenario: interleaved text expressions and inline elements with whitespace.

crates/biome_html_formatter/tests/specs/html/elements/inline/nested_inline_expressions.astro (1)

1-7: LGTM!

Nested inline element scenarios are well covered, ensuring the formatter handles complex nesting correctly.

crates/biome_html_formatter/src/utils/metadata.rs (3)

3-3: LGTM!

Import addition correctly brings in AnyHtmlContent variants needed for text expression detection.


782-787: LGTM!

Early-return logic correctly treats text expressions as whitespace-sensitive in strict or CSS modes, ensuring spaces around interpolations are preserved as intended.


820-826: LGTM!

Helper function cleanly identifies text expressions using appropriate pattern matching.

crates/biome_html_formatter/src/html/auxiliary/closing_element.rs (1)

60-66: LGTM!

Trailing whitespace preservation mirrors the existing leading whitespace logic and correctly addresses the core issue.

crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/options.json (1)

1-8: LGTM!

Configuration appropriately enables testing the "ignore" whitespace sensitivity mode.

crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_line_boundaries.astro (1)

1-8: LGTM!

Line boundary scenarios are crucial for ensuring the formatter doesn't incorrectly collapse whitespace across lines.

crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/options.json (1)

1-8: LGTM! Configuration correctly enables strict whitespace mode.

The configuration appropriately sets strict whitespace sensitivity for testing the formatter's behaviour in this mode.

crates/biome_html_formatter/tests/specs/html/text_expressions/expressions_ignore/expressions-whitespace-ignore.astro (1)

1-1: Good minimal test case for expression whitespace.

This concisely tests whitespace preservation around text expressions with the added complexity of parentheses.

crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-strict/whitespace-after-closing-tag-strict.html (1)

1-3: LGTM! Effectively tests strict whitespace preservation.

This test case should validate that the space after the </span> closing tag is preserved in strict mode.

crates/biome_html_formatter/tests/specs/html/elements/inline/whitespace-after-closing-tag.html (1)

1-11: Excellent test coverage for inline element whitespace scenarios.

These test cases cover various combinations of inline elements and whitespace patterns, providing comprehensive validation for the whitespace preservation fixes.

crates/biome_html_formatter/tests/specs/html/component-frameworks/astro-expressions-whitespace.astro (1)

1-6: LGTM! Comprehensive Astro expression test cases.

This fixture provides excellent coverage for various Astro expression patterns, including parenthesised expressions, multiple expressions with spacing, and expressions in arithmetic contexts.


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.

@dyc3 dyc3 self-requested a review November 4, 2025 19:57
Copy link
Contributor

@dyc3 dyc3 left a comment

Choose a reason for hiding this comment

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

yeah this one's gonna be a little rough. if you're only using ai for this... good luck.

note that some of the playgrounds i posted are using svelte and not astro. there's something wrong with the playground and astro files.

also needs a changeset

Comment on lines +40 to +41
Start {expr1}
{expr2}middle end {expr3}
Copy link
Contributor

Choose a reason for hiding this comment

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

The space from the input {expr2} middle disappeared in the output.

It's a bit weird that it keeps the newline between {expr1} and {expr2}, but it matches prettier behavior, so keep it.

Comment on lines +7 to +12
```vue
<template>
<p>{a} {b} {c}</p>
<div>{firstName}{middleInitial}.{lastName}</div>
<span> {padded} </span>
</template>
Copy link
Contributor

Choose a reason for hiding this comment

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

Vue uses {{ and }}

Comment on lines +7 to +11
```vue
<template>
<p>User: {name} ({username})</p>
<div>{count} items in cart</div>
<span>{first} {last}</span>
Copy link
Contributor

Choose a reason for hiding this comment

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

same thing here

Comment on lines +41 to +43
<p>{name}({username})</p>
<p>Hello {firstName} {lastName}!</p>
<p>{a}+ {b}= {sum}</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. The space between {name} and ({username}) disappeared.
  2. The spaces before the + and = disappeared.

Comment on lines +35 to +47
```astro
<div>
<span>Name:</span>
{fullName}
<span>Age:</span>
{age}
</div>
<p>
<strong>Total:</strong>
{price}
<em>(tax included)</em>
</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

-----

```astro
<p>{name}({username})</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

The space disappeared

@ematipico
Copy link
Member

It would be nice if the PR description would highlight what kind of strategy (business logic) was used to fix the bug.

Without it, I wouldn't know what to review and how.

}

/// Whether the element is a text expression (like `{name}` in HTML-ish languages)
pub(crate) fn is_text_expression(element: &AnyHtmlElement) -> bool {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
pub(crate) fn is_text_expression(element: &AnyHtmlElement) -> bool {
const pub(crate) fn is_text_expression(element: &AnyHtmlElement) -> bool {

&& is_whitespace_sensitive
&& r_angle_token.has_trailing_whitespace()
{
write!(f, [space()])?;
Copy link
Member

Choose a reason for hiding this comment

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

Why do we add a whitespace?

@alissonlauffer
Copy link
Contributor

I see there are other issues related to whitespaces. I think we should revisit these to know whether this PR also resolves them:
#4927
#6407

My issue (#7875) was almost a duplicate of these, but it also encompasses expressions.

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

Labels

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

Projects

None yet

4 participants