Skip to content

Conversation

@dibashthapa
Copy link
Contributor

Summary

This PR migrates the no_unknown_property rule from Eslint React. This closes #7657

However, my code is not ready for a good PR yet 😅. For some reasons, I am unable to test with the options although i have them inside options.json file. This code doesn't take care of the react version to handle some edge cases.

This PR may conflict with existing no-unknown-property rule from css, and may redirect to same url.

Test Plan

The tests are included according to the spec. Valid cases are inside valid.jsx and invalid cases in invalid.jsx. For valid and invalid cases with options, I have added them in different folder. For ignore options, the code is inside ignore folder and for requireDataLowerCase, they are stored inside lowercase folder.

Docs

@changeset-bot
Copy link

changeset-bot bot commented Oct 16, 2025

🦋 Changeset detected

Latest commit: 30307bf

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-Project Area: project A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels Oct 16, 2025
@dibashthapa dibashthapa changed the title Feat/no unknown property feat(lint): implement no-unknown-property from eslint react Oct 16, 2025
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.

A good first draft :)

Also, this should implement the ignore option for the css rule.

@codspeed-hq
Copy link

codspeed-hq bot commented Oct 16, 2025

CodSpeed Performance Report

Merging #7774 will not alter performance

Comparing dibashthapa:feat/no-unknown-property (30307bf) with main (04f4973)1

Summary

✅ 53 untouched
⏩ 85 skipped2

Footnotes

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

  2. 85 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.

autofix-ci bot and others added 5 commits October 16, 2025 20:38
- Remove to_lowercase from most places
- Added react domain to the rule
- Removed regex and replaced with custom if checks
- Merged two constant arrays to avoid allocations
- remove TextRange from State, to use ctx.query()
- Used standard messages for diagnostics
@github-actions github-actions bot added the A-CLI Area: CLI label Oct 17, 2025
@dibashthapa dibashthapa marked this pull request as ready for review October 20, 2025 14:08
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 20, 2025

Walkthrough

Adds a new nursery lint rule NoUnknownAttribute (no-unknown-attribute) for JSX/DOM attribute validation, including public rule type, state enum, Rule impl, and configurable NoUnknownAttributeOptions (with ignore: Vec<String>). Adds tests and fixtures (valid, invalid, popover, ignore) plus test package manifests; exposes the rule options via crates/biome_rule_options::no_unknown_attribute. Introduces diagnostics for unknown props, standard-name suggestions, and invalid props on specific tags. References port of eslint-plugin-react's no-unknown-property and linked issue #7657.

Suggested reviewers

  • ematipico

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "feat(lint): implement no-unknown-property from eslint react" accurately describes the primary objective of implementing a new lint rule ported from ESLint React to validate unknown JSX attributes. While the internal implementation uses the name NoUnknownAttribute rather than the suggested NoUnknownProperty (to avoid conflicts with an existing CSS rule), the title correctly references the upstream rule name being migrated. The title is clear, concise, and appropriately conveys the main change without unnecessary details.
Linked Issues Check ✅ Passed The PR implements the core objective from issue #7657: a new lint rule to detect unknown JSX attributes, comprehensive test coverage (valid/invalid cases across multiple scenarios), and configuration options. However, there is a naming deviation: the implementation uses NoUnknownAttribute rather than the issue's suggested NoUnknownProperty, justified by the author to avoid conflicts with an existing CSS rule. The author acknowledges remaining work (React version-specific prop handling, docstring expansion) but the core porting objective is substantially met.
Out of Scope Changes Check ✅ Passed All code changes are directly aligned with implementing the new lint rule: the changeset entry documents the feature addition, the lint rule implementation provides the core validation logic, test fixtures validate both correct and incorrect attribute usage across various scenarios, configuration option structures enable rule customisation, and manifest fixtures support test infrastructure. No unrelated refactoring, dependency updates, or tangential changes are present.
Description Check ✅ Passed The PR description is directly related to the changeset, clearly explaining the migration of the no-unknown-property rule from ESLint React and referencing issue #7657. The author transparently discloses limitations (options not yet fully functional during testing, React version-specific handling incomplete, potential naming conflicts) and describes the test structure. While acknowledging incompleteness, the description provides sufficient context about what is being implemented and where work remains.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c3adfa and 30307bf.

📒 Files selected for processing (1)
  • .changeset/small-words-show.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

.changeset/*.md: In changeset files, only use #### or ##### headers
Changesets should describe user-facing changes; internal-only changes do not need changesets
Use past tense for what you did in the changeset description and present tense for current behavior
For bug fixes, start the changeset description with a link to the issue (e.g., Fixed #1234: ...)
When referencing a rule or assist in a changeset, include a link to the rule/assist page on the website
Include a code block in the changeset when applicable to illustrate the change
End every sentence in a changeset with a full stop (.)

Files:

  • .changeset/small-words-show.md
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : If a rule provides a code action, add fix_kind to declare_lint_rule! (FixKind::Safe or ::Unsafe)
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set the language field in declare_lint_rule! to the most appropriate dialect (js/jsx/ts/tsx)
📚 Learning: 2025-10-26T15:28:00.951Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-26T15:28:00.951Z
Learning: Applies to .changeset/*.md : Changesets should describe user-facing changes; internal-only changes do not need changesets

Applied to files:

  • .changeset/small-words-show.md
📚 Learning: 2025-08-05T14:43:29.581Z
Learnt from: dyc3
Repo: biomejs/biome PR: 7081
File: packages/@biomejs/biome/configuration_schema.json:7765-7781
Timestamp: 2025-08-05T14:43:29.581Z
Learning: The file `packages/biomejs/biome/configuration_schema.json` is auto-generated and should not be manually edited or reviewed for schema issues; any changes should be made at the code generation source.

Applied to files:

  • .changeset/small-words-show.md
📚 Learning: 2025-09-25T12:32:59.003Z
Learnt from: arendjr
Repo: biomejs/biome PR: 7593
File: crates/biome_service/src/workspace/server.rs:1306-1306
Timestamp: 2025-09-25T12:32:59.003Z
Learning: In the biomejs/biome project, do not flag compilation errors during code review as they are handled by the existing test infrastructure and CI. Focus on other code quality aspects instead.

Applied to files:

  • .changeset/small-words-show.md
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group

Applied to files:

  • .changeset/small-words-show.md
📚 Learning: 2025-10-26T15:28:00.951Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-26T15:28:00.951Z
Learning: Applies to .changeset/*.md : For bug fixes, start the changeset description with a link to the issue (e.g., Fixed #1234: ...)

Applied to files:

  • .changeset/small-words-show.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Test Node.js API
  • GitHub Check: Documentation
  • GitHub Check: End-to-end tests
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Check JS Files
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Check Dependencies
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: autofix

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

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
.changeset/small-words-show.md (1)

5-5: Tighten the changeset copy, add examples, and fix the link.

  • Use past tense, proper naming (“eslint‑plugin‑react”), and end sentences with a period.
  • Add tiny valid/invalid examples.
  • Point to the correct rule page; the current slug likely collides with the CSS rule page. Update once the docs page exists.

Apply this diff:

-Added the new rule [`no-unknown-property`](https://biomejs.dev/linter/rules/no-unknown-property/)  from eslint react
+#### Lint rules.
+
+Added the new nursery rule [`noUnknownProperty`](<update-with-correct-docs-url>) ported from `eslint-plugin-react`.
+
+Examples:
+
+```jsx
+/* valid */
+<App class="foo" /><div data-foo="bar" />
+```
+
+```jsx
+/* invalid */
+<div class="foo" /><div data-testID="bar" />
+```

As per coding guidelines.

🧹 Nitpick comments (10)
crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.jsx (1)

1-6: Nice focused “ignore” case.

Consider adding a sibling negative case (property not on the ignore list) to prove the rule still fires.

crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.jsx (1)

1-4: Confirm parity on custom components.

Do we intend requireDataLowercase to apply to custom components like <App />? ESLint’s rule often limits DOM‑prop checks to host elements. If we want parity, scope this to intrinsic elements; if we want stricter Biome behaviour, keep as is and document it.

crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.jsx (1)

1-204: Big omnibus “valid” test – consider splitting by theme.

Smaller themed fixtures (events, SVG, boolean attrs, data/aria, legacy attrs) make diffs and failures easier to triage. Also keep the React 19 popover block gated in a dedicated future test.

Quick sweep for potential tag‑specific mismatches (e.g. allowFullScreen on non‑iframe) would be good to double‑check against the rule’s allowed‑tags map.

crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/invalid.jsx (2)

21-38: Add popover/onBeforeToggle cases to lock React 19 support

Please add invalid/valid cases for popover API:

  • Attributes: popover, popovertarget, popovertargetaction.
  • Events: onBeforeToggle/onToggle on allowed tags.
    This prevents regressions and aligns with your commented code in the rule.

1-3: Consider a companion valid case for custom elements

Add a valid fixture using a custom element (e.g., ) to assert the rule skips custom elements and tags with an is attribute. This documents intent.

crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs (5)

1065-1077: Avoid avoidable allocations for attribute names

name/value_token().text_trimmed().to_string() and the manual namespace concatenation allocate on every attribute. Use TokenText and Cow to allocate only for namespaced cases.

@@
-        let node_name = match node.name().ok()? {
-            AnyJsxAttributeName::JsxName(name) => {
-                name.value_token().ok()?.text_trimmed().to_string()
-            }
-            AnyJsxAttributeName::JsxNamespaceName(name) => {
-                let namespace = name.namespace().ok()?.value_token().ok()?;
-                let name = &name.name().ok()?.value_token().ok()?;
-                // There could be better way, but i couldn't extract namespaced attributes
-                // For e.g xlink:href
-                // without manually concatenating with ':'
-                namespace.text_trimmed().to_string() + ":" + name.text_trimmed()
-            }
-        };
+        use std::borrow::Cow;
+        let node_name: Cow<'_, str> = match node.name().ok()? {
+            AnyJsxAttributeName::JsxName(name) => {
+                Cow::Borrowed(name.value_token().ok()?.text_trimmed())
+            }
+            AnyJsxAttributeName::JsxNamespaceName(name) => {
+                let ns = name.namespace().ok()?.value_token().ok()?.text_trimmed();
+                let local = name.name().ok()?.value_token().ok()?.text_trimmed();
+                Cow::Owned(format!("{ns}:{local}"))
+            }
+        };
@@
-        if options.ignore.contains(&node_name) {
+        if options.ignore.iter().any(|s| s == &*node_name) {
             return None;
         }
@@
-        let name = normalize_attribute_case(&node_name);
+        let name = normalize_attribute_case(&node_name);

Also applies to: 1079-1081


1009-1014: Simplify tag_name_has_dot signature

This always returns Some(..). Make it return bool and drop ? at call sites; avoids needless Option churn.

-fn tag_name_has_dot(node: &AnyJsxElement) -> Option<bool> {
-    Some(matches!(
-        node.name().ok()?,
-        AnyJsxElementName::JsxMemberName(_)
-    ))
-}
+fn tag_name_has_dot(node: &AnyJsxElement) -> bool {
+    matches!(node.name().ok(), Ok(AnyJsxElementName::JsxMemberName(_)))
+}
@@
-        if tag_name_has_dot(&element)? {
+        if tag_name_has_dot(&element) {
             return None;
         }

1167-1183: Minor copy tweak

The diagnostic says “for React components”, but this rule validates DOM elements after gating out components. Suggest “in JSX” to avoid confusion.

-                    "Use '"{standard_name}"' instead of '"{name}"' for React components."
+                    "Use '"{standard_name}"' instead of '"{name}"' in JSX."

1484-1510: Use case‑insensitive check for data‑ only after the prefix*

Current has_uppercase(name) flags any uppercase anywhere, which is fine, but the option intent is about the part after data-. Consider restricting the scan to the suffix to keep the message crisp for odd inputs.

-            if options.require_data_lowercase && has_uppercase(&name) {
+            if options.require_data_lowercase {
+                let suffix = &name["data-".len()..];
+                if has_uppercase(suffix) {
                     return Some(NoUnknownPropertyDiagnostic::DataLowercaseRequired {
                         name: name.to_string(),
                         lowercase_name: name.to_lowercase(),
                     });
-            }
+                }
+            }

226-231: Keys are sorted — guard test is defensive, not critical

The ATTRIBUTE_TAGS_MAP keys are currently sorted and the code is correct. However, the suggestion to add a guard test is reasonable: without one, future edits could accidentally break sort order without triggering a compile-time error, and binary_search_by_key would silently fail at runtime.

Consider adding a simple unit test at the end of the file to assert the map remains sorted:

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn attribute_tags_map_is_sorted() {
        let keys: Vec<_> = ATTRIBUTE_TAGS_MAP.iter().map(|(k, _)| k).collect();
        let mut sorted = keys.clone();
        sorted.sort();
        assert_eq!(keys, sorted, "ATTRIBUTE_TAGS_MAP keys must remain sorted for binary_search_by_key");
    }
}
📜 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 0086309 and 91d7893.

⛔ Files ignored due to path filters (11)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/domain_selector.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_js_analyze/src/lint/nursery.rs is excluded by !**/nursery.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/invalid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.jsx.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (10)
  • .changeset/small-words-show.md (1 hunks)
  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.jsx (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.options.json (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/invalid.jsx (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.jsx (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.options.json (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.jsx (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.package.json (1 hunks)
  • crates/biome_rule_options/src/no_unknown_property.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_rule_options/src/no_unknown_property.rs
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/invalid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.package.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.jsx
  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Format Rust files before committing (e.g., via just f which formats Rust)
Document rules, assists, and options with inline rustdoc in source

Files:

  • crates/biome_rule_options/src/no_unknown_property.rs
  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}

Files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/invalid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.package.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.jsx
  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
**/tests/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place test files under a tests/ directory in each crate

Files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/invalid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.package.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.jsx
.changeset/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

.changeset/*.md: In changesets, only use #### or ##### headers; other header levels are not allowed
Changesets should cover user-facing changes only; internal changes do not need changesets
Use past tense for what you did and present tense for current Biome behavior in changesets
When fixing a bug in a changeset, start with an issue link (e.g., “Fixed #1234: …”)
When referencing a rule or assist in a changeset, include a link to its page on the website
Include code blocks in changesets when applicable to illustrate changes
End every sentence in a changeset with a period

Files:

  • .changeset/small-words-show.md
🧠 Learnings (6)
📚 Learning: 2025-10-15T09:20:19.139Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.139Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : For options types, derive Serialize, Deserialize, Deserializable (and JsonSchema under the schema feature) and use #[serde(rename_all="camelCase", deny_unknown_fields, default)] with skip_serializing_if where appropriate

Applied to files:

  • crates/biome_rule_options/src/no_unknown_property.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/tests/specs/**/options.json : Use options.json files colocated with test inputs to override formatting options for all files in that folder

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.options.json
📚 Learning: 2025-08-05T14:43:29.581Z
Learnt from: dyc3
PR: biomejs/biome#7081
File: packages/@biomejs/biome/configuration_schema.json:7765-7781
Timestamp: 2025-08-05T14:43:29.581Z
Learning: The file `packages/biomejs/biome/configuration_schema.json` is auto-generated and should not be manually edited or reviewed for schema issues; any changes should be made at the code generation source.

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.options.json
📚 Learning: 2025-10-15T09:20:19.139Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.139Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/*.{js,jsx,ts,tsx} : Place snapshot test cases under tests/specs/<group>/<ruleName>/ with files typically prefixed by invalid/ or valid/

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.package.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.jsx
📚 Learning: 2025-10-15T09:20:19.139Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.139Z
Learning: A rule’s diagnostic should explain what the error is, why it’s triggered, and what to do (ideally via a code action or a note)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
📚 Learning: 2025-10-15T09:21:24.116Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:21:24.116Z
Learning: A diagnostic must explain why something went wrong, using log advices and links to documentation when helpful

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
🧬 Code graph analysis (2)
crates/biome_rule_options/src/no_unknown_property.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
  • NoUnknownPropertyOptions (8160-8163)
crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs (2)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (2)
  • RuleDomain (927-935)
  • NoUnknownPropertyOptions (8160-8163)
crates/biome_rowan/src/ast/mod.rs (1)
  • cast_ref (142-151)
🔇 Additional comments (4)
crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/ignore/valid.options.json (1)

1-16: No issues identified; convention verified.

The per-file naming pattern (<basename>.options.json) is indeed the established convention across analyser specs—over 20 examples confirm this, including other noUnknownProperty subfolder tests. The review comment is accurate.

crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/valid.package.json (1)

1-6: Remove or document the React 16.4.0 fixture as a placeholder.

The rule currently does not consult React versions (no version gating logic exists in the implementation). The commented-out POPOVER_API_PROPS constant suggests this is planned. Either drop the fixture file to avoid confusion, or add a comment documenting that it's a placeholder for future version-gated testing.

crates/biome_js_analyze/tests/specs/nursery/noUnknownProperty/lowercase/invalid.options.json (1)

1-17: Verified: Options structure and JSON serialisation are correct.

The struct at crates/biome_rule_options/src/no_unknown_property.rs has the expected serde attributes: #[serde(rename_all = "camelCase", deny_unknown_fields, default)] with proper derives (Serialize, Deserialize, Deserializable, JsonSchema). The field require_data_lowercase correctly serialises to "requireDataLowercase" via camelCase conversion, matching the test JSON precisely. Pattern confirmed across 174 .options.json files in the specs directory.

crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs (1)

56-87: Code already correctly configured—no changes needed

The struct in crates/biome_rule_options/src/no_unknown_property.rs already has the proper serde setup:

  • #[serde(rename_all = "camelCase", deny_unknown_fields, default)] is present ✓
  • Rust field require_data_lowercase (snake_case) correctly maps to JSON requireDataLowercase via the bulk rename
  • Documentation uses the correct camelCase field names
  • Field ignore properly uses #[serde(skip_serializing_if = "Vec::is_empty")]

This follows the established pattern for options types in the codebase. The serde rename mechanism is already working as intended.

Comment on lines 6 to 10
pub struct NoUnknownPropertyOptions {
pub require_data_lowercase: bool,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub ignore: Vec<String>,
}
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 | 🔴 Critical

🧩 Analysis chain

Add rustdoc and check schema optionality for ignore.

  • Please document the struct and fields (what each option does, defaults).
  • Ensure the generated JSON schema doesn’t make ignore required; TS shows it as required today.

Proposed doc comments:

 #[serde(rename_all = "camelCase", deny_unknown_fields, default)]
 pub struct NoUnknownPropertyOptions {
-    pub require_data_lowercase: bool,
+    /// Enforce lower-case `data-*` attribute names when true. Default: false.
+    pub require_data_lowercase: bool,
     #[serde(skip_serializing_if = "Vec::is_empty")]
-    pub ignore: Vec<String>,
+    /// Additional attribute names to ignore (case-sensitive). Default: [].
+    pub ignore: Vec<String>,
 }

Verify schema/TS:


🏁 Script executed:

#!/bin/bash
# After codegen, check required fields under noUnknownProperty
jq -r '
  .. | objects | select(has("title") and .title=="noUnknownProperty") |
  .allOf[]?.then?.properties? // empty
' packages/@biomejs/biome/configuration_schema.json

rg -n 'interface NoUnknownPropertyOptions' packages/@biomejs/backend-jsonrpc/src/workspace.ts -n -A3

Length of output: 117


🏁 Script executed:

#!/bin/bash
# Check current state of the Rust file to see if rustdoc is present
cat crates/biome_rule_options/src/no_unknown_property.rs

Length of output: 456


Add rustdoc and fix schema optionality for ignore.

Confirmed: the struct lacks documentation, and the TypeScript interface incorrectly marks ignore as required. The #[serde(skip_serializing_if = "Vec::is_empty")] attribute means it should be optional in the schema.

Implement the proposed rustdoc additions and verify the codegen pipeline regenerates the TypeScript interface with ignore?: string[].

🤖 Prompt for AI Agents
In crates/biome_rule_options/src/no_unknown_property.rs around lines 6–10, add
rustdoc comments describing the struct and its fields, and make the `ignore`
field optional for schema generation by changing its type to Option<Vec<String>>
and updating serde attributes to use a default and skip serialization when None
(e.g. add #[serde(default, skip_serializing_if = "Option::is_none")]). After
updating the doc comments and the field type/serde attrs, run the codegen
pipeline to regenerate the TypeScript interface so it emits `ignore?: string[]`.

@dibashthapa
Copy link
Contributor Author

@dyc3 hey thank you for your comments, i have worked on your suggestions, and I think they are resolved.

I believe these are the things I need to work on next

  • Support for different props based on react version
  • Docstring coverage (based on rabbitai feedback)

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

♻️ Duplicate comments (1)
crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs (1)

713-714: Event casing: add onBeforeToggle; drop ontoggle; prefer camelCase suggestions

Current list includes lowercase "onbeforetoggle" and "ontoggle", but misses the canonical React props "onBeforeToggle" and (already present) "onToggle". As written, ontoggle/onbeforetoggle will be accepted and won’t auto‑fix to camelCase.

-    "onbeforetoggle",
+    "onBeforeToggle",
@@
-    "ontoggle",
+    // Intentionally omit lowercase "ontoggle" so it maps to "onToggle"

Add tests asserting:

  • <div onbeforetoggle={() => {}} /> → diagnostic suggesting onBeforeToggle
  • <div ontoggle={() => {}} /> → diagnostic suggesting onToggle

This keeps behaviour aligned with React 19’s events and improves auto‑fix.

Also applies to: 847-848

🧹 Nitpick comments (3)
crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs (3)

1065-1077: Avoid unnecessary allocations for attribute names; make ignore check case‑insensitive

You allocate for every attribute (to_string, manual concat). We can avoid allocations in the common case and only allocate for namespaced attributes, while matching ignore without allocating.

+use std::borrow::Cow;
@@
-        let node_name = match node.name().ok()? {
-            AnyJsxAttributeName::JsxName(name) => {
-                name.value_token().ok()?.text_trimmed().to_string()
-            }
-            AnyJsxAttributeName::JsxNamespaceName(name) => {
-                let namespace = name.namespace().ok()?.value_token().ok()?;
-                let name = &name.name().ok()?.value_token().ok()?;
-                // There could be better way, but i couldn't extract namespaced attributes
-                // For e.g xlink:href
-                // without manually concatenating with ':'
-                namespace.text_trimmed().to_string() + ":" + name.text_trimmed()
-            }
-        };
+        let node_name_text: Cow<'_, str> = match node.name().ok()? {
+            AnyJsxAttributeName::JsxName(name) => {
+                Cow::Borrowed(name.value_token().ok()?.text_trimmed())
+            }
+            AnyJsxAttributeName::JsxNamespaceName(name) => {
+                let ns = name.namespace().ok()?.value_token().ok()?.text_trimmed();
+                let nm = name.name().ok()?.value_token().ok()?.text_trimmed();
+                Cow::Owned(format!("{ns}:{nm}"))
+            }
+        };
@@
-        if options.ignore.contains(&node_name) {
+        if options
+            .ignore
+            .iter()
+            .any(|s| s.eq_ignore_ascii_case(node_name_text.as_ref()))
+        {
             return None;
         }
@@
-        let name = normalize_attribute_case(&node_name);
+        let name = normalize_attribute_case(node_name_text.as_ref());

This removes hot‑path allocations and makes ignore friendlier. If ignore is meant to be case‑sensitive, drop eq_ignore_ascii_case.

Also applies to: 1079-1084


972-973: Redundant use inside function

use biome_string_case::StrOnlyExtension; is already imported at the module level. Remove the inner use.

-    use biome_string_case::StrOnlyExtension;

1169-1177: Offer quick‑fixes in diagnostics (rename)

You already tell users what to do; wire in code actions to auto‑rename to standard_name and lower‑case data-* attributes.

Happy to sketch the .action plumbing if useful.

Also applies to: 1205-1213

📜 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 91d7893 and 22e95d7.

📒 Files selected for processing (1)
  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Format Rust files before committing (e.g., via just f which formats Rust)
Document rules, assists, and options with inline rustdoc in source

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
🧠 Learnings (2)
📚 Learning: 2025-10-15T09:20:19.139Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.139Z
Learning: A rule’s diagnostic should explain what the error is, why it’s triggered, and what to do (ideally via a code action or a note)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
📚 Learning: 2025-10-15T09:21:24.116Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:21:24.116Z
Learning: A diagnostic must explain why something went wrong, using log advices and links to documentation when helpful

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (2)
  • RuleDomain (927-935)
  • NoUnknownPropertyOptions (8160-8163)
crates/biome_analyze/src/rule.rs (4)
  • domains (625-628)
  • sources (610-613)
  • same (246-251)
  • recommended (595-598)
crates/biome_rowan/src/ast/mod.rs (1)
  • cast_ref (142-151)
⏰ 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). (2)
  • GitHub Check: triage
  • GitHub Check: Validate PR title
🔇 Additional comments (3)
crates/biome_js_analyze/src/lint/nursery/no_unknown_property.rs (3)

73-89: No issues found—serde mapping is correctly configured

The NoUnknownPropertyOptions struct already includes #[serde(rename_all = "camelCase", deny_unknown_fields, default)], which ensures the Rust field require_data_lowercase serialises as requireDataLowercase in JSON, matching the documentation. All coding guidelines are satisfied.


95-100: The review comment is incorrect—both RuleSource variants are valid and active

Both EslintReactX and EslintReactXyz are legitimate, properly-documented variants in the RuleSource enum (lines 125 and 127 of crates/biome_analyze/src/rule.rs). They represent distinct ESLint React plugins with different outputs in the Display trait:

  • EslintReactX displays as "eslint-plugin-react-x"
  • EslintReactXyz displays as "@eslint-react/eslint-plugin"

The code compiles and is correct as written. The suggestion to consolidate to a single EslintReact source would lose important provenance information about which tool each rule originates from.

Likely an incorrect or invalid review comment.


114-225: All constants are correctly sorted—no action needed.

The verification confirms that ATTRIBUTE_TAGS_MAP, DOM_ATTRIBUTE_NAMES, and SVGDOM_ATTRIBUTE_NAMES are all properly sorted by their first keys. Binary search will work as expected; the code is sound.

name.value_token().ok()?.text_trimmed().to_string()
}
AnyJsxAttributeName::JsxNamespaceName(name) => {
let namespace = name.namespace().ok()?.value_token().ok()?;
Copy link
Contributor Author

@dibashthapa dibashthapa Oct 20, 2025

Choose a reason for hiding this comment

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

@dyc3 And this issue as well, I couldn't figure out the method to have attributes with colon , something like xmlns:href from the element, and I had to manually concatenate : and convert to String

Copy link
Contributor

Choose a reason for hiding this comment

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

You could put namespaced attributes into a different map, and that would let you avoid the string allocation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dyc3 I couldn't figure out how to do that without repeating same line of code

So I resorted to this

  let node_name = match node.name().ok()? {
      AnyJsxAttributeName::JsxName(name) => name.syntax().text_trimmed(),
      AnyJsxAttributeName::JsxNamespaceName(name) => name.syntax().text_trimmed(),
  };
  let node_name = node_name.to_string();

  if options.ignore.contains(&node_name) {
      return None;
  }

I had to use to_string() because, contains method requires borrowed String as argument

name.value_token().ok()?.text_trimmed().to_string()
}
AnyJsxAttributeName::JsxNamespaceName(name) => {
let namespace = name.namespace().ok()?.value_token().ok()?;
Copy link
Contributor

Choose a reason for hiding this comment

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

You could put namespaced attributes into a different map, and that would let you avoid the string allocation.

@ematipico ematipico deleted the branch biomejs:main October 23, 2025 10:03
@ematipico ematipico closed this Oct 23, 2025
@ematipico ematipico reopened this Oct 23, 2025
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 (4)
crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs (4)

107-113: Remove commented-out code or implement Popover API support.

This commented block has been sitting here—either implement React 19 Popover API prop validation or remove it to keep the codebase tidy.


115-226: Consider sorting ATTRIBUTE_TAGS_MAP alphabetically for maintainability.

The map entries aren't alphabetically sorted (e.g., "onCancel" appears after "onCanPlay", "onLoadedData" after "onLoadStart"). Whilst the HashMap lookup (line 1110) is unaffected, keeping the source sorted makes future edits less error-prone.


969-969: Remove redundant import.

StrOnlyExtension is already imported at the module level (line 8); this local import is unnecessary.

Apply this diff:

 fn is_valid_data_attribute(name: &str) -> bool {
-    use biome_string_case::StrOnlyExtension;
     if !name.starts_with("data-") {

1188-1188: Improve formatting of allowed tags list.

Add a space after the comma for better readability in the diagnostic message.

Apply this diff:

-                       "This attribute is only allowed on: "{allowed_tags.join(",")}
+                       "This attribute is only allowed on: "{allowed_tags.join(", ")}
📜 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 fcd942c and c1040df.

📒 Files selected for processing (1)
  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Format Rust files before committing (e.g., via just f which formats Rust)
Document rules, assists, and options with inline rustdoc in source

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
🧠 Learnings (1)
📚 Learning: 2025-10-24T21:24:58.631Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.631Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : If a rule is inspired by an external source, populate sources in declare_lint_rule! with RuleSource::{Eslint,...} and same()/inspired()

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs (2)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (2)
  • RuleDomain (927-935)
  • NoUnknownAttributeOptions (8281-8284)
crates/biome_rowan/src/ast/mod.rs (1)
  • cast_ref (142-151)

@dibashthapa
Copy link
Contributor Author

@dyc3 i have pushed new changes with updated name for rule. I haven't yet added support for popover api (react 19), should i leave it like this ?

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.

Biome targets more recent tech stacks. So if there are new things in React 19 that affect this rule, this rule should handle it.

'@biomejs/biome': patch
---

Added the new rule [`no-unknown-property`](https://biomejs.dev/linter/rules/no-unknown-property/) from eslint react
Copy link
Contributor

Choose a reason for hiding this comment

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

The bot is correct, but you need to link the issue like this: [#7657](https://github.com/biomejs/biome/issues/7657)

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

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

♻️ Duplicate comments (5)
crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs (5)

68-68: Update documentation example to match corrected rule name.

The rule identifier should be noUnknownProperty throughout.

-  "noUnknownAttribute": {
+  "noUnknownProperty": {

85-85: Update documentation example to match corrected rule name.

Same as above—align with noUnknownProperty.

-  "noUnknownAttribute": {
+  "noUnknownProperty": {

95-95: Rule name must match tests and options configuration.

The published rule ID noUnknownAttribute conflicts with test fixtures and option definitions that expect noUnknownProperty.

-        name: "noUnknownAttribute",
+        name: "noUnknownProperty",

1101-1104: requireDataLowercase option is defined but never enforced.

The option exists in the schema and has diagnostic logic, but you never check options.require_data_lowercase before returning None here.

Add before the early return:

 if is_valid_data_attribute(name) {
+    if options.require_data_lowercase.unwrap_or(false) 
+        && name != &name.to_lowercase() 
+    {
+        return Some(NoUnknownAttributeState::DataLowercaseRequired {
+            name: (*name).into(),
+        });
+    }
     return None;
 }

Note: You'll also need to add the DataLowercaseRequired variant to NoUnknownAttributeState and implement its diagnostic.


1126-1126: TokenText doesn't have a trim() method.

tag_name is TokenText (line 1111). Use .text() instead.

-            if !allowed_tags.contains(&tag_name.trim()) {
+            if !allowed_tags.contains(&tag_name.text()) {
📜 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 1d339b3 and ff60ce1.

⛔ Files ignored due to path filters (4)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/popover/valid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/valid.jsx.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (5)
  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/popover/valid.jsx (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/popover/valid.package.json (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/valid.jsx (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/valid.package.json (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/popover/valid.package.json
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/popover/valid.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/valid.jsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rs,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Format Rust and TOML files before committing (e.g., via just f)

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Document rules, assists, and their options with inline rustdoc in the Rust source

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
🧠 Learnings (26)
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/tests/specs/**/*.jsonc : .jsonc snapshot test files must contain an array of code strings and are interpreted as script (no ESM import/export)

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/valid.package.json
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/tests/specs/**/{invalid*,valid*}.* : Name snapshot test files with invalid* and valid* prefixes to indicate reported vs non-reported cases

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/valid.package.json
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Set the language field in declare_lint_rule! to the most appropriate dialect (js/jsx/ts/tsx)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/lint/nursery/**/*.rs : Place all new rules in the nursery group

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/a11y/**/*.rs : Rules in a11y group must have severity: error

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule documentation: first paragraph must be a single line summary

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : If a rule is inspired by an external source, populate sources in declare_lint_rule! with RuleSource::{Eslint,...} and same()/inspired()

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : In declare_lint_rule! macros, set version: "next"

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Provide informative diagnostics: explain what the error is, why it triggers, and what to do (prefer a code action or a note)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : If a rule provides a code action, add fix_kind to declare_lint_rule! (FixKind::Safe or ::Unsafe)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use no<Concept> when forbidding a single concept (e.g., noDebugger)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Use rule_category! macro to reference the diagnostic category created by declare_lint_rule!

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Prefer conventional naming families when applicable: use<Framework>..., noConstant<Concept>, noDuplicate<Concept>, noEmpty<Concept>, noExcessive<Concept>, noRedundant<Concept>, noUnused<Concept>, noUseless<Concept>, noInvalid<Concept>, useValid<Concept>, noUnknown<Concept>, noMisleading<Concept>, noRestricted<Concept>, noUndeclared<Concept>, noUnsafe<Concept>, useConsistent<Concept>, useShorthand<Concept>

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Rule names should use use<Concept> when mandating a single concept (e.g., useValidLang)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/style/**/*.rs : Rules in style group must have severity: info or warn (prefer info if unsure)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/suspicious/**/*.rs : Rules in suspicious group must have severity: warn or error (prefer warn if unsure)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Place per-rule options types in biome_rule_options crate under lib/, one file per rule

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Avoid avoidable string allocations; compare against &str or TokenText rather than allocating Strings

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-15T09:22:46.002Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:46.002Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Do not attempt to fix code; if a mandatory token/node is missing, return `None` instead

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-15T09:22:46.002Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:46.002Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : For non-mandatory tokens, use the provided helper constructors (e.g., `token`, `space_token`, `dynamic_token`)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-15T09:22:46.002Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:46.002Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : When a token is mandatory and present in the AST, use the AST-provided token (e.g., `node.l_paren_token().format()`) instead of emitting a static token

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : In ### Invalid doc examples, each snippet must use the expect_diagnostic modifier and emit exactly one diagnostic

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Documentation must include a ## Examples section with ### Invalid before ### Valid

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/*_analyze/**/src/**/lint/**/*.rs : Avoid deep indentation by using combinators (map, filter, and_then) rather than nested if-let/unwrap chains

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-24T21:24:58.650Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-24T21:24:58.650Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Prefer Box<[Box<str>]> over Vec<String> for options string lists to reduce memory usage

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/src/**/*.rs : After generation, remove usages of `format_verbatim_node` and implement real formatting with biome_formatter utilities

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (2)
  • RuleDomain (927-935)
  • NoUnknownAttributeOptions (8281-8283)
crates/biome_analyze/src/rule.rs (4)
  • domains (625-628)
  • sources (610-613)
  • same (246-251)
  • recommended (595-598)
crates/biome_rowan/src/ast/mod.rs (1)
  • cast_ref (142-151)
🔇 Additional comments (1)
crates/biome_js_analyze/tests/specs/nursery/noUnknownAttribute/valid.package.json (1)

1-6: LGTM—test fixture is appropriate.

This package.json properly sets up a React 16.4.0 environment for testing version-specific attribute handling.

Comment on lines +115 to +120
const POPOVER_API_PROPS_LOWERCASE: &[&str] = &[
"onbeforetoggle",
"popover",
"popovertarget",
"popovertargetaction",
];
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 | 🟠 Major

Lowercase Popover props shouldn't be used as standard names.

The logic at lines 1045–1051 returns lowercase property names (e.g., "popovertarget") as the "standard name" for React < 19. React props are always camelCase; suggesting lowercase names will mislead users.

Consider either:

  • Removing Popover API support for React < 19 entirely (simplest)
  • Or returning None when React < 19 so these props are flagged as unknown
🤖 Prompt for AI Agents
crates/biome_js_analyze/src/lint/nursery/no_unknown_attribute.rs lines 115-120:
the POPOVER_API_PROPS_LOWERCASE list causes the linter to suggest lowercase prop
names (e.g., "popovertarget") as the "standard name" for React < 19, which is
incorrect because React props must be camelCase; update the code that handles
popover props (around lines 1045–1051) to stop returning those lowercase names
for React < 19 — either remove/populate the POPOVER_API_PROPS_LOWERCASE usage
and treat these props as unsupported for React < 19 (simplest: delete the branch
that maps to lowercase names), or change the branch to return None when
react_version < 19 so the props are flagged unknown; implement the chosen
approach and adjust any tests accordingly.

@dibashthapa
Copy link
Contributor Author

I just fixed the clippy errors

@dibashthapa
Copy link
Contributor Author

@dyc3 i have pushed new commits. I removed the wrong folder and had to revert the commit again.

Please let me know if i need to do any fixes or any changes in the codebase

Although its been 2-3weeks since my PR 😅

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.

Looks good. Nice work!

@dyc3 dyc3 merged commit 2509b91 into biomejs:main Nov 2, 2025
20 checks passed
@github-actions github-actions bot mentioned this pull request Nov 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

📎 Port no-unknown-property from react rules

3 participants