diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index a4f984f195..d6945150aa 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -86,6 +86,7 @@ import { validateMemoizedEffectDependencies, validateNoCapitalizedCalls, validateNoRefAccessInRender, + validateNoForbiddenVariableNames, validateNoSetStateInRender, validatePreservedManualMemoization, validateUseMemo, @@ -247,6 +248,10 @@ function runWithEnvironment( } } + if (env.config.validateNoForbiddenVariableNames) { + validateNoForbiddenVariableNames(hir); + } + if (!env.config.enableNewMutationAliasingModel) { validateLocalsNotReassignedAfterRender(hir); } 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 957c5ab84a..0f2e952669 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -330,6 +330,11 @@ export const EnvironmentConfigSchema = z.object({ */ validateNoSetStateInEffects: z.boolean().default(false), + /* + * Validates there are no forbidden variable names in the component. + */ + validateNoForbiddenVariableNames:z.boolean().default(false), + /** * Validates that effects are not used to calculate derived data which could instead be computed * during render. diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoForbiddenVariableNames.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoForbiddenVariableNames.ts new file mode 100644 index 0000000000..1a9b339e4e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoForbiddenVariableNames.ts @@ -0,0 +1,31 @@ +import { + GeneratedSource, + HIRFunction, +} from '../HIR'; + +import {CompilerError, ErrorSeverity} from '..'; +export function validateNoForbiddenVariableNames(fn: HIRFunction) { + const errors = new CompilerError(); + + for (const block of fn.body.blocks.values()) { + for (const instr of block.instructions) { + const {loc} = instr; + + console.log(instr) + if (loc !== GeneratedSource && loc.identifierName === 'forbidden') { + errors.push({ + reason: + 'Values derived from props and state should be calculated during render, not in an effect. (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)', + description: null, + severity: ErrorSeverity.InvalidReact, + loc, + suggestions: null, + }); + } + }} + + + if (errors.hasErrors()) { + throw errors; + } +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/index.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/index.ts index 3bf03f362f..0037146053 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/index.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/index.ts @@ -11,5 +11,6 @@ export {validateMemoizedEffectDependencies} from './ValidateMemoizedEffectDepend export {validateNoCapitalizedCalls} from './ValidateNoCapitalizedCalls'; export {validateNoRefAccessInRender} from './ValidateNoRefAccessInRender'; export {validateNoSetStateInRender} from './ValidateNoSetStateInRender'; +export {validateNoForbiddenVariableNames} from './ValidateNoForbiddenVariableNames'; export {validatePreservedManualMemoization} from './ValidatePreservedManualMemoization'; export {validateUseMemo} from './ValidateUseMemo';