diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts index 7d12e054373..5ac580abbf0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts @@ -400,7 +400,15 @@ export function compileProgram( */ const suppressions = findProgramSuppressions( pass.comments, - pass.opts.eslintSuppressionRules ?? DEFAULT_ESLINT_SUPPRESSIONS, + /* + * If the compiler is validating hooks rules and exhaustive memo dependencies, we don't need to check + * for React ESLint suppressions + */ + pass.opts.environment.validateExhaustiveMemoizationDependencies && + pass.opts.environment.validateHooksUsage + ? null + : (pass.opts.eslintSuppressionRules ?? DEFAULT_ESLINT_SUPPRESSIONS), + // Always bail on Flow suppressions pass.opts.flowSuppressions, ); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts index 24a9bccf426..e0f845f269b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts @@ -78,7 +78,7 @@ export function filterSuppressionsThatAffectFunction( export function findProgramSuppressions( programComments: Array, - ruleNames: Array, + ruleNames: Array | null, flowSuppressions: boolean, ): Array { const suppressionRanges: Array = []; @@ -89,7 +89,7 @@ export function findProgramSuppressions( let disableNextLinePattern: RegExp | null = null; let disablePattern: RegExp | null = null; let enablePattern: RegExp | null = null; - if (ruleNames.length !== 0) { + if (ruleNames != null && ruleNames.length !== 0) { const rulePattern = `(${ruleNames.join('|')})`; disableNextLinePattern = new RegExp( `eslint-disable-next-line ${rulePattern}`, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/compile-files-with-exhaustive-deps-violation-in-effects.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/compile-files-with-exhaustive-deps-violation-in-effects.expect.md new file mode 100644 index 00000000000..e8e18395eca --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/compile-files-with-exhaustive-deps-violation-in-effects.expect.md @@ -0,0 +1,91 @@ + +## Input + +```javascript +// @validateExhaustiveMemoizationDependencies + +import {useMemo} from 'react'; +import {ValidateMemoization} from 'shared-runtime'; + +function Component({x}) { + useEffect( + () => { + console.log(x); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, + [ + /* intentionally missing deps */ + ] + ); + + const memo = useMemo(() => { + return [x]; + }, [x]); + + return ; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveMemoizationDependencies + +import { useMemo } from "react"; +import { ValidateMemoization } from "shared-runtime"; + +function Component(t0) { + const $ = _c(10); + const { x } = t0; + let t1; + if ($[0] !== x) { + t1 = () => { + console.log(x); + }; + $[0] = x; + $[1] = t1; + } else { + t1 = $[1]; + } + let t2; + if ($[2] === Symbol.for("react.memo_cache_sentinel")) { + t2 = []; + $[2] = t2; + } else { + t2 = $[2]; + } + useEffect(t1, t2); + let t3; + if ($[3] !== x) { + t3 = [x]; + $[3] = x; + $[4] = t3; + } else { + t3 = $[4]; + } + const memo = t3; + let t4; + if ($[5] !== x) { + t4 = [x]; + $[5] = x; + $[6] = t4; + } else { + t4 = $[6]; + } + let t5; + if ($[7] !== memo || $[8] !== t4) { + t5 = ; + $[7] = memo; + $[8] = t4; + $[9] = t5; + } else { + t5 = $[9]; + } + return t5; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/compile-files-with-exhaustive-deps-violation-in-effects.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/compile-files-with-exhaustive-deps-violation-in-effects.js new file mode 100644 index 00000000000..64817e701f0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/compile-files-with-exhaustive-deps-violation-in-effects.js @@ -0,0 +1,22 @@ +// @validateExhaustiveMemoizationDependencies + +import {useMemo} from 'react'; +import {ValidateMemoization} from 'shared-runtime'; + +function Component({x}) { + useEffect( + () => { + console.log(x); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, + [ + /* intentionally missing deps */ + ] + ); + + const memo = useMemo(() => { + return [x]; + }, [x]); + + return ; +} diff --git a/compiler/packages/snap/src/runner.ts b/compiler/packages/snap/src/runner.ts index 92a0a0f82ee..478a32d426c 100644 --- a/compiler/packages/snap/src/runner.ts +++ b/compiler/packages/snap/src/runner.ts @@ -53,8 +53,10 @@ const opts: RunnerOptions = yargs .default('worker-threads', true) .boolean('watch') .describe('watch', 'Run compiler in watch mode, re-running after changes') + .alias('w', 'watch') .default('watch', false) .boolean('update') + .alias('u', 'update') .describe('update', 'Update fixtures') .default('update', false) .boolean('filter')