diff --git a/ReactVersions.js b/ReactVersions.js index c657857cbbc82..ba7b222bf0688 100644 --- a/ReactVersions.js +++ b/ReactVersions.js @@ -33,7 +33,7 @@ const canaryChannelLabel = 'canary'; const rcNumber = 0; const stablePackages = { - 'eslint-plugin-react-hooks': '6.2.0', + 'eslint-plugin-react-hooks': '7.0.0', 'jest-react': '0.18.0', react: ReactVersion, 'react-art': ReactVersion, diff --git a/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts b/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts index 2e7acac25424f..1c077edd8d8a5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts @@ -536,7 +536,8 @@ function printErrorSummary(category: ErrorCategory, message: string): string { case ErrorCategory.StaticComponents: case ErrorCategory.Suppression: case ErrorCategory.Syntax: - case ErrorCategory.UseMemo: { + case ErrorCategory.UseMemo: + case ErrorCategory.VoidUseMemo: { heading = 'Error'; break; } @@ -582,6 +583,10 @@ export enum ErrorCategory { * Checking for valid usage of manual memoization */ UseMemo = 'UseMemo', + /** + * Checking that useMemos always return a value + */ + VoidUseMemo = 'VoidUseMemo', /** * Checking for higher order functions acting as factories for components/hooks */ @@ -669,6 +674,21 @@ export enum ErrorCategory { FBT = 'FBT', } +export enum LintRulePreset { + /** + * Rules that are stable and included in the `recommended` preset. + */ + Recommended = 'recommended', + /** + * Rules that are more experimental and only included in the `recommended-latest` preset. + */ + RecommendedLatest = 'recommended-latest', + /** + * Rules that are disabled. + */ + Off = 'off', +} + export type LintRule = { // Stores the category the rule corresponds to, used to filter errors when reporting category: ErrorCategory; @@ -689,15 +709,14 @@ export type LintRule = { description: string; /** - * If true, this rule will automatically appear in the default, "recommended" ESLint - * rule set. Otherwise it will be part of an `allRules` export that developers can - * use to opt-in to showing output of all possible rules. + * Configures the preset in which the rule is enabled. If 'off', the rule will not be included in + * any preset. * * NOTE: not all validations are enabled by default! Setting this flag only affects * whether a given rule is part of the recommended set. The corresponding validation * also should be enabled by default if you want the error to actually show up! */ - recommended: boolean; + preset: LintRulePreset; }; const RULE_NAME_PATTERN = /^[a-z]+(-[a-z]+)*$/; @@ -720,7 +739,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'automatic-effect-dependencies', description: 'Verifies that automatic effect dependencies are compiled if opted-in', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.CapitalizedCalls: { @@ -730,7 +749,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'capitalized-calls', description: 'Validates against calling capitalized functions/methods instead of using JSX', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.Config: { @@ -739,7 +758,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { severity: ErrorSeverity.Error, name: 'config', description: 'Validates the compiler configuration options', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.EffectDependencies: { @@ -748,7 +767,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { severity: ErrorSeverity.Error, name: 'memoized-effect-dependencies', description: 'Validates that effect dependencies are memoized', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.EffectDerivationsOfState: { @@ -758,7 +777,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'no-deriving-state-in-effects', description: 'Validates against deriving values from state in an effect', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.EffectSetState: { @@ -768,7 +787,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'set-state-in-effect', description: 'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.ErrorBoundaries: { @@ -778,7 +797,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'error-boundaries', description: 'Validates usage of error boundaries instead of try/catch for errors in child components', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.Factories: { @@ -789,7 +808,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { description: 'Validates against higher order functions defining nested components or hooks. ' + 'Components and hooks should be defined at the module level', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.FBT: { @@ -798,7 +817,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { severity: ErrorSeverity.Error, name: 'fbt', description: 'Validates usage of fbt', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.Fire: { @@ -807,7 +826,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { severity: ErrorSeverity.Error, name: 'fire', description: 'Validates usage of `fire`', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.Gating: { @@ -817,7 +836,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'gating', description: 'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.Globals: { @@ -828,7 +847,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { description: 'Validates against assignment/mutation of globals during render, part of ensuring that ' + '[side effects must render outside of render](https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.Hooks: { @@ -842,7 +861,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { * We need to dedeupe these (moving the remaining bits into the compiler) and then enable * this rule. */ - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.Immutability: { @@ -852,7 +871,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'immutability', description: 'Validates against mutating props, state, and other values that [are immutable](https://react.dev/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable)', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.Invariant: { @@ -861,7 +880,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { severity: ErrorSeverity.Error, name: 'invariant', description: 'Internal invariants', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.PreserveManualMemo: { @@ -873,7 +892,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { 'Validates that existing manual memoized is preserved by the compiler. ' + 'React Compiler will only compile components and hooks if its inference ' + '[matches or exceeds the existing manual memoization](https://react.dev/learn/react-compiler/introduction#what-should-i-do-about-usememo-usecallback-and-reactmemo)', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.Purity: { @@ -883,7 +902,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'purity', description: 'Validates that [components/hooks are pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) by checking that they do not call known-impure functions', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.Refs: { @@ -893,7 +912,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'refs', description: 'Validates correct usage of refs, not reading/writing during render. See the "pitfalls" section in [`useRef()` usage](https://react.dev/reference/react/useRef#usage)', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.RenderSetState: { @@ -903,7 +922,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'set-state-in-render', description: 'Validates against setting state during render, which can trigger additional renders and potential infinite render loops', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.StaticComponents: { @@ -913,7 +932,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'static-components', description: 'Validates that components are static, not recreated every render. Components that are recreated dynamically can reset state and trigger excessive re-rendering', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.Suppression: { @@ -922,7 +941,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { severity: ErrorSeverity.Error, name: 'rule-suppression', description: 'Validates against suppression of other rules', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.Syntax: { @@ -931,7 +950,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { severity: ErrorSeverity.Error, name: 'syntax', description: 'Validates against invalid syntax', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.Todo: { @@ -940,7 +959,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { severity: ErrorSeverity.Hint, name: 'todo', description: 'Unimplemented features', - recommended: false, + preset: LintRulePreset.Off, }; } case ErrorCategory.UnsupportedSyntax: { @@ -950,7 +969,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'unsupported-syntax', description: 'Validates against syntax that we do not plan to support in React Compiler', - recommended: true, + preset: LintRulePreset.Recommended, }; } case ErrorCategory.UseMemo: { @@ -960,7 +979,17 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'use-memo', description: 'Validates usage of the useMemo() hook against common mistakes. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.', - recommended: true, + preset: LintRulePreset.Recommended, + }; + } + case ErrorCategory.VoidUseMemo: { + return { + category, + severity: ErrorSeverity.Error, + name: 'void-use-memo', + description: + 'Validates that useMemos always return a value. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.', + preset: LintRulePreset.RecommendedLatest, }; } case ErrorCategory.IncompatibleLibrary: { @@ -970,7 +999,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { name: 'incompatible-library', description: 'Validates against usage of libraries which are incompatible with memoization (manual or automatic)', - recommended: true, + preset: LintRulePreset.Recommended, }; } default: { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts index 3eaeb5e4aa037..f86747618dd59 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts @@ -454,7 +454,7 @@ export function dropManualMemoization( if (!hasNonVoidReturn(funcToCheck.loweredFunc.func)) { errors.pushDiagnostic( CompilerDiagnostic.create({ - category: ErrorCategory.UseMemo, + category: ErrorCategory.VoidUseMemo, reason: 'useMemo() callbacks must return a value', description: `This ${ manualMemo.loadInstr.value.kind === 'PropertyLoad' diff --git a/compiler/packages/babel-plugin-react-compiler/src/index.ts b/compiler/packages/babel-plugin-react-compiler/src/index.ts index c5d8c4cb6e86e..d2abd744d6b48 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/index.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/index.ts @@ -14,6 +14,7 @@ export { ErrorSeverity, ErrorCategory, LintRules, + LintRulePreset, type CompilerErrorDetailOptions, type CompilerDiagnosticOptions, type CompilerDiagnosticDetail, diff --git a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts index 7dacbe6d19074..8f41b3afaba43 100644 --- a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts +++ b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts @@ -15,6 +15,7 @@ import type {Linter, Rule} from 'eslint'; import runReactCompiler, {RunCacheEntry} from '../shared/RunReactCompiler'; import { ErrorSeverity, + LintRulePreset, LintRules, type LintRule, } from 'babel-plugin-react-compiler/src/CompilerError'; @@ -150,7 +151,7 @@ function makeRule(rule: LintRule): Rule.RuleModule { type: 'problem', docs: { description: rule.description, - recommended: rule.recommended, + recommended: rule.preset === LintRulePreset.Recommended, }, fixable: 'code', hasSuggestions: true, @@ -171,7 +172,16 @@ export const allRules: RulesConfig = LintRules.reduce((acc, rule) => { }, {} as RulesConfig); export const recommendedRules: RulesConfig = LintRules.filter( - rule => rule.recommended, + rule => rule.preset === LintRulePreset.Recommended, +).reduce((acc, rule) => { + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; + return acc; +}, {} as RulesConfig); + +export const recommendedLatestRules: RulesConfig = LintRules.filter( + rule => + rule.preset === LintRulePreset.Recommended || + rule.preset === LintRulePreset.RecommendedLatest, ).reduce((acc, rule) => { acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; return acc; diff --git a/fixtures/eslint-v6/.eslintrc.json b/fixtures/eslint-v6/.eslintrc.json index f76a20fea576e..672da7a085a64 100644 --- a/fixtures/eslint-v6/.eslintrc.json +++ b/fixtures/eslint-v6/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "extends": ["plugin:react-hooks/recommended-latest-legacy"], + "extends": ["plugin:react-hooks/recommended"], "parserOptions": { "ecmaVersion": 2020, "sourceType": "module", diff --git a/fixtures/eslint-v7/.eslintrc.json b/fixtures/eslint-v7/.eslintrc.json index f76a20fea576e..672da7a085a64 100644 --- a/fixtures/eslint-v7/.eslintrc.json +++ b/fixtures/eslint-v7/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "extends": ["plugin:react-hooks/recommended-latest-legacy"], + "extends": ["plugin:react-hooks/recommended"], "parserOptions": { "ecmaVersion": 2020, "sourceType": "module", diff --git a/fixtures/eslint-v8/.eslintrc.json b/fixtures/eslint-v8/.eslintrc.json index f76a20fea576e..672da7a085a64 100644 --- a/fixtures/eslint-v8/.eslintrc.json +++ b/fixtures/eslint-v8/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "extends": ["plugin:react-hooks/recommended-latest-legacy"], + "extends": ["plugin:react-hooks/recommended"], "parserOptions": { "ecmaVersion": 2020, "sourceType": "module", diff --git a/packages/eslint-plugin-react-hooks/CHANGELOG.md b/packages/eslint-plugin-react-hooks/CHANGELOG.md index cd376cd4dca04..0aba9e00561f7 100644 --- a/packages/eslint-plugin-react-hooks/CHANGELOG.md +++ b/packages/eslint-plugin-react-hooks/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.0.0 + +This release slims down presets to just 2 configurations (`recommended` and `recommended-latest`), and all compiler rules are enabled by default. + +- **Breaking:** Removed `recommended-latest-legacy` and `flat/recommended` configs. The plugin now provides `recommended` (legacy and flat configs with all recommended rules), and `recommended-latest` (legacy and flat configs with all recommended rules plus new bleeding edge experimental compiler rules). ([@poteto](https://github.com/poteto) in [#34757](https://github.com/facebook/react/pull/34757)) + ## 6.1.1 **Note:** 6.1.0 accidentally allowed use of `recommended` without flat config, causing errors when used with ESLint v9's `defineConfig()` helper. This has been fixed in 6.1.1. diff --git a/packages/eslint-plugin-react-hooks/README.md b/packages/eslint-plugin-react-hooks/README.md index afd89ab2263ac..a1b4bcabb59fd 100644 --- a/packages/eslint-plugin-react-hooks/README.md +++ b/packages/eslint-plugin-react-hooks/README.md @@ -4,8 +4,6 @@ The official ESLint plugin for [React](https://react.dev) which enforces the [Ru ## Installation -**Note: If you're using Create React App, please use `react-scripts` >= 3 instead of adding it directly.** - Assuming you already have ESLint installed, run: ```sh @@ -18,9 +16,7 @@ yarn add eslint-plugin-react-hooks --dev ### Flat Config (eslint.config.js|ts) -#### >= 6.0.0 - -For users of 6.0 and beyond, add the `recommended` config. +Add the `recommended` config for all recommended rules: ```js // eslint.config.js @@ -28,61 +24,32 @@ import reactHooks from 'eslint-plugin-react-hooks'; import { defineConfig } from 'eslint/config'; export default defineConfig([ - { - files: ["src/**/*.{js,jsx,ts,tsx}"], - plugins: { - 'react-hooks': reactHooks, - }, - extends: ['react-hooks/recommended'], - }, + reactHooks.configs.flat.recommended, ]); ``` -#### 5.2.0 - -For users of 5.2.0 (the first version with flat config support), add the `recommended-latest` config. +If you want to try bleeding edge experimental compiler rules, use `recommended-latest`. ```js +// eslint.config.js import reactHooks from 'eslint-plugin-react-hooks'; import { defineConfig } from 'eslint/config'; export default defineConfig([ - { - files: ["src/**/*.{js,jsx,ts,tsx}"], - plugins: { - 'react-hooks': reactHooks, - }, - extends: ['react-hooks/recommended-latest'], - }, + reactHooks.configs.flat['recommended-latest'], ]); ``` ### Legacy Config (.eslintrc) -#### >= 5.2.0 - -If you are still using ESLint below 9.0.0, you can use `recommended-legacy` for accessing a legacy version of the recommended config. +If you are still using ESLint below 9.0.0, the `recommended` preset can also be used to enable all recommended rules. ```js { - "extends": [ - // ... - "plugin:react-hooks/recommended-legacy" - ] + "extends": ["plugin:react-hooks/recommended"], + // ... } -``` - -#### < 5.2.0 - -If you're using a version earlier than 5.2.0, the legacy config was simply `recommended`. -```js -{ - "extends": [ - // ... - "plugin:react-hooks/recommended" - ] -} ``` ### Custom Configuration @@ -92,7 +59,7 @@ If you want more fine-grained configuration, you can instead choose to enable sp #### Flat Config (eslint.config.js|ts) ```js -import * as reactHooks from 'eslint-plugin-react-hooks'; +import reactHooks from 'eslint-plugin-react-hooks'; export default [ { @@ -100,8 +67,26 @@ export default [ plugins: { 'react-hooks': reactHooks }, // ... rules: { + // Core hooks rules 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn', + + // React Compiler rules + 'react-hooks/config': 'error', + 'react-hooks/error-boundaries': 'error', + 'react-hooks/component-hook-factories': 'error', + 'react-hooks/gating': 'error', + 'react-hooks/globals': 'error', + 'react-hooks/immutability': 'error', + 'react-hooks/preserve-manual-memoization': 'error', + 'react-hooks/purity': 'error', + 'react-hooks/refs': 'error', + 'react-hooks/set-state-in-effect': 'error', + 'react-hooks/set-state-in-render': 'error', + 'react-hooks/static-components': 'error', + 'react-hooks/unsupported-syntax': 'warn', + 'react-hooks/use-memo': 'error', + 'react-hooks/incompatible-library': 'warn', } }, ]; @@ -116,8 +101,26 @@ export default [ ], "rules": { // ... + // Core hooks rules "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "warn" + "react-hooks/exhaustive-deps": "warn", + + // React Compiler rules + "react-hooks/config": "error", + "react-hooks/error-boundaries": "error", + "react-hooks/component-hook-factories": "error", + "react-hooks/gating": "error", + "react-hooks/globals": "error", + "react-hooks/immutability": "error", + "react-hooks/preserve-manual-memoization": "error", + "react-hooks/purity": "error", + "react-hooks/refs": "error", + "react-hooks/set-state-in-effect": "error", + "react-hooks/set-state-in-render": "error", + "react-hooks/static-components": "error", + "react-hooks/unsupported-syntax": "warn", + "react-hooks/use-memo": "error", + "react-hooks/incompatible-library": "warn" } } ``` diff --git a/packages/eslint-plugin-react-hooks/package.json b/packages/eslint-plugin-react-hooks/package.json index ea39fb4903247..a22448f11c78f 100644 --- a/packages/eslint-plugin-react-hooks/package.json +++ b/packages/eslint-plugin-react-hooks/package.json @@ -1,7 +1,7 @@ { "name": "eslint-plugin-react-hooks", "description": "ESLint rules for React Hooks", - "version": "5.2.0", + "version": "7.0.0", "repository": { "type": "git", "url": "https://github.com/facebook/react.git", diff --git a/packages/eslint-plugin-react-hooks/src/index.ts b/packages/eslint-plugin-react-hooks/src/index.ts index 838b1081a7ef8..6d72c1daa57a9 100644 --- a/packages/eslint-plugin-react-hooks/src/index.ts +++ b/packages/eslint-plugin-react-hooks/src/index.ts @@ -11,6 +11,7 @@ import { allRules, mapErrorSeverityToESlint, recommendedRules, + recommendedLatestRules, } from './shared/ReactCompiler'; import RulesOfHooks from './rules/RulesOfHooks'; @@ -27,7 +28,7 @@ const basicRuleConfigs = { 'react-hooks/exhaustive-deps': 'warn', } as const satisfies Linter.RulesRecord; -const compilerRuleConfigs = Object.fromEntries( +const recommendedCompilerRuleConfigs = Object.fromEntries( Object.entries(recommendedRules).map(([name, ruleConfig]) => { return [ `react-hooks/${name}` as const, @@ -36,38 +37,39 @@ const compilerRuleConfigs = Object.fromEntries( }), ) as Record<`react-hooks/${string}`, Linter.RuleEntry>; -const allRuleConfigs: Linter.RulesRecord = { +const recommendedLatestCompilerRuleConfigs = Object.fromEntries( + Object.entries(recommendedLatestRules).map(([name, ruleConfig]) => { + return [ + `react-hooks/${name}` as const, + mapErrorSeverityToESlint(ruleConfig.severity), + ] as const; + }), +) as Record<`react-hooks/${string}`, Linter.RuleEntry>; + +const recommendedRuleConfigs: Linter.RulesRecord = { + ...basicRuleConfigs, + ...recommendedCompilerRuleConfigs, +}; +const recommendedLatestRuleConfigs: Linter.RulesRecord = { ...basicRuleConfigs, - ...compilerRuleConfigs, + ...recommendedLatestCompilerRuleConfigs, }; const plugins = ['react-hooks']; type ReactHooksFlatConfig = { - plugins: Record; + plugins: {react: any}; rules: Linter.RulesRecord; }; const configs = { - 'recommended-legacy': { - plugins, - rules: basicRuleConfigs, - }, - 'recommended-latest-legacy': { - plugins, - rules: allRuleConfigs, - }, - 'flat/recommended': { + recommended: { plugins, - rules: basicRuleConfigs, + rules: recommendedRuleConfigs, }, 'recommended-latest': { plugins, - rules: allRuleConfigs, - }, - recommended: { - plugins, - rules: basicRuleConfigs, + rules: recommendedLatestRuleConfigs, }, flat: {} as Record, }; @@ -75,24 +77,13 @@ const configs = { const plugin = { meta: { name: 'eslint-plugin-react-hooks', + version: '7.0.0', }, rules, configs, }; Object.assign(configs.flat, { - 'recommended-legacy': { - plugins: {'react-hooks': plugin}, - rules: configs['recommended-legacy'].rules, - }, - 'recommended-latest-legacy': { - plugins: {'react-hooks': plugin}, - rules: configs['recommended-latest-legacy'].rules, - }, - 'flat/recommended': { - plugins: {'react-hooks': plugin}, - rules: configs['flat/recommended'].rules, - }, 'recommended-latest': { plugins: {'react-hooks': plugin}, rules: configs['recommended-latest'].rules, diff --git a/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts b/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts index cdb3af38489d4..854e26149f7bc 100644 --- a/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts +++ b/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts @@ -14,6 +14,7 @@ import { LintRules, type LintRule, ErrorSeverity, + LintRulePreset, } from 'babel-plugin-react-compiler'; import {type Linter, type Rule} from 'eslint'; import runReactCompiler, {RunCacheEntry} from './RunReactCompiler'; @@ -149,7 +150,7 @@ function makeRule(rule: LintRule): Rule.RuleModule { type: 'problem', docs: { description: rule.description, - recommended: rule.recommended, + recommended: rule.preset === LintRulePreset.Recommended, }, fixable: 'code', hasSuggestions: true, @@ -164,23 +165,26 @@ type RulesConfig = { [name: string]: {rule: Rule.RuleModule; severity: ErrorSeverity}; }; -export const allRules: RulesConfig = LintRules.reduce( - (acc, rule) => { - acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; - return acc; - }, - {} as RulesConfig, -); +export const allRules: RulesConfig = LintRules.reduce((acc, rule) => { + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; + return acc; +}, {} as RulesConfig); export const recommendedRules: RulesConfig = LintRules.filter( - rule => rule.recommended, -).reduce( - (acc, rule) => { - acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; - return acc; - }, - {} as RulesConfig, -); + rule => rule.preset === LintRulePreset.Recommended, +).reduce((acc, rule) => { + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; + return acc; +}, {} as RulesConfig); + +export const recommendedLatestRules: RulesConfig = LintRules.filter( + rule => + rule.preset === LintRulePreset.Recommended || + rule.preset === LintRulePreset.RecommendedLatest, +).reduce((acc, rule) => { + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; + return acc; +}, {} as RulesConfig); export function mapErrorSeverityToESlint( severity: ErrorSeverity,