fix(html_analyze): correctly handle dynamic values for attributes#10683
Conversation
✅ Organic activityNo automation signals detected in the analyzed events. This is an automated analysis by AgentScan |
🦋 Changeset detectedLatest commit: 8920542 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
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 |
Merging this PR will not alter performance
Comparing Footnotes
|
d1ad198 to
ada4e1b
Compare
WalkthroughThe 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
Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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 winRead
aria-labelandaltthrough the static-value path.
get_aria_labelandget_img_altstill only acceptinitializer.value().as_html_string(). That drops static bound strings such as Vue:aria-label="'read more'"or Astro/Sveltealt={"read more"}, sonoAmbiguousAnchorTextwill 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 winUse the binding-aware lookup here too.
These
AnyHtmlTagElementhelpers still callfind_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 winDon't conflate dynamic
contenteditablewith a bare attribute.
as_static_value()beingNonedoes not just mean “bare attribute”; it also covers values you cannot fold statically. With the newNone => truebranch,contenteditable={expr}is treated as truthy and this rule will start flagging dynamic templates as focusable when the runtime value may befalse.🤖 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
⛔ Files ignored due to path filters (83)
crates/biome_html_analyze/tests/specs/a11y/noAccessKey/astro/invalid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAccessKey/svelte/invalid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAccessKey/vue/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/invalid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/invalid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/invalid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/invalid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/astro/invalid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/svelte/invalid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/vue/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAutofocus/astro/invalid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAutofocus/svelte/invalid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noAutofocus/vue/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/astro/invalid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/svelte/invalid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/vue/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noHeaderScope/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noLabelWithoutControl/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAltText/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAltText/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useButtonType/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useSemanticElements/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useSemanticElements/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useSemanticElements/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAnchor/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAnchor/vue/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAnchor/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAriaProps/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAriaProps/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAutocomplete/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidAutocomplete/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidLang/astro/valid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidLang/svelte/valid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useValidLang/vue/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/security/noScriptUrl/invalid.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/security/noScriptUrl/invalid.html.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/security/noScriptUrl/invalid.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/security/noScriptUrl/invalid.vue.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (125)
crates/biome_html_analyze/src/a11y.rscrates/biome_html_analyze/src/a11y_tests.rscrates/biome_html_analyze/src/lint/a11y/no_access_key.rscrates/biome_html_analyze/src/lint/a11y/no_ambiguous_anchor_text.rscrates/biome_html_analyze/src/lint/a11y/no_aria_hidden_on_focusable.rscrates/biome_html_analyze/src/lint/a11y/no_aria_unsupported_elements.rscrates/biome_html_analyze/src/lint/a11y/no_autofocus.rscrates/biome_html_analyze/src/lint/a11y/no_header_scope.rscrates/biome_html_analyze/src/lint/a11y/no_interactive_element_to_noninteractive_role.rscrates/biome_html_analyze/src/lint/a11y/no_label_without_control.rscrates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_to_interactive_role.rscrates/biome_html_analyze/src/lint/a11y/no_noninteractive_tabindex.rscrates/biome_html_analyze/src/lint/a11y/no_positive_tabindex.rscrates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rscrates/biome_html_analyze/src/lint/a11y/no_redundant_roles.rscrates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rscrates/biome_html_analyze/src/lint/a11y/use_alt_text.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rscrates/biome_html_analyze/src/lint/a11y/use_aria_activedescendant_with_tabindex.rscrates/biome_html_analyze/src/lint/a11y/use_aria_props_for_role.rscrates/biome_html_analyze/src/lint/a11y/use_aria_props_supported_by_role.rscrates/biome_html_analyze/src/lint/a11y/use_button_type.rscrates/biome_html_analyze/src/lint/a11y/use_focusable_interactive.rscrates/biome_html_analyze/src/lint/a11y/use_key_with_click_events.rscrates/biome_html_analyze/src/lint/a11y/use_key_with_mouse_events.rscrates/biome_html_analyze/src/lint/a11y/use_media_caption.rscrates/biome_html_analyze/src/lint/a11y/use_semantic_elements.rscrates/biome_html_analyze/src/lint/a11y/use_valid_anchor.rscrates/biome_html_analyze/src/lint/a11y/use_valid_aria_role.rscrates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rscrates/biome_html_analyze/src/lint/a11y/use_valid_autocomplete.rscrates/biome_html_analyze/src/lint/a11y/use_valid_lang.rscrates/biome_html_analyze/src/lint/nursery/use_scoped_styles.rscrates/biome_html_analyze/src/lint/performance/no_sync_scripts.rscrates/biome_html_analyze/src/lint/performance/use_vue_vapor.rscrates/biome_html_analyze/src/lint/security/no_script_url.rscrates/biome_html_analyze/tests/specs/a11y/noAccessKey/astro/invalid.astrocrates/biome_html_analyze/tests/specs/a11y/noAccessKey/svelte/invalid.sveltecrates/biome_html_analyze/tests/specs/a11y/noAccessKey/vue/invalid.vuecrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/invalid.astrocrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/invalid.astrocrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/invalid.options.jsoncrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/astro/words/valid.options.jsoncrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/invalid.sveltecrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/invalid.options.jsoncrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/invalid.sveltecrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/valid.options.jsoncrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/svelte/words/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/invalid.vuecrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/invalid.options.jsoncrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/invalid.vuecrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/valid.options.jsoncrates/biome_html_analyze/tests/specs/a11y/noAmbiguousAnchorText/vue/words/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noAriaHiddenOnFocusable/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/astro/invalid.astrocrates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/svelte/invalid.sveltecrates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/vue/invalid.vuecrates/biome_html_analyze/tests/specs/a11y/noAriaUnsupportedElements/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noAutofocus/astro/invalid.astrocrates/biome_html_analyze/tests/specs/a11y/noAutofocus/svelte/invalid.sveltecrates/biome_html_analyze/tests/specs/a11y/noAutofocus/vue/invalid.vuecrates/biome_html_analyze/tests/specs/a11y/noHeaderScope/astro/invalid.astrocrates/biome_html_analyze/tests/specs/a11y/noHeaderScope/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noHeaderScope/svelte/invalid.sveltecrates/biome_html_analyze/tests/specs/a11y/noHeaderScope/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noHeaderScope/vue/invalid.vuecrates/biome_html_analyze/tests/specs/a11y/noHeaderScope/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noLabelWithoutControl/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noNoninteractiveTabindex/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noPositiveTabindex/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/noRedundantRoles/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/useAltText/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useAltText/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useAriaActivedescendantWithTabindex/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/useButtonType/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useHtmlLang/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useHtmlLang/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useHtmlLang/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/useIframeTitle/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useIframeTitle/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useIframeTitle/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/useSemanticElements/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useSemanticElements/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useSemanticElements/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/useValidAnchor/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useValidAnchor/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/useValidAriaProps/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useValidAriaProps/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useValidAutocomplete/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useValidAutocomplete/vue/valid.vuecrates/biome_html_analyze/tests/specs/a11y/useValidLang/astro/valid.astrocrates/biome_html_analyze/tests/specs/a11y/useValidLang/svelte/valid.sveltecrates/biome_html_analyze/tests/specs/a11y/useValidLang/vue/valid.vuecrates/biome_html_formatter/src/svelte/value/directive_value.rscrates/biome_html_syntax/src/attribute_ext.rscrates/biome_html_syntax/src/element_ext.rscrates/biome_html_syntax/src/text_ext.rscrates/biome_module_graph/src/html_module_info/visitor.rs
| let aria_label_attribute = node.find_attribute_by_name("aria-label"); | ||
| if aria_label_attribute.is_some() { | ||
| return None; | ||
| } |
There was a problem hiding this comment.
🎯 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.
| // 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())) |
There was a problem hiding this comment.
🎯 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.
| // 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.
| .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) | ||
| }) |
There was a problem hiding this comment.
🎯 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.
36986f8 to
c869350
Compare
|
What's missing @Netail ? How can I help to merge the PR? |
Hi, Bit caught up with company work & turned out a bit bigger than initially thought |
|
Alright, let the clanker loose on the static vue binding values. Some finishing touches left I guess |
|
Does the PR closes all those issues? If so can you use the correct comments for auto closing? |
|
@Netail I updated the PR description. Auto-closing works only for single issues |
Ahh okay, TIL, thanks! |
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 (@​biomejs/biome)</summary> ### [`v2.5.2`](https://github.com/biomejs/biome/blob/HEAD/packages/@​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 - [#​10595](biomejs/biome#10595) [`f458028`](biomejs/biome@f458028) Thanks [@​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. - [#​10798](biomejs/biome#10798) [`4a32b63`](biomejs/biome@4a32b63) Thanks [@​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`. - [#​10545](biomejs/biome#10545) [`f3d4c00`](biomejs/biome@f3d4c00) Thanks [@​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> ``` - [#​10752](biomejs/biome#10752) [`f62fb8b`](biomejs/biome@f62fb8b) Thanks [@​ematipico](https://github.com/ematipico)! - Fixed [#​10739](biomejs/biome#10739). Now the rule [`useValidAutocomplete`](https://biomejs.dev/linter/rules/use-valid-autocomplete/) correctly flags the `autoComplete` attribute. - [#​10796](biomejs/biome#10796) [`f1b3ab2`](biomejs/biome@f1b3ab2) Thanks [@​ematipico](https://github.com/ematipico)! - Fixed [#​10768](biomejs/biome#10768). Improved the performance of the Biome Language Server by cancelling certain in-flight operations when there are fast updates. - [#​10719](biomejs/biome#10719) [`aa649b5`](biomejs/biome@aa649b5) Thanks [@​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; } ``` - [#​10678](biomejs/biome#10678) [`8f073a7`](biomejs/biome@8f073a7) Thanks [@​PranavAchar01](https://github.com/PranavAchar01)! - Fixed [#​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; }`. - [#​10756](biomejs/biome#10756) [`5ec965a`](biomejs/biome@5ec965a) Thanks [@​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) { } ``` - [#​10757](biomejs/biome#10757) [`6232fcd`](biomejs/biome@6232fcd) Thanks [@​PranavAchar01](https://github.com/PranavAchar01)! - Fixed [#​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 @​utility container { @​variant 2xl { max-width: 1400px; } } ``` - [#​10777](biomejs/biome#10777) [`575ced6`](biomejs/biome@575ced6) Thanks [@​WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed an issue reported in [#​10708](biomejs/biome#10708): the GitLab reporter now handles `--verbose` diagnostics filtering correctly. - [#​10281](biomejs/biome#10281) [`0efe244`](biomejs/biome@0efe244) Thanks [@​Zelys-DFKH](https://github.com/Zelys-DFKH)! - Fixed a bug where GritQL patterns rejected positional (unkeyed) arguments. - [#​10758](biomejs/biome#10758) [`e36fd8a`](biomejs/biome@e36fd8a) Thanks [@​henrybrewer00-dotcom](https://github.com/henrybrewer00-dotcom)! - Fixed [#​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. - [#​10586](biomejs/biome#10586) [`3617094`](biomejs/biome@3617094) Thanks [@​IxxyDev](https://github.com/IxxyDev)! - Fixed [#​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); ``` - [#​10766](biomejs/biome#10766) [`7aff4c1`](biomejs/biome@7aff4c1) Thanks [@​JamBalaya56562](https://github.com/JamBalaya56562)! - Fixed [#​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. - [#​10680](biomejs/biome#10680) [`771daa4`](biomejs/biome@771daa4) Thanks [@​WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed [#​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. - [#​10759](biomejs/biome#10759) [`34570b5`](biomejs/biome@34570b5) Thanks [@​henrybrewer00-dotcom](https://github.com/henrybrewer00-dotcom)! - Fixed [#​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. - [#​10741](biomejs/biome#10741) [`bd2364e`](biomejs/biome@bd2364e) Thanks [@​JamBalaya56562](https://github.com/JamBalaya56562)! - Fixed [#​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. - [#​10763](biomejs/biome#10763) [`2c3e82d`](biomejs/biome@2c3e82d) Thanks [@​Aqu1bp](https://github.com/Aqu1bp)! - Fixed [#​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. - [#​10606](biomejs/biome#10606) [`a4cc4ab`](biomejs/biome@a4cc4ab) Thanks [@​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. - [#​10767](biomejs/biome#10767) [`36d5aa7`](biomejs/biome@36d5aa7) Thanks [@​otkrickey](https://github.com/otkrickey)! - Fixed [#​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. - [#​10775](biomejs/biome#10775) [`a918af0`](biomejs/biome@a918af0) Thanks [@​WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed an issue reported in [#​10708](biomejs/biome#10708): `biome rage` didn't detect running Biome daemon pipes on Windows. - [#​10730](biomejs/biome#10730) [`5a2e65b`](biomejs/biome@5a2e65b) Thanks [@​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. - [#​10807](biomejs/biome#10807) [`d97fffe`](biomejs/biome@d97fffe) Thanks [@​ematipico](https://github.com/ematipico)! - Fixed an issue where `.scss` files were incorrectly analyzed when running `biome check`. - [#​10672](biomejs/biome#10672) [`53c6efc`](biomejs/biome@53c6efc) Thanks [@​ematipico](https://github.com/ematipico)! - Fixed a bug where Biome incorrectly formatted snippets that have parsing errors. - [#​10719](biomejs/biome#10719) [`aa649b5`](biomejs/biome@aa649b5) Thanks [@​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; } ``` - [#​10734](biomejs/biome#10734) [`4396496`](biomejs/biome@4396496) Thanks [@​BangDori](https://github.com/BangDori)! - Fixed [#​10708](biomejs/biome#10708): `biome migrate` now preserves trivia when migrating the deprecated `recommended` option to `preset`. - [#​10683](biomejs/biome#10683) [`ae31a00`](biomejs/biome@ae31a00) Thanks [@​Netail](https://github.com/Netail)! - Fixed [#​10657](biomejs/biome#10657) [#​10671](biomejs/biome#10671) [#​10661](biomejs/biome#10661) [#​10637](biomejs/biome#10637) [#​10718](biomejs/biome#10718): HTML rules now correctly handle dynamic attributes. - [#​10746](biomejs/biome#10746) [`54e8239`](biomejs/biome@54e8239) Thanks [@​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`. - [#​10770](biomejs/biome#10770) [`dd1429c`](biomejs/biome@dd1429c) Thanks [@​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. - [#​10473](biomejs/biome#10473) [`d9b5133`](biomejs/biome@d9b5133) Thanks [@​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. - [#​10796](biomejs/biome#10796) [`f1b3ab2`](biomejs/biome@f1b3ab2) Thanks [@​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. - [#​10746](biomejs/biome#10746) [`54e8239`](biomejs/biome@54e8239) Thanks [@​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. - [#​10774](biomejs/biome#10774) [`bde945b`](biomejs/biome@bde945b) Thanks [@​pattrickrice](https://github.com/pattrickrice)! - Fixed [#​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
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 (@​biomejs/biome)</summary> ### [`v2.5.2`](https://github.com/biomejs/biome/blob/HEAD/packages/@​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 - [#​10595](biomejs/biome#10595) [`f458028`](biomejs/biome@f458028) Thanks [@​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. - [#​10798](biomejs/biome#10798) [`4a32b63`](biomejs/biome@4a32b63) Thanks [@​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`. - [#​10545](biomejs/biome#10545) [`f3d4c00`](biomejs/biome@f3d4c00) Thanks [@​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> ``` - [#​10752](biomejs/biome#10752) [`f62fb8b`](biomejs/biome@f62fb8b) Thanks [@​ematipico](https://github.com/ematipico)! - Fixed [#​10739](biomejs/biome#10739). Now the rule [`useValidAutocomplete`](https://biomejs.dev/linter/rules/use-valid-autocomplete/) correctly flags the `autoComplete` attribute. - [#​10796](biomejs/biome#10796) [`f1b3ab2`](biomejs/biome@f1b3ab2) Thanks [@​ematipico](https://github.com/ematipico)! - Fixed [#​10768](biomejs/biome#10768). Improved the performance of the Biome Language Server by cancelling certain in-flight operations when there are fast updates. - [#​10719](biomejs/biome#10719) [`aa649b5`](biomejs/biome@aa649b5) Thanks [@​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; } ``` - [#​10678](biomejs/biome#10678) [`8f073a7`](biomejs/biome@8f073a7) Thanks [@​PranavAchar01](https://github.com/PranavAchar01)! - Fixed [#​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; }`. - [#​10756](biomejs/biome#10756) [`5ec965a`](biomejs/biome@5ec965a) Thanks [@​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) { } ``` - [#​10757](biomejs/biome#10757) [`6232fcd`](biomejs/biome@6232fcd) Thanks [@​PranavAchar01](https://github.com/PranavAchar01)! - Fixed [#​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 @​utility container { @​variant 2xl { max-width: 1400px; } } ``` - [#​10777](biomejs/biome#10777) [`575ced6`](biomejs/biome@575ced6) Thanks [@​WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed an issue reported in [#​10708](biomejs/biome#10708): the GitLab reporter now handles `--verbose` diagnostics filtering correctly. - [#​10281](biomejs/biome#10281) [`0efe244`](biomejs/biome@0efe244) Thanks [@​Zelys-DFKH](https://github.com/Zelys-DFKH)! - Fixed a bug where GritQL patterns rejected positional (unkeyed) arguments. - [#​10758](biomejs/biome#10758) [`e36fd8a`](biomejs/biome@e36fd8a) Thanks [@​henrybrewer00-dotcom](https://github.com/henrybrewer00-dotcom)! - Fixed [#​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. - [#​10586](biomejs/biome#10586) [`3617094`](biomejs/biome@3617094) Thanks [@​IxxyDev](https://github.com/IxxyDev)! - Fixed [#​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); ``` - [#​10766](biomejs/biome#10766) [`7aff4c1`](biomejs/biome@7aff4c1) Thanks [@​JamBalaya56562](https://github.com/JamBalaya56562)! - Fixed [#​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. - [#​10680](biomejs/biome#10680) [`771daa4`](biomejs/biome@771daa4) Thanks [@​WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed [#​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. - [#​10759](biomejs/biome#10759) [`34570b5`](biomejs/biome@34570b5) Thanks [@​henrybrewer00-dotcom](https://github.com/henrybrewer00-dotcom)! - Fixed [#​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. - [#​10741](biomejs/biome#10741) [`bd2364e`](biomejs/biome@bd2364e) Thanks [@​JamBalaya56562](https://github.com/JamBalaya56562)! - Fixed [#​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. - [#​10763](biomejs/biome#10763) [`2c3e82d`](biomejs/biome@2c3e82d) Thanks [@​Aqu1bp](https://github.com/Aqu1bp)! - Fixed [#​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. - [#​10606](biomejs/biome#10606) [`a4cc4ab`](biomejs/biome@a4cc4ab) Thanks [@​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. - [#​10767](biomejs/biome#10767) [`36d5aa7`](biomejs/biome@36d5aa7) Thanks [@​otkrickey](https://github.com/otkrickey)! - Fixed [#​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. - [#​10775](biomejs/biome#10775) [`a918af0`](biomejs/biome@a918af0) Thanks [@​WaterWhisperer](https://github.com/WaterWhisperer)! - Fixed an issue reported in [#​10708](biomejs/biome#10708): `biome rage` didn't detect running Biome daemon pipes on Windows. - [#​10730](biomejs/biome#10730) [`5a2e65b`](biomejs/biome@5a2e65b) Thanks [@​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. - [#​10807](biomejs/biome#10807) [`d97fffe`](biomejs/biome@d97fffe) Thanks [@​ematipico](https://github.com/ematipico)! - Fixed an issue where `.scss` files were incorrectly analyzed when running `biome check`. - [#​10672](biomejs/biome#10672) [`53c6efc`](biomejs/biome@53c6efc) Thanks [@​ematipico](https://github.com/ematipico)! - Fixed a bug where Biome incorrectly formatted snippets that have parsing errors. - [#​10719](biomejs/biome#10719) [`aa649b5`](biomejs/biome@aa649b5) Thanks [@​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; } ``` - [#​10734](biomejs/biome#10734) [`4396496`](biomejs/biome@4396496) Thanks [@​BangDori](https://github.com/BangDori)! - Fixed [#​10708](biomejs/biome#10708): `biome migrate` now preserves trivia when migrating the deprecated `recommended` option to `preset`. - [#​10683](biomejs/biome#10683) [`ae31a00`](biomejs/biome@ae31a00) Thanks [@​Netail](https://github.com/Netail)! - Fixed [#​10657](biomejs/biome#10657) [#​10671](biomejs/biome#10671) [#​10661](biomejs/biome#10661) [#​10637](biomejs/biome#10637) [#​10718](biomejs/biome#10718): HTML rules now correctly handle dynamic attributes. - [#​10746](biomejs/biome#10746) [`54e8239`](biomejs/biome@54e8239) Thanks [@​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`. - [#​10770](biomejs/biome#10770) [`dd1429c`](biomejs/biome@dd1429c) Thanks [@​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. - [#​10473](biomejs/biome#10473) [`d9b5133`](biomejs/biome@d9b5133) Thanks [@​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. - [#​10796](biomejs/biome#10796) [`f1b3ab2`](biomejs/biome@f1b3ab2) Thanks [@​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. - [#​10746](biomejs/biome#10746) [`54e8239`](biomejs/biome@54e8239) Thanks [@​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. - [#​10774](biomejs/biome#10774) [`bde945b`](biomejs/biome@bde945b) Thanks [@​pattrickrice](https://github.com/pattrickrice)! - Fixed [#​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
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