eslint-plugin-react-hooks 6.1.0-canary-33a1095d-20250827 → 6.1.0-canary-89a803fc-20250828

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17972,6 +17972,7 @@ var ErrorCategory;
17972
17972
  ErrorCategory["CapitalizedCalls"] = "CapitalizedCalls";
17973
17973
  ErrorCategory["StaticComponents"] = "StaticComponents";
17974
17974
  ErrorCategory["UseMemo"] = "UseMemo";
17975
+ ErrorCategory["Factories"] = "Factories";
17975
17976
  ErrorCategory["PreserveManualMemo"] = "PreserveManualMemo";
17976
17977
  ErrorCategory["Immutability"] = "Immutability";
17977
17978
  ErrorCategory["Globals"] = "Globals";
@@ -18057,6 +18058,15 @@ function getRuleForCategoryImpl(category) {
18057
18058
  recommended: true,
18058
18059
  };
18059
18060
  }
18061
+ case ErrorCategory.Factories: {
18062
+ return {
18063
+ category,
18064
+ name: 'component-hook-factories',
18065
+ description: 'Validates against higher order functions defining nested components or hooks. ' +
18066
+ 'Components and hooks should be defined at the module level',
18067
+ recommended: true,
18068
+ };
18069
+ }
18060
18070
  case ErrorCategory.FBT: {
18061
18071
  return {
18062
18072
  category,
@@ -19500,6 +19510,7 @@ function getFunctionName$2(instrValue, defaultValue) {
19500
19510
  }
19501
19511
  }
19502
19512
  function printAliasingEffect(effect) {
19513
+ var _a;
19503
19514
  switch (effect.kind) {
19504
19515
  case 'Assign': {
19505
19516
  return `Assign ${printPlaceForAliasEffect(effect.into)} = ${printPlaceForAliasEffect(effect.from)}`;
@@ -19558,7 +19569,7 @@ function printAliasingEffect(effect) {
19558
19569
  case 'MutateConditionally':
19559
19570
  case 'MutateTransitive':
19560
19571
  case 'MutateTransitiveConditionally': {
19561
- return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}`;
19572
+ return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}${effect.kind === 'Mutate' && ((_a = effect.reason) === null || _a === void 0 ? void 0 : _a.kind) === 'AssignCurrentProperty' ? ' (assign `.current`)' : ''}`;
19562
19573
  }
19563
19574
  case 'MutateFrozen': {
19564
19575
  return `MutateFrozen ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
@@ -21070,7 +21081,7 @@ class HIRBuilder {
21070
21081
  }
21071
21082
  }
21072
21083
  resolveBinding(node) {
21073
- var _a, _b;
21084
+ var _a, _b, _c;
21074
21085
  if (node.name === 'fbt') {
21075
21086
  CompilerError.throwDiagnostic({
21076
21087
  severity: ErrorSeverity.Todo,
@@ -21086,6 +21097,21 @@ class HIRBuilder {
21086
21097
  ],
21087
21098
  });
21088
21099
  }
21100
+ if (node.name === 'this') {
21101
+ CompilerError.throwDiagnostic({
21102
+ severity: ErrorSeverity.UnsupportedJS,
21103
+ category: ErrorCategory.UnsupportedSyntax,
21104
+ reason: '`this` is not supported syntax',
21105
+ description: 'React Compiler does not support compiling functions that use `this`',
21106
+ details: [
21107
+ {
21108
+ kind: 'error',
21109
+ message: '`this` was used here',
21110
+ loc: (_b = node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
21111
+ },
21112
+ ],
21113
+ });
21114
+ }
21089
21115
  const originalName = node.name;
21090
21116
  let name = originalName;
21091
21117
  let index = 0;
@@ -21103,7 +21129,7 @@ class HIRBuilder {
21103
21129
  },
21104
21130
  scope: null,
21105
21131
  type: makeType(),
21106
- loc: (_b = node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
21132
+ loc: (_c = node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
21107
21133
  };
21108
21134
  __classPrivateFieldGet(this, _HIRBuilder_env, "f").programContext.addNewReference(name);
21109
21135
  __classPrivateFieldGet(this, _HIRBuilder_bindings, "f").set(name, { node, identifier });
@@ -31612,6 +31638,7 @@ const EnvironmentConfigSchema = zod.z.object({
31612
31638
  enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(true),
31613
31639
  lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
31614
31640
  validateNoVoidUseMemo: zod.z.boolean().default(false),
31641
+ validateNoDynamicallyCreatedComponentsOrHooks: zod.z.boolean().default(false),
31615
31642
  });
31616
31643
  class Environment {
31617
31644
  constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
@@ -42237,7 +42264,7 @@ class RewriteBlockIds extends ReactiveFunctionVisitor {
42237
42264
  }
42238
42265
 
42239
42266
  function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42240
- var _a, _b, _c, _d, _e, _f;
42267
+ var _a, _b, _c, _d, _e, _f, _g;
42241
42268
  const functionEffects = [];
42242
42269
  const state = new AliasingState();
42243
42270
  const pendingPhis = new Map();
@@ -42304,6 +42331,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42304
42331
  kind: effect.kind === 'MutateTransitive'
42305
42332
  ? MutationKind.Definite
42306
42333
  : MutationKind.Conditional,
42334
+ reason: null,
42307
42335
  place: effect.value,
42308
42336
  });
42309
42337
  }
@@ -42316,6 +42344,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42316
42344
  kind: effect.kind === 'Mutate'
42317
42345
  ? MutationKind.Definite
42318
42346
  : MutationKind.Conditional,
42347
+ reason: effect.kind === 'Mutate' ? ((_a = effect.reason) !== null && _a !== void 0 ? _a : null) : null,
42319
42348
  place: effect.value,
42320
42349
  });
42321
42350
  }
@@ -42357,7 +42386,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42357
42386
  }
42358
42387
  }
42359
42388
  for (const mutation of mutations) {
42360
- state.mutate(mutation.index, mutation.place.identifier, makeInstructionId(mutation.id + 1), mutation.transitive, mutation.kind, mutation.place.loc, errors);
42389
+ state.mutate(mutation.index, mutation.place.identifier, makeInstructionId(mutation.id + 1), mutation.transitive, mutation.kind, mutation.place.loc, mutation.reason, errors);
42361
42390
  }
42362
42391
  for (const render of renders) {
42363
42392
  state.render(render.index, render.place.identifier, errors);
@@ -42382,6 +42411,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42382
42411
  functionEffects.push({
42383
42412
  kind: 'Mutate',
42384
42413
  value: Object.assign(Object.assign({}, place), { loc: node.local.loc }),
42414
+ reason: node.mutationReason,
42385
42415
  });
42386
42416
  }
42387
42417
  }
@@ -42409,7 +42439,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42409
42439
  for (const phi of block.phis) {
42410
42440
  phi.place.effect = Effect.Store;
42411
42441
  const isPhiMutatedAfterCreation = phi.place.identifier.mutableRange.end >
42412
- ((_b = (_a = block.instructions.at(0)) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : block.terminal.id);
42442
+ ((_c = (_b = block.instructions.at(0)) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : block.terminal.id);
42413
42443
  for (const operand of phi.operands.values()) {
42414
42444
  operand.effect = isPhiMutatedAfterCreation
42415
42445
  ? Effect.Capture
@@ -42417,7 +42447,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42417
42447
  }
42418
42448
  if (isPhiMutatedAfterCreation &&
42419
42449
  phi.place.identifier.mutableRange.start === 0) {
42420
- const firstInstructionIdOfBlock = (_d = (_c = block.instructions.at(0)) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : block.terminal.id;
42450
+ const firstInstructionIdOfBlock = (_e = (_d = block.instructions.at(0)) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : block.terminal.id;
42421
42451
  phi.place.identifier.mutableRange.start = makeInstructionId(firstInstructionIdOfBlock - 1);
42422
42452
  }
42423
42453
  }
@@ -42495,7 +42525,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42495
42525
  }
42496
42526
  }
42497
42527
  for (const lvalue of eachInstructionLValue(instr)) {
42498
- const effect = (_e = operandEffects.get(lvalue.identifier.id)) !== null && _e !== void 0 ? _e : Effect.ConditionallyMutate;
42528
+ const effect = (_f = operandEffects.get(lvalue.identifier.id)) !== null && _f !== void 0 ? _f : Effect.ConditionallyMutate;
42499
42529
  lvalue.effect = effect;
42500
42530
  }
42501
42531
  for (const operand of eachInstructionValueOperand(instr.value)) {
@@ -42503,7 +42533,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42503
42533
  operand.identifier.mutableRange.start === 0) {
42504
42534
  operand.identifier.mutableRange.start = instr.id;
42505
42535
  }
42506
- const effect = (_f = operandEffects.get(operand.identifier.id)) !== null && _f !== void 0 ? _f : Effect.Read;
42536
+ const effect = (_g = operandEffects.get(operand.identifier.id)) !== null && _g !== void 0 ? _g : Effect.Read;
42507
42537
  operand.effect = effect;
42508
42538
  }
42509
42539
  if (instr.value.kind === 'StoreContext' &&
@@ -42541,7 +42571,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42541
42571
  }
42542
42572
  for (const into of tracked) {
42543
42573
  const mutationIndex = index++;
42544
- state.mutate(mutationIndex, into.identifier, null, true, MutationKind.Conditional, into.loc, ignoredErrors);
42574
+ state.mutate(mutationIndex, into.identifier, null, true, MutationKind.Conditional, into.loc, null, ignoredErrors);
42545
42575
  for (const from of tracked) {
42546
42576
  if (from.identifier.id === into.identifier.id ||
42547
42577
  from.identifier.id === fn.returns.identifier.id) {
@@ -42609,6 +42639,7 @@ class AliasingState {
42609
42639
  transitive: null,
42610
42640
  local: null,
42611
42641
  lastMutated: 0,
42642
+ mutationReason: null,
42612
42643
  value,
42613
42644
  });
42614
42645
  }
@@ -42693,7 +42724,8 @@ class AliasingState {
42693
42724
  }
42694
42725
  }
42695
42726
  }
42696
- mutate(index, start, end, transitive, startKind, loc, errors) {
42727
+ mutate(index, start, end, transitive, startKind, loc, reason, errors) {
42728
+ var _a;
42697
42729
  const seen = new Map();
42698
42730
  const queue = [{ place: start, transitive, direction: 'backwards', kind: startKind }];
42699
42731
  while (queue.length !== 0) {
@@ -42707,6 +42739,7 @@ class AliasingState {
42707
42739
  if (node == null) {
42708
42740
  continue;
42709
42741
  }
42742
+ (_a = node.mutationReason) !== null && _a !== void 0 ? _a : (node.mutationReason = reason);
42710
42743
  node.lastMutated = Math.max(node.lastMutated, index);
42711
42744
  if (end != null) {
42712
42745
  node.id.mutableRange.end = makeInstructionId(Math.max(node.id.mutableRange.end, end));
@@ -50942,7 +50975,14 @@ function findFunctionsToCompile(program, pass, programContext) {
50942
50975
  var _a;
50943
50976
  const queue = [];
50944
50977
  const traverseFunction = (fn, pass) => {
50978
+ if (pass.opts.compilationMode === 'all' &&
50979
+ fn.scope.getProgramParent() !== fn.scope.parent) {
50980
+ return;
50981
+ }
50945
50982
  const fnType = getReactFunctionType(fn, pass);
50983
+ if (pass.opts.environment.validateNoDynamicallyCreatedComponentsOrHooks) {
50984
+ validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext);
50985
+ }
50946
50986
  if (fnType === null || programContext.alreadyCompiled.has(fn.node)) {
50947
50987
  return;
50948
50988
  }
@@ -51127,6 +51167,52 @@ function shouldSkipCompilation(program, pass) {
51127
51167
  }
51128
51168
  return false;
51129
51169
  }
51170
+ function validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext) {
51171
+ const parentNameExpr = getFunctionName$1(fn);
51172
+ const parentName = parentNameExpr !== null && parentNameExpr.isIdentifier()
51173
+ ? parentNameExpr.node.name
51174
+ : '<anonymous>';
51175
+ const validateNestedFunction = (nestedFn) => {
51176
+ var _a, _b, _c, _d;
51177
+ if (nestedFn.node === fn.node ||
51178
+ programContext.alreadyCompiled.has(nestedFn.node)) {
51179
+ return;
51180
+ }
51181
+ if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
51182
+ const nestedFnType = getReactFunctionType(nestedFn, pass);
51183
+ const nestedFnNameExpr = getFunctionName$1(nestedFn);
51184
+ const nestedName = nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
51185
+ ? nestedFnNameExpr.node.name
51186
+ : '<anonymous>';
51187
+ if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
51188
+ CompilerError.throwDiagnostic({
51189
+ category: ErrorCategory.Factories,
51190
+ severity: ErrorSeverity.InvalidReact,
51191
+ reason: `Components and hooks cannot be created dynamically`,
51192
+ description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
51193
+ details: [
51194
+ {
51195
+ kind: 'error',
51196
+ message: 'this function dynamically created a component/hook',
51197
+ loc: (_b = (_a = parentNameExpr === null || parentNameExpr === void 0 ? void 0 : parentNameExpr.node.loc) !== null && _a !== void 0 ? _a : fn.node.loc) !== null && _b !== void 0 ? _b : null,
51198
+ },
51199
+ {
51200
+ kind: 'error',
51201
+ message: 'the component is created here',
51202
+ loc: (_d = (_c = nestedFnNameExpr === null || nestedFnNameExpr === void 0 ? void 0 : nestedFnNameExpr.node.loc) !== null && _c !== void 0 ? _c : nestedFn.node.loc) !== null && _d !== void 0 ? _d : null,
51203
+ },
51204
+ ],
51205
+ });
51206
+ }
51207
+ }
51208
+ nestedFn.skip();
51209
+ };
51210
+ fn.traverse({
51211
+ FunctionDeclaration: validateNestedFunction,
51212
+ FunctionExpression: validateNestedFunction,
51213
+ ArrowFunctionExpression: validateNestedFunction,
51214
+ });
51215
+ }
51130
51216
  function getReactFunctionType(fn, pass) {
51131
51217
  var _a, _b;
51132
51218
  const hookPattern = pass.opts.environment.hookPattern;
@@ -51156,9 +51242,6 @@ function getReactFunctionType(fn, pass) {
51156
51242
  return componentSyntaxType;
51157
51243
  }
51158
51244
  case 'all': {
51159
- if (fn.scope.getProgramParent() !== fn.scope.parent) {
51160
- return null;
51161
- }
51162
51245
  return (_b = getComponentOrHookLike(fn, hookPattern)) !== null && _b !== void 0 ? _b : 'Other';
51163
51246
  }
51164
51247
  default: {
@@ -17963,6 +17963,7 @@ var ErrorCategory;
17963
17963
  ErrorCategory["CapitalizedCalls"] = "CapitalizedCalls";
17964
17964
  ErrorCategory["StaticComponents"] = "StaticComponents";
17965
17965
  ErrorCategory["UseMemo"] = "UseMemo";
17966
+ ErrorCategory["Factories"] = "Factories";
17966
17967
  ErrorCategory["PreserveManualMemo"] = "PreserveManualMemo";
17967
17968
  ErrorCategory["Immutability"] = "Immutability";
17968
17969
  ErrorCategory["Globals"] = "Globals";
@@ -18048,6 +18049,15 @@ function getRuleForCategoryImpl(category) {
18048
18049
  recommended: true,
18049
18050
  };
18050
18051
  }
18052
+ case ErrorCategory.Factories: {
18053
+ return {
18054
+ category,
18055
+ name: 'component-hook-factories',
18056
+ description: 'Validates against higher order functions defining nested components or hooks. ' +
18057
+ 'Components and hooks should be defined at the module level',
18058
+ recommended: true,
18059
+ };
18060
+ }
18051
18061
  case ErrorCategory.FBT: {
18052
18062
  return {
18053
18063
  category,
@@ -19491,6 +19501,7 @@ function getFunctionName$2(instrValue, defaultValue) {
19491
19501
  }
19492
19502
  }
19493
19503
  function printAliasingEffect(effect) {
19504
+ var _a;
19494
19505
  switch (effect.kind) {
19495
19506
  case 'Assign': {
19496
19507
  return `Assign ${printPlaceForAliasEffect(effect.into)} = ${printPlaceForAliasEffect(effect.from)}`;
@@ -19549,7 +19560,7 @@ function printAliasingEffect(effect) {
19549
19560
  case 'MutateConditionally':
19550
19561
  case 'MutateTransitive':
19551
19562
  case 'MutateTransitiveConditionally': {
19552
- return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}`;
19563
+ return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}${effect.kind === 'Mutate' && ((_a = effect.reason) === null || _a === void 0 ? void 0 : _a.kind) === 'AssignCurrentProperty' ? ' (assign `.current`)' : ''}`;
19553
19564
  }
19554
19565
  case 'MutateFrozen': {
19555
19566
  return `MutateFrozen ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
@@ -21061,7 +21072,7 @@ class HIRBuilder {
21061
21072
  }
21062
21073
  }
21063
21074
  resolveBinding(node) {
21064
- var _a, _b;
21075
+ var _a, _b, _c;
21065
21076
  if (node.name === 'fbt') {
21066
21077
  CompilerError.throwDiagnostic({
21067
21078
  severity: ErrorSeverity.Todo,
@@ -21077,6 +21088,21 @@ class HIRBuilder {
21077
21088
  ],
21078
21089
  });
21079
21090
  }
21091
+ if (node.name === 'this') {
21092
+ CompilerError.throwDiagnostic({
21093
+ severity: ErrorSeverity.UnsupportedJS,
21094
+ category: ErrorCategory.UnsupportedSyntax,
21095
+ reason: '`this` is not supported syntax',
21096
+ description: 'React Compiler does not support compiling functions that use `this`',
21097
+ details: [
21098
+ {
21099
+ kind: 'error',
21100
+ message: '`this` was used here',
21101
+ loc: (_b = node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
21102
+ },
21103
+ ],
21104
+ });
21105
+ }
21080
21106
  const originalName = node.name;
21081
21107
  let name = originalName;
21082
21108
  let index = 0;
@@ -21094,7 +21120,7 @@ class HIRBuilder {
21094
21120
  },
21095
21121
  scope: null,
21096
21122
  type: makeType(),
21097
- loc: (_b = node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
21123
+ loc: (_c = node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
21098
21124
  };
21099
21125
  __classPrivateFieldGet(this, _HIRBuilder_env, "f").programContext.addNewReference(name);
21100
21126
  __classPrivateFieldGet(this, _HIRBuilder_bindings, "f").set(name, { node, identifier });
@@ -31439,6 +31465,7 @@ const EnvironmentConfigSchema = zod.z.object({
31439
31465
  enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(true),
31440
31466
  lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
31441
31467
  validateNoVoidUseMemo: zod.z.boolean().default(false),
31468
+ validateNoDynamicallyCreatedComponentsOrHooks: zod.z.boolean().default(false),
31442
31469
  });
31443
31470
  class Environment {
31444
31471
  constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
@@ -42064,7 +42091,7 @@ class RewriteBlockIds extends ReactiveFunctionVisitor {
42064
42091
  }
42065
42092
 
42066
42093
  function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42067
- var _a, _b, _c, _d, _e, _f;
42094
+ var _a, _b, _c, _d, _e, _f, _g;
42068
42095
  const functionEffects = [];
42069
42096
  const state = new AliasingState();
42070
42097
  const pendingPhis = new Map();
@@ -42131,6 +42158,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42131
42158
  kind: effect.kind === 'MutateTransitive'
42132
42159
  ? MutationKind.Definite
42133
42160
  : MutationKind.Conditional,
42161
+ reason: null,
42134
42162
  place: effect.value,
42135
42163
  });
42136
42164
  }
@@ -42143,6 +42171,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42143
42171
  kind: effect.kind === 'Mutate'
42144
42172
  ? MutationKind.Definite
42145
42173
  : MutationKind.Conditional,
42174
+ reason: effect.kind === 'Mutate' ? ((_a = effect.reason) !== null && _a !== void 0 ? _a : null) : null,
42146
42175
  place: effect.value,
42147
42176
  });
42148
42177
  }
@@ -42184,7 +42213,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42184
42213
  }
42185
42214
  }
42186
42215
  for (const mutation of mutations) {
42187
- state.mutate(mutation.index, mutation.place.identifier, makeInstructionId(mutation.id + 1), mutation.transitive, mutation.kind, mutation.place.loc, errors);
42216
+ state.mutate(mutation.index, mutation.place.identifier, makeInstructionId(mutation.id + 1), mutation.transitive, mutation.kind, mutation.place.loc, mutation.reason, errors);
42188
42217
  }
42189
42218
  for (const render of renders) {
42190
42219
  state.render(render.index, render.place.identifier, errors);
@@ -42209,6 +42238,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42209
42238
  functionEffects.push({
42210
42239
  kind: 'Mutate',
42211
42240
  value: Object.assign(Object.assign({}, place), { loc: node.local.loc }),
42241
+ reason: node.mutationReason,
42212
42242
  });
42213
42243
  }
42214
42244
  }
@@ -42236,7 +42266,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42236
42266
  for (const phi of block.phis) {
42237
42267
  phi.place.effect = Effect.Store;
42238
42268
  const isPhiMutatedAfterCreation = phi.place.identifier.mutableRange.end >
42239
- ((_b = (_a = block.instructions.at(0)) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : block.terminal.id);
42269
+ ((_c = (_b = block.instructions.at(0)) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : block.terminal.id);
42240
42270
  for (const operand of phi.operands.values()) {
42241
42271
  operand.effect = isPhiMutatedAfterCreation
42242
42272
  ? Effect.Capture
@@ -42244,7 +42274,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42244
42274
  }
42245
42275
  if (isPhiMutatedAfterCreation &&
42246
42276
  phi.place.identifier.mutableRange.start === 0) {
42247
- const firstInstructionIdOfBlock = (_d = (_c = block.instructions.at(0)) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : block.terminal.id;
42277
+ const firstInstructionIdOfBlock = (_e = (_d = block.instructions.at(0)) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : block.terminal.id;
42248
42278
  phi.place.identifier.mutableRange.start = makeInstructionId(firstInstructionIdOfBlock - 1);
42249
42279
  }
42250
42280
  }
@@ -42322,7 +42352,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42322
42352
  }
42323
42353
  }
42324
42354
  for (const lvalue of eachInstructionLValue(instr)) {
42325
- const effect = (_e = operandEffects.get(lvalue.identifier.id)) !== null && _e !== void 0 ? _e : Effect.ConditionallyMutate;
42355
+ const effect = (_f = operandEffects.get(lvalue.identifier.id)) !== null && _f !== void 0 ? _f : Effect.ConditionallyMutate;
42326
42356
  lvalue.effect = effect;
42327
42357
  }
42328
42358
  for (const operand of eachInstructionValueOperand(instr.value)) {
@@ -42330,7 +42360,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42330
42360
  operand.identifier.mutableRange.start === 0) {
42331
42361
  operand.identifier.mutableRange.start = instr.id;
42332
42362
  }
42333
- const effect = (_f = operandEffects.get(operand.identifier.id)) !== null && _f !== void 0 ? _f : Effect.Read;
42363
+ const effect = (_g = operandEffects.get(operand.identifier.id)) !== null && _g !== void 0 ? _g : Effect.Read;
42334
42364
  operand.effect = effect;
42335
42365
  }
42336
42366
  if (instr.value.kind === 'StoreContext' &&
@@ -42368,7 +42398,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
42368
42398
  }
42369
42399
  for (const into of tracked) {
42370
42400
  const mutationIndex = index++;
42371
- state.mutate(mutationIndex, into.identifier, null, true, MutationKind.Conditional, into.loc, ignoredErrors);
42401
+ state.mutate(mutationIndex, into.identifier, null, true, MutationKind.Conditional, into.loc, null, ignoredErrors);
42372
42402
  for (const from of tracked) {
42373
42403
  if (from.identifier.id === into.identifier.id ||
42374
42404
  from.identifier.id === fn.returns.identifier.id) {
@@ -42436,6 +42466,7 @@ class AliasingState {
42436
42466
  transitive: null,
42437
42467
  local: null,
42438
42468
  lastMutated: 0,
42469
+ mutationReason: null,
42439
42470
  value,
42440
42471
  });
42441
42472
  }
@@ -42520,7 +42551,8 @@ class AliasingState {
42520
42551
  }
42521
42552
  }
42522
42553
  }
42523
- mutate(index, start, end, transitive, startKind, loc, errors) {
42554
+ mutate(index, start, end, transitive, startKind, loc, reason, errors) {
42555
+ var _a;
42524
42556
  const seen = new Map();
42525
42557
  const queue = [{ place: start, transitive, direction: 'backwards', kind: startKind }];
42526
42558
  while (queue.length !== 0) {
@@ -42534,6 +42566,7 @@ class AliasingState {
42534
42566
  if (node == null) {
42535
42567
  continue;
42536
42568
  }
42569
+ (_a = node.mutationReason) !== null && _a !== void 0 ? _a : (node.mutationReason = reason);
42537
42570
  node.lastMutated = Math.max(node.lastMutated, index);
42538
42571
  if (end != null) {
42539
42572
  node.id.mutableRange.end = makeInstructionId(Math.max(node.id.mutableRange.end, end));
@@ -50769,7 +50802,14 @@ function findFunctionsToCompile(program, pass, programContext) {
50769
50802
  var _a;
50770
50803
  const queue = [];
50771
50804
  const traverseFunction = (fn, pass) => {
50805
+ if (pass.opts.compilationMode === 'all' &&
50806
+ fn.scope.getProgramParent() !== fn.scope.parent) {
50807
+ return;
50808
+ }
50772
50809
  const fnType = getReactFunctionType(fn, pass);
50810
+ if (pass.opts.environment.validateNoDynamicallyCreatedComponentsOrHooks) {
50811
+ validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext);
50812
+ }
50773
50813
  if (fnType === null || programContext.alreadyCompiled.has(fn.node)) {
50774
50814
  return;
50775
50815
  }
@@ -50954,6 +50994,52 @@ function shouldSkipCompilation(program, pass) {
50954
50994
  }
50955
50995
  return false;
50956
50996
  }
50997
+ function validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext) {
50998
+ const parentNameExpr = getFunctionName$1(fn);
50999
+ const parentName = parentNameExpr !== null && parentNameExpr.isIdentifier()
51000
+ ? parentNameExpr.node.name
51001
+ : '<anonymous>';
51002
+ const validateNestedFunction = (nestedFn) => {
51003
+ var _a, _b, _c, _d;
51004
+ if (nestedFn.node === fn.node ||
51005
+ programContext.alreadyCompiled.has(nestedFn.node)) {
51006
+ return;
51007
+ }
51008
+ if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
51009
+ const nestedFnType = getReactFunctionType(nestedFn, pass);
51010
+ const nestedFnNameExpr = getFunctionName$1(nestedFn);
51011
+ const nestedName = nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
51012
+ ? nestedFnNameExpr.node.name
51013
+ : '<anonymous>';
51014
+ if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
51015
+ CompilerError.throwDiagnostic({
51016
+ category: ErrorCategory.Factories,
51017
+ severity: ErrorSeverity.InvalidReact,
51018
+ reason: `Components and hooks cannot be created dynamically`,
51019
+ description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
51020
+ details: [
51021
+ {
51022
+ kind: 'error',
51023
+ message: 'this function dynamically created a component/hook',
51024
+ loc: (_b = (_a = parentNameExpr === null || parentNameExpr === void 0 ? void 0 : parentNameExpr.node.loc) !== null && _a !== void 0 ? _a : fn.node.loc) !== null && _b !== void 0 ? _b : null,
51025
+ },
51026
+ {
51027
+ kind: 'error',
51028
+ message: 'the component is created here',
51029
+ loc: (_d = (_c = nestedFnNameExpr === null || nestedFnNameExpr === void 0 ? void 0 : nestedFnNameExpr.node.loc) !== null && _c !== void 0 ? _c : nestedFn.node.loc) !== null && _d !== void 0 ? _d : null,
51030
+ },
51031
+ ],
51032
+ });
51033
+ }
51034
+ }
51035
+ nestedFn.skip();
51036
+ };
51037
+ fn.traverse({
51038
+ FunctionDeclaration: validateNestedFunction,
51039
+ FunctionExpression: validateNestedFunction,
51040
+ ArrowFunctionExpression: validateNestedFunction,
51041
+ });
51042
+ }
50957
51043
  function getReactFunctionType(fn, pass) {
50958
51044
  var _a, _b;
50959
51045
  const hookPattern = pass.opts.environment.hookPattern;
@@ -50983,9 +51069,6 @@ function getReactFunctionType(fn, pass) {
50983
51069
  return componentSyntaxType;
50984
51070
  }
50985
51071
  case 'all': {
50986
- if (fn.scope.getProgramParent() !== fn.scope.parent) {
50987
- return null;
50988
- }
50989
51072
  return (_b = getComponentOrHookLike(fn, hookPattern)) !== null && _b !== void 0 ? _b : 'Other';
50990
51073
  }
50991
51074
  default: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks",
3
3
  "description": "ESLint rules for React Hooks",
4
- "version": "6.1.0-canary-33a1095d-20250827",
4
+ "version": "6.1.0-canary-89a803fc-20250828",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/facebook/react.git",