Skip to content

feat(html): improved parsing spread attributes#8894

Merged
ematipico merged 2 commits intonextfrom
feat/spread-html-attribute
Jan 28, 2026
Merged

feat(html): improved parsing spread attributes#8894
ematipico merged 2 commits intonextfrom
feat/spread-html-attribute

Conversation

@ematipico
Copy link
Member

@ematipico ematipico commented Jan 28, 2026

Summary

Closes #8887
Part of #8590
Closes #8851

I believe we're almost there, and we are stable enough to finally say that Svelte is definitely more stable and usable.

Test Plan

Added new tests

Docs

N/A

@changeset-bot
Copy link

changeset-bot bot commented Jan 28, 2026

🦋 Changeset detected

Latest commit: d1930a3

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-CLI Area: CLI A-Project Area: project A-Parser Area: parser A-Formatter Area: formatter A-Tooling Area: internal tools L-HTML Language: HTML and super languages labels Jan 28, 2026
@ematipico ematipico force-pushed the feat/spread-html-attribute branch from 2ee68a3 to abbfc67 Compare January 28, 2026 10:15
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 28, 2026

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing feat/spread-html-attribute (d1930a3) with next (fda74af)

Summary

✅ 4 untouched benchmarks
⏩ 152 skipped benchmarks1

Footnotes

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 28, 2026

Walkthrough

This PR adds parsing support for spread attributes in Svelte and Astro files, enabling syntax like {...props} on HTML elements and components. It introduces new parser functions for both frameworks, updates the HTML syntax grammar to include HtmlSpreadAttribute, adds corresponding formatter implementations, and extends test coverage with both valid and error cases across multiple test suites.

Possibly related PRs

Suggested reviewers

  • dyc3
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding improved parsing support for spread attributes in HTML-like files (Svelte/Astro).
Linked Issues check ✅ Passed The PR successfully implements spread attribute parsing for Svelte and Astro, addressing the core requirement from issue #8887.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing spread attribute parsing: syntax definitions, parsers, formatters, and tests.
Description check ✅ Passed The PR description clearly relates to the changeset by explaining that spread attributes parsing support is being added for Svelte and Astro, with references to specific closed/related issues.

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


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: 4

🤖 Fix all issues with AI agents
In `@crates/biome_html_parser/src/syntax/mod.rs`:
- Around line 739-758: The current condition in parse_name misuses
should_bail_if and causes tokens to be consumed when callers pass |_| true;
change the early-return to bail when a name is missing AND should_bail_if(p) is
true (i.e., replace `if !p.at(IDENT) && !should_bail_if(p) { return Absent; }`
with `if !p.at(IDENT) && should_bail_if(p) { return Absent; }`) so missing names
fail instead of being consumed, and update any call sites that relied on the old
inverted semantics of the should_bail_if closure.
- Around line 465-472: The match arm ordering currently checks
SingleTextExpressions before Astro, so when both flags are enabled (Astro
frontmatter + SingleTextExpressions) the parse_astro_spread_or_expression branch
is shadowed; swap the two guards so the T!['{'] if Astro.is_supported(p) =>
parse_astro_spread_or_expression(p) arm comes before the T!['{'] if
SingleTextExpressions.is_supported(p) => parse_svelte_spread_or_expression(p)
arm (leave the fallback T!['{'] exclusive parse_exclusive_syntax entry
unchanged) to ensure Astro-specific parsing runs first.

In `@crates/biome_html_parser/src/syntax/svelte.rs`:
- Around line 359-389: parse_svelte_spread_or_expression currently calls
parse_name after consuming "..." which only accepts a single identifier; replace
that with the general expression parser so spread attributes accept arbitrary JS
expressions. Specifically, in parse_svelte_spread_or_expression, instead of
parse_name(p, HtmlLexContext::Svelte, ...), invoke the module's general
expression parsing entry (the same parser used for text expressions—e.g., the
logic behind parse_single_text_expression or a parse_expression(p,
HtmlLexContext::Svelte) helper) to parse any valid expression, keep the existing
diagnostic (.or_add_diagnostic(...)) if parsing fails, and then expect the
closing '}' as before before completing HTML_SPREAD_ATTRIBUTE.

In `@xtask/codegen/html.ungram`:
- Line 212: The grammar rule for spread attribute currently restricts the
argument to an identifier via "HtmlName = 'ident'" / "argument: HtmlName", which
rejects valid JS expressions (e.g., {...foo.bar}, {...getProps()}, {...cond ? a
: b}); change the grammar so the spread attribute argument uses a generic
expression production instead of HtmlName (e.g., use the existing Expression or
JsExpression nonterminal) and update the parser code handling the spread
attribute (the parser branch that consumes "argument" in the spread-attribute
handling code) to parse and store a full expression node rather than only an
identifier; apply the same change to the other spread-attribute occurrences
referenced (the second spread-attribute production area) so both grammar and
parser accept arbitrary expressions.

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.

I tested this on a private repo I have and https://github.com/huntabyte/shadcn-svelte. This definitely resolves a lot of the parsing errors, but IMO there's still too many false positives for the rules to fully close #8590.

@ematipico
Copy link
Member Author

I tested this on a private repo I have and huntabyte/shadcn-svelte. This definitely resolves a lot of the parsing errors, but IMO there's still too many false positives for the rules to fully close #8590.

Yeah definitely. I updated the PR description, and we could use that issue to collect issues/bugs

@github-actions github-actions bot removed the A-Project Area: project label Jan 28, 2026
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: 0

Caution

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

⚠️ Outside diff range comments (1)
crates/biome_html_parser/src/syntax/mod.rs (1)

427-448: Remove duplicate match arm.

The second T!["{{"] arm (lines 438-448) is unreachable—Rust's match evaluates top-to-bottom, so the first arm at lines 427-436 always wins. This looks like a merge artefact.

🐛 Proposed fix
         T!["{{"] => {
             let m = p.start();
             DoubleTextExpressions
                 .parse_exclusive_syntax(
                     p,
                     |p| parse_double_text_expression(p, HtmlLexContext::InsideTag),
                     |p, marker| disabled_interpolation(p, marker.range(p)),
                 )
                 .ok();
             Present(m.complete(p, HTML_ATTRIBUTE))
         }
-        T!["{{"] => {
-            let m = p.start();
-            HtmlSyntaxFeatures::DoubleTextExpressions
-                .parse_exclusive_syntax(
-                    p,
-                    |p| parse_double_text_expression(p, HtmlLexContext::InsideTag),
-                    |p, marker| disabled_interpolation(p, marker.range(p)),
-                )
-                .ok();
-
-            Present(m.complete(p, HTML_ATTRIBUTE))
-        }
🧹 Nitpick comments (1)
crates/biome_html_parser/src/syntax/astro.rs (1)

46-77: LGTM!

The implementation correctly handles Astro spread attributes and mirrors the Svelte implementation. The comment explaining why HtmlLexContext::Svelte is used for lexing ... is helpful.

The logic is nearly identical to parse_svelte_spread_or_expression in svelte.rs. If spread parsing grows more complex, consider extracting a shared helper that takes the feature check as a parameter.

@ematipico ematipico requested a review from dyc3 January 28, 2026 15:09
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.

I believe this should also close #8851

When I get a chance, I'll start filing issues related to #8590

@ematipico ematipico merged commit 6bf1b09 into next Jan 28, 2026
19 checks passed
@ematipico ematipico deleted the feat/spread-html-attribute branch January 28, 2026 18:31
@github-actions github-actions bot mentioned this pull request Feb 14, 2026
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-Parser Area: parser A-Tooling Area: internal tools L-HTML Language: HTML and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants