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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
48451
|
+
didError = true;
|
|
48452
|
+
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
48367
48453
|
severity: ErrorSeverity.InvalidReact,
|
|
48368
|
-
|
|
48454
|
+
category: 'Cannot access refs during render',
|
|
48455
|
+
description: ERROR_DESCRIPTION,
|
|
48456
|
+
}).withDetail({
|
|
48457
|
+
kind: 'error',
|
|
48369
48458
|
loc: callee.loc,
|
|
48370
|
-
|
|
48371
|
-
|
|
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
|
-
|
|
48379
|
-
|
|
48380
|
-
|
|
48381
|
-
|
|
48382
|
-
|
|
48383
|
-
|
|
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
|
-
|
|
48419
|
-
|
|
48420
|
-
|
|
48421
|
-
|
|
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
|
-
|
|
48520
|
+
validateNoRefUpdate(errors, env, instr.value.object, instr.loc);
|
|
48425
48521
|
}
|
|
48426
|
-
|
|
48427
|
-
|
|
48428
|
-
|
|
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.
|
|
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.
|
|
48635
|
+
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
48529
48636
|
severity: ErrorSeverity.InvalidReact,
|
|
48530
|
-
|
|
48637
|
+
category: 'Cannot access refs during render',
|
|
48638
|
+
description: ERROR_DESCRIPTION,
|
|
48639
|
+
}).withDetail({
|
|
48640
|
+
kind: 'error',
|
|
48531
48641
|
loc: operand.loc,
|
|
48532
|
-
|
|
48533
|
-
|
|
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.
|
|
48651
|
+
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
48546
48652
|
severity: ErrorSeverity.InvalidReact,
|
|
48547
|
-
|
|
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
|
-
|
|
48550
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
48568
|
-
|
|
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.
|
|
48697
|
+
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
48580
48698
|
severity: ErrorSeverity.InvalidReact,
|
|
48581
|
-
|
|
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
|
-
|
|
48584
|
-
|
|
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:
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
48278
|
+
didError = true;
|
|
48279
|
+
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
48194
48280
|
severity: ErrorSeverity.InvalidReact,
|
|
48195
|
-
|
|
48281
|
+
category: 'Cannot access refs during render',
|
|
48282
|
+
description: ERROR_DESCRIPTION,
|
|
48283
|
+
}).withDetail({
|
|
48284
|
+
kind: 'error',
|
|
48196
48285
|
loc: callee.loc,
|
|
48197
|
-
|
|
48198
|
-
|
|
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
|
-
|
|
48206
|
-
|
|
48207
|
-
|
|
48208
|
-
|
|
48209
|
-
|
|
48210
|
-
|
|
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
|
-
|
|
48246
|
-
|
|
48247
|
-
|
|
48248
|
-
|
|
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
|
-
|
|
48347
|
+
validateNoRefUpdate(errors, env, instr.value.object, instr.loc);
|
|
48252
48348
|
}
|
|
48253
|
-
|
|
48254
|
-
|
|
48255
|
-
|
|
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.
|
|
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.
|
|
48462
|
+
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
48356
48463
|
severity: ErrorSeverity.InvalidReact,
|
|
48357
|
-
|
|
48464
|
+
category: 'Cannot access refs during render',
|
|
48465
|
+
description: ERROR_DESCRIPTION,
|
|
48466
|
+
}).withDetail({
|
|
48467
|
+
kind: 'error',
|
|
48358
48468
|
loc: operand.loc,
|
|
48359
|
-
|
|
48360
|
-
|
|
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.
|
|
48478
|
+
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
48373
48479
|
severity: ErrorSeverity.InvalidReact,
|
|
48374
|
-
|
|
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
|
-
|
|
48377
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
48395
|
-
|
|
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.
|
|
48524
|
+
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
48407
48525
|
severity: ErrorSeverity.InvalidReact,
|
|
48408
|
-
|
|
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
|
-
|
|
48411
|
-
|
|
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:
|
|
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-
|
|
4
|
+
"version": "6.1.0-canary-9784cb37-20250730",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/facebook/react.git",
|