Skip to content

fix(html_analyze): correctly handle dynamic values for attributes#10683

Merged
ematipico merged 2 commits into
biomejs:mainfrom
Netail:fix/html-props
Jul 1, 2026
Merged

fix(html_analyze): correctly handle dynamic values for attributes#10683
ematipico merged 2 commits into
biomejs:mainfrom
Netail:fix/html-props

Conversation

@Netail

@Netail Netail commented Jun 17, 2026

Copy link
Copy Markdown
Member

Summary

Correctly skip validation for some a11y rules when the value is dynamic. We did not correctly handle vue bindings, expression values & svelte shorthands.

Created several new find attribute flavours & aligned some helpers for the static text value

Closes #10657
Closes #10671
Closes #10661
Closes #10637
Closes #10718

Test Plan

Added unit tests (Which are quite some, due to many a11y tests, sorry)

Docs

@github-actions

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

@changeset-bot

changeset-bot Bot commented Jun 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8920542

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

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

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added A-Project Area: project A-Linter Area: linter A-Parser Area: parser A-Formatter Area: formatter L-HTML Language: HTML and super languages labels Jun 17, 2026
@codspeed-hq

codspeed-hq Bot commented Jun 20, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 71 untouched benchmarks
⏩ 185 skipped benchmarks1


Comparing Netail:fix/html-props (8920542) with main (2fcf7a5)2

Open in CodSpeed

Footnotes

  1. 185 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (5a2e65b) during the generation of this report, so 2fcf7a5 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@Netail Netail force-pushed the fix/html-props branch 10 times, most recently from d1ad198 to ada4e1b Compare June 24, 2026 22:18
@Netail Netail marked this pull request as ready for review June 24, 2026 22:21
@Netail Netail changed the title fix: catch shorthand props & correctly handle static values fix(html_analyze): catch shorthand props & correctly handle static values Jun 24, 2026
@Netail Netail changed the title fix(html_analyze): catch shorthand props & correctly handle static values fix(html_analyze): correctly handle dynamic values for attributes Jun 24, 2026
@Netail Netail marked this pull request as draft June 24, 2026 22:28
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR adds static-value extraction and Vue-binding-aware attribute lookup APIs, updates accessibility helpers and lint rules to use them, and adjusts module-graph stylesheet detection. Test fixtures were refreshed across Astro, Svelte, and Vue for accesskey, ARIA, tabindex, role, anchor, lang, autocomplete, and iframe-title cases.

Possibly related issues

  • biomejs/biome issue 10661 — The changes cover the same Vue-binding-aware attribute lookup paths across the accessibility rules.
  • biomejs/biome issue 10718 — The useValidAnchor lookup and binding handling changes match this area.
  • biomejs/biome issue 10637 — The same static-value handling and aria-rowcount fixture updates are present.

Possibly related PRs

  • biomejs/biome#8987 — Updates the same useValidAnchor path to static-value and Vue-aware lookup handling.
  • biomejs/biome#9491 — Touches the same no_aria_unsupported_elements attribute/directive handling.
  • biomejs/biome#9928 — Changes the same use_valid_aria_values static-value extraction path.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly matches the main change: handling dynamic attribute values in html_analyze.
Description check ✅ Passed The description matches the changeset, covering dynamic values, Vue bindings, Svelte shorthands, and new static-text helpers.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

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

Caution

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

⚠️ Outside diff range comments (3)
crates/biome_html_analyze/src/lint/a11y/no_ambiguous_anchor_text.rs (1)

113-136: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Read aria-label and alt through the static-value path.

get_aria_label and get_img_alt still only accept initializer.value().as_html_string(). That drops static bound strings such as Vue :aria-label="'read more'" or Astro/Svelte alt={"read more"}, so noAmbiguousAnchorText will still miss the very cases this PR is trying to teach it.

🤖 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/a11y/no_ambiguous_anchor_text.rs` around
lines 113 - 136, Update get_aria_label and get_img_alt in
no_ambiguous_anchor_text to read attribute values through the static-value path
instead of only accepting initializer.value().as_html_string(). Extend the
extraction logic to unwrap static/bound string forms (for example Vue bound
attributes and Astro/Svelte expression string literals) and return the resolved
text when it is statically known. Keep the existing attribute lookups and tag
check in get_img_alt, but broaden the value handling so noAmbiguousAnchorText
can analyze these cases too.
crates/biome_html_analyze/src/a11y.rs (1)

84-120: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the binding-aware lookup here too.

These AnyHtmlTagElement helpers still call find_attribute_by_name, so :aria-hidden="'true'"-style props are ignored even though the element-specific helpers below switched to the binding-aware path. That makes downstream rules behave differently depending on which helper they happen to call.

Also applies to: 129-135

🤖 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/a11y.rs` around lines 84 - 120, The
AnyHtmlTagElement accessibility helpers still use find_attribute_by_name, so
bound props like :aria-hidden are missed and behavior diverges from the
element-specific helpers. Update is_hidden_from_screen_reader and
is_aria_hidden_true to use the binding-aware attribute lookup path already used
elsewhere in this module, and preserve the existing truthy/strict checks on the
resolved attribute value. Make sure both the aria-hidden branch and the input
type=hidden branch continue to work with bound attributes.
crates/biome_html_analyze/src/lint/a11y/no_aria_hidden_on_focusable.rs (1)

196-203: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't conflate dynamic contenteditable with a bare attribute.

as_static_value() being None does not just mean “bare attribute”; it also covers values you cannot fold statically. With the new None => true branch, contenteditable={expr} is treated as truthy and this rule will start flagging dynamic templates as focusable when the runtime value may be false.

🤖 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/a11y/no_aria_hidden_on_focusable.rs`
around lines 196 - 203, The `no_aria_hidden_on_focusable` check is treating
`attr.as_static_value() == None` as a bare `contenteditable` attribute, which
incorrectly marks dynamic expressions like `contenteditable={expr}` as truthy.
Update the logic in the `contenteditable` attribute handling to only treat an
actually bare attribute as true and avoid folding non-static values; use the
existing `as_static_value` result to distinguish bare attributes from dynamic
expressions before deciding focusability.
🤖 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/a11y.rs`:
- Around line 227-248: The self-closing element helpers are still only checking
literal attributes, so bound values are being treated as missing. Update
html_self_closing_element_has_accessible_name and
html_self_closing_element_has_non_empty_attribute to use the same
bound-attribute lookup as other HTML accessibility checks instead of
find_attribute_by_name, so aria-label, aria-labelledby, title, and alt bindings
are recognized consistently for self-closing elements.

In `@crates/biome_html_analyze/src/lint/a11y/no_aria_unsupported_elements.rs`:
- Around line 91-137: The fixer in no_aria_unsupported_elements still only
removes attributes via as_html_attribute(), so the new Vue cases (:role and
v-bind:aria-*) are diagnosed but not removed. Update action() to locate the
matching AnyHtmlAttribute using the same attribute-discovery logic as run()
(including AnyVueDirective handling), then remove that matched attribute for
both HTML and Vue bindings. Keep the logic aligned with RuleState/AttributeKind
so the diagnostic and removal paths cover the same cases.

In `@crates/biome_html_analyze/src/lint/a11y/no_autofocus.rs`:
- Around line 162-164: Add a regression fixture for the new bound/shorthand
popover allowance in no_autofocus: update the noAutofocus test coverage to
include one valid case where an autofocus descendant sits inside a bound popover
container, so the is_dialog_or_popover path is exercised with a passing example
and future false positives are caught.

In `@crates/biome_html_analyze/src/lint/a11y/no_noninteractive_tabindex.rs`:
- Around line 92-109: The role handling in no_noninteractive_tabindex is too
broad because the non-HtmlAttribute branch currently returns early for any bound
role, which suppresses valid diagnostics. Update the logic around
node.find_attribute_or_vue_binding("role") so only a role that can be resolved
to a static interactive AriaRole causes an early exit, and keep reporting when
the binding resolves to a non-interactive role such as presentation. Use the
existing role_attribute match and AriaRole::from_roles path as the reference
points, but avoid returning None for unresolved or non-interactive bindings.

In `@crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs`:
- Around line 151-154: The `no_svg_without_title` check is short-circuiting in
the `aria_label_attribute` branch just because `aria-label` exists, which
incorrectly treats empty labels as valid. Update the logic in this rule to only
return early when the `aria-label` value is statically non-empty in the SVG
node, and keep the current behavior explicit for dynamic/unknown values if you
choose to skip them. Use the existing
`node.find_attribute_by_name("aria-label")` handling to inspect the attribute
value before suppressing the rule.

In `@crates/biome_html_analyze/src/lint/a11y/use_aria_props_supported_by_role.rs`:
- Around line 92-94: The nullish check in use_aria_props_supported_by_role is
too broad because StaticValue::text() strips quotes, so literal strings like
aria-hidden="null" and aria-hidden="undefined" are being treated as nullish
expressions. Update the logic in use_aria_props_supported_by_role to verify the
StaticValue variant itself rather than matching only on text(), and keep the
exemption limited to actual null/undefined values so quoted strings still go
through validation.
- Around line 62-73: The role extraction in the
`use_aria_props_supported_by_role` logic is ignoring static Vue bindings because
it only handles `AnyHtmlAttribute::HtmlAttribute`, so `:role="'button'"` and
`v-bind:role="'button'"` are treated as implicit roles and can trigger false
positives. Update the role parsing branch to also recognize static Vue `role`
bindings from the same attribute path, using the existing
`AnyHtmlAttribute`/`AriaRole::from_roles` flow so both plain HTML and static Vue
bindings resolve consistently.

In `@crates/biome_html_analyze/src/lint/a11y/use_button_type.rs`:
- Around line 82-87: In the use_button_type lint logic, the current guard only
checks HTML strings and Svelte template attributes before validating the button
type, so statically evaluable expressions like type={"foo"} can bypass the rule.
Update the validation in use_button_type to run against any value where
as_static_value() returns Some, regardless of whether it came from
as_html_string() or as_svelte_template_attribute_value(), and keep the existing
ALLOWED_BUTTON_TYPES check plus the invalid-reporting path for non-allowed
static text.

In `@crates/biome_html_analyze/src/lint/a11y/use_focusable_interactive.rs`:
- Around line 69-73: The static Vue role binding is being lost because
`use_focusable_interactive` calls `as_html_attribute()` after
`find_attribute_by_name("role")`, which drops `:role`/`v-bind:role` and prevents
the `tabindex` check from running. Update the `role_attribute` handling in
`use_focusable_interactive` to read the bound attribute value in a binding-aware
way instead of converting it to a plain HTML attribute, and apply the same fix
to the other `role_attribute` usage noted in the rule so `:role="'button'"`
still triggers the diagnostic.

In `@crates/biome_html_analyze/src/lint/a11y/use_key_with_click_events.rs`:
- Line 78: The anchor shortcut in use_key_with_click_events still treats only
plain href as an escape hatch, which causes false positives for Vue-bound links
like :href. Update the check in the logic around the anchor handling to use
find_attribute_or_vue_binding("href") instead of find_attribute_by_name("href"),
keeping it consistent with the existing onclick Vue-aware lookup and preserving
the href-based exemption.

In `@crates/biome_html_analyze/src/lint/a11y/use_media_caption.rs`:
- Around line 141-146: The `useMediaCaption` check in `use_media_caption.rs` is
too restrictive because `kind_attr.as_html_attribute()?` filters out Vue bound
`kind` values like `:kind="'captions'"`. Update the `kind` handling in the
`track` analysis path so it still recognizes static string literals coming from
bindings as caption tracks, likely by inspecting both plain HTML attributes and
bound/static initializer values in the same `kind_attr` flow. Keep the existing
`string_value.text().eq_ignore_ascii_case("captions")` match, but make sure the
lookup path in `as_html_attribute`, `initializer`, and `as_static_value` does
not exclude valid static Vue bindings.

In `@crates/biome_html_analyze/src/lint/performance/no_sync_scripts.rs`:
- Around line 73-79: The `no_sync_scripts` check in
`attribute.initializer().is_some_and(...)` only handles plain HTML string values
for `type="module"`, so static expressions/templates that evaluate to the same
literal are missed. Update the detection logic in `no_sync_scripts.rs` to use
static-value extraction on the attribute initializer/value path (through the
existing `value()`/`as_html_string()` flow or equivalent helper) so any
statically resolvable `module` initializer is treated as a module script and not
reported as synchronous.

In `@crates/biome_html_analyze/src/lint/security/no_script_url.rs`:
- Around line 74-76: The href lookup in no_script_url is not Vue-aware, so
Vue-bound hrefs like :href and v-bind:href are skipped before the security check
runs. Update the attribute search in the no_script_url rule to use the Vue-aware
path on attrs instead of find_attribute_by_name, then keep the existing
as_html_attribute and as_static_value flow so static Vue bindings that resolve
to javascript: are still examined.

In
`@crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/invalid.options.json`:
- Line 2: The $schema reference in this fixture is missing one parent directory
and will not resolve correctly in editors. Update the schema path in
invalid.options.json so it matches the fixture’s actual nesting depth, keeping
the existing configuration_schema.json target but adding the missing ../
segment. Use the $schema field as the anchor when locating the change.

In
`@crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/valid.options.json`:
- Line 2: The fixture’s $schema reference is one directory level too shallow, so
editor validation cannot resolve it. Update the $schema value in the
valid.options.json fixture to point to the correct configuration_schema.json
location by adding the missing ../ segment, using the existing $schema field as
the identifier to adjust.

In `@crates/biome_html_syntax/src/attribute_ext.rs`:
- Around line 180-195: The Vue event name matching in attribute_ext’s event
lookup is case-insensitive, but it should follow exact-case semantics for Vue
event directives. Update the comparisons inside the
AnyVueDirective::VueDirective path (and the matching logic in the referenced
event-finder code) to use case-sensitive equality instead of
eq_ignore_ascii_case, so lookups like `@fooBar` only match the exact event name.
- Around line 20-38: The Svelte template attribute handling in attribute_ext.rs
is incorrectly returning only the first static chunk as the recovered value,
which truncates multi-chunk literals. Update the SvelteTemplateAttributeValue
branch in the static value extraction logic to avoid using only the first token
from elements(); either concatenate all SvelteTemplateChunkElement token text
into one StaticValue::String or, if that full reconstruction is not supported
yet, return None whenever more than one static chunk is present. Keep the
behavior aligned with the existing AnySvelteTemplateElement matching and the
html_template_chunk_token flow.

In `@crates/biome_html_syntax/src/text_ext.rs`:
- Around line 26-28: The static string parser in text_ext.rs only recognizes
double-quoted literals, so single-quoted bindings are currently missed. Update
the logic around StaticValue and the text parsing helper to accept both quote
styles, and make sure cases like alt={'Save'} and type={'button'} return
Some(StaticValue::String(token)) instead of None.

---

Outside diff comments:
In `@crates/biome_html_analyze/src/a11y.rs`:
- Around line 84-120: The AnyHtmlTagElement accessibility helpers still use
find_attribute_by_name, so bound props like :aria-hidden are missed and behavior
diverges from the element-specific helpers. Update is_hidden_from_screen_reader
and is_aria_hidden_true to use the binding-aware attribute lookup path already
used elsewhere in this module, and preserve the existing truthy/strict checks on
the resolved attribute value. Make sure both the aria-hidden branch and the
input type=hidden branch continue to work with bound attributes.

In `@crates/biome_html_analyze/src/lint/a11y/no_ambiguous_anchor_text.rs`:
- Around line 113-136: Update get_aria_label and get_img_alt in
no_ambiguous_anchor_text to read attribute values through the static-value path
instead of only accepting initializer.value().as_html_string(). Extend the
extraction logic to unwrap static/bound string forms (for example Vue bound
attributes and Astro/Svelte expression string literals) and return the resolved
text when it is statically known. Keep the existing attribute lookups and tag
check in get_img_alt, but broaden the value handling so noAmbiguousAnchorText
can analyze these cases too.

In `@crates/biome_html_analyze/src/lint/a11y/no_aria_hidden_on_focusable.rs`:
- Around line 196-203: The `no_aria_hidden_on_focusable` check is treating
`attr.as_static_value() == None` as a bare `contenteditable` attribute, which
incorrectly marks dynamic expressions like `contenteditable={expr}` as truthy.
Update the logic in the `contenteditable` attribute handling to only treat an
actually bare attribute as true and avoid folding non-static values; use the
existing `as_static_value` result to distinguish bare attributes from dynamic
expressions before deciding focusability.
🪄 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: d25c5f2e-36a3-46b4-bfb4-3d86ae1f390d

📥 Commits

Reviewing files that changed from the base of the PR and between 5a2e65b and ada4e1b.

⛔ Files ignored due to path filters (83)
  • crates/biome_html_analyze/tests/specs/a11y/noAccessKey/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAccessKey/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAccessKey/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAutofocus/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAutofocus/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noAutofocus/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noLabelWithoutControl/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAltText/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAltText/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useButtonType/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useSemanticElements/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useSemanticElements/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useSemanticElements/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAnchor/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAnchor/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAnchor/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaProps/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaProps/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAutocomplete/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAutocomplete/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/security/noScriptUrl/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/security/noScriptUrl/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/security/noScriptUrl/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/security/noScriptUrl/invalid.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (125)
  • crates/biome_html_analyze/src/a11y.rs
  • crates/biome_html_analyze/src/a11y_tests.rs
  • crates/biome_html_analyze/src/lint/a11y/no_access_key.rs
  • crates/biome_html_analyze/src/lint/a11y/no_ambiguous_anchor_text.rs
  • crates/biome_html_analyze/src/lint/a11y/no_aria_hidden_on_focusable.rs
  • crates/biome_html_analyze/src/lint/a11y/no_aria_unsupported_elements.rs
  • crates/biome_html_analyze/src/lint/a11y/no_autofocus.rs
  • crates/biome_html_analyze/src/lint/a11y/no_header_scope.rs
  • crates/biome_html_analyze/src/lint/a11y/no_interactive_element_to_noninteractive_role.rs
  • crates/biome_html_analyze/src/lint/a11y/no_label_without_control.rs
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_to_interactive_role.rs
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_tabindex.rs
  • crates/biome_html_analyze/src/lint/a11y/no_positive_tabindex.rs
  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_html_analyze/src/lint/a11y/no_redundant_roles.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/use_alt_text.rs
  • crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
  • crates/biome_html_analyze/src/lint/a11y/use_aria_activedescendant_with_tabindex.rs
  • crates/biome_html_analyze/src/lint/a11y/use_aria_props_for_role.rs
  • crates/biome_html_analyze/src/lint/a11y/use_aria_props_supported_by_role.rs
  • crates/biome_html_analyze/src/lint/a11y/use_button_type.rs
  • crates/biome_html_analyze/src/lint/a11y/use_focusable_interactive.rs
  • crates/biome_html_analyze/src/lint/a11y/use_key_with_click_events.rs
  • crates/biome_html_analyze/src/lint/a11y/use_key_with_mouse_events.rs
  • crates/biome_html_analyze/src/lint/a11y/use_media_caption.rs
  • crates/biome_html_analyze/src/lint/a11y/use_semantic_elements.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_anchor.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_aria_role.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_autocomplete.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_analyze/src/lint/nursery/use_scoped_styles.rs
  • crates/biome_html_analyze/src/lint/performance/no_sync_scripts.rs
  • crates/biome_html_analyze/src/lint/performance/use_vue_vapor.rs
  • crates/biome_html_analyze/src/lint/security/no_script_url.rs
  • crates/biome_html_analyze/tests/specs/a11y/noAccessKey/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noAccessKey/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noAccessKey/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/invalid.options.json
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/valid.options.json
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/invalid.options.json
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/valid.options.json
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/invalid.options.json
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/valid.options.json
  • crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noAutofocus/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noAutofocus/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noAutofocus/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noLabelWithoutControl/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useAltText/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAltText/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useButtonType/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useSemanticElements/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useSemanticElements/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useSemanticElements/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidAnchor/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useValidAnchor/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaProps/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaProps/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useValidAutocomplete/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useValidAutocomplete/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/vue/valid.vue
  • crates/biome_html_formatter/src/svelte/value/directive_value.rs
  • crates/biome_html_syntax/src/attribute_ext.rs
  • crates/biome_html_syntax/src/element_ext.rs
  • crates/biome_html_syntax/src/text_ext.rs
  • crates/biome_module_graph/src/html_module_info/visitor.rs

Comment thread crates/biome_html_analyze/src/a11y.rs Outdated
Comment thread crates/biome_html_analyze/src/lint/a11y/no_autofocus.rs
Comment thread crates/biome_html_analyze/src/lint/a11y/no_noninteractive_tabindex.rs Outdated
Comment on lines +151 to +154
let aria_label_attribute = node.find_attribute_by_name("aria-label");
if aria_label_attribute.is_some() {
return 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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Require a usable aria-label, not just its presence.

Line 152 now treats <svg role="img" aria-label=""> as named and suppresses the rule, but an empty label still leaves the SVG without alternative text. Please only short-circuit when the label is statically non-empty, or when you intentionally choose to skip unknown dynamic values.

🤖 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/a11y/no_svg_without_title.rs` around lines
151 - 154, The `no_svg_without_title` check is short-circuiting in the
`aria_label_attribute` branch just because `aria-label` exists, which
incorrectly treats empty labels as valid. Update the logic in this rule to only
return early when the `aria-label` value is statically non-empty in the SVG
node, and keep the current behavior explicit for dynamic/unknown values if you
choose to skip them. Use the existing
`node.find_attribute_by_name("aria-label")` handling to inspect the attribute
value before suppressing the rule.

Comment on lines 20 to +38
// When all elements are plain text chunks (no {expression} interpolations),
// the static text can be recovered by concatenating the chunk tokens.
Self::SvelteTemplateAttributeValue(value) => {
let elements = value.elements();
let mut text = String::new();
let mut tokens = Vec::new();
for element in elements.iter() {
match element {
AnySvelteTemplateElement::SvelteTemplateChunkElement(chunk) => {
text.push_str(chunk.html_template_chunk_token().ok()?.text_trimmed());
tokens.push(chunk.html_template_chunk_token().ok()?);
}
AnySvelteTemplateElement::HtmlAttributeSingleTextExpression(_) => {
// Dynamic interpolation — no static value available.
return None;
}
}
}
Some(Text::from(text))
tokens
.first()
.map(|token| StaticValue::String(token.clone()))

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not treat only the first Svelte chunk as the full static value.

The comment says the chunks are concatenated, but Line 37 returns just .first(). If the parser emits multiple static chunks, consumers compare or resolve a truncated value; if concatenation is not representable yet, returning None is safer.

Safer fallback until concatenated static values are supported
-                tokens
-                    .first()
-                    .map(|token| StaticValue::String(token.clone()))
+                match tokens.as_slice() {
+                    [] => None,
+                    [token] => Some(StaticValue::String(token.clone())),
+                    _ => None,
+                }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// When all elements are plain text chunks (no {expression} interpolations),
// the static text can be recovered by concatenating the chunk tokens.
Self::SvelteTemplateAttributeValue(value) => {
let elements = value.elements();
let mut text = String::new();
let mut tokens = Vec::new();
for element in elements.iter() {
match element {
AnySvelteTemplateElement::SvelteTemplateChunkElement(chunk) => {
text.push_str(chunk.html_template_chunk_token().ok()?.text_trimmed());
tokens.push(chunk.html_template_chunk_token().ok()?);
}
AnySvelteTemplateElement::HtmlAttributeSingleTextExpression(_) => {
// Dynamic interpolation — no static value available.
return None;
}
}
}
Some(Text::from(text))
tokens
.first()
.map(|token| StaticValue::String(token.clone()))
// When all elements are plain text chunks (no {expression} interpolations),
// the static text can be recovered by concatenating the chunk tokens.
Self::SvelteTemplateAttributeValue(value) => {
let elements = value.elements();
let mut tokens = Vec::new();
for element in elements.iter() {
match element {
AnySvelteTemplateElement::SvelteTemplateChunkElement(chunk) => {
tokens.push(chunk.html_template_chunk_token().ok()?);
}
AnySvelteTemplateElement::HtmlAttributeSingleTextExpression(_) => {
// Dynamic interpolation — no static value available.
return None;
}
}
}
match tokens.as_slice() {
[] => None,
[token] => Some(StaticValue::String(token.clone())),
_ => None,
}
🤖 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_syntax/src/attribute_ext.rs` around lines 20 - 38, The
Svelte template attribute handling in attribute_ext.rs is incorrectly returning
only the first static chunk as the recovered value, which truncates multi-chunk
literals. Update the SvelteTemplateAttributeValue branch in the static value
extraction logic to avoid using only the first token from elements(); either
concatenate all SvelteTemplateChunkElement token text into one
StaticValue::String or, if that full reconstruction is not supported yet, return
None whenever more than one static chunk is present. Keep the behavior aligned
with the existing AnySvelteTemplateElement matching and the
html_template_chunk_token flow.

Comment on lines +180 to +195
.is_some_and(|t| {
t.text_trimmed()
.eq_ignore_ascii_case(stripped_name_to_lookup)
}),

// v-on:name="..."
AnyVueDirective::VueDirective(d) => {
d.is_event_listener()
&& d.arg()
.and_then(|arg| arg.arg().ok())
.and_then(|arg| arg.as_vue_static_argument().cloned())
.and_then(|s| s.name_token().ok())
.is_some_and(|t| {
t.text_trimmed()
.eq_ignore_ascii_case(stripped_name_to_lookup)
})

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep Vue event directive names case-sensitive.

The Vue event finder documents exact-case matching, but these comparisons use eq_ignore_ascii_case, so @fooBar can satisfy a lookup for foobar. That can make event-based lint checks miss or report the wrong Vue component event.

Suggested fix
-                            t.text_trimmed()
-                                .eq_ignore_ascii_case(stripped_name_to_lookup)
+                            t.text_trimmed() == stripped_name_to_lookup
-                                    t.text_trimmed()
-                                        .eq_ignore_ascii_case(stripped_name_to_lookup)
+                                    t.text_trimmed() == stripped_name_to_lookup
-                    .is_some_and(|t| t.text_trimmed().eq_ignore_ascii_case(name_to_lookup)),
+                    .is_some_and(|t| t.text_trimmed() == name_to_lookup),
-                            .is_some_and(|t| t.text_trimmed().eq_ignore_ascii_case(name_to_lookup))
+                            .is_some_and(|t| t.text_trimmed() == name_to_lookup)

Also applies to: 344-353

🤖 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_syntax/src/attribute_ext.rs` around lines 180 - 195, The
Vue event name matching in attribute_ext’s event lookup is case-insensitive, but
it should follow exact-case semantics for Vue event directives. Update the
comparisons inside the AnyVueDirective::VueDirective path (and the matching
logic in the referenced event-finder code) to use case-sensitive equality
instead of eq_ignore_ascii_case, so lookups like `@fooBar` only match the exact
event name.

Comment thread crates/biome_html_syntax/src/text_ext.rs Outdated
@Netail Netail force-pushed the fix/html-props branch 3 times, most recently from 36986f8 to c869350 Compare June 27, 2026 22:48
@ematipico

Copy link
Copy Markdown
Member

What's missing @Netail ? How can I help to merge the PR?

@Netail

Netail commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

What's missing @Netail ? How can I help to merge the PR?

Hi,
Majority is done. But the AI bot mentioned that you could also put static values in vue bindings, like: <div tabindex="0" :role="'presentation'">. Which I was not aware of and has not been tackled yet. We could do it in another PR, but that was the only thing left really

Bit caught up with company work & turned out a bit bigger than initially thought

@Netail

Netail commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

Alright, let the clanker loose on the static vue binding values. Some finishing touches left I guess

@Netail Netail marked this pull request as ready for review June 30, 2026 21:57
@ematipico

Copy link
Copy Markdown
Member

Does the PR closes all those issues? If so can you use the correct comments for auto closing?

@ematipico

Copy link
Copy Markdown
Member

@Netail I updated the PR description. Auto-closing works only for single issues

@ematipico ematipico merged commit ae31a00 into biomejs:main Jul 1, 2026
34 checks passed
@Netail

Netail commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

@Netail I updated the PR description. Auto-closing works only for single issues

Ahh okay, TIL, thanks!

@Netail Netail deleted the fix/html-props branch July 1, 2026 07:51
@github-actions github-actions Bot mentioned this pull request Jul 1, 2026
OIRNOIR pushed a commit to OIRNOIR/YouTube-Helper-Client that referenced this pull request Jul 4, 2026
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [@biomejs/biome](https://biomejs.dev) ([source](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome)) | imports | patch | [`2.5.1` -> `2.5.2`](https://renovatebot.com/diffs/npm/@biomejs%2fbiome/2.5.1/2.5.2) |

---

### Release Notes

<details>
<summary>biomejs/biome (@&#8203;biomejs/biome)</summary>

### [`v2.5.2`](https://github.com/biomejs/biome/blob/HEAD/packages/@&#8203;biomejs/biome/CHANGELOG.md#252)

[Compare Source](https://github.com/biomejs/biome/compare/@biomejs/biome@2.5.1...@biomejs/biome@2.5.2)

##### Patch Changes

- [#&#8203;10595](biomejs/biome#10595) [`f458028`](biomejs/biome@f458028) Thanks [@&#8203;pkallos](https://github.com/pkallos)! - Added the option `ignoreBooleanCoercion` to [useNullishCoalescing](https://biomejs.dev/linter/rules/use-nullish-coalescing/). When enabled, Biome ignores `||` and `||=` used inside a `Boolean()` call, where coalescing on falsy values is intentional.

- [#&#8203;10798](biomejs/biome#10798) [`4a32b63`](biomejs/biome@4a32b63) Thanks [@&#8203;pkallos](https://github.com/pkallos)! - Added the option `ignorePrimitives` to [useNullishCoalescing](https://biomejs.dev/linter/rules/use-nullish-coalescing/). When enabled, Biome ignores `||`, `||=`, and ternary expressions whose non-nullish operands are all primitives the option opts out of. Use `true` to ignore all primitives, or an object selecting `string`, `number`, `boolean`, or `bigint`.

- [#&#8203;10545](biomejs/biome#10545) [`f3d4c00`](biomejs/biome@f3d4c00) Thanks [@&#8203;Mokto](https://github.com/Mokto)! - Added the new nursery rule [`noSvelteUnnecessaryStateWrap`](https://biomejs.dev/linter/rules/no-svelte-unnecessary-state-wrap/), which reports unnecessary `$state()` wrapping of classes from `svelte/reactivity` that are already reactive.

  ```svelte
  <script>
  import { SvelteMap } from "svelte/reactivity";
  const map = $state(new SvelteMap()); // redundant
  </script>
  ```

- [#&#8203;10752](biomejs/biome#10752) [`f62fb8b`](biomejs/biome@f62fb8b) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed [#&#8203;10739](biomejs/biome#10739). Now the rule [`useValidAutocomplete`](https://biomejs.dev/linter/rules/use-valid-autocomplete/) correctly flags the `autoComplete` attribute.

- [#&#8203;10796](biomejs/biome#10796) [`f1b3ab2`](biomejs/biome@f1b3ab2) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed [#&#8203;10768](biomejs/biome#10768). Improved the performance of the Biome Language Server by cancelling certain in-flight operations when there are fast updates.

- [#&#8203;10719](biomejs/biome#10719) [`aa649b5`](biomejs/biome@aa649b5) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - Fixed [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) false positive on returns that use a widening type assertion: `"a" as string` is no longer reported as misleading. The rule now also reports a literal-pinning assertion such as `false as false`, matching the existing `as const` behavior.

  ```ts
  // No longer flagged (returns are `string`):
  function getValue(b: boolean): string {
    if (b) return "a" as string;
    return "b" as string;
  }

  // Now also reported, like `as const` (returns `false`):
  function isReady(): boolean {
    return false as false;
  }
  ```

- [#&#8203;10678](biomejs/biome#10678) [`8f073a7`](biomejs/biome@8f073a7) Thanks [@&#8203;PranavAchar01](https://github.com/PranavAchar01)! - Fixed [#&#8203;7718](biomejs/biome#7718): Biome now correctly parses CSS nesting selectors when `&` appears as a trailing sub-selector after a type selector, e.g. `h1& { color: red; }`.

- [#&#8203;10756](biomejs/biome#10756) [`5ec965a`](biomejs/biome@5ec965a) Thanks [@&#8203;denbezrukov](https://github.com/denbezrukov)! - Fixed CSS formatter output for selector lists with `allowWrongLineComments` and `//` comments after a selector comma. Biome now keeps the selector before the line comment inline instead of breaking it across descendant combinators.

  ```diff
  -.powerPathNavigator
  -  .helm
  -  button.pressedButton, // pressed
  +.powerPathNavigator .helm button.pressedButton, // pressed
   .powerPathNavigator .helm button:active:not(.disabledButton) {
   }
  ```

- [#&#8203;10757](biomejs/biome#10757) [`6232fcd`](biomejs/biome@6232fcd) Thanks [@&#8203;PranavAchar01](https://github.com/PranavAchar01)! - Fixed [#&#8203;8269](biomejs/biome#8269): the CSS parser now accepts Tailwind `@variant` and `@utility` names that start with a digit, such as the `2xl` breakpoint.

  ```css
  @&#8203;utility container {
    @&#8203;variant 2xl {
      max-width: 1400px;
    }
  }
  ```

- [#&#8203;10777](biomejs/biome#10777) [`575ced6`](biomejs/biome@575ced6) Thanks [@&#8203;WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed an issue reported in [#&#8203;10708](biomejs/biome#10708): the GitLab reporter now handles `--verbose` diagnostics filtering correctly.

- [#&#8203;10281](biomejs/biome#10281) [`0efe244`](biomejs/biome@0efe244) Thanks [@&#8203;Zelys-DFKH](https://github.com/Zelys-DFKH)! - Fixed a bug where GritQL patterns rejected positional (unkeyed) arguments.

- [#&#8203;10758](biomejs/biome#10758) [`e36fd8a`](biomejs/biome@e36fd8a) Thanks [@&#8203;henrybrewer00-dotcom](https://github.com/henrybrewer00-dotcom)! - Fixed [#&#8203;10697](biomejs/biome#10697): The formatter no longer removes the parentheses around an `await` or `yield` expression used as the target of a TypeScript instantiation expression. For example, `(await makeFactory)<Value>` is no longer reformatted to `await makeFactory<Value>`, which would change the meaning of the code.

- [#&#8203;10586](biomejs/biome#10586) [`3617094`](biomejs/biome@3617094) Thanks [@&#8203;IxxyDev](https://github.com/IxxyDev)! - Fixed [#&#8203;9568](biomejs/biome#9568): [`noFloatingPromises`](https://biomejs.dev/linter/rules/no-floating-promises/) no longer reports a false positive when calling an overloaded function and the selected overload does not return a promise.

  ```ts
  function bestEffort(cb: () => Promise<number>): Promise<number>;
  function bestEffort(cb: () => number): number;
  function bestEffort(
    cb: () => number | Promise<number>,
  ): Promise<number> | number {
    return cb() as Promise<number> | number;
  }

  // This resolves to the second overload, which returns `number`, so it is no
  // longer flagged as a floating promise.
  bestEffort(() => 42);
  ```

- [#&#8203;10766](biomejs/biome#10766) [`7aff4c1`](biomejs/biome@7aff4c1) Thanks [@&#8203;JamBalaya56562](https://github.com/JamBalaya56562)! - Fixed [#&#8203;2862](biomejs/biome#2862): [`noInteractiveElementToNoninteractiveRole`](https://biomejs.dev/linter/rules/no-interactive-element-to-noninteractive-role/) no longer reports custom elements (a tag name containing a dash, e.g. `<my-button role="img" />`). Per the [W3C HTML-ARIA specification](https://www.w3.org/TR/html-aria/#el-autonomous-custom-element), a custom element may be given any role or none.

- [#&#8203;10680](biomejs/biome#10680) [`771daa4`](biomejs/biome@771daa4) Thanks [@&#8203;WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed [#&#8203;10635](biomejs/biome#10635): Biome now recognizes chained
  table tests such as `test.concurrent.each()` and `it.concurrent.each()` as test calls, fixing
  `noMisplacedAssertion` false positives and improving formatting for those test declarations.

- [#&#8203;10759](biomejs/biome#10759) [`34570b5`](biomejs/biome@34570b5) Thanks [@&#8203;henrybrewer00-dotcom](https://github.com/henrybrewer00-dotcom)! - Fixed [#&#8203;10636](biomejs/biome#10636): [noStaticElementInteractions](https://biomejs.dev/linter/rules/no-static-element-interactions/) no longer reports a false positive for event handlers on Svelte special elements such as `<svelte:window>`, `<svelte:document>`, and `<svelte:body>`. These are not real DOM elements, so they are now ignored by the rule.

- [#&#8203;10741](biomejs/biome#10741) [`bd2364e`](biomejs/biome@bd2364e) Thanks [@&#8203;JamBalaya56562](https://github.com/JamBalaya56562)! - Fixed [#&#8203;6686](biomejs/biome#6686): the `rage` command now respects the `--config-path` option and the `BIOME_CONFIG_PATH` environment variable when loading the Biome configuration. Previously it always used the default configuration resolution and reported the configuration as `Not set` when no `biome.json` existed in the working directory.

- [#&#8203;10763](biomejs/biome#10763) [`2c3e82d`](biomejs/biome@2c3e82d) Thanks [@&#8203;Aqu1bp](https://github.com/Aqu1bp)! - Fixed [#&#8203;10742](biomejs/biome#10742): [`noSolidDestructuredProps`](https://biomejs.dev/linter/rules/no-solid-destructured-props) now reports destructured props in Solid function components and JSX children.

- [#&#8203;10606](biomejs/biome#10606) [`a4cc4ab`](biomejs/biome@a4cc4ab) Thanks [@&#8203;Mokto](https://github.com/Mokto)! - Fixed false positives in `noUnusedImports`, `noUnusedVariables`, and `useImportType` for Svelte components that use both a `<script module>` and a `<script>` block. The two blocks compile to a single module and share a top-level scope, so a binding (import, function, or variable) declared in one block and used only in the other is no longer reported as unused.

- [#&#8203;10767](biomejs/biome#10767) [`36d5aa7`](biomejs/biome@36d5aa7) Thanks [@&#8203;otkrickey](https://github.com/otkrickey)! - Fixed [#&#8203;10754](biomejs/biome#10754): [`useVueValidVBind`](https://biomejs.dev/linter/rules/use-vue-valid-v-bind/) no longer reports the Vue 3.4+ same-name shorthand as missing a value. `:foo` and `v-bind:foo` are now accepted as equivalent to `:foo="foo"`, while `v-bind`, `v-bind:[dynamicArg]`, and `:[dynamicArg]` without a value continue to be reported.

- [#&#8203;10775](biomejs/biome#10775) [`a918af0`](biomejs/biome@a918af0) Thanks [@&#8203;WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed an issue reported in [#&#8203;10708](biomejs/biome#10708): `biome rage` didn't detect running Biome daemon pipes on Windows.

- [#&#8203;10730](biomejs/biome#10730) [`5a2e65b`](biomejs/biome@5a2e65b) Thanks [@&#8203;dinocosta](https://github.com/dinocosta)! - Fixed an issue where Biome was resolving [the well-known Zed settings file](https://biomejs.dev/guides/configure-biome/#well-known-files) from the wrong location on macOS and Windows.

- [#&#8203;10807](biomejs/biome#10807) [`d97fffe`](biomejs/biome@d97fffe) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed an issue where `.scss` files were incorrectly analyzed when running `biome check`.

- [#&#8203;10672](biomejs/biome#10672) [`53c6efc`](biomejs/biome@53c6efc) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed a bug where Biome incorrectly formatted snippets that have parsing errors.

- [#&#8203;10719](biomejs/biome#10719) [`aa649b5`](biomejs/biome@aa649b5) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - Fixed [`useAwaitThenable`](https://biomejs.dev/linter/rules/use-await-thenable/) false positive when awaiting a custom thenable that is not the global `Promise`. A value with a callable `then` member is now recognized as awaitable.

  ```ts
  interface Thenable<T> {
    then(onfulfilled: (value: T) => void): void;
  }
  declare const t: Thenable<number>;
  async function f() {
    await t;
  }
  ```

- [#&#8203;10734](biomejs/biome#10734) [`4396496`](biomejs/biome@4396496) Thanks [@&#8203;BangDori](https://github.com/BangDori)! - Fixed [#&#8203;10708](biomejs/biome#10708): `biome migrate` now preserves trivia when migrating the deprecated `recommended` option to `preset`.

- [#&#8203;10683](biomejs/biome#10683) [`ae31a00`](biomejs/biome@ae31a00) Thanks [@&#8203;Netail](https://github.com/Netail)! - Fixed [#&#8203;10657](biomejs/biome#10657) [#&#8203;10671](biomejs/biome#10671) [#&#8203;10661](biomejs/biome#10661) [#&#8203;10637](biomejs/biome#10637) [#&#8203;10718](biomejs/biome#10718): HTML rules now correctly handle dynamic attributes.

- [#&#8203;10746](biomejs/biome#10746) [`54e8239`](biomejs/biome@54e8239) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed an issue where [`noUndeclaredClasses`](https://biomejs.dev/linter/rules/no-undeclared-classes) didn't correctly detect styles defined inside the Astro directive `is:global`.

- [#&#8203;10770](biomejs/biome#10770) [`dd1429c`](biomejs/biome@dd1429c) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Improved the Biome Language Server DX by orchestrating certain operations, so that they won't block the editor during typing. This improvement is more visible in large documents.

- [#&#8203;10473](biomejs/biome#10473) [`d9b5133`](biomejs/biome@d9b5133) Thanks [@&#8203;Mokto](https://github.com/Mokto)! - Improved [`noUnusedImports`](https://biomejs.dev/linter/rules/no-unused-imports/), [`noUnusedVariables`](https://biomejs.dev/linter/rules/no-unused-variables/), [`noUnusedFunctionParameters`](https://biomejs.dev/linter/rules/no-unused-function-parameters/), and [`useImportType`](https://biomejs.dev/linter/rules/use-import-type/) for Svelte, Vue, and Astro files (with `html.experimentalFullSupportEnabled`). Bindings used only in the template — including component tags, attribute interpolations, directives, `bind:` shorthand, and snippet parameters — are no longer reported as unused, while genuinely unused ones still are.

- [#&#8203;10796](biomejs/biome#10796) [`f1b3ab2`](biomejs/biome@f1b3ab2) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed an issue where the Biome Language Server didn't enable project or type-aware lint rules, even when they were explicitly enabled.

- [#&#8203;10746](biomejs/biome#10746) [`54e8239`](biomejs/biome@54e8239) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed an issue where [`noUndeclaredClasses`](https://biomejs.dev/linter/rules/no-undeclared-classes) didn't detect styles declared inside HTML documents.

- [#&#8203;10774](biomejs/biome#10774) [`bde945b`](biomejs/biome@bde945b) Thanks [@&#8203;pattrickrice](https://github.com/pattrickrice)! - Fixed [#&#8203;10268](biomejs/biome#10268) where a race condition resulted in internal errors such as: `The file biome.json does not exist in the workspace`.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMzQuMCIsInVwZGF0ZWRJblZlciI6IjQzLjIzNC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://git.oirnoir.dev/OIRNOIR/YouTube-Helper-Client/pulls/9
OIRNOIR pushed a commit to OIRNOIR/YouTube-Helper-Server that referenced this pull request Jul 8, 2026
This PR contains the following updates:

| Package | Type | Update | Change | Pending |
|---|---|---|---|---|
| [@biomejs/biome](https://biomejs.dev) ([source](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome)) | imports | patch | [`2.5.1` -> `2.5.2`](https://renovatebot.com/diffs/npm/@biomejs%2fbiome/2.5.1/2.5.2) | `2.5.3` |

---

### Release Notes

<details>
<summary>biomejs/biome (@&#8203;biomejs/biome)</summary>

### [`v2.5.2`](https://github.com/biomejs/biome/blob/HEAD/packages/@&#8203;biomejs/biome/CHANGELOG.md#252)

[Compare Source](https://github.com/biomejs/biome/compare/@biomejs/biome@2.5.1...@biomejs/biome@2.5.2)

##### Patch Changes

- [#&#8203;10595](biomejs/biome#10595) [`f458028`](biomejs/biome@f458028) Thanks [@&#8203;pkallos](https://github.com/pkallos)! - Added the option `ignoreBooleanCoercion` to [useNullishCoalescing](https://biomejs.dev/linter/rules/use-nullish-coalescing/). When enabled, Biome ignores `||` and `||=` used inside a `Boolean()` call, where coalescing on falsy values is intentional.

- [#&#8203;10798](biomejs/biome#10798) [`4a32b63`](biomejs/biome@4a32b63) Thanks [@&#8203;pkallos](https://github.com/pkallos)! - Added the option `ignorePrimitives` to [useNullishCoalescing](https://biomejs.dev/linter/rules/use-nullish-coalescing/). When enabled, Biome ignores `||`, `||=`, and ternary expressions whose non-nullish operands are all primitives the option opts out of. Use `true` to ignore all primitives, or an object selecting `string`, `number`, `boolean`, or `bigint`.

- [#&#8203;10545](biomejs/biome#10545) [`f3d4c00`](biomejs/biome@f3d4c00) Thanks [@&#8203;Mokto](https://github.com/Mokto)! - Added the new nursery rule [`noSvelteUnnecessaryStateWrap`](https://biomejs.dev/linter/rules/no-svelte-unnecessary-state-wrap/), which reports unnecessary `$state()` wrapping of classes from `svelte/reactivity` that are already reactive.

  ```svelte
  <script>
  import { SvelteMap } from "svelte/reactivity";
  const map = $state(new SvelteMap()); // redundant
  </script>
  ```

- [#&#8203;10752](biomejs/biome#10752) [`f62fb8b`](biomejs/biome@f62fb8b) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed [#&#8203;10739](biomejs/biome#10739). Now the rule [`useValidAutocomplete`](https://biomejs.dev/linter/rules/use-valid-autocomplete/) correctly flags the `autoComplete` attribute.

- [#&#8203;10796](biomejs/biome#10796) [`f1b3ab2`](biomejs/biome@f1b3ab2) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed [#&#8203;10768](biomejs/biome#10768). Improved the performance of the Biome Language Server by cancelling certain in-flight operations when there are fast updates.

- [#&#8203;10719](biomejs/biome#10719) [`aa649b5`](biomejs/biome@aa649b5) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - Fixed [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) false positive on returns that use a widening type assertion: `"a" as string` is no longer reported as misleading. The rule now also reports a literal-pinning assertion such as `false as false`, matching the existing `as const` behavior.

  ```ts
  // No longer flagged (returns are `string`):
  function getValue(b: boolean): string {
    if (b) return "a" as string;
    return "b" as string;
  }

  // Now also reported, like `as const` (returns `false`):
  function isReady(): boolean {
    return false as false;
  }
  ```

- [#&#8203;10678](biomejs/biome#10678) [`8f073a7`](biomejs/biome@8f073a7) Thanks [@&#8203;PranavAchar01](https://github.com/PranavAchar01)! - Fixed [#&#8203;7718](biomejs/biome#7718): Biome now correctly parses CSS nesting selectors when `&` appears as a trailing sub-selector after a type selector, e.g. `h1& { color: red; }`.

- [#&#8203;10756](biomejs/biome#10756) [`5ec965a`](biomejs/biome@5ec965a) Thanks [@&#8203;denbezrukov](https://github.com/denbezrukov)! - Fixed CSS formatter output for selector lists with `allowWrongLineComments` and `//` comments after a selector comma. Biome now keeps the selector before the line comment inline instead of breaking it across descendant combinators.

  ```diff
  -.powerPathNavigator
  -  .helm
  -  button.pressedButton, // pressed
  +.powerPathNavigator .helm button.pressedButton, // pressed
   .powerPathNavigator .helm button:active:not(.disabledButton) {
   }
  ```

- [#&#8203;10757](biomejs/biome#10757) [`6232fcd`](biomejs/biome@6232fcd) Thanks [@&#8203;PranavAchar01](https://github.com/PranavAchar01)! - Fixed [#&#8203;8269](biomejs/biome#8269): the CSS parser now accepts Tailwind `@variant` and `@utility` names that start with a digit, such as the `2xl` breakpoint.

  ```css
  @&#8203;utility container {
    @&#8203;variant 2xl {
      max-width: 1400px;
    }
  }
  ```

- [#&#8203;10777](biomejs/biome#10777) [`575ced6`](biomejs/biome@575ced6) Thanks [@&#8203;WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed an issue reported in [#&#8203;10708](biomejs/biome#10708): the GitLab reporter now handles `--verbose` diagnostics filtering correctly.

- [#&#8203;10281](biomejs/biome#10281) [`0efe244`](biomejs/biome@0efe244) Thanks [@&#8203;Zelys-DFKH](https://github.com/Zelys-DFKH)! - Fixed a bug where GritQL patterns rejected positional (unkeyed) arguments.

- [#&#8203;10758](biomejs/biome#10758) [`e36fd8a`](biomejs/biome@e36fd8a) Thanks [@&#8203;henrybrewer00-dotcom](https://github.com/henrybrewer00-dotcom)! - Fixed [#&#8203;10697](biomejs/biome#10697): The formatter no longer removes the parentheses around an `await` or `yield` expression used as the target of a TypeScript instantiation expression. For example, `(await makeFactory)<Value>` is no longer reformatted to `await makeFactory<Value>`, which would change the meaning of the code.

- [#&#8203;10586](biomejs/biome#10586) [`3617094`](biomejs/biome@3617094) Thanks [@&#8203;IxxyDev](https://github.com/IxxyDev)! - Fixed [#&#8203;9568](biomejs/biome#9568): [`noFloatingPromises`](https://biomejs.dev/linter/rules/no-floating-promises/) no longer reports a false positive when calling an overloaded function and the selected overload does not return a promise.

  ```ts
  function bestEffort(cb: () => Promise<number>): Promise<number>;
  function bestEffort(cb: () => number): number;
  function bestEffort(
    cb: () => number | Promise<number>,
  ): Promise<number> | number {
    return cb() as Promise<number> | number;
  }

  // This resolves to the second overload, which returns `number`, so it is no
  // longer flagged as a floating promise.
  bestEffort(() => 42);
  ```

- [#&#8203;10766](biomejs/biome#10766) [`7aff4c1`](biomejs/biome@7aff4c1) Thanks [@&#8203;JamBalaya56562](https://github.com/JamBalaya56562)! - Fixed [#&#8203;2862](biomejs/biome#2862): [`noInteractiveElementToNoninteractiveRole`](https://biomejs.dev/linter/rules/no-interactive-element-to-noninteractive-role/) no longer reports custom elements (a tag name containing a dash, e.g. `<my-button role="img" />`). Per the [W3C HTML-ARIA specification](https://www.w3.org/TR/html-aria/#el-autonomous-custom-element), a custom element may be given any role or none.

- [#&#8203;10680](biomejs/biome#10680) [`771daa4`](biomejs/biome@771daa4) Thanks [@&#8203;WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed [#&#8203;10635](biomejs/biome#10635): Biome now recognizes chained
  table tests such as `test.concurrent.each()` and `it.concurrent.each()` as test calls, fixing
  `noMisplacedAssertion` false positives and improving formatting for those test declarations.

- [#&#8203;10759](biomejs/biome#10759) [`34570b5`](biomejs/biome@34570b5) Thanks [@&#8203;henrybrewer00-dotcom](https://github.com/henrybrewer00-dotcom)! - Fixed [#&#8203;10636](biomejs/biome#10636): [noStaticElementInteractions](https://biomejs.dev/linter/rules/no-static-element-interactions/) no longer reports a false positive for event handlers on Svelte special elements such as `<svelte:window>`, `<svelte:document>`, and `<svelte:body>`. These are not real DOM elements, so they are now ignored by the rule.

- [#&#8203;10741](biomejs/biome#10741) [`bd2364e`](biomejs/biome@bd2364e) Thanks [@&#8203;JamBalaya56562](https://github.com/JamBalaya56562)! - Fixed [#&#8203;6686](biomejs/biome#6686): the `rage` command now respects the `--config-path` option and the `BIOME_CONFIG_PATH` environment variable when loading the Biome configuration. Previously it always used the default configuration resolution and reported the configuration as `Not set` when no `biome.json` existed in the working directory.

- [#&#8203;10763](biomejs/biome#10763) [`2c3e82d`](biomejs/biome@2c3e82d) Thanks [@&#8203;Aqu1bp](https://github.com/Aqu1bp)! - Fixed [#&#8203;10742](biomejs/biome#10742): [`noSolidDestructuredProps`](https://biomejs.dev/linter/rules/no-solid-destructured-props) now reports destructured props in Solid function components and JSX children.

- [#&#8203;10606](biomejs/biome#10606) [`a4cc4ab`](biomejs/biome@a4cc4ab) Thanks [@&#8203;Mokto](https://github.com/Mokto)! - Fixed false positives in `noUnusedImports`, `noUnusedVariables`, and `useImportType` for Svelte components that use both a `<script module>` and a `<script>` block. The two blocks compile to a single module and share a top-level scope, so a binding (import, function, or variable) declared in one block and used only in the other is no longer reported as unused.

- [#&#8203;10767](biomejs/biome#10767) [`36d5aa7`](biomejs/biome@36d5aa7) Thanks [@&#8203;otkrickey](https://github.com/otkrickey)! - Fixed [#&#8203;10754](biomejs/biome#10754): [`useVueValidVBind`](https://biomejs.dev/linter/rules/use-vue-valid-v-bind/) no longer reports the Vue 3.4+ same-name shorthand as missing a value. `:foo` and `v-bind:foo` are now accepted as equivalent to `:foo="foo"`, while `v-bind`, `v-bind:[dynamicArg]`, and `:[dynamicArg]` without a value continue to be reported.

- [#&#8203;10775](biomejs/biome#10775) [`a918af0`](biomejs/biome@a918af0) Thanks [@&#8203;WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed an issue reported in [#&#8203;10708](biomejs/biome#10708): `biome rage` didn't detect running Biome daemon pipes on Windows.

- [#&#8203;10730](biomejs/biome#10730) [`5a2e65b`](biomejs/biome@5a2e65b) Thanks [@&#8203;dinocosta](https://github.com/dinocosta)! - Fixed an issue where Biome was resolving [the well-known Zed settings file](https://biomejs.dev/guides/configure-biome/#well-known-files) from the wrong location on macOS and Windows.

- [#&#8203;10807](biomejs/biome#10807) [`d97fffe`](biomejs/biome@d97fffe) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed an issue where `.scss` files were incorrectly analyzed when running `biome check`.

- [#&#8203;10672](biomejs/biome#10672) [`53c6efc`](biomejs/biome@53c6efc) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed a bug where Biome incorrectly formatted snippets that have parsing errors.

- [#&#8203;10719](biomejs/biome#10719) [`aa649b5`](biomejs/biome@aa649b5) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - Fixed [`useAwaitThenable`](https://biomejs.dev/linter/rules/use-await-thenable/) false positive when awaiting a custom thenable that is not the global `Promise`. A value with a callable `then` member is now recognized as awaitable.

  ```ts
  interface Thenable<T> {
    then(onfulfilled: (value: T) => void): void;
  }
  declare const t: Thenable<number>;
  async function f() {
    await t;
  }
  ```

- [#&#8203;10734](biomejs/biome#10734) [`4396496`](biomejs/biome@4396496) Thanks [@&#8203;BangDori](https://github.com/BangDori)! - Fixed [#&#8203;10708](biomejs/biome#10708): `biome migrate` now preserves trivia when migrating the deprecated `recommended` option to `preset`.

- [#&#8203;10683](biomejs/biome#10683) [`ae31a00`](biomejs/biome@ae31a00) Thanks [@&#8203;Netail](https://github.com/Netail)! - Fixed [#&#8203;10657](biomejs/biome#10657) [#&#8203;10671](biomejs/biome#10671) [#&#8203;10661](biomejs/biome#10661) [#&#8203;10637](biomejs/biome#10637) [#&#8203;10718](biomejs/biome#10718): HTML rules now correctly handle dynamic attributes.

- [#&#8203;10746](biomejs/biome#10746) [`54e8239`](biomejs/biome@54e8239) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed an issue where [`noUndeclaredClasses`](https://biomejs.dev/linter/rules/no-undeclared-classes) didn't correctly detect styles defined inside the Astro directive `is:global`.

- [#&#8203;10770](biomejs/biome#10770) [`dd1429c`](biomejs/biome@dd1429c) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Improved the Biome Language Server DX by orchestrating certain operations, so that they won't block the editor during typing. This improvement is more visible in large documents.

- [#&#8203;10473](biomejs/biome#10473) [`d9b5133`](biomejs/biome@d9b5133) Thanks [@&#8203;Mokto](https://github.com/Mokto)! - Improved [`noUnusedImports`](https://biomejs.dev/linter/rules/no-unused-imports/), [`noUnusedVariables`](https://biomejs.dev/linter/rules/no-unused-variables/), [`noUnusedFunctionParameters`](https://biomejs.dev/linter/rules/no-unused-function-parameters/), and [`useImportType`](https://biomejs.dev/linter/rules/use-import-type/) for Svelte, Vue, and Astro files (with `html.experimentalFullSupportEnabled`). Bindings used only in the template — including component tags, attribute interpolations, directives, `bind:` shorthand, and snippet parameters — are no longer reported as unused, while genuinely unused ones still are.

- [#&#8203;10796](biomejs/biome#10796) [`f1b3ab2`](biomejs/biome@f1b3ab2) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed an issue where the Biome Language Server didn't enable project or type-aware lint rules, even when they were explicitly enabled.

- [#&#8203;10746](biomejs/biome#10746) [`54e8239`](biomejs/biome@54e8239) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed an issue where [`noUndeclaredClasses`](https://biomejs.dev/linter/rules/no-undeclared-classes) didn't detect styles declared inside HTML documents.

- [#&#8203;10774](biomejs/biome#10774) [`bde945b`](biomejs/biome@bde945b) Thanks [@&#8203;pattrickrice](https://github.com/pattrickrice)! - Fixed [#&#8203;10268](biomejs/biome#10268) where a race condition resulted in internal errors such as: `The file biome.json does not exist in the workspace`.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDYuMSIsInVwZGF0ZWRJblZlciI6IjQzLjI0Ni4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://git.oirnoir.dev/OIRNOIR/YouTube-Helper-Server/pulls/22
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-Project Area: project L-HTML Language: HTML and super languages

Projects

None yet

2 participants