eslint-plugin-react-hooks 6.1.0-canary-9be531cd-20250729 → 6.1.0-canary-9784cb37-20250730

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.
@@ -22065,6 +22065,7 @@ addObject(BUILTIN_SHAPES, BuiltInUseRefId, [
22065
22065
  addObject(BUILTIN_SHAPES, BuiltInRefValueId, [
22066
22066
  ['*', { kind: 'Object', shapeId: BuiltInRefValueId }],
22067
22067
  ]);
22068
+ addObject(BUILTIN_SHAPES, ReanimatedSharedValueId, []);
22068
22069
  addFunction(BUILTIN_SHAPES, [], {
22069
22070
  positionalParams: [],
22070
22071
  restParam: Effect.ConditionallyMutate,
@@ -30682,7 +30683,7 @@ const EnvironmentConfigSchema = zod.z.object({
30682
30683
  enableChangeDetectionForDebugging: ExternalFunctionSchema.nullable().default(null),
30683
30684
  enableCustomTypeDefinitionForReanimated: zod.z.boolean().default(false),
30684
30685
  hookPattern: zod.z.string().nullable().default(null),
30685
- enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(false),
30686
+ enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(true),
30686
30687
  lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
30687
30688
  validateNoVoidUseMemo: zod.z.boolean().default(false),
30688
30689
  });
@@ -44060,12 +44061,6 @@ class StableSidemap {
44060
44061
  });
44061
44062
  }
44062
44063
  }
44063
- else if (this.env.config.enableTreatRefLikeIdentifiersAsRefs &&
44064
- isUseRefType(lvalue.identifier)) {
44065
- this.map.set(lvalue.identifier.id, {
44066
- isStable: true,
44067
- });
44068
- }
44069
44064
  break;
44070
44065
  }
44071
44066
  case 'Destructure':
@@ -45244,7 +45239,7 @@ function makeOrMergeProperty(node, property, accessType) {
45244
45239
  var _DependencyCollectionContext_instances, _DependencyCollectionContext_declarations, _DependencyCollectionContext_reassignments, _DependencyCollectionContext_scopes, _DependencyCollectionContext_dependencies, _DependencyCollectionContext_temporaries, _DependencyCollectionContext_temporariesUsedOutsideScope, _DependencyCollectionContext_processedInstrsInOptional, _DependencyCollectionContext_innerFnContext, _DependencyCollectionContext_checkValidDependency, _DependencyCollectionContext_isScopeActive;
45245
45240
  function propagateScopeDependenciesHIR(fn) {
45246
45241
  const usedOutsideDeclaringScope = findTemporariesUsedOutsideDeclaringScope(fn);
45247
- const temporaries = collectTemporariesSidemap(fn, usedOutsideDeclaringScope);
45242
+ const temporaries = collectTemporariesSidemap$1(fn, usedOutsideDeclaringScope);
45248
45243
  const { temporariesReadInOptional, processedInstrsInOptional, hoistableObjects, } = collectOptionalChainSidemap(fn);
45249
45244
  const hoistablePropertyLoads = keyByScopeId(fn, collectHoistablePropertyLoads(fn, temporaries, hoistableObjects));
45250
45245
  const scopeDeps = collectDependencies(fn, usedOutsideDeclaringScope, new Map([...temporaries, ...temporariesReadInOptional]), processedInstrsInOptional);
@@ -45315,7 +45310,7 @@ function findTemporariesUsedOutsideDeclaringScope(fn) {
45315
45310
  }
45316
45311
  return usedOutsideDeclaringScope;
45317
45312
  }
45318
- function collectTemporariesSidemap(fn, usedOutsideDeclaringScope) {
45313
+ function collectTemporariesSidemap$1(fn, usedOutsideDeclaringScope) {
45319
45314
  const temporaries = new Map();
45320
45315
  collectTemporariesSidemapImpl(fn, usedOutsideDeclaringScope, temporaries, null);
45321
45316
  return temporaries;
@@ -46140,7 +46135,7 @@ function collectDepUsages(deps, fnExpr) {
46140
46135
  }
46141
46136
  function inferMinimalDependencies(fnInstr) {
46142
46137
  const fn = fnInstr.value.loweredFunc.func;
46143
- const temporaries = collectTemporariesSidemap(fn, new Set());
46138
+ const temporaries = collectTemporariesSidemap$1(fn, new Set());
46144
46139
  const { hoistableObjects, processedInstrsInOptional, temporariesReadInOptional, } = collectOptionalChainSidemap(fn);
46145
46140
  const hoistablePropertyLoads = collectHoistablePropertyLoadsInInnerFn(fnInstr, temporaries, hoistableObjects);
46146
46141
  const hoistableToFnEntry = hoistablePropertyLoads.get(fn.body.entry);
@@ -47308,6 +47303,18 @@ function* generateInstructionTypes(env, names, instr) {
47308
47303
  }
47309
47304
  case 'JsxExpression':
47310
47305
  case 'JsxFragment': {
47306
+ if (env.config.enableTreatRefLikeIdentifiersAsRefs) {
47307
+ if (value.kind === 'JsxExpression') {
47308
+ for (const prop of value.props) {
47309
+ if (prop.kind === 'JsxAttribute' && prop.name === 'ref') {
47310
+ yield equation(prop.place.identifier.type, {
47311
+ kind: 'Object',
47312
+ shapeId: BuiltInUseRefId,
47313
+ });
47314
+ }
47315
+ }
47316
+ }
47317
+ }
47311
47318
  yield equation(left, { kind: 'Object', shapeId: BuiltInJsxId });
47312
47319
  break;
47313
47320
  }
@@ -47322,7 +47329,18 @@ function* generateInstructionTypes(env, names, instr) {
47322
47329
  yield equation(left, returnType);
47323
47330
  break;
47324
47331
  }
47325
- case 'PropertyStore':
47332
+ case 'PropertyStore': {
47333
+ yield equation(makeType(), {
47334
+ kind: 'Property',
47335
+ objectType: value.object.identifier.type,
47336
+ objectName: getName(names, value.object.identifier.id),
47337
+ propertyName: {
47338
+ kind: 'literal',
47339
+ value: value.property,
47340
+ },
47341
+ });
47342
+ break;
47343
+ }
47326
47344
  case 'DeclareLocal':
47327
47345
  case 'RegExpLiteral':
47328
47346
  case 'MetaProperty':
@@ -48083,7 +48101,7 @@ function validateNoCapitalizedCalls(fn) {
48083
48101
  return errors.asResult();
48084
48102
  }
48085
48103
 
48086
- var _Env_changed;
48104
+ var _Env_changed, _Env_data, _Env_temporaries;
48087
48105
  function makeRefId(id) {
48088
48106
  CompilerError.invariant(id >= 0 && Number.isInteger(id), {
48089
48107
  reason: 'Expected identifier id to be a non-negative integer',
@@ -48097,10 +48115,18 @@ let _refId = 0;
48097
48115
  function nextRefId() {
48098
48116
  return makeRefId(_refId++);
48099
48117
  }
48100
- class Env extends Map {
48118
+ class Env {
48101
48119
  constructor() {
48102
- super(...arguments);
48103
48120
  _Env_changed.set(this, false);
48121
+ _Env_data.set(this, new Map());
48122
+ _Env_temporaries.set(this, new Map());
48123
+ }
48124
+ lookup(place) {
48125
+ var _a;
48126
+ return (_a = __classPrivateFieldGet(this, _Env_temporaries, "f").get(place.identifier.id)) !== null && _a !== void 0 ? _a : place;
48127
+ }
48128
+ define(place, value) {
48129
+ __classPrivateFieldGet(this, _Env_temporaries, "f").set(place.identifier.id, value);
48104
48130
  }
48105
48131
  resetChanged() {
48106
48132
  __classPrivateFieldSet(this, _Env_changed, false, "f");
@@ -48108,21 +48134,65 @@ class Env extends Map {
48108
48134
  hasChanged() {
48109
48135
  return __classPrivateFieldGet(this, _Env_changed, "f");
48110
48136
  }
48137
+ get(key) {
48138
+ var _a, _b;
48139
+ const operandId = (_b = (_a = __classPrivateFieldGet(this, _Env_temporaries, "f").get(key)) === null || _a === void 0 ? void 0 : _a.identifier.id) !== null && _b !== void 0 ? _b : key;
48140
+ return __classPrivateFieldGet(this, _Env_data, "f").get(operandId);
48141
+ }
48111
48142
  set(key, value) {
48112
- const cur = this.get(key);
48143
+ var _a, _b;
48144
+ const operandId = (_b = (_a = __classPrivateFieldGet(this, _Env_temporaries, "f").get(key)) === null || _a === void 0 ? void 0 : _a.identifier.id) !== null && _b !== void 0 ? _b : key;
48145
+ const cur = __classPrivateFieldGet(this, _Env_data, "f").get(operandId);
48113
48146
  const widenedValue = joinRefAccessTypes(value, cur !== null && cur !== void 0 ? cur : { kind: 'None' });
48114
48147
  if (!(cur == null && widenedValue.kind === 'None') &&
48115
48148
  (cur == null || !tyEqual(cur, widenedValue))) {
48116
48149
  __classPrivateFieldSet(this, _Env_changed, true, "f");
48117
48150
  }
48118
- return super.set(key, widenedValue);
48151
+ __classPrivateFieldGet(this, _Env_data, "f").set(operandId, widenedValue);
48152
+ return this;
48119
48153
  }
48120
48154
  }
48121
- _Env_changed = new WeakMap();
48155
+ _Env_changed = new WeakMap(), _Env_data = new WeakMap(), _Env_temporaries = new WeakMap();
48122
48156
  function validateNoRefAccessInRender(fn) {
48123
48157
  const env = new Env();
48158
+ collectTemporariesSidemap(fn, env);
48124
48159
  return validateNoRefAccessInRenderImpl(fn, env).map(_ => undefined);
48125
48160
  }
48161
+ function collectTemporariesSidemap(fn, env) {
48162
+ for (const block of fn.body.blocks.values()) {
48163
+ for (const instr of block.instructions) {
48164
+ const { lvalue, value } = instr;
48165
+ switch (value.kind) {
48166
+ case 'LoadLocal': {
48167
+ const temp = env.lookup(value.place);
48168
+ if (temp != null) {
48169
+ env.define(lvalue, temp);
48170
+ }
48171
+ break;
48172
+ }
48173
+ case 'StoreLocal': {
48174
+ const temp = env.lookup(value.value);
48175
+ if (temp != null) {
48176
+ env.define(lvalue, temp);
48177
+ env.define(value.lvalue.place, temp);
48178
+ }
48179
+ break;
48180
+ }
48181
+ case 'PropertyLoad': {
48182
+ if (isUseRefType(value.object.identifier) &&
48183
+ value.property === 'current') {
48184
+ continue;
48185
+ }
48186
+ const temp = env.lookup(value.object);
48187
+ if (temp != null) {
48188
+ env.define(lvalue, temp);
48189
+ }
48190
+ break;
48191
+ }
48192
+ }
48193
+ }
48194
+ }
48195
+ }
48126
48196
  function refTypeOfType(place) {
48127
48197
  if (isRefValueType(place.identifier)) {
48128
48198
  return { kind: 'RefValue' };
@@ -48266,12 +48336,26 @@ function validateNoRefAccessInRenderImpl(fn, env) {
48266
48336
  const type = refTypeOfType(place);
48267
48337
  env.set(place.identifier.id, type);
48268
48338
  }
48339
+ const interpolatedAsJsx = new Set();
48340
+ for (const block of fn.body.blocks.values()) {
48341
+ for (const instr of block.instructions) {
48342
+ const { value } = instr;
48343
+ if (value.kind === 'JsxExpression' || value.kind === 'JsxFragment') {
48344
+ if (value.children != null) {
48345
+ for (const child of value.children) {
48346
+ interpolatedAsJsx.add(child.identifier.id);
48347
+ }
48348
+ }
48349
+ }
48350
+ }
48351
+ }
48269
48352
  for (let i = 0; (i == 0 || env.hasChanged()) && i < 10; i++) {
48270
48353
  env.resetChanged();
48271
48354
  returnValues = [];
48272
- const safeBlocks = new Map();
48355
+ const safeBlocks = [];
48273
48356
  const errors = new CompilerError();
48274
48357
  for (const [, block] of fn.body.blocks) {
48358
+ retainWhere(safeBlocks, entry => entry.block !== block.id);
48275
48359
  for (const phi of block.phis) {
48276
48360
  env.set(phi.place.identifier.id, joinRefAccessTypes(...Array(...phi.operands.values()).map(operand => { var _a; return (_a = env.get(operand.identifier.id)) !== null && _a !== void 0 ? _a : { kind: 'None' }; })));
48277
48361
  }
@@ -48360,27 +48444,37 @@ function validateNoRefAccessInRenderImpl(fn, env) {
48360
48444
  const hookKind = getHookKindForType(fn.env, callee.identifier.type);
48361
48445
  let returnType = { kind: 'None' };
48362
48446
  const fnType = env.get(callee.identifier.id);
48447
+ let didError = false;
48363
48448
  if ((fnType === null || fnType === void 0 ? void 0 : fnType.kind) === 'Structure' && fnType.fn !== null) {
48364
48449
  returnType = fnType.fn.returnType;
48365
48450
  if (fnType.fn.readRefEffect) {
48366
- errors.push({
48451
+ didError = true;
48452
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48367
48453
  severity: ErrorSeverity.InvalidReact,
48368
- reason: 'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)',
48454
+ category: 'Cannot access refs during render',
48455
+ description: ERROR_DESCRIPTION,
48456
+ }).withDetail({
48457
+ kind: 'error',
48369
48458
  loc: callee.loc,
48370
- description: callee.identifier.name !== null &&
48371
- callee.identifier.name.kind === 'named'
48372
- ? `Function \`${callee.identifier.name.value}\` accesses a ref`
48373
- : null,
48374
- suggestions: null,
48375
- });
48459
+ message: `This function accesses a ref value`,
48460
+ }));
48376
48461
  }
48377
48462
  }
48378
- for (const operand of eachInstructionValueOperand(instr.value)) {
48379
- if (hookKind != null) {
48380
- validateNoDirectRefValueAccess(errors, operand, env);
48381
- }
48382
- else {
48383
- validateNoRefAccess(errors, env, operand, operand.loc);
48463
+ if (!didError) {
48464
+ const isRefLValue = isUseRefType(instr.lvalue.identifier);
48465
+ for (const operand of eachInstructionValueOperand(instr.value)) {
48466
+ if (isRefLValue ||
48467
+ (hookKind != null &&
48468
+ hookKind !== 'useState' &&
48469
+ hookKind !== 'useReducer')) {
48470
+ validateNoDirectRefValueAccess(errors, operand, env);
48471
+ }
48472
+ else if (interpolatedAsJsx.has(instr.lvalue.identifier.id)) {
48473
+ validateNoRefValueAccess(errors, env, operand);
48474
+ }
48475
+ else {
48476
+ validateNoRefPassedToFunction(errors, env, operand, operand.loc);
48477
+ }
48384
48478
  }
48385
48479
  }
48386
48480
  env.set(instr.lvalue.identifier.id, returnType);
@@ -48412,22 +48506,34 @@ function validateNoRefAccessInRenderImpl(fn, env) {
48412
48506
  case 'PropertyStore':
48413
48507
  case 'ComputedDelete':
48414
48508
  case 'ComputedStore': {
48415
- const safe = safeBlocks.get(block.id);
48416
48509
  const target = env.get(instr.value.object.identifier.id);
48510
+ let safe = null;
48417
48511
  if (instr.value.kind === 'PropertyStore' &&
48418
- safe != null &&
48419
- (target === null || target === void 0 ? void 0 : target.kind) === 'Ref' &&
48420
- target.refId === safe) {
48421
- safeBlocks.delete(block.id);
48512
+ target != null &&
48513
+ target.kind === 'Ref') {
48514
+ safe = safeBlocks.find(entry => entry.ref === target.refId);
48515
+ }
48516
+ if (safe != null) {
48517
+ retainWhere(safeBlocks, entry => entry !== safe);
48422
48518
  }
48423
48519
  else {
48424
- validateNoRefAccess(errors, env, instr.value.object, instr.loc);
48520
+ validateNoRefUpdate(errors, env, instr.value.object, instr.loc);
48425
48521
  }
48426
- for (const operand of eachInstructionValueOperand(instr.value)) {
48427
- if (operand === instr.value.object) {
48428
- continue;
48522
+ if (instr.value.kind === 'ComputedDelete' ||
48523
+ instr.value.kind === 'ComputedStore') {
48524
+ validateNoRefValueAccess(errors, env, instr.value.property);
48525
+ }
48526
+ if (instr.value.kind === 'ComputedStore' ||
48527
+ instr.value.kind === 'PropertyStore') {
48528
+ validateNoDirectRefValueAccess(errors, instr.value.value, env);
48529
+ const type = env.get(instr.value.value.identifier.id);
48530
+ if (type != null && type.kind === 'Structure') {
48531
+ let objectType = type;
48532
+ if (target != null) {
48533
+ objectType = joinRefAccessTypes(objectType, target);
48534
+ }
48535
+ env.set(instr.value.object.identifier.id, objectType);
48429
48536
  }
48430
- validateNoRefValueAccess(errors, env, operand);
48431
48537
  }
48432
48538
  break;
48433
48539
  }
@@ -48488,8 +48594,9 @@ function validateNoRefAccessInRenderImpl(fn, env) {
48488
48594
  }
48489
48595
  if (block.terminal.kind === 'if') {
48490
48596
  const test = env.get(block.terminal.test.identifier.id);
48491
- if ((test === null || test === void 0 ? void 0 : test.kind) === 'Guard') {
48492
- safeBlocks.set(block.terminal.consequent, test.refId);
48597
+ if ((test === null || test === void 0 ? void 0 : test.kind) === 'Guard' &&
48598
+ safeBlocks.find(entry => entry.ref === test.refId) == null) {
48599
+ safeBlocks.push({ block: block.terminal.fallthrough, ref: test.refId });
48493
48600
  }
48494
48601
  }
48495
48602
  for (const operand of eachTerminalOperand(block.terminal)) {
@@ -48525,16 +48632,15 @@ function destructure(type) {
48525
48632
  function guardCheck(errors, operand, env) {
48526
48633
  var _a;
48527
48634
  if (((_a = env.get(operand.identifier.id)) === null || _a === void 0 ? void 0 : _a.kind) === 'Guard') {
48528
- errors.push({
48635
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48529
48636
  severity: ErrorSeverity.InvalidReact,
48530
- reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
48637
+ category: 'Cannot access refs during render',
48638
+ description: ERROR_DESCRIPTION,
48639
+ }).withDetail({
48640
+ kind: 'error',
48531
48641
  loc: operand.loc,
48532
- description: operand.identifier.name !== null &&
48533
- operand.identifier.name.kind === 'named'
48534
- ? `Cannot access ref value \`${operand.identifier.name.value}\``
48535
- : null,
48536
- suggestions: null,
48537
- });
48642
+ message: `Cannot access ref value during render`,
48643
+ }));
48538
48644
  }
48539
48645
  }
48540
48646
  function validateNoRefValueAccess(errors, env, operand) {
@@ -48542,52 +48648,67 @@ function validateNoRefValueAccess(errors, env, operand) {
48542
48648
  const type = destructure(env.get(operand.identifier.id));
48543
48649
  if ((type === null || type === void 0 ? void 0 : type.kind) === 'RefValue' ||
48544
48650
  ((type === null || type === void 0 ? void 0 : type.kind) === 'Structure' && ((_a = type.fn) === null || _a === void 0 ? void 0 : _a.readRefEffect))) {
48545
- errors.push({
48651
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48546
48652
  severity: ErrorSeverity.InvalidReact,
48547
- reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
48653
+ category: 'Cannot access refs during render',
48654
+ description: ERROR_DESCRIPTION,
48655
+ }).withDetail({
48656
+ kind: 'error',
48548
48657
  loc: (type.kind === 'RefValue' && type.loc) || operand.loc,
48549
- description: operand.identifier.name !== null &&
48550
- operand.identifier.name.kind === 'named'
48551
- ? `Cannot access ref value \`${operand.identifier.name.value}\``
48552
- : null,
48553
- suggestions: null,
48554
- });
48658
+ message: `Cannot access ref value during render`,
48659
+ }));
48555
48660
  }
48556
48661
  }
48557
- function validateNoRefAccess(errors, env, operand, loc) {
48662
+ function validateNoRefPassedToFunction(errors, env, operand, loc) {
48558
48663
  var _a;
48559
48664
  const type = destructure(env.get(operand.identifier.id));
48560
48665
  if ((type === null || type === void 0 ? void 0 : type.kind) === 'Ref' ||
48561
48666
  (type === null || type === void 0 ? void 0 : type.kind) === 'RefValue' ||
48562
48667
  ((type === null || type === void 0 ? void 0 : type.kind) === 'Structure' && ((_a = type.fn) === null || _a === void 0 ? void 0 : _a.readRefEffect))) {
48563
- errors.push({
48668
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48669
+ severity: ErrorSeverity.InvalidReact,
48670
+ category: 'Cannot access refs during render',
48671
+ description: ERROR_DESCRIPTION,
48672
+ }).withDetail({
48673
+ kind: 'error',
48674
+ loc: (type.kind === 'RefValue' && type.loc) || loc,
48675
+ message: `Passing a ref to a function may read its value during render`,
48676
+ }));
48677
+ }
48678
+ }
48679
+ function validateNoRefUpdate(errors, env, operand, loc) {
48680
+ const type = destructure(env.get(operand.identifier.id));
48681
+ if ((type === null || type === void 0 ? void 0 : type.kind) === 'Ref' || (type === null || type === void 0 ? void 0 : type.kind) === 'RefValue') {
48682
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48564
48683
  severity: ErrorSeverity.InvalidReact,
48565
- reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
48684
+ category: 'Cannot access refs during render',
48685
+ description: ERROR_DESCRIPTION,
48686
+ }).withDetail({
48687
+ kind: 'error',
48566
48688
  loc: (type.kind === 'RefValue' && type.loc) || loc,
48567
- description: operand.identifier.name !== null &&
48568
- operand.identifier.name.kind === 'named'
48569
- ? `Cannot access ref value \`${operand.identifier.name.value}\``
48570
- : null,
48571
- suggestions: null,
48572
- });
48689
+ message: `Cannot update ref during render`,
48690
+ }));
48573
48691
  }
48574
48692
  }
48575
48693
  function validateNoDirectRefValueAccess(errors, operand, env) {
48576
48694
  var _a;
48577
48695
  const type = destructure(env.get(operand.identifier.id));
48578
48696
  if ((type === null || type === void 0 ? void 0 : type.kind) === 'RefValue') {
48579
- errors.push({
48697
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48580
48698
  severity: ErrorSeverity.InvalidReact,
48581
- reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
48699
+ category: 'Cannot access refs during render',
48700
+ description: ERROR_DESCRIPTION,
48701
+ }).withDetail({
48702
+ kind: 'error',
48582
48703
  loc: (_a = type.loc) !== null && _a !== void 0 ? _a : operand.loc,
48583
- description: operand.identifier.name !== null &&
48584
- operand.identifier.name.kind === 'named'
48585
- ? `Cannot access ref value \`${operand.identifier.name.value}\``
48586
- : null,
48587
- suggestions: null,
48588
- });
48704
+ message: `Cannot access ref value during render`,
48705
+ }));
48589
48706
  }
48590
48707
  }
48708
+ const ERROR_DESCRIPTION = 'React refs are values that are not needed for rendering. Refs should only be accessed ' +
48709
+ 'outside of render, such as in event handlers or effects. ' +
48710
+ 'Accessing a ref value (the `current` property) during render can cause your component ' +
48711
+ 'not to update as expected (https://react.dev/reference/react/useRef)';
48591
48712
 
48592
48713
  function validateNoSetStateInRender(fn) {
48593
48714
  const unconditionalSetStateFunctions = new Set();
@@ -52676,7 +52797,7 @@ const COMPILER_OPTIONS = {
52676
52797
  panicThreshold: 'none',
52677
52798
  flowSuppressions: false,
52678
52799
  environment: validateEnvironmentConfig({
52679
- validateRefAccessDuringRender: false,
52800
+ validateRefAccessDuringRender: true,
52680
52801
  validateNoSetStateInRender: true,
52681
52802
  validateNoSetStateInEffects: true,
52682
52803
  validateNoJSXInTryStatements: true,
@@ -55745,6 +55866,15 @@ function isInsideDoWhileLoop(node) {
55745
55866
  }
55746
55867
  return false;
55747
55868
  }
55869
+ function isInsideTryCatch(node) {
55870
+ while (node) {
55871
+ if (node.type === 'TryStatement' || node.type === 'CatchClause') {
55872
+ return true;
55873
+ }
55874
+ node = node.parent;
55875
+ }
55876
+ return false;
55877
+ }
55748
55878
  function isUseEffectEventIdentifier(node) {
55749
55879
  return false;
55750
55880
  }
@@ -55946,6 +56076,12 @@ const rule = {
55946
56076
  if (hasFlowSuppression(hook, 'react-rule-hook')) {
55947
56077
  continue;
55948
56078
  }
56079
+ if (isUseIdentifier(hook) && isInsideTryCatch(hook)) {
56080
+ context.report({
56081
+ node: hook,
56082
+ message: `React Hook "${getSourceCode().getText(hook)}" cannot be called in a try/catch block.`,
56083
+ });
56084
+ }
55949
56085
  if ((cycled || isInsideDoWhileLoop(hook)) &&
55950
56086
  !isUseIdentifier(hook)) {
55951
56087
  context.report({
@@ -22056,6 +22056,7 @@ addObject(BUILTIN_SHAPES, BuiltInUseRefId, [
22056
22056
  addObject(BUILTIN_SHAPES, BuiltInRefValueId, [
22057
22057
  ['*', { kind: 'Object', shapeId: BuiltInRefValueId }],
22058
22058
  ]);
22059
+ addObject(BUILTIN_SHAPES, ReanimatedSharedValueId, []);
22059
22060
  addFunction(BUILTIN_SHAPES, [], {
22060
22061
  positionalParams: [],
22061
22062
  restParam: Effect.ConditionallyMutate,
@@ -30509,7 +30510,7 @@ const EnvironmentConfigSchema = zod.z.object({
30509
30510
  enableChangeDetectionForDebugging: ExternalFunctionSchema.nullable().default(null),
30510
30511
  enableCustomTypeDefinitionForReanimated: zod.z.boolean().default(false),
30511
30512
  hookPattern: zod.z.string().nullable().default(null),
30512
- enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(false),
30513
+ enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(true),
30513
30514
  lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
30514
30515
  validateNoVoidUseMemo: zod.z.boolean().default(false),
30515
30516
  });
@@ -43887,12 +43888,6 @@ class StableSidemap {
43887
43888
  });
43888
43889
  }
43889
43890
  }
43890
- else if (this.env.config.enableTreatRefLikeIdentifiersAsRefs &&
43891
- isUseRefType(lvalue.identifier)) {
43892
- this.map.set(lvalue.identifier.id, {
43893
- isStable: true,
43894
- });
43895
- }
43896
43891
  break;
43897
43892
  }
43898
43893
  case 'Destructure':
@@ -45071,7 +45066,7 @@ function makeOrMergeProperty(node, property, accessType) {
45071
45066
  var _DependencyCollectionContext_instances, _DependencyCollectionContext_declarations, _DependencyCollectionContext_reassignments, _DependencyCollectionContext_scopes, _DependencyCollectionContext_dependencies, _DependencyCollectionContext_temporaries, _DependencyCollectionContext_temporariesUsedOutsideScope, _DependencyCollectionContext_processedInstrsInOptional, _DependencyCollectionContext_innerFnContext, _DependencyCollectionContext_checkValidDependency, _DependencyCollectionContext_isScopeActive;
45072
45067
  function propagateScopeDependenciesHIR(fn) {
45073
45068
  const usedOutsideDeclaringScope = findTemporariesUsedOutsideDeclaringScope(fn);
45074
- const temporaries = collectTemporariesSidemap(fn, usedOutsideDeclaringScope);
45069
+ const temporaries = collectTemporariesSidemap$1(fn, usedOutsideDeclaringScope);
45075
45070
  const { temporariesReadInOptional, processedInstrsInOptional, hoistableObjects, } = collectOptionalChainSidemap(fn);
45076
45071
  const hoistablePropertyLoads = keyByScopeId(fn, collectHoistablePropertyLoads(fn, temporaries, hoistableObjects));
45077
45072
  const scopeDeps = collectDependencies(fn, usedOutsideDeclaringScope, new Map([...temporaries, ...temporariesReadInOptional]), processedInstrsInOptional);
@@ -45142,7 +45137,7 @@ function findTemporariesUsedOutsideDeclaringScope(fn) {
45142
45137
  }
45143
45138
  return usedOutsideDeclaringScope;
45144
45139
  }
45145
- function collectTemporariesSidemap(fn, usedOutsideDeclaringScope) {
45140
+ function collectTemporariesSidemap$1(fn, usedOutsideDeclaringScope) {
45146
45141
  const temporaries = new Map();
45147
45142
  collectTemporariesSidemapImpl(fn, usedOutsideDeclaringScope, temporaries, null);
45148
45143
  return temporaries;
@@ -45967,7 +45962,7 @@ function collectDepUsages(deps, fnExpr) {
45967
45962
  }
45968
45963
  function inferMinimalDependencies(fnInstr) {
45969
45964
  const fn = fnInstr.value.loweredFunc.func;
45970
- const temporaries = collectTemporariesSidemap(fn, new Set());
45965
+ const temporaries = collectTemporariesSidemap$1(fn, new Set());
45971
45966
  const { hoistableObjects, processedInstrsInOptional, temporariesReadInOptional, } = collectOptionalChainSidemap(fn);
45972
45967
  const hoistablePropertyLoads = collectHoistablePropertyLoadsInInnerFn(fnInstr, temporaries, hoistableObjects);
45973
45968
  const hoistableToFnEntry = hoistablePropertyLoads.get(fn.body.entry);
@@ -47135,6 +47130,18 @@ function* generateInstructionTypes(env, names, instr) {
47135
47130
  }
47136
47131
  case 'JsxExpression':
47137
47132
  case 'JsxFragment': {
47133
+ if (env.config.enableTreatRefLikeIdentifiersAsRefs) {
47134
+ if (value.kind === 'JsxExpression') {
47135
+ for (const prop of value.props) {
47136
+ if (prop.kind === 'JsxAttribute' && prop.name === 'ref') {
47137
+ yield equation(prop.place.identifier.type, {
47138
+ kind: 'Object',
47139
+ shapeId: BuiltInUseRefId,
47140
+ });
47141
+ }
47142
+ }
47143
+ }
47144
+ }
47138
47145
  yield equation(left, { kind: 'Object', shapeId: BuiltInJsxId });
47139
47146
  break;
47140
47147
  }
@@ -47149,7 +47156,18 @@ function* generateInstructionTypes(env, names, instr) {
47149
47156
  yield equation(left, returnType);
47150
47157
  break;
47151
47158
  }
47152
- case 'PropertyStore':
47159
+ case 'PropertyStore': {
47160
+ yield equation(makeType(), {
47161
+ kind: 'Property',
47162
+ objectType: value.object.identifier.type,
47163
+ objectName: getName(names, value.object.identifier.id),
47164
+ propertyName: {
47165
+ kind: 'literal',
47166
+ value: value.property,
47167
+ },
47168
+ });
47169
+ break;
47170
+ }
47153
47171
  case 'DeclareLocal':
47154
47172
  case 'RegExpLiteral':
47155
47173
  case 'MetaProperty':
@@ -47910,7 +47928,7 @@ function validateNoCapitalizedCalls(fn) {
47910
47928
  return errors.asResult();
47911
47929
  }
47912
47930
 
47913
- var _Env_changed;
47931
+ var _Env_changed, _Env_data, _Env_temporaries;
47914
47932
  function makeRefId(id) {
47915
47933
  CompilerError.invariant(id >= 0 && Number.isInteger(id), {
47916
47934
  reason: 'Expected identifier id to be a non-negative integer',
@@ -47924,10 +47942,18 @@ let _refId = 0;
47924
47942
  function nextRefId() {
47925
47943
  return makeRefId(_refId++);
47926
47944
  }
47927
- class Env extends Map {
47945
+ class Env {
47928
47946
  constructor() {
47929
- super(...arguments);
47930
47947
  _Env_changed.set(this, false);
47948
+ _Env_data.set(this, new Map());
47949
+ _Env_temporaries.set(this, new Map());
47950
+ }
47951
+ lookup(place) {
47952
+ var _a;
47953
+ return (_a = __classPrivateFieldGet(this, _Env_temporaries, "f").get(place.identifier.id)) !== null && _a !== void 0 ? _a : place;
47954
+ }
47955
+ define(place, value) {
47956
+ __classPrivateFieldGet(this, _Env_temporaries, "f").set(place.identifier.id, value);
47931
47957
  }
47932
47958
  resetChanged() {
47933
47959
  __classPrivateFieldSet(this, _Env_changed, false, "f");
@@ -47935,21 +47961,65 @@ class Env extends Map {
47935
47961
  hasChanged() {
47936
47962
  return __classPrivateFieldGet(this, _Env_changed, "f");
47937
47963
  }
47964
+ get(key) {
47965
+ var _a, _b;
47966
+ const operandId = (_b = (_a = __classPrivateFieldGet(this, _Env_temporaries, "f").get(key)) === null || _a === void 0 ? void 0 : _a.identifier.id) !== null && _b !== void 0 ? _b : key;
47967
+ return __classPrivateFieldGet(this, _Env_data, "f").get(operandId);
47968
+ }
47938
47969
  set(key, value) {
47939
- const cur = this.get(key);
47970
+ var _a, _b;
47971
+ const operandId = (_b = (_a = __classPrivateFieldGet(this, _Env_temporaries, "f").get(key)) === null || _a === void 0 ? void 0 : _a.identifier.id) !== null && _b !== void 0 ? _b : key;
47972
+ const cur = __classPrivateFieldGet(this, _Env_data, "f").get(operandId);
47940
47973
  const widenedValue = joinRefAccessTypes(value, cur !== null && cur !== void 0 ? cur : { kind: 'None' });
47941
47974
  if (!(cur == null && widenedValue.kind === 'None') &&
47942
47975
  (cur == null || !tyEqual(cur, widenedValue))) {
47943
47976
  __classPrivateFieldSet(this, _Env_changed, true, "f");
47944
47977
  }
47945
- return super.set(key, widenedValue);
47978
+ __classPrivateFieldGet(this, _Env_data, "f").set(operandId, widenedValue);
47979
+ return this;
47946
47980
  }
47947
47981
  }
47948
- _Env_changed = new WeakMap();
47982
+ _Env_changed = new WeakMap(), _Env_data = new WeakMap(), _Env_temporaries = new WeakMap();
47949
47983
  function validateNoRefAccessInRender(fn) {
47950
47984
  const env = new Env();
47985
+ collectTemporariesSidemap(fn, env);
47951
47986
  return validateNoRefAccessInRenderImpl(fn, env).map(_ => undefined);
47952
47987
  }
47988
+ function collectTemporariesSidemap(fn, env) {
47989
+ for (const block of fn.body.blocks.values()) {
47990
+ for (const instr of block.instructions) {
47991
+ const { lvalue, value } = instr;
47992
+ switch (value.kind) {
47993
+ case 'LoadLocal': {
47994
+ const temp = env.lookup(value.place);
47995
+ if (temp != null) {
47996
+ env.define(lvalue, temp);
47997
+ }
47998
+ break;
47999
+ }
48000
+ case 'StoreLocal': {
48001
+ const temp = env.lookup(value.value);
48002
+ if (temp != null) {
48003
+ env.define(lvalue, temp);
48004
+ env.define(value.lvalue.place, temp);
48005
+ }
48006
+ break;
48007
+ }
48008
+ case 'PropertyLoad': {
48009
+ if (isUseRefType(value.object.identifier) &&
48010
+ value.property === 'current') {
48011
+ continue;
48012
+ }
48013
+ const temp = env.lookup(value.object);
48014
+ if (temp != null) {
48015
+ env.define(lvalue, temp);
48016
+ }
48017
+ break;
48018
+ }
48019
+ }
48020
+ }
48021
+ }
48022
+ }
47953
48023
  function refTypeOfType(place) {
47954
48024
  if (isRefValueType(place.identifier)) {
47955
48025
  return { kind: 'RefValue' };
@@ -48093,12 +48163,26 @@ function validateNoRefAccessInRenderImpl(fn, env) {
48093
48163
  const type = refTypeOfType(place);
48094
48164
  env.set(place.identifier.id, type);
48095
48165
  }
48166
+ const interpolatedAsJsx = new Set();
48167
+ for (const block of fn.body.blocks.values()) {
48168
+ for (const instr of block.instructions) {
48169
+ const { value } = instr;
48170
+ if (value.kind === 'JsxExpression' || value.kind === 'JsxFragment') {
48171
+ if (value.children != null) {
48172
+ for (const child of value.children) {
48173
+ interpolatedAsJsx.add(child.identifier.id);
48174
+ }
48175
+ }
48176
+ }
48177
+ }
48178
+ }
48096
48179
  for (let i = 0; (i == 0 || env.hasChanged()) && i < 10; i++) {
48097
48180
  env.resetChanged();
48098
48181
  returnValues = [];
48099
- const safeBlocks = new Map();
48182
+ const safeBlocks = [];
48100
48183
  const errors = new CompilerError();
48101
48184
  for (const [, block] of fn.body.blocks) {
48185
+ retainWhere(safeBlocks, entry => entry.block !== block.id);
48102
48186
  for (const phi of block.phis) {
48103
48187
  env.set(phi.place.identifier.id, joinRefAccessTypes(...Array(...phi.operands.values()).map(operand => { var _a; return (_a = env.get(operand.identifier.id)) !== null && _a !== void 0 ? _a : { kind: 'None' }; })));
48104
48188
  }
@@ -48187,27 +48271,37 @@ function validateNoRefAccessInRenderImpl(fn, env) {
48187
48271
  const hookKind = getHookKindForType(fn.env, callee.identifier.type);
48188
48272
  let returnType = { kind: 'None' };
48189
48273
  const fnType = env.get(callee.identifier.id);
48274
+ let didError = false;
48190
48275
  if ((fnType === null || fnType === void 0 ? void 0 : fnType.kind) === 'Structure' && fnType.fn !== null) {
48191
48276
  returnType = fnType.fn.returnType;
48192
48277
  if (fnType.fn.readRefEffect) {
48193
- errors.push({
48278
+ didError = true;
48279
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48194
48280
  severity: ErrorSeverity.InvalidReact,
48195
- reason: 'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)',
48281
+ category: 'Cannot access refs during render',
48282
+ description: ERROR_DESCRIPTION,
48283
+ }).withDetail({
48284
+ kind: 'error',
48196
48285
  loc: callee.loc,
48197
- description: callee.identifier.name !== null &&
48198
- callee.identifier.name.kind === 'named'
48199
- ? `Function \`${callee.identifier.name.value}\` accesses a ref`
48200
- : null,
48201
- suggestions: null,
48202
- });
48286
+ message: `This function accesses a ref value`,
48287
+ }));
48203
48288
  }
48204
48289
  }
48205
- for (const operand of eachInstructionValueOperand(instr.value)) {
48206
- if (hookKind != null) {
48207
- validateNoDirectRefValueAccess(errors, operand, env);
48208
- }
48209
- else {
48210
- validateNoRefAccess(errors, env, operand, operand.loc);
48290
+ if (!didError) {
48291
+ const isRefLValue = isUseRefType(instr.lvalue.identifier);
48292
+ for (const operand of eachInstructionValueOperand(instr.value)) {
48293
+ if (isRefLValue ||
48294
+ (hookKind != null &&
48295
+ hookKind !== 'useState' &&
48296
+ hookKind !== 'useReducer')) {
48297
+ validateNoDirectRefValueAccess(errors, operand, env);
48298
+ }
48299
+ else if (interpolatedAsJsx.has(instr.lvalue.identifier.id)) {
48300
+ validateNoRefValueAccess(errors, env, operand);
48301
+ }
48302
+ else {
48303
+ validateNoRefPassedToFunction(errors, env, operand, operand.loc);
48304
+ }
48211
48305
  }
48212
48306
  }
48213
48307
  env.set(instr.lvalue.identifier.id, returnType);
@@ -48239,22 +48333,34 @@ function validateNoRefAccessInRenderImpl(fn, env) {
48239
48333
  case 'PropertyStore':
48240
48334
  case 'ComputedDelete':
48241
48335
  case 'ComputedStore': {
48242
- const safe = safeBlocks.get(block.id);
48243
48336
  const target = env.get(instr.value.object.identifier.id);
48337
+ let safe = null;
48244
48338
  if (instr.value.kind === 'PropertyStore' &&
48245
- safe != null &&
48246
- (target === null || target === void 0 ? void 0 : target.kind) === 'Ref' &&
48247
- target.refId === safe) {
48248
- safeBlocks.delete(block.id);
48339
+ target != null &&
48340
+ target.kind === 'Ref') {
48341
+ safe = safeBlocks.find(entry => entry.ref === target.refId);
48342
+ }
48343
+ if (safe != null) {
48344
+ retainWhere(safeBlocks, entry => entry !== safe);
48249
48345
  }
48250
48346
  else {
48251
- validateNoRefAccess(errors, env, instr.value.object, instr.loc);
48347
+ validateNoRefUpdate(errors, env, instr.value.object, instr.loc);
48252
48348
  }
48253
- for (const operand of eachInstructionValueOperand(instr.value)) {
48254
- if (operand === instr.value.object) {
48255
- continue;
48349
+ if (instr.value.kind === 'ComputedDelete' ||
48350
+ instr.value.kind === 'ComputedStore') {
48351
+ validateNoRefValueAccess(errors, env, instr.value.property);
48352
+ }
48353
+ if (instr.value.kind === 'ComputedStore' ||
48354
+ instr.value.kind === 'PropertyStore') {
48355
+ validateNoDirectRefValueAccess(errors, instr.value.value, env);
48356
+ const type = env.get(instr.value.value.identifier.id);
48357
+ if (type != null && type.kind === 'Structure') {
48358
+ let objectType = type;
48359
+ if (target != null) {
48360
+ objectType = joinRefAccessTypes(objectType, target);
48361
+ }
48362
+ env.set(instr.value.object.identifier.id, objectType);
48256
48363
  }
48257
- validateNoRefValueAccess(errors, env, operand);
48258
48364
  }
48259
48365
  break;
48260
48366
  }
@@ -48315,8 +48421,9 @@ function validateNoRefAccessInRenderImpl(fn, env) {
48315
48421
  }
48316
48422
  if (block.terminal.kind === 'if') {
48317
48423
  const test = env.get(block.terminal.test.identifier.id);
48318
- if ((test === null || test === void 0 ? void 0 : test.kind) === 'Guard') {
48319
- safeBlocks.set(block.terminal.consequent, test.refId);
48424
+ if ((test === null || test === void 0 ? void 0 : test.kind) === 'Guard' &&
48425
+ safeBlocks.find(entry => entry.ref === test.refId) == null) {
48426
+ safeBlocks.push({ block: block.terminal.fallthrough, ref: test.refId });
48320
48427
  }
48321
48428
  }
48322
48429
  for (const operand of eachTerminalOperand(block.terminal)) {
@@ -48352,16 +48459,15 @@ function destructure(type) {
48352
48459
  function guardCheck(errors, operand, env) {
48353
48460
  var _a;
48354
48461
  if (((_a = env.get(operand.identifier.id)) === null || _a === void 0 ? void 0 : _a.kind) === 'Guard') {
48355
- errors.push({
48462
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48356
48463
  severity: ErrorSeverity.InvalidReact,
48357
- reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
48464
+ category: 'Cannot access refs during render',
48465
+ description: ERROR_DESCRIPTION,
48466
+ }).withDetail({
48467
+ kind: 'error',
48358
48468
  loc: operand.loc,
48359
- description: operand.identifier.name !== null &&
48360
- operand.identifier.name.kind === 'named'
48361
- ? `Cannot access ref value \`${operand.identifier.name.value}\``
48362
- : null,
48363
- suggestions: null,
48364
- });
48469
+ message: `Cannot access ref value during render`,
48470
+ }));
48365
48471
  }
48366
48472
  }
48367
48473
  function validateNoRefValueAccess(errors, env, operand) {
@@ -48369,52 +48475,67 @@ function validateNoRefValueAccess(errors, env, operand) {
48369
48475
  const type = destructure(env.get(operand.identifier.id));
48370
48476
  if ((type === null || type === void 0 ? void 0 : type.kind) === 'RefValue' ||
48371
48477
  ((type === null || type === void 0 ? void 0 : type.kind) === 'Structure' && ((_a = type.fn) === null || _a === void 0 ? void 0 : _a.readRefEffect))) {
48372
- errors.push({
48478
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48373
48479
  severity: ErrorSeverity.InvalidReact,
48374
- reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
48480
+ category: 'Cannot access refs during render',
48481
+ description: ERROR_DESCRIPTION,
48482
+ }).withDetail({
48483
+ kind: 'error',
48375
48484
  loc: (type.kind === 'RefValue' && type.loc) || operand.loc,
48376
- description: operand.identifier.name !== null &&
48377
- operand.identifier.name.kind === 'named'
48378
- ? `Cannot access ref value \`${operand.identifier.name.value}\``
48379
- : null,
48380
- suggestions: null,
48381
- });
48485
+ message: `Cannot access ref value during render`,
48486
+ }));
48382
48487
  }
48383
48488
  }
48384
- function validateNoRefAccess(errors, env, operand, loc) {
48489
+ function validateNoRefPassedToFunction(errors, env, operand, loc) {
48385
48490
  var _a;
48386
48491
  const type = destructure(env.get(operand.identifier.id));
48387
48492
  if ((type === null || type === void 0 ? void 0 : type.kind) === 'Ref' ||
48388
48493
  (type === null || type === void 0 ? void 0 : type.kind) === 'RefValue' ||
48389
48494
  ((type === null || type === void 0 ? void 0 : type.kind) === 'Structure' && ((_a = type.fn) === null || _a === void 0 ? void 0 : _a.readRefEffect))) {
48390
- errors.push({
48495
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48496
+ severity: ErrorSeverity.InvalidReact,
48497
+ category: 'Cannot access refs during render',
48498
+ description: ERROR_DESCRIPTION,
48499
+ }).withDetail({
48500
+ kind: 'error',
48501
+ loc: (type.kind === 'RefValue' && type.loc) || loc,
48502
+ message: `Passing a ref to a function may read its value during render`,
48503
+ }));
48504
+ }
48505
+ }
48506
+ function validateNoRefUpdate(errors, env, operand, loc) {
48507
+ const type = destructure(env.get(operand.identifier.id));
48508
+ if ((type === null || type === void 0 ? void 0 : type.kind) === 'Ref' || (type === null || type === void 0 ? void 0 : type.kind) === 'RefValue') {
48509
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48391
48510
  severity: ErrorSeverity.InvalidReact,
48392
- reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
48511
+ category: 'Cannot access refs during render',
48512
+ description: ERROR_DESCRIPTION,
48513
+ }).withDetail({
48514
+ kind: 'error',
48393
48515
  loc: (type.kind === 'RefValue' && type.loc) || loc,
48394
- description: operand.identifier.name !== null &&
48395
- operand.identifier.name.kind === 'named'
48396
- ? `Cannot access ref value \`${operand.identifier.name.value}\``
48397
- : null,
48398
- suggestions: null,
48399
- });
48516
+ message: `Cannot update ref during render`,
48517
+ }));
48400
48518
  }
48401
48519
  }
48402
48520
  function validateNoDirectRefValueAccess(errors, operand, env) {
48403
48521
  var _a;
48404
48522
  const type = destructure(env.get(operand.identifier.id));
48405
48523
  if ((type === null || type === void 0 ? void 0 : type.kind) === 'RefValue') {
48406
- errors.push({
48524
+ errors.pushDiagnostic(CompilerDiagnostic.create({
48407
48525
  severity: ErrorSeverity.InvalidReact,
48408
- reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
48526
+ category: 'Cannot access refs during render',
48527
+ description: ERROR_DESCRIPTION,
48528
+ }).withDetail({
48529
+ kind: 'error',
48409
48530
  loc: (_a = type.loc) !== null && _a !== void 0 ? _a : operand.loc,
48410
- description: operand.identifier.name !== null &&
48411
- operand.identifier.name.kind === 'named'
48412
- ? `Cannot access ref value \`${operand.identifier.name.value}\``
48413
- : null,
48414
- suggestions: null,
48415
- });
48531
+ message: `Cannot access ref value during render`,
48532
+ }));
48416
48533
  }
48417
48534
  }
48535
+ const ERROR_DESCRIPTION = 'React refs are values that are not needed for rendering. Refs should only be accessed ' +
48536
+ 'outside of render, such as in event handlers or effects. ' +
48537
+ 'Accessing a ref value (the `current` property) during render can cause your component ' +
48538
+ 'not to update as expected (https://react.dev/reference/react/useRef)';
48418
48539
 
48419
48540
  function validateNoSetStateInRender(fn) {
48420
48541
  const unconditionalSetStateFunctions = new Set();
@@ -52503,7 +52624,7 @@ const COMPILER_OPTIONS = {
52503
52624
  panicThreshold: 'none',
52504
52625
  flowSuppressions: false,
52505
52626
  environment: validateEnvironmentConfig({
52506
- validateRefAccessDuringRender: false,
52627
+ validateRefAccessDuringRender: true,
52507
52628
  validateNoSetStateInRender: true,
52508
52629
  validateNoSetStateInEffects: true,
52509
52630
  validateNoJSXInTryStatements: true,
@@ -55572,6 +55693,15 @@ function isInsideDoWhileLoop(node) {
55572
55693
  }
55573
55694
  return false;
55574
55695
  }
55696
+ function isInsideTryCatch(node) {
55697
+ while (node) {
55698
+ if (node.type === 'TryStatement' || node.type === 'CatchClause') {
55699
+ return true;
55700
+ }
55701
+ node = node.parent;
55702
+ }
55703
+ return false;
55704
+ }
55575
55705
  function isUseEffectEventIdentifier(node) {
55576
55706
  return false;
55577
55707
  }
@@ -55773,6 +55903,12 @@ const rule = {
55773
55903
  if (hasFlowSuppression(hook, 'react-rule-hook')) {
55774
55904
  continue;
55775
55905
  }
55906
+ if (isUseIdentifier(hook) && isInsideTryCatch(hook)) {
55907
+ context.report({
55908
+ node: hook,
55909
+ message: `React Hook "${getSourceCode().getText(hook)}" cannot be called in a try/catch block.`,
55910
+ });
55911
+ }
55776
55912
  if ((cycled || isInsideDoWhileLoop(hook)) &&
55777
55913
  !isUseIdentifier(hook)) {
55778
55914
  context.report({
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-9be531cd-20250729",
4
+ "version": "6.1.0-canary-9784cb37-20250730",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/facebook/react.git",