eslint-plugin-react-hooks 6.1.0-canary-4123f6b7-20250826 → 6.1.0-canary-8d7b5e49-20250827
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -17972,6 +17972,7 @@ var ErrorCategory;
|
|
|
17972
17972
|
ErrorCategory["CapitalizedCalls"] = "CapitalizedCalls";
|
|
17973
17973
|
ErrorCategory["StaticComponents"] = "StaticComponents";
|
|
17974
17974
|
ErrorCategory["UseMemo"] = "UseMemo";
|
|
17975
|
+
ErrorCategory["Factories"] = "Factories";
|
|
17975
17976
|
ErrorCategory["PreserveManualMemo"] = "PreserveManualMemo";
|
|
17976
17977
|
ErrorCategory["Immutability"] = "Immutability";
|
|
17977
17978
|
ErrorCategory["Globals"] = "Globals";
|
|
@@ -18057,6 +18058,15 @@ function getRuleForCategoryImpl(category) {
|
|
|
18057
18058
|
recommended: true,
|
|
18058
18059
|
};
|
|
18059
18060
|
}
|
|
18061
|
+
case ErrorCategory.Factories: {
|
|
18062
|
+
return {
|
|
18063
|
+
category,
|
|
18064
|
+
name: 'component-hook-factories',
|
|
18065
|
+
description: 'Validates against higher order functions defining nested components or hooks. ' +
|
|
18066
|
+
'Components and hooks should be defined at the module level',
|
|
18067
|
+
recommended: true,
|
|
18068
|
+
};
|
|
18069
|
+
}
|
|
18060
18070
|
case ErrorCategory.FBT: {
|
|
18061
18071
|
return {
|
|
18062
18072
|
category,
|
|
@@ -19467,7 +19477,8 @@ function printType(type) {
|
|
|
19467
19477
|
return `:T${type.kind}<${type.shapeId}>`;
|
|
19468
19478
|
}
|
|
19469
19479
|
else if (type.kind === 'Function' && type.shapeId != null) {
|
|
19470
|
-
|
|
19480
|
+
const returnType = printType(type.return);
|
|
19481
|
+
return `:T${type.kind}<${type.shapeId}>()${returnType !== '' ? `: ${returnType}` : ''}`;
|
|
19471
19482
|
}
|
|
19472
19483
|
else {
|
|
19473
19484
|
return `:T${type.kind}`;
|
|
@@ -19499,6 +19510,7 @@ function getFunctionName$2(instrValue, defaultValue) {
|
|
|
19499
19510
|
}
|
|
19500
19511
|
}
|
|
19501
19512
|
function printAliasingEffect(effect) {
|
|
19513
|
+
var _a;
|
|
19502
19514
|
switch (effect.kind) {
|
|
19503
19515
|
case 'Assign': {
|
|
19504
19516
|
return `Assign ${printPlaceForAliasEffect(effect.into)} = ${printPlaceForAliasEffect(effect.from)}`;
|
|
@@ -19557,7 +19569,7 @@ function printAliasingEffect(effect) {
|
|
|
19557
19569
|
case 'MutateConditionally':
|
|
19558
19570
|
case 'MutateTransitive':
|
|
19559
19571
|
case 'MutateTransitiveConditionally': {
|
|
19560
|
-
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}`;
|
|
19572
|
+
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}${effect.kind === 'Mutate' && ((_a = effect.reason) === null || _a === void 0 ? void 0 : _a.kind) === 'AssignCurrentProperty' ? ' (assign `.current`)' : ''}`;
|
|
19561
19573
|
}
|
|
19562
19574
|
case 'MutateFrozen': {
|
|
19563
19575
|
return `MutateFrozen ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
|
|
@@ -21069,7 +21081,7 @@ class HIRBuilder {
|
|
|
21069
21081
|
}
|
|
21070
21082
|
}
|
|
21071
21083
|
resolveBinding(node) {
|
|
21072
|
-
var _a, _b;
|
|
21084
|
+
var _a, _b, _c;
|
|
21073
21085
|
if (node.name === 'fbt') {
|
|
21074
21086
|
CompilerError.throwDiagnostic({
|
|
21075
21087
|
severity: ErrorSeverity.Todo,
|
|
@@ -21085,6 +21097,21 @@ class HIRBuilder {
|
|
|
21085
21097
|
],
|
|
21086
21098
|
});
|
|
21087
21099
|
}
|
|
21100
|
+
if (node.name === 'this') {
|
|
21101
|
+
CompilerError.throwDiagnostic({
|
|
21102
|
+
severity: ErrorSeverity.UnsupportedJS,
|
|
21103
|
+
category: ErrorCategory.UnsupportedSyntax,
|
|
21104
|
+
reason: '`this` is not supported syntax',
|
|
21105
|
+
description: 'React Compiler does not support compiling functions that use `this`',
|
|
21106
|
+
details: [
|
|
21107
|
+
{
|
|
21108
|
+
kind: 'error',
|
|
21109
|
+
message: '`this` was used here',
|
|
21110
|
+
loc: (_b = node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
21111
|
+
},
|
|
21112
|
+
],
|
|
21113
|
+
});
|
|
21114
|
+
}
|
|
21088
21115
|
const originalName = node.name;
|
|
21089
21116
|
let name = originalName;
|
|
21090
21117
|
let index = 0;
|
|
@@ -21102,7 +21129,7 @@ class HIRBuilder {
|
|
|
21102
21129
|
},
|
|
21103
21130
|
scope: null,
|
|
21104
21131
|
type: makeType(),
|
|
21105
|
-
loc: (
|
|
21132
|
+
loc: (_c = node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
21106
21133
|
};
|
|
21107
21134
|
__classPrivateFieldGet(this, _HIRBuilder_env, "f").programContext.addNewReference(name);
|
|
21108
21135
|
__classPrivateFieldGet(this, _HIRBuilder_bindings, "f").set(name, { node, identifier });
|
|
@@ -31611,6 +31638,7 @@ const EnvironmentConfigSchema = zod.z.object({
|
|
|
31611
31638
|
enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(true),
|
|
31612
31639
|
lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
|
|
31613
31640
|
validateNoVoidUseMemo: zod.z.boolean().default(false),
|
|
31641
|
+
validateNoDynamicallyCreatedComponentsOrHooks: zod.z.boolean().default(false),
|
|
31614
31642
|
});
|
|
31615
31643
|
class Environment {
|
|
31616
31644
|
constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
|
|
@@ -40452,6 +40480,18 @@ function computeSignatureForInstruction(context, env, instr) {
|
|
|
40452
40480
|
});
|
|
40453
40481
|
}
|
|
40454
40482
|
}
|
|
40483
|
+
for (const prop of value.props) {
|
|
40484
|
+
if (prop.kind === 'JsxAttribute' &&
|
|
40485
|
+
prop.place.identifier.type.kind === 'Function' &&
|
|
40486
|
+
(isJsxType(prop.place.identifier.type.return) ||
|
|
40487
|
+
(prop.place.identifier.type.return.kind === 'Phi' &&
|
|
40488
|
+
prop.place.identifier.type.return.operands.some(operand => isJsxType(operand))))) {
|
|
40489
|
+
effects.push({
|
|
40490
|
+
kind: 'Render',
|
|
40491
|
+
place: prop.place,
|
|
40492
|
+
});
|
|
40493
|
+
}
|
|
40494
|
+
}
|
|
40455
40495
|
}
|
|
40456
40496
|
break;
|
|
40457
40497
|
}
|
|
@@ -42224,7 +42264,7 @@ class RewriteBlockIds extends ReactiveFunctionVisitor {
|
|
|
42224
42264
|
}
|
|
42225
42265
|
|
|
42226
42266
|
function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
42227
|
-
var _a, _b, _c, _d, _e, _f;
|
|
42267
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
42228
42268
|
const functionEffects = [];
|
|
42229
42269
|
const state = new AliasingState();
|
|
42230
42270
|
const pendingPhis = new Map();
|
|
@@ -42291,6 +42331,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42291
42331
|
kind: effect.kind === 'MutateTransitive'
|
|
42292
42332
|
? MutationKind.Definite
|
|
42293
42333
|
: MutationKind.Conditional,
|
|
42334
|
+
reason: null,
|
|
42294
42335
|
place: effect.value,
|
|
42295
42336
|
});
|
|
42296
42337
|
}
|
|
@@ -42303,6 +42344,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42303
42344
|
kind: effect.kind === 'Mutate'
|
|
42304
42345
|
? MutationKind.Definite
|
|
42305
42346
|
: MutationKind.Conditional,
|
|
42347
|
+
reason: effect.kind === 'Mutate' ? ((_a = effect.reason) !== null && _a !== void 0 ? _a : null) : null,
|
|
42306
42348
|
place: effect.value,
|
|
42307
42349
|
});
|
|
42308
42350
|
}
|
|
@@ -42344,7 +42386,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42344
42386
|
}
|
|
42345
42387
|
}
|
|
42346
42388
|
for (const mutation of mutations) {
|
|
42347
|
-
state.mutate(mutation.index, mutation.place.identifier, makeInstructionId(mutation.id + 1), mutation.transitive, mutation.kind, mutation.place.loc, errors);
|
|
42389
|
+
state.mutate(mutation.index, mutation.place.identifier, makeInstructionId(mutation.id + 1), mutation.transitive, mutation.kind, mutation.place.loc, mutation.reason, errors);
|
|
42348
42390
|
}
|
|
42349
42391
|
for (const render of renders) {
|
|
42350
42392
|
state.render(render.index, render.place.identifier, errors);
|
|
@@ -42369,6 +42411,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42369
42411
|
functionEffects.push({
|
|
42370
42412
|
kind: 'Mutate',
|
|
42371
42413
|
value: Object.assign(Object.assign({}, place), { loc: node.local.loc }),
|
|
42414
|
+
reason: node.mutationReason,
|
|
42372
42415
|
});
|
|
42373
42416
|
}
|
|
42374
42417
|
}
|
|
@@ -42396,7 +42439,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42396
42439
|
for (const phi of block.phis) {
|
|
42397
42440
|
phi.place.effect = Effect.Store;
|
|
42398
42441
|
const isPhiMutatedAfterCreation = phi.place.identifier.mutableRange.end >
|
|
42399
|
-
((
|
|
42442
|
+
((_c = (_b = block.instructions.at(0)) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : block.terminal.id);
|
|
42400
42443
|
for (const operand of phi.operands.values()) {
|
|
42401
42444
|
operand.effect = isPhiMutatedAfterCreation
|
|
42402
42445
|
? Effect.Capture
|
|
@@ -42404,7 +42447,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42404
42447
|
}
|
|
42405
42448
|
if (isPhiMutatedAfterCreation &&
|
|
42406
42449
|
phi.place.identifier.mutableRange.start === 0) {
|
|
42407
|
-
const firstInstructionIdOfBlock = (
|
|
42450
|
+
const firstInstructionIdOfBlock = (_e = (_d = block.instructions.at(0)) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : block.terminal.id;
|
|
42408
42451
|
phi.place.identifier.mutableRange.start = makeInstructionId(firstInstructionIdOfBlock - 1);
|
|
42409
42452
|
}
|
|
42410
42453
|
}
|
|
@@ -42482,7 +42525,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42482
42525
|
}
|
|
42483
42526
|
}
|
|
42484
42527
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
42485
|
-
const effect = (
|
|
42528
|
+
const effect = (_f = operandEffects.get(lvalue.identifier.id)) !== null && _f !== void 0 ? _f : Effect.ConditionallyMutate;
|
|
42486
42529
|
lvalue.effect = effect;
|
|
42487
42530
|
}
|
|
42488
42531
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
@@ -42490,7 +42533,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42490
42533
|
operand.identifier.mutableRange.start === 0) {
|
|
42491
42534
|
operand.identifier.mutableRange.start = instr.id;
|
|
42492
42535
|
}
|
|
42493
|
-
const effect = (
|
|
42536
|
+
const effect = (_g = operandEffects.get(operand.identifier.id)) !== null && _g !== void 0 ? _g : Effect.Read;
|
|
42494
42537
|
operand.effect = effect;
|
|
42495
42538
|
}
|
|
42496
42539
|
if (instr.value.kind === 'StoreContext' &&
|
|
@@ -42528,7 +42571,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42528
42571
|
}
|
|
42529
42572
|
for (const into of tracked) {
|
|
42530
42573
|
const mutationIndex = index++;
|
|
42531
|
-
state.mutate(mutationIndex, into.identifier, null, true, MutationKind.Conditional, into.loc, ignoredErrors);
|
|
42574
|
+
state.mutate(mutationIndex, into.identifier, null, true, MutationKind.Conditional, into.loc, null, ignoredErrors);
|
|
42532
42575
|
for (const from of tracked) {
|
|
42533
42576
|
if (from.identifier.id === into.identifier.id ||
|
|
42534
42577
|
from.identifier.id === fn.returns.identifier.id) {
|
|
@@ -42596,6 +42639,7 @@ class AliasingState {
|
|
|
42596
42639
|
transitive: null,
|
|
42597
42640
|
local: null,
|
|
42598
42641
|
lastMutated: 0,
|
|
42642
|
+
mutationReason: null,
|
|
42599
42643
|
value,
|
|
42600
42644
|
});
|
|
42601
42645
|
}
|
|
@@ -42680,7 +42724,8 @@ class AliasingState {
|
|
|
42680
42724
|
}
|
|
42681
42725
|
}
|
|
42682
42726
|
}
|
|
42683
|
-
mutate(index, start, end, transitive, startKind, loc, errors) {
|
|
42727
|
+
mutate(index, start, end, transitive, startKind, loc, reason, errors) {
|
|
42728
|
+
var _a;
|
|
42684
42729
|
const seen = new Map();
|
|
42685
42730
|
const queue = [{ place: start, transitive, direction: 'backwards', kind: startKind }];
|
|
42686
42731
|
while (queue.length !== 0) {
|
|
@@ -42694,6 +42739,7 @@ class AliasingState {
|
|
|
42694
42739
|
if (node == null) {
|
|
42695
42740
|
continue;
|
|
42696
42741
|
}
|
|
42742
|
+
(_a = node.mutationReason) !== null && _a !== void 0 ? _a : (node.mutationReason = reason);
|
|
42697
42743
|
node.lastMutated = Math.max(node.lastMutated, index);
|
|
42698
42744
|
if (end != null) {
|
|
42699
42745
|
node.id.mutableRange.end = makeInstructionId(Math.max(node.id.mutableRange.end, end));
|
|
@@ -46745,6 +46791,14 @@ class Unifier {
|
|
|
46745
46791
|
if (type.kind === 'Phi') {
|
|
46746
46792
|
return { kind: 'Phi', operands: type.operands.map(o => this.get(o)) };
|
|
46747
46793
|
}
|
|
46794
|
+
if (type.kind === 'Function') {
|
|
46795
|
+
return {
|
|
46796
|
+
kind: 'Function',
|
|
46797
|
+
isConstructor: type.isConstructor,
|
|
46798
|
+
shapeId: type.shapeId,
|
|
46799
|
+
return: this.get(type.return),
|
|
46800
|
+
};
|
|
46801
|
+
}
|
|
46748
46802
|
return type;
|
|
46749
46803
|
}
|
|
46750
46804
|
}
|
|
@@ -50921,7 +50975,14 @@ function findFunctionsToCompile(program, pass, programContext) {
|
|
|
50921
50975
|
var _a;
|
|
50922
50976
|
const queue = [];
|
|
50923
50977
|
const traverseFunction = (fn, pass) => {
|
|
50978
|
+
if (pass.opts.compilationMode === 'all' &&
|
|
50979
|
+
fn.scope.getProgramParent() !== fn.scope.parent) {
|
|
50980
|
+
return;
|
|
50981
|
+
}
|
|
50924
50982
|
const fnType = getReactFunctionType(fn, pass);
|
|
50983
|
+
if (pass.opts.environment.validateNoDynamicallyCreatedComponentsOrHooks) {
|
|
50984
|
+
validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext);
|
|
50985
|
+
}
|
|
50925
50986
|
if (fnType === null || programContext.alreadyCompiled.has(fn.node)) {
|
|
50926
50987
|
return;
|
|
50927
50988
|
}
|
|
@@ -51106,6 +51167,52 @@ function shouldSkipCompilation(program, pass) {
|
|
|
51106
51167
|
}
|
|
51107
51168
|
return false;
|
|
51108
51169
|
}
|
|
51170
|
+
function validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext) {
|
|
51171
|
+
const parentNameExpr = getFunctionName$1(fn);
|
|
51172
|
+
const parentName = parentNameExpr !== null && parentNameExpr.isIdentifier()
|
|
51173
|
+
? parentNameExpr.node.name
|
|
51174
|
+
: '<anonymous>';
|
|
51175
|
+
const validateNestedFunction = (nestedFn) => {
|
|
51176
|
+
var _a, _b, _c, _d;
|
|
51177
|
+
if (nestedFn.node === fn.node ||
|
|
51178
|
+
programContext.alreadyCompiled.has(nestedFn.node)) {
|
|
51179
|
+
return;
|
|
51180
|
+
}
|
|
51181
|
+
if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
|
|
51182
|
+
const nestedFnType = getReactFunctionType(nestedFn, pass);
|
|
51183
|
+
const nestedFnNameExpr = getFunctionName$1(nestedFn);
|
|
51184
|
+
const nestedName = nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
|
|
51185
|
+
? nestedFnNameExpr.node.name
|
|
51186
|
+
: '<anonymous>';
|
|
51187
|
+
if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
|
|
51188
|
+
CompilerError.throwDiagnostic({
|
|
51189
|
+
category: ErrorCategory.Factories,
|
|
51190
|
+
severity: ErrorSeverity.InvalidReact,
|
|
51191
|
+
reason: `Components and hooks cannot be created dynamically`,
|
|
51192
|
+
description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
|
|
51193
|
+
details: [
|
|
51194
|
+
{
|
|
51195
|
+
kind: 'error',
|
|
51196
|
+
message: 'this function dynamically created a component/hook',
|
|
51197
|
+
loc: (_b = (_a = parentNameExpr === null || parentNameExpr === void 0 ? void 0 : parentNameExpr.node.loc) !== null && _a !== void 0 ? _a : fn.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
51198
|
+
},
|
|
51199
|
+
{
|
|
51200
|
+
kind: 'error',
|
|
51201
|
+
message: 'the component is created here',
|
|
51202
|
+
loc: (_d = (_c = nestedFnNameExpr === null || nestedFnNameExpr === void 0 ? void 0 : nestedFnNameExpr.node.loc) !== null && _c !== void 0 ? _c : nestedFn.node.loc) !== null && _d !== void 0 ? _d : null,
|
|
51203
|
+
},
|
|
51204
|
+
],
|
|
51205
|
+
});
|
|
51206
|
+
}
|
|
51207
|
+
}
|
|
51208
|
+
nestedFn.skip();
|
|
51209
|
+
};
|
|
51210
|
+
fn.traverse({
|
|
51211
|
+
FunctionDeclaration: validateNestedFunction,
|
|
51212
|
+
FunctionExpression: validateNestedFunction,
|
|
51213
|
+
ArrowFunctionExpression: validateNestedFunction,
|
|
51214
|
+
});
|
|
51215
|
+
}
|
|
51109
51216
|
function getReactFunctionType(fn, pass) {
|
|
51110
51217
|
var _a, _b;
|
|
51111
51218
|
const hookPattern = pass.opts.environment.hookPattern;
|
|
@@ -51135,9 +51242,6 @@ function getReactFunctionType(fn, pass) {
|
|
|
51135
51242
|
return componentSyntaxType;
|
|
51136
51243
|
}
|
|
51137
51244
|
case 'all': {
|
|
51138
|
-
if (fn.scope.getProgramParent() !== fn.scope.parent) {
|
|
51139
|
-
return null;
|
|
51140
|
-
}
|
|
51141
51245
|
return (_b = getComponentOrHookLike(fn, hookPattern)) !== null && _b !== void 0 ? _b : 'Other';
|
|
51142
51246
|
}
|
|
51143
51247
|
default: {
|
|
@@ -17963,6 +17963,7 @@ var ErrorCategory;
|
|
|
17963
17963
|
ErrorCategory["CapitalizedCalls"] = "CapitalizedCalls";
|
|
17964
17964
|
ErrorCategory["StaticComponents"] = "StaticComponents";
|
|
17965
17965
|
ErrorCategory["UseMemo"] = "UseMemo";
|
|
17966
|
+
ErrorCategory["Factories"] = "Factories";
|
|
17966
17967
|
ErrorCategory["PreserveManualMemo"] = "PreserveManualMemo";
|
|
17967
17968
|
ErrorCategory["Immutability"] = "Immutability";
|
|
17968
17969
|
ErrorCategory["Globals"] = "Globals";
|
|
@@ -18048,6 +18049,15 @@ function getRuleForCategoryImpl(category) {
|
|
|
18048
18049
|
recommended: true,
|
|
18049
18050
|
};
|
|
18050
18051
|
}
|
|
18052
|
+
case ErrorCategory.Factories: {
|
|
18053
|
+
return {
|
|
18054
|
+
category,
|
|
18055
|
+
name: 'component-hook-factories',
|
|
18056
|
+
description: 'Validates against higher order functions defining nested components or hooks. ' +
|
|
18057
|
+
'Components and hooks should be defined at the module level',
|
|
18058
|
+
recommended: true,
|
|
18059
|
+
};
|
|
18060
|
+
}
|
|
18051
18061
|
case ErrorCategory.FBT: {
|
|
18052
18062
|
return {
|
|
18053
18063
|
category,
|
|
@@ -19458,7 +19468,8 @@ function printType(type) {
|
|
|
19458
19468
|
return `:T${type.kind}<${type.shapeId}>`;
|
|
19459
19469
|
}
|
|
19460
19470
|
else if (type.kind === 'Function' && type.shapeId != null) {
|
|
19461
|
-
|
|
19471
|
+
const returnType = printType(type.return);
|
|
19472
|
+
return `:T${type.kind}<${type.shapeId}>()${returnType !== '' ? `: ${returnType}` : ''}`;
|
|
19462
19473
|
}
|
|
19463
19474
|
else {
|
|
19464
19475
|
return `:T${type.kind}`;
|
|
@@ -19490,6 +19501,7 @@ function getFunctionName$2(instrValue, defaultValue) {
|
|
|
19490
19501
|
}
|
|
19491
19502
|
}
|
|
19492
19503
|
function printAliasingEffect(effect) {
|
|
19504
|
+
var _a;
|
|
19493
19505
|
switch (effect.kind) {
|
|
19494
19506
|
case 'Assign': {
|
|
19495
19507
|
return `Assign ${printPlaceForAliasEffect(effect.into)} = ${printPlaceForAliasEffect(effect.from)}`;
|
|
@@ -19548,7 +19560,7 @@ function printAliasingEffect(effect) {
|
|
|
19548
19560
|
case 'MutateConditionally':
|
|
19549
19561
|
case 'MutateTransitive':
|
|
19550
19562
|
case 'MutateTransitiveConditionally': {
|
|
19551
|
-
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}`;
|
|
19563
|
+
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}${effect.kind === 'Mutate' && ((_a = effect.reason) === null || _a === void 0 ? void 0 : _a.kind) === 'AssignCurrentProperty' ? ' (assign `.current`)' : ''}`;
|
|
19552
19564
|
}
|
|
19553
19565
|
case 'MutateFrozen': {
|
|
19554
19566
|
return `MutateFrozen ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
|
|
@@ -21060,7 +21072,7 @@ class HIRBuilder {
|
|
|
21060
21072
|
}
|
|
21061
21073
|
}
|
|
21062
21074
|
resolveBinding(node) {
|
|
21063
|
-
var _a, _b;
|
|
21075
|
+
var _a, _b, _c;
|
|
21064
21076
|
if (node.name === 'fbt') {
|
|
21065
21077
|
CompilerError.throwDiagnostic({
|
|
21066
21078
|
severity: ErrorSeverity.Todo,
|
|
@@ -21076,6 +21088,21 @@ class HIRBuilder {
|
|
|
21076
21088
|
],
|
|
21077
21089
|
});
|
|
21078
21090
|
}
|
|
21091
|
+
if (node.name === 'this') {
|
|
21092
|
+
CompilerError.throwDiagnostic({
|
|
21093
|
+
severity: ErrorSeverity.UnsupportedJS,
|
|
21094
|
+
category: ErrorCategory.UnsupportedSyntax,
|
|
21095
|
+
reason: '`this` is not supported syntax',
|
|
21096
|
+
description: 'React Compiler does not support compiling functions that use `this`',
|
|
21097
|
+
details: [
|
|
21098
|
+
{
|
|
21099
|
+
kind: 'error',
|
|
21100
|
+
message: '`this` was used here',
|
|
21101
|
+
loc: (_b = node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
21102
|
+
},
|
|
21103
|
+
],
|
|
21104
|
+
});
|
|
21105
|
+
}
|
|
21079
21106
|
const originalName = node.name;
|
|
21080
21107
|
let name = originalName;
|
|
21081
21108
|
let index = 0;
|
|
@@ -21093,7 +21120,7 @@ class HIRBuilder {
|
|
|
21093
21120
|
},
|
|
21094
21121
|
scope: null,
|
|
21095
21122
|
type: makeType(),
|
|
21096
|
-
loc: (
|
|
21123
|
+
loc: (_c = node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
21097
21124
|
};
|
|
21098
21125
|
__classPrivateFieldGet(this, _HIRBuilder_env, "f").programContext.addNewReference(name);
|
|
21099
21126
|
__classPrivateFieldGet(this, _HIRBuilder_bindings, "f").set(name, { node, identifier });
|
|
@@ -31438,6 +31465,7 @@ const EnvironmentConfigSchema = zod.z.object({
|
|
|
31438
31465
|
enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(true),
|
|
31439
31466
|
lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
|
|
31440
31467
|
validateNoVoidUseMemo: zod.z.boolean().default(false),
|
|
31468
|
+
validateNoDynamicallyCreatedComponentsOrHooks: zod.z.boolean().default(false),
|
|
31441
31469
|
});
|
|
31442
31470
|
class Environment {
|
|
31443
31471
|
constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
|
|
@@ -40279,6 +40307,18 @@ function computeSignatureForInstruction(context, env, instr) {
|
|
|
40279
40307
|
});
|
|
40280
40308
|
}
|
|
40281
40309
|
}
|
|
40310
|
+
for (const prop of value.props) {
|
|
40311
|
+
if (prop.kind === 'JsxAttribute' &&
|
|
40312
|
+
prop.place.identifier.type.kind === 'Function' &&
|
|
40313
|
+
(isJsxType(prop.place.identifier.type.return) ||
|
|
40314
|
+
(prop.place.identifier.type.return.kind === 'Phi' &&
|
|
40315
|
+
prop.place.identifier.type.return.operands.some(operand => isJsxType(operand))))) {
|
|
40316
|
+
effects.push({
|
|
40317
|
+
kind: 'Render',
|
|
40318
|
+
place: prop.place,
|
|
40319
|
+
});
|
|
40320
|
+
}
|
|
40321
|
+
}
|
|
40282
40322
|
}
|
|
40283
40323
|
break;
|
|
40284
40324
|
}
|
|
@@ -42051,7 +42091,7 @@ class RewriteBlockIds extends ReactiveFunctionVisitor {
|
|
|
42051
42091
|
}
|
|
42052
42092
|
|
|
42053
42093
|
function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
42054
|
-
var _a, _b, _c, _d, _e, _f;
|
|
42094
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
42055
42095
|
const functionEffects = [];
|
|
42056
42096
|
const state = new AliasingState();
|
|
42057
42097
|
const pendingPhis = new Map();
|
|
@@ -42118,6 +42158,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42118
42158
|
kind: effect.kind === 'MutateTransitive'
|
|
42119
42159
|
? MutationKind.Definite
|
|
42120
42160
|
: MutationKind.Conditional,
|
|
42161
|
+
reason: null,
|
|
42121
42162
|
place: effect.value,
|
|
42122
42163
|
});
|
|
42123
42164
|
}
|
|
@@ -42130,6 +42171,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42130
42171
|
kind: effect.kind === 'Mutate'
|
|
42131
42172
|
? MutationKind.Definite
|
|
42132
42173
|
: MutationKind.Conditional,
|
|
42174
|
+
reason: effect.kind === 'Mutate' ? ((_a = effect.reason) !== null && _a !== void 0 ? _a : null) : null,
|
|
42133
42175
|
place: effect.value,
|
|
42134
42176
|
});
|
|
42135
42177
|
}
|
|
@@ -42171,7 +42213,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42171
42213
|
}
|
|
42172
42214
|
}
|
|
42173
42215
|
for (const mutation of mutations) {
|
|
42174
|
-
state.mutate(mutation.index, mutation.place.identifier, makeInstructionId(mutation.id + 1), mutation.transitive, mutation.kind, mutation.place.loc, errors);
|
|
42216
|
+
state.mutate(mutation.index, mutation.place.identifier, makeInstructionId(mutation.id + 1), mutation.transitive, mutation.kind, mutation.place.loc, mutation.reason, errors);
|
|
42175
42217
|
}
|
|
42176
42218
|
for (const render of renders) {
|
|
42177
42219
|
state.render(render.index, render.place.identifier, errors);
|
|
@@ -42196,6 +42238,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42196
42238
|
functionEffects.push({
|
|
42197
42239
|
kind: 'Mutate',
|
|
42198
42240
|
value: Object.assign(Object.assign({}, place), { loc: node.local.loc }),
|
|
42241
|
+
reason: node.mutationReason,
|
|
42199
42242
|
});
|
|
42200
42243
|
}
|
|
42201
42244
|
}
|
|
@@ -42223,7 +42266,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42223
42266
|
for (const phi of block.phis) {
|
|
42224
42267
|
phi.place.effect = Effect.Store;
|
|
42225
42268
|
const isPhiMutatedAfterCreation = phi.place.identifier.mutableRange.end >
|
|
42226
|
-
((
|
|
42269
|
+
((_c = (_b = block.instructions.at(0)) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : block.terminal.id);
|
|
42227
42270
|
for (const operand of phi.operands.values()) {
|
|
42228
42271
|
operand.effect = isPhiMutatedAfterCreation
|
|
42229
42272
|
? Effect.Capture
|
|
@@ -42231,7 +42274,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42231
42274
|
}
|
|
42232
42275
|
if (isPhiMutatedAfterCreation &&
|
|
42233
42276
|
phi.place.identifier.mutableRange.start === 0) {
|
|
42234
|
-
const firstInstructionIdOfBlock = (
|
|
42277
|
+
const firstInstructionIdOfBlock = (_e = (_d = block.instructions.at(0)) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : block.terminal.id;
|
|
42235
42278
|
phi.place.identifier.mutableRange.start = makeInstructionId(firstInstructionIdOfBlock - 1);
|
|
42236
42279
|
}
|
|
42237
42280
|
}
|
|
@@ -42309,7 +42352,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42309
42352
|
}
|
|
42310
42353
|
}
|
|
42311
42354
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
42312
|
-
const effect = (
|
|
42355
|
+
const effect = (_f = operandEffects.get(lvalue.identifier.id)) !== null && _f !== void 0 ? _f : Effect.ConditionallyMutate;
|
|
42313
42356
|
lvalue.effect = effect;
|
|
42314
42357
|
}
|
|
42315
42358
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
@@ -42317,7 +42360,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42317
42360
|
operand.identifier.mutableRange.start === 0) {
|
|
42318
42361
|
operand.identifier.mutableRange.start = instr.id;
|
|
42319
42362
|
}
|
|
42320
|
-
const effect = (
|
|
42363
|
+
const effect = (_g = operandEffects.get(operand.identifier.id)) !== null && _g !== void 0 ? _g : Effect.Read;
|
|
42321
42364
|
operand.effect = effect;
|
|
42322
42365
|
}
|
|
42323
42366
|
if (instr.value.kind === 'StoreContext' &&
|
|
@@ -42355,7 +42398,7 @@ function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
|
42355
42398
|
}
|
|
42356
42399
|
for (const into of tracked) {
|
|
42357
42400
|
const mutationIndex = index++;
|
|
42358
|
-
state.mutate(mutationIndex, into.identifier, null, true, MutationKind.Conditional, into.loc, ignoredErrors);
|
|
42401
|
+
state.mutate(mutationIndex, into.identifier, null, true, MutationKind.Conditional, into.loc, null, ignoredErrors);
|
|
42359
42402
|
for (const from of tracked) {
|
|
42360
42403
|
if (from.identifier.id === into.identifier.id ||
|
|
42361
42404
|
from.identifier.id === fn.returns.identifier.id) {
|
|
@@ -42423,6 +42466,7 @@ class AliasingState {
|
|
|
42423
42466
|
transitive: null,
|
|
42424
42467
|
local: null,
|
|
42425
42468
|
lastMutated: 0,
|
|
42469
|
+
mutationReason: null,
|
|
42426
42470
|
value,
|
|
42427
42471
|
});
|
|
42428
42472
|
}
|
|
@@ -42507,7 +42551,8 @@ class AliasingState {
|
|
|
42507
42551
|
}
|
|
42508
42552
|
}
|
|
42509
42553
|
}
|
|
42510
|
-
mutate(index, start, end, transitive, startKind, loc, errors) {
|
|
42554
|
+
mutate(index, start, end, transitive, startKind, loc, reason, errors) {
|
|
42555
|
+
var _a;
|
|
42511
42556
|
const seen = new Map();
|
|
42512
42557
|
const queue = [{ place: start, transitive, direction: 'backwards', kind: startKind }];
|
|
42513
42558
|
while (queue.length !== 0) {
|
|
@@ -42521,6 +42566,7 @@ class AliasingState {
|
|
|
42521
42566
|
if (node == null) {
|
|
42522
42567
|
continue;
|
|
42523
42568
|
}
|
|
42569
|
+
(_a = node.mutationReason) !== null && _a !== void 0 ? _a : (node.mutationReason = reason);
|
|
42524
42570
|
node.lastMutated = Math.max(node.lastMutated, index);
|
|
42525
42571
|
if (end != null) {
|
|
42526
42572
|
node.id.mutableRange.end = makeInstructionId(Math.max(node.id.mutableRange.end, end));
|
|
@@ -46572,6 +46618,14 @@ class Unifier {
|
|
|
46572
46618
|
if (type.kind === 'Phi') {
|
|
46573
46619
|
return { kind: 'Phi', operands: type.operands.map(o => this.get(o)) };
|
|
46574
46620
|
}
|
|
46621
|
+
if (type.kind === 'Function') {
|
|
46622
|
+
return {
|
|
46623
|
+
kind: 'Function',
|
|
46624
|
+
isConstructor: type.isConstructor,
|
|
46625
|
+
shapeId: type.shapeId,
|
|
46626
|
+
return: this.get(type.return),
|
|
46627
|
+
};
|
|
46628
|
+
}
|
|
46575
46629
|
return type;
|
|
46576
46630
|
}
|
|
46577
46631
|
}
|
|
@@ -50748,7 +50802,14 @@ function findFunctionsToCompile(program, pass, programContext) {
|
|
|
50748
50802
|
var _a;
|
|
50749
50803
|
const queue = [];
|
|
50750
50804
|
const traverseFunction = (fn, pass) => {
|
|
50805
|
+
if (pass.opts.compilationMode === 'all' &&
|
|
50806
|
+
fn.scope.getProgramParent() !== fn.scope.parent) {
|
|
50807
|
+
return;
|
|
50808
|
+
}
|
|
50751
50809
|
const fnType = getReactFunctionType(fn, pass);
|
|
50810
|
+
if (pass.opts.environment.validateNoDynamicallyCreatedComponentsOrHooks) {
|
|
50811
|
+
validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext);
|
|
50812
|
+
}
|
|
50752
50813
|
if (fnType === null || programContext.alreadyCompiled.has(fn.node)) {
|
|
50753
50814
|
return;
|
|
50754
50815
|
}
|
|
@@ -50933,6 +50994,52 @@ function shouldSkipCompilation(program, pass) {
|
|
|
50933
50994
|
}
|
|
50934
50995
|
return false;
|
|
50935
50996
|
}
|
|
50997
|
+
function validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext) {
|
|
50998
|
+
const parentNameExpr = getFunctionName$1(fn);
|
|
50999
|
+
const parentName = parentNameExpr !== null && parentNameExpr.isIdentifier()
|
|
51000
|
+
? parentNameExpr.node.name
|
|
51001
|
+
: '<anonymous>';
|
|
51002
|
+
const validateNestedFunction = (nestedFn) => {
|
|
51003
|
+
var _a, _b, _c, _d;
|
|
51004
|
+
if (nestedFn.node === fn.node ||
|
|
51005
|
+
programContext.alreadyCompiled.has(nestedFn.node)) {
|
|
51006
|
+
return;
|
|
51007
|
+
}
|
|
51008
|
+
if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
|
|
51009
|
+
const nestedFnType = getReactFunctionType(nestedFn, pass);
|
|
51010
|
+
const nestedFnNameExpr = getFunctionName$1(nestedFn);
|
|
51011
|
+
const nestedName = nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
|
|
51012
|
+
? nestedFnNameExpr.node.name
|
|
51013
|
+
: '<anonymous>';
|
|
51014
|
+
if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
|
|
51015
|
+
CompilerError.throwDiagnostic({
|
|
51016
|
+
category: ErrorCategory.Factories,
|
|
51017
|
+
severity: ErrorSeverity.InvalidReact,
|
|
51018
|
+
reason: `Components and hooks cannot be created dynamically`,
|
|
51019
|
+
description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
|
|
51020
|
+
details: [
|
|
51021
|
+
{
|
|
51022
|
+
kind: 'error',
|
|
51023
|
+
message: 'this function dynamically created a component/hook',
|
|
51024
|
+
loc: (_b = (_a = parentNameExpr === null || parentNameExpr === void 0 ? void 0 : parentNameExpr.node.loc) !== null && _a !== void 0 ? _a : fn.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
51025
|
+
},
|
|
51026
|
+
{
|
|
51027
|
+
kind: 'error',
|
|
51028
|
+
message: 'the component is created here',
|
|
51029
|
+
loc: (_d = (_c = nestedFnNameExpr === null || nestedFnNameExpr === void 0 ? void 0 : nestedFnNameExpr.node.loc) !== null && _c !== void 0 ? _c : nestedFn.node.loc) !== null && _d !== void 0 ? _d : null,
|
|
51030
|
+
},
|
|
51031
|
+
],
|
|
51032
|
+
});
|
|
51033
|
+
}
|
|
51034
|
+
}
|
|
51035
|
+
nestedFn.skip();
|
|
51036
|
+
};
|
|
51037
|
+
fn.traverse({
|
|
51038
|
+
FunctionDeclaration: validateNestedFunction,
|
|
51039
|
+
FunctionExpression: validateNestedFunction,
|
|
51040
|
+
ArrowFunctionExpression: validateNestedFunction,
|
|
51041
|
+
});
|
|
51042
|
+
}
|
|
50936
51043
|
function getReactFunctionType(fn, pass) {
|
|
50937
51044
|
var _a, _b;
|
|
50938
51045
|
const hookPattern = pass.opts.environment.hookPattern;
|
|
@@ -50962,9 +51069,6 @@ function getReactFunctionType(fn, pass) {
|
|
|
50962
51069
|
return componentSyntaxType;
|
|
50963
51070
|
}
|
|
50964
51071
|
case 'all': {
|
|
50965
|
-
if (fn.scope.getProgramParent() !== fn.scope.parent) {
|
|
50966
|
-
return null;
|
|
50967
|
-
}
|
|
50968
51072
|
return (_b = getComponentOrHookLike(fn, hookPattern)) !== null && _b !== void 0 ? _b : 'Other';
|
|
50969
51073
|
}
|
|
50970
51074
|
default: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-hooks",
|
|
3
3
|
"description": "ESLint rules for React Hooks",
|
|
4
|
-
"version": "6.1.0-canary-
|
|
4
|
+
"version": "6.1.0-canary-8d7b5e49-20250827",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/facebook/react.git",
|