Skip to content

feat(html/analyze): add useValidLang#8690

Merged
ematipico merged 4 commits intonextfrom
feat/use-valid-lang
Jan 6, 2026
Merged

feat(html/analyze): add useValidLang#8690
ematipico merged 4 commits intonextfrom
feat/use-valid-lang

Conversation

@ematipico
Copy link
Member

Summary

Closes #8229

Test Plan

Added new tests

Docs

Copied the docs from the JSX rule

@changeset-bot
Copy link

changeset-bot bot commented Jan 5, 2026

🦋 Changeset detected

Latest commit: dc17f81

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 5, 2026 09:41
@github-actions github-actions bot added A-Linter Area: linter A-Parser Area: parser L-HTML Language: HTML and super languages labels Jan 5, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

Walkthrough

Adds a new HTML accessibility lint rule UseValidLang (and public state type UseValidLangState) that validates lang attribute subtags (language, script, region) and emits targeted diagnostics with contextual footers. Registers the rule in the A11y lint group. Adds tests (valid/invalid) for multiple lang variants. Also exposes two new modules (attribute_ext, static_value), introduces StaticValue and an as_static_value conversion on attribute initializers, and adds a factory helper token(kind).

Possibly related PRs

Suggested reviewers

  • dyc3
  • arendjr

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main change: adding the useValidLang rule to HTML analysis as a new feature.
Description check ✅ Passed The description relates to the changeset, referencing issue #8229 and confirming test coverage and documentation work.
Linked Issues check ✅ Passed The PR successfully implements the useValidLang rule for HTML analysis, mirroring the JSX variant with proper validation, tests, and documentation [#8229].
Out of Scope Changes check ✅ Passed All changes are narrowly scoped to implementing the useValidLang HTML rule; supporting factory and syntax modules are appropriately extended.
✨ Finishing touches
  • 📝 Generate docstrings

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: 3

Fix all issues with AI Agents 🤖
In @crates/biome_html_factory/src/make.rs:
- Around line 19-26: The function token currently panics when kind.to_string()
returns None; change its signature from pub fn token(kind: HtmlSyntaxKind) ->
HtmlSyntaxToken to return Option<HtmlSyntaxToken> and return
Some(HtmlSyntaxToken::new_detached(...)) when to_string() yields text, otherwise
return None so callers can handle unsupported kinds; update all call sites of
token to handle the Option (propagate with ? or match) and add brief rustdoc on
token explaining it returns None for kinds that cannot be converted to text.

In @crates/biome_html_syntax/src/static_value.rs:
- Line 71: Fix the typo in the doc comment for the static value range: change
"Return teh range of the static value." to "Return the range of the static
value." in the documentation comment above the relevant item in static_value.rs
(the doc for the function/struct that returns the static value range).
- Around line 59-66: The code in Self::String uses raw indexing
(&text[1..text.len() - 1]) which assumes length ≥ 2; change it to mirror
inner_string_text() by constructing a TextRange (e.g. TextRange::new(1.into(),
text.len() - TextSize::from(1))) and use that TextRange to slice the token text
instead of raw numeric indexing; update the branch handling
HtmlSyntaxKind::HTML_STRING_LITERAL to return the TextRange-based slice of
token.text_trimmed(), keeping the behavior but making bounds explicit and
consistent with inner_string_text().
🧹 Nitpick comments (3)
.changeset/eight-bars-unite.md (1)

5-5: Optional: Simplify phrasing.

Consider "to HTML" or "for HTML" instead of "to the HTML language" for brevity.

🔎 Suggested simplification
-Added the rule [`useValidLang`](https://biomejs.dev/linter/rules/use-valid-lang) to the HTML language.
+Added the rule [`useValidLang`](https://biomejs.dev/linter/rules/use-valid-lang) for HTML.
crates/biome_html_syntax/src/static_value.rs (1)

5-7: Docstring mentions JavaScript but this is HTML syntax.

The comment says "static values defined in JavaScript's expressions" which is a bit confusing for an HTML syntax crate. Consider updating to reflect HTML context.

Suggested fix
 #[derive(Debug, Clone, Eq, PartialEq)]
-/// static values defined in JavaScript's expressions
+/// Static values that can be extracted from HTML attributes.
 pub enum StaticValue {
crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs (1)

110-133: Length-based heuristic for script vs country is reasonable but worth documenting.

Using character length (4 = script, 2-3 = country) to distinguish ambiguous second segments is pragmatic and aligns with BCP 47 conventions. A brief inline comment explaining this would help future maintainers.

Suggested comment
                     } else if !is_valid_script(script_or_country)
                         && !is_valid_country(script_or_country)
                     {
+                        // BCP 47: script tags are 4 chars, country/region codes are 2-3 chars
                         match script_or_country.len() {
📜 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 adcce82 and 1abc345.

⛔ Files ignored due to path filters (5)
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_syntax/src/generated/nodes.rs is excluded by !**/generated/**, !**/generated/** and included by **
📒 Files selected for processing (10)
  • .changeset/eight-bars-unite.md
  • crates/biome_html_analyze/src/lint/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
  • crates/biome_html_factory/src/make.rs
  • crates/biome_html_syntax/src/lib.rs
  • crates/biome_html_syntax/src/static_value.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_factory/src/make.rs
  • crates/biome_html_analyze/src/lint/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_syntax/src/static_value.rs
  • crates/biome_html_syntax/src/lib.rs
🧠 Learnings (39)
📚 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/useValidLang/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
📚 Learning: 2025-10-03T12:28:56.788Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7670
File: crates/biome_service/src/file_handlers/html.rs:744-748
Timestamp: 2025-10-03T12:28:56.788Z
Learning: In Biome's codebase, when creating tokens with new text content, use the factory pattern with functions like `ident(text)` from the respective `*_factory` crates (e.g., `biome_html_factory::make::ident`). There is no `.with_text()` method on tokens. The `ident()` function creates a new detached token with the IDENT kind, which is the standard approach for token construction.

Applied to files:

  • crates/biome_html_factory/src/make.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 : When formatting AST nodes, use mandatory tokens from the AST instead of hardcoding token strings (e.g., use `node.l_paren_token().format()` instead of `token("(")`)

Applied to files:

  • crates/biome_html_factory/src/make.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 : For tokens that are not mandatory, use helper functions instead of hardcoding

Applied to files:

  • crates/biome_html_factory/src/make.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/language_kind.rs : Add a new variant to `LanguageKind` enum in `language_kind.rs` file and implement all methods for the new language variant

Applied to files:

  • crates/biome_html_factory/src/make.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Implement a token source struct that wraps the lexer and implements `TokenSourceWithBufferedLexer` and `LexerWithCheckpoint` for lookahead and re-lexing capabilities

Applied to files:

  • crates/biome_html_factory/src/make.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/language_kind.rs : Add a new language prefix to the `LANGUAGE_PREFIXES` constant in `language_kind.rs` file

Applied to files:

  • crates/biome_html_factory/src/make.rs
  • crates/biome_html_syntax/src/lib.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/*_kinds_src.rs : Create a file called `src/{language}_kinds_src.rs` that returns a static `KindSrc` for new language parsers

Applied to files:

  • crates/biome_html_factory/src/make.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_html_factory/src/make.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_factory/src/make.rs
📚 Learning: 2025-12-22T09:27:13.161Z
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:27:13.161Z
Learning: In crates/biome_analyze/**/*analyze/src/**/*.rs, the `fix_kind` field in `declare_lint_rule!` should only be specified when the rule implements the `action` function. Rules that only emit diagnostics without providing code fixes should not include `fix_kind` in their metadata.

Applied to files:

  • crates/biome_html_factory/src/make.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.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • .changeset/eight-bars-unite.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/**/*_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.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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 : 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 : 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.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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 the `Semantic<T>` query type to access semantic information about bindings, references, and scope within a rule

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 : 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.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
  • .changeset/eight-bars-unite.md
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/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 : 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.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.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_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_html_analyze/src/lint/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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/use_valid_lang.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.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 : Invalid code snippets in rule documentation must emit exactly one diagnostic

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.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 : 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/use_valid_lang.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 `diagnostic` function to provide error messages explaining what the error is, why it is triggered, and what the user should do

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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 `run` function to return `Option<Self::State>` or `Vec<Self::State>` (as `Box<[Self::State]>`) depending on whether the rule reports one or multiple signals

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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/tests/language.rs : Implement `TestFormatLanguage` trait in `tests/language.rs` for the formatter's test language

Applied to files:

  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
📚 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/useValidLang/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
📚 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/tests/spec_tests.rs : Use the `tests_macros::gen_tests!` macro in `spec_tests.rs` to generate test functions for each specification file matching the pattern `tests/specs/<language>/**/*.<ext>`

Applied to files:

  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
📚 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/eight-bars-unite.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: Biome linter rules must be designed to work across languages, requiring careful naming to indicate intended scope

Applied to files:

  • .changeset/eight-bars-unite.md
📚 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_syntax/src/lib.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 : No module may copy or clone data from another module in the module graph, not even behind an `Arc`

Applied to files:

  • crates/biome_html_syntax/src/lib.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Create two new crates `biome_{language}_syntax` and `biome_{language}_factory` using `cargo new --lib` for new language parsers

Applied to files:

  • crates/biome_html_syntax/src/lib.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/context.rs : Define `<Language>FormatContext` struct in a `context.rs` file containing `comments` and `source_map` fields, implementing `FormatContext` and `CstFormatContext` traits

Applied to files:

  • crates/biome_html_syntax/src/lib.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_syntax/src/lib.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/**/tests/specs/**/*.jsonc : Use `.jsonc` format for test files containing multiple code snippets, where each snippet is a string in an array

Applied to files:

  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
🧬 Code graph analysis (3)
crates/biome_html_factory/src/make.rs (2)
crates/biome_html_syntax/src/static_value.rs (1)
  • text (52-69)
crates/biome_rowan/src/syntax/node.rs (1)
  • new_detached (33-47)
crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs (1)
crates/biome_analyze/src/rule.rs (3)
  • sources (641-644)
  • same (252-257)
  • recommended (626-629)
crates/biome_html_syntax/src/static_value.rs (2)
crates/biome_service/src/workspace_types.rs (1)
  • Self (748-748)
crates/biome_html_factory/src/make.rs (1)
  • token (20-26)
🪛 LanguageTool
.changeset/eight-bars-unite.md

[style] ~5-~5: This phrase is redundant (‘L’ stands for ‘language’). Use simply “HTML”.
Context: ...ejs.dev/linter/rules/use-valid-lang) to the HTML language.

(ACRONYM_TAUTOLOGY)

⏰ 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). (6)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Documentation
  • GitHub Check: Check Dependencies
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: autofix
🔇 Additional comments (12)
crates/biome_html_syntax/src/lib.rs (1)

9-9: LGTM!

Module export follows the established pattern and correctly exposes the new static value functionality.

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

1-7: LGTM!

The valid test cases properly cover various BCP 47 language tag formats: language-only, language-region, and language-script-region combinations.

crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue (1)

1-7: All test cases are correctly invalid per BCP 47 (RFC 5646). Each fails validation against the IANA Language Subtag Registry:

  • "lorem": primary language not registered
  • "en-babab": variant "babab" not registered
  • "en-GB-something": variant "something" invalid
  • "zh-Xxxx": script "Xxxx" not registered (only "Zzzz" is valid for unknown scripts)
  • "zh-Hans-ZZ": region "ZZ" is reserved/user-assigned in ISO 3166-1, not in IANA BCP 47 registry
  • "en-US-GB-Extra": multiple regions invalid, "Extra" not registered

Test cases are sound.

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

1-7: Good test coverage for invalid lang attributes.

The test cases cover the key invalid scenarios: invalid language code, invalid country/script segments, and overly complex tags. Nicely aligned with the rule's validation branches.

crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue (2)

2-2: Clever case-sensitivity test.

This verifies that Vue mode uses case-sensitive tag matching (Htmlhtml), so the invalid "lorem" value doesn't trigger a diagnostic. Worth a brief inline comment if future maintainers wonder why this is in valid.vue.


3-8: Valid lang values look correct.

All these are legitimate BCP 47 language tags. The trailing semicolons are a bit quirky but harmless for test purposes.

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

18-19: LGTM!

The new rule is correctly wired into the A11y lint group, following the established alphabetical ordering.

crates/biome_html_syntax/src/static_value.rs (1)

19-39: Doctests look well-structured.

Good use of dbg!()-style assertions in the doctests. As per coding guidelines, these doc tests help ensure the API works as documented.

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

11-43: Rule declaration follows guidelines.

Version is next, uses use prefix for mandating valid lang, no fix_kind since there's no auto-fix, and sources correctly reference the ESLint JSX A11y origin. Well done!


63-71: Case-sensitivity logic is well-handled.

HTML mode uses case-insensitive matching (eq_ignore_ascii_case) whilst Vue/other modes use exact matching. This correctly reflects that <HTML> and <html> are equivalent in HTML but not in component frameworks.


151-193: Diagnostic implementation is solid.

Clear error message with helpful footer listing valid options (capped at 15). The Markup! macro usage follows guidelines.


180-189: The scripts() function is present in biome_aria_metadata at crates/biome_aria_metadata/src/lib.rs:68. No action needed.

@ematipico ematipico force-pushed the feat/use-valid-lang branch from 1abc345 to 9558785 Compare January 5, 2026 10:01
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: 1

Fix all issues with AI Agents 🤖
In @.changeset/eight-bars-unite.md:
- Line 5: Replace the phrase "HTML language" with "HTML" in the changeset text
that currently reads "Added the rule
[`useValidLang`](https://biomejs.dev/linter/rules/use-valid-lang) to the HTML
language." so it reads "Added the rule
[`useValidLang`](https://biomejs.dev/linter/rules/use-valid-lang) to HTML.";
locate and update the sentence in .changeset/eight-bars-unite.md where that line
appears.
♻️ Duplicate comments (3)
crates/biome_html_factory/src/make.rs (1)

19-26: Previous review comment on panic behaviour still applies.

The concern about panicking when kind.to_string() returns None has already been raised in a previous review. Please address that feedback.

crates/biome_html_syntax/src/static_value.rs (2)

59-66: String delimiter handling already flagged in previous review.

The raw indexing approach has been noted in past comments. See the existing discussion about using TextRange for consistency with inner_string_text().


71-92: Typo in doc comment already noted.

The "teh" → "the" typo on line 71 was flagged in previous review. Implementation is correct.

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

110-132: Consider documenting the length heuristic.

The fallback logic uses length to infer whether an invalid subtag is a script (4 chars) or country (2-3 chars). Whilst this aligns with ISO standards, a brief comment explaining this heuristic would help future maintainers.

🔎 Suggested documentation
                 } else if !is_valid_script(script_or_country)
                     && !is_valid_country(script_or_country)
                 {
+                    // ISO 15924 script codes are 4 characters; ISO 3166 country codes are 2-3 characters
                     match script_or_country.len() {
crates/biome_html_syntax/src/static_value.rs (1)

1-17: Solid enum design with comprehensive variant coverage.

The structure mirrors the JS equivalent for API consistency. The EmptyString(TextRange) variant is a clever design choice for representing empty template strings without requiring a token.

Minor note: Line 6 mentions "JavaScript's expressions" in an HTML context, which might confuse readers unfamiliar with the codebase's cross-language patterns. Consider "static values from JavaScript-like expressions" if clarity is desired, but this is purely optional.

📜 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 1abc345 and 9558785.

⛔ Files ignored due to path filters (5)
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_syntax/src/generated/nodes.rs is excluded by !**/generated/**, !**/generated/** and included by **
📒 Files selected for processing (11)
  • .changeset/eight-bars-unite.md
  • crates/biome_html_analyze/src/lint/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
  • crates/biome_html_factory/src/make.rs
  • crates/biome_html_syntax/src/attribute_ext.rs
  • crates/biome_html_syntax/src/lib.rs
  • crates/biome_html_syntax/src/static_value.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
  • crates/biome_html_syntax/src/lib.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
🧰 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_syntax/src/attribute_ext.rs
  • crates/biome_html_syntax/src/static_value.rs
  • crates/biome_html_factory/src/make.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_analyze/src/lint/a11y.rs
🧠 Learnings (34)
📚 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 : Distinguish between `TypeData::Unknown` and `TypeData::UnknownKeyword` to measure inference effectiveness versus explicit user-provided unknown types

Applied to files:

  • crates/biome_html_syntax/src/static_value.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_html_syntax/src/static_value.rs
  • crates/biome_html_factory/src/make.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 : For tokens that are not mandatory, use helper functions instead of hardcoding

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
  • crates/biome_html_factory/src/make.rs
📚 Learning: 2025-10-03T12:28:56.788Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7670
File: crates/biome_service/src/file_handlers/html.rs:744-748
Timestamp: 2025-10-03T12:28:56.788Z
Learning: In Biome's codebase, when creating tokens with new text content, use the factory pattern with functions like `ident(text)` from the respective `*_factory` crates (e.g., `biome_html_factory::make::ident`). There is no `.with_text()` method on tokens. The `ident()` function creates a new detached token with the IDENT kind, which is the standard approach for token construction.

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
  • crates/biome_html_factory/src/make.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 : When formatting AST nodes, use mandatory tokens from the AST instead of hardcoding token strings (e.g., use `node.l_paren_token().format()` instead of `token("(")`)

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
  • crates/biome_html_factory/src/make.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_syntax/src/static_value.rs
  • crates/biome_html_factory/src/make.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Use `ConditionalParsedSyntax` for syntax that is only valid in specific contexts (e.g., strict mode, file types, language versions) and call `or_invalid_to_bogus()` to convert to a bogus node if not supported

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-12-19T11:31:06.239Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8509
File: crates/biome_html_parser/src/syntax/svelte.rs:465-467
Timestamp: 2025-12-19T11:31:06.239Z
Learning: In the Biome HTML parser, `parse_single_text_expression_content` does not advance the parser if the current token is empty. This is intentional to support cases where an expression is optional. When calling this function, callers must check if `p.cur_text().is_empty()` after the call and manually advance the parser with `p.bump_remap(HTML_LITERAL)` if needed.

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/*.ungram : Nodes for enclosing syntax errors must have the `Bogus` word, e.g., `HtmlBogusAttribute`, and must be part of a variant

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Implement a token source struct that wraps the lexer and implements `TokenSourceWithBufferedLexer` and `LexerWithCheckpoint` for lookahead and re-lexing capabilities

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
  • crates/biome_html_factory/src/make.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_syntax/src/static_value.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_analyze/src/lint/a11y.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/language_kind.rs : Add a new variant to `LanguageKind` enum in `language_kind.rs` file and implement all methods for the new language variant

Applied to files:

  • crates/biome_html_factory/src/make.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/language_kind.rs : Add a new language prefix to the `LANGUAGE_PREFIXES` constant in `language_kind.rs` file

Applied to files:

  • crates/biome_html_factory/src/make.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/*_kinds_src.rs : Create a file called `src/{language}_kinds_src.rs` that returns a static `KindSrc` for new language parsers

Applied to files:

  • crates/biome_html_factory/src/make.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Use `p.eat(token)` for optional tokens, `p.expect(token)` for required tokens, `parse_rule(p).ok(p)` for optional nodes, and `parse_rule(p).or_add_diagnostic(p, error)` for required nodes

Applied to files:

  • crates/biome_html_factory/src/make.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/use_valid_lang.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 : 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/use_valid_lang.rs
  • crates/biome_html_analyze/src/lint/a11y.rs
  • .changeset/eight-bars-unite.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/**/*_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/use_valid_lang.rs
  • crates/biome_html_analyze/src/lint/a11y.rs
  • .changeset/eight-bars-unite.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/**/*_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/use_valid_lang.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 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/use_valid_lang.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/use_valid_lang.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/use_valid_lang.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 : 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/use_valid_lang.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/use_valid_lang.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 `diagnostic` function to provide error messages explaining what the error is, why it is triggered, and what the user should do

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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 `run` function to return `Option<Self::State>` or `Vec<Self::State>` (as `Box<[Self::State]>`) depending on whether the rule reports one or multiple signals

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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/use_valid_lang.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 the `Semantic<T>` query type to access semantic information about bindings, references, and scope within a rule

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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 : 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 : 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.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.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_html_analyze/src/lint/a11y.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/eight-bars-unite.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: Biome linter rules must be designed to work across languages, requiring careful naming to indicate intended scope

Applied to files:

  • .changeset/eight-bars-unite.md
🧬 Code graph analysis (3)
crates/biome_html_syntax/src/static_value.rs (1)
crates/biome_html_factory/src/make.rs (1)
  • token (20-26)
crates/biome_html_factory/src/make.rs (2)
crates/biome_html_syntax/src/static_value.rs (1)
  • text (52-69)
crates/biome_rowan/src/syntax/node.rs (1)
  • new_detached (33-47)
crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs (2)
crates/biome_aria_metadata/src/lib.rs (5)
  • is_valid_country (43-45)
  • is_valid_language (48-50)
  • is_valid_script (53-55)
  • languages (63-65)
  • countries (58-60)
crates/biome_analyze/src/rule.rs (3)
  • sources (641-644)
  • same (252-257)
  • recommended (626-629)
🪛 LanguageTool
.changeset/eight-bars-unite.md

[style] ~5-~5: This phrase is redundant (‘L’ stands for ‘language’). Use simply “HTML”.
Context: ...ejs.dev/linter/rules/use-valid-lang) to the HTML language.

(ACRONYM_TAUTOLOGY)

⏰ 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). (8)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Documentation
  • GitHub Check: Check Dependencies
  • GitHub Check: autofix
🔇 Additional comments (9)
crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs (3)

11-43: Excellent rule declaration.

The metadata is properly configured with version: "next", correct source attribution, and comprehensive documentation with properly tagged examples. Well done.


63-102: Validation logic is sound.

The three-segment validation (language-script-country) correctly checks for extra segments first, then validates each component in order. The early returns keep the logic clean.


151-194: Helpful diagnostic messages.

The per-category footers listing valid values (limited to 15 entries) provide excellent user guidance without overwhelming the output.

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

18-19: Proper rule registration.

The new use_valid_lang module is correctly exposed and integrated into the A11y lint group.

crates/biome_html_syntax/src/attribute_ext.rs (1)

4-11: Clean attribute value extraction.

The as_static_value() method provides a sensible API for converting HTML string attributes to StaticValue, correctly returning None for dynamic expressions.

crates/biome_html_syntax/src/static_value.rs (4)

19-39: Correctly implements JavaScript falsy semantics.

The logic accurately handles all falsy cases, and the doctest demonstrates usage clearly.


94-114: Method logic correctly implements the documented behavior.

The naming is precise in context: it checks whether the value is a string constant that differs from the given text. Non-string types correctly return false.


116-137: Clean and idiomatic Option-based API.

The method provides a straightforward way to extract string constants, complementing is_not_string_constant() nicely.


139-143: Standard trait implementation enables ergonomic string access.

Delegating to text() is the correct approach here.

@ematipico ematipico changed the title feat(html/analyze) add useValidLang feat(html/analyze): add useValidLang Jan 5, 2026
Copy link
Contributor

@dyc3 dyc3 left a comment

Choose a reason for hiding this comment

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

LGTM

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

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

5-17: Documentation references JavaScript but this is HTML syntax.

The doc comment on line 6 states "static values defined in JavaScript's expressions", but this enum lives in the biome_html_syntax crate for HTML analysis. Consider updating the documentation to clarify its role in the HTML context (e.g., "static values extracted from HTML attribute expressions").

📜 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 9558785 and b287c36.

📒 Files selected for processing (1)
  • crates/biome_html_syntax/src/static_value.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_syntax/src/static_value.rs
🧠 Learnings (11)
📓 Common learnings
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
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
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
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
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
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:27:13.161Z
Learning: In crates/biome_analyze/**/*analyze/src/**/*.rs, the `fix_kind` field in `declare_lint_rule!` should only be specified when the rule implements the `action` function. Rules that only emit diagnostics without providing code fixes should not include `fix_kind` in their metadata.
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 the `Semantic<T>` query type to access semantic information about bindings, references, and scope within a rule
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
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
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
📚 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_html_syntax/src/static_value.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 : For tokens that are not mandatory, use helper functions instead of hardcoding

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-10-03T12:28:56.788Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7670
File: crates/biome_service/src/file_handlers/html.rs:744-748
Timestamp: 2025-10-03T12:28:56.788Z
Learning: In Biome's codebase, when creating tokens with new text content, use the factory pattern with functions like `ident(text)` from the respective `*_factory` crates (e.g., `biome_html_factory::make::ident`). There is no `.with_text()` method on tokens. The `ident()` function creates a new detached token with the IDENT kind, which is the standard approach for token construction.

Applied to files:

  • crates/biome_html_syntax/src/static_value.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 : When formatting AST nodes, use mandatory tokens from the AST instead of hardcoding token strings (e.g., use `node.l_paren_token().format()` instead of `token("(")`)

Applied to files:

  • crates/biome_html_syntax/src/static_value.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_syntax/src/static_value.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Use `ConditionalParsedSyntax` for syntax that is only valid in specific contexts (e.g., strict mode, file types, language versions) and call `or_invalid_to_bogus()` to convert to a bogus node if not supported

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-12-19T11:31:06.239Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8509
File: crates/biome_html_parser/src/syntax/svelte.rs:465-467
Timestamp: 2025-12-19T11:31:06.239Z
Learning: In the Biome HTML parser, `parse_single_text_expression_content` does not advance the parser if the current token is empty. This is intentional to support cases where an expression is optional. When calling this function, callers must check if `p.cur_text().is_empty()` after the call and manually advance the parser with `p.bump_remap(HTML_LITERAL)` if needed.

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/*.ungram : Nodes for enclosing syntax errors must have the `Bogus` word, e.g., `HtmlBogusAttribute`, and must be part of a variant

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Implement a token source struct that wraps the lexer and implements `TokenSourceWithBufferedLexer` and `LexerWithCheckpoint` for lookahead and re-lexing capabilities

Applied to files:

  • crates/biome_html_syntax/src/static_value.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_syntax/src/static_value.rs
🧬 Code graph analysis (1)
crates/biome_html_syntax/src/static_value.rs (1)
crates/biome_html_factory/src/make.rs (1)
  • token (20-26)
🔇 Additional comments (2)
crates/biome_html_syntax/src/static_value.rs (2)

94-143: LGTM!

The string constant methods and AsRef<str> implementation are well-documented with proper doctests and handle the string variants correctly.


71-71: Typo: "teh" → "the".

Suggested fix
-    /// Return teh range of the static value.
+    /// Return the range of the static value.

Likely an incorrect or invalid review comment.

@ematipico ematipico force-pushed the feat/use-valid-lang branch from b287c36 to 1bc2ecc Compare January 6, 2026 10:13
@ematipico ematipico force-pushed the feat/use-valid-lang branch from d6904e5 to 61ecf69 Compare January 6, 2026 16:40
@github-actions github-actions bot added A-Formatter Area: formatter L-JavaScript Language: JavaScript and super languages L-CSS Language: CSS L-JSON Language: JSON and super languages L-Grit Language: GritQL labels Jan 6, 2026
@ematipico ematipico force-pushed the feat/use-valid-lang branch from 61ecf69 to dc17f81 Compare January 6, 2026 16:42
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

🤖 Fix all issues with AI Agents
In @.changeset/eight-bars-unite.md:
- Line 5: In the changeset markdown file, the phrase "HTML language" is
redundant since the 'L' in HTML already stands for 'language'. Replace "HTML
language" with just "HTML" in the sentence describing the addition of the
useValidLang rule.

In @crates/biome_html_syntax/src/static_value.rs:
- Line 71: Fix the typo in the doc comment for the range accessor: change
"Return teh range of the static value." to "Return the range of the static
value." in the documentation comment for the StaticValue::range method (or the
range() function/impl in static_value.rs).
🧹 Nitpick comments (2)
crates/biome_html_syntax/src/static_value.rs (1)

5-7: Clarify the doc comment for the HTML context.

The comment mentions "JavaScript's expressions" but this enum lives in the HTML syntax crate. Consider rephrasing to reflect that these are static values found in HTML attributes (which may contain JavaScript-like literals in certain contexts).

📝 Suggested clarification
-/// static values defined in JavaScript's expressions
+/// Static values that can appear in HTML attributes
crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs (1)

63-150: LGTM!

The validation logic correctly handles all BCP 47 subtag patterns (language, language-script, language-country, language-script-country), appropriately distinguishes HTML vs Vue case sensitivity, and provides accurate error categorisation.

Optional: simplify the nested conditional at lines 106-113

Since line 111 returns early, the else if at line 112 can be simplified to if:

             (Some(language), Some(script_or_country), None) => {
                 if !is_valid_language(language) {
                     return Some(UseValidLangState {
                         attribute_range: attribute_value.range(),
                         invalid_kind: InvalidKind::Language,
                     });
-                } else if !is_valid_script(script_or_country)
+                }
+                if !is_valid_script(script_or_country)
                     && !is_valid_country(script_or_country)
                 {
📜 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 1bc2ecc and 61ecf69.

⛔ Files ignored due to path filters (9)
  • crates/biome_css_formatter/tests/specs/css/global_suppression.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_graphql_formatter/tests/specs/graphql/suppression.graphql.snap is excluded by !**/*.snap and included by **
  • crates/biome_grit_formatter/tests/specs/grit/global_suppression.grit.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_formatter/tests/specs/js/module/global_suppression.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_json_formatter/tests/specs/json/global_suppression.jsonc.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (11)
  • .changeset/eight-bars-unite.md
  • crates/biome_html_analyze/src/lint/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
  • crates/biome_html_factory/src/make.rs
  • crates/biome_html_syntax/src/attribute_ext.rs
  • crates/biome_html_syntax/src/lib.rs
  • crates/biome_html_syntax/src/static_value.rs
🚧 Files skipped from review as they are similar to previous changes (7)
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/invalid.vue
  • crates/biome_html_factory/src/make.rs
  • crates/biome_html_syntax/src/lib.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/valid.vue
  • crates/biome_html_analyze/src/lint/a11y.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidLang/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_syntax/src/attribute_ext.rs
  • crates/biome_html_syntax/src/static_value.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs
🧠 Learnings (26)
📚 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 : Distinguish between `TypeData::Unknown` and `TypeData::UnknownKeyword` to measure inference effectiveness versus explicit user-provided unknown types

Applied to files:

  • crates/biome_html_syntax/src/static_value.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_html_syntax/src/static_value.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/language_kind.rs : Add a new variant to `LanguageKind` enum in `language_kind.rs` file and implement all methods for the new language variant

Applied to files:

  • crates/biome_html_syntax/src/static_value.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 : For tokens that are not mandatory, use helper functions instead of hardcoding

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-10-03T12:28:56.788Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7670
File: crates/biome_service/src/file_handlers/html.rs:744-748
Timestamp: 2025-10-03T12:28:56.788Z
Learning: In Biome's codebase, when creating tokens with new text content, use the factory pattern with functions like `ident(text)` from the respective `*_factory` crates (e.g., `biome_html_factory::make::ident`). There is no `.with_text()` method on tokens. The `ident()` function creates a new detached token with the IDENT kind, which is the standard approach for token construction.

Applied to files:

  • crates/biome_html_syntax/src/static_value.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 : When formatting AST nodes, use mandatory tokens from the AST instead of hardcoding token strings (e.g., use `node.l_paren_token().format()` instead of `token("(")`)

Applied to files:

  • crates/biome_html_syntax/src/static_value.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_syntax/src/static_value.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Use `ConditionalParsedSyntax` for syntax that is only valid in specific contexts (e.g., strict mode, file types, language versions) and call `or_invalid_to_bogus()` to convert to a bogus node if not supported

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-12-19T11:31:06.239Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8509
File: crates/biome_html_parser/src/syntax/svelte.rs:465-467
Timestamp: 2025-12-19T11:31:06.239Z
Learning: In the Biome HTML parser, `parse_single_text_expression_content` does not advance the parser if the current token is empty. This is intentional to support cases where an expression is optional. When calling this function, callers must check if `p.cur_text().is_empty()` after the call and manually advance the parser with `p.bump_remap(HTML_LITERAL)` if needed.

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/*.ungram : Nodes for enclosing syntax errors must have the `Bogus` word, e.g., `HtmlBogusAttribute`, and must be part of a variant

Applied to files:

  • crates/biome_html_syntax/src/static_value.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Implement a token source struct that wraps the lexer and implements `TokenSourceWithBufferedLexer` and `LexerWithCheckpoint` for lookahead and re-lexing capabilities

Applied to files:

  • crates/biome_html_syntax/src/static_value.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_syntax/src/static_value.rs
  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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/use_valid_lang.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/use_valid_lang.rs
  • .changeset/eight-bars-unite.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/**/*_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/use_valid_lang.rs
  • .changeset/eight-bars-unite.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/**/*_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/use_valid_lang.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/use_valid_lang.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/use_valid_lang.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/use_valid_lang.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/use_valid_lang.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/use_valid_lang.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 `diagnostic` function to provide error messages explaining what the error is, why it is triggered, and what the user should do

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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 `run` function to return `Option<Self::State>` or `Vec<Self::State>` (as `Box<[Self::State]>`) depending on whether the rule reports one or multiple signals

Applied to files:

  • crates/biome_html_analyze/src/lint/a11y/use_valid_lang.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/use_valid_lang.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/eight-bars-unite.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: Biome linter rules must be designed to work across languages, requiring careful naming to indicate intended scope

Applied to files:

  • .changeset/eight-bars-unite.md
🪛 LanguageTool
.changeset/eight-bars-unite.md

[style] ~5-~5: This phrase is redundant (‘L’ stands for ‘language’). Use simply “HTML”.
Context: ...ejs.dev/linter/rules/use-valid-lang) to the HTML language.

(ACRONYM_TAUTOLOGY)

⏰ 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). (9)
  • GitHub Check: Validate rules documentation
  • GitHub Check: Documentation
  • GitHub Check: Check Dependencies
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: autofix
🔇 Additional comments (8)
crates/biome_html_syntax/src/static_value.rs (3)

19-39: LGTM!

The falsy logic correctly handles all variants, and the doctest provides clear usage.


94-136: LGTM!

Both methods correctly handle string constant checks and extraction, with clear doctests demonstrating usage.


139-143: LGTM!

Clean delegation to text() for the AsRef<str> trait.

crates/biome_html_syntax/src/attribute_ext.rs (2)

1-2: LGTM!

Imports are clean and necessary.


4-11: LGTM!

The conversion logic appropriately handles both variants, and the ok()? pattern gracefully handles cases where the value token isn't available.

crates/biome_html_analyze/src/lint/a11y/use_valid_lang.rs (3)

11-43: LGTM!

Rule declaration follows all conventions correctly: proper version, source attribution, documentation format with tagged code blocks, and appropriately omits fix_kind since no code fix is provided.


45-55: LGTM!

State structures are well-designed. The InvalidKind enum enables targeted diagnostics, and UseValidLangState appropriately captures the error context.


152-194: LGTM!

Diagnostic implementation is excellent: proper use of rule_category!() and markup! macros, helpful contextual footers with example values, and sensible list truncation for readability.

"@biomejs/biome": minor
---

Added the rule [`useValidLang`](https://biomejs.dev/linter/rules/use-valid-lang) to the HTML language.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Simplify "HTML language" to "HTML".

The phrase is redundant since the 'L' in HTML already stands for 'language'.

🔎 Proposed fix
-Added the rule [`useValidLang`](https://biomejs.dev/linter/rules/use-valid-lang) to the HTML language.
+Added the rule [`useValidLang`](https://biomejs.dev/linter/rules/use-valid-lang) to HTML.
📝 Committable suggestion

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

Suggested change
Added the rule [`useValidLang`](https://biomejs.dev/linter/rules/use-valid-lang) to the HTML language.
Added the rule [`useValidLang`](https://biomejs.dev/linter/rules/use-valid-lang) to HTML.
🧰 Tools
🪛 LanguageTool

[style] ~5-~5: This phrase is redundant (‘L’ stands for ‘language’). Use simply “HTML”.
Context: ...ejs.dev/linter/rules/use-valid-lang) to the HTML language.

(ACRONYM_TAUTOLOGY)

🤖 Prompt for AI Agents
In @.changeset/eight-bars-unite.md at line 5, In the changeset markdown file,
the phrase "HTML language" is redundant since the 'L' in HTML already stands for
'language'. Replace "HTML language" with just "HTML" in the sentence describing
the addition of the useValidLang rule.

}
}

/// Return teh range of the static value.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Typo: "teh" → "the".

Suggested fix
-    /// Return teh range of the static value.
+    /// Return the range of the static value.
📝 Committable suggestion

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

Suggested change
/// Return teh range of the static value.
/// Return the range of the static value.
🤖 Prompt for AI Agents
In @crates/biome_html_syntax/src/static_value.rs at line 71, Fix the typo in the
doc comment for the range accessor: change "Return teh range of the static
value." to "Return the range of the static value." in the documentation comment
for the StaticValue::range method (or the range() function/impl in
static_value.rs).

@ematipico ematipico merged commit e06e5d1 into next Jan 6, 2026
13 checks passed
@ematipico ematipico deleted the feat/use-valid-lang branch January 6, 2026 16:52
@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-Formatter Area: formatter A-Linter Area: linter A-Parser Area: parser L-CSS Language: CSS L-Grit Language: GritQL L-HTML Language: HTML and super languages L-JavaScript Language: JavaScript and super languages L-JSON Language: JSON and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants