Skip to content

feat(html): directives parsing and formatting#8719

Merged
ematipico merged 7 commits intonextfrom
feat/svelte-directives-parsing
Jan 9, 2026
Merged

feat(html): directives parsing and formatting#8719
ematipico merged 7 commits intonextfrom
feat/svelte-directives-parsing

Conversation

@ematipico
Copy link
Member

Summary

Closes #8600

This PR adds a specialised parsing of Svelte directives.

As decided in #8600, the parser won't check if the value of a directive is actually valid or not. We will do that in a separate rule (probably a syntax rule).

I also added benchmarks for HTML. I believe it's time, we're almost getting there.

Test Plan

I used AI to generate the tests.

Docs

@changeset-bot
Copy link

changeset-bot bot commented Jan 9, 2026

🦋 Changeset detected

Latest commit: 119ce98

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

@ematipico ematipico requested review from a team and dyc3 January 9, 2026 14:56
@github-actions github-actions bot added A-Parser Area: parser A-Formatter Area: formatter A-Tooling Area: internal tools L-HTML Language: HTML and super languages labels Jan 9, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

Walkthrough

This pull request implements parsing and formatting support for Svelte directives in the HTML formatter. The changes introduce lexer and parser support for eight directive types (bind, transition, in, out, use, animate, style, class), along with their values, modifiers, and optional initializers. Formatter implementations are added for each directive type with support for compact formatting mode, which transforms patterns like x={x} to {x} and bind:x={x} to bind:x. The grammar is updated to define Svelte directive structures, and comprehensive test coverage is provided for both valid and error cases. A new HTML benchmark workflow is also introduced to measure formatter performance via CodSpeed.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarises the primary change: adding Svelte directives parsing and formatting support, which is the main focus of this PR.
Description check ✅ Passed The description is related to the changeset, explaining the motivation (issue #8600), approach (specialised Svelte directive parsing), and mentioning benchmarks and AI-generated tests.
Linked Issues check ✅ Passed The PR addresses issue #8600's core requirements: implementing Svelte directive parsing and formatting to convert x={x} to {x} and bind:x={x} to bind:x, with parser remaining deliberately uninvolved in value validation.
Out of Scope Changes check ✅ Passed All changes are directly scoped to Svelte directive support: parser updates (lexer, syntax, token context), formatter implementations, HTML grammar extensions, and comprehensive test coverage. Benchmark infrastructure additions align with stated objective.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

Caution

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

⚠️ Outside diff range comments (2)
crates/biome_html_parser/benches/html_parser.rs (1)

1-6: Remove the duplicate BenchCase import.

You've imported BenchCase from both biome_bench_utils (line 1) and biome_test_utils (line 6). The latter shadows the former, making line 1's import unused. Please remove whichever import is incorrect.

🧹 Proposed fix

If biome_bench_utils::BenchCase is the correct one to use:

-use biome_bench_utils::BenchCase;
-
 use biome_diagnostics::{DiagnosticExt, print_diagnostic_to_string};
 use biome_html_parser::{HtmlParseOptions, parse_html, parse_html_with_cache};
 use biome_html_syntax::HtmlFileSource;
 use biome_rowan::NodeCache;
-use biome_test_utils::BenchCase;
+use biome_bench_utils::BenchCase;

If biome_test_utils::BenchCase is the correct one to use:

-use biome_bench_utils::BenchCase;
-
 use biome_diagnostics::{DiagnosticExt, print_diagnostic_to_string};
 use biome_html_parser::{HtmlParseOptions, parse_html, parse_html_with_cache};
 use biome_html_syntax::HtmlFileSource;
 use biome_rowan::NodeCache;
 use biome_test_utils::BenchCase;
crates/biome_html_parser/src/syntax/mod.rs (1)

356-378: Duplicate match arm detected.

Lines 356-365 and 367-378 both match T!["{{"]. The second arm (367-378) is unreachable code. This looks like an unintended duplication—one of these should likely be removed.

🐛 Proposed fix
     match p.cur() {
         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))
-        }
         T![:] => HtmlSyntaxFeatures::Vue.parse_exclusive_syntax(
🤖 Fix all issues with AI agents
In @.github/workflows/benchmark_html.yml:
- Line 1: The workflow name string "Benchmarks JS" should be updated to reflect
that it benchmarks HTML crates; replace the name value with something like
"Benchmarks HTML" (update the top-level name field in the workflow where
"Benchmarks JS" appears) so the workflow title matches the
biome_html_parser/biome_html_formatter/biome_html_analyze targets.

In @crates/biome_html_formatter/src/html/any/attribute_initializer.rs:
- Line 1: The file-level comment indicates the file is autogenerated but was
manually edited; either re-run the generator (cargo codegen formatter) to
regenerate crates/biome_html_formatter/src/html/any/attribute_initializer.rs so
the generated header is accurate, or remove/replace the "This is a generated
file. Don't modify it by hand!" comment and update the module comment to reflect
that attribute_initializer.rs is now hand-maintained (keep the compact mode
changes intact if manual).

In @crates/biome_html_parser/src/syntax/svelte.rs:
- Around line 1185-1190: The parse_element function currently swallows missing
modifier names by calling parse_name(p).ok(); instead detect when parse_name(p)
returns Absent and emit a parse diagnostic before completing the node so a
trailing pipe like `bind:value|` produces an error. Replace the `.ok()` call
with an explicit match on the parse_name(p) result and on the Absent branch call
the parser's error reporting (e.g., p.error(...) or the project's equivalent)
with a message like "expected modifier name", then still complete m as
SVELTE_DIRECTIVE_MODIFIER.

In
@crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_invalid_params.svelte:
- Line 1: The test fixture uses an unquoted '>' that prematurely closes the
start tag; change the Svelte snippet so the error stays inside the directive
parameters (i.e., keep the start tag and braces balanced) and make the
expression inside the in:fly params syntactically invalid—for example close the
tag/braces but leave the object or expression incomplete or malformed inside the
{{ ... }} of the in:fly directive so the parser reports an error specific to
directive params (refer to the in:fly directive in this file).

In @crates/biome_html_syntax/src/text_ext.rs:
- Around line 5-10: Update the rustdoc for the method string_value() to clarify
it returns the string value of a text expression (unquoted content like
{expression}) rather than implying it strips quotes; e.g., change "Returns the
string value of the attribute, if available, without quotes." to something like
"Returns the string value of the text expression, if available." and ensure the
comment references that this is for HtmlTextExpression/unquoted content to avoid
implying quote removal.

In @xtask/codegen/html.ungram:
- Around line 558-563: The SvelteDirectiveValue production has inconsistent
indentation (line with "initializer: HtmlAttributeInitializerClause?" uses two
spaces instead of a tab); update the indentation to match the other lines (use a
tab before "initializer: HtmlAttributeInitializerClause?") so the
SvelteDirectiveValue block aligns with the rest of the grammar; verify the
change around the SvelteDirectiveValue symbol and ensure no other lines in that
production use spaces.
- Around line 498-507: The grammar rule AnySvelteDirective contains inconsistent
indentation: SvelteInDirective through SvelteStyleDirective are indented with
two spaces while the rest of the file uses tabs; normalize the indentation by
replacing those two-space indents with a single tab so all alternatives
(SvelteBindDirective, SvelteTransitionDirective, SvelteInDirective,
SvelteOutDirective, SvelteUseDirective, SvelteAnimateDirective,
SvelteStyleDirective, SvelteClassDirective) align with the existing tab-based
formatting for the grammar.
🧹 Nitpick comments (8)
crates/biome_html_parser/tests/quick_test.rs (1)

4-19: Test input updated to exercise Svelte directive parsing.

The new test input correctly exercises the style: directive shorthand, aligning with the PR's Svelte directive parsing feature.

Minor observation: The blank line at line 8 appears deliberate but seems unnecessary for this test case. If it's intentional for whitespace handling validation, consider adding a comment to clarify.

crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_invalid_expression.svelte (1)

1-1: Consider adding the closing brace for test clarity.

The fixture tests two error conditions simultaneously: an invalid expression (>Invalid) and a missing closing brace. To isolate what's being tested, consider: <div class:active={>Invalid}></div>. The missing brace could be covered in a separate test like class_missing_closing_brace.svelte.

crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_invalid_expression.svelte (1)

1-1: Verify if multiple syntax errors are intentional.

This test fixture contains several syntax errors: an invalid expression (>Invalid), a missing closing brace for the expression, and an unclosed opening tag. Whilst testing compound error scenarios can be valuable, a test named use_invalid_expression might be clearer if it isolated the expression error.

Consider whether you want:

  • Current: Multiple errors for compound error recovery testing
  • Alternative: <div use:tooltip={>Invalid}></div> (isolates invalid expression)
  • Alternative: <div use:tooltip={1 + )}></div> (incomplete expression)

Is the compound error scenario intentional for this test case?

crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_value_basic.svelte (1)

1-1: Solid baseline for bind: with an explicit expression.

Optional follow-up (if not already covered elsewhere): add bind:value={value} to directly exercise the formatter’s shorthand rewrite path.

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

12-15: Unnecessary .clone() call.

value_token is already a SyntaxResult<SyntaxToken>, so the .clone() is superfluous. This differs from the pattern in crates/biome_html_formatter/src/svelte/auxiliary/literal.rs:12 which uses node.value_token()? directly.

♻️ Proposed simplification
         if self.compact {
-            let value_token = value_token.clone()?;
+            let value_token = value_token?;
             return format_removed(&value_token).fmt(f);
         }
crates/biome_html_formatter/src/html/auxiliary/single_text_expression.rs (1)

21-27: Optional: simplify by removing intermediate bindings and clones.

The cloning and intermediate bindings can be avoided:

if self.compact {
    format_removed(&l_curly_token?).fmt(f)?;
    format_removed(&r_curly_token?).fmt(f)?;
    expression?.format().with_options(self.compact).fmt(f)
} else {

This is cleaner and avoids the clones, though the performance impact is likely negligible.

crates/biome_html_formatter/src/utils/svelte_directive.rs (1)

15-20: Consider removing unused _node field.

The _node field is stored but never read. If it's reserved for future debugging or comments handling, a brief doc comment would clarify intent. Otherwise, it can be removed to reduce struct size.

♻️ If unused, consider removing
 pub(crate) struct FmtSvelteDirective<'a> {
-    _node: &'a HtmlSyntaxNode,
     token: SyntaxResult<HtmlSyntaxToken>,
     value: SyntaxResult<SvelteDirectiveValue>,
     allows_compact: bool,
 }

And update each From implementation to remove the _node / value.syntax() assignment.

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

152-160: Redundant clone() calls and explicit return.

The eq_token and value bindings from line 72 are already available here. The .clone() calls and explicit return Ok(()) can be simplified:

♻️ Proposed simplification
             CompactKind::Remove => {
-                let eq_token = eq_token.clone()?;
-                let value = value.clone()?;
+                let eq_token = eq_token?;
+                let value = value?;
                 write!(
                     f,
                     [format_removed(&eq_token), value.format().with_options(true),]
-                )?;
-                return Ok(());
+                )
             }

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

🧹 Nitpick comments (1)
Cargo.toml (1)

23-23: Relocate to the "not publish" section.

biome_bench_utils appears to be an internal benchmarking utility that won't be published. It should be moved below the # not publish comment (line 24) to align with the versioning pattern—published crates have versions, unpublished ones don't.

♻️ Proposed relocation

Remove from line 23 and add it after line 24 in the "not publish" section, for example after biome_cli:

-biome_bench_utils            = { path = "./crates/biome_bench_utils" }
 # not publish
+biome_bench_utils            = { path = "./crates/biome_bench_utils" }
 biome_cli                    = { path = "./crates/biome_cli" }
📜 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 ce72619 and 4edb762.

📒 Files selected for processing (1)
  • Cargo.toml
🧰 Additional context used
📓 Path-based instructions (1)
**/Cargo.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/Cargo.toml: Use workspace dependencies with workspace = true for internal crates in Cargo.toml
Use path dependencies for dev-dependencies in crates to avoid requiring published versions

Files:

  • Cargo.toml
🧠 Learnings (15)
📓 Common learnings
Learnt from: dyc3
Repo: biomejs/biome PR: 8291
File: crates/biome_html_formatter/tests/specs/prettier/vue/html-vue/elastic-header.html:10-10
Timestamp: 2025-12-04T13:29:49.287Z
Learning: Files under `crates/biome_html_formatter/tests/specs/prettier` are test fixtures synced from Prettier and should not receive detailed code quality reviews (e.g., HTTP vs HTTPS, formatting suggestions, etc.). These files are test data meant to validate formatter behavior and should be preserved as-is.
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Applies to **/Cargo.toml : Use workspace dependencies with `workspace = true` for internal crates in Cargo.toml

Applied to files:

  • Cargo.toml
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace*.rs : Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances

Applied to files:

  • Cargo.toml
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/Cargo.toml : Include development dependencies in `Cargo.toml` for formatter tests: `biome_formatter_test`, `biome_<language>_factory`, `biome_<language>_parser`, `biome_parser`, `biome_service`, `countme`, `iai`, `quickcheck`, `quickcheck_macros`, and `tests_macros`

Applied to files:

  • Cargo.toml
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests

Applied to files:

  • Cargo.toml
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Build debug binaries using `cargo build --bin biome` for development and triaging

Applied to files:

  • Cargo.toml
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Applies to **/Cargo.toml : Use path dependencies for dev-dependencies in crates to avoid requiring published versions

Applied to files:

  • Cargo.toml
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/server.rs : Use WorkspaceServer implementation for maintaining workspace state in daemon mode and CLI daemonless mode

Applied to files:

  • Cargo.toml
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use helper functions like `map`, `filter`, and `and_then` to avoid excessive nested `if let` statements

Applied to files:

  • Cargo.toml
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule options must be defined in the `biome_rule_options` crate with a file named after the rule

Applied to files:

  • Cargo.toml
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Create two new crates `biome_{language}_syntax` and `biome_{language}_factory` using `cargo new --lib` for new language parsers

Applied to files:

  • Cargo.toml
📚 Learning: 2025-11-24T18:04:47.058Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_aria_metadata/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:47.058Z
Learning: Applies to crates/biome_aria_metadata/**/build.rs : The `build.rs` script uses `aria-data.json` to generate ARIA metadata

Applied to files:

  • Cargo.toml
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use helper types from the biome_diagnostics::v2 module (CodeFrameAdvice, CommandAdvice, DiffAdvice, LogAdvice) or implement the Advices trait yourself for custom advice handling

Applied to files:

  • Cargo.toml
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(rename_all = "camelCase")]` to rule option structs to match JSON configuration naming convention

Applied to files:

  • Cargo.toml
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `.ok()?` to transform `Result` types into `Option` or `let else` pattern to handle errors when the function returns `Vec`

Applied to files:

  • Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Check Dependencies
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Bench (biome_html_analyze)
  • GitHub Check: Documentation
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_html_parser)

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.

Nice!

b'!' => self.consume_byte(T![!]),
b'{' if self.at_svelte_opening_block() => self.consume_svelte_opening_block(),
b'{' => {
let dispatched = lookup_byte(current);
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this do for us?

Copy link
Member Author

Choose a reason for hiding this comment

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

It speeds things up. We should always use the lookup table

// The speed difference comes from the difference in table size, a 2kb table is easily fit into cpu cache
// While a 16kb table will be ejected from cache very often leading to slowdowns, this also allows LLVM
// to do more aggressive optimizations on the match regarding how to map it to instructions

@github-actions github-actions bot added the A-Linter Area: linter label Jan 9, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 9, 2026

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 95 skipped benchmarks1


Comparing feat/svelte-directives-parsing (119ce98) with next (0f5a05b)

Open in CodSpeed

Footnotes

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

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

Caution

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

⚠️ Outside diff range comments (2)
xtask/codegen/html.ungram (1)

3-3: Fix the copy-paste error in the comment.

The comment incorrectly states this grammar specifies "Rust's concrete syntax tree". It should reference HTML instead.

📝 Proposed fix
-// This grammar specifies the structure of Rust's concrete syntax tree.
+// This grammar specifies the structure of HTML's concrete syntax tree.
crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs (1)

19-34: Docs don’t match behaviour for compact/CompactKind.

The field docs say “in compact mode, all tokens and children are removed”, but CompactKind::Curly keeps the value and only sometimes removes =. Consider updating the docs to describe each variant precisely (None/Remove/Curly).

Also applies to: 37-45

🤖 Fix all issues with AI agents
In
@crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs:
- Around line 74-90: The CompactKind::Remove branch currently calls
value.format().with_options(true) which uses an opaque bool that behaves
inconsistently for HtmlString vs HtmlSingleTextExpression; update this by
introducing a clear options type (e.g., RemoveOptions with a flag like
remove_entire_value vs remove_outer_wrapper) and thread it through
value.format().with_options(...) instead of a bare bool, or alternatively detect
the value variant (AnyHtmlAttributeInitializer::HtmlString vs
HtmlSingleTextExpression) in the CompactKind::Remove handling and call
format_removed(value) for HtmlString and the appropriate wrapper-only removal
for HtmlSingleTextExpression so that format_removed() is used when the entire
value must be omitted and only the braces are removed when intended.
- Around line 92-107: The match arm currently checks (Some("iframe"),
Some("allow")) using a case-sensitive comparison on self.tag_name and
self.attribute_name; change it to a case-insensitive check by comparing with
eq_ignore_ascii_case (e.g., check self.tag_name.as_deref().map(|s|
s.eq_ignore_ascii_case("iframe")) and similarly for attribute_name) or normalize
the stored values to lowercase before matching so the special iframe/allow
handling triggers for mixed- or upper-case HTML names.

In @crates/biome_html_parser/src/syntax/svelte.rs:
- Around line 941-945: parse_binding_literal currently always consumes a token;
modify it to follow the parser pattern by first checking p.at(HTML_LITERAL) and
returning Absent if false, otherwise proceed to start the marker (m =
p.start()), call p.bump_with_context(HTML_LITERAL, HtmlLexContext::InsideTag),
and complete the marker with SVELTE_LITERAL (Present(m.complete(...))). Ensure
you reference the same symbols: parse_binding_literal, p.at(HTML_LITERAL),
p.bump_with_context, m.start(), m.complete(..., SVELTE_LITERAL), and return
Absent when the token check fails.
🧹 Nitpick comments (3)
crates/biome_html_analyze/benches/html_analyzer.rs (2)

28-31: Simplify the single-entry HashMap.

The all_suites HashMap contains only one entry. Consider directly using the string constant or removing the intermediate HashMap structure for clarity.

♻️ Simplified version
-    let mut all_suites = HashMap::new();
-    all_suites.insert("html", include_str!("libs-html.txt"));
-    let mut libs = vec![];
-    libs.extend(all_suites.values().flat_map(|suite| suite.lines()));
+    let libs: Vec<_> = include_str!("libs-html.txt").lines().collect();

36-77: Consider validating parse success.

The benchmark directly uses the parse result without checking for parse errors. Whilst benchmarking malformed HTML is valuable, you might want to verify that test cases parse successfully to avoid skewing results with error paths.

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

110-116: Nice: iframe allow list formatting; small clean-up opportunity.

This is readable and matches the intended behaviour. Minor: JoinWithSemicolon could be a const/fn returning a formatter (or use join_with + closure) to reduce local type noise, but it’s not a blocker.

Also applies to: 117-143

📜 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 4edb762 and 119ce98.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock and included by **
📒 Files selected for processing (7)
  • .github/workflows/benchmark_html.yml
  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_analyze/benches/html_analyzer.rs
  • crates/biome_html_analyze/benches/libs-html.txt
  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
  • crates/biome_html_parser/src/syntax/svelte.rs
  • xtask/codegen/html.ungram
✅ Files skipped from review due to trivial changes (1)
  • crates/biome_html_analyze/benches/libs-html.txt
🧰 Additional context used
📓 Path-based instructions (2)
**/Cargo.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/Cargo.toml: Use workspace dependencies with workspace = true for internal crates in Cargo.toml
Use path dependencies for dev-dependencies in crates to avoid requiring published versions

Files:

  • crates/biome_html_analyze/Cargo.toml
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
  • crates/biome_html_parser/src/syntax/svelte.rs
  • crates/biome_html_analyze/benches/html_analyzer.rs
🧠 Learnings (49)
📓 Common learnings
Learnt from: dyc3
Repo: biomejs/biome PR: 8291
File: crates/biome_html_formatter/tests/specs/prettier/vue/html-vue/elastic-header.html:10-10
Timestamp: 2025-12-04T13:29:49.287Z
Learning: Files under `crates/biome_html_formatter/tests/specs/prettier` are test fixtures synced from Prettier and should not receive detailed code quality reviews (e.g., HTTP vs HTTPS, formatting suggestions, etc.). These files are test data meant to validate formatter behavior and should be preserved as-is.
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/Cargo.toml : Include development dependencies in `Cargo.toml` for formatter tests: `biome_formatter_test`, `biome_<language>_factory`, `biome_<language>_parser`, `biome_parser`, `biome_service`, `countme`, `iai`, `quickcheck`, `quickcheck_macros`, and `tests_macros`

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Avoid string allocations by using `&str` or `TokenText` instead of `to_string()`

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Deprecated rules must include a `deprecated` field in the `declare_lint_rule!` macro with an explanation of what rule to use instead

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : The first paragraph of rule documentation must be written in a single line to ensure proper rendering in the rules overview table

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `Markup!` macro for diagnostic messages and code action descriptions to ensure proper formatting

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_parser/src/syntax/svelte.rs
  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `action` function and add `fix_kind` metadata to the rule macro if the rule provides code actions

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_lint_rule!` macro with a `version` field set to `next` for new rules

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Create two new crates `biome_{language}_syntax` and `biome_{language}_factory` using `cargo new --lib` for new language parsers

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_node_union!` macro to query multiple node types together to avoid redundant traversal passes

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2025-12-22T09:27:13.161Z
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.

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_parser/src/syntax/svelte.rs
  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Build debug binaries using `cargo build --bin biome` for development and triaging

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Applies to **/Cargo.toml : Use path dependencies for dev-dependencies in crates to avoid requiring published versions

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Applies to **/Cargo.toml : Use workspace dependencies with `workspace = true` for internal crates in Cargo.toml

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace*.rs : Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(rename_all = "camelCase")]` to rule option structs to match JSON configuration naming convention

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Box<[Box<str>]>` instead of `Vec<String>` for collections of strings in rule options to save memory

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/tests/spec_tests.rs : Use the `tests_macros::gen_tests!` macro in `spec_tests.rs` to generate test functions for each specification file matching the pattern `tests/specs/<language>/**/*.<ext>`

Applied to files:

  • crates/biome_html_analyze/Cargo.toml
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : When formatting AST nodes, use mandatory tokens from the AST instead of hardcoding token strings (e.g., use `node.l_paren_token().format()` instead of `token("(")`)

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Define `FormatHtmlSyntaxNode` struct in a `cst.rs` file implementing `FormatRule<HtmlSyntaxNode>`, `AsFormat<HtmlFormatContext>`, and `IntoFormat<HtmlFormatContext>` traits using the provided boilerplate code

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Import the `FormatNode` trait and implement it for your Node when creating formatters in biome_js_formatter

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/lib.rs : Expose a public `format_node` function that accepts formatting options and a root syntax node, returning a `FormatResult<Formatted<Context>>` with appropriate documentation

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : For tokens that are not mandatory, use helper functions instead of hardcoding

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/context.rs : Define `<Language>FormatContext` struct in a `context.rs` file containing `comments` and `source_map` fields, implementing `FormatContext` and `CstFormatContext` traits

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/lib.rs : Define a type alias `<Language>Formatter<'buf>` as `Formatter<'buf, <Language>FormatContext>` in the main formatter crate

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Create a new formatter crate using the command `just new-crate biome_<language>_formatter` where `<language>` is the target language (e.g., `biome_html_formatter` for HTML)

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Do not attempt to 'fix' the code; if a token/node is known to be mandatory but is missing, return `None` instead

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Use the `dbg_write!` macro to debug formatter output instead of other logging methods

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Implement the `FormatNodeRule<N>` trait with `fmt_fields` as the only required method; default implementations of `fmt`, `is_suppressed`, `fmt_leading_comments`, `fmt_dangling_comments`, and `fmt_trailing_comments` are provided

Applied to files:

  • crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Use `ConditionalParsedSyntax` for syntax that is only valid in specific contexts (e.g., strict mode, file types, language versions) and call `or_invalid_to_bogus()` to convert to a bogus node if not supported

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Parse rules must take a mutable reference to the parser as their only parameter and return a `ParsedSyntax`

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Use `p.eat(token)` for optional tokens, `p.expect(token)` for required tokens, `parse_rule(p).ok(p)` for optional nodes, and `parse_rule(p).or_add_diagnostic(p, error)` for required nodes

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Parse rules must return `ParsedSyntax::Absent` if the rule can't predict by the next token(s) if they form the expected node, and must not progress the parser in this case

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `diagnostic` function to provide error messages explaining what the error is, why it is triggered, and what the user should do

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/*.ungram : Nodes for enclosing syntax errors must have the `Bogus` word, e.g., `HtmlBogusAttribute`, and must be part of a variant

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-11-09T12:47:46.298Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8031
File: crates/biome_html_parser/src/syntax/svelte.rs:140-147
Timestamp: 2025-11-09T12:47:46.298Z
Learning: In the Biome HTML parser, `expect` and `expect_with_context` consume the current token and then lex the next token. The context parameter in `expect_with_context` controls how the next token (after the consumed one) is lexed, not the current token being consumed. For example, in Svelte parsing, after `bump_with_context(T!["{:"], HtmlLexContext::Svelte)`, the next token is already lexed in the Svelte context, so `expect(T![else])` is sufficient unless the token after `else` also needs to be lexed in a specific context.

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/*.ungram : All grammar nodes must start with the prefix of the language, e.g., `HtmlSimpleAttribute`

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : A parser struct must implement the `Parser` trait and save the token source, parser context, and optional parser options

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Use `ParseSeparatedList` and `ParseNodeList` for parsing lists with error recovery to avoid infinite loops

Applied to files:

  • crates/biome_html_parser/src/syntax/svelte.rs
📚 Learning: 2025-12-04T13:29:49.287Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8291
File: crates/biome_html_formatter/tests/specs/prettier/vue/html-vue/elastic-header.html:10-10
Timestamp: 2025-12-04T13:29:49.287Z
Learning: Files under `crates/biome_html_formatter/tests/specs/prettier` are test fixtures synced from Prettier and should not receive detailed code quality reviews (e.g., HTTP vs HTTPS, formatting suggestions, etc.). These files are test data meant to validate formatter behavior and should be preserved as-is.

Applied to files:

  • .github/workflows/benchmark_html.yml
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use helper functions like `map`, `filter`, and `and_then` to avoid excessive nested `if let` statements

Applied to files:

  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Invalid code snippets in rule documentation must emit exactly one diagnostic

Applied to files:

  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use the `try operator (?)` to transform `Result` types into `Option` when the `run` function returns `Option`

Applied to files:

  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `.ok()?` to transform `Result` types into `Option` or `let else` pattern to handle errors when the function returns `Vec`

Applied to files:

  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use the `Semantic<T>` query type to access semantic information about bindings, references, and scope within a rule

Applied to files:

  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement custom `Queryable` and `Visitor` types for rules that require deep inspection of child nodes to avoid inefficient traversals

Applied to files:

  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `run` function to return `Option<Self::State>` or `Vec<Self::State>` (as `Box<[Self::State]>`) depending on whether the rule reports one or multiple signals

Applied to files:

  • crates/biome_html_analyze/benches/html_analyzer.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `rule_category!()` macro to refer to the diagnostic category instead of dynamically parsing its string name

Applied to files:

  • crates/biome_html_analyze/benches/html_analyzer.rs
🧬 Code graph analysis (1)
crates/biome_html_analyze/benches/html_analyzer.rs (2)
crates/biome_html_parser/src/lib.rs (1)
  • parse_html (37-40)
crates/biome_html_syntax/src/file_source.rs (1)
  • html (43-47)
🪛 actionlint (1.7.10)
.github/workflows/benchmark_html.yml

42-42: label "depot-ubuntu-24.04-arm-16" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-slim", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xlarge", "macos-14-large", "macos-14", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
  • GitHub Check: Check Dependencies
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Documentation
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Validate rules documentation
  • GitHub Check: Bench (biome_package)
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_tailwind_parser)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Bench (biome_html_analyze)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_configuration)
🔇 Additional comments (11)
.github/workflows/benchmark_html.yml (3)

1-35: Workflow structure looks solid.

Trigger conditions and path filters are appropriate for an HTML benchmark workflow.


73-79: Verify that the CODSPEED_TOKEN secret is configured.

The CodSpeed action requires the CODSPEED_TOKEN secret to upload benchmark results. Ensure this is configured in your repository secrets.


42-42: This runner is fine—it's Depot.dev in action.

The depot-ubuntu-24.04-arm-16 label is used throughout your CI/CD pipeline (48+ workflows) without issue. Actionlint flags it as "unknown" because it doesn't recognise third-party runners by default, but Depot.dev integration is properly configured at the repository level. No changes needed here.

crates/biome_html_analyze/Cargo.toml (2)

41-45: The dev-dependencies for tikv-jemallocator and mimalloc already use workspace = true, which is the correct approach per our guidelines. No changes needed here.

Likely an incorrect or invalid review comment.


37-37: The exact version constraint =3.0.5 for codspeed-criterion-compat is consistent across the entire codebase and appears intentional. No change needed here.

Likely an incorrect or invalid review comment.

crates/biome_html_parser/src/syntax/svelte.rs (4)

1089-1128: LGTM!

The two-phase approach (string prefix check followed by re-lexing) correctly handles the lexer's initial tokenisation of directive syntax. The context differentiation for class and style directives properly supports binding literals.


1130-1155: Solid implementation of directive value parsing.

The empty text check (line 1138) correctly validates that content follows the colon, and the context-based branching appropriately handles different directive types. The re-lex at line 1151 properly resets context when no initialiser is present.


1158-1207: LGTM!

The parse_directive helper and ModifiersList implementation follow the established parser patterns correctly. The use of expect_with_context for the pipe token is safe since parse_element is only called when the token is present.


1228-1255: LGTM!

The keyword additions and directive start detection correctly handle the lexer's initial tokenisation, enabling proper directive recognition. The string prefix matching in is_at_svelte_directive_start is the appropriate approach for pre-lexing detection.

xtask/codegen/html.ungram (2)

508-575: Well-structured and consistent directive grammar.

The directive definitions follow a clean, consistent pattern across all 8 types, with a shared SvelteDirectiveValue structure. The grammar is intentionally permissive (allowing modifiers and literals on all directives), which aligns perfectly with the PR objective to defer semantic validation to a separate rule.

The support for optional initialisers enables shorthand formatting (e.g., bind:value when the variable name matches), which addresses the core requirement from issue #8600.


498-507: Confirm whether event handler directives are intentionally out of scope.

The on: directive for event handlers (e.g., on:click={handler}) isn't implemented—no event handler parsing code exists in the codebase. Just confirming this is by design (Svelte 5 focus, deferred to a future PR, etc.) or if it should be added.

@ematipico ematipico merged commit a215408 into next Jan 9, 2026
32 checks passed
@ematipico ematipico deleted the feat/svelte-directives-parsing branch January 9, 2026 16:29
@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-Formatter Area: formatter A-Linter Area: linter 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