fix(lint): fix useComponentExportOnlyModules false positive with TanStack Router#8669
Conversation
🦋 Changeset detectedLatest commit: 699c44e The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
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 |
…tack Router Fixes biomejs#8628 Components referenced as object property values in exported expressions are now exempt from the 'should be exported' diagnostic. This handles patterns like TanStack Router's createFileRoute where components are passed via configuration objects.
43e7e81 to
699c44e
Compare
CodSpeed Performance ReportMerging #8669 will not alter performanceComparing Summary
Footnotes
|
WalkthroughThis change resolves false positives in the Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (4 passed)
✨ Finishing touches
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rs (1)
266-268: LGTM!The retain logic is correctly placed before diagnostic generation and efficiently filters in-place.
Optional: Consider combining the two sets
- let referenced_ids: FxHashSet<Box<str>> = exported_non_component_ids + let mut referenced_ids: FxHashSet<Box<str>> = exported_non_component_ids .iter() // ... existing collection logic .collect(); - // Also collect shorthand property references like { HomeComponent } - let shorthand_ids: FxHashSet<Box<str>> = exported_non_component_ids - .iter() - .filter_map(|item| item.exported.as_ref()) - .flat_map(|exported| { - exported - .syntax() - .descendants() - .filter_map(JsShorthandPropertyObjectMember::cast) - .filter_map(|prop| prop.name().ok()) - .filter_map(|name| name.value_token().ok()) - .map(|token| token.text_trimmed().into()) - }) - .collect(); + // Also collect shorthand property references like { HomeComponent } + referenced_ids.extend( + exported_non_component_ids + .iter() + .filter_map(|item| item.exported.as_ref()) + .flat_map(|exported| { + exported + .syntax() + .descendants() + .filter_map(JsShorthandPropertyObjectMember::cast) + .filter_map(|prop| prop.name().ok()) + .filter_map(|name| name.value_token().ok()) + .map(|token| token.text_trimmed().into()) + }), + ); // Remove components that are referenced as object property values - local_components - .retain(|name, _| !referenced_ids.contains(name) && !shorthand_ids.contains(name)); + local_components.retain(|name, _| !referenced_ids.contains(name));This would slightly simplify the retain condition, though the current approach is perfectly fine and arguably more readable with the separate sets.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
crates/biome_js_analyze/tests/specs/style/useComponentExportOnlyModules/valid_component_referenced_in_export.jsx.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/style/useComponentExportOnlyModules/valid_component_shorthand_in_export.jsx.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (4)
.changeset/fix-component-export-tanstack-router.mdcrates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rscrates/biome_js_analyze/tests/specs/style/useComponentExportOnlyModules/valid_component_referenced_in_export.jsxcrates/biome_js_analyze/tests/specs/style/useComponentExportOnlyModules/valid_component_shorthand_in_export.jsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use thedbg!()macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests
Files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rs
🧠 Learnings (18)
📚 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/**/js_module_info/collector.rs : Implement module-level (thin) inference to resolve `TypeReference::Qualifier` variants by looking up declarations in module scopes and handling import statements
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Check if a variable is global using the semantic model before reporting diagnostics for rules that ban global functions or variables
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_node_union!` macro to query multiple node types together to avoid redundant traversal passes
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Use `TypeReference` instead of `Arc` for types that reference other types to avoid stale cache issues when modules are replaced
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.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/**/scoped_resolver.rs : Implement full inference to resolve `TypeReference::Import` variants across the entire module graph
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.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/**/local_inference.rs : Implement local inference in dedicated modules to derive type definitions from expressions without context of surrounding scopes
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use helper functions like `map`, `filter`, and `and_then` to avoid excessive nested `if let` statements
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.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_js_analyze/src/lint/style/use_component_export_only_modules.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 : Distinguish between `TypeData::Unknown` and `TypeData::UnknownKeyword` to measure inference effectiveness versus explicit user-provided unknown types
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `use` prefix when the rule's sole intention is to mandate a single concept
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `no` prefix when the rule's sole intention is to forbid a single concept
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.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_js_analyze/src/lint/style/use_component_export_only_modules.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule options must be defined in the `biome_rule_options` crate with a file named after the rule
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.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_js_analyze/src/lint/style/use_component_export_only_modules.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : When porting rules from other linters, use `sources` metadata with `RuleSource::Eslint().same()` for identical behavior or `.inspired()` for different behavior
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.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_js_analyze/src/lint/style/use_component_export_only_modules.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).
Applied to files:
crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.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/**/* : Create test files with `invalid` and `valid` prefixes to represent code that should and should not trigger the rule
Applied to files:
crates/biome_js_analyze/tests/specs/style/useComponentExportOnlyModules/valid_component_referenced_in_export.jsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: Lint project (depot-windows-2022)
- 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: End-to-end tests
- GitHub Check: Check Dependencies
- GitHub Check: Documentation
- GitHub Check: Bench (biome_js_formatter)
- GitHub Check: Bench (biome_js_parser)
- GitHub Check: Bench (biome_js_analyze)
- GitHub Check: autofix
🔇 Additional comments (6)
.changeset/fix-component-export-tanstack-router.md (1)
1-13: LGTM!Clear and well-documented changeset. The example nicely illustrates the fixed false positive scenario.
crates/biome_js_analyze/tests/specs/style/useComponentExportOnlyModules/valid_component_shorthand_in_export.jsx (1)
1-10: LGTM!Good test coverage for the shorthand property syntax. Based on learnings, the
valid_prefix correctly indicates this should not trigger diagnostics.crates/biome_js_analyze/tests/specs/style/useComponentExportOnlyModules/valid_component_referenced_in_export.jsx (1)
1-12: LGTM!Excellent test coverage for the TanStack Router pattern. This directly addresses the issue #8628 use case. Based on learnings, the
valid_prefix correctly indicates this should not trigger diagnostics.crates/biome_js_analyze/src/lint/style/use_component_export_only_modules.rs (3)
7-13: LGTM!Imports are well-chosen for the new functionality. Using
FxHashSetfor the lookup sets is a sensible choice.
221-249: Well-documented logic.The inline comments clearly explain the rationale for exempting object property values whilst excluding direct function call arguments. The parent check correctly identifies identifiers that are values within
JsPropertyObjectMember.One minor consideration: for deeply nested object literals like
{ outer: { component: X } },Xwould still be exempted since its immediate parent is aJsPropertyObjectMember. This seems like reasonable behaviour, but worth confirming it aligns with your intent.
251-264: LGTM!Clean handling of shorthand property syntax. The separation from regular property collection keeps the logic readable.
Summary
Fixes #8628
Components referenced as object property values in exported expressions are now exempt from the "should be exported" diagnostic.
This handles patterns like TanStack Router where components are passed via configuration objects:
The fix only exempts components referenced in object literals (like
{ component: X }), not direct function call arguments (likehoge(X)), because the latter might be non-standard HOCs that could break Fast Refresh.Test plan
{ HomeComponent })AI Assistance Disclosure
I used Codex to review the changes, sanity-check the implementation against existing patterns, and help spot potential edge cases.