eslint-plugin-react-hooks 7.1.0-canary-378973b3-20251205 → 7.1.0-canary-ec9cc003-20251208
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.
|
@@ -18033,7 +18033,8 @@ function printErrorSummary(category, message) {
|
|
|
18033
18033
|
case ErrorCategory.Syntax:
|
|
18034
18034
|
case ErrorCategory.UseMemo:
|
|
18035
18035
|
case ErrorCategory.VoidUseMemo:
|
|
18036
|
-
case ErrorCategory.MemoDependencies:
|
|
18036
|
+
case ErrorCategory.MemoDependencies:
|
|
18037
|
+
case ErrorCategory.EffectExhaustiveDependencies: {
|
|
18037
18038
|
heading = 'Error';
|
|
18038
18039
|
break;
|
|
18039
18040
|
}
|
|
@@ -18073,6 +18074,7 @@ var ErrorCategory;
|
|
|
18073
18074
|
ErrorCategory["Globals"] = "Globals";
|
|
18074
18075
|
ErrorCategory["Refs"] = "Refs";
|
|
18075
18076
|
ErrorCategory["EffectDependencies"] = "EffectDependencies";
|
|
18077
|
+
ErrorCategory["EffectExhaustiveDependencies"] = "EffectExhaustiveDependencies";
|
|
18076
18078
|
ErrorCategory["EffectSetState"] = "EffectSetState";
|
|
18077
18079
|
ErrorCategory["EffectDerivationsOfState"] = "EffectDerivationsOfState";
|
|
18078
18080
|
ErrorCategory["ErrorBoundaries"] = "ErrorBoundaries";
|
|
@@ -18139,6 +18141,15 @@ function getRuleForCategoryImpl(category) {
|
|
|
18139
18141
|
preset: LintRulePreset.Off,
|
|
18140
18142
|
};
|
|
18141
18143
|
}
|
|
18144
|
+
case ErrorCategory.EffectExhaustiveDependencies: {
|
|
18145
|
+
return {
|
|
18146
|
+
category,
|
|
18147
|
+
severity: ErrorSeverity.Error,
|
|
18148
|
+
name: 'exhaustive-effect-dependencies',
|
|
18149
|
+
description: 'Validates that effect dependencies are exhaustive and without extraneous values',
|
|
18150
|
+
preset: LintRulePreset.Off,
|
|
18151
|
+
};
|
|
18152
|
+
}
|
|
18142
18153
|
case ErrorCategory.EffectDerivationsOfState: {
|
|
18143
18154
|
return {
|
|
18144
18155
|
category,
|
|
@@ -32206,6 +32217,7 @@ const EnvironmentConfigSchema = v4.z.object({
|
|
|
32206
32217
|
enablePreserveExistingMemoizationGuarantees: v4.z.boolean().default(true),
|
|
32207
32218
|
validatePreserveExistingMemoizationGuarantees: v4.z.boolean().default(true),
|
|
32208
32219
|
validateExhaustiveMemoizationDependencies: v4.z.boolean().default(true),
|
|
32220
|
+
validateExhaustiveEffectDependencies: v4.z.boolean().default(false),
|
|
32209
32221
|
enablePreserveExistingManualUseMemo: v4.z.boolean().default(false),
|
|
32210
32222
|
enableForest: v4.z.boolean().default(false),
|
|
32211
32223
|
enableUseTypeAnnotations: v4.z.boolean().default(false),
|
|
@@ -33139,12 +33151,6 @@ function findDisjointMutableValues(fn) {
|
|
|
33139
33151
|
for (const operand of eachInstructionOperand(instr)) {
|
|
33140
33152
|
if (isMutable(instr, operand) &&
|
|
33141
33153
|
operand.identifier.mutableRange.start > 0) {
|
|
33142
|
-
if (instr.value.kind === 'FunctionExpression' ||
|
|
33143
|
-
instr.value.kind === 'ObjectMethod') {
|
|
33144
|
-
if (operand.identifier.type.kind === 'Primitive') {
|
|
33145
|
-
continue;
|
|
33146
|
-
}
|
|
33147
|
-
}
|
|
33148
33154
|
operands.push(operand.identifier);
|
|
33149
33155
|
}
|
|
33150
33156
|
}
|
|
@@ -53483,6 +53489,7 @@ function isKnownEventHandler(_tag, prop) {
|
|
|
53483
53489
|
}
|
|
53484
53490
|
|
|
53485
53491
|
function validateExhaustiveDependencies(fn) {
|
|
53492
|
+
const env = fn.env;
|
|
53486
53493
|
const reactive = collectReactiveIdentifiersHIR(fn);
|
|
53487
53494
|
const temporaries = new Map();
|
|
53488
53495
|
for (const param of fn.params) {
|
|
@@ -53507,215 +53514,259 @@ function validateExhaustiveDependencies(fn) {
|
|
|
53507
53514
|
locals.clear();
|
|
53508
53515
|
}
|
|
53509
53516
|
function onFinishMemoize(value, dependencies, locals) {
|
|
53510
|
-
var
|
|
53517
|
+
var _a;
|
|
53511
53518
|
CompilerError.simpleInvariant(startMemo != null && startMemo.manualMemoId === value.manualMemoId, {
|
|
53512
53519
|
reason: 'Found FinishMemoize without corresponding StartMemoize',
|
|
53513
53520
|
loc: value.loc,
|
|
53514
53521
|
});
|
|
53515
|
-
|
|
53516
|
-
|
|
53517
|
-
|
|
53518
|
-
|
|
53519
|
-
if (
|
|
53520
|
-
|
|
53521
|
-
}
|
|
53522
|
-
|
|
53523
|
-
|
|
53524
|
-
|
|
53525
|
-
|
|
53526
|
-
|
|
53527
|
-
|
|
53528
|
-
|
|
53529
|
-
|
|
53530
|
-
|
|
53531
|
-
|
|
53532
|
-
|
|
53533
|
-
|
|
53534
|
-
|
|
53522
|
+
if (env.config.validateExhaustiveMemoizationDependencies) {
|
|
53523
|
+
visitCandidateDependency(value.decl, temporaries, dependencies, locals);
|
|
53524
|
+
const inferred = Array.from(dependencies);
|
|
53525
|
+
const diagnostic = validateDependencies(inferred, (_a = startMemo.deps) !== null && _a !== void 0 ? _a : [], reactive, startMemo.depsLoc, ErrorCategory.MemoDependencies);
|
|
53526
|
+
if (diagnostic != null) {
|
|
53527
|
+
error.pushDiagnostic(diagnostic);
|
|
53528
|
+
}
|
|
53529
|
+
}
|
|
53530
|
+
dependencies.clear();
|
|
53531
|
+
locals.clear();
|
|
53532
|
+
startMemo = null;
|
|
53533
|
+
}
|
|
53534
|
+
collectDependencies(fn, temporaries, {
|
|
53535
|
+
onStartMemoize,
|
|
53536
|
+
onFinishMemoize,
|
|
53537
|
+
onEffect: (inferred, manual, manualMemoLoc) => {
|
|
53538
|
+
if (env.config.validateExhaustiveEffectDependencies === false) {
|
|
53539
|
+
return;
|
|
53540
|
+
}
|
|
53541
|
+
const manualDeps = [];
|
|
53542
|
+
for (const dep of manual) {
|
|
53543
|
+
if (dep.kind === 'Local') {
|
|
53544
|
+
manualDeps.push({
|
|
53545
|
+
root: {
|
|
53546
|
+
kind: 'NamedLocal',
|
|
53547
|
+
constant: false,
|
|
53548
|
+
value: {
|
|
53549
|
+
effect: Effect.Read,
|
|
53550
|
+
identifier: dep.identifier,
|
|
53551
|
+
kind: 'Identifier',
|
|
53552
|
+
loc: dep.loc,
|
|
53553
|
+
reactive: reactive.has(dep.identifier.id),
|
|
53554
|
+
},
|
|
53555
|
+
},
|
|
53556
|
+
path: dep.path,
|
|
53557
|
+
loc: dep.loc,
|
|
53558
|
+
});
|
|
53535
53559
|
}
|
|
53536
|
-
|
|
53537
|
-
|
|
53538
|
-
|
|
53539
|
-
|
|
53540
|
-
|
|
53541
|
-
|
|
53542
|
-
|
|
53543
|
-
|
|
53544
|
-
|
|
53545
|
-
return String(aProperty.property).localeCompare(String(bProperty.property));
|
|
53546
|
-
}
|
|
53560
|
+
else {
|
|
53561
|
+
manualDeps.push({
|
|
53562
|
+
root: {
|
|
53563
|
+
kind: 'Global',
|
|
53564
|
+
identifierName: dep.binding.name,
|
|
53565
|
+
},
|
|
53566
|
+
path: [],
|
|
53567
|
+
loc: GeneratedSource,
|
|
53568
|
+
});
|
|
53547
53569
|
}
|
|
53548
|
-
return 0;
|
|
53549
53570
|
}
|
|
53550
|
-
|
|
53551
|
-
|
|
53552
|
-
|
|
53553
|
-
if (aName != null && bName != null) {
|
|
53554
|
-
return aName.localeCompare(bName);
|
|
53555
|
-
}
|
|
53556
|
-
return 0;
|
|
53571
|
+
const diagnostic = validateDependencies(Array.from(inferred), manualDeps, reactive, manualMemoLoc, ErrorCategory.EffectExhaustiveDependencies);
|
|
53572
|
+
if (diagnostic != null) {
|
|
53573
|
+
error.pushDiagnostic(diagnostic);
|
|
53557
53574
|
}
|
|
53558
|
-
}
|
|
53559
|
-
|
|
53560
|
-
|
|
53561
|
-
|
|
53562
|
-
|
|
53563
|
-
|
|
53564
|
-
|
|
53565
|
-
|
|
53575
|
+
},
|
|
53576
|
+
}, false);
|
|
53577
|
+
return error.asResult();
|
|
53578
|
+
}
|
|
53579
|
+
function validateDependencies(inferred, manualDependencies, reactive, manualMemoLoc, category) {
|
|
53580
|
+
var _a, _b, _c, _d;
|
|
53581
|
+
inferred.sort((a, b) => {
|
|
53582
|
+
var _a, _b;
|
|
53583
|
+
if (a.kind === 'Global' && b.kind == 'Global') {
|
|
53584
|
+
return a.binding.name.localeCompare(b.binding.name);
|
|
53585
|
+
}
|
|
53586
|
+
else if (a.kind == 'Local' && b.kind == 'Local') {
|
|
53587
|
+
CompilerError.simpleInvariant(a.identifier.name != null &&
|
|
53588
|
+
a.identifier.name.kind === 'named' &&
|
|
53589
|
+
b.identifier.name != null &&
|
|
53590
|
+
b.identifier.name.kind === 'named', {
|
|
53591
|
+
reason: 'Expected dependencies to be named variables',
|
|
53592
|
+
loc: a.loc,
|
|
53566
53593
|
});
|
|
53567
|
-
|
|
53568
|
-
|
|
53569
|
-
|
|
53570
|
-
|
|
53571
|
-
|
|
53572
|
-
|
|
53573
|
-
|
|
53574
|
-
|
|
53575
|
-
|
|
53576
|
-
|
|
53577
|
-
|
|
53578
|
-
|
|
53579
|
-
|
|
53580
|
-
|
|
53581
|
-
|
|
53594
|
+
if (a.identifier.id !== b.identifier.id) {
|
|
53595
|
+
return a.identifier.name.value.localeCompare(b.identifier.name.value);
|
|
53596
|
+
}
|
|
53597
|
+
if (a.path.length !== b.path.length) {
|
|
53598
|
+
return a.path.length - b.path.length;
|
|
53599
|
+
}
|
|
53600
|
+
for (let i = 0; i < a.path.length; i++) {
|
|
53601
|
+
const aProperty = a.path[i];
|
|
53602
|
+
const bProperty = b.path[i];
|
|
53603
|
+
const aOptional = aProperty.optional ? 0 : 1;
|
|
53604
|
+
const bOptional = bProperty.optional ? 0 : 1;
|
|
53605
|
+
if (aOptional !== bOptional) {
|
|
53606
|
+
return aOptional - bOptional;
|
|
53607
|
+
}
|
|
53608
|
+
else if (aProperty.property !== bProperty.property) {
|
|
53609
|
+
return String(aProperty.property).localeCompare(String(bProperty.property));
|
|
53582
53610
|
}
|
|
53583
|
-
continue;
|
|
53584
53611
|
}
|
|
53585
|
-
|
|
53586
|
-
|
|
53587
|
-
|
|
53588
|
-
|
|
53589
|
-
|
|
53612
|
+
return 0;
|
|
53613
|
+
}
|
|
53614
|
+
else {
|
|
53615
|
+
const aName = a.kind === 'Global' ? a.binding.name : (_a = a.identifier.name) === null || _a === void 0 ? void 0 : _a.value;
|
|
53616
|
+
const bName = b.kind === 'Global' ? b.binding.name : (_b = b.identifier.name) === null || _b === void 0 ? void 0 : _b.value;
|
|
53617
|
+
if (aName != null && bName != null) {
|
|
53618
|
+
return aName.localeCompare(bName);
|
|
53619
|
+
}
|
|
53620
|
+
return 0;
|
|
53621
|
+
}
|
|
53622
|
+
});
|
|
53623
|
+
retainWhere(inferred, (dep, ix) => {
|
|
53624
|
+
const match = inferred.findIndex(prevDep => {
|
|
53625
|
+
return (isEqualTemporary(prevDep, dep) ||
|
|
53626
|
+
(prevDep.kind === 'Local' &&
|
|
53627
|
+
dep.kind === 'Local' &&
|
|
53628
|
+
prevDep.identifier.id === dep.identifier.id &&
|
|
53629
|
+
isSubPath(prevDep.path, dep.path)));
|
|
53630
|
+
});
|
|
53631
|
+
return match === -1 || match >= ix;
|
|
53632
|
+
});
|
|
53633
|
+
const matched = new Set();
|
|
53634
|
+
const missing = [];
|
|
53635
|
+
const extra = [];
|
|
53636
|
+
for (const inferredDependency of inferred) {
|
|
53637
|
+
if (inferredDependency.kind === 'Global') {
|
|
53590
53638
|
for (const manualDependency of manualDependencies) {
|
|
53591
|
-
if (manualDependency.root.kind === '
|
|
53592
|
-
manualDependency.root.
|
|
53593
|
-
inferredDependency.
|
|
53594
|
-
(areEqualPaths(manualDependency.path, inferredDependency.path) ||
|
|
53595
|
-
isSubPathIgnoringOptionals(manualDependency.path, inferredDependency.path))) {
|
|
53596
|
-
hasMatchingManualDependency = true;
|
|
53639
|
+
if (manualDependency.root.kind === 'Global' &&
|
|
53640
|
+
manualDependency.root.identifierName ===
|
|
53641
|
+
inferredDependency.binding.name) {
|
|
53597
53642
|
matched.add(manualDependency);
|
|
53643
|
+
extra.push(manualDependency);
|
|
53598
53644
|
}
|
|
53599
53645
|
}
|
|
53600
|
-
|
|
53601
|
-
isOptionalDependency(inferredDependency, reactive)) {
|
|
53602
|
-
continue;
|
|
53603
|
-
}
|
|
53604
|
-
missing.push(inferredDependency);
|
|
53646
|
+
continue;
|
|
53605
53647
|
}
|
|
53606
|
-
|
|
53607
|
-
|
|
53608
|
-
|
|
53609
|
-
|
|
53610
|
-
|
|
53611
|
-
|
|
53612
|
-
|
|
53613
|
-
|
|
53614
|
-
|
|
53615
|
-
|
|
53616
|
-
|
|
53648
|
+
CompilerError.simpleInvariant(inferredDependency.kind === 'Local', {
|
|
53649
|
+
reason: 'Unexpected function dependency',
|
|
53650
|
+
loc: inferredDependency.loc,
|
|
53651
|
+
});
|
|
53652
|
+
if (isEffectEventFunctionType(inferredDependency.identifier)) {
|
|
53653
|
+
continue;
|
|
53654
|
+
}
|
|
53655
|
+
let hasMatchingManualDependency = false;
|
|
53656
|
+
for (const manualDependency of manualDependencies) {
|
|
53657
|
+
if (manualDependency.root.kind === 'NamedLocal' &&
|
|
53658
|
+
manualDependency.root.value.identifier.id ===
|
|
53659
|
+
inferredDependency.identifier.id &&
|
|
53660
|
+
(areEqualPaths(manualDependency.path, inferredDependency.path) ||
|
|
53661
|
+
isSubPathIgnoringOptionals(manualDependency.path, inferredDependency.path))) {
|
|
53662
|
+
hasMatchingManualDependency = true;
|
|
53663
|
+
matched.add(manualDependency);
|
|
53617
53664
|
}
|
|
53618
|
-
|
|
53619
|
-
|
|
53620
|
-
|
|
53621
|
-
|
|
53622
|
-
|
|
53623
|
-
|
|
53624
|
-
|
|
53625
|
-
|
|
53626
|
-
|
|
53627
|
-
|
|
53628
|
-
|
|
53629
|
-
|
|
53630
|
-
|
|
53631
|
-
|
|
53665
|
+
}
|
|
53666
|
+
if (hasMatchingManualDependency ||
|
|
53667
|
+
isOptionalDependency(inferredDependency, reactive)) {
|
|
53668
|
+
continue;
|
|
53669
|
+
}
|
|
53670
|
+
missing.push(inferredDependency);
|
|
53671
|
+
}
|
|
53672
|
+
for (const dep of manualDependencies) {
|
|
53673
|
+
if (matched.has(dep)) {
|
|
53674
|
+
continue;
|
|
53675
|
+
}
|
|
53676
|
+
if (dep.root.kind === 'NamedLocal' && dep.root.constant) {
|
|
53677
|
+
CompilerError.simpleInvariant(!dep.root.value.reactive && isPrimitiveType(dep.root.value.identifier), {
|
|
53678
|
+
reason: 'Expected constant-folded dependency to be non-reactive',
|
|
53679
|
+
loc: dep.root.value.loc,
|
|
53680
|
+
});
|
|
53681
|
+
continue;
|
|
53682
|
+
}
|
|
53683
|
+
extra.push(dep);
|
|
53684
|
+
}
|
|
53685
|
+
if (missing.length !== 0 || extra.length !== 0) {
|
|
53686
|
+
let suggestion = null;
|
|
53687
|
+
if (manualMemoLoc != null && typeof manualMemoLoc !== 'symbol') {
|
|
53688
|
+
suggestion = {
|
|
53689
|
+
description: 'Update dependencies',
|
|
53690
|
+
range: [manualMemoLoc.start.index, manualMemoLoc.end.index],
|
|
53691
|
+
op: CompilerSuggestionOperation.Replace,
|
|
53692
|
+
text: `[${inferred
|
|
53693
|
+
.filter(dep => dep.kind === 'Local' &&
|
|
53694
|
+
!isOptionalDependency(dep, reactive) &&
|
|
53695
|
+
!isEffectEventFunctionType(dep.identifier))
|
|
53696
|
+
.map(printInferredDependency)
|
|
53697
|
+
.join(', ')}]`,
|
|
53698
|
+
};
|
|
53699
|
+
}
|
|
53700
|
+
const diagnostic = createDiagnostic(category, missing, extra, suggestion);
|
|
53701
|
+
for (const dep of missing) {
|
|
53702
|
+
let reactiveStableValueHint = '';
|
|
53703
|
+
if (isStableType(dep.identifier)) {
|
|
53704
|
+
reactiveStableValueHint =
|
|
53705
|
+
'. Refs, setState functions, and other "stable" values generally do not need to be added ' +
|
|
53706
|
+
'as dependencies, but this variable may change over time to point to different values';
|
|
53632
53707
|
}
|
|
53633
|
-
|
|
53634
|
-
|
|
53635
|
-
|
|
53636
|
-
|
|
53637
|
-
missing.length !== 0
|
|
53638
|
-
? 'Missing dependencies can cause a value to update less often than it should, ' +
|
|
53639
|
-
'resulting in stale UI'
|
|
53640
|
-
: null,
|
|
53641
|
-
extra.length !== 0
|
|
53642
|
-
? 'Extra dependencies can cause a value to update more often than it should, ' +
|
|
53643
|
-
'resulting in performance problems such as excessive renders or effects firing too often'
|
|
53644
|
-
: null,
|
|
53645
|
-
]
|
|
53646
|
-
.filter(Boolean)
|
|
53647
|
-
.join('. '),
|
|
53648
|
-
suggestions: suggestion != null ? [suggestion] : null,
|
|
53708
|
+
diagnostic.withDetails({
|
|
53709
|
+
kind: 'error',
|
|
53710
|
+
message: `Missing dependency \`${printInferredDependency(dep)}\`${reactiveStableValueHint}`,
|
|
53711
|
+
loc: dep.loc,
|
|
53649
53712
|
});
|
|
53650
|
-
|
|
53651
|
-
|
|
53652
|
-
|
|
53653
|
-
reactiveStableValueHint =
|
|
53654
|
-
'. Refs, setState functions, and other "stable" values generally do not need to be added ' +
|
|
53655
|
-
'as dependencies, but this variable may change over time to point to different values';
|
|
53656
|
-
}
|
|
53713
|
+
}
|
|
53714
|
+
for (const dep of extra) {
|
|
53715
|
+
if (dep.root.kind === 'Global') {
|
|
53657
53716
|
diagnostic.withDetails({
|
|
53658
53717
|
kind: 'error',
|
|
53659
|
-
message: `
|
|
53660
|
-
|
|
53718
|
+
message: `Unnecessary dependency \`${printManualMemoDependency(dep)}\`. ` +
|
|
53719
|
+
'Values declared outside of a component/hook should not be listed as ' +
|
|
53720
|
+
'dependencies as the component will not re-render if they change',
|
|
53721
|
+
loc: (_a = dep.loc) !== null && _a !== void 0 ? _a : manualMemoLoc,
|
|
53661
53722
|
});
|
|
53662
53723
|
}
|
|
53663
|
-
|
|
53664
|
-
|
|
53724
|
+
else {
|
|
53725
|
+
const root = dep.root.value;
|
|
53726
|
+
const matchingInferred = inferred.find((inferredDep) => {
|
|
53727
|
+
return (inferredDep.kind === 'Local' &&
|
|
53728
|
+
inferredDep.identifier.id === root.identifier.id &&
|
|
53729
|
+
isSubPathIgnoringOptionals(inferredDep.path, dep.path));
|
|
53730
|
+
});
|
|
53731
|
+
if (matchingInferred != null &&
|
|
53732
|
+
isEffectEventFunctionType(matchingInferred.identifier)) {
|
|
53733
|
+
diagnostic.withDetails({
|
|
53734
|
+
kind: 'error',
|
|
53735
|
+
message: `Functions returned from \`useEffectEvent\` must not be included in the dependency array. ` +
|
|
53736
|
+
`Remove \`${printManualMemoDependency(dep)}\` from the dependencies.`,
|
|
53737
|
+
loc: (_b = dep.loc) !== null && _b !== void 0 ? _b : manualMemoLoc,
|
|
53738
|
+
});
|
|
53739
|
+
}
|
|
53740
|
+
else if (matchingInferred != null &&
|
|
53741
|
+
!isOptionalDependency(matchingInferred, reactive)) {
|
|
53665
53742
|
diagnostic.withDetails({
|
|
53666
53743
|
kind: 'error',
|
|
53667
|
-
message: `
|
|
53668
|
-
|
|
53669
|
-
|
|
53670
|
-
loc: (_e = (_d = dep.loc) !== null && _d !== void 0 ? _d : startMemo.depsLoc) !== null && _e !== void 0 ? _e : value.loc,
|
|
53744
|
+
message: `Overly precise dependency \`${printManualMemoDependency(dep)}\`, ` +
|
|
53745
|
+
`use \`${printInferredDependency(matchingInferred)}\` instead`,
|
|
53746
|
+
loc: (_c = dep.loc) !== null && _c !== void 0 ? _c : manualMemoLoc,
|
|
53671
53747
|
});
|
|
53672
|
-
error.pushDiagnostic(diagnostic);
|
|
53673
53748
|
}
|
|
53674
53749
|
else {
|
|
53675
|
-
|
|
53676
|
-
|
|
53677
|
-
|
|
53678
|
-
|
|
53679
|
-
isSubPathIgnoringOptionals(inferredDep.path, dep.path));
|
|
53750
|
+
diagnostic.withDetails({
|
|
53751
|
+
kind: 'error',
|
|
53752
|
+
message: `Unnecessary dependency \`${printManualMemoDependency(dep)}\``,
|
|
53753
|
+
loc: (_d = dep.loc) !== null && _d !== void 0 ? _d : manualMemoLoc,
|
|
53680
53754
|
});
|
|
53681
|
-
if (matchingInferred != null &&
|
|
53682
|
-
!isOptionalDependency(matchingInferred, reactive)) {
|
|
53683
|
-
diagnostic.withDetails({
|
|
53684
|
-
kind: 'error',
|
|
53685
|
-
message: `Overly precise dependency \`${printManualMemoDependency(dep)}\`, ` +
|
|
53686
|
-
`use \`${printInferredDependency(matchingInferred)}\` instead`,
|
|
53687
|
-
loc: (_g = (_f = dep.loc) !== null && _f !== void 0 ? _f : startMemo.depsLoc) !== null && _g !== void 0 ? _g : value.loc,
|
|
53688
|
-
});
|
|
53689
|
-
}
|
|
53690
|
-
else {
|
|
53691
|
-
diagnostic.withDetails({
|
|
53692
|
-
kind: 'error',
|
|
53693
|
-
message: `Unnecessary dependency \`${printManualMemoDependency(dep)}\``,
|
|
53694
|
-
loc: (_j = (_h = dep.loc) !== null && _h !== void 0 ? _h : startMemo.depsLoc) !== null && _j !== void 0 ? _j : value.loc,
|
|
53695
|
-
});
|
|
53696
|
-
}
|
|
53697
53755
|
}
|
|
53698
53756
|
}
|
|
53699
|
-
if (suggestion != null) {
|
|
53700
|
-
diagnostic.withDetails({
|
|
53701
|
-
kind: 'hint',
|
|
53702
|
-
message: `Inferred dependencies: \`${suggestion.text}\``,
|
|
53703
|
-
});
|
|
53704
|
-
}
|
|
53705
|
-
error.pushDiagnostic(diagnostic);
|
|
53706
53757
|
}
|
|
53707
|
-
|
|
53708
|
-
|
|
53709
|
-
|
|
53758
|
+
if (suggestion != null) {
|
|
53759
|
+
diagnostic.withDetails({
|
|
53760
|
+
kind: 'hint',
|
|
53761
|
+
message: `Inferred dependencies: \`${suggestion.text}\``,
|
|
53762
|
+
});
|
|
53763
|
+
}
|
|
53764
|
+
return diagnostic;
|
|
53710
53765
|
}
|
|
53711
|
-
|
|
53712
|
-
onStartMemoize,
|
|
53713
|
-
onFinishMemoize,
|
|
53714
|
-
}, false);
|
|
53715
|
-
return error.asResult();
|
|
53766
|
+
return null;
|
|
53716
53767
|
}
|
|
53717
53768
|
function addDependency(dep, dependencies, locals) {
|
|
53718
|
-
if (dep.kind === '
|
|
53769
|
+
if (dep.kind === 'Aggregate') {
|
|
53719
53770
|
for (const x of dep.dependencies) {
|
|
53720
53771
|
addDependency(x, dependencies, locals);
|
|
53721
53772
|
}
|
|
@@ -53734,7 +53785,7 @@ function visitCandidateDependency(place, temporaries, dependencies, locals) {
|
|
|
53734
53785
|
}
|
|
53735
53786
|
}
|
|
53736
53787
|
function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
|
|
53737
|
-
var _a;
|
|
53788
|
+
var _a, _b;
|
|
53738
53789
|
const optionals = findOptionalPlaces(fn);
|
|
53739
53790
|
const locals = new Set();
|
|
53740
53791
|
if (isFunctionExpression) {
|
|
@@ -53749,20 +53800,20 @@ function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
|
|
|
53749
53800
|
}
|
|
53750
53801
|
for (const block of fn.body.blocks.values()) {
|
|
53751
53802
|
for (const phi of block.phis) {
|
|
53752
|
-
|
|
53803
|
+
const deps = [];
|
|
53753
53804
|
for (const operand of phi.operands.values()) {
|
|
53754
53805
|
const dep = temporaries.get(operand.identifier.id);
|
|
53755
53806
|
if (dep == null) {
|
|
53756
53807
|
continue;
|
|
53757
53808
|
}
|
|
53758
|
-
if (
|
|
53759
|
-
deps
|
|
53809
|
+
if (dep.kind === 'Aggregate') {
|
|
53810
|
+
deps.push(...dep.dependencies);
|
|
53760
53811
|
}
|
|
53761
53812
|
else {
|
|
53762
53813
|
deps.push(dep);
|
|
53763
53814
|
}
|
|
53764
53815
|
}
|
|
53765
|
-
if (deps
|
|
53816
|
+
if (deps.length === 0) {
|
|
53766
53817
|
continue;
|
|
53767
53818
|
}
|
|
53768
53819
|
else if (deps.length === 1) {
|
|
@@ -53770,7 +53821,7 @@ function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
|
|
|
53770
53821
|
}
|
|
53771
53822
|
else {
|
|
53772
53823
|
temporaries.set(phi.place.identifier.id, {
|
|
53773
|
-
kind: '
|
|
53824
|
+
kind: 'Aggregate',
|
|
53774
53825
|
dependencies: new Set(deps),
|
|
53775
53826
|
});
|
|
53776
53827
|
}
|
|
@@ -53787,9 +53838,6 @@ function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
|
|
|
53787
53838
|
}
|
|
53788
53839
|
case 'LoadContext':
|
|
53789
53840
|
case 'LoadLocal': {
|
|
53790
|
-
if (locals.has(value.place.identifier.id)) {
|
|
53791
|
-
break;
|
|
53792
|
-
}
|
|
53793
53841
|
const temp = temporaries.get(value.place.identifier.id);
|
|
53794
53842
|
if (temp != null) {
|
|
53795
53843
|
if (temp.kind === 'Local') {
|
|
@@ -53799,6 +53847,9 @@ function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
|
|
|
53799
53847
|
else {
|
|
53800
53848
|
temporaries.set(lvalue.identifier.id, temp);
|
|
53801
53849
|
}
|
|
53850
|
+
if (locals.has(value.place.identifier.id)) {
|
|
53851
|
+
locals.add(lvalue.identifier.id);
|
|
53852
|
+
}
|
|
53802
53853
|
}
|
|
53803
53854
|
break;
|
|
53804
53855
|
}
|
|
@@ -53927,9 +53978,41 @@ function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
|
|
|
53927
53978
|
}
|
|
53928
53979
|
break;
|
|
53929
53980
|
}
|
|
53981
|
+
case 'ArrayExpression': {
|
|
53982
|
+
const arrayDeps = new Set();
|
|
53983
|
+
for (const item of value.elements) {
|
|
53984
|
+
if (item.kind === 'Hole') {
|
|
53985
|
+
continue;
|
|
53986
|
+
}
|
|
53987
|
+
const place = item.kind === 'Identifier' ? item : item.place;
|
|
53988
|
+
visitCandidateDependency(place, temporaries, arrayDeps, new Set());
|
|
53989
|
+
visit(place);
|
|
53990
|
+
}
|
|
53991
|
+
temporaries.set(lvalue.identifier.id, {
|
|
53992
|
+
kind: 'Aggregate',
|
|
53993
|
+
dependencies: arrayDeps,
|
|
53994
|
+
loc: value.loc,
|
|
53995
|
+
});
|
|
53996
|
+
break;
|
|
53997
|
+
}
|
|
53998
|
+
case 'CallExpression':
|
|
53930
53999
|
case 'MethodCall': {
|
|
54000
|
+
const receiver = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
54001
|
+
const onEffect = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onEffect;
|
|
54002
|
+
if (onEffect != null && isEffectHook(receiver.identifier)) {
|
|
54003
|
+
const [fn, deps] = value.args;
|
|
54004
|
+
if ((fn === null || fn === void 0 ? void 0 : fn.kind) === 'Identifier' && (deps === null || deps === void 0 ? void 0 : deps.kind) === 'Identifier') {
|
|
54005
|
+
const fnDeps = temporaries.get(fn.identifier.id);
|
|
54006
|
+
const manualDeps = temporaries.get(deps.identifier.id);
|
|
54007
|
+
if ((fnDeps === null || fnDeps === void 0 ? void 0 : fnDeps.kind) === 'Aggregate' &&
|
|
54008
|
+
(manualDeps === null || manualDeps === void 0 ? void 0 : manualDeps.kind) === 'Aggregate') {
|
|
54009
|
+
onEffect(fnDeps.dependencies, manualDeps.dependencies, (_b = manualDeps.loc) !== null && _b !== void 0 ? _b : null);
|
|
54010
|
+
}
|
|
54011
|
+
}
|
|
54012
|
+
}
|
|
53931
54013
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
53932
|
-
if (
|
|
54014
|
+
if (value.kind === 'MethodCall' &&
|
|
54015
|
+
operand.identifier.id === value.property.identifier.id) {
|
|
53933
54016
|
continue;
|
|
53934
54017
|
}
|
|
53935
54018
|
visit(operand);
|
|
@@ -53953,7 +54036,7 @@ function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
|
|
|
53953
54036
|
visit(operand);
|
|
53954
54037
|
}
|
|
53955
54038
|
}
|
|
53956
|
-
return { kind: '
|
|
54039
|
+
return { kind: 'Aggregate', dependencies };
|
|
53957
54040
|
}
|
|
53958
54041
|
function printInferredDependency(dep) {
|
|
53959
54042
|
switch (dep.kind) {
|
|
@@ -53986,7 +54069,7 @@ function printManualMemoDependency(dep) {
|
|
|
53986
54069
|
}
|
|
53987
54070
|
function isEqualTemporary(a, b) {
|
|
53988
54071
|
switch (a.kind) {
|
|
53989
|
-
case '
|
|
54072
|
+
case 'Aggregate': {
|
|
53990
54073
|
return false;
|
|
53991
54074
|
}
|
|
53992
54075
|
case 'Global': {
|
|
@@ -54098,6 +54181,44 @@ function isOptionalDependency(inferredDependency, reactive) {
|
|
|
54098
54181
|
(isStableType(inferredDependency.identifier) ||
|
|
54099
54182
|
isPrimitiveType(inferredDependency.identifier)));
|
|
54100
54183
|
}
|
|
54184
|
+
function createDiagnostic(category, missing, extra, suggestion) {
|
|
54185
|
+
let reason;
|
|
54186
|
+
let description;
|
|
54187
|
+
function joinMissingExtraDetail(missingString, extraString, joinStr) {
|
|
54188
|
+
return [
|
|
54189
|
+
missing.length !== 0 ? missingString : null,
|
|
54190
|
+
extra.length !== 0 ? extraString : null,
|
|
54191
|
+
]
|
|
54192
|
+
.filter(Boolean)
|
|
54193
|
+
.join(joinStr);
|
|
54194
|
+
}
|
|
54195
|
+
switch (category) {
|
|
54196
|
+
case ErrorCategory.MemoDependencies: {
|
|
54197
|
+
reason = `Found ${joinMissingExtraDetail('missing', 'extra', '/')} memoization dependencies`;
|
|
54198
|
+
description = joinMissingExtraDetail('Missing dependencies can cause a value to update less often than it should, resulting in stale UI', 'Extra dependencies can cause a value to update more often than it should, resulting in performance' +
|
|
54199
|
+
' problems such as excessive renders or effects firing too often', '. ');
|
|
54200
|
+
break;
|
|
54201
|
+
}
|
|
54202
|
+
case ErrorCategory.EffectExhaustiveDependencies: {
|
|
54203
|
+
reason = `Found ${joinMissingExtraDetail('missing', 'extra', '/')} effect dependencies`;
|
|
54204
|
+
description = joinMissingExtraDetail('Missing dependencies can cause an effect to fire less often than it should', 'Extra dependencies can cause an effect to fire more often than it should, resulting' +
|
|
54205
|
+
' in performance problems such as excessive renders and side effects', '. ');
|
|
54206
|
+
break;
|
|
54207
|
+
}
|
|
54208
|
+
default: {
|
|
54209
|
+
CompilerError.simpleInvariant(false, {
|
|
54210
|
+
reason: `Unexpected error category: ${category}`,
|
|
54211
|
+
loc: GeneratedSource,
|
|
54212
|
+
});
|
|
54213
|
+
}
|
|
54214
|
+
}
|
|
54215
|
+
return CompilerDiagnostic.create({
|
|
54216
|
+
category,
|
|
54217
|
+
reason,
|
|
54218
|
+
description,
|
|
54219
|
+
suggestions: suggestion != null ? [suggestion] : null,
|
|
54220
|
+
});
|
|
54221
|
+
}
|
|
54101
54222
|
|
|
54102
54223
|
function run(func, config, fnType, mode, programContext, logger, filename, code) {
|
|
54103
54224
|
var _a, _b;
|
|
@@ -54225,7 +54346,8 @@ function runWithEnvironment(func, env) {
|
|
|
54225
54346
|
inferReactivePlaces(hir);
|
|
54226
54347
|
log({ kind: 'hir', name: 'InferReactivePlaces', value: hir });
|
|
54227
54348
|
if (env.enableValidations) {
|
|
54228
|
-
if (env.config.validateExhaustiveMemoizationDependencies
|
|
54349
|
+
if (env.config.validateExhaustiveMemoizationDependencies ||
|
|
54350
|
+
env.config.validateExhaustiveEffectDependencies) {
|
|
54229
54351
|
validateExhaustiveDependencies(hir).unwrap();
|
|
54230
54352
|
}
|
|
54231
54353
|
}
|