Skip to content

Commit

Permalink
feat(eslint-plugin-react-hooks): make flat config the recommended c…
Browse files Browse the repository at this point in the history
…onfig (#32457)

This change swaps which config `recommended` is aliasing. In 5.2.0, the
new flat config was introduced as `recommended-latest`, while
`recommended` still pointed at the legacy rc-based config, with a note
that in the next major version `recommended` would be updated to point
at `recommend-latest`. This change makes that swap, and make the default
`recommended` experience the flat config. To continue using the legacy
rc recommended config, please make the following change in your config

```diff
- extends: ['plugin:react-hooks/recommended']
+ extends: ['plugin:react-hooks/recommended-legacy']
```

This change also deprecates `recommended-latest` in favor of
`recommended`. `recommended-latest` will be removed in a future major
version.

The README has been updated to reflect the new usage, and to put the
flat config sections before the legacy config sections.

I also took the opportunity to change the v9 fixture to use a typescript
config, serving as a demonstration for usage as well as a way to
validate the types are correct.

BREAKING CHANGE

---------

Co-authored-by: lauren <[email protected]>
  • Loading branch information
michaelfaith and poteto authored Feb 28, 2025
1 parent d55cc79 commit ca12911
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 91 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type {Linter} from 'eslint';
import * as reactHooks from 'eslint-plugin-react-hooks';

export default [
Expand All @@ -12,10 +13,10 @@ export default [
},
},
},
reactHooks.configs['recommended-latest'],
reactHooks.configs['recommended'],
{
rules: {
'react-hooks/exhaustive-deps': 'error',
},
},
];
] satisfies Linter.Config[];
5 changes: 3 additions & 2 deletions fixtures/eslint-v9/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
"private": true,
"name": "eslint-v9",
"dependencies": {
"eslint": "^9",
"eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks"
"eslint": "^9.18.0",
"eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks",
"jiti": "^2.4.2"
},
"scripts": {
"build": "node build.mjs && yarn",
Expand Down
2 changes: 2 additions & 0 deletions fixtures/eslint-v9/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
76 changes: 37 additions & 39 deletions fixtures/eslint-v9/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==

"@eslint/config-array@^0.19.0":
"@eslint/config-array@^0.19.2":
version "0.19.2"
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa"
integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==
Expand All @@ -23,24 +23,17 @@
debug "^4.3.1"
minimatch "^3.1.2"

"@eslint/core@^0.10.0":
version "0.10.0"
resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.10.0.tgz#23727063c21b335f752dbb3a16450f6f9cbc9091"
integrity sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==
"@eslint/core@^0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.12.0.tgz#5f960c3d57728be9f6c65bd84aa6aa613078798e"
integrity sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==
dependencies:
"@types/json-schema" "^7.0.15"

"@eslint/core@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.11.0.tgz#7a9226e850922e42cbd2ba71361eacbe74352a12"
integrity sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==
dependencies:
"@types/json-schema" "^7.0.15"

"@eslint/eslintrc@^3.2.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c"
integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==
"@eslint/eslintrc@^3.3.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.0.tgz#96a558f45842989cca7ea1ecd785ad5491193846"
integrity sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
Expand All @@ -52,22 +45,22 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"

"@eslint/js@9.20.0":
version "9.20.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4"
integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==
"@eslint/js@9.21.0":
version "9.21.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.21.0.tgz#4303ef4e07226d87c395b8fad5278763e9c15c08"
integrity sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==

"@eslint/object-schema@^2.1.6":
version "2.1.6"
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f"
integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==

"@eslint/plugin-kit@^0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz#ee07372035539e7847ef834e3f5e7b79f09e3a81"
integrity sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==
"@eslint/plugin-kit@^0.2.7":
version "0.2.7"
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz#9901d52c136fb8f375906a73dcc382646c3b6a27"
integrity sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==
dependencies:
"@eslint/core" "^0.10.0"
"@eslint/core" "^0.12.0"
levn "^0.4.1"

"@humanfs/core@^0.19.1":
Expand All @@ -93,10 +86,10 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==

"@humanwhocodes/retry@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
"@humanwhocodes/retry@^0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.2.tgz#1860473de7dfa1546767448f333db80cb0ff2161"
integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==

"@types/estree@^1.0.6":
version "1.0.6"
Expand Down Expand Up @@ -231,21 +224,21 @@ eslint-visitor-keys@^4.2.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==

eslint@^9:
version "9.20.1"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.20.1.tgz#923924c078f5226832449bac86662dd7e53c91d6"
integrity sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==
eslint@^9.18.0:
version "9.21.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.21.0.tgz#b1c9c16f5153ff219791f627b94ab8f11f811591"
integrity sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.12.1"
"@eslint/config-array" "^0.19.0"
"@eslint/core" "^0.11.0"
"@eslint/eslintrc" "^3.2.0"
"@eslint/js" "9.20.0"
"@eslint/plugin-kit" "^0.2.5"
"@eslint/config-array" "^0.19.2"
"@eslint/core" "^0.12.0"
"@eslint/eslintrc" "^3.3.0"
"@eslint/js" "9.21.0"
"@eslint/plugin-kit" "^0.2.7"
"@humanfs/node" "^0.16.6"
"@humanwhocodes/module-importer" "^1.0.1"
"@humanwhocodes/retry" "^0.4.1"
"@humanwhocodes/retry" "^0.4.2"
"@types/estree" "^1.0.6"
"@types/json-schema" "^7.0.15"
ajv "^6.12.4"
Expand Down Expand Up @@ -399,6 +392,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==

jiti@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560"
integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==

js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
Expand Down
59 changes: 29 additions & 30 deletions packages/eslint-plugin-react-hooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,22 @@ npm install eslint-plugin-react-hooks --save-dev
yarn add eslint-plugin-react-hooks --dev
```

### Flat Config (eslint.config.js|ts)

For [ESLint 9.0.0 and above](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/), add the `recommended` config.

```js
import * as reactHooks from 'eslint-plugin-react-hooks';

export default [
// ...
reactHooks.configs['recommended'],
];
```

### Legacy Config (.eslintrc)

If you are still using ESLint below 9.0.0, please continue to use `recommended-legacy`. To avoid breaking changes, we still support `recommended` as well, but note that this will be changed to alias the flat recommended config in v6.
If you are still using ESLint below 9.0.0, you can use `recommended-legacy` for accessing the recommended config.

```js
{
Expand All @@ -31,25 +44,29 @@ If you are still using ESLint below 9.0.0, please continue to use `recommended-l
}
```

### Flat Config (eslint.config.js)
### Custom Configuration

For [ESLint 9.0.0 and above](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/) users, add the `recommended-latest` config.
If you want more fine-grained configuration, you can instead add a snippet like this to your ESLint configuration file:

#### Flat Config (eslint.config.js|ts)

```js
import * as reactHooks from 'eslint-plugin-react-hooks';

export default [
// ...
reactHooks.configs['recommended-latest'],
{
files: ['**/*.{js,jsx}'],
plugins: { 'react-hooks': reactHooks },
// ...
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
}
},
];
```

### Custom Configuration

If you want more fine-grained configuration, you can instead add a snippet like this to your ESLint configuration file:

#### Legacy Config (.eslintrc)

```js
{
"plugins": [
Expand All @@ -64,35 +81,17 @@ If you want more fine-grained configuration, you can instead add a snippet like
}
```

#### Flat Config (eslint.config.js)

```js
import * as reactHooks from 'eslint-plugin-react-hooks';

export default [
{
files: ['**/*.{js,jsx}'],
plugins: { 'react-hooks': reactHooks },
// ...
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
}
},
];
```

## Advanced Configuration

`exhaustive-deps` can be configured to validate dependencies of custom Hooks with the `additionalHooks` option.
This option accepts a regex to match the names of custom Hooks that have dependencies.

```js
{
"rules": {
rules: {
// ...
"react-hooks/exhaustive-deps": ["warn", {
"additionalHooks": "(useMyCustomHook|useMyOtherCustomHook)"
additionalHooks: "(useMyCustomHook|useMyOtherCustomHook)"
}]
}
}
Expand Down
35 changes: 17 additions & 18 deletions packages/eslint-plugin-react-hooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ const configRules = {
'react-hooks/exhaustive-deps': 'warn',
} satisfies Linter.RulesRecord;

// Legacy config
const legacyRecommendedConfig = {
plugins: ['react-hooks'],
// Flat config
const recommendedConfig = {
name: 'react-hooks/recommended',
plugins: {
get 'react-hooks'(): ESLint.Plugin {
return plugin;
},
},
rules: configRules,
} satisfies Linter.LegacyConfig;
};

// Plugin object
const plugin = {
Expand All @@ -34,24 +39,18 @@ const plugin = {
rules,
configs: {
/** Legacy recommended config, to be used with rc-based configurations */
'recommended-legacy': legacyRecommendedConfig,
'recommended-legacy': {
plugins: ['react-hooks'],
rules: configRules,
},

/**
* 'recommended' is currently aliased to the legacy / rc recommended config) to maintain backwards compatibility.
* This is deprecated and in v6, it will switch to alias the flat recommended config.
* Recommended config, to be used with flat configs.
*/
recommended: legacyRecommendedConfig,
recommended: recommendedConfig,

/** Latest recommended config, to be used with flat configurations */
'recommended-latest': {
name: 'react-hooks/recommended',
plugins: {
get 'react-hooks'(): ESLint.Plugin {
return plugin;
},
},
rules: configRules,
},
/** @deprecated please use `recommended`; will be removed in v7 */
'recommended-latest': recommendedConfig,
},
} satisfies ESLint.Plugin;

Expand Down

0 comments on commit ca12911

Please sign in to comment.