@samitouri / QOS-React / commits / ca12911d1f

feat(eslint-plugin-react-hooks): make flat config the `recommended` config (#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 <poteto@users.noreply.github.com>

michael faith committed Feb 28, 2025 at 10:22 UTC ca12911d1fbe755b9b2b7d1bf548589317311a82
6 files changed +91 -91
fixtures/eslint-v9/eslint.config.ts renamed
+3 -2
@@ -1,3 +1,4 @@
1 +import type {Linter} from 'eslint';
2 import * as reactHooks from 'eslint-plugin-react-hooks';
3
4 export default [
@@ -12,10 +13,10 @@ export default [
13 },
14 },
15 },
15 - reactHooks.configs['recommended-latest'],
16 + reactHooks.configs['recommended'],
17 {
18 rules: {
19 'react-hooks/exhaustive-deps': 'error',
20 },
21 },
21 -];
22 +] satisfies Linter.Config[];
fixtures/eslint-v9/package.json
+3 -2
@@ -2,8 +2,9 @@
2 "private": true,
3 "name": "eslint-v9",
4 "dependencies": {
5 - "eslint": "^9",
6 - "eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks"
5 + "eslint": "^9.18.0",
6 + "eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks",
7 + "jiti": "^2.4.2"
8 },
9 "scripts": {
10 "build": "node build.mjs && yarn",
fixtures/eslint-v9/tsconfig.json new
+2
@@ -0,0 +1,2 @@
1 +{
2 +}
fixtures/eslint-v9/yarn.lock
+37 -39
@@ -14,7 +14,7 @@
14 resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
15 integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
16
17 -"@eslint/config-array@^0.19.0":
17 +"@eslint/config-array@^0.19.2":
18 version "0.19.2"
19 resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa"
20 integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==
@@ -23,24 +23,17 @@
23 debug "^4.3.1"
24 minimatch "^3.1.2"
25
26 -"@eslint/core@^0.10.0":
27 - version "0.10.0"
28 - resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.10.0.tgz#23727063c21b335f752dbb3a16450f6f9cbc9091"
29 - integrity sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==
26 +"@eslint/core@^0.12.0":
27 + version "0.12.0"
28 + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.12.0.tgz#5f960c3d57728be9f6c65bd84aa6aa613078798e"
29 + integrity sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==
30 dependencies:
31 "@types/json-schema" "^7.0.15"
32
33 -"@eslint/core@^0.11.0":
34 - version "0.11.0"
35 - resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.11.0.tgz#7a9226e850922e42cbd2ba71361eacbe74352a12"
36 - integrity sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==
37 - dependencies:
38 - "@types/json-schema" "^7.0.15"
39 -
40 -"@eslint/eslintrc@^3.2.0":
41 - version "3.2.0"
42 - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c"
43 - integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==
33 +"@eslint/eslintrc@^3.3.0":
34 + version "3.3.0"
35 + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.0.tgz#96a558f45842989cca7ea1ecd785ad5491193846"
36 + integrity sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==
37 dependencies:
38 ajv "^6.12.4"
39 debug "^4.3.2"
@@ -52,22 +45,22 @@
45 minimatch "^3.1.2"
46 strip-json-comments "^3.1.1"
47
55 -"@eslint/js@9.20.0":
56 - version "9.20.0"
57 - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4"
58 - integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==
48 +"@eslint/js@9.21.0":
49 + version "9.21.0"
50 + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.21.0.tgz#4303ef4e07226d87c395b8fad5278763e9c15c08"
51 + integrity sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==
52
53 "@eslint/object-schema@^2.1.6":
54 version "2.1.6"
55 resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f"
56 integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==
57
65 -"@eslint/plugin-kit@^0.2.5":
66 - version "0.2.5"
67 - resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz#ee07372035539e7847ef834e3f5e7b79f09e3a81"
68 - integrity sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==
58 +"@eslint/plugin-kit@^0.2.7":
59 + version "0.2.7"
60 + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz#9901d52c136fb8f375906a73dcc382646c3b6a27"
61 + integrity sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==
62 dependencies:
70 - "@eslint/core" "^0.10.0"
63 + "@eslint/core" "^0.12.0"
64 levn "^0.4.1"
65
66 "@humanfs/core@^0.19.1":
@@ -93,10 +86,10 @@
86 resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
87 integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
88
96 -"@humanwhocodes/retry@^0.4.1":
97 - version "0.4.1"
98 - resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
99 - integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
89 +"@humanwhocodes/retry@^0.4.2":
90 + version "0.4.2"
91 + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.2.tgz#1860473de7dfa1546767448f333db80cb0ff2161"
92 + integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==
93
94 "@types/estree@^1.0.6":
95 version "1.0.6"
@@ -231,21 +224,21 @@ eslint-visitor-keys@^4.2.0:
224 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
225 integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
226
234 -eslint@^9:
235 - version "9.20.1"
236 - resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.20.1.tgz#923924c078f5226832449bac86662dd7e53c91d6"
237 - integrity sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==
227 +eslint@^9.18.0:
228 + version "9.21.0"
229 + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.21.0.tgz#b1c9c16f5153ff219791f627b94ab8f11f811591"
230 + integrity sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==
231 dependencies:
232 "@eslint-community/eslint-utils" "^4.2.0"
233 "@eslint-community/regexpp" "^4.12.1"
241 - "@eslint/config-array" "^0.19.0"
242 - "@eslint/core" "^0.11.0"
243 - "@eslint/eslintrc" "^3.2.0"
244 - "@eslint/js" "9.20.0"
245 - "@eslint/plugin-kit" "^0.2.5"
234 + "@eslint/config-array" "^0.19.2"
235 + "@eslint/core" "^0.12.0"
236 + "@eslint/eslintrc" "^3.3.0"
237 + "@eslint/js" "9.21.0"
238 + "@eslint/plugin-kit" "^0.2.7"
239 "@humanfs/node" "^0.16.6"
240 "@humanwhocodes/module-importer" "^1.0.1"
248 - "@humanwhocodes/retry" "^0.4.1"
241 + "@humanwhocodes/retry" "^0.4.2"
242 "@types/estree" "^1.0.6"
243 "@types/json-schema" "^7.0.15"
244 ajv "^6.12.4"
@@ -399,6 +392,11 @@ isexe@^2.0.0:
392 resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
393 integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
394
395 +jiti@^2.4.2:
396 + version "2.4.2"
397 + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560"
398 + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==
399 +
400 js-yaml@^4.1.0:
401 version "4.1.0"
402 resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
packages/eslint-plugin-react-hooks/README.md
+29 -30
@@ -18,9 +18,22 @@ npm install eslint-plugin-react-hooks --save-dev
18 yarn add eslint-plugin-react-hooks --dev
19 ```
20
21 +### Flat Config (eslint.config.js|ts)
22 +
23 +For [ESLint 9.0.0 and above](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/), add the `recommended` config.
24 +
25 +```js
26 +import * as reactHooks from 'eslint-plugin-react-hooks';
27 +
28 +export default [
29 + // ...
30 + reactHooks.configs['recommended'],
31 +];
32 +```
33 +
34 ### Legacy Config (.eslintrc)
35
23 -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.
36 +If you are still using ESLint below 9.0.0, you can use `recommended-legacy` for accessing the recommended config.
37
38 ```js
39 {
@@ -31,25 +44,29 @@ If you are still using ESLint below 9.0.0, please continue to use `recommended-l
44 }
45 ```
46
34 -### Flat Config (eslint.config.js)
47 +### Custom Configuration
48
36 -For [ESLint 9.0.0 and above](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/) users, add the `recommended-latest` config.
49 +If you want more fine-grained configuration, you can instead add a snippet like this to your ESLint configuration file:
50 +
51 +#### Flat Config (eslint.config.js|ts)
52
53 ```js
54 import * as reactHooks from 'eslint-plugin-react-hooks';
55
56 export default [
42 - // ...
43 - reactHooks.configs['recommended-latest'],
57 + {
58 + files: ['**/*.{js,jsx}'],
59 + plugins: { 'react-hooks': reactHooks },
60 + // ...
61 + rules: {
62 + 'react-hooks/rules-of-hooks': 'error',
63 + 'react-hooks/exhaustive-deps': 'warn',
64 + }
65 + },
66 ];
67 ```
68
47 -### Custom Configuration
48 -
49 -If you want more fine-grained configuration, you can instead add a snippet like this to your ESLint configuration file:
50 -
69 #### Legacy Config (.eslintrc)
52 -
70 ```js
71 {
72 "plugins": [
@@ -64,24 +81,6 @@ If you want more fine-grained configuration, you can instead add a snippet like
81 }
82 ```
83
67 -#### Flat Config (eslint.config.js)
68 -
69 -```js
70 -import * as reactHooks from 'eslint-plugin-react-hooks';
71 -
72 -export default [
73 - {
74 - files: ['**/*.{js,jsx}'],
75 - plugins: { 'react-hooks': reactHooks },
76 - // ...
77 - rules: {
78 - 'react-hooks/rules-of-hooks': 'error',
79 - 'react-hooks/exhaustive-deps': 'warn',
80 - }
81 - },
82 -];
83 -```
84 -
84 ## Advanced Configuration
85
86 `exhaustive-deps` can be configured to validate dependencies of custom Hooks with the `additionalHooks` option.
@@ -89,10 +88,10 @@ This option accepts a regex to match the names of custom Hooks that have depende
88
89 ```js
90 {
92 - "rules": {
91 + rules: {
92 // ...
93 "react-hooks/exhaustive-deps": ["warn", {
95 - "additionalHooks": "(useMyCustomHook|useMyOtherCustomHook)"
94 + additionalHooks: "(useMyCustomHook|useMyOtherCustomHook)"
95 }]
96 }
97 }
packages/eslint-plugin-react-hooks/src/index.ts
+17 -18
@@ -20,11 +20,16 @@ const configRules = {
20 'react-hooks/exhaustive-deps': 'warn',
21 } satisfies Linter.RulesRecord;
22
23 -// Legacy config
24 -const legacyRecommendedConfig = {
25 - plugins: ['react-hooks'],
23 +// Flat config
24 +const recommendedConfig = {
25 + name: 'react-hooks/recommended',
26 + plugins: {
27 + get 'react-hooks'(): ESLint.Plugin {
28 + return plugin;
29 + },
30 + },
31 rules: configRules,
27 -} satisfies Linter.LegacyConfig;
32 +};
33
34 // Plugin object
35 const plugin = {
@@ -34,24 +39,18 @@ const plugin = {
39 rules,
40 configs: {
41 /** Legacy recommended config, to be used with rc-based configurations */
37 - 'recommended-legacy': legacyRecommendedConfig,
42 + 'recommended-legacy': {
43 + plugins: ['react-hooks'],
44 + rules: configRules,
45 + },
46
47 /**
40 - * 'recommended' is currently aliased to the legacy / rc recommended config) to maintain backwards compatibility.
41 - * This is deprecated and in v6, it will switch to alias the flat recommended config.
48 + * Recommended config, to be used with flat configs.
49 */
43 - recommended: legacyRecommendedConfig,
50 + recommended: recommendedConfig,
51
45 - /** Latest recommended config, to be used with flat configurations */
46 - 'recommended-latest': {
47 - name: 'react-hooks/recommended',
48 - plugins: {
49 - get 'react-hooks'(): ESLint.Plugin {
50 - return plugin;
51 - },
52 - },
53 - rules: configRules,
54 - },
52 + /** @deprecated please use `recommended`; will be removed in v7 */
53 + 'recommended-latest': recommendedConfig,
54 },
55 } satisfies ESLint.Plugin;
56