feat(eslint-config)!: upgrade @eslint-react/eslint-plugin to v4#3107
feat(eslint-config)!: upgrade @eslint-react/eslint-plugin to v4#3107marcusrbrown merged 2 commits intomainfrom
Conversation
fro-bot
left a comment
There was a problem hiding this comment.
Verdict: CONDITIONAL
This migration is structurally sound — the unified plugin architecture is correctly adopted and the spread of pluginReact.configs.all.plugins works as expected (the v4 all config exposes a single '@eslint-react' key). However, there is one blocking bug introduced by the migration.
Blocking issues
ReactTypeAwareRules uses the wrong plugin prefix (packages/eslint-config/src/configs/react.ts, lines 26–29)
const ReactTypeAwareRules: Config['rules'] = {
'react/no-implicit-key': 'warn', // ← stale v2 prefix
'react/no-leaked-conditional-rendering': 'warn', // ← stale v2 prefix
}In v2 the plugin was explicitly aliased as react (react: plugins['@eslint-react']). After this migration the spread of pluginReact.configs.all.plugins registers the plugin under its native key '@eslint-react', not 'react'. The rules resolver will fail to find any rule under the old namespace — ESLint either silently drops or errors on unknown rule names at runtime.
The correct v4 prefixes are:
const ReactTypeAwareRules: Config['rules'] = {
'@eslint-react/no-implicit-key': 'warn',
'@eslint-react/no-leaked-conditional-rendering': 'warn',
}Both rules exist in the v4 plugin (confirmed via node_modules/@eslint-react/eslint-plugin inspection). They are also absent from the default recommended spread, so the type-aware block remains necessary — it just needs the correct prefix.
Non-blocking concerns
-
Changeset bump type —
.changeset/eslint-react-v4.mddeclaresminor, but the PR title uses!(breaking change marker) and the description explicitly calls out breaking changes: peer dep range jumps from^2.2.3to^4.2.3, rule names change fromreact/*to@eslint-react/*, and several rules are removed entirely. Consumers who override any of those removed rules or who pin overrides to oldreact/prefixed rule names will see breakage on upgrade. Per the repo's own AGENTS.md convention («Major: breaking API changes»), this warrants a major bump. This is a judgment call the author can make intentionally, but it should be conscious. -
Stale JSDoc — The function-level JSDoc in
react.ts(lines 44–51) still enumerates «React DOM rules», «React Hooks rules», «React Web API rules» as separate configuration categories. These are now all delivered via the singlepluginReact.configs.recommended.rulesspread. The bullet list is technically still accurate as a description of what rules are applied but implies a structural separation that no longer exists in code. Low-priority cleanup. -
eslint-plugin-react-hookspeer dependency retained — The package remains inpeerDependencies(anddevDependencies) but is no longer imported or used inreact.ts. The changeset notes «eslint-plugin-react-hooksremains as a peer dependency for consumers using it directly.» If that intent is correct, a code comment on the peer entry would help future readers understand why. If it's unintentional, the peer dep and itspeerDependenciesMetaentry can be removed.
Missing tests
The eslint-config package does not appear to have tests exercising the type-aware rule resolution path (the ReactTypeAwareRules block). The blocking bug above would have been caught by an integration test that instantiates the config with tsconfigPath set and asserts the resulting rule names contain @eslint-react/ prefixes. Not required to block merge, but worth adding to close the gap.
Risk assessment: MED
- The
react/prefix bug means the two type-aware rules (no-implicit-key,no-leaked-conditional-rendering) are silently dropped for every consumer who enables type-aware linting. This is a correctness regression — the rules disappear without error, making it easy to miss in CI. - The broader migration (plugin registration, recommended spread, hooks coverage) is correct and mirrors the antfu/eslint-config reference PR faithfully.
- Blast radius is limited to the React type-aware linting path, which requires explicit opt-in via
tsconfigPath.
Run Summary
| Field | Value |
|---|---|
| Event | pull_request |
| Repository | bfra-me/works |
| Run ID | 24437992496 |
| Cache | hit |
| Session | ses_270650720ffei5Tyq5Lat0XDJL |
…prefix for v4 compatibility In @eslint-react/eslint-plugin v4, the unified plugin architecture registers rules under the `@eslint-react/` namespace rather than the legacy `react/` namespace. Update rule references from `react/no-implicit-key` and `react/no-leaked-conditional-rendering` to `@eslint-react/no-implicit-key` and `@eslint-react/no-leaked-conditional-rendering` to fix the ts-strict-with-react fixture test failure.
Autohealing FixFailing check: Root cause: The
In Fix applied (commit
All tests now pass locally ( |
fro-bot
left a comment
There was a problem hiding this comment.
Verdict: PASS
The blocking issue from the previous review has been addressed in commit dba1f8f: ReactTypeAwareRules now correctly uses the @eslint-react/ prefix for both type-aware rules. Verified in the current file:
const ReactTypeAwareRules: Config['rules'] = {
'@eslint-react/no-implicit-key': 'warn',
'@eslint-react/no-leaked-conditional-rendering': 'warn',
}The migration is correct end-to-end:
- Unified plugin registered via
pluginReact.configs.all.pluginsspread (key:'@eslint-react') - Recommended ruleset replaces ~40 hand-listed rules
- Hooks rules (
rules-of-hooks,exhaustive-deps) covered via v4 recommended config - DOM and Web API rules covered via recommended spread
- Type-aware rules retain correct v4 prefixes
Blocking issues
None — all resolved.
Non-blocking concerns
The concerns from the previous review remain open for author's discretion:
- Changeset bump type — declared
minordespite peer dep major bump and rule-name breaking changes. Reasonable call if the package treats peer dep changes as non-breaking, but worth a note in the changelog. eslint-plugin-react-hookspeer dep — retained but no longer used inreact.ts. Intentional per the changeset note; a code comment on the peer entry would help future readers.
Missing tests
None that are blocking. A test exercising the type-aware path with tsconfigPath set would have caught the prefix bug earlier. Non-blocking.
Risk assessment: LOW
Both commits are correct. The fix addresses the only regression path (type-aware rules silently dropping). The broader migration matches the upstream reference (antfu/eslint-config PR #839). All CI checks pass.
Run Summary
| Field | Value |
|---|---|
| Event | pull_request |
| Repository | bfra-me/works |
| Run ID | 24438596334 |
| Cache | hit |
| Session | ses_270650720ffei5Tyq5Lat0XDJL |
fro-bot
left a comment
There was a problem hiding this comment.
Verdict: PASS
The blocking issue from the previous review has been addressed in commit dba1f8f: ReactTypeAwareRules now correctly uses the @eslint-react/ prefix for both type-aware rules. Verified in the current file:
const ReactTypeAwareRules: Config['rules'] = {
'@eslint-react/no-implicit-key': 'warn',
'@eslint-react/no-leaked-conditional-rendering': 'warn',
}The migration is correct end-to-end:
- Unified plugin registered via
pluginReact.configs.all.pluginsspread (key:'@eslint-react') - Recommended ruleset replaces ~40 hand-listed rules
- Hooks rules (
rules-of-hooks,exhaustive-deps) covered via v4 recommended config - DOM and Web API rules covered via recommended spread
- Type-aware rules retain correct v4 prefixes
Blocking issues
None — all resolved.
Non-blocking concerns
The concerns from the previous review remain open for author's discretion:
- Changeset bump type — declared
minordespite peer dep major bump and rule-name breaking changes. Reasonable call if the package treats peer dep changes as non-breaking, but worth a note in the changelog. eslint-plugin-react-hookspeer dep — retained but no longer used inreact.ts. Intentional per the changeset note; a code comment on the peer entry would help future readers.
Missing tests
None that are blocking. A test exercising the type-aware path with tsconfigPath set would have caught the prefix bug earlier. Non-blocking.
Risk assessment: LOW
Both commits are correct. The fix addresses the only regression path (type-aware rules silently dropping). The broader migration matches the upstream reference (antfu/eslint-config PR #839). All CI checks pass.
Run Summary
| Field | Value |
|---|---|
| Event | pull_request |
| Repository | bfra-me/works |
| Run ID | 24438596334 |
| Cache | hit |
| Session | ses_270650720ffei5Tyq5Lat0XDJL |
Summary
Upgrades
@eslint-react/eslint-pluginfrom v2 to v4, adopting the unified plugin architecture. Follows the same migration pattern as antfu/eslint-config PR #839.Breaking Changes
@eslint-react/eslint-pluginnow requires^4.2.3(was^2.2.3)@eslint-reactnamespace instead of separate sub-plugins with/separatorsno-default-props,no-prop-types,jsx-no-duplicate-props,jsx-uses-vars,no-string-refs,no-useless-forward-ref,prefer-use-state-lazy-initializationWhat Changed
react-dom,react-hooks-extra, etc.)@eslint-react) +react-refreshpluginReact.configs.recommended.rulesspreadeslint-plugin-react-hooksimport + spreadrules-of-hooks,exhaustive-deps)no-implicit-key,no-leaked-conditional-renderingVerification
pnpm install— cleanpnpm type-check— passespnpm lint— passespnpm build— passes (includinggenerate-typesfor eslint-typegen)Related