From 88ee1f595572b1dcf8f45897cb115b4bbd1aefb8 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Mon, 15 Dec 2025 18:59:27 -0500 Subject: [PATCH] Add reporting modes for react-hooks/exhaustive-effect-dependencies and temporarily enable (#35365) `react-hooks/exhaustive-effect-dependencies` from `ValidateExhaustiveDeps` reports errors for both missing and extra effect deps. We already have `react-hooks/exhaustive-deps` that errors on missing dependencies. In the future we'd like to consolidate this all to the compiler based error, but for now there's a lot of overlap. Let's enable testing the extra dep warning by splitting out reporting modes. This PR - Creates `on`, `off`, `missing-only`, and `extra-only` reporting modes for the effect dep validation flag - Temporarily enables the new rule with `extra-only` in `eslint-plugin-react-hooks` - Adds additional null checking to `manualMemoLoc` to fix a bug found when running against the fixture --- .../src/HIR/Environment.ts | 9 +- .../ValidateExhaustiveDependencies.ts | 35 ++++++-- ...or.exhaustive-deps-effect-events.expect.md | 2 +- .../error.exhaustive-deps-effect-events.js | 2 +- ...xhaustive-effect-deps-extra-only.expect.md | 83 ++++++++++++++++++ ...valid-exhaustive-effect-deps-extra-only.js | 24 ++++++ ...austive-effect-deps-missing-only.expect.md | 84 +++++++++++++++++++ ...lid-exhaustive-effect-deps-missing-only.js | 24 ++++++ ...r.invalid-exhaustive-effect-deps.expect.md | 2 +- .../error.invalid-exhaustive-effect-deps.js | 2 +- ...ctive-stable-types-as-extra-deps.expect.md | 4 +- ...-nonreactive-stable-types-as-extra-deps.js | 2 +- .../exhaustive-deps-effect-events.expect.md | 4 +- .../exhaustive-deps-effect-events.js | 2 +- fixtures/eslint-v9/index.js | 13 +++ fixtures/eslint-v9/yarn.lock | 22 +++-- .../src/shared/RunReactCompiler.ts | 1 + 17 files changed, 293 insertions(+), 22 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-extra-only.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-extra-only.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-missing-only.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-missing-only.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 05105ae5973..d6c0e245b84 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -225,8 +225,15 @@ export const EnvironmentConfigSchema = z.object({ /** * Validate that dependencies supplied to effect hooks are exhaustive. + * Can be: + * - 'off': No validation (default) + * - 'all': Validate and report both missing and extra dependencies + * - 'missing-only': Only report missing dependencies + * - 'extra-only': Only report extra/unnecessary dependencies */ - validateExhaustiveEffectDependencies: z.boolean().default(false), + validateExhaustiveEffectDependencies: z + .enum(['off', 'all', 'missing-only', 'extra-only']) + .default('off'), /** * When this is true, rather than pruning existing manual memoization but ensuring or validating diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateExhaustiveDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateExhaustiveDependencies.ts index e364c025f38..e72de6c3a3e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateExhaustiveDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateExhaustiveDependencies.ts @@ -141,6 +141,7 @@ export function validateExhaustiveDependencies( reactive, startMemo.depsLoc, ErrorCategory.MemoDependencies, + 'all', ); if (diagnostic != null) { error.pushDiagnostic(diagnostic); @@ -159,7 +160,7 @@ export function validateExhaustiveDependencies( onStartMemoize, onFinishMemoize, onEffect: (inferred, manual, manualMemoLoc) => { - if (env.config.validateExhaustiveEffectDependencies === false) { + if (env.config.validateExhaustiveEffectDependencies === 'off') { return; } if (DEBUG) { @@ -195,12 +196,17 @@ export function validateExhaustiveDependencies( }); } } + const effectReportMode = + typeof env.config.validateExhaustiveEffectDependencies === 'string' + ? env.config.validateExhaustiveEffectDependencies + : 'all'; const diagnostic = validateDependencies( Array.from(inferred), manualDeps, reactive, manualMemoLoc, ErrorCategory.EffectExhaustiveDependencies, + effectReportMode, ); if (diagnostic != null) { error.pushDiagnostic(diagnostic); @@ -220,6 +226,7 @@ function validateDependencies( category: | ErrorCategory.MemoDependencies | ErrorCategory.EffectExhaustiveDependencies, + exhaustiveDepsReportMode: 'all' | 'missing-only' | 'extra-only', ): CompilerDiagnostic | null { // Sort dependencies by name and path, with shorter/non-optional paths first inferred.sort((a, b) => { @@ -370,9 +377,20 @@ function validateDependencies( extra.push(dep); } - if (missing.length !== 0 || extra.length !== 0) { + // Filter based on report mode + const filteredMissing = + exhaustiveDepsReportMode === 'extra-only' ? [] : missing; + const filteredExtra = + exhaustiveDepsReportMode === 'missing-only' ? [] : extra; + + if (filteredMissing.length !== 0 || filteredExtra.length !== 0) { let suggestion: CompilerSuggestion | null = null; - if (manualMemoLoc != null && typeof manualMemoLoc !== 'symbol') { + if ( + manualMemoLoc != null && + typeof manualMemoLoc !== 'symbol' && + manualMemoLoc.start.index != null && + manualMemoLoc.end.index != null + ) { suggestion = { description: 'Update dependencies', range: [manualMemoLoc.start.index, manualMemoLoc.end.index], @@ -388,8 +406,13 @@ function validateDependencies( .join(', ')}]`, }; } - const diagnostic = createDiagnostic(category, missing, extra, suggestion); - for (const dep of missing) { + const diagnostic = createDiagnostic( + category, + filteredMissing, + filteredExtra, + suggestion, + ); + for (const dep of filteredMissing) { let reactiveStableValueHint = ''; if (isStableType(dep.identifier)) { reactiveStableValueHint = @@ -402,7 +425,7 @@ function validateDependencies( loc: dep.loc, }); } - for (const dep of extra) { + for (const dep of filteredExtra) { if (dep.root.kind === 'Global') { diagnostic.withDetails({ kind: 'error', diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.exhaustive-deps-effect-events.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.exhaustive-deps-effect-events.expect.md index e2ab53dd05f..d0a626e50ea 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.exhaustive-deps-effect-events.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.exhaustive-deps-effect-events.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateExhaustiveEffectDependencies +// @validateExhaustiveEffectDependencies:"all" import {useEffect, useEffectEvent} from 'react'; function Component({x, y, z}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.exhaustive-deps-effect-events.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.exhaustive-deps-effect-events.js index f8e9c8d700e..03e4a326f95 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.exhaustive-deps-effect-events.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.exhaustive-deps-effect-events.js @@ -1,4 +1,4 @@ -// @validateExhaustiveEffectDependencies +// @validateExhaustiveEffectDependencies:"all" import {useEffect, useEffectEvent} from 'react'; function Component({x, y, z}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-extra-only.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-extra-only.expect.md new file mode 100644 index 00000000000..f9aac96434a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-extra-only.expect.md @@ -0,0 +1,83 @@ + +## Input + +```javascript +// @validateExhaustiveEffectDependencies:"extra-only" +import {useEffect} from 'react'; + +function Component({x, y, z}) { + // no error: missing dep not reported in extra-only mode + useEffect(() => { + log(x); + }, []); + + // error: extra dep - y + useEffect(() => { + log(x); + }, [x, y]); + + // error: extra dep - y (missing dep - z not reported) + useEffect(() => { + log(x, z); + }, [x, y]); + + // error: extra dep - x.y + useEffect(() => { + log(x); + }, [x.y]); +} + +``` + + +## Error + +``` +Found 3 errors: + +Error: Found extra effect dependencies + +Extra dependencies can cause an effect to fire more often than it should, resulting in performance problems such as excessive renders and side effects. + +error.invalid-exhaustive-effect-deps-extra-only.ts:13:9 + 11 | useEffect(() => { + 12 | log(x); +> 13 | }, [x, y]); + | ^ Unnecessary dependency `y` + 14 | + 15 | // error: extra dep - y (missing dep - z not reported) + 16 | useEffect(() => { + +Inferred dependencies: `[x]` + +Error: Found extra effect dependencies + +Extra dependencies can cause an effect to fire more often than it should, resulting in performance problems such as excessive renders and side effects. + +error.invalid-exhaustive-effect-deps-extra-only.ts:18:9 + 16 | useEffect(() => { + 17 | log(x, z); +> 18 | }, [x, y]); + | ^ Unnecessary dependency `y` + 19 | + 20 | // error: extra dep - x.y + 21 | useEffect(() => { + +Inferred dependencies: `[x, z]` + +Error: Found extra effect dependencies + +Extra dependencies can cause an effect to fire more often than it should, resulting in performance problems such as excessive renders and side effects. + +error.invalid-exhaustive-effect-deps-extra-only.ts:23:6 + 21 | useEffect(() => { + 22 | log(x); +> 23 | }, [x.y]); + | ^^^ Overly precise dependency `x.y`, use `x` instead + 24 | } + 25 | + +Inferred dependencies: `[x]` +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-extra-only.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-extra-only.js new file mode 100644 index 00000000000..fcdc4c1a75e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-extra-only.js @@ -0,0 +1,24 @@ +// @validateExhaustiveEffectDependencies:"extra-only" +import {useEffect} from 'react'; + +function Component({x, y, z}) { + // no error: missing dep not reported in extra-only mode + useEffect(() => { + log(x); + }, []); + + // error: extra dep - y + useEffect(() => { + log(x); + }, [x, y]); + + // error: extra dep - y (missing dep - z not reported) + useEffect(() => { + log(x, z); + }, [x, y]); + + // error: extra dep - x.y + useEffect(() => { + log(x); + }, [x.y]); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-missing-only.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-missing-only.expect.md new file mode 100644 index 00000000000..5a104f529ee --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-missing-only.expect.md @@ -0,0 +1,84 @@ + +## Input + +```javascript +// @validateExhaustiveEffectDependencies:"missing-only" +import {useEffect} from 'react'; + +function Component({x, y, z}) { + // error: missing dep - x + useEffect(() => { + log(x); + }, []); + + // no error: extra dep not reported in missing-only mode + useEffect(() => { + log(x); + }, [x, y]); + + // error: missing dep - z (extra dep - y not reported) + useEffect(() => { + log(x, z); + }, [x, y]); + + // error: missing dep x + useEffect(() => { + log(x); + }, [x.y]); +} + +``` + + +## Error + +``` +Found 3 errors: + +Error: Found missing effect dependencies + +Missing dependencies can cause an effect to fire less often than it should. + +error.invalid-exhaustive-effect-deps-missing-only.ts:7:8 + 5 | // error: missing dep - x + 6 | useEffect(() => { +> 7 | log(x); + | ^ Missing dependency `x` + 8 | }, []); + 9 | + 10 | // no error: extra dep not reported in missing-only mode + +Inferred dependencies: `[x]` + +Error: Found missing effect dependencies + +Missing dependencies can cause an effect to fire less often than it should. + +error.invalid-exhaustive-effect-deps-missing-only.ts:17:11 + 15 | // error: missing dep - z (extra dep - y not reported) + 16 | useEffect(() => { +> 17 | log(x, z); + | ^ Missing dependency `z` + 18 | }, [x, y]); + 19 | + 20 | // error: missing dep x + +Inferred dependencies: `[x, z]` + +Error: Found missing effect dependencies + +Missing dependencies can cause an effect to fire less often than it should. + +error.invalid-exhaustive-effect-deps-missing-only.ts:22:8 + 20 | // error: missing dep x + 21 | useEffect(() => { +> 22 | log(x); + | ^ Missing dependency `x` + 23 | }, [x.y]); + 24 | } + 25 | + +Inferred dependencies: `[x]` +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-missing-only.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-missing-only.js new file mode 100644 index 00000000000..7b333f97a85 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps-missing-only.js @@ -0,0 +1,24 @@ +// @validateExhaustiveEffectDependencies:"missing-only" +import {useEffect} from 'react'; + +function Component({x, y, z}) { + // error: missing dep - x + useEffect(() => { + log(x); + }, []); + + // no error: extra dep not reported in missing-only mode + useEffect(() => { + log(x); + }, [x, y]); + + // error: missing dep - z (extra dep - y not reported) + useEffect(() => { + log(x, z); + }, [x, y]); + + // error: missing dep x + useEffect(() => { + log(x); + }, [x.y]); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps.expect.md index 78332c7071b..55dcd921a20 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateExhaustiveEffectDependencies +// @validateExhaustiveEffectDependencies:"all" import {useEffect} from 'react'; function Component({x, y, z}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps.js index b508117acb0..e810fd3f7c8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/error.invalid-exhaustive-effect-deps.js @@ -1,4 +1,4 @@ -// @validateExhaustiveEffectDependencies +// @validateExhaustiveEffectDependencies:"all" import {useEffect} from 'react'; function Component({x, y, z}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-allow-nonreactive-stable-types-as-extra-deps.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-allow-nonreactive-stable-types-as-extra-deps.expect.md index 2c449ddc5e5..a5b500ddcf5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-allow-nonreactive-stable-types-as-extra-deps.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-allow-nonreactive-stable-types-as-extra-deps.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies +// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies:"all" import { useCallback, useTransition, @@ -69,7 +69,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies +import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies:"all" import { useCallback, useTransition, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-allow-nonreactive-stable-types-as-extra-deps.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-allow-nonreactive-stable-types-as-extra-deps.js index 721832eac1b..75ea6edbb34 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-allow-nonreactive-stable-types-as-extra-deps.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-allow-nonreactive-stable-types-as-extra-deps.js @@ -1,4 +1,4 @@ -// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies +// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies:"all" import { useCallback, useTransition, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-effect-events.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-effect-events.expect.md index 3b0e696911a..a633db2d8da 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-effect-events.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-effect-events.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateExhaustiveEffectDependencies +// @validateExhaustiveEffectDependencies:"all" import {useEffect, useEffectEvent} from 'react'; function Component({x, y, z}) { @@ -30,7 +30,7 @@ function Component({x, y, z}) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveEffectDependencies +import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveEffectDependencies:"all" import { useEffect, useEffectEvent } from "react"; function Component(t0) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-effect-events.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-effect-events.js index 1c8c710d6cb..ef3853b6e4d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-effect-events.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/exhaustive-deps/exhaustive-deps-effect-events.js @@ -1,4 +1,4 @@ -// @validateExhaustiveEffectDependencies +// @validateExhaustiveEffectDependencies:"all" import {useEffect, useEffectEvent} from 'react'; function Component({x, y, z}) { diff --git a/fixtures/eslint-v9/index.js b/fixtures/eslint-v9/index.js index 5a43235df97..601b68a0328 100644 --- a/fixtures/eslint-v9/index.js +++ b/fixtures/eslint-v9/index.js @@ -167,3 +167,16 @@ function InvalidUseMemo({items}) { const sorted = useMemo(() => [...items].sort(), []); return
{sorted.length}
; } + +// Invalid: missing/extra deps in useEffect +function InvalidEffectDeps({a, b}) { + useEffect(() => { + console.log(a); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + console.log(a); + // TODO: eslint-disable-next-line react-hooks/exhaustive-effect-dependencies + }, [a, b]); +} diff --git a/fixtures/eslint-v9/yarn.lock b/fixtures/eslint-v9/yarn.lock index 936b5336938..964edad8223 100644 --- a/fixtures/eslint-v9/yarn.lock +++ b/fixtures/eslint-v9/yarn.lock @@ -603,6 +603,18 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +hermes-estree@0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.25.1.tgz#6aeec17d1983b4eabf69721f3aa3eb705b17f480" + integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw== + +hermes-parser@^0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.1.tgz#5be0e487b2090886c62bd8a11724cd766d5f54d1" + integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA== + dependencies: + hermes-estree "0.25.1" + ignore@^5.2.0: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" @@ -877,12 +889,12 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -"zod-validation-error@^3.0.3 || ^4.0.0": +"zod-validation-error@^3.5.0 || ^4.0.0": version "4.0.2" resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz#bc605eba49ce0fcd598c127fee1c236be3f22918" integrity sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ== -"zod@^3.22.4 || ^4.0.0": - version "4.1.11" - resolved "https://registry.yarnpkg.com/zod/-/zod-4.1.11.tgz#4aab62f76cfd45e6c6166519ba31b2ea019f75f5" - integrity sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg== +"zod@^3.25.0 || ^4.0.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.2.0.tgz#01e86f2c2b6d525a1b9fa6dbe78beccad082118f" + integrity sha512-Bd5fw9wlIhtqCCxotZgdTOMwGm1a0u75wARVEY9HMs1X17trvA/lMi4+MGK5EUfYkXVTbX8UDiDKW4OgzHVUZw== diff --git a/packages/eslint-plugin-react-hooks/src/shared/RunReactCompiler.ts b/packages/eslint-plugin-react-hooks/src/shared/RunReactCompiler.ts index 1cf08cb7002..acd50a36816 100644 --- a/packages/eslint-plugin-react-hooks/src/shared/RunReactCompiler.ts +++ b/packages/eslint-plugin-react-hooks/src/shared/RunReactCompiler.ts @@ -42,6 +42,7 @@ const COMPILER_OPTIONS: PluginOptions = { // Temporarily enabled for internal testing enableUseKeyedState: true, enableVerboseNoSetStateInEffect: true, + validateExhaustiveEffectDependencies: 'extra-only', }, };