Skip to content

fix(lint): improve noSvgWithoutTitle so that it reports more invalid cases#8556

Merged
dyc3 merged 5 commits intobiomejs:nextfrom
mehm8128:improve-no-svg-without-title
Jan 16, 2026
Merged

fix(lint): improve noSvgWithoutTitle so that it reports more invalid cases#8556
dyc3 merged 5 commits intobiomejs:nextfrom
mehm8128:improve-no-svg-without-title

Conversation

@mehm8128
Copy link
Contributor

@mehm8128 mehm8128 commented Dec 22, 2025

Summary

close #8422

As I wrote in the issue, I improved noSvgWithoutTitle so that it reports more invalid cases.

  • Fixed the rule not to recursively traverse title elements.
  • Added support for graphics-document and graphics-symbol roles.
  • Added support for multiple role specifications.

Test Plan

Docs

@changeset-bot
Copy link

changeset-bot bot commented Dec 22, 2025

🦋 Changeset detected

Latest commit: 83469d1

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

@github-actions github-actions bot added A-Linter Area: linter L-JavaScript Language: JavaScript and super languages L-HTML Language: HTML and super languages labels Dec 22, 2025
@mehm8128 mehm8128 force-pushed the improve-no-svg-without-title branch from 07bdc50 to b6ba130 Compare December 22, 2025 13:57
@mehm8128 mehm8128 marked this pull request as ready for review December 22, 2025 13:57
@codspeed-hq
Copy link

codspeed-hq bot commented Dec 22, 2025

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing mehm8128:improve-no-svg-without-title (83469d1) with next (0f5a05b)

Summary

✅ 58 untouched benchmarks
⏩ 95 skipped benchmarks1

Footnotes

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 22, 2025

Walkthrough

This PR updates the noSvgWithoutTitle accessibility lints for HTML and JS/JSX analyzers to: restrict checks to SVGs with image-like ARIA roles (img, image, graphics-document, graphics-symbol) using ARIA role resolution; accept multiple whitespace-separated role tokens; and require a <title> to be the immediate first child (no recursive traversal). Tests and examples were added or adjusted to reflect the new role and title-position behaviour.

Possibly related PRs

Suggested reviewers

  • ematipico
  • dyc3
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: improving the noSvgWithoutTitle rule to report more invalid cases.
Description check ✅ Passed The description provides clear context, links the related issue, and outlines the three key improvements made to the rule.
Linked Issues check ✅ Passed The PR implementation aligns with all requirements from issue #8422: prevents recursive title traversal, adds graphics-document and graphics-symbol role support, and handles multiple role tokens.
Out of Scope Changes check ✅ Passed All changes directly support the three stated objectives. The new has_name_required_image_role method and role-based validation are in scope; test updates are minimal and focused.

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

✨ Finishing touches
  • 📝 Generate docstrings

📜 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 8de39db and 83469d1.

📒 Files selected for processing (3)
  • .changeset/hungry-jokes-crash.md
  • .changeset/solid-maps-relax.md
  • crates/biome_aria/src/roles.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/biome_aria/src/roles.rs
  • .changeset/solid-maps-relax.md
  • .changeset/hungry-jokes-crash.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). (10)
  • GitHub Check: Documentation
  • GitHub Check: Check Dependencies
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_js_formatter)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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

Caution

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

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

90-98: Incorrect valid example at line 97.

The example <svg role="graphics-symbol img"><rect /></svg> lacks both a title element and aria-label/aria-labelledby attributes. Since both "graphics-symbol" and "img" are in NAME_REQUIRED_ROLES, the rule logic (lines 176-189) would flag this as invalid.

Either move this to the Invalid section or add an accessible name attribute.

🔎 Verification of rule logic

The rule would process this example as:

  1. Line 150: has_valid_title_element returns Some(false) (first child is <rect>)
  2. Lines 176-178: has_name_required_role is true (contains "graphics-symbol" and "img")
  3. Lines 181-185: No aria-label or aria-labelledby found
  4. Line 189: Returns Some(()) → diagnostic emitted
🧹 Nitpick comments (1)
crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs (1)

156-159: Update outdated comment.

The comment refers only to role='img', but the code now handles multiple name-required roles.

🔎 Suggested rewording
-    // Checks if a `svg` element has role='img' and title/aria-label/aria-labelledby attribute
+    // Checks if a `svg` element has a name-required role and appropriate accessibility attributes
📜 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 73f4f53 and b6ba130.

⛔ Files ignored due to path filters (4)
  • crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/valid.jsx.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (7)
  • .changeset/hungry-jokes-crash.md
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/valid.html
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.jsx
  • crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/valid.jsx
🧰 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_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
🧠 Learnings (10)
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation must include `## Options` section if the rule has options

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Rule options must be placed inside the `biome_rule_options` crate

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.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_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Set rule severity to `error` for rules in correctness, security, and a11y groups

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Each rule option must have its own h3 header with description, default value, options block, and code example

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use language-specific rule names if the rule is meant for a specific language only

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : The first paragraph of rule documentation must be a single line describing what the rule does

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use generic rule names if the rule could potentially be implemented for multiple languages

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : Add `issue_number` field to `declare_lint_rule!` macro for work-in-progress rules

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : Set `recommended` field to `false` for new rules in the nursery group

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
🧬 Code graph analysis (1)
crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs (2)
crates/biome_js_analyze/src/lint/a11y/use_semantic_elements.rs (1)
  • role (111-116)
crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs (2)
  • is_valid_attribute_value (206-224)
  • has_valid_title_element (227-239)
⏰ 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: Documentation
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • 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: Check Dependencies
  • GitHub Check: End-to-end tests
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_analyze)
🔇 Additional comments (14)
.changeset/hungry-jokes-crash.md (1)

1-9: LGTM!

Changeset accurately captures the three behaviour changes. Minor bump is appropriate for these fixes.

crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs (2)

9-9: LGTM! Well-structured constant for role checking.

Centralising the roles that require accessible names makes the logic cleaner and easier to maintain.


163-186: Role handling logic looks solid.

The split on whitespace correctly supports multiple role specifications, and the short-circuit for empty roles is sensible. The flow ensures that SVGs with non-name-required roles (like presentation) don't trigger false positives.

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

18-25: LGTM!

Good coverage for the new graphics-symbol role support, including the multiple role (graphics-symbol img) scenario.

crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.html (2)

7-15: Good test case for non-recursive title search.

This correctly validates that a <title> nested within a <g> element should trigger the diagnostic, as only direct child titles are valid.


25-30: Solid coverage for role-based validation.

Both the standalone graphics-symbol and the combined presentation img cases correctly exercise the new role handling logic.

crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.jsx (2)

7-15: LGTM!

Mirrors the HTML test case — validates that nested titles within <g> elements should trigger diagnostics.


25-30: Good role-based test coverage.

The graphics-symbol and presentation img cases ensure the JSX implementation handles these scenarios consistently with the HTML linter.

crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/valid.jsx (2)

20-27: LGTM! Test coverage for new role support.

The added test cases correctly validate SVGs with graphics-symbol role (single and multiple) that include proper title elements, aligning with the PR's objective to support additional name-required roles.


37-42: LGTM! Formatting adjustment.

The indentation fix improves readability.

crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs (4)

9-9: LGTM! Centralised role definition.

The NAME_REQUIRED_ROLES constant provides a single source of truth for roles requiring accessible names, improving maintainability.


46-60: LGTM! Documentation examples align with non-recursive validation.

The invalid examples correctly demonstrate cases the updated rule should flag, including nested titles (lines 46-56) and graphics-symbol without title (lines 58-60).


170-192: LGTM! Multi-role support correctly implemented.

The refactored logic properly:

  • Handles whitespace-separated role tokens (line 177)
  • Validates if any role requires an accessible name (lines 176-178)
  • Enforces title or aria requirements only for name-required roles (lines 180-189)
  • Returns None (no diagnostic) for roles like "presentation" or "none"

The empty/whitespace role handling (lines 171-173) correctly treats missing semantic roles as requiring a title.


211-224: LGTM! Non-recursive title validation.

The simplified implementation correctly checks only the first child element for a non-empty <title>, aligning with the PR objective to prevent recursive traversal per SVG 1.1 backwards compatibility.

@@ -0,0 +1,9 @@
---
"@biomejs/biome": minor
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Even though its going against the next branch, this should be a patch because its a fix for the rule's original behavior.

Suggested change
"@biomejs/biome": minor
"@biomejs/biome": patch

Copy link
Member

Choose a reason for hiding this comment

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

I think there should be two changesets:

  • one for the fix
  • one for the new supported stuff

use biome_rule_options::no_svg_without_title::NoSvgWithoutTitleOptions;
use biome_string_case::StrLikeExtension;

const NAME_REQUIRED_ROLES: &[&str] = &["img", "graphics-document", "graphics-symbol"];
Copy link
Contributor

Choose a reason for hiding this comment

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

This const could go in the aria crate so its not duplicated across the crates. Ideally we would be able to deduplicate more of it.

Copy link
Contributor Author

@mehm8128 mehm8128 Dec 23, 2025

Choose a reason for hiding this comment

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

There is not struct Aria for now in the biome_html_analyzer crate to use biome_aria crate, so I left the TODO comment and only refactored biome_js_analyzer.

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 (4)
crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs (1)

9-9: Duplication with aria crate.

This constant duplicates the role list in has_name_required_image_role. Consider moving it to the aria crate to maintain a single source of truth.

.changeset/hungry-jokes-crash.md (1)

1-5: Changeset may need splitting.

Per prior feedback, consider two changesets:

  1. A patch for the fix (stopping recursive traversal)
  2. A minor for the new feature (graphics-document/graphics-symbol role support)

The current changeset only documents the recursive traversal fix but omits the new role support.

crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs (2)

203-215: The nth(1) assumption is fragile.

The comment says "first element" but the code uses nth(1), assuming whitespace always occupies index 0. If the JSX has no leading whitespace, the actual first child would be skipped.

Consider filtering to the first actual element rather than relying on positional indexing:

🔎 Proposed fix
 fn has_valid_title_element(jsx_child_list: &JsxChildList) -> Option<bool> {
-    let first_child = jsx_child_list.iter().nth(1)?;
+    let first_child = jsx_child_list
+        .iter()
+        .find(|child| child.as_jsx_element().is_some())?;
     let jsx_element = first_child.as_jsx_element()?;
     let opening_element = jsx_element.opening_element().ok()?;

154-154: Empty aria-label passes validation.

aria_label.is_some() accepts empty strings like aria-label="". While the valid example at lines 89-93 shows this as intentional, an empty label provides no accessible text. Consider whether this aligns with accessibility best practices.

🧹 Nitpick comments (3)
.changeset/solid-maps-relax.md (1)

5-8: Description could be slightly more complete.

The changeset captures the new role support and multiple role token handling, but omits the fix for recursive title traversal (which should now only check immediate children). Worth noting if this is user-facing, but the description is acceptable as-is if the fix is considered an implementation detail.

🔎 Proposed enhancement (optional)
 Added two new behaviors to the `noSvgWithoutTitle` rule.

 - Support for `graphics-document` and `graphics-symbol` roles.
 - Support for multiple role specifications.
+- Improved title detection to only check immediate child elements (not recursive).
crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs (2)

156-156: TODO left in code.

The TODO suggests using aria_roles.has_name_required_image_role from the aria crate. The JS analyzer already uses this method. Would you like help implementing this to maintain consistency between the HTML and JS analyzers?


212-224: Refactored title check looks correct; minor efficiency nit.

The logic correctly checks only the first child element for a valid <title>. However, line 223 uses .count() > 0 which iterates all children just to check non-emptiness.

🔎 Proposed fix
-    let has_child = html_element.children().into_iter().count() > 0;
+    let has_child = html_element.children().into_iter().next().is_some();
📜 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 b6ba130 and b4541c7.

⛔ Files ignored due to path filters (1)
  • crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.jsx.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (7)
  • .changeset/hungry-jokes-crash.md
  • .changeset/solid-maps-relax.md
  • crates/biome_aria/src/roles.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.html
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.html
🧰 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_svg_without_title.rs
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_aria/src/roles.rs
🧠 Learnings (29)
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Each rule option must have its own h3 header with description, default value, options block, and code example

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.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_svg_without_title.rs
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation must include `## Options` section if the rule has options

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Set rule severity to `error` for rules in correctness, security, and a11y groups

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use language-specific rule names if the rule is meant for a specific language only

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : The first paragraph of rule documentation must be a single line describing what the rule does

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : Add `issue_number` field to `declare_lint_rule!` macro for work-in-progress rules

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use generic rule names if the rule could potentially be implemented for multiple languages

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : Set `recommended` field to `false` for new rules in the nursery group

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Set `version` field to `next` in `declare_lint_rule!` macro

Applied to files:

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

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Store type data in linear vectors instead of using recursive data structures with `Arc` for improved data locality and performance

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Use `TypeReference` instead of `Arc` for types that reference other types to avoid stale cache issues when modules are replaced

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Rule options must be placed inside the `biome_rule_options` crate

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Assist rules should detect refactoring opportunities and emit code action signals

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `RuleSource::Eslint(...).inspired()` when implementing a rule inspired by but with different behavior than an ESLint rule

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules should perform static analysis of source code to detect invalid or error-prone patterns and emit diagnostics with proposed fixes

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Prefix line with `#` in documentation code examples sparingly; prefer concise complete snippets

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `declare_lint_rule!` macro to declare analyzer rule types and implement the RuleMeta trait

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules should check syntax according to language specification and emit error diagnostics

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `domains` field in `declare_lint_rule!` to tag rules that belong to specific concepts like testing or frameworks

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation code blocks should be ordered as language, expect_diagnostic, options/full_options/use_options, ignore, file

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Each invalid code example in rule documentation must emit exactly one diagnostic

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Commit rule work with message format `feat(biome_<language>_analyze): <ruleName>`

Applied to files:

  • .changeset/solid-maps-relax.md
📚 Learning: 2025-12-21T21:15:03.782Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.782Z
Learning: For promoting rules from nursery or implementing new features affecting end users, send PRs to the `next` branch

Applied to files:

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

Applied to files:

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

Applied to files:

  • .changeset/hungry-jokes-crash.md
📚 Learning: 2025-12-21T21:15:03.782Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.782Z
Learning: For rule changes in changesets, clearly demonstrate what is now invalid that wasn't before, or vice versa

Applied to files:

  • .changeset/hungry-jokes-crash.md
📚 Learning: 2025-12-21T21:15:03.782Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.782Z
Learning: In changesets, start with a link to the issue when fixing a bug (e.g., 'Fixed [#4444](link): ...')

Applied to files:

  • .changeset/hungry-jokes-crash.md
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs (1)
crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs (3)
  • run (131-194)
  • is_valid_attribute_value (228-244)
  • has_valid_title_element (213-225)
⏰ 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: Test (depot-windows-2022-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Check Dependencies
  • GitHub Check: Documentation
  • GitHub Check: End-to-end tests
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: autofix
🔇 Additional comments (4)
crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.jsx (1)

7-30: Good test coverage for new scenarios.

The new test cases properly cover:

  • Nested <title> inside <g> (should fail as it's not a direct child)
  • graphics-symbol role without accessible name
  • Multiple roles including a name-required role (img presentation)
crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs (2)

116-117: Nice refactor to use the Aria service.

Switching to Aria<AnyJsxElement> and leveraging ctx.aria_roles() is cleaner than manually parsing role attributes. Good alignment with the aria crate's new method.


148-163: Logic is sound but implicit role handling differs from HTML version.

The JS version uses aria_roles.has_name_required_image_role(node) which considers the implicit role (GraphicsDocument for <svg>). This means an <svg> without an explicit role will require a title.

The HTML version at line 158 returns Some(()) when no role attribute is present, which has the same effect. Just confirming this is the intended behaviour—SVGs without roles are now flagged.

crates/biome_aria/src/roles.rs (1)

287-304: Implementation is correct; no issues found.

The method cleanly handles image-related roles per ARIA specification. The first valid role token determines the element's semantic role, so checking only the single returned role is correct.

@mehm8128 mehm8128 force-pushed the improve-no-svg-without-title branch from b4541c7 to 8de39db Compare December 23, 2025 04:34
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

Caution

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

⚠️ Outside diff range comments (1)
crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs (1)

32-34: Duplicate example in documentation.

This example (<svg>foo</svg>) is identical to lines 22-23. Consider removing the duplicate or replacing with a distinct invalid case.

♻️ Duplicate comments (2)
crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs (2)

89-93: Empty aria-label treated as valid.

As previously noted, aria-label="" doesn't provide accessible text, yet this is shown as a valid example. The check at line 154 only verifies presence (aria_label.is_some()), not content.


203-215: Comment vs code mismatch: "first element" but using nth(1).

The doc comment says "first element" but the code uses nth(1), which skips index 0. This assumes whitespace always occupies position 0. Either update the comment to clarify the whitespace-skipping behaviour or refactor to explicitly filter non-element nodes.

🧹 Nitpick comments (1)
crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs (1)

223-223: Minor efficiency improvement.

.count() > 0 iterates all children. Consider .next().is_some() for a short-circuit check.

🔎 Proposed fix
-    let has_child = html_element.children().into_iter().count() > 0;
+    let has_child = html_element.children().into_iter().next().is_some();
📜 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 b4541c7 and 8de39db.

⛔ Files ignored due to path filters (2)
  • crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.jsx.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (7)
  • .changeset/hungry-jokes-crash.md
  • .changeset/solid-maps-relax.md
  • crates/biome_aria/src/roles.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.html
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.jsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • .changeset/solid-maps-relax.md
  • .changeset/hungry-jokes-crash.md
  • crates/biome_html_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.html
🧰 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_aria/src/roles.rs
  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
🧠 Learnings (28)
📚 Learning: 2025-11-24T18:04:47.058Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_aria_metadata/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:47.058Z
Learning: Applies to crates/biome_aria_metadata/**/build.rs : The `build.rs` script uses `aria-data.json` to generate ARIA metadata

Applied to files:

  • crates/biome_aria/src/roles.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Assist rules should detect refactoring opportunities and emit code action signals

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Set rule severity to `error` for rules in correctness, security, and a11y groups

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.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_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `RuleSource::Eslint(...).inspired()` when implementing a rule inspired by but with different behavior than an ESLint rule

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules should perform static analysis of source code to detect invalid or error-prone patterns and emit diagnostics with proposed fixes

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Prefix line with `#` in documentation code examples sparingly; prefer concise complete snippets

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : The first paragraph of rule documentation must be a single line describing what the rule does

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `declare_lint_rule!` macro to declare analyzer rule types and implement the RuleMeta trait

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules should check syntax according to language specification and emit error diagnostics

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Each rule option must have its own h3 header with description, default value, options block, and code example

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : Add `issue_number` field to `declare_lint_rule!` macro for work-in-progress rules

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `domains` field in `declare_lint_rule!` to tag rules that belong to specific concepts like testing or frameworks

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation code blocks should be ordered as language, expect_diagnostic, options/full_options/use_options, ignore, file

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Each invalid code example in rule documentation must emit exactly one diagnostic

Applied to files:

  • crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation must include `## Options` section if the rule has options

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use language-specific rule names if the rule is meant for a specific language only

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation must include `## Examples` section with `### Invalid` and `### Valid` subsections

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use generic rule names if the rule could potentially be implemented for multiple languages

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : Set `recommended` field to `false` for new rules in the nursery group

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Store type data in linear vectors instead of using recursive data structures with `Arc` for improved data locality and performance

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Use `TypeReference` instead of `Arc` for types that reference other types to avoid stale cache issues when modules are replaced

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-11-24T18:04:47.058Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_aria_metadata/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:47.058Z
Learning: Applies to crates/biome_aria_metadata/**/aria-data.json : `aria-data.json` must be a symlink to `packages/aria-data/aria-data-<version>.json`

Applied to files:

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

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-11-24T18:04:47.058Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_aria_metadata/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:47.058Z
Learning: Refer to the documentation of `packages/aria-data` to generate the ARIA metadata file

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Lines prefixed with `#` in rule documentation code examples will be hidden from output

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `full_options` code block property for complete biome.json configuration snippets in documentation

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
📚 Learning: 2025-12-19T12:53:30.399Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.399Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Rule options must be placed inside the `biome_rule_options` crate

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
🧬 Code graph analysis (1)
crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs (2)
crates/biome_js_analyze/src/lint/a11y/use_semantic_elements.rs (1)
  • role (111-116)
crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs (3)
  • node (140-140)
  • is_valid_attribute_value (183-201)
  • has_valid_title_element (204-216)
⏰ 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: Documentation
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Check Dependencies
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: autofix
🔇 Additional comments (6)
crates/biome_aria/src/roles.rs (1)

287-304: LGTM!

Clean implementation that correctly identifies image-related roles requiring accessible names. The use of get_role_by_element_name ensures both explicit and implicit roles are handled consistently.

crates/biome_js_analyze/tests/specs/a11y/noSvgWithoutTitle/invalid.jsx (1)

7-30: Good test coverage for the new behaviours.

These test cases nicely cover:

  • Nested <title> inside <g> (lines 7-15) — correctly flagged per SVG 1.1 spec
  • graphics-symbol role without accessible name (lines 25-27)
  • Multiple role tokens where the first requires a name (lines 28-30)
crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs (2)

171-193: Solid role-based validation logic.

The split_whitespace approach correctly handles multiple role tokens (e.g., "graphics-symbol img"), and the conditional check for aria-label/aria-labelledby only when a name-required role is present aligns with the PR objectives.


212-222: First-child title check aligns with SVG 1.1 spec.

Good refactor — only checking the immediate first child prevents false negatives from deeply nested <title> elements.

crates/biome_js_analyze/src/lint/a11y/no_svg_without_title.rs (2)

116-124: Nice integration with the ARIA service.

Switching to Aria<AnyJsxElement> and using ctx.aria_roles() keeps the logic consistent with the new has_name_required_image_role helper. Clean approach.


148-163: Role-based gating looks correct.

Using aria_roles.has_name_required_image_role(node) centralises the role check, avoiding duplication of the role list. The subsequent validation of aria-label/aria-labelledby only triggers when needed.

@mehm8128 mehm8128 requested a review from dyc3 December 23, 2025 07:14
@mehm8128 mehm8128 force-pushed the improve-no-svg-without-title branch from 8de39db to 83469d1 Compare January 9, 2026 15:26
@dyc3 dyc3 merged commit 47a79f1 into biomejs:next Jan 16, 2026
17 checks passed
@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 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.

3 participants