Skip to content

feat(html): implement noRedundantAlt#8666

Merged
ematipico merged 5 commits intonextfrom
feat/no-redudant-alt
Jan 5, 2026
Merged

feat(html): implement noRedundantAlt#8666
ematipico merged 5 commits intonextfrom
feat/no-redudant-alt

Conversation

@ematipico
Copy link
Member

Summary

Part of #8155

It implements noRedundantAlt to HTML

Test Plan

Added various test cases

Docs

Copied from the original rule

@changeset-bot
Copy link

changeset-bot bot commented Jan 3, 2026

🦋 Changeset detected

Latest commit: 0dc9450

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

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

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

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

@ematipico ematipico requested review from a team January 3, 2026 19:44
@github-actions github-actions bot added A-Project Area: project A-Linter Area: linter A-Parser Area: parser L-JavaScript Language: JavaScript and super languages L-HTML Language: HTML and super languages labels Jan 3, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 3, 2026

Walkthrough

Adds a new HTML accessibility lint rule noRedundantAlt that flags img elements whose alt attribute contains the words "image", "picture" or "photo" (case‑insensitive), skipping elements when aria-hidden is not explicitly false. Registers the rule in the A11y lint group, extracts is_redundant_alt into shared options, makes NoRedundantAltOptions serialisable/mergeable, adds HtmlElement::name() helper, and adds HTML/Vue test fixtures for valid and invalid cases.

Possibly related PRs

Suggested labels

A-Diagnostic

Suggested reviewers

  • dyc3

Pre-merge checks

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: implementing the noRedundantAlt linting rule for HTML.
Description check ✅ Passed The description is related to the changeset, referencing the GitHub issue and explaining the implementation of noRedundantAlt for HTML with test cases added.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d7671c and 0dc9450.

📒 Files selected for processing (1)
  • .changeset/small-seas-laugh.md
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Changesets should describe user-facing changes only; internal refactoring without behavior changes does not require a changeset

Applied to files:

  • .changeset/small-seas-laugh.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Check Dependencies
  • GitHub Check: End-to-end tests
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Documentation
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_formatter)
🔇 Additional comments (1)
.changeset/small-seas-laugh.md (1)

1-5: Looks good!

The changeset format is correct, the version bump is appropriate for a new linter rule, and the description clearly communicates the user-facing change. The grammar issue from the prior review has been resolved.

One minor note: the description doesn't mention the aria-hidden exception referenced in the rule's implementation, but that's an implementation detail rather than a user-facing concern, so it's fine to omit it from the changelog.


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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/biome_html_syntax/src/element_ext.rs (1)

223-225: Add rustdoc documentation for this public method.

Per the coding guidelines for Rust files, public methods should include inline rustdoc comments. Consider documenting what this method returns and any errors it might produce.

🔎 Suggested documentation
+    /// Returns the tag name of this HTML element.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if the opening element is missing or malformed.
     pub fn name(&self) -> SyntaxResult<HtmlTagName> {
         self.opening_element()?.name()
     }

As per coding guidelines, Rust code should use inline rustdoc documentation.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b36ff03 and f601418.

⛔ Files ignored due to path filters (5)
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/valid.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (11)
  • .changeset/small-seas-laugh.md
  • crates/biome_html_analyze/src/lint/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/valid.vue
  • crates/biome_html_syntax/src/element_ext.rs
  • crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_rule_options/src/no_redundant_alt.rs
  • crates/biome_rule_options/src/shared/mod.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

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

Files:

  • crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_rule_options/src/shared/mod.rs
  • crates/biome_html_syntax/src/element_ext.rs
  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_html_analyze/src/lint/a11y.rs
  • crates/biome_rule_options/src/no_redundant_alt.rs
🧠 Learnings (33)
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Deprecated rules must include a `deprecated` field in the `declare_lint_rule!` macro with an explanation of what rule to use instead

Applied to files:

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

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_rule_options/src/shared/mod.rs
  • crates/biome_html_analyze/src/lint/a11y.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `use` prefix when the rule's sole intention is to mandate a single concept

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_rule_options/src/shared/mod.rs
  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_html_analyze/src/lint/a11y.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Check if a variable is global using the semantic model before reporting diagnostics for rules that ban global functions or variables

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `no` prefix when the rule's sole intention is to forbid a single concept

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_rule_options/src/shared/mod.rs
  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_html_analyze/src/lint/a11y.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_rule_options/src/shared/mod.rs
  • crates/biome_rule_options/src/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : When porting rules from other linters, use `sources` metadata with `RuleSource::Eslint().same()` for identical behavior or `.inspired()` for different behavior

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_rule_options/src/shared/mod.rs
  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Option<_>` wrapper for rule option fields to enable proper merging of configurations

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • crates/biome_html_syntax/src/element_ext.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Changesets should describe user-facing changes only; internal refactoring without behavior changes does not require a changeset

Applied to files:

  • .changeset/small-seas-laugh.md
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Changesets should be concise (1-3 sentences) and provide quick overview of changes without overwhelming details

Applied to files:

  • .changeset/small-seas-laugh.md
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/* : Create test files with `invalid` and `valid` prefixes to represent code that should and should not trigger the rule

Applied to files:

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

Applied to files:

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

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Code blocks in rule documentation must specify a language identifier and be tagged with `expect_diagnostic` for invalid examples or remain untagged for valid examples

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/valid.vue
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : New rules must be placed inside the `nursery` group before promotion to other groups

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Mark rules with `issue_number` in the `declare_lint_rule!` macro if they are work-in-progress to indicate missing features

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule option types must derive `Deserializable`, `Serialize`, `Deserialize`, and optionally `JsonSchema` traits

Applied to files:

  • crates/biome_rule_options/src/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(deny_unknown_fields)]` to rule option structs to enforce strict configuration validation

Applied to files:

  • crates/biome_rule_options/src/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Implement `biome_deserialize::Merge` for rule option types to define how shared and user configurations are merged

Applied to files:

  • crates/biome_rule_options/src/no_redundant_alt.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use #[derive(Diagnostic)] on enums when every variant contains a type that is itself a diagnostic

Applied to files:

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

Applied to files:

  • crates/biome_rule_options/src/no_redundant_alt.rs
🧬 Code graph analysis (2)
crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs (1)
crates/biome_rule_options/src/shared/mod.rs (1)
  • is_redundant_alt (8-13)
crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs (2)
crates/biome_rule_options/src/shared/mod.rs (1)
  • is_redundant_alt (8-13)
crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs (1)
  • diagnostic (130-143)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: autofix
  • GitHub Check: Check Dependencies
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Documentation
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_configuration)
🔇 Additional comments (9)
crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/invalid.vue (1)

6-6: Verify JSX syntax in Vue test fixture.

The syntax alt={"photo"} is JSX-specific and not valid Vue. Vue uses :alt for dynamic bindings or plain alt for static strings. Is this intentional to test parser error handling?

crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/invalid.html (1)

6-6: Invalid HTML syntax in test fixture.

The syntax alt={"photo"} is JSX, not valid HTML. HTML attributes use alt="value" or alt='value'. Is this intentional to test parser robustness, or should it be corrected?

crates/biome_js_analyze/src/lint/a11y/no_redundant_alt.rs (1)

10-10: Nice refactoring to share code between HTML and JS analyzers! 🎯

Extracting is_redundant_alt into a shared utility ensures consistency and reduces duplication.

crates/biome_html_analyze/src/lint/a11y.rs (1)

11-11: Clean integration of the new rule into the A11y group.

The module declaration and lint group registration follow the existing pattern correctly.

Also applies to: 19-19

crates/biome_rule_options/src/shared/mod.rs (1)

6-13: LGTM!

Clean implementation of the shared redundant alt detection logic. Using to_ascii_lowercase_cow() is a nice touch to avoid unnecessary allocations when the text is already lowercase. Based on learnings, this follows the guideline to avoid string allocations by using &str.

crates/biome_rule_options/src/no_redundant_alt.rs (1)

4-7: LGTM!

The options struct follows the project conventions with proper serde attributes and required trait derivations. As per learnings, #[serde(rename_all = "camelCase", deny_unknown_fields)] is correctly applied.

crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/valid.vue (1)

1-15: LGTM!

Good coverage of edge cases for the Vue context. Line 14 with <Img> (capital I) correctly belongs in the valid file since Vue uses case-sensitive tag matching - Img is treated as a component, not the HTML img element.

crates/biome_html_analyze/tests/specs/a11y/noRedundantAlt/valid.html (1)

1-12: LGTM!

Solid test coverage for the HTML context. Good inclusion of case variations (ALt, IMG) to verify case-insensitive handling, and proper aria-hidden edge cases.

crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs (1)

49-121: LGTM!

The rule implementation is well-structured. The aria-hidden handling correctly distinguishes between the attribute being present (truthy unless explicitly "false") and absent. Good use of the shared is_redundant_alt helper for consistency with the JS linter.

@github-actions github-actions bot removed the A-Project Area: project label Jan 3, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs (1)

22-37: Documentation examples still use JSX syntax instead of HTML.

This issue was previously flagged: the examples contain JSX-specific syntax (aria-hidden={false}, <>...</>, and trailing semicolons) that isn't valid HTML. Please update to use proper HTML syntax as suggested in the earlier review.

🧹 Nitpick comments (2)
crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs (2)

59-64: Consider simplifying the tag name check for readability.

The logic is correct (case-insensitive for HTML, case-sensitive for Vue/JSX), but the compound condition with || and negations is a bit dense.

🔎 Optional refactor for clarity
-    let name = node.name().ok()?.value_token().ok()?;
-    if (file_source.is_html() && !name.text_trimmed().eq_ignore_ascii_case("img"))
-        || (!file_source.is_html() && name.text_trimmed() != "img")
-    {
-        return None;
-    }
+    let name_token = node.name().ok()?.value_token().ok()?;
+    let name = name_token.text_trimmed();
+    
+    let is_img_tag = if file_source.is_html() {
+        name.eq_ignore_ascii_case("img")
+    } else {
+        name == "img"
+    };
+    
+    if !is_img_tag {
+        return None;
+    }

66-86: Consider adding a comment to clarify aria-hidden handling.

The logic correctly handles all cases (boolean attribute, "true", "false"), but the early return via ? on line 68 is subtle. A brief comment would help future maintainers understand why boolean aria-hidden (without a value) skips the check.

🔎 Suggested comment
     let aria_hidden_attribute = node.find_attribute_by_name("aria-hidden");
     if let Some(aria_hidden) = aria_hidden_attribute {
+        // If aria-hidden has no value (boolean attribute), the ? below returns None,
+        // correctly skipping the check since the image is hidden.
         let is_false = match aria_hidden.initializer()?.value().ok()? {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f601418 and 167f4c6.

📒 Files selected for processing (1)
  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

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

Files:

  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
🧠 Learnings (14)
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `no` prefix when the rule's sole intention is to forbid a single concept

Applied to files:

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

Applied to files:

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

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `use` prefix when the rule's sole intention is to mandate a single concept

Applied to files:

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

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Code blocks in rule documentation must specify a language identifier and be tagged with `expect_diagnostic` for invalid examples or remain untagged for valid examples

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : When porting rules from other linters, use `sources` metadata with `RuleSource::Eslint().same()` for identical behavior or `.inspired()` for different behavior

Applied to files:

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

Applied to files:

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

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule documentation must include an `## Examples` section followed by `### Invalid` and `### Valid` subsections, with Invalid appearing first

Applied to files:

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

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: For new lint rules in changesets, show an example of invalid case in inline code or code block

Applied to files:

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

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
🧬 Code graph analysis (1)
crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs (2)
crates/biome_rule_options/src/shared/mod.rs (1)
  • is_redundant_alt (8-13)
crates/biome_html_syntax/src/element_ext.rs (3)
  • name (56-71)
  • name (223-225)
  • name (247-252)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Check Dependencies
  • GitHub Check: Documentation
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: End-to-end tests
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_analyze)
🔇 Additional comments (4)
crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs (4)

1-11: LGTM!

The imports are well-organised and correctly reference the shared is_redundant_alt validation logic from biome_rule_options.


39-46: LGTM!

Rule metadata follows Biome's conventions correctly: appropriate severity for accessibility, correct source attribution, and no fix_kind since the rule only diagnoses without providing automatic fixes.


88-104: LGTM!

The alt text extraction correctly handles both expression and string attribute formats, and the use of the shared is_redundant_alt validation ensures consistency with the JS rules.


107-120: LGTM!

The diagnostic message is clear and actionable, and the note provides helpful context about screen reader behaviour. Properly uses rule_category!() and markup! macros per Biome's conventions.

@codspeed-hq
Copy link

codspeed-hq bot commented Jan 3, 2026

CodSpeed Performance Report

Merging #8666 will not alter performance

Comparing feat/no-redudant-alt (0dc9450) with next (adcce82)1

Summary

✅ 58 untouched
⏩ 95 skipped2

Footnotes

  1. No successful run was found on next (b36ff03) during the generation of this report, so adcce82 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

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

Co-authored-by: chansuke <chansuke0@gmail.com>
@Netail Netail mentioned this pull request Jan 5, 2026
32 tasks
@ematipico ematipico merged commit 7733f90 into next Jan 5, 2026
22 of 24 checks passed
@ematipico ematipico deleted the feat/no-redudant-alt branch January 5, 2026 10:44
@github-actions github-actions bot mentioned this pull request Feb 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Linter Area: linter A-Parser Area: parser L-HTML Language: HTML and super languages L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants