eslint-plugin-react-hooks 4.0.5 → 4.0.6
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.
|
@@ -768,7 +768,7 @@ var ExhaustiveDeps = {
|
|
|
768
768
|
|
|
769
769
|
var setStateCallSites = new WeakMap();
|
|
770
770
|
var stateVariables = new WeakSet();
|
|
771
|
-
var
|
|
771
|
+
var stableKnownValueCache = new WeakMap();
|
|
772
772
|
var functionWithoutCapturedValueCache = new WeakMap();
|
|
773
773
|
|
|
774
774
|
function memoizeWithWeakMap(fn, map) {
|
|
@@ -965,7 +965,7 @@ var ExhaustiveDeps = {
|
|
|
965
965
|
componentScope = currentScope;
|
|
966
966
|
} // Next we'll define a few helpers that helps us
|
|
967
967
|
// tell if some values don't have to be declared as deps.
|
|
968
|
-
// Some are known to be
|
|
968
|
+
// Some are known to be stable based on Hook calls.
|
|
969
969
|
// const [state, setState] = useState() / React.useState()
|
|
970
970
|
// ^^^ true for this reference
|
|
971
971
|
// const [state, dispatch] = useReducer() / React.useReducer()
|
|
@@ -974,7 +974,7 @@ var ExhaustiveDeps = {
|
|
|
974
974
|
// ^^^ true for this reference
|
|
975
975
|
// False for everything else.
|
|
976
976
|
|
|
977
|
-
function
|
|
977
|
+
function isStableKnownHookValue(resolved) {
|
|
978
978
|
if (!Array.isArray(resolved.defs)) {
|
|
979
979
|
return false;
|
|
980
980
|
}
|
|
@@ -1017,7 +1017,7 @@ var ExhaustiveDeps = {
|
|
|
1017
1017
|
}
|
|
1018
1018
|
|
|
1019
1019
|
if (declaration.kind === 'const' && init.type === 'Literal' && (typeof init.value === 'string' || typeof init.value === 'number' || init.value === null)) {
|
|
1020
|
-
// Definitely
|
|
1020
|
+
// Definitely stable
|
|
1021
1021
|
return true;
|
|
1022
1022
|
} // Detect known Hook calls
|
|
1023
1023
|
// const [_, setState] = useState()
|
|
@@ -1042,10 +1042,10 @@ var ExhaustiveDeps = {
|
|
|
1042
1042
|
name = _callee.name;
|
|
1043
1043
|
|
|
1044
1044
|
if (name === 'useRef' && id.type === 'Identifier') {
|
|
1045
|
-
// useRef() return value is
|
|
1045
|
+
// useRef() return value is stable.
|
|
1046
1046
|
return true;
|
|
1047
1047
|
} else if (name === 'useState' || name === 'useReducer') {
|
|
1048
|
-
// Only consider second value in initializing tuple
|
|
1048
|
+
// Only consider second value in initializing tuple stable.
|
|
1049
1049
|
if (id.type === 'ArrayPattern' && id.elements.length === 2 && Array.isArray(resolved.identifiers)) {
|
|
1050
1050
|
// Is second tuple value the same reference we're checking?
|
|
1051
1051
|
if (id.elements[1] === resolved.identifiers[0]) {
|
|
@@ -1055,7 +1055,7 @@ var ExhaustiveDeps = {
|
|
|
1055
1055
|
for (var i = 0; i < references.length; i++) {
|
|
1056
1056
|
setStateCallSites.set(references[i].identifier, id.elements[0]);
|
|
1057
1057
|
}
|
|
1058
|
-
} // Setter is
|
|
1058
|
+
} // Setter is stable.
|
|
1059
1059
|
|
|
1060
1060
|
|
|
1061
1061
|
return true;
|
|
@@ -1128,20 +1128,20 @@ var ExhaustiveDeps = {
|
|
|
1128
1128
|
continue;
|
|
1129
1129
|
}
|
|
1130
1130
|
|
|
1131
|
-
if (pureScopes.has(ref.resolved.scope) && //
|
|
1131
|
+
if (pureScopes.has(ref.resolved.scope) && // Stable values are fine though,
|
|
1132
1132
|
// although we won't check functions deeper.
|
|
1133
|
-
!
|
|
1133
|
+
!memoizedIsStablecKnownHookValue(ref.resolved)) {
|
|
1134
1134
|
return false;
|
|
1135
1135
|
}
|
|
1136
1136
|
} // If we got here, this function doesn't capture anything
|
|
1137
|
-
// from render--or everything it captures is known
|
|
1137
|
+
// from render--or everything it captures is known stable.
|
|
1138
1138
|
|
|
1139
1139
|
|
|
1140
1140
|
return true;
|
|
1141
1141
|
} // Remember such values. Avoid re-running extra checks on them.
|
|
1142
1142
|
|
|
1143
1143
|
|
|
1144
|
-
var
|
|
1144
|
+
var memoizedIsStablecKnownHookValue = memoizeWithWeakMap(isStableKnownHookValue, stableKnownValueCache);
|
|
1145
1145
|
var memoizedIsFunctionWithoutCapturedValues = memoizeWithWeakMap(isFunctionWithoutCapturedValues, functionWithoutCapturedValueCache); // These are usually mistaken. Collect them.
|
|
1146
1146
|
|
|
1147
1147
|
var currentRefsInEffectCleanup = new Map(); // Is this reference inside a cleanup function for this effect node?
|
|
@@ -1162,10 +1162,11 @@ var ExhaustiveDeps = {
|
|
|
1162
1162
|
|
|
1163
1163
|
return isInReturnedFunction;
|
|
1164
1164
|
} // Get dependencies from all our resolved references in pure scopes.
|
|
1165
|
-
// Key is dependency string, value is whether it's
|
|
1165
|
+
// Key is dependency string, value is whether it's stable.
|
|
1166
1166
|
|
|
1167
1167
|
|
|
1168
1168
|
var dependencies = new Map();
|
|
1169
|
+
var optionalChains = new Map();
|
|
1169
1170
|
gatherDependenciesRecursively(scope);
|
|
1170
1171
|
|
|
1171
1172
|
function gatherDependenciesRecursively(currentScope) {
|
|
@@ -1191,11 +1192,11 @@ var ExhaustiveDeps = {
|
|
|
1191
1192
|
|
|
1192
1193
|
var referenceNode = fastFindReferenceWithParent(node, reference.identifier);
|
|
1193
1194
|
var dependencyNode = getDependency(referenceNode);
|
|
1194
|
-
var dependency =
|
|
1195
|
+
var dependency = analyzePropertyChain(dependencyNode, optionalChains); // Accessing ref.current inside effect cleanup is bad.
|
|
1195
1196
|
|
|
1196
1197
|
if ( // We're in an effect...
|
|
1197
1198
|
isEffect && // ... and this look like accessing .current...
|
|
1198
|
-
dependencyNode.type === 'Identifier' && dependencyNode.parent.type === 'MemberExpression' && !dependencyNode.parent.computed && dependencyNode.parent.property.type === 'Identifier' && dependencyNode.parent.property.name === 'current' && // ...in a cleanup function or below...
|
|
1199
|
+
dependencyNode.type === 'Identifier' && (dependencyNode.parent.type === 'MemberExpression' || dependencyNode.parent.type === 'OptionalMemberExpression') && !dependencyNode.parent.computed && dependencyNode.parent.property.type === 'Identifier' && dependencyNode.parent.property.name === 'current' && // ...in a cleanup function or below...
|
|
1199
1200
|
isInsideEffectCleanup(reference)) {
|
|
1200
1201
|
currentRefsInEffectCleanup.set(dependency, {
|
|
1201
1202
|
reference: reference,
|
|
@@ -1218,14 +1219,14 @@ var ExhaustiveDeps = {
|
|
|
1218
1219
|
if (def.type === 'TypeParameter') {
|
|
1219
1220
|
continue;
|
|
1220
1221
|
} // Add the dependency to a map so we can make sure it is referenced
|
|
1221
|
-
// again in our dependencies array. Remember whether it's
|
|
1222
|
+
// again in our dependencies array. Remember whether it's stable.
|
|
1222
1223
|
|
|
1223
1224
|
|
|
1224
1225
|
if (!dependencies.has(dependency)) {
|
|
1225
1226
|
var resolved = reference.resolved;
|
|
1226
|
-
var
|
|
1227
|
+
var isStable = memoizedIsStablecKnownHookValue(resolved) || memoizedIsFunctionWithoutCapturedValues(resolved);
|
|
1227
1228
|
dependencies.set(dependency, {
|
|
1228
|
-
|
|
1229
|
+
isStable: isStable,
|
|
1229
1230
|
references: [reference]
|
|
1230
1231
|
});
|
|
1231
1232
|
} else {
|
|
@@ -1286,6 +1287,7 @@ var ExhaustiveDeps = {
|
|
|
1286
1287
|
var parent = identifier.parent;
|
|
1287
1288
|
|
|
1288
1289
|
if (parent != null && // ref.current
|
|
1290
|
+
// Note: no need to handle OptionalMemberExpression because it can't be LHS.
|
|
1289
1291
|
parent.type === 'MemberExpression' && !parent.computed && parent.property.type === 'Identifier' && parent.property.name === 'current' && // ref.current = <something>
|
|
1290
1292
|
parent.parent.type === 'AssignmentExpression' && parent.parent.left === parent) {
|
|
1291
1293
|
foundCurrentAssignment = true;
|
|
@@ -1317,16 +1319,16 @@ var ExhaustiveDeps = {
|
|
|
1317
1319
|
node: writeExpr,
|
|
1318
1320
|
message: "Assignments to the '" + key + "' variable from inside React Hook " + (context.getSource(reactiveHook) + " will be lost after each ") + "render. To preserve the value over time, store it in a useRef " + "Hook and keep the mutable value in the '.current' property. " + "Otherwise, you can move this variable directly inside " + (context.getSource(reactiveHook) + ".")
|
|
1319
1321
|
});
|
|
1320
|
-
} // Remember which deps are
|
|
1322
|
+
} // Remember which deps are stable and report bad usage first.
|
|
1321
1323
|
|
|
1322
1324
|
|
|
1323
|
-
var
|
|
1325
|
+
var stableDependencies = new Set();
|
|
1324
1326
|
dependencies.forEach(function (_ref2, key) {
|
|
1325
|
-
var
|
|
1327
|
+
var isStable = _ref2.isStable,
|
|
1326
1328
|
references = _ref2.references;
|
|
1327
1329
|
|
|
1328
|
-
if (
|
|
1329
|
-
|
|
1330
|
+
if (isStable) {
|
|
1331
|
+
stableDependencies.add(key);
|
|
1330
1332
|
}
|
|
1331
1333
|
|
|
1332
1334
|
references.forEach(function (reference) {
|
|
@@ -1346,7 +1348,7 @@ var ExhaustiveDeps = {
|
|
|
1346
1348
|
// Those tend to lead to infinite loops.
|
|
1347
1349
|
var setStateInsideEffectWithoutDeps = null;
|
|
1348
1350
|
dependencies.forEach(function (_ref3, key) {
|
|
1349
|
-
var
|
|
1351
|
+
var isStable = _ref3.isStable,
|
|
1350
1352
|
references = _ref3.references;
|
|
1351
1353
|
|
|
1352
1354
|
if (setStateInsideEffectWithoutDeps) {
|
|
@@ -1384,7 +1386,7 @@ var ExhaustiveDeps = {
|
|
|
1384
1386
|
var _collectRecommendatio = collectRecommendations({
|
|
1385
1387
|
dependencies: dependencies,
|
|
1386
1388
|
declaredDependencies: [],
|
|
1387
|
-
|
|
1389
|
+
stableDependencies: stableDependencies,
|
|
1388
1390
|
externalDependencies: new Set(),
|
|
1389
1391
|
isEffect: true
|
|
1390
1392
|
}),
|
|
@@ -1437,7 +1439,7 @@ var ExhaustiveDeps = {
|
|
|
1437
1439
|
var declaredDependency;
|
|
1438
1440
|
|
|
1439
1441
|
try {
|
|
1440
|
-
declaredDependency =
|
|
1442
|
+
declaredDependency = analyzePropertyChain(declaredDependencyNode, null);
|
|
1441
1443
|
} catch (error) {
|
|
1442
1444
|
if (/Unsupported node type/.test(error.message)) {
|
|
1443
1445
|
if (declaredDependencyNode.type === 'Literal') {
|
|
@@ -1467,7 +1469,7 @@ var ExhaustiveDeps = {
|
|
|
1467
1469
|
|
|
1468
1470
|
var maybeID = declaredDependencyNode;
|
|
1469
1471
|
|
|
1470
|
-
while (maybeID.type === 'MemberExpression') {
|
|
1472
|
+
while (maybeID.type === 'MemberExpression' || maybeID.type === 'OptionalMemberExpression') {
|
|
1471
1473
|
maybeID = maybeID.object;
|
|
1472
1474
|
}
|
|
1473
1475
|
|
|
@@ -1489,7 +1491,7 @@ var ExhaustiveDeps = {
|
|
|
1489
1491
|
var _collectRecommendatio2 = collectRecommendations({
|
|
1490
1492
|
dependencies: dependencies,
|
|
1491
1493
|
declaredDependencies: declaredDependencies,
|
|
1492
|
-
|
|
1494
|
+
stableDependencies: stableDependencies,
|
|
1493
1495
|
externalDependencies: externalDependencies,
|
|
1494
1496
|
isEffect: isEffect
|
|
1495
1497
|
}),
|
|
@@ -1561,7 +1563,7 @@ var ExhaustiveDeps = {
|
|
|
1561
1563
|
dependencies: dependencies,
|
|
1562
1564
|
declaredDependencies: [],
|
|
1563
1565
|
// Pretend we don't know
|
|
1564
|
-
|
|
1566
|
+
stableDependencies: stableDependencies,
|
|
1565
1567
|
externalDependencies: externalDependencies,
|
|
1566
1568
|
isEffect: isEffect
|
|
1567
1569
|
}).suggestedDependencies;
|
|
@@ -1582,6 +1584,27 @@ var ExhaustiveDeps = {
|
|
|
1582
1584
|
|
|
1583
1585
|
if (areDeclaredDepsAlphabetized()) {
|
|
1584
1586
|
suggestedDeps.sort();
|
|
1587
|
+
} // Most of our algorithm deals with dependency paths with optional chaining stripped.
|
|
1588
|
+
// This function is the last step before printing a dependency, so now is a good time to
|
|
1589
|
+
// check whether any members in our path are always used as optional-only. In that case,
|
|
1590
|
+
// we will use ?. instead of . to concatenate those parts of the path.
|
|
1591
|
+
|
|
1592
|
+
|
|
1593
|
+
function formatDependency(path) {
|
|
1594
|
+
var members = path.split('.');
|
|
1595
|
+
var finalPath = '';
|
|
1596
|
+
|
|
1597
|
+
for (var i = 0; i < members.length; i++) {
|
|
1598
|
+
if (i !== 0) {
|
|
1599
|
+
var pathSoFar = members.slice(0, i + 1).join('.');
|
|
1600
|
+
var isOptional = optionalChains.get(pathSoFar) === true;
|
|
1601
|
+
finalPath += isOptional ? '?.' : '.';
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
finalPath += members[i];
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
return finalPath;
|
|
1585
1608
|
}
|
|
1586
1609
|
|
|
1587
1610
|
function getWarningMessage(deps, singlePrefix, label, fixVerb) {
|
|
@@ -1590,7 +1613,7 @@ var ExhaustiveDeps = {
|
|
|
1590
1613
|
}
|
|
1591
1614
|
|
|
1592
1615
|
return (deps.size > 1 ? '' : singlePrefix + ' ') + label + ' ' + (deps.size > 1 ? 'dependencies' : 'dependency') + ': ' + joinEnglish(Array.from(deps).sort().map(function (name) {
|
|
1593
|
-
return "'" + name + "'";
|
|
1616
|
+
return "'" + formatDependency(name) + "'";
|
|
1594
1617
|
})) + (". Either " + fixVerb + " " + (deps.size > 1 ? 'them' : 'it') + " or remove the dependency array.");
|
|
1595
1618
|
}
|
|
1596
1619
|
|
|
@@ -1654,7 +1677,7 @@ var ExhaustiveDeps = {
|
|
|
1654
1677
|
break;
|
|
1655
1678
|
}
|
|
1656
1679
|
|
|
1657
|
-
if (parent.type !== 'MemberExpression') {
|
|
1680
|
+
if (parent.type !== 'MemberExpression' && parent.type !== 'OptionalMemberExpression') {
|
|
1658
1681
|
isPropsOnlyUsedInMembers = false;
|
|
1659
1682
|
break;
|
|
1660
1683
|
}
|
|
@@ -1696,7 +1719,7 @@ var ExhaustiveDeps = {
|
|
|
1696
1719
|
for (var _i2 = 0; _i2 < usedDep.references.length; _i2++) {
|
|
1697
1720
|
id = usedDep.references[_i2].identifier;
|
|
1698
1721
|
|
|
1699
|
-
if (id != null && id.parent != null && id.parent.type === 'CallExpression' && id.parent.callee === id) {
|
|
1722
|
+
if (id != null && id.parent != null && (id.parent.type === 'CallExpression' || id.parent.type === 'OptionalCallExpression') && id.parent.callee === id) {
|
|
1700
1723
|
isFunctionCall = true;
|
|
1701
1724
|
break;
|
|
1702
1725
|
}
|
|
@@ -1809,10 +1832,10 @@ var ExhaustiveDeps = {
|
|
|
1809
1832
|
message: "React Hook " + context.getSource(reactiveHook) + " has " + ( // To avoid a long message, show the next actionable item.
|
|
1810
1833
|
getWarningMessage(missingDependencies, 'a', 'missing', 'include') || getWarningMessage(unnecessaryDependencies, 'an', 'unnecessary', 'exclude') || getWarningMessage(duplicateDependencies, 'a', 'duplicate', 'omit')) + extraWarning,
|
|
1811
1834
|
suggest: [{
|
|
1812
|
-
desc: "Update the dependencies array to be: [" + suggestedDeps.join(', ') + "]",
|
|
1835
|
+
desc: "Update the dependencies array to be: [" + suggestedDeps.map(formatDependency).join(', ') + "]",
|
|
1813
1836
|
fix: function (fixer) {
|
|
1814
1837
|
// TODO: consider preserving the comments or formatting?
|
|
1815
|
-
return fixer.replaceText(declaredDependenciesNode, "[" + suggestedDeps.join(', ') + "]");
|
|
1838
|
+
return fixer.replaceText(declaredDependenciesNode, "[" + suggestedDeps.map(formatDependency).join(', ') + "]");
|
|
1816
1839
|
}
|
|
1817
1840
|
}]
|
|
1818
1841
|
});
|
|
@@ -1823,7 +1846,7 @@ var ExhaustiveDeps = {
|
|
|
1823
1846
|
function collectRecommendations(_ref5) {
|
|
1824
1847
|
var dependencies = _ref5.dependencies,
|
|
1825
1848
|
declaredDependencies = _ref5.declaredDependencies,
|
|
1826
|
-
|
|
1849
|
+
stableDependencies = _ref5.stableDependencies,
|
|
1827
1850
|
externalDependencies = _ref5.externalDependencies,
|
|
1828
1851
|
isEffect = _ref5.isEffect;
|
|
1829
1852
|
// Our primary data structure.
|
|
@@ -1839,11 +1862,11 @@ function collectRecommendations(_ref5) {
|
|
|
1839
1862
|
|
|
1840
1863
|
function createDepTree() {
|
|
1841
1864
|
return {
|
|
1842
|
-
|
|
1865
|
+
isUsed: false,
|
|
1843
1866
|
// True if used in code
|
|
1844
1867
|
isSatisfiedRecursively: false,
|
|
1845
1868
|
// True if specified in deps
|
|
1846
|
-
|
|
1869
|
+
isSubtreeUsed: false,
|
|
1847
1870
|
// True if something deeper is used by code
|
|
1848
1871
|
children: new Map() // Nodes for properties
|
|
1849
1872
|
|
|
@@ -1854,9 +1877,9 @@ function collectRecommendations(_ref5) {
|
|
|
1854
1877
|
|
|
1855
1878
|
dependencies.forEach(function (_, key) {
|
|
1856
1879
|
var node = getOrCreateNodeByPath(depTree, key);
|
|
1857
|
-
node.
|
|
1880
|
+
node.isUsed = true;
|
|
1858
1881
|
markAllParentsByPath(depTree, key, function (parent) {
|
|
1859
|
-
parent.
|
|
1882
|
+
parent.isSubtreeUsed = true;
|
|
1860
1883
|
});
|
|
1861
1884
|
}); // Mark all satisfied nodes.
|
|
1862
1885
|
// Imagine checkmarks next to each declared dependency.
|
|
@@ -1866,7 +1889,7 @@ function collectRecommendations(_ref5) {
|
|
|
1866
1889
|
var node = getOrCreateNodeByPath(depTree, key);
|
|
1867
1890
|
node.isSatisfiedRecursively = true;
|
|
1868
1891
|
});
|
|
1869
|
-
|
|
1892
|
+
stableDependencies.forEach(function (key) {
|
|
1870
1893
|
var node = getOrCreateNodeByPath(depTree, key);
|
|
1871
1894
|
node.isSatisfiedRecursively = true;
|
|
1872
1895
|
}); // Tree manipulation helpers.
|
|
@@ -1881,7 +1904,7 @@ function collectRecommendations(_ref5) {
|
|
|
1881
1904
|
try {
|
|
1882
1905
|
for (var _iterator3 = keys[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
|
|
1883
1906
|
var key = _step3.value;
|
|
1884
|
-
var child =
|
|
1907
|
+
var child = node.children.get(key);
|
|
1885
1908
|
|
|
1886
1909
|
if (!child) {
|
|
1887
1910
|
child = createDepTree();
|
|
@@ -1918,7 +1941,7 @@ function collectRecommendations(_ref5) {
|
|
|
1918
1941
|
try {
|
|
1919
1942
|
for (var _iterator4 = keys[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
|
|
1920
1943
|
var key = _step4.value;
|
|
1921
|
-
var child =
|
|
1944
|
+
var child = node.children.get(key);
|
|
1922
1945
|
|
|
1923
1946
|
if (!child) {
|
|
1924
1947
|
return;
|
|
@@ -1941,18 +1964,6 @@ function collectRecommendations(_ref5) {
|
|
|
1941
1964
|
}
|
|
1942
1965
|
}
|
|
1943
1966
|
}
|
|
1944
|
-
}
|
|
1945
|
-
/**
|
|
1946
|
-
* Match key with optional chaining
|
|
1947
|
-
* key -> key
|
|
1948
|
-
* key? -> key
|
|
1949
|
-
* key -> key?
|
|
1950
|
-
* Otherwise undefined.
|
|
1951
|
-
*/
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
function getChildByKey(node, key) {
|
|
1955
|
-
return node.children.get(key) || node.children.get(key.split('?')[0]) || node.children.get(key + '?');
|
|
1956
1967
|
} // Now we can learn which dependencies are missing or necessary.
|
|
1957
1968
|
|
|
1958
1969
|
|
|
@@ -1964,15 +1975,12 @@ function collectRecommendations(_ref5) {
|
|
|
1964
1975
|
|
|
1965
1976
|
function scanTreeRecursively(node, missingPaths, satisfyingPaths, keyToPath) {
|
|
1966
1977
|
node.children.forEach(function (child, key) {
|
|
1967
|
-
var path = keyToPath(key);
|
|
1968
|
-
// foo?.bar -> foo.bar
|
|
1969
|
-
|
|
1970
|
-
var normalizedPath = path.replace(/\?$/, '');
|
|
1978
|
+
var path = keyToPath(key);
|
|
1971
1979
|
|
|
1972
1980
|
if (child.isSatisfiedRecursively) {
|
|
1973
|
-
if (child.
|
|
1981
|
+
if (child.isSubtreeUsed) {
|
|
1974
1982
|
// Remember this dep actually satisfied something.
|
|
1975
|
-
satisfyingPaths.add(
|
|
1983
|
+
satisfyingPaths.add(path);
|
|
1976
1984
|
} // It doesn't matter if there's something deeper.
|
|
1977
1985
|
// It would be transitively satisfied since we assume immutability.
|
|
1978
1986
|
// `props.foo` is enough if you read `props.foo.id`.
|
|
@@ -1981,9 +1989,9 @@ function collectRecommendations(_ref5) {
|
|
|
1981
1989
|
return;
|
|
1982
1990
|
}
|
|
1983
1991
|
|
|
1984
|
-
if (child.
|
|
1992
|
+
if (child.isUsed) {
|
|
1985
1993
|
// Remember that no declared deps satisfied this node.
|
|
1986
|
-
missingPaths.add(
|
|
1994
|
+
missingPaths.add(path); // If we got here, nothing in its subtree was satisfied.
|
|
1987
1995
|
// No need to search further.
|
|
1988
1996
|
|
|
1989
1997
|
return;
|
|
@@ -2125,9 +2133,10 @@ function scanForDeclaredBareFunctions(_ref8) {
|
|
|
2125
2133
|
|
|
2126
2134
|
|
|
2127
2135
|
function getDependency(node) {
|
|
2128
|
-
if ((node.parent.type === 'MemberExpression' || node.parent.type === 'OptionalMemberExpression') && node.parent.object === node && node.parent.property.name !== 'current' && !node.parent.computed && !(node.parent.parent != null && node.parent.parent.type === 'CallExpression' && node.parent.parent.callee === node.parent)) {
|
|
2136
|
+
if ((node.parent.type === 'MemberExpression' || node.parent.type === 'OptionalMemberExpression') && node.parent.object === node && node.parent.property.name !== 'current' && !node.parent.computed && !(node.parent.parent != null && (node.parent.parent.type === 'CallExpression' || node.parent.parent.type === 'OptionalCallExpression') && node.parent.parent.callee === node.parent)) {
|
|
2129
2137
|
return getDependency(node.parent);
|
|
2130
|
-
} else if (
|
|
2138
|
+
} else if ( // Note: we don't check OptionalMemberExpression because it can't be LHS.
|
|
2139
|
+
node.type === 'MemberExpression' && node.parent && node.parent.type === 'AssignmentExpression') {
|
|
2131
2140
|
return node.object;
|
|
2132
2141
|
} else {
|
|
2133
2142
|
return node;
|
|
@@ -2136,26 +2145,58 @@ function getDependency(node) {
|
|
|
2136
2145
|
/**
|
|
2137
2146
|
* Assuming () means the passed node.
|
|
2138
2147
|
* (foo) -> 'foo'
|
|
2139
|
-
* foo.
|
|
2140
|
-
* foo.bar.
|
|
2141
|
-
* foo?.(bar) -> 'foo?.bar'
|
|
2148
|
+
* foo(.)bar -> 'foo.bar'
|
|
2149
|
+
* foo.bar(.)baz -> 'foo.bar.baz'
|
|
2142
2150
|
* Otherwise throw.
|
|
2143
2151
|
*/
|
|
2144
2152
|
|
|
2145
2153
|
|
|
2146
|
-
function
|
|
2154
|
+
function analyzePropertyChain(node, optionalChains) {
|
|
2147
2155
|
if (node.type === 'Identifier') {
|
|
2148
|
-
|
|
2156
|
+
var result = node.name;
|
|
2157
|
+
|
|
2158
|
+
if (optionalChains) {
|
|
2159
|
+
// Mark as required.
|
|
2160
|
+
optionalChains.set(result, false);
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
return result;
|
|
2149
2164
|
} else if (node.type === 'MemberExpression' && !node.computed) {
|
|
2150
|
-
var object =
|
|
2151
|
-
var property =
|
|
2152
|
-
|
|
2165
|
+
var object = analyzePropertyChain(node.object, optionalChains);
|
|
2166
|
+
var property = analyzePropertyChain(node.property, null);
|
|
2167
|
+
|
|
2168
|
+
var _result = object + "." + property;
|
|
2169
|
+
|
|
2170
|
+
if (optionalChains) {
|
|
2171
|
+
// Mark as required.
|
|
2172
|
+
optionalChains.set(_result, false);
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
return _result;
|
|
2153
2176
|
} else if (node.type === 'OptionalMemberExpression' && !node.computed) {
|
|
2154
|
-
var _object =
|
|
2177
|
+
var _object = analyzePropertyChain(node.object, optionalChains);
|
|
2155
2178
|
|
|
2156
|
-
var _property =
|
|
2179
|
+
var _property = analyzePropertyChain(node.property, null);
|
|
2180
|
+
|
|
2181
|
+
var _result2 = _object + "." + _property;
|
|
2182
|
+
|
|
2183
|
+
if (optionalChains) {
|
|
2184
|
+
// Note: OptionalMemberExpression doesn't necessarily mean this node is optional.
|
|
2185
|
+
// It just means there is an optional member somewhere inside.
|
|
2186
|
+
// This particular node might still represent a required member, so check .optional field.
|
|
2187
|
+
if (node.optional) {
|
|
2188
|
+
// We only want to consider it optional if *all* usages were optional.
|
|
2189
|
+
if (!optionalChains.has(_result2)) {
|
|
2190
|
+
// Mark as (maybe) optional. If there's a required usage, this will be overridden.
|
|
2191
|
+
optionalChains.set(_result2, true);
|
|
2192
|
+
}
|
|
2193
|
+
} else {
|
|
2194
|
+
// Mark as required.
|
|
2195
|
+
optionalChains.set(_result2, false);
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2157
2198
|
|
|
2158
|
-
return
|
|
2199
|
+
return _result2;
|
|
2159
2200
|
} else {
|
|
2160
2201
|
throw new Error("Unsupported node type: " + node.type);
|
|
2161
2202
|
}
|
|
@@ -2200,7 +2241,7 @@ function getReactiveHookCallbackIndex(calleeNode, options) {
|
|
|
2200
2241
|
var name;
|
|
2201
2242
|
|
|
2202
2243
|
try {
|
|
2203
|
-
name =
|
|
2244
|
+
name = analyzePropertyChain(node, null);
|
|
2204
2245
|
} catch (error) {
|
|
2205
2246
|
if (/Unsupported node type/.test(error.message)) {
|
|
2206
2247
|
return 0;
|
|
@@ -6,51 +6,52 @@
|
|
|
6
6
|
* This source code is licensed under the MIT license found in the
|
|
7
7
|
* LICENSE file in the root directory of this source tree.
|
|
8
8
|
*/
|
|
9
|
-
'use strict';function
|
|
10
|
-
function
|
|
11
|
-
function
|
|
9
|
+
'use strict';function O(a){if("Identifier"===a.type)return/^use[A-Z0-9].*$/.test(a.name);if("MemberExpression"===a.type&&!a.computed&&O(a.property)){a=a.object;var c=/^[A-Z].*/;return"Identifier"===a.type&&c.test(a.name)}return!1}function aa(a){return"Identifier"===a.type?!/^[a-z]/.test(a.name):!1}function ba(a,c){return a.name===c||"MemberExpression"===a.type&&"React"===a.object.name&&a.property.name===c}function ea(a){return!!(a.parent&&a.parent.callee&&ba(a.parent.callee,"forwardRef"))}
|
|
10
|
+
function fa(a){return!!(a.parent&&a.parent.callee&&ba(a.parent.callee,"memo"))}function ha(a){for(;a;){var c=ia(a);if(c&&(aa(c)||O(c))||ea(a)||fa(a))return!0;a=a.parent}return!1}
|
|
11
|
+
function ia(a){if("FunctionDeclaration"===a.type||"FunctionExpression"===a.type&&a.id)return a.id;if("FunctionExpression"===a.type||"ArrowFunctionExpression"===a.type)return"VariableDeclarator"===a.parent.type&&a.parent.init===a?a.parent.id:"AssignmentExpression"===a.parent.type&&a.parent.right===a&&"="===a.parent.operator?a.parent.left:"Property"!==a.parent.type||a.parent.value!==a||a.parent.computed?"AssignmentPattern"!==a.parent.type||a.parent.right!==a||a.parent.computed?void 0:a.parent.left:
|
|
12
12
|
a.parent.key}
|
|
13
|
-
function
|
|
14
|
-
!0){var
|
|
15
|
-
|
|
16
|
-
return{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function
|
|
20
|
-
function
|
|
21
|
-
function
|
|
22
|
-
function
|
|
23
|
-
function
|
|
24
|
-
exports.rules={"rules-of-hooks":{meta:{type:"problem",docs:{description:"enforces the Rules of Hooks",category:"Possible Errors",recommended:!0,url:"https://reactjs.org/docs/hooks-rules.html"}},create:function(a){var c=[],e=[];return{onCodePathSegmentStart:function(a){return e.push(a)},onCodePathSegmentEnd:function(){return e.pop()},onCodePathStart:function(){return c.push(new Map)},onCodePathEnd:function(e,
|
|
25
|
-
a=
|
|
26
|
-
|
|
27
|
-
1;else{b=0;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if(
|
|
31
|
-
a.report({node:
|
|
32
|
-
'React Hook "'+a.getSource(
|
|
33
|
-
docs:{description:"verifies the list of dependencies for Hooks like useEffect and similar",category:"Best Practices",recommended:!0,url:"https://github.com/facebook/react/issues/14920"},fixable:"code",schema:[{type:"object",additionalProperties:!1,enableDangerousAutofixThisMayCauseInfiniteLoops:!1,properties:{additionalHooks:{type:"string"},enableDangerousAutofixThisMayCauseInfiniteLoops:{type:"boolean"}}}]},create:function(a){function c(c){
|
|
34
|
-
c.suggest[0].fix);a.report(c)}function e(a,c){return function(b){if(c.has(b))return c.get(b);var d=a(b);c.set(b,d);return d}}function h(d,b,h,
|
|
35
|
-
|
|
36
|
-
a.childScopes[Symbol.iterator](),
|
|
37
|
-
|
|
38
|
-
null
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
13
|
+
function ja(a){function c(){return{isUsed:!1,isSatisfiedRecursively:!1,isSubtreeUsed:!1,children:new Map}}function e(a,b){b=b.split(".");var m=!0,e=!1,f=void 0;try{for(var d=b[Symbol.iterator](),h;!(m=(h=d.next()).done);m=!0){var y=h.value,l=a.children.get(y);l||(l=c(),a.children.set(y,l));a=l}}catch(K){e=!0,f=K}finally{try{m||null==d.return||d.return()}finally{if(e)throw f;}}return a}function h(a,c,b){c=c.split(".");var m=!0,e=!1,f=void 0;try{for(var d=c[Symbol.iterator](),h;!(m=(h=d.next()).done);m=
|
|
14
|
+
!0){var l=a.children.get(h.value);if(!l)break;b(l);a=l}}catch(K){e=!0,f=K}finally{try{m||null==d.return||d.return()}finally{if(e)throw f;}}}function f(a,c,b,e){a.children.forEach(function(a,m){var d=e(m);a.isSatisfiedRecursively?a.isSubtreeUsed&&b.add(d):a.isUsed?c.add(d):f(a,c,b,function(a){return d+"."+a})})}var B=a.dependencies,k=a.declaredDependencies,q=a.stableDependencies,u=a.externalDependencies,v=a.isEffect,E=c();B.forEach(function(a,c){e(E,c).isUsed=!0;h(E,c,function(a){a.isSubtreeUsed=!0})});
|
|
15
|
+
k.forEach(function(a){e(E,a.key).isSatisfiedRecursively=!0});q.forEach(function(a){e(E,a).isSatisfiedRecursively=!0});a=new Set;var d=new Set;f(E,a,d,function(a){return a});var b=[],l=new Set,w=new Set;k.forEach(function(a){a=a.key;d.has(a)?-1===b.indexOf(a)?b.push(a):w.add(a):!v||a.endsWith(".current")||u.has(a)?l.add(a):-1===b.indexOf(a)&&b.push(a)});a.forEach(function(a){b.push(a)});return{suggestedDependencies:b,unnecessaryDependencies:l,duplicateDependencies:w,missingDependencies:a}}
|
|
16
|
+
function la(a){var c=a.declaredDependenciesNode,e=a.componentScope,h=a.scope;return a.declaredDependencies.map(function(a){a=e.set.get(a.key);if(null==a)return null;var c=a.defs[0];return null==c?null:"Variable"===c.type&&"VariableDeclarator"===c.node.type&&null!=c.node.init&&("ArrowFunctionExpression"===c.node.init.type||"FunctionExpression"===c.node.init.type)||"FunctionName"===c.type&&"FunctionDeclaration"===c.node.type?a:null}).filter(Boolean).map(function(a){var e=a.defs[0];a:{for(var f=!1,q=
|
|
17
|
+
0;q<a.references.length;q++){var u=a.references[q];if(u.writeExpr)if(f){a=!0;break a}else{f=!0;continue}for(var v=u.from;v!==h&&null!=v;)v=v.upper;if(v!==h&&!ma(c,u.identifier)){a=!0;break a}}a=!1}return{fn:e,suggestUseCallback:a}})}
|
|
18
|
+
function na(a){return"MemberExpression"!==a.parent.type&&"OptionalMemberExpression"!==a.parent.type||a.parent.object!==a||"current"===a.parent.property.name||a.parent.computed||null!=a.parent.parent&&("CallExpression"===a.parent.parent.type||"OptionalCallExpression"===a.parent.parent.type)&&a.parent.parent.callee===a.parent?"MemberExpression"===a.type&&a.parent&&"AssignmentExpression"===a.parent.type?a.object:a:na(a.parent)}
|
|
19
|
+
function W(a,c){if("Identifier"===a.type)return a=a.name,c&&c.set(a,!1),a;if("MemberExpression"!==a.type||a.computed){if("OptionalMemberExpression"!==a.type||a.computed)throw Error("Unsupported node type: "+a.type);var e=W(a.object,c),h=W(a.property,null);e=e+"."+h;c&&(a.optional?c.has(e)||c.set(e,!0):c.set(e,!1));return e}e=W(a.object,c);a=W(a.property,null);a=e+"."+a;c&&c.set(a,!1);return a}
|
|
20
|
+
function oa(a){return"MemberExpression"!==a.type||"Identifier"!==a.object.type||"React"!==a.object.name||"Identifier"!==a.property.type||a.computed?a:a.property}
|
|
21
|
+
function qa(a,c){var e=oa(a);if("Identifier"!==e.type)return-1;switch(e.name){case "useEffect":case "useLayoutEffect":case "useCallback":case "useMemo":return 0;case "useImperativeHandle":return 1;default:if(e===a&&c&&c.additionalHooks){try{var h=W(e,null)}catch(f){if(/Unsupported node type/.test(f.message))return 0;throw f;}return c.additionalHooks.test(h)?0:-1}return-1}}
|
|
22
|
+
function ra(a,c){for(var e=[a],h=null;e.length;){h=e.shift();if("Identifier"===h.type&&h.name===c.name&&h.range[0]===c.range[0]&&h.range[1]===c.range[1])return h;if(ma(h,c)){a=0;for(var f=Object.entries(h);a<f.length;a++){var B=f[a],k=B[1];"parent"!==B[0]&&(sa(k)?(k.parent=h,e.push(k)):Array.isArray(k)&&k.forEach(function(a){sa(a)&&(a.parent=h,e.push(a))}))}}}return null}
|
|
23
|
+
function ta(a){for(var c="",e=0;e<a.length;e++)c+=a[e],0===e&&2===a.length?c+=" and ":e===a.length-2&&2<a.length?c+=", and ":e<a.length-1&&(c+=", ");return c}function sa(a){return"object"===typeof a&&null!==a&&!Array.isArray(a)&&"string"===typeof a.type}function ma(a,c){return a.range[0]<=c.range[0]&&a.range[1]>=c.range[1]}exports.configs={recommended:{plugins:["react-hooks"],rules:{"react-hooks/rules-of-hooks":"error","react-hooks/exhaustive-deps":"warn"}}};
|
|
24
|
+
exports.rules={"rules-of-hooks":{meta:{type:"problem",docs:{description:"enforces the Rules of Hooks",category:"Possible Errors",recommended:!0,url:"https://reactjs.org/docs/hooks-rules.html"}},create:function(a){var c=[],e=[];return{onCodePathSegmentStart:function(a){return e.push(a)},onCodePathSegmentEnd:function(){return e.pop()},onCodePathStart:function(){return c.push(new Map)},onCodePathEnd:function(e,f){function h(a,c){var b=h.cache,d=b.get(a.id);c=new Set(c);if(c.has(a.id)){b=[].concat(c);
|
|
25
|
+
a=b.slice(b.indexOf(a.id)+1);b=!0;d=!1;var l=void 0;try{for(var f=a[Symbol.iterator](),g;!(b=(g=f.next()).done);b=!0)v.add(g.value)}catch(G){d=!0,l=G}finally{try{b||null==f.return||f.return()}finally{if(d)throw l;}}return 0}c.add(a.id);if(void 0!==d)return d;if(e.thrownSegments.includes(a))d=0;else if(0===a.prevSegments.length)d=1;else{d=0;f=!0;g=!1;var L=void 0;try{l=a.prevSegments[Symbol.iterator]();for(var M;!(f=(M=l.next()).done);f=!0)d+=h(M.value,c)}catch(G){g=!0,L=G}finally{try{f||null==l.return||
|
|
26
|
+
l.return()}finally{if(g)throw L;}}}a.reachable&&0===d?b.delete(a.id):b.set(a.id,d);return d}function k(a,c){var d=k.cache,b=d.get(a.id);c=new Set(c);if(c.has(a.id)){d=Array.from(c);a=d.slice(d.indexOf(a.id)+1);d=!0;b=!1;var f=void 0;try{for(var l=a[Symbol.iterator](),g;!(d=(g=l.next()).done);d=!0)v.add(g.value)}catch(G){b=!0,f=G}finally{try{d||null==l.return||l.return()}finally{if(b)throw f;}}return 0}c.add(a.id);if(void 0!==b)return b;if(e.thrownSegments.includes(a))b=0;else if(0===a.nextSegments.length)b=
|
|
27
|
+
1;else{b=0;l=!0;g=!1;var L=void 0;try{f=a.nextSegments[Symbol.iterator]();for(var M;!(l=(M=f.next()).done);l=!0)b+=k(M.value,c)}catch(G){g=!0,L=G}finally{try{l||null==f.return||f.return()}finally{if(g)throw L;}}}d.set(a.id,b);return b}function q(a){var c=q.cache,b=c.get(a.id);if(null===b)return Infinity;if(void 0!==b)return b;c.set(a.id,null);if(0===a.prevSegments.length)b=1;else{b=Infinity;var d=!0,e=!1,l=void 0;try{for(var g=a.prevSegments[Symbol.iterator](),L;!(d=(L=g.next()).done);d=!0){var M=
|
|
28
|
+
q(L.value);M<b&&(b=M)}}catch(G){e=!0,l=G}finally{try{d||null==g.return||g.return()}finally{if(e)throw l;}}b+=1}c.set(a.id,b);return b}var u=c.pop();if(0!==u.size){var v=new Set;h.cache=new Map;k.cache=new Map;q.cache=new Map;var E=k(e.initialSegment),d=ia(f),b=ha(f),l=d?aa(d)||O(d):ea(f)||fa(f),w=Infinity,m=!0,y=!1,J=void 0;try{for(var A=e.finalSegments[Symbol.iterator](),p;!(m=(p=A.next()).done);m=!0){var ka=p.value;if(ka.reachable){var z=q(ka);z<w&&(w=z)}}}catch(F){y=!0,J=F}finally{try{m||null==
|
|
29
|
+
A.return||A.return()}finally{if(y)throw J;}}m=!0;y=!1;J=void 0;try{for(var r=u[Symbol.iterator](),T;!(m=(T=r.next()).done);m=!0){var K=T.value,C=K[0],x=K[1];if(C.reachable){var Y=0===C.nextSegments.length?w<=q(C):w<q(C),V=h(C)*k(C),P=v.has(C.id);u=!0;A=!1;p=void 0;try{for(var H=x[Symbol.iterator](),N;!(u=(N=H.next()).done);u=!0){var n=N.value;P&&a.report({node:n,message:'React Hook "'+a.getSource(n)+'" may be executed more than once. Possibly because it is called in a loop. React Hooks must be called in the exact same order in every component render.'});
|
|
30
|
+
if(l){if(!P&&V!==E){var D='React Hook "'+a.getSource(n)+'" is called conditionally. React Hooks must be called in the exact same order in every component render.'+(Y?" Did you accidentally call a React Hook after an early return?":"");a.report({node:n,message:D})}}else if(f.parent&&("MethodDefinition"===f.parent.type||"ClassProperty"===f.parent.type)&&f.parent.value===f){var Z='React Hook "'+a.getSource(n)+'" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function.';
|
|
31
|
+
a.report({node:n,message:Z})}else if(d){var R='React Hook "'+a.getSource(n)+'" is called in function "'+(a.getSource(d)+'" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter.');a.report({node:n,message:R})}else if("Program"===f.type){var S='React Hook "'+a.getSource(n)+'" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function.';a.report({node:n,message:S})}else if(b){var I=
|
|
32
|
+
'React Hook "'+a.getSource(n)+'" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.';a.report({node:n,message:I})}}}catch(F){A=!0,p=F}finally{try{u||null==H.return||H.return()}finally{if(A)throw p;}}}}}catch(F){y=!0,J=F}finally{try{m||null==r.return||r.return()}finally{if(y)throw J;}}}},CallExpression:function(a){if(O(a.callee)){var f=c[c.length-1],h=e[e.length-1],k=f.get(h);k||(k=[],f.set(h,k));k.push(a.callee)}}}}},"exhaustive-deps":{meta:{type:"suggestion",
|
|
33
|
+
docs:{description:"verifies the list of dependencies for Hooks like useEffect and similar",category:"Best Practices",recommended:!0,url:"https://github.com/facebook/react/issues/14920"},fixable:"code",schema:[{type:"object",additionalProperties:!1,enableDangerousAutofixThisMayCauseInfiniteLoops:!1,properties:{additionalHooks:{type:"string"},enableDangerousAutofixThisMayCauseInfiniteLoops:{type:"boolean"}}}]},create:function(a){function c(c){f&&Array.isArray(c.suggest)&&0<c.suggest.length&&(c.fix=
|
|
34
|
+
c.suggest[0].fix);a.report(c)}function e(a,c){return function(b){if(c.has(b))return c.get(b);var d=a(b);c.set(b,d);return d}}function h(d,b,f,h,m){function l(a){var c=!0,g=!1,b=void 0;try{for(var f=a.references[Symbol.iterator](),e;!(c=(e=f.next()).done);c=!0){var h=e.value;if(h.resolved&&B.has(h.resolved.scope)){var n=ra(d,h.identifier),k=na(n),w=W(k,Y),y;if(y=m&&"Identifier"===k.type&&("MemberExpression"===k.parent.type||"OptionalMemberExpression"===k.parent.type)&&!k.parent.computed&&"Identifier"===
|
|
35
|
+
k.parent.property.type&&"current"===k.parent.property.name){for(var p=h.from,r=!1;p.block!==d;)"function"===p.type&&(r=null!=p.block.parent&&"ReturnStatement"===p.block.parent.type),p=p.upper;y=r}y&&C.set(w,{reference:h,dependencyNode:k});var q=h.resolved.defs[0];if(null!=q&&(null==q.node||q.node.init!==d.parent)&&"TypeParameter"!==q.type)if(x.has(w))x.get(w).references.push(h);else{var t=h.resolved,u=T(t)||K(t);x.set(w,{isStable:u,references:[h]})}}}}catch(da){g=!0,b=da}finally{try{c||null==f.return||
|
|
36
|
+
f.return()}finally{if(g)throw b;}}c=!0;g=!1;b=void 0;try{for(var v=a.childScopes[Symbol.iterator](),J;!(c=(J=v.next()).done);c=!0)l(J.value)}catch(da){g=!0,b=da}finally{try{c||null==v.return||v.return()}finally{if(g)throw b;}}}function w(a){a=a.split(".");for(var c="",g=0;g<a.length;g++){if(0!==g){var b=a.slice(0,g+1).join(".");b=!0===Y.get(b);c+=b?"?.":"."}c+=a[g]}return c}function A(a,c,b,d){return 0===a.size?null:(1<a.size?"":c+" ")+b+" "+(1<a.size?"dependencies":"dependency")+": "+ta(Array.from(a).sort().map(function(a){return"'"+
|
|
37
|
+
w(a)+"'"}))+(". Either "+d+" "+(1<a.size?"them":"it")+" or remove the dependency array.")}m&&d.async&&c({node:d,message:"Effect callbacks are synchronous to prevent race conditions. Put the async function inside:\n\nuseEffect(() => {\n async function fetchData() {\n // You can await here\n const response = await MyAPI.getData(someId);\n // ...\n }\n fetchData();\n}, [someId]); // Or [] if effect doesn't need props or state\n\nLearn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching"});
|
|
38
|
+
for(var p=k.acquire(d),B=new Set,z=null,r=p.upper;r;){B.add(r);if("function"===r.type)break;r=r.upper}if(r){z=r;var T=e(function(a){if(!Array.isArray(a.defs))return!1;var c=a.defs[0];if(null==c||"VariableDeclarator"!==c.node.type)return!1;var b=c.node.init;if(null==b)return!1;for(;"TSAsExpression"===b.type;)b=b.expression;var g=c.node.parent;if(null==g&&(ra(z.block,c.node.id),g=c.node.parent,null==g))return!1;if("const"===g.kind&&"Literal"===b.type&&("string"===typeof b.value||"number"===typeof b.value||
|
|
39
|
+
null===b.value))return!0;if("CallExpression"!==b.type)return!1;b=b.callee;"MemberExpression"!==b.type||"React"!==b.object.name||null==b.property||b.computed||(b=b.property);if("Identifier"!==b.type)return!1;c=c.node.id;b=b.name;if("useRef"===b&&"Identifier"===c.type)return!0;if(("useState"===b||"useReducer"===b)&&"ArrayPattern"===c.type&&2===c.elements.length&&Array.isArray(a.identifiers)){if(c.elements[1]===a.identifiers[0]){if("useState"===b)for(a=a.references,b=0;b<a.length;b++)q.set(a[b].identifier,
|
|
40
|
+
c.elements[0]);return!0}if(c.elements[0]===a.identifiers[0]&&"useState"===b)for(a=a.references,c=0;c<a.length;c++)u.add(a[c].identifier)}return!1},v),K=e(function(a){if(!Array.isArray(a.defs))return!1;a=a.defs[0];if(null==a||null==a.node||null==a.node.id)return!1;var c=a.node,b=z.childScopes;a=null;var g;for(g=0;g<b.length;g++){var d=b[g],f=d.block;if("FunctionDeclaration"===c.type&&f===c||"VariableDeclarator"===c.type&&f.parent===c){a=d;break}}if(null==a)return!1;for(g=0;g<a.through.length;g++)if(c=
|
|
41
|
+
a.through[g],null!=c.resolved&&B.has(c.resolved.scope)&&!T(c.resolved))return!1;return!0},E),C=new Map,x=new Map,Y=new Map;l(p);C.forEach(function(a,b){var g=a.dependencyNode;a=a.reference.resolved.references;for(var d=!1,f=0;f<a.length;f++){var e=a[f].identifier.parent;if(null!=e&&"MemberExpression"===e.type&&!e.computed&&"Identifier"===e.property.type&&"current"===e.property.name&&"AssignmentExpression"===e.parent.type&&e.parent.left===e){d=!0;break}}d||c({node:g.parent.property,message:"The ref value '"+
|
|
42
|
+
b+".current' will likely have changed by the time this effect cleanup function runs. If this ref points to a node rendered by React, copy '"+(b+".current' to a variable inside the effect, and use that variable in the cleanup function.")})});var V=new Set,P=new Set;x.forEach(function(b,d){var g=b.references;b.isStable&&P.add(d);g.forEach(function(b){b.writeExpr&&(b=b.writeExpr,V.has(d)||(V.add(d),c({node:b,message:"Assignments to the '"+d+"' variable from inside React Hook "+(a.getSource(f)+" will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside ")+
|
|
43
|
+
(a.getSource(f)+".")})))})});if(!(0<V.size))if(b){var H=[],N=new Set;"ArrayExpression"!==b.type?c({node:b,message:"React Hook "+a.getSource(f)+" was passed a dependency list that is not an array literal. This means we can't statically verify whether you've passed the correct dependencies."}):b.elements.forEach(function(b){if(null!==b)if("SpreadElement"===b.type)c({node:b,message:"React Hook "+a.getSource(f)+" has a spread element in its dependency array. This means we can't statically verify whether you've passed the correct dependencies."});
|
|
44
|
+
else{try{var d=W(b,null)}catch(pa){if(/Unsupported node type/.test(pa.message)){"Literal"===b.type?x.has(b.value)?c({node:b,message:"The "+b.raw+" literal is not a valid dependency because it never changes. Did you mean to include "+(b.value+" in the array instead?")}):c({node:b,message:"The "+b.raw+" literal is not a valid dependency because it never changes. You can safely remove it."}):c({node:b,message:"React Hook "+a.getSource(f)+" has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked."});
|
|
45
|
+
return}throw pa;}for(var g=b;"MemberExpression"===g.type||"OptionalMemberExpression"===g.type;)g=g.object;var e=!z.through.some(function(a){return a.identifier===g});H.push({key:d,node:b});e||N.add(d)}});var n=ja({dependencies:x,declaredDependencies:H,stableDependencies:P,externalDependencies:N,isEffect:m});r=n.unnecessaryDependencies;var D=n.missingDependencies,Z=n.duplicateDependencies,R=n.suggestedDependencies;if(0===Z.size+D.size+r.size)la({declaredDependencies:H,declaredDependenciesNode:b,componentScope:z,
|
|
46
|
+
scope:p}).forEach(function(a){var d=a.fn;a=a.suggestUseCallback;var g="The '"+d.name.name+"' function makes the dependencies of "+(h+" Hook (at line "+b.loc.start.line+") change on every render.");g=a?g+(" To fix this, wrap the '"+(d.name.name+"' definition into its own useCallback() Hook.")):g+(" Move it inside the "+h+" callback. Alternatively, wrap the '"+(d.name.name+"' definition into its own useCallback() Hook."));var e;a&&"Variable"===d.type&&(e=[{desc:"Wrap the '"+d.name.name+"' definition into its own useCallback() Hook.",
|
|
47
|
+
fix:function(a){return[a.insertTextBefore(d.node.init,"useCallback("),a.insertTextAfter(d.node.init,")")]}}]);c({node:d.node,message:g,suggest:e})});else{!m&&0<D.size&&(R=ja({dependencies:x,declaredDependencies:[],stableDependencies:P,externalDependencies:N,isEffect:m}).suggestedDependencies);(function(){if(0===H.length)return!0;var a=H.map(function(a){return a.key}),b=a.slice().sort();return a.join(",")===b.join(",")})()&&R.sort();n="";if(0<r.size){var S=null;Array.from(r.keys()).forEach(function(a){null===
|
|
48
|
+
S&&a.endsWith(".current")&&(S=a)});if(null!==S)n=" Mutable values like '"+S+"' aren't valid dependencies because mutating them doesn't re-render the component.";else if(0<N.size){var I=Array.from(N)[0];p.set.has(I)||(n=" Outer scope values like '"+I+"' aren't valid dependencies because mutating them doesn't re-render the component.")}}if(!n&&D.has("props")){p=x.get("props");if(null==p)return;p=p.references;if(!Array.isArray(p))return;I=!0;for(var F=0;F<p.length;F++){var Q=ra(z.block,p[F].identifier);
|
|
49
|
+
if(!Q){I=!1;break}Q=Q.parent;if(null==Q){I=!1;break}if("MemberExpression"!==Q.type&&"OptionalMemberExpression"!==Q.type){I=!1;break}}I&&(n=" However, 'props' will change when *any* prop changes, so the preferred fix is to destructure the 'props' object outside of the "+(h+" call and refer to those specific props inside ")+(a.getSource(f)+"."))}if(!n&&0<D.size){var X=null;D.forEach(function(a){if(!X){var b=z.set.get(a),c=x.get(a);if(c.references[0].resolved===b&&(b=b.defs[0],null!=b&&null!=b.name&&
|
|
50
|
+
"Parameter"===b.type)){b=!1;for(var d,e=0;e<c.references.length;e++)if(d=c.references[e].identifier,null!=d&&null!=d.parent&&("CallExpression"===d.parent.type||"OptionalCallExpression"===d.parent.type)&&d.parent.callee===d){b=!0;break}b&&(X=a)}}});null!==X&&(n=" If '"+X+"' changes too often, find the parent component that defines it and wrap that definition in useCallback.")}if(!n&&0<D.size){var t=null;D.forEach(function(a){if(null===t)for(var b=x.get(a).references,c,d,e=0;e<b.length;e++){c=b[e].identifier;
|
|
51
|
+
for(d=c.parent;null!=d&&d!==z.block;){if("CallExpression"===d.type){var f=q.get(d.callee);if(null!=f){f.name===a?t={missingDep:a,setter:d.callee.name,form:"updater"}:u.has(c)?t={missingDep:a,setter:d.callee.name,form:"reducer"}:(c=b[e].resolved,null!=c&&(c=c.defs[0],null!=c&&"Parameter"===c.type&&(t={missingDep:a,setter:d.callee.name,form:"inlineReducer"})));break}}d=d.parent}if(null!==t)break}});if(null!==t)switch(t.form){case "reducer":n=" You can also replace multiple useState variables with useReducer if '"+
|
|
52
|
+
(t.setter+"' needs the current value of '")+(t.missingDep+"'.");break;case "inlineReducer":n=" If '"+t.setter+"' needs the current value of '"+(t.missingDep+"', you can also switch to useReducer instead of useState and read '")+(t.missingDep+"' in the reducer.");break;case "updater":n=" You can also do a functional update '"+t.setter+"("+t.missingDep.substring(0,1)+" => ...)' if you only need '"+t.missingDep+"' in the '"+(t.setter+"' call.");break;default:throw Error("Unknown case.");}}c({node:b,
|
|
53
|
+
message:"React Hook "+a.getSource(f)+" has "+(A(D,"a","missing","include")||A(r,"an","unnecessary","exclude")||A(Z,"a","duplicate","omit"))+n,suggest:[{desc:"Update the dependencies array to be: ["+R.map(w).join(", ")+"]",fix:function(a){return a.replaceText(b,"["+R.map(w).join(", ")+"]")}}]})}}else{var U=null;x.forEach(function(a,b){U||a.references.forEach(function(a){if(!U&&q.has(a.identifier)){for(a=a.from;"function"!==a.type;)a=a.upper;a.block===d&&(U=b)}})});if(U){var ca=ja({dependencies:x,declaredDependencies:[],
|
|
54
|
+
stableDependencies:P,externalDependencies:new Set,isEffect:!0}).suggestedDependencies;c({node:f,message:"React Hook "+h+" contains a call to '"+U+"'. Without a list of dependencies, this can lead to an infinite chain of updates. To fix this, pass ["+ca.join(", ")+("] as a second argument to the "+h+" Hook."),suggest:[{desc:"Add dependencies array: ["+ca.join(", ")+"]",fix:function(a){return a.insertTextAfter(d,", ["+ca.join(", ")+"]")}}]})}}}}var f=a.options&&a.options[0]&&a.options[0].enableDangerousAutofixThisMayCauseInfiniteLoops||
|
|
55
|
+
!1,B={additionalHooks:a.options&&a.options[0]&&a.options[0].additionalHooks?new RegExp(a.options[0].additionalHooks):void 0,enableDangerousAutofixThisMayCauseInfiniteLoops:f},k=a.getSourceCode().scopeManager,q=new WeakMap,u=new WeakSet,v=new WeakMap,E=new WeakMap;return{CallExpression:function(d){var b=qa(d.callee,B);if(-1!==b){var e=d.arguments[b],f=d.callee,m=oa(f).name,k=d.arguments[b+1];d=/Effect($|[^a-z])/g.test(m);if(k||d){switch(e.type){case "FunctionExpression":case "ArrowFunctionExpression":h(e,
|
|
56
|
+
k,f,m,d);return;case "Identifier":if(!k||k.elements&&k.elements.some(function(a){return a&&"Identifier"===a.type&&a.name===e.name}))return;b=a.getScope().set.get(e.name);if(null==b||null==b.defs)return;b=b.defs[0];if(!b||!b.node)break;if("Variable"!==b.type&&"FunctionName"!==b.type)break;switch(b.node.type){case "FunctionDeclaration":h(b.node,k,f,m,d);return;case "VariableDeclarator":if(b=b.node.init)switch(b.type){case "ArrowFunctionExpression":case "FunctionExpression":h(b,k,f,m,d);return}}break;
|
|
57
|
+
default:c({node:f,message:"React Hook "+m+" received a function whose dependencies are unknown. Pass an inline function instead."});return}c({node:f,message:"React Hook "+m+" has a missing dependency: '"+e.name+"'. Either include it or remove the dependency array.",suggest:[{desc:"Update the dependencies array to be: ["+e.name+"]",fix:function(a){return a.replaceText(k,"["+e.name+"]")}}]})}else"useMemo"!==m&&"useCallback"!==m||c({node:f,message:"React Hook "+m+" does nothing when called with only one argument. Did you forget to pass an array of dependencies?"})}}}}}};
|