eslint-plugin-react-hooks 7.1.0-canary-93fc5740-20251113 → 7.1.0-canary-fb2177c1-20251114

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.
@@ -22085,8 +22085,9 @@ const BuiltInStartTransitionId = 'BuiltInStartTransition';
22085
22085
  const BuiltInFireId = 'BuiltInFire';
22086
22086
  const BuiltInFireFunctionId = 'BuiltInFireFunction';
22087
22087
  const BuiltInUseEffectEventId = 'BuiltInUseEffectEvent';
22088
- const BuiltinEffectEventId = 'BuiltInEffectEventFunction';
22088
+ const BuiltInEffectEventId = 'BuiltInEffectEventFunction';
22089
22089
  const BuiltInAutodepsId = 'BuiltInAutoDepsId';
22090
+ const BuiltInEventHandlerId = 'BuiltInEventHandlerId';
22090
22091
  const ReanimatedSharedValueId = 'ReanimatedSharedValueId';
22091
22092
  const BUILTIN_SHAPES = new Map();
22092
22093
  addObject(BUILTIN_SHAPES, BuiltInPropsId, [
@@ -22733,7 +22734,14 @@ addFunction(BUILTIN_SHAPES, [], {
22733
22734
  returnType: { kind: 'Poly' },
22734
22735
  calleeEffect: Effect.ConditionallyMutate,
22735
22736
  returnValueKind: ValueKind.Mutable,
22736
- }, BuiltinEffectEventId);
22737
+ }, BuiltInEffectEventId);
22738
+ addFunction(BUILTIN_SHAPES, [], {
22739
+ positionalParams: [],
22740
+ restParam: Effect.ConditionallyMutate,
22741
+ returnType: { kind: 'Poly' },
22742
+ calleeEffect: Effect.ConditionallyMutate,
22743
+ returnValueKind: ValueKind.Mutable,
22744
+ }, BuiltInEventHandlerId);
22737
22745
  addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
22738
22746
  [
22739
22747
  'toString',
@@ -31121,7 +31129,7 @@ const REACT_APIS = [
31121
31129
  returnType: {
31122
31130
  kind: 'Function',
31123
31131
  return: { kind: 'Poly' },
31124
- shapeId: BuiltinEffectEventId,
31132
+ shapeId: BuiltInEffectEventId,
31125
31133
  isConstructor: false,
31126
31134
  },
31127
31135
  calleeEffect: Effect.Read,
@@ -32144,6 +32152,7 @@ const EnvironmentConfigSchema = v4.z.object({
32144
32152
  validateNoVoidUseMemo: v4.z.boolean().default(true),
32145
32153
  validateNoDynamicallyCreatedComponentsOrHooks: v4.z.boolean().default(false),
32146
32154
  enableAllowSetStateFromRefsInEffects: v4.z.boolean().default(true),
32155
+ enableInferEventHandlers: v4.z.boolean().default(false),
32147
32156
  });
32148
32157
  class Environment {
32149
32158
  constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
@@ -41052,6 +41061,7 @@ function applyEffect(context, state, _effect, initialized, effects) {
41052
41061
  case ValueKind.Primitive: {
41053
41062
  break;
41054
41063
  }
41064
+ case ValueKind.MaybeFrozen:
41055
41065
  case ValueKind.Frozen: {
41056
41066
  sourceType = 'frozen';
41057
41067
  break;
@@ -48306,6 +48316,25 @@ function* generateInstructionTypes(env, names, instr) {
48306
48316
  }
48307
48317
  }
48308
48318
  }
48319
+ if (env.config.enableInferEventHandlers) {
48320
+ if (value.kind === 'JsxExpression' &&
48321
+ value.tag.kind === 'BuiltinTag' &&
48322
+ !value.tag.name.includes('-')) {
48323
+ for (const prop of value.props) {
48324
+ if (prop.kind === 'JsxAttribute' &&
48325
+ prop.name.startsWith('on') &&
48326
+ prop.name.length > 2 &&
48327
+ prop.name[2] === prop.name[2].toUpperCase()) {
48328
+ yield equation(prop.place.identifier.type, {
48329
+ kind: 'Function',
48330
+ shapeId: BuiltInEventHandlerId,
48331
+ return: makeType(),
48332
+ isConstructor: false,
48333
+ });
48334
+ }
48335
+ }
48336
+ }
48337
+ }
48309
48338
  yield equation(left, { kind: 'Object', shapeId: BuiltInJsxId });
48310
48339
  break;
48311
48340
  }
@@ -49229,6 +49258,10 @@ function refTypeOfType(place) {
49229
49258
  return { kind: 'None' };
49230
49259
  }
49231
49260
  }
49261
+ function isEventHandlerType(identifier) {
49262
+ const type = identifier.type;
49263
+ return type.kind === 'Function' && type.shapeId === BuiltInEventHandlerId;
49264
+ }
49232
49265
  function tyEqual(a, b) {
49233
49266
  if (a.kind !== b.kind) {
49234
49267
  return false;
@@ -49515,8 +49548,10 @@ function validateNoRefAccessInRenderImpl(fn, env) {
49515
49548
  }
49516
49549
  if (!didError) {
49517
49550
  const isRefLValue = isUseRefType(instr.lvalue.identifier);
49551
+ const isEventHandlerLValue = isEventHandlerType(instr.lvalue.identifier);
49518
49552
  for (const operand of eachInstructionValueOperand(instr.value)) {
49519
49553
  if (isRefLValue ||
49554
+ isEventHandlerLValue ||
49520
49555
  (hookKind != null &&
49521
49556
  hookKind !== 'useState' &&
49522
49557
  hookKind !== 'useReducer')) {
@@ -52370,16 +52405,18 @@ function isNamedIdentifier(place) {
52370
52405
  }
52371
52406
  function validateNoDerivedComputationsInEffects_exp(fn) {
52372
52407
  const functions = new Map();
52408
+ const candidateDependencies = new Map();
52373
52409
  const derivationCache = new DerivationCache();
52374
52410
  const errors = new CompilerError();
52375
- const effects = new Set();
52411
+ const effectsCache = new Map();
52376
52412
  const setStateLoads = new Map();
52377
52413
  const setStateUsages = new Map();
52378
52414
  const context = {
52379
52415
  functions,
52416
+ candidateDependencies,
52380
52417
  errors,
52381
52418
  derivationCache,
52382
- effects,
52419
+ effectsCache,
52383
52420
  setStateLoads,
52384
52421
  setStateUsages,
52385
52422
  };
@@ -52416,8 +52453,8 @@ function validateNoDerivedComputationsInEffects_exp(fn) {
52416
52453
  }
52417
52454
  context.derivationCache.checkForChanges();
52418
52455
  } while (context.derivationCache.snapshot());
52419
- for (const effect of effects) {
52420
- validateEffect(effect, context);
52456
+ for (const [, effect] of effectsCache) {
52457
+ validateEffect(effect.effect, effect.dependencies, context);
52421
52458
  }
52422
52459
  return errors.asResult();
52423
52460
  }
@@ -52501,8 +52538,12 @@ function recordInstructionDerivations(instr, context, isFirstPass) {
52501
52538
  value.args[0].kind === 'Identifier' &&
52502
52539
  value.args[1].kind === 'Identifier') {
52503
52540
  const effectFunction = context.functions.get(value.args[0].identifier.id);
52504
- if (effectFunction != null) {
52505
- context.effects.add(effectFunction.loweredFunc.func);
52541
+ const deps = context.candidateDependencies.get(value.args[1].identifier.id);
52542
+ if (effectFunction != null && deps != null) {
52543
+ context.effectsCache.set(value.args[0].identifier.id, {
52544
+ effect: effectFunction.loweredFunc.func,
52545
+ dependencies: deps,
52546
+ });
52506
52547
  }
52507
52548
  }
52508
52549
  else if (isUseStateType(lvalue.identifier) && value.args.length > 0) {
@@ -52511,6 +52552,9 @@ function recordInstructionDerivations(instr, context, isFirstPass) {
52511
52552
  return;
52512
52553
  }
52513
52554
  }
52555
+ else if (value.kind === 'ArrayExpression') {
52556
+ context.candidateDependencies.set(lvalue.identifier.id, value);
52557
+ }
52514
52558
  for (const operand of eachInstructionOperand(instr)) {
52515
52559
  if (context.setStateLoads.has(operand.identifier.id)) {
52516
52560
  const rootSetStateId = getRootSetState(operand.identifier.id, context.setStateLoads);
@@ -52667,11 +52711,19 @@ function getFnLocalDeps(fn) {
52667
52711
  }
52668
52712
  return deps;
52669
52713
  }
52670
- function validateEffect(effectFunction, context) {
52714
+ function validateEffect(effectFunction, dependencies, context) {
52671
52715
  var _a;
52672
52716
  const seenBlocks = new Set();
52673
52717
  const effectDerivedSetStateCalls = [];
52674
52718
  const effectSetStateUsages = new Map();
52719
+ for (const dep of dependencies.elements) {
52720
+ if (dep.kind === 'Identifier') {
52721
+ const root = getRootSetState(dep.identifier.id, context.setStateLoads);
52722
+ if (root !== null) {
52723
+ effectSetStateUsages.set(root, new Set([dep.loc]));
52724
+ }
52725
+ }
52726
+ }
52675
52727
  let cleanUpFunctionDeps;
52676
52728
  const globals = new Set();
52677
52729
  for (const block of effectFunction.body.blocks.values()) {
@@ -52701,6 +52753,10 @@ function validateEffect(effectFunction, context) {
52701
52753
  isSetStateType(instr.value.callee.identifier) &&
52702
52754
  instr.value.args.length === 1 &&
52703
52755
  instr.value.args[0].kind === 'Identifier') {
52756
+ const calleeMetadata = context.derivationCache.cache.get(instr.value.callee.identifier.id);
52757
+ if ((calleeMetadata === null || calleeMetadata === void 0 ? void 0 : calleeMetadata.typeOfValue) != 'fromState') {
52758
+ continue;
52759
+ }
52704
52760
  const argMetadata = context.derivationCache.cache.get(instr.value.args[0].identifier.id);
52705
52761
  if (argMetadata !== undefined) {
52706
52762
  effectDerivedSetStateCalls.push({
@@ -22076,8 +22076,9 @@ const BuiltInStartTransitionId = 'BuiltInStartTransition';
22076
22076
  const BuiltInFireId = 'BuiltInFire';
22077
22077
  const BuiltInFireFunctionId = 'BuiltInFireFunction';
22078
22078
  const BuiltInUseEffectEventId = 'BuiltInUseEffectEvent';
22079
- const BuiltinEffectEventId = 'BuiltInEffectEventFunction';
22079
+ const BuiltInEffectEventId = 'BuiltInEffectEventFunction';
22080
22080
  const BuiltInAutodepsId = 'BuiltInAutoDepsId';
22081
+ const BuiltInEventHandlerId = 'BuiltInEventHandlerId';
22081
22082
  const ReanimatedSharedValueId = 'ReanimatedSharedValueId';
22082
22083
  const BUILTIN_SHAPES = new Map();
22083
22084
  addObject(BUILTIN_SHAPES, BuiltInPropsId, [
@@ -22724,7 +22725,14 @@ addFunction(BUILTIN_SHAPES, [], {
22724
22725
  returnType: { kind: 'Poly' },
22725
22726
  calleeEffect: Effect.ConditionallyMutate,
22726
22727
  returnValueKind: ValueKind.Mutable,
22727
- }, BuiltinEffectEventId);
22728
+ }, BuiltInEffectEventId);
22729
+ addFunction(BUILTIN_SHAPES, [], {
22730
+ positionalParams: [],
22731
+ restParam: Effect.ConditionallyMutate,
22732
+ returnType: { kind: 'Poly' },
22733
+ calleeEffect: Effect.ConditionallyMutate,
22734
+ returnValueKind: ValueKind.Mutable,
22735
+ }, BuiltInEventHandlerId);
22728
22736
  addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
22729
22737
  [
22730
22738
  'toString',
@@ -30948,7 +30956,7 @@ const REACT_APIS = [
30948
30956
  returnType: {
30949
30957
  kind: 'Function',
30950
30958
  return: { kind: 'Poly' },
30951
- shapeId: BuiltinEffectEventId,
30959
+ shapeId: BuiltInEffectEventId,
30952
30960
  isConstructor: false,
30953
30961
  },
30954
30962
  calleeEffect: Effect.Read,
@@ -31971,6 +31979,7 @@ const EnvironmentConfigSchema = v4.z.object({
31971
31979
  validateNoVoidUseMemo: v4.z.boolean().default(true),
31972
31980
  validateNoDynamicallyCreatedComponentsOrHooks: v4.z.boolean().default(false),
31973
31981
  enableAllowSetStateFromRefsInEffects: v4.z.boolean().default(true),
31982
+ enableInferEventHandlers: v4.z.boolean().default(false),
31974
31983
  });
31975
31984
  class Environment {
31976
31985
  constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
@@ -40879,6 +40888,7 @@ function applyEffect(context, state, _effect, initialized, effects) {
40879
40888
  case ValueKind.Primitive: {
40880
40889
  break;
40881
40890
  }
40891
+ case ValueKind.MaybeFrozen:
40882
40892
  case ValueKind.Frozen: {
40883
40893
  sourceType = 'frozen';
40884
40894
  break;
@@ -48133,6 +48143,25 @@ function* generateInstructionTypes(env, names, instr) {
48133
48143
  }
48134
48144
  }
48135
48145
  }
48146
+ if (env.config.enableInferEventHandlers) {
48147
+ if (value.kind === 'JsxExpression' &&
48148
+ value.tag.kind === 'BuiltinTag' &&
48149
+ !value.tag.name.includes('-')) {
48150
+ for (const prop of value.props) {
48151
+ if (prop.kind === 'JsxAttribute' &&
48152
+ prop.name.startsWith('on') &&
48153
+ prop.name.length > 2 &&
48154
+ prop.name[2] === prop.name[2].toUpperCase()) {
48155
+ yield equation(prop.place.identifier.type, {
48156
+ kind: 'Function',
48157
+ shapeId: BuiltInEventHandlerId,
48158
+ return: makeType(),
48159
+ isConstructor: false,
48160
+ });
48161
+ }
48162
+ }
48163
+ }
48164
+ }
48136
48165
  yield equation(left, { kind: 'Object', shapeId: BuiltInJsxId });
48137
48166
  break;
48138
48167
  }
@@ -49056,6 +49085,10 @@ function refTypeOfType(place) {
49056
49085
  return { kind: 'None' };
49057
49086
  }
49058
49087
  }
49088
+ function isEventHandlerType(identifier) {
49089
+ const type = identifier.type;
49090
+ return type.kind === 'Function' && type.shapeId === BuiltInEventHandlerId;
49091
+ }
49059
49092
  function tyEqual(a, b) {
49060
49093
  if (a.kind !== b.kind) {
49061
49094
  return false;
@@ -49342,8 +49375,10 @@ function validateNoRefAccessInRenderImpl(fn, env) {
49342
49375
  }
49343
49376
  if (!didError) {
49344
49377
  const isRefLValue = isUseRefType(instr.lvalue.identifier);
49378
+ const isEventHandlerLValue = isEventHandlerType(instr.lvalue.identifier);
49345
49379
  for (const operand of eachInstructionValueOperand(instr.value)) {
49346
49380
  if (isRefLValue ||
49381
+ isEventHandlerLValue ||
49347
49382
  (hookKind != null &&
49348
49383
  hookKind !== 'useState' &&
49349
49384
  hookKind !== 'useReducer')) {
@@ -52197,16 +52232,18 @@ function isNamedIdentifier(place) {
52197
52232
  }
52198
52233
  function validateNoDerivedComputationsInEffects_exp(fn) {
52199
52234
  const functions = new Map();
52235
+ const candidateDependencies = new Map();
52200
52236
  const derivationCache = new DerivationCache();
52201
52237
  const errors = new CompilerError();
52202
- const effects = new Set();
52238
+ const effectsCache = new Map();
52203
52239
  const setStateLoads = new Map();
52204
52240
  const setStateUsages = new Map();
52205
52241
  const context = {
52206
52242
  functions,
52243
+ candidateDependencies,
52207
52244
  errors,
52208
52245
  derivationCache,
52209
- effects,
52246
+ effectsCache,
52210
52247
  setStateLoads,
52211
52248
  setStateUsages,
52212
52249
  };
@@ -52243,8 +52280,8 @@ function validateNoDerivedComputationsInEffects_exp(fn) {
52243
52280
  }
52244
52281
  context.derivationCache.checkForChanges();
52245
52282
  } while (context.derivationCache.snapshot());
52246
- for (const effect of effects) {
52247
- validateEffect(effect, context);
52283
+ for (const [, effect] of effectsCache) {
52284
+ validateEffect(effect.effect, effect.dependencies, context);
52248
52285
  }
52249
52286
  return errors.asResult();
52250
52287
  }
@@ -52328,8 +52365,12 @@ function recordInstructionDerivations(instr, context, isFirstPass) {
52328
52365
  value.args[0].kind === 'Identifier' &&
52329
52366
  value.args[1].kind === 'Identifier') {
52330
52367
  const effectFunction = context.functions.get(value.args[0].identifier.id);
52331
- if (effectFunction != null) {
52332
- context.effects.add(effectFunction.loweredFunc.func);
52368
+ const deps = context.candidateDependencies.get(value.args[1].identifier.id);
52369
+ if (effectFunction != null && deps != null) {
52370
+ context.effectsCache.set(value.args[0].identifier.id, {
52371
+ effect: effectFunction.loweredFunc.func,
52372
+ dependencies: deps,
52373
+ });
52333
52374
  }
52334
52375
  }
52335
52376
  else if (isUseStateType(lvalue.identifier) && value.args.length > 0) {
@@ -52338,6 +52379,9 @@ function recordInstructionDerivations(instr, context, isFirstPass) {
52338
52379
  return;
52339
52380
  }
52340
52381
  }
52382
+ else if (value.kind === 'ArrayExpression') {
52383
+ context.candidateDependencies.set(lvalue.identifier.id, value);
52384
+ }
52341
52385
  for (const operand of eachInstructionOperand(instr)) {
52342
52386
  if (context.setStateLoads.has(operand.identifier.id)) {
52343
52387
  const rootSetStateId = getRootSetState(operand.identifier.id, context.setStateLoads);
@@ -52494,11 +52538,19 @@ function getFnLocalDeps(fn) {
52494
52538
  }
52495
52539
  return deps;
52496
52540
  }
52497
- function validateEffect(effectFunction, context) {
52541
+ function validateEffect(effectFunction, dependencies, context) {
52498
52542
  var _a;
52499
52543
  const seenBlocks = new Set();
52500
52544
  const effectDerivedSetStateCalls = [];
52501
52545
  const effectSetStateUsages = new Map();
52546
+ for (const dep of dependencies.elements) {
52547
+ if (dep.kind === 'Identifier') {
52548
+ const root = getRootSetState(dep.identifier.id, context.setStateLoads);
52549
+ if (root !== null) {
52550
+ effectSetStateUsages.set(root, new Set([dep.loc]));
52551
+ }
52552
+ }
52553
+ }
52502
52554
  let cleanUpFunctionDeps;
52503
52555
  const globals = new Set();
52504
52556
  for (const block of effectFunction.body.blocks.values()) {
@@ -52528,6 +52580,10 @@ function validateEffect(effectFunction, context) {
52528
52580
  isSetStateType(instr.value.callee.identifier) &&
52529
52581
  instr.value.args.length === 1 &&
52530
52582
  instr.value.args[0].kind === 'Identifier') {
52583
+ const calleeMetadata = context.derivationCache.cache.get(instr.value.callee.identifier.id);
52584
+ if ((calleeMetadata === null || calleeMetadata === void 0 ? void 0 : calleeMetadata.typeOfValue) != 'fromState') {
52585
+ continue;
52586
+ }
52531
52587
  const argMetadata = context.derivationCache.cache.get(instr.value.args[0].identifier.id);
52532
52588
  if (argMetadata !== undefined) {
52533
52589
  effectDerivedSetStateCalls.push({
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": "7.1.0-canary-93fc5740-20251113",
4
+ "version": "7.1.0-canary-fb2177c1-20251114",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/facebook/react.git",