Skip to content

feat(html/nursery): add noDupeElseIfBlocks, noDupeStyleProperties, noDupeUseDirectives#10549

Open
Mokto wants to merge 6 commits into
biomejs:mainfrom
Mokto:feat/svelte-dupe-rules
Open

feat(html/nursery): add noDupeElseIfBlocks, noDupeStyleProperties, noDupeUseDirectives#10549
Mokto wants to merge 6 commits into
biomejs:mainfrom
Mokto:feat/svelte-dupe-rules

Conversation

@Mokto

@Mokto Mokto commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Ports three rules from eslint-plugin-svelte to Biome, all targeting Svelte templates (.svelte files):

All three rules are in the nursery group, tagged with RuleDomain::Svelte, and marked recommended: true.

Test plan

  • Snapshot tests for invalid and valid cases for all three rules (cargo test -p biome_html_analyze)
  • All 162 tests pass

This PR was written primarily by Claude Code.

…DupeUseDirectives

Port three eslint-plugin-svelte rules:
- noDupeElseIfBlocks: disallow duplicate conditions in {#if}/{:else if} chains
- noDupeStyleProperties: disallow duplicate style: directives on the same element
- noDupeUseDirectives: disallow duplicate use: directives on the same element

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jun 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6edb74c

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 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

✅ Organic activity

No automation signals detected in the analyzed events.

View full analysis →

This is an automated analysis by AgentScan

@github-actions github-actions Bot added A-CLI Area: CLI A-Project Area: project A-Linter Area: linter A-Diagnostic Area: diagnostocis L-HTML Language: HTML and super languages labels Jun 3, 2026
@Mokto Mokto changed the title [WIP] feat(html/nursery): add noDupeElseIfBlocks, noDupeStyleProperties, noDupeUseDirectives geat(html/nursery): add noDupeElseIfBlocks, noDupeStyleProperties, noDupeUseDirectives Jun 3, 2026
@Mokto Mokto changed the title geat(html/nursery): add noDupeElseIfBlocks, noDupeStyleProperties, noDupeUseDirectives feat(html/nursery): add noDupeElseIfBlocks, noDupeStyleProperties, noDupeUseDirectives Jun 3, 2026
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR adds three independent Svelte nursery lint rules to the Biome linter. The noDuplicateElseIf rule detects textually identical conditions within {#if}/{:else if} chains that would make later branches unreachable. The noSvelteDuplicateStyleProperties rule flags duplicate style: directives on the same element since only the last takes effect. The noSvelteDuplicateUseDirectives rule identifies duplicate use: directives with the same action name and initialiser. Each rule includes detection logic with state tracking, diagnostic construction with references to original occurrences, empty option structs, and paired valid/invalid test fixtures with snapshots. The rule modules are exported from the rule-options library and documented in changesets.

Suggested reviewers

  • dyc3
  • ematipico
  • Netail
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding three new Svelte linting rules (noDupeElseIfBlocks, noDupeStyleProperties, noDupeUseDirectives) to the HTML/nursery rule set.
Description check ✅ Passed The description clearly explains the PR's purpose: porting three Svelte linting rules from eslint-plugin-svelte with proper context on what each rule does and test coverage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
crates/biome_html_analyze/src/lint/nursery/no_dupe_style_properties.rs (2)

95-110: ⚡ Quick win

Diagnostic is missing the "how to fix" pillar.

It explains the what (duplicate) and why (first occurrence), but not the what to do. A short note nudging the user to remove the redundant directive completes the three pillars.

♻️ Suggested note
             .detail(
                 state.original_range,
                 "This is the first occurrence of the directive.",
-            ),
+            )
+            .note(markup! {
+                "Remove the duplicate "<Emphasis>"style:"</Emphasis>" directive."
+            }),

As per coding guidelines: "The 'diagnostic' function must explain what the error is, why it is triggered, and what the user should do to fix it according to the three pillars".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_html_analyze/src/lint/nursery/no_dupe_style_properties.rs`
around lines 95 - 110, The diagnostic in fn diagnostic(_ctx: &RuleContext<Self>,
state: &Self::State) builds a RuleDiagnostic that states the duplicate and
points to the original occurrence but lacks a remediation message; update the
RuleDiagnostic (where RuleDiagnostic::new is constructed for
state.duplicate_range) to include a short "how to fix" pillar—e.g., add a .help
or .note (or the crate's equivalent) telling the user to remove the redundant
"style:" directive or merge its properties into the first occurrence so the
diagnostic explains what to do to fix the issue.

29-36: 🏗️ Heavy lift

Consider noDuplicateStyleProperties over noDupe....

Biome convention spells out "Duplicate" (e.g. noDuplicateObjectKeys, noDuplicateClassMembers), even when porting no-dupe-* ESLint rules. Since this reports duplicate directives where only the last wins, the noDuplicate<Concept> prefix fits. Worth aligning now while it's still nursery (and the same applies to the two sibling rules in this PR).

As per coding guidelines: "Use noDuplicate<Concept> prefix for rules that report duplication overriding previous occurrences".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_html_analyze/src/lint/nursery/no_dupe_style_properties.rs`
around lines 29 - 36, Rename the rule to use the "Duplicate" spelling: change
the identifier NoDupeStyleProperties to NoDuplicateStyleProperties and update
the rule metadata name string from "noDupeStyleProperties" to
"noDuplicateStyleProperties"; also search and update any other usages
(registrations, tests, docs, sibling rule references) that reference
NoDupeStyleProperties or "noDupeStyleProperties" so identifiers and the
published rule name stay consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/biome_html_analyze/src/lint/nursery/no_dupe_else_if_blocks.rs`:
- Line 43: Rename the rule identifier "noDupeElseIfBlocks" to the full-word,
cross-language form "noDuplicateElseIf" throughout the module: update the rule's
name field (currently "noDupeElseIfBlocks"), rename the Rust module/file, the
rule struct and any Options/config struct(s) and references (e.g., types or
constructors named around NoDupeElseIfBlocks) to use NoDuplicateElseIf /
noDuplicateElseIf; after renaming, re-run the generation tasks `just gen-rules`
and `just gen-configuration` to regenerate rule metadata and configuration.

In `@crates/biome_rule_options/src/no_dupe_else_if_blocks.rs`:
- Line 7: Add a rustdoc comment above the NoDupeElseIfBlocksOptions struct:
include a short one-line description of what the options represent (even if you
simply state "Options for the NoDupeElseIfBlocks lint" or similar) and, if
helpful, a note that the struct is currently empty and reserved for future
options; place the doc comment immediately above the pub struct
NoDupeElseIfBlocksOptions {} declaration so generated docs include this type.

In `@crates/biome_rule_options/src/no_dupe_style_properties.rs`:
- Line 7: Add a rustdoc comment for the NoDupeStylePropertiesOptions struct
explaining its purpose and usage so the rule options are discoverable; locate
the struct declaration NoDupeStylePropertiesOptions and add a short /// comment
above it that describes what options it represents (e.g., controls behavior for
the "no duplicate style properties" rule) and any default/field semantics if
applicable.

In `@crates/biome_rule_options/src/no_dupe_use_directives.rs`:
- Line 7: Add rustdoc for the new options type NoDupeUseDirectivesOptions by
placing a /// doc comment above the struct that briefly explains what the
options control (e.g., prevents duplicate use directives in a module), documents
any fields or the lack thereof, describes default behavior and example usage if
applicable, and includes any relevant notes or stability/feature flags; ensure
the comment follows project doc style and uses complete sentences so it shows up
in generated docs.

---

Nitpick comments:
In `@crates/biome_html_analyze/src/lint/nursery/no_dupe_style_properties.rs`:
- Around line 95-110: The diagnostic in fn diagnostic(_ctx: &RuleContext<Self>,
state: &Self::State) builds a RuleDiagnostic that states the duplicate and
points to the original occurrence but lacks a remediation message; update the
RuleDiagnostic (where RuleDiagnostic::new is constructed for
state.duplicate_range) to include a short "how to fix" pillar—e.g., add a .help
or .note (or the crate's equivalent) telling the user to remove the redundant
"style:" directive or merge its properties into the first occurrence so the
diagnostic explains what to do to fix the issue.
- Around line 29-36: Rename the rule to use the "Duplicate" spelling: change the
identifier NoDupeStyleProperties to NoDuplicateStyleProperties and update the
rule metadata name string from "noDupeStyleProperties" to
"noDuplicateStyleProperties"; also search and update any other usages
(registrations, tests, docs, sibling rule references) that reference
NoDupeStyleProperties or "noDupeStyleProperties" so identifiers and the
published rule name stay consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 342bed8c-93fa-43dd-9074-322992070865

📥 Commits

Reviewing files that changed from the base of the PR and between e39bb2c and fbddf81.

⛔ Files ignored due to path filters (10)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noDupeElseIfBlocks/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noDupeElseIfBlocks/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noDupeStyleProperties/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noDupeStyleProperties/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noDupeUseDirectives/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noDupeUseDirectives/valid.svelte.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (13)
  • crates/biome_html_analyze/src/lint/nursery/no_dupe_else_if_blocks.rs
  • crates/biome_html_analyze/src/lint/nursery/no_dupe_style_properties.rs
  • crates/biome_html_analyze/src/lint/nursery/no_dupe_use_directives.rs
  • crates/biome_html_analyze/tests/specs/nursery/noDupeElseIfBlocks/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDupeElseIfBlocks/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDupeStyleProperties/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDupeStyleProperties/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDupeUseDirectives/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDupeUseDirectives/valid.svelte
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_dupe_else_if_blocks.rs
  • crates/biome_rule_options/src/no_dupe_style_properties.rs
  • crates/biome_rule_options/src/no_dupe_use_directives.rs

///
pub NoDupeElseIfBlocks {
version: "next",
name: "noDupeElseIfBlocks",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Rule name: prefer the full-word, cross-language form noDuplicateElseIf.

Biome already ships the JS rule noDuplicateElseIf, and naming conventions favour full words (noDuplicate<Concept> / noRedundant<Concept>) over abbreviations like "Dupe". Reusing the established name keeps the linter consistent across languages and avoids a painful rename later. Note this also affects the file/module name and the options struct.

If you do rename, remember to re-run just gen-rules and just gen-configuration.

As per coding guidelines: "Use noDuplicate<Concept> prefix for rules that report duplication overriding previous occurrences" and "Biome linter is designed to work across multiple languages, so rule naming and design should consider cross-language applicability".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_html_analyze/src/lint/nursery/no_dupe_else_if_blocks.rs` at line
43, Rename the rule identifier "noDupeElseIfBlocks" to the full-word,
cross-language form "noDuplicateElseIf" throughout the module: update the rule's
name field (currently "noDupeElseIfBlocks"), rename the Rust module/file, the
rule struct and any Options/config struct(s) and references (e.g., types or
constructors named around NoDupeElseIfBlocks) to use NoDuplicateElseIf /
noDuplicateElseIf; after renaming, re-run the generation tasks `just gen-rules`
and `just gen-configuration` to regenerate rule metadata and configuration.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The bot is correct, rename this html rule to match the js rule name. Make a note that it only works for svelte, and not vue as well.

@ematipico ematipico Jun 4, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we rename the rule to match what we already have, it must be shipped as a feature, and it can't belong to this PR. FYI

Comment thread crates/biome_rule_options/src/no_dupe_else_if_blocks.rs Outdated
Comment thread crates/biome_rule_options/src/no_dupe_style_properties.rs Outdated
Comment thread crates/biome_rule_options/src/no_dupe_use_directives.rs Outdated
@codspeed-hq

codspeed-hq Bot commented Jun 3, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 68 untouched benchmarks
⏩ 188 skipped benchmarks1


Comparing Mokto:feat/svelte-dupe-rules (6edb74c) with main (e39bb2c)

Open in CodSpeed

Footnotes

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

… for svelte dupe rules

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Mokto Mokto force-pushed the feat/svelte-dupe-rules branch from 05a42bb to db70b98 Compare June 3, 2026 03:56
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/svelte-dupe-rules.md:
- Around line 5-9: The changeset adds three new Svelte lint rules but lacks the
required invalid-example snippets; update the .changeset entry to include at
least one invalid Svelte code example for each rule named noDupeElseIfBlocks,
noDupeStyleProperties, and noDupeUseDirectives (you may also include a valid
example for clarity). For each rule, add a brief fenced code block showing the
minimal Svelte template that violates the rule (e.g., duplicate {:else if}
condition for noDupeElseIfBlocks, repeated style: directives on one element for
noDupeStyleProperties, and repeated use: directives on one element for
noDupeUseDirectives) and label them as invalid cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1e6d007c-31d4-40fe-a63d-6e70a4e20b28

📥 Commits

Reviewing files that changed from the base of the PR and between fbddf81 and 9a1e7cf.

⛔ Files ignored due to path filters (3)
  • crates/biome_configuration/src/generated/domain_selector.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (4)
  • .changeset/svelte-dupe-rules.md
  • crates/biome_rule_options/src/no_dupe_else_if_blocks.rs
  • crates/biome_rule_options/src/no_dupe_style_properties.rs
  • crates/biome_rule_options/src/no_dupe_use_directives.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/biome_rule_options/src/no_dupe_use_directives.rs
  • crates/biome_rule_options/src/no_dupe_else_if_blocks.rs

Comment thread .changeset/svelte-dupe-rules.md Outdated
Comment on lines +5 to +9
Added three new nursery rules for Svelte templates:

- [`noDupeElseIfBlocks`](https://biomejs.dev/linter/rules/no-dupe-else-if-blocks/): disallow duplicate conditions in `{#if}` / `{:else if}` chains. A condition that is textually identical to a previous one can never execute.
- [`noDupeStyleProperties`](https://biomejs.dev/linter/rules/no-dupe-style-properties/): disallow duplicate `style:` directives on the same element.
- [`noDupeUseDirectives`](https://biomejs.dev/linter/rules/no-dupe-use-directives/): disallow duplicate `use:` directives on the same element.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add at least one invalid Svelte example per new rule in this changeset.

The entry is clear, but it misses the required invalid-case examples for new lint rules.

Suggested patch
 Added three new nursery rules for Svelte templates:
 
-- [`noDupeElseIfBlocks`](https://biomejs.dev/linter/rules/no-dupe-else-if-blocks/): disallow duplicate conditions in `{`#if`}` / `{:else if}` chains. A condition that is textually identical to a previous one can never execute.
-- [`noDupeStyleProperties`](https://biomejs.dev/linter/rules/no-dupe-style-properties/): disallow duplicate `style:` directives on the same element.
-- [`noDupeUseDirectives`](https://biomejs.dev/linter/rules/no-dupe-use-directives/): disallow duplicate `use:` directives on the same element.
+- [`noDupeElseIfBlocks`](https://biomejs.dev/linter/rules/no-dupe-else-if-blocks/): disallow duplicate conditions in `{`#if`}` / `{:else if}` chains. For example, `{`#if` a}{:else if a}{/if}` is now reported because the second branch can never execute.
+- [`noDupeStyleProperties`](https://biomejs.dev/linter/rules/no-dupe-style-properties/): disallow duplicate `style:` directives on the same element. For example, `<div style:color="red" style:color="blue" />` is now reported.
+- [`noDupeUseDirectives`](https://biomejs.dev/linter/rules/no-dupe-use-directives/): disallow duplicate `use:` directives on the same element. For example, `<div use:tooltip={a} use:tooltip={a} />` is now reported.

As per coding guidelines: “For new lint rules in changesets, show examples of invalid cases in inline code snippets or code blocks, optionally showing valid cases if it helps”.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~7-~7: Loose punctuation mark.
Context: ...ev/linter/rules/no-dupe-else-if-blocks/): disallow duplicate conditions in {#if`}...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~8-~8: Loose punctuation mark.
Context: .../linter/rules/no-dupe-style-properties/): disallow duplicate style: directives ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~9-~9: Loose punctuation mark.
Context: ...ev/linter/rules/no-dupe-use-directives/): disallow duplicate use: directives on...

(UNLIKELY_OPENING_PUNCTUATION)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/svelte-dupe-rules.md around lines 5 - 9, The changeset adds three
new Svelte lint rules but lacks the required invalid-example snippets; update
the .changeset entry to include at least one invalid Svelte code example for
each rule named noDupeElseIfBlocks, noDupeStyleProperties, and
noDupeUseDirectives (you may also include a valid example for clarity). For each
rule, add a brief fenced code block showing the minimal Svelte template that
violates the rule (e.g., duplicate {:else if} condition for noDupeElseIfBlocks,
repeated style: directives on one element for noDupeStyleProperties, and
repeated use: directives on one element for noDupeUseDirectives) and label them
as invalid cases.

@dyc3 dyc3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Generally, I would try to avoid putting multiple rules in one PR. It's fine for now, just for future reference.

Comment thread .changeset/svelte-dupe-rules.md Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

split this into 3 changesets, one for each rule

Comment on lines +113 to +125
/// Extract the property name text from an `AnySvelteBindingProperty`.
/// Handles both `SvelteName` (simple identifier) and `SvelteLiteral` (hyphenated name).
fn property_name_text(property: &AnySvelteBindingProperty) -> Option<String> {
if let Some(svelte_name) = property.as_svelte_name() {
let token = svelte_name.ident_token().ok()?;
return Some(token.text_trimmed().to_string());
}
if let Some(svelte_literal) = property.as_svelte_literal() {
let token = svelte_literal.value_token().ok()?;
return Some(token.text_trimmed().to_string());
}
None
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

prefer TokenText over String to avoid the heap allocation

{
violations.push(State {
duplicate_range: directive.range(),
name: ident.text_trimmed().to_string(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

another heap allocated String, use TokenText

///
pub NoDupeStyleProperties {
version: "next",
name: "noDupeStyleProperties",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rename rule

Suggested change
name: "noDupeStyleProperties",
name: "noSvelteDuplicateStyleProperties",

///
pub NoDupeUseDirectives {
version: "next",
name: "noDupeUseDirectives",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rename rule

Suggested change
name: "noDupeUseDirectives",
name: "noSvelteDuplicateUseDirectives",

Comment on lines +95 to +112
fn diagnostic(_ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
let name = state.name.as_str();
Some(
RuleDiagnostic::new(
rule_category!(),
state.duplicate_range,
markup! {
"Duplicate "<Emphasis>"style:"</Emphasis>" directive for property "<Emphasis>{name}</Emphasis>"."
},
)
.detail(
state.original_range,
"This is the first occurrence of the directive.",
),
)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The diagnostic must explain:

  1. what is the error
  2. why is it an error
  3. how to fix the error

Comment on lines +115 to +130
fn diagnostic(_ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
let name = state.name.as_str();
Some(
RuleDiagnostic::new(
rule_category!(),
state.duplicate_range,
markup! {
"Duplicate "<Emphasis>"use:"</Emphasis>" directive "<Emphasis>{name}</Emphasis>"."
},
)
.detail(
state.original_range,
"This is the first occurrence of the directive.",
),
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The diagnostic must explain:

  1. what is the error
  2. why is it an error
  3. how to fix the error

Comment on lines +110 to +125
fn diagnostic(_ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
let condition = state.condition.as_str();
Some(
RuleDiagnostic::new(
rule_category!(),
state.duplicate_range,
markup! {
"This branch can never execute. Its condition "<Emphasis>{condition}</Emphasis>" is a duplicate of a previous condition."
},
)
.detail(
state.original_range,
"This is the first occurrence of the condition.",
),
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The diagnostic must explain:

  1. what is the error
  2. why is it an error
  3. how to fix the error

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/invalid.svelte.snap.new (1)

1-100: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Accept and commit the snapshot instead of keeping .snap.new.

This still looks like a pending insta snapshot artefact; please run cargo insta accept (or review/reject) and commit the canonical .snap file to avoid test/CI churn.
As per coding guidelines: “Use snapshot testing with the insta crate for testing Rust code, accepting/rejecting changes with cargo insta accept/reject/review.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/invalid.svelte.snap.new`
around lines 1 - 100, The failing snapshot file invalid.svelte.snap.new is an
unaccepted insta snapshot; run cargo insta accept (or cargo insta review/reject
as appropriate) from the tests directory to convert the .snap.new into the
canonical .snap, then commit the updated snapshot (the generated
invalid.svelte.snap) and remove the .snap.new artifact so
crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties
uses the accepted snapshot referenced by spec_tests.rs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/no-duplicate-else-if.md:
- Line 5: Update the changeset sentence in .changeset/no-duplicate-else-if.md to
end with a full stop instead of a colon; specifically modify the sentence that
mentions the nursery rule noDuplicateElseIf so the final character is a period
(.) to comply with the changeset style guideline.

---

Outside diff comments:
In
`@crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/invalid.svelte.snap.new`:
- Around line 1-100: The failing snapshot file invalid.svelte.snap.new is an
unaccepted insta snapshot; run cargo insta accept (or cargo insta review/reject
as appropriate) from the tests directory to convert the .snap.new into the
canonical .snap, then commit the updated snapshot (the generated
invalid.svelte.snap) and remove the .snap.new artifact so
crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties
uses the accepted snapshot referenced by spec_tests.rs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fa0ce64a-b887-4704-bdd5-f0eb77f4561d

📥 Commits

Reviewing files that changed from the base of the PR and between 9a1e7cf and 2194d9d.

⛔ Files ignored due to path filters (11)
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/valid.svelte.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (22)
  • .changeset/no-duplicate-else-if.md
  • .changeset/no-svelte-duplicate-style-properties.md
  • .changeset/no-svelte-duplicate-use-directives.md
  • crates/biome_html_analyze/src/lint/nursery/no_duplicate_else_if.rs
  • crates/biome_html_analyze/src/lint/nursery/no_svelte_duplicate_style_properties.rs
  • crates/biome_html_analyze/src/lint/nursery/no_svelte_duplicate_use_directives.rs
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/invalid.svelte.snap.new
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/valid.svelte.snap.new
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/invalid.svelte.snap.new
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/valid.svelte.snap.new
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/invalid.svelte.snap.new
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/valid.svelte.snap.new
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_duplicate_else_if.rs
  • crates/biome_rule_options/src/no_svelte_duplicate_style_properties.rs
  • crates/biome_rule_options/src/no_svelte_duplicate_use_directives.rs
💤 Files with no reviewable changes (9)
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/valid.svelte.snap.new
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateStyleProperties/valid.svelte.snap.new
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/valid.svelte.snap.new
✅ Files skipped from review due to trivial changes (6)
  • crates/biome_rule_options/src/no_duplicate_else_if.rs
  • .changeset/no-svelte-duplicate-use-directives.md
  • .changeset/no-svelte-duplicate-style-properties.md
  • crates/biome_html_analyze/src/lint/nursery/no_svelte_duplicate_use_directives.rs
  • crates/biome_html_analyze/tests/specs/nursery/noDuplicateElseIf/invalid.svelte.snap.new
  • crates/biome_html_analyze/tests/specs/nursery/noSvelteDuplicateUseDirectives/invalid.svelte.snap.new

"@biomejs/biome": patch
---

Added the nursery rule [`noDuplicateElseIf`](https://biomejs.dev/linter/rules/no-duplicate-else-if/) for Svelte templates: disallow duplicate conditions in `{#if}` / `{:else if}` chains. A condition identical to a previous one can never execute:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

End the sentence with a full stop.

Tiny docs nit: Line 5 currently ends with a colon; the changeset style requires a full stop at sentence end.
As per coding guidelines: “End every sentence in a changeset with a full stop (.).”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/no-duplicate-else-if.md at line 5, Update the changeset sentence
in .changeset/no-duplicate-else-if.md to end with a full stop instead of a
colon; specifically modify the sentence that mentions the nursery rule
noDuplicateElseIf so the final character is a period (.) to comply with the
changeset style guideline.

@Mokto Mokto requested a review from dyc3 June 4, 2026 04:26

@dyc3 dyc3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since noDuplicateElseIf is already a stable rule, we'll have to put it in a new PR against the next branch.

Comment on lines +90 to +93
let initializer_text = value
.initializer()
.map(|init| init.syntax().text_trimmed().to_string());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This allocates a string. what you probably want is is_node_equal

pub(crate) fn is_node_equal(a_node: &JsSyntaxNode, b_node: &JsSyntaxNode) -> bool {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

snapshots haven't been accepted

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

Labels

A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project L-HTML Language: HTML and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants