Skip to content

chore: abstract html tag matcher#9988

Merged
Netail merged 4 commits intobiomejs:mainfrom
Netail:chore/rework-is-html-tag
Apr 15, 2026
Merged

chore: abstract html tag matcher#9988
Netail merged 4 commits intobiomejs:mainfrom
Netail:chore/rework-is-html-tag

Conversation

@Netail
Copy link
Copy Markdown
Member

@Netail Netail commented Apr 14, 2026

Summary

  • Abstracted checking for regular html tags
  • Used a smaller union query for certain rules (which affects diagnostic ranges; now only opening & self-closing instead the full open till close, which is better honestly)

Test Plan

Docs

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 14, 2026

🦋 Changeset detected

Latest commit: 6962357

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

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

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

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

@github-actions github-actions bot added A-Linter Area: linter A-Parser Area: parser L-HTML Language: HTML and super languages labels Apr 14, 2026
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Apr 14, 2026

Merging this PR will not alter performance

✅ 67 untouched benchmarks
⏩ 189 skipped benchmarks1


Comparing Netail:chore/rework-is-html-tag (6962357) with main (baaacfc)

Open in CodSpeed

Footnotes

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

@Netail Netail force-pushed the chore/rework-is-html-tag branch 6 times, most recently from 372c009 to d9e15d1 Compare April 14, 2026 23:28
@github-actions github-actions bot added the A-CLI Area: CLI label Apr 14, 2026
@Netail Netail force-pushed the chore/rework-is-html-tag branch from d9e15d1 to 76b0c80 Compare April 14, 2026 23:49
@Netail Netail marked this pull request as ready for review April 15, 2026 00:12
@Netail Netail changed the title chore: rework html tag matcher chore: abstract html tag matcher Apr 15, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3b1185f7-cc1a-4535-8153-77027b40e539

📥 Commits

Reviewing files that changed from the base of the PR and between a799ccf and 6962357.

📒 Files selected for processing (1)
  • .changeset/frogs-like-green.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/frogs-like-green.md

Walkthrough

This change centralises source-aware HTML tag matching and narrows element types across the analyzer. It adds utils::is_html_tag and AnyHtmlElement::as_any_html_tag_element, moves attribute-lookup helpers onto AnyHtmlTagElement, and updates many lints and a11y helpers to use AnyHtmlTagElement and the new is_html_tag for tag-name checks. Several helper signatures were tightened from &AnyHtmlElement&AnyHtmlTagElement.

Possibly related PRs

Suggested reviewers

  • dyc3
  • ematipico
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'chore: abstract html tag matcher' accurately reflects the main refactoring objective of consolidating HTML tag matching logic across multiple lint rules.
Description check ✅ Passed The description clearly relates to the changeset, outlining the core abstraction of HTML tag checking and the resulting diagnostic range improvements from narrower query types.

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

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

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

Copy link
Copy Markdown
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.

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

100-109: Consider reusing the cached source_type.

You've already derived source_type at line 83. Lines 100 and 109 call ctx.source_type::<HtmlFileSource>() again—consider using the local variable instead.

♻️ Proposed fix
-        if ctx.source_type::<HtmlFileSource>().is_vue() {
+        if source_type.is_vue() {
             let has_scoped = attributes.find_by_name("scoped").is_some();
             let has_module = attributes.find_by_name("module").is_some();

             if has_scoped || has_module {
                 return None;
             } else {
                 return Some(GlobalStylesKind::Vue);
             }
-        } else if ctx.source_type::<HtmlFileSource>().is_astro() {
+        } else if source_type.is_astro() {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_html_analyze/src/lint/nursery/use_scoped_styles.rs` around lines
100 - 109, The code calls ctx.source_type::<HtmlFileSource>() multiple times
inside use_scoped_styles.rs (e.g., in the branches that check .is_vue() and
.is_astro()); reuse the previously computed local variable (the cached
source_type you created earlier) instead of calling
ctx.source_type::<HtmlFileSource>() again — replace subsequent
ctx.source_type::<HtmlFileSource>().is_vue()/is_astro() checks with
source_type.is_vue()/source_type.is_astro() to avoid redundant lookups while
preserving the existing conditional logic that returns
Some(GlobalStylesKind::Vue) when no scoped/module attributes are present.
crates/biome_html_analyze/src/lint/nursery/no_script_url.rs (1)

62-73: Consider querying AnyHtmlTagElement directly.

The rule queries HtmlOpeningElement but then converts it to AnyHtmlTagElement for the tag check. This works correctly, though for consistency with other refactored rules in this PR, you could query Ast<AnyHtmlTagElement> directly and avoid the conversion on line 71.

That said, the current approach is functionally correct — self-closing <a/> tags are unusual in practice.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_html_analyze/src/lint/nursery/no_script_url.rs` around lines 62
- 73, Change the rule to query AnyHtmlTagElement directly instead of
HtmlOpeningElement: update the type alias Query from Ast<HtmlOpeningElement> to
Ast<AnyHtmlTagElement>, and in run(ctx: &RuleContext<Self>) use ctx.query() as
an AnyHtmlTagElement (removing the conversion
AnyHtmlTagElement::from(element.clone())). Keep the same source_type check and
is_html_tag call but pass the queried AnyHtmlTagElement directly to is_html_tag;
adjust any variable names/types in run accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_html_analyze/src/lint/nursery/no_script_url.rs`:
- Around line 62-73: Change the rule to query AnyHtmlTagElement directly instead
of HtmlOpeningElement: update the type alias Query from Ast<HtmlOpeningElement>
to Ast<AnyHtmlTagElement>, and in run(ctx: &RuleContext<Self>) use ctx.query()
as an AnyHtmlTagElement (removing the conversion
AnyHtmlTagElement::from(element.clone())). Keep the same source_type check and
is_html_tag call but pass the queried AnyHtmlTagElement directly to is_html_tag;
adjust any variable names/types in run accordingly.

In `@crates/biome_html_analyze/src/lint/nursery/use_scoped_styles.rs`:
- Around line 100-109: The code calls ctx.source_type::<HtmlFileSource>()
multiple times inside use_scoped_styles.rs (e.g., in the branches that check
.is_vue() and .is_astro()); reuse the previously computed local variable (the
cached source_type you created earlier) instead of calling
ctx.source_type::<HtmlFileSource>() again — replace subsequent
ctx.source_type::<HtmlFileSource>().is_vue()/is_astro() checks with
source_type.is_vue()/source_type.is_astro() to avoid redundant lookups while
preserving the existing conditional logic that returns
Some(GlobalStylesKind::Vue) when no scoped/module attributes are present.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a08b06ee-e62d-42f1-887b-fe5145208da6

📥 Commits

Reviewing files that changed from the base of the PR and between 79c09f2 and 76b0c80.

⛔ Files ignored due to path filters (16)
  • crates/biome_cli/tests/snapshots/main_cases_handle_astro_files/full_support.snap is excluded by !**/*.snap and included by **
  • crates/biome_cli/tests/snapshots/main_cases_handle_svelte_files/full_support.snap is excluded by !**/*.snap and included by **
  • crates/biome_cli/tests/snapshots/main_cases_handle_svelte_files/full_support_ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_cli/tests/snapshots/main_cases_handle_vue_files/full_support.snap is excluded by !**/*.snap and included by **
  • crates/biome_cli/tests/snapshots/main_cases_handle_vue_files/full_support_ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAltText/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useButtonType/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useButtonType/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useButtonType/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useHtmlLang/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useIframeTitle/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaRole/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/useIframeSandbox/invalid.html.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (29)
  • crates/biome_html_analyze/src/a11y.rs
  • crates/biome_html_analyze/src/a11y_tests.rs
  • crates/biome_html_analyze/src/lib.rs
  • crates/biome_html_analyze/src/lint/a11y/no_autofocus.rs
  • crates/biome_html_analyze/src/lint/a11y/no_distracting_elements.rs
  • crates/biome_html_analyze/src/lint/a11y/no_header_scope.rs
  • crates/biome_html_analyze/src/lint/a11y/no_positive_tabindex.rs
  • crates/biome_html_analyze/src/lint/a11y/no_redundant_alt.rs
  • crates/biome_html_analyze/src/lint/a11y/no_svg_without_title.rs
  • crates/biome_html_analyze/src/lint/a11y/use_alt_text.rs
  • crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
  • crates/biome_html_analyze/src/lint/a11y/use_aria_props_for_role.rs
  • crates/biome_html_analyze/src/lint/a11y/use_button_type.rs
  • crates/biome_html_analyze/src/lint/a11y/use_html_lang.rs
  • crates/biome_html_analyze/src/lint/a11y/use_iframe_title.rs
  • crates/biome_html_analyze/src/lint/a11y/use_media_caption.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_aria_role.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_analyze/src/lint/nursery/no_ambiguous_anchor_text.rs
  • crates/biome_html_analyze/src/lint/nursery/no_inline_styles.rs
  • crates/biome_html_analyze/src/lint/nursery/no_script_url.rs
  • crates/biome_html_analyze/src/lint/nursery/no_sync_scripts.rs
  • crates/biome_html_analyze/src/lint/nursery/use_iframe_sandbox.rs
  • crates/biome_html_analyze/src/lint/nursery/use_scoped_styles.rs
  • crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs
  • crates/biome_html_analyze/src/lint/nursery/use_vue_valid_template_root.rs
  • crates/biome_html_analyze/src/lint/nursery/use_vue_vapor.rs
  • crates/biome_html_analyze/src/utils.rs
  • crates/biome_html_syntax/src/element_ext.rs

Comment thread crates/biome_html_analyze/src/lint/nursery/use_scoped_styles.rs Outdated
Comment thread crates/biome_html_analyze/src/lint/nursery/use_scoped_styles.rs Outdated
Copy link
Copy Markdown
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

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

This change affected diagnostics, which are emitted to users. This means that it needs a changeset.

@Netail Netail merged commit eabf54a into biomejs:main Apr 15, 2026
29 of 30 checks passed
@Netail Netail deleted the chore/rework-is-html-tag branch April 15, 2026 09:09
@github-actions github-actions bot mentioned this pull request Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants