eslint-plugin-react-hooks 1.5.0-beta.0 → 1.6.0
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.
|
@@ -760,17 +760,25 @@ var ExhaustiveDeps = {
|
|
|
760
760
|
// So no need to check for dependency inclusion.
|
|
761
761
|
var depsIndex = callbackIndex + 1;
|
|
762
762
|
var declaredDependenciesNode = node.parent.arguments[depsIndex];
|
|
763
|
-
if (!declaredDependenciesNode) {
|
|
763
|
+
if (!declaredDependenciesNode && !isEffect) {
|
|
764
764
|
// These are only used for optimization.
|
|
765
765
|
if (reactiveHookName === 'useMemo' || reactiveHookName === 'useCallback') {
|
|
766
|
+
// TODO: Can this have an autofix?
|
|
766
767
|
context.report({
|
|
767
768
|
node: node.parent.callee,
|
|
768
|
-
message: 'React Hook ' + reactiveHookName + '
|
|
769
|
+
message: 'React Hook ' + reactiveHookName + ' does nothing when called with ' + 'only one argument. Did you forget to pass an array of ' + 'dependencies?'
|
|
769
770
|
});
|
|
770
771
|
}
|
|
771
772
|
return;
|
|
772
773
|
}
|
|
773
774
|
|
|
775
|
+
if (isEffect && node.async) {
|
|
776
|
+
context.report({
|
|
777
|
+
node: node,
|
|
778
|
+
message: 'Effect callbacks are synchronous to prevent race conditions. ' + 'Put the async function inside:\n\n' + 'useEffect(() => {\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\n' + 'Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching'
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
|
|
774
782
|
// Get the current scope.
|
|
775
783
|
var scope = context.getScope();
|
|
776
784
|
|
|
@@ -1014,6 +1022,12 @@ var ExhaustiveDeps = {
|
|
|
1014
1022
|
});
|
|
1015
1023
|
}
|
|
1016
1024
|
|
|
1025
|
+
// Ignore references to the function itself as it's not defined yet.
|
|
1026
|
+
var def = reference.resolved.defs[0];
|
|
1027
|
+
if (def != null && def.node != null && def.node.init === node.parent) {
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1017
1031
|
// Add the dependency to a map so we can make sure it is referenced
|
|
1018
1032
|
// again in our dependencies array. Remember whether it's static.
|
|
1019
1033
|
if (!dependencies.has(dependency)) {
|
|
@@ -1096,10 +1110,99 @@ var ExhaustiveDeps = {
|
|
|
1096
1110
|
}
|
|
1097
1111
|
context.report({
|
|
1098
1112
|
node: dependencyNode.parent.property,
|
|
1099
|
-
message: '
|
|
1113
|
+
message: 'The ref value \'' + dependency + '.current\' will likely have ' + 'changed by the time this effect cleanup function runs. If ' + 'this ref points to a node rendered by React, copy ' + ('\'' + dependency + '.current\' to a variable inside the effect, and ') + 'use that variable in the cleanup function.'
|
|
1114
|
+
});
|
|
1115
|
+
});
|
|
1116
|
+
|
|
1117
|
+
// Warn about assigning to variables in the outer scope.
|
|
1118
|
+
// Those are usually bugs.
|
|
1119
|
+
var staleAssignments = new Set();
|
|
1120
|
+
function reportStaleAssignment(writeExpr, key) {
|
|
1121
|
+
if (staleAssignments.has(key)) {
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
staleAssignments.add(key);
|
|
1125
|
+
context.report({
|
|
1126
|
+
node: writeExpr,
|
|
1127
|
+
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) + '.')
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// Remember which deps are optional and report bad usage first.
|
|
1132
|
+
var optionalDependencies = new Set();
|
|
1133
|
+
dependencies.forEach(function (_ref2, key) {
|
|
1134
|
+
var isStatic = _ref2.isStatic,
|
|
1135
|
+
references = _ref2.references;
|
|
1136
|
+
|
|
1137
|
+
if (isStatic) {
|
|
1138
|
+
optionalDependencies.add(key);
|
|
1139
|
+
}
|
|
1140
|
+
references.forEach(function (reference) {
|
|
1141
|
+
if (reference.writeExpr) {
|
|
1142
|
+
reportStaleAssignment(reference.writeExpr, key);
|
|
1143
|
+
}
|
|
1100
1144
|
});
|
|
1101
1145
|
});
|
|
1102
1146
|
|
|
1147
|
+
if (staleAssignments.size > 0) {
|
|
1148
|
+
// The intent isn't clear so we'll wait until you fix those first.
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
if (!declaredDependenciesNode) {
|
|
1153
|
+
// Check if there are any top-level setState() calls.
|
|
1154
|
+
// Those tend to lead to infinite loops.
|
|
1155
|
+
var setStateInsideEffectWithoutDeps = null;
|
|
1156
|
+
dependencies.forEach(function (_ref3, key) {
|
|
1157
|
+
var isStatic = _ref3.isStatic,
|
|
1158
|
+
references = _ref3.references;
|
|
1159
|
+
|
|
1160
|
+
if (setStateInsideEffectWithoutDeps) {
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
references.forEach(function (reference) {
|
|
1164
|
+
if (setStateInsideEffectWithoutDeps) {
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
var id = reference.identifier;
|
|
1169
|
+
var isSetState = setStateCallSites.has(id);
|
|
1170
|
+
if (!isSetState) {
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
var fnScope = reference.from;
|
|
1175
|
+
while (fnScope.type !== 'function') {
|
|
1176
|
+
fnScope = fnScope.upper;
|
|
1177
|
+
}
|
|
1178
|
+
var isDirectlyInsideEffect = fnScope.block === node;
|
|
1179
|
+
if (isDirectlyInsideEffect) {
|
|
1180
|
+
// TODO: we could potentially ignore early returns.
|
|
1181
|
+
setStateInsideEffectWithoutDeps = key;
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
});
|
|
1185
|
+
if (setStateInsideEffectWithoutDeps) {
|
|
1186
|
+
var _collectRecommendatio = collectRecommendations({
|
|
1187
|
+
dependencies: dependencies,
|
|
1188
|
+
declaredDependencies: [],
|
|
1189
|
+
optionalDependencies: optionalDependencies,
|
|
1190
|
+
externalDependencies: new Set(),
|
|
1191
|
+
isEffect: true
|
|
1192
|
+
}),
|
|
1193
|
+
_suggestedDependencies = _collectRecommendatio.suggestedDependencies;
|
|
1194
|
+
|
|
1195
|
+
context.report({
|
|
1196
|
+
node: node.parent.callee,
|
|
1197
|
+
message: 'React Hook ' + reactiveHookName + ' contains a call to \'' + setStateInsideEffectWithoutDeps + '\'. ' + 'Without a list of dependencies, this can lead to an infinite chain of updates. ' + 'To fix this, pass [' + _suggestedDependencies.join(', ') + ('] as a second argument to the ' + reactiveHookName + ' Hook.'),
|
|
1198
|
+
fix: function (fixer) {
|
|
1199
|
+
return fixer.insertTextAfter(node, ', [' + _suggestedDependencies.join(', ') + ']');
|
|
1200
|
+
}
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1103
1206
|
var declaredDependencies = [];
|
|
1104
1207
|
var externalDependencies = new Set();
|
|
1105
1208
|
if (declaredDependenciesNode.type !== 'ArrayExpression') {
|
|
@@ -1108,7 +1211,7 @@ var ExhaustiveDeps = {
|
|
|
1108
1211
|
// the user this in an error.
|
|
1109
1212
|
context.report({
|
|
1110
1213
|
node: declaredDependenciesNode,
|
|
1111
|
-
message: 'React Hook ' + context.getSource(reactiveHook) + '
|
|
1214
|
+
message: 'React Hook ' + context.getSource(reactiveHook) + ' 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.'
|
|
1112
1215
|
});
|
|
1113
1216
|
} else {
|
|
1114
1217
|
declaredDependenciesNode.elements.forEach(function (declaredDependencyNode) {
|
|
@@ -1132,15 +1235,15 @@ var ExhaustiveDeps = {
|
|
|
1132
1235
|
} catch (error) {
|
|
1133
1236
|
if (/Unsupported node type/.test(error.message)) {
|
|
1134
1237
|
if (declaredDependencyNode.type === 'Literal') {
|
|
1135
|
-
if (
|
|
1238
|
+
if (dependencies.has(declaredDependencyNode.value)) {
|
|
1136
1239
|
context.report({
|
|
1137
1240
|
node: declaredDependencyNode,
|
|
1138
|
-
message: 'The ' + declaredDependencyNode.raw + '
|
|
1241
|
+
message: 'The ' + declaredDependencyNode.raw + ' literal is not a valid dependency ' + 'because it never changes. ' + ('Did you mean to include ' + declaredDependencyNode.value + ' in the array instead?')
|
|
1139
1242
|
});
|
|
1140
1243
|
} else {
|
|
1141
1244
|
context.report({
|
|
1142
1245
|
node: declaredDependencyNode,
|
|
1143
|
-
message: 'The
|
|
1246
|
+
message: 'The ' + declaredDependencyNode.raw + ' literal is not a valid dependency ' + 'because it never changes. You can safely remove it.'
|
|
1144
1247
|
});
|
|
1145
1248
|
}
|
|
1146
1249
|
} else {
|
|
@@ -1176,51 +1279,17 @@ var ExhaustiveDeps = {
|
|
|
1176
1279
|
});
|
|
1177
1280
|
}
|
|
1178
1281
|
|
|
1179
|
-
|
|
1180
|
-
// Those are usually bugs.
|
|
1181
|
-
var staleAssignments = new Set();
|
|
1182
|
-
function reportStaleAssignment(writeExpr, key) {
|
|
1183
|
-
if (staleAssignments.has(key)) {
|
|
1184
|
-
return;
|
|
1185
|
-
}
|
|
1186
|
-
staleAssignments.add(key);
|
|
1187
|
-
context.report({
|
|
1188
|
-
node: writeExpr,
|
|
1189
|
-
message: 'Assignments to the \'' + key + '\' variable from inside a React ' + context.getSource(reactiveHook) + ' Hook ' + 'will not persist between re-renders. ' + 'If it\'s only needed by this Hook, move the variable inside it. ' + 'Alternatively, declare a ref with the useRef Hook, ' + 'and keep the mutable value in its \'current\' property.'
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
// Remember which deps are optional and report bad usage first.
|
|
1194
|
-
var optionalDependencies = new Set();
|
|
1195
|
-
dependencies.forEach(function (_ref2, key) {
|
|
1196
|
-
var isStatic = _ref2.isStatic,
|
|
1197
|
-
references = _ref2.references;
|
|
1198
|
-
|
|
1199
|
-
if (isStatic) {
|
|
1200
|
-
optionalDependencies.add(key);
|
|
1201
|
-
}
|
|
1202
|
-
references.forEach(function (reference) {
|
|
1203
|
-
if (reference.writeExpr) {
|
|
1204
|
-
reportStaleAssignment(reference.writeExpr, key);
|
|
1205
|
-
}
|
|
1206
|
-
});
|
|
1207
|
-
});
|
|
1208
|
-
if (staleAssignments.size > 0) {
|
|
1209
|
-
// The intent isn't clear so we'll wait until you fix those first.
|
|
1210
|
-
return;
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
var _collectRecommendatio = collectRecommendations({
|
|
1282
|
+
var _collectRecommendatio2 = collectRecommendations({
|
|
1214
1283
|
dependencies: dependencies,
|
|
1215
1284
|
declaredDependencies: declaredDependencies,
|
|
1216
1285
|
optionalDependencies: optionalDependencies,
|
|
1217
1286
|
externalDependencies: externalDependencies,
|
|
1218
1287
|
isEffect: isEffect
|
|
1219
1288
|
}),
|
|
1220
|
-
suggestedDependencies =
|
|
1221
|
-
unnecessaryDependencies =
|
|
1222
|
-
missingDependencies =
|
|
1223
|
-
duplicateDependencies =
|
|
1289
|
+
suggestedDependencies = _collectRecommendatio2.suggestedDependencies,
|
|
1290
|
+
unnecessaryDependencies = _collectRecommendatio2.unnecessaryDependencies,
|
|
1291
|
+
missingDependencies = _collectRecommendatio2.missingDependencies,
|
|
1292
|
+
duplicateDependencies = _collectRecommendatio2.duplicateDependencies;
|
|
1224
1293
|
|
|
1225
1294
|
var problemCount = duplicateDependencies.size + missingDependencies.size + unnecessaryDependencies.size;
|
|
1226
1295
|
|
|
@@ -1233,17 +1302,20 @@ var ExhaustiveDeps = {
|
|
|
1233
1302
|
componentScope: componentScope,
|
|
1234
1303
|
scope: scope
|
|
1235
1304
|
});
|
|
1236
|
-
bareFunctions.forEach(function (
|
|
1237
|
-
var fn =
|
|
1238
|
-
suggestUseCallback =
|
|
1305
|
+
bareFunctions.forEach(function (_ref4) {
|
|
1306
|
+
var fn = _ref4.fn,
|
|
1307
|
+
suggestUseCallback = _ref4.suggestUseCallback;
|
|
1239
1308
|
|
|
1240
1309
|
var message = 'The \'' + fn.name.name + '\' function makes the dependencies of ' + (reactiveHookName + ' Hook (at line ' + declaredDependenciesNode.loc.start.line + ') ') + 'change on every render.';
|
|
1241
1310
|
if (suggestUseCallback) {
|
|
1242
1311
|
message += ' To fix this, ' + ('wrap the \'' + fn.name.name + '\' definition into its own useCallback() Hook.');
|
|
1243
1312
|
} else {
|
|
1244
|
-
message += '
|
|
1313
|
+
message += ' Move it inside the ' + reactiveHookName + ' callback. ' + ('Alternatively, wrap the \'' + fn.name.name + '\' definition into its own useCallback() Hook.');
|
|
1245
1314
|
}
|
|
1315
|
+
// TODO: What if the function needs to change on every render anyway?
|
|
1316
|
+
// Should we suggest removing effect deps as an appropriate fix too?
|
|
1246
1317
|
context.report({
|
|
1318
|
+
// TODO: Why not report this at the dependency site?
|
|
1247
1319
|
node: fn.node,
|
|
1248
1320
|
message: message,
|
|
1249
1321
|
fix: function (fixer) {
|
|
@@ -1253,10 +1325,10 @@ var ExhaustiveDeps = {
|
|
|
1253
1325
|
return [
|
|
1254
1326
|
// TODO: also add an import?
|
|
1255
1327
|
fixer.insertTextBefore(fn.node.init, 'useCallback('),
|
|
1256
|
-
// TODO: ideally we'd gather deps here but it would
|
|
1257
|
-
//
|
|
1258
|
-
//
|
|
1259
|
-
// [] because that changes semantics.
|
|
1328
|
+
// TODO: ideally we'd gather deps here but it would require
|
|
1329
|
+
// restructuring the rule code. This will cause a new lint
|
|
1330
|
+
// error to appear immediately for useCallback. Note we're
|
|
1331
|
+
// not adding [] because would that changes semantics.
|
|
1260
1332
|
fixer.insertTextAfter(fn.node.init, ')')];
|
|
1261
1333
|
}
|
|
1262
1334
|
}
|
|
@@ -1317,10 +1389,14 @@ var ExhaustiveDeps = {
|
|
|
1317
1389
|
}
|
|
1318
1390
|
});
|
|
1319
1391
|
if (badRef !== null) {
|
|
1320
|
-
extraWarning = ' Mutable values like \'' + badRef + '\' aren\'t valid dependencies ' + "because
|
|
1392
|
+
extraWarning = ' Mutable values like \'' + badRef + '\' aren\'t valid dependencies ' + "because mutating them doesn't re-render the component.";
|
|
1321
1393
|
} else if (externalDependencies.size > 0) {
|
|
1322
1394
|
var dep = Array.from(externalDependencies)[0];
|
|
1323
|
-
|
|
1395
|
+
// Don't show this warning for things that likely just got moved *inside* the callback
|
|
1396
|
+
// because in that case they're clearly not referring to globals.
|
|
1397
|
+
if (!scope.set.has(dep)) {
|
|
1398
|
+
extraWarning = ' Outer scope values like \'' + dep + '\' aren\'t valid dependencies ' + 'because mutating them doesn\'t re-render the component.';
|
|
1399
|
+
}
|
|
1324
1400
|
}
|
|
1325
1401
|
}
|
|
1326
1402
|
|
|
@@ -1355,7 +1431,7 @@ var ExhaustiveDeps = {
|
|
|
1355
1431
|
}
|
|
1356
1432
|
}
|
|
1357
1433
|
if (isPropsOnlyUsedInMembers) {
|
|
1358
|
-
extraWarning = ' However, the preferred fix is to destructure the \'props\' ' + ('
|
|
1434
|
+
extraWarning = ' However, \'props\' will change when *any* prop changes, so the ' + 'preferred fix is to destructure the \'props\' object outside of ' + ('the ' + reactiveHookName + ' call and refer to those specific props ') + ('inside ' + context.getSource(reactiveHook) + '.');
|
|
1359
1435
|
}
|
|
1360
1436
|
}
|
|
1361
1437
|
|
|
@@ -1397,7 +1473,7 @@ var ExhaustiveDeps = {
|
|
|
1397
1473
|
missingCallbackDep = missingDep;
|
|
1398
1474
|
});
|
|
1399
1475
|
if (missingCallbackDep !== null) {
|
|
1400
|
-
extraWarning = ' If
|
|
1476
|
+
extraWarning = ' If \'' + missingCallbackDep + '\' changes too often, ' + 'find the parent component that defines it ' + 'and wrap that definition in useCallback.';
|
|
1401
1477
|
}
|
|
1402
1478
|
}
|
|
1403
1479
|
|
|
@@ -1460,21 +1536,19 @@ var ExhaustiveDeps = {
|
|
|
1460
1536
|
}
|
|
1461
1537
|
});
|
|
1462
1538
|
if (setStateRecommendation !== null) {
|
|
1463
|
-
var suggestion = void 0;
|
|
1464
1539
|
switch (setStateRecommendation.form) {
|
|
1465
1540
|
case 'reducer':
|
|
1466
|
-
|
|
1541
|
+
extraWarning = ' You can also replace multiple useState variables with useReducer ' + ('if \'' + setStateRecommendation.setter + '\' needs the ') + ('current value of \'' + setStateRecommendation.missingDep + '\'.');
|
|
1467
1542
|
break;
|
|
1468
1543
|
case 'inlineReducer':
|
|
1469
|
-
|
|
1544
|
+
extraWarning = ' If \'' + setStateRecommendation.setter + '\' needs the ' + ('current value of \'' + setStateRecommendation.missingDep + '\', ') + 'you can also switch to useReducer instead of useState and ' + ('read \'' + setStateRecommendation.missingDep + '\' in the reducer.');
|
|
1470
1545
|
break;
|
|
1471
1546
|
case 'updater':
|
|
1472
|
-
|
|
1547
|
+
extraWarning = ' You can also do a functional update \'' + setStateRecommendation.setter + '(' + setStateRecommendation.missingDep.substring(0, 1) + ' => ...)\' if you only need \'' + setStateRecommendation.missingDep + '\'' + (' in the \'' + setStateRecommendation.setter + '\' call.');
|
|
1473
1548
|
break;
|
|
1474
1549
|
default:
|
|
1475
1550
|
throw new Error('Unknown case.');
|
|
1476
1551
|
}
|
|
1477
|
-
extraWarning = ' If \'' + setStateRecommendation.missingDep + '\'' + ' is only necessary for calculating the next state, ' + ('consider refactoring to the ' + suggestion);
|
|
1478
1552
|
}
|
|
1479
1553
|
}
|
|
1480
1554
|
|
|
@@ -1493,12 +1567,12 @@ var ExhaustiveDeps = {
|
|
|
1493
1567
|
};
|
|
1494
1568
|
|
|
1495
1569
|
// The meat of the logic.
|
|
1496
|
-
function collectRecommendations(
|
|
1497
|
-
var dependencies =
|
|
1498
|
-
declaredDependencies =
|
|
1499
|
-
optionalDependencies =
|
|
1500
|
-
externalDependencies =
|
|
1501
|
-
isEffect =
|
|
1570
|
+
function collectRecommendations(_ref5) {
|
|
1571
|
+
var dependencies = _ref5.dependencies,
|
|
1572
|
+
declaredDependencies = _ref5.declaredDependencies,
|
|
1573
|
+
optionalDependencies = _ref5.optionalDependencies,
|
|
1574
|
+
externalDependencies = _ref5.externalDependencies,
|
|
1575
|
+
isEffect = _ref5.isEffect;
|
|
1502
1576
|
|
|
1503
1577
|
// Our primary data structure.
|
|
1504
1578
|
// It is a logical representation of property chains:
|
|
@@ -1531,8 +1605,8 @@ function collectRecommendations(_ref4) {
|
|
|
1531
1605
|
|
|
1532
1606
|
// Mark all satisfied nodes.
|
|
1533
1607
|
// Imagine checkmarks next to each declared dependency.
|
|
1534
|
-
declaredDependencies.forEach(function (
|
|
1535
|
-
var key =
|
|
1608
|
+
declaredDependencies.forEach(function (_ref6) {
|
|
1609
|
+
var key = _ref6.key;
|
|
1536
1610
|
|
|
1537
1611
|
var node = getOrCreateNodeByPath(depTree, key);
|
|
1538
1612
|
node.isSatisfiedRecursively = true;
|
|
@@ -1648,8 +1722,8 @@ function collectRecommendations(_ref4) {
|
|
|
1648
1722
|
var suggestedDependencies = [];
|
|
1649
1723
|
var unnecessaryDependencies = new Set();
|
|
1650
1724
|
var duplicateDependencies = new Set();
|
|
1651
|
-
declaredDependencies.forEach(function (
|
|
1652
|
-
var key =
|
|
1725
|
+
declaredDependencies.forEach(function (_ref7) {
|
|
1726
|
+
var key = _ref7.key;
|
|
1653
1727
|
|
|
1654
1728
|
// Does this declared dep satsify a real need?
|
|
1655
1729
|
if (satisfyingDependencies.has(key)) {
|
|
@@ -1691,14 +1765,14 @@ function collectRecommendations(_ref4) {
|
|
|
1691
1765
|
|
|
1692
1766
|
// Finds functions declared as dependencies
|
|
1693
1767
|
// that would invalidate on every render.
|
|
1694
|
-
function scanForDeclaredBareFunctions(
|
|
1695
|
-
var declaredDependencies =
|
|
1696
|
-
declaredDependenciesNode =
|
|
1697
|
-
componentScope =
|
|
1698
|
-
scope =
|
|
1699
|
-
|
|
1700
|
-
var bareFunctions = declaredDependencies.map(function (
|
|
1701
|
-
var key =
|
|
1768
|
+
function scanForDeclaredBareFunctions(_ref8) {
|
|
1769
|
+
var declaredDependencies = _ref8.declaredDependencies,
|
|
1770
|
+
declaredDependenciesNode = _ref8.declaredDependenciesNode,
|
|
1771
|
+
componentScope = _ref8.componentScope,
|
|
1772
|
+
scope = _ref8.scope;
|
|
1773
|
+
|
|
1774
|
+
var bareFunctions = declaredDependencies.map(function (_ref9) {
|
|
1775
|
+
var key = _ref9.key;
|
|
1702
1776
|
|
|
1703
1777
|
var fnRef = componentScope.set.get(key);
|
|
1704
1778
|
if (fnRef == null) {
|
|
@@ -7,41 +7,45 @@
|
|
|
7
7
|
* LICENSE file in the root directory of this source tree.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
'use strict';function
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
!0
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
function
|
|
19
|
-
function
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
a.report({node:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if(!(0<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
0<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
10
|
+
'use strict';function R(a){return"Identifier"===a.type?/^use[A-Z0-9].*$/.test(a.name):"MemberExpression"===a.type&&!a.computed&&R(a.property)?(a=a.object,"Identifier"===a.type&&"React"===a.name):!1}function aa(a){return"Identifier"===a.type?!/^[a-z]/.test(a.name):!1}function ba(a){for(;a;){var b=ca(a);if(b&&(aa(b)||R(b)))return!0;a=a.parent}return!1}
|
|
11
|
+
function ca(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
|
+
a.parent.key}
|
|
13
|
+
function V(a){function b(){return{isRequired:!1,isSatisfiedRecursively:!1,hasRequiredNodesBelow:!1,children:new Map}}function e(a,h){h=h.split(".");var l=!0,c=!1,e=void 0;try{for(var f=h[Symbol.iterator](),p;!(l=(p=f.next()).done);l=!0){var u=p.value,g=a.children.get(u);g||(g=b(),a.children.set(u,g));a=g}}catch(E){c=!0,e=E}finally{try{!l&&f.return&&f.return()}finally{if(c)throw e;}}return a}function f(a,h,c){h=h.split(".");var l=!0,b=!1,f=void 0;try{for(var e=h[Symbol.iterator](),g;!(l=(g=e.next()).done);l=
|
|
14
|
+
!0){var u=a.children.get(g.value);if(!u)break;c(u);a=u}}catch(E){b=!0,f=E}finally{try{!l&&e.return&&e.return()}finally{if(b)throw f;}}}function h(a,c,b,e){a.children.forEach(function(a,l){var f=e(l);a.isSatisfiedRecursively?a.hasRequiredNodesBelow&&b.add(f):a.isRequired?c.add(f):h(a,c,b,function(a){return f+"."+a})})}var u=a.dependencies,q=a.declaredDependencies,t=a.optionalDependencies,c=a.externalDependencies,n=a.isEffect,C=b();u.forEach(function(a,h){e(C,h).isRequired=!0;f(C,h,function(a){a.hasRequiredNodesBelow=
|
|
15
|
+
!0})});q.forEach(function(a){e(C,a.key).isSatisfiedRecursively=!0});t.forEach(function(a){e(C,a).isSatisfiedRecursively=!0});a=new Set;var g=new Set;h(C,a,g,function(a){return a});var v=[],A=new Set,B=new Set;q.forEach(function(a){a=a.key;g.has(a)?-1===v.indexOf(a)?v.push(a):B.add(a):!n||a.endsWith(".current")||c.has(a)?A.add(a):-1===v.indexOf(a)&&v.push(a)});a.forEach(function(a){v.push(a)});return{suggestedDependencies:v,unnecessaryDependencies:A,duplicateDependencies:B,missingDependencies:a}}
|
|
16
|
+
function da(a){var b=a.declaredDependenciesNode,e=a.componentScope,f=a.scope;return a.declaredDependencies.map(function(a){a=e.set.get(a.key);if(null==a)return null;var b=a.defs[0];return null==b?null:"Variable"===b.type&&"VariableDeclarator"===b.node.type&&null!=b.node.init&&("ArrowFunctionExpression"===b.node.init.type||"FunctionExpression"===b.node.init.type)||"FunctionName"===b.type&&"FunctionDeclaration"===b.node.type?a:null}).filter(Boolean).map(function(a){var e=a.defs[0];a:{for(var h=!1,t=
|
|
17
|
+
0;t<a.references.length;t++){var c=a.references[t];if(c.writeExpr)if(h){a=!0;break a}else{h=!0;continue}for(var n=c.from;n!==f&&null!=n;)n=n.upper;if(n!==f&&!ea(b,c.identifier)){a=!0;break a}}a=!1}return{fn:e,suggestUseCallback:a}})}function fa(a){return"MemberExpression"!==a.parent.type||a.parent.object!==a||"current"===a.parent.property.name||a.parent.computed||null!=a.parent.parent&&"CallExpression"===a.parent.parent.type&&a.parent.parent.callee===a.parent?a:fa(a.parent)}
|
|
18
|
+
function X(a){if("Identifier"===a.type)return a.name;if("MemberExpression"!==a.type||a.computed)throw Error("Unsupported node type: "+a.type);var b=X(a.object);a=X(a.property);return b+"."+a}function ja(a){return"MemberExpression"!==a.type||"Identifier"!==a.object.type||"React"!==a.object.name||"Identifier"!==a.property.type||a.computed?a:a.property}
|
|
19
|
+
function ka(a,b){var e=ja(a);if("Identifier"!==e.type)return null;switch(e.name){case "useEffect":case "useLayoutEffect":case "useCallback":case "useMemo":return 0;case "useImperativeHandle":return 1;default:if(e===a&&b&&b.additionalHooks){a=void 0;try{a=X(e)}catch(f){if(/Unsupported node type/.test(f.message))return 0;throw f;}return b.additionalHooks.test(a)?0:-1}return-1}}
|
|
20
|
+
function Y(a,b){for(var e=[a],f=null;e.length;){f=e.shift();if("Identifier"===f.type&&f.name===b.name&&f.range[0]===b.range[0]&&f.range[1]===b.range[1])return f;if(ea(f,b)){a=!0;var h=!1,u=void 0;try{for(var q=Object.entries(f)[Symbol.iterator](),t;!(a=(t=q.next()).done);a=!0){var c=t.value,n=c[1];"parent"!==c[0]&&(la(n)?(n.parent=f,e.push(n)):Array.isArray(n)&&n.forEach(function(a){la(a)&&(a.parent=f,e.push(a))}))}}catch(C){h=!0,u=C}finally{try{!a&&q.return&&q.return()}finally{if(h)throw u;}}}}return null}
|
|
21
|
+
function ma(a){for(var b="",e=0;e<a.length;e++)b+=a[e],0===e&&2===a.length?b+=" and ":e===a.length-2&&2<a.length?b+=", and ":e<a.length-1&&(b+=", ");return b}function la(a){return"object"===typeof a&&null!==a&&!Array.isArray(a)&&"string"===typeof a.type}function ea(a,b){return a.range[0]<=b.range[0]&&a.range[1]>=b.range[1]}
|
|
22
|
+
module.exports={rules:{"rules-of-hooks":{create:function(a){var b=[],e=[];return{onCodePathSegmentStart:function(a){return e.push(a)},onCodePathSegmentEnd:function(){return e.pop()},onCodePathStart:function(){return b.push(new Map)},onCodePathEnd:function(e,h){function f(a){var b=f.cache,c=b.get(a.id);if(null===c){if(!n.has(a.id)){n.add(a.id);b=!0;c=!1;var d=void 0;try{for(var m=a.prevSegments[Symbol.iterator](),r;!(b=(r=m.next()).done);b=!0)f(r.value)}catch(K){c=!0,d=K}finally{try{!b&&m.return&&
|
|
23
|
+
m.return()}finally{if(c)throw d;}}}return 0}if(void 0!==c)return c;b.set(a.id,null);if(e.thrownSegments.includes(a))c=0;else if(0===a.prevSegments.length)c=1;else{c=0;m=!0;r=!1;var H=void 0;try{d=a.prevSegments[Symbol.iterator]();for(var k;!(m=(k=d.next()).done);m=!0)c+=f(k.value)}catch(K){r=!0,H=K}finally{try{!m&&d.return&&d.return()}finally{if(r)throw H;}}}a.reachable&&0===c?b.delete(a.id):b.set(a.id,c);return c}function q(a){var b=q.cache,c=b.get(a.id);if(null===c){if(!n.has(a.id)){n.add(a.id);
|
|
24
|
+
b=!0;c=!1;var d=void 0;try{for(var m=a.nextSegments[Symbol.iterator](),r;!(b=(r=m.next()).done);b=!0)q(r.value)}catch(K){c=!0,d=K}finally{try{!b&&m.return&&m.return()}finally{if(c)throw d;}}}return 0}if(void 0!==c)return c;b.set(a.id,null);if(e.thrownSegments.includes(a))c=0;else if(0===a.nextSegments.length)c=1;else{c=0;m=!0;r=!1;var H=void 0;try{d=a.nextSegments[Symbol.iterator]();for(var f;!(m=(f=d.next()).done);m=!0)c+=q(f.value)}catch(K){r=!0,H=K}finally{try{!m&&d.return&&d.return()}finally{if(r)throw H;
|
|
25
|
+
}}}b.set(a.id,c);return c}function t(a){var c=t.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,m=!1,r=void 0;try{for(var H=a.prevSegments[Symbol.iterator](),e;!(d=(e=H.next()).done);d=!0){var f=t(e.value);f<b&&(b=f)}}catch(na){m=!0,r=na}finally{try{!d&&H.return&&H.return()}finally{if(m)throw r;}}b+=1}c.set(a.id,b);return b}var c=b.pop();if(0!==c.size){var n=new Set;f.cache=new Map;q.cache=new Map;t.cache=
|
|
26
|
+
new Map;var C=q(e.initialSegment),g=ca(h),v=ba(h),A=g?aa(g)||R(g):!1,B=Infinity,l=!0,p=!1,G=void 0;try{for(var w=e.finalSegments[Symbol.iterator](),J;!(l=(J=w.next()).done);l=!0){var W=J.value;if(W.reachable){var Q=t(W);Q<B&&(B=Q)}}}catch(k){p=!0,G=k}finally{try{!l&&w.return&&w.return()}finally{if(p)throw G;}}l=!0;p=!1;G=void 0;try{for(var z=c[Symbol.iterator](),O;!(l=(O=z.next()).done);l=!0){var E=O.value,D=E[0],L=E[1];if(D.reachable){var I=0===D.nextSegments.length?B<=t(D):B<t(D),T=f(D)*q(D),F=
|
|
27
|
+
n.has(D.id);c=!0;w=!1;J=void 0;try{for(var x=L[Symbol.iterator](),M;!(c=(M=x.next()).done);c=!0){var y=M.value;F&&a.report({node:y,message:'React Hook "'+a.getSource(y)+'" 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.'});if(A){if(!F&&T!==C){var U='React Hook "'+a.getSource(y)+'" is called conditionally. React Hooks must be called in the exact same order in every component render.'+(I?" Did you accidentally call a React Hook after an early return?":
|
|
28
|
+
"");a.report({node:y,message:U})}}else if(!h.parent||"MethodDefinition"!==h.parent.type&&"ClassProperty"!==h.parent.type||h.parent.value!==h)if(g){var N='React Hook "'+a.getSource(y)+'" is called in '+('function "'+a.getSource(g)+'" ')+"which is neither a React function component or a custom React Hook function.";a.report({node:y,message:N})}else if("Program"!==h.type&&v){var P='React Hook "'+a.getSource(y)+'" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.';
|
|
29
|
+
a.report({node:y,message:P})}}}catch(k){w=!0,J=k}finally{try{!c&&x.return&&x.return()}finally{if(w)throw J;}}}}}catch(k){p=!0,G=k}finally{try{!l&&z.return&&z.return()}finally{if(p)throw G;}}}},CallExpression:function(a){if(R(a.callee)){var f=b[b.length-1],u=e[e.length-1],q=f.get(u);q||(q=[],f.set(u,q));q.push(a.callee)}}}}},"exhaustive-deps":{meta:{fixable:"code",schema:[{type:"object",additionalProperties:!1,properties:{additionalHooks:{type:"string"}}}]},create:function(a){function b(a,b){return function(c){if(b.has(c))return b.get(c);
|
|
30
|
+
var e=a(c);b.set(c,e);return e}}function e(c){function e(a){var d=!0,r=!1,b=void 0;try{for(var f=a.references[Symbol.iterator](),h;!(d=(h=f.next()).done);d=!0){var g=h.value;if(g.resolved&&G.has(g.resolved.scope)){var l=Y(c,g.identifier),k=fa(l),p=X(k),q;if(q=B&&"Identifier"===k.type&&"MemberExpression"===k.parent.type&&!k.parent.computed&&"Identifier"===k.parent.property.type&&"current"===k.parent.property.name){for(var n=g.from,u=!1;n.block!==c;)"function"===n.type&&(u=null!=n.block.parent&&"ReturnStatement"===
|
|
31
|
+
n.block.parent.type),n=n.upper;q=u}q&&Q.set(p,{reference:g,dependencyNode:k});var t=g.resolved.defs[0];if(null==t||null==t.node||t.node.init!==c.parent)if(z.has(p))z.get(p).references.push(g);else{var v=g.resolved,y=J(v)||W(v);z.set(p,{isStatic:y,references:[g]})}}}}catch(Z){r=!0,b=Z}finally{try{!d&&f.return&&f.return()}finally{if(r)throw b;}}d=!0;r=!1;b=void 0;try{for(var w=a.childScopes[Symbol.iterator](),x;!(d=(x=w.next()).done);d=!0)e(x.value)}catch(Z){r=!0,b=Z}finally{try{!d&&w.return&&w.return()}finally{if(r)throw b;
|
|
32
|
+
}}}function C(a,b,r,c){return 0===a.size?null:(1<a.size?"":b+" ")+r+" "+(1<a.size?"dependencies":"dependency")+": "+ma(Array.from(a).sort().map(function(a){return"'"+a+"'"}))+(". Either "+c+" "+(1<a.size?"them":"it")+" or remove the dependency array.")}if(("FunctionExpression"===c.type||"ArrowFunctionExpression"===c.type)&&"CallExpression"===c.parent.type){var g=ka(c.parent.callee,f);if(c.parent.arguments[g]===c){var v=c.parent.callee,A=ja(v).name,B=A.endsWith("Effect"),l=c.parent.arguments[g+1];
|
|
33
|
+
if(l||B){B&&c.async&&a.report({node:c,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"});var p=a.getScope(),G=new Set,w=null;for(g=p.upper;g;){G.add(g);
|
|
34
|
+
if("function"===g.type)break;g=g.upper}if(g){w=g;var J=b(function(a){if(!Array.isArray(a.defs))return!1;var d=a.defs[0];if(null==d||"VariableDeclarator"!==d.node.type)return!1;var b=d.node.init;if(null==b)return!1;var c=d.node.parent;if(null==c&&(Y(w.block,d.node.id),c=d.node.parent,null==c))return!1;if("const"===c.kind&&"Literal"===b.type&&("string"===typeof b.value||"number"===typeof b.value||null===b.value))return!0;if("CallExpression"!==b.type)return!1;b=b.callee;"MemberExpression"!==b.type||
|
|
35
|
+
"React"!==b.object.name||null==b.property||b.computed||(b=b.property);if("Identifier"!==b.type)return!1;d=d.node.id;b=b.name;if("useRef"===b&&"Identifier"===d.type)return!0;if(("useState"===b||"useReducer"===b)&&"ArrayPattern"===d.type&&2===d.elements.length&&Array.isArray(a.identifiers)){if(d.elements[1]===a.identifiers[0]){if("useState"===b)for(a=a.references,b=0;b<a.length;b++)h.set(a[b].identifier,d.elements[0]);return!0}if(d.elements[0]===a.identifiers[0]&&"useState"===b)for(a=a.references,d=
|
|
36
|
+
0;d<a.length;d++)u.add(a[d].identifier)}return!1},q),W=b(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 b=a.node,d=w.childScopes;a=null;var c;for(c=0;c<d.length;c++){var e=d[c],f=e.block;if("FunctionDeclaration"===b.type&&f===b||"VariableDeclarator"===b.type&&f.parent===b){a=e;break}}if(null==a)return!1;for(c=0;c<a.through.length;c++)if(b=a.through[c],null!=b.resolved&&G.has(b.resolved.scope)&&!J(b.resolved))return!1;return!0},t),
|
|
37
|
+
Q=new Map,z=new Map;e(p);Q.forEach(function(b,c){var d=b.dependencyNode;b=b.reference.resolved.references;for(var e=!1,f=0;f<b.length;f++){var m=b[f].identifier.parent;if(null!=m&&"MemberExpression"===m.type&&!m.computed&&"Identifier"===m.property.type&&"current"===m.property.name&&"AssignmentExpression"===m.parent.type&&m.parent.left===m){e=!0;break}}e||a.report({node:d.parent.property,message:"The ref value '"+c+".current' will likely have changed by the time this effect cleanup function runs. If this ref points to a node rendered by React, copy "+
|
|
38
|
+
("'"+c+".current' to a variable inside the effect, and ")+"use that variable in the cleanup function."})});var O=new Set,E=new Set;z.forEach(function(b,c){var d=b.references;b.isStatic&&E.add(c);d.forEach(function(b){b.writeExpr&&(b=b.writeExpr,O.has(c)||(O.add(c),a.report({node:b,message:"Assignments to the '"+c+"' variable from inside React Hook "+(a.getSource(v)+" 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 "+
|
|
39
|
+
(a.getSource(v)+".")})))})});if(!(0<O.size))if(l){var D=[],L=new Set;"ArrayExpression"!==l.type?a.report({node:l,message:"React Hook "+a.getSource(v)+" 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."}):l.elements.forEach(function(b){if(null!==b)if("SpreadElement"===b.type)a.report({node:b,message:"React Hook "+a.getSource(v)+" has a spread element in its dependency array. This means we can't statically verify whether you've passed the correct dependencies."});
|
|
40
|
+
else{var c=void 0;try{c=X(b)}catch(ia){if(/Unsupported node type/.test(ia.message)){"Literal"===b.type?z.has(b.value)?a.report({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?")}):a.report({node:b,message:"The "+b.raw+" literal is not a valid dependency because it never changes. You can safely remove it."}):a.report({node:b,message:"React Hook "+a.getSource(v)+" has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked."});
|
|
41
|
+
return}throw ia;}for(var d=b;"MemberExpression"===d.type;)d=d.object;var e=!w.through.some(function(a){return a.identifier===d});D.push({key:c,node:b});e||L.add(c)}});var I=V({dependencies:z,declaredDependencies:D,optionalDependencies:E,externalDependencies:L,isEffect:B}),T=I.suggestedDependencies;g=I.unnecessaryDependencies;var F=I.missingDependencies;I=I.duplicateDependencies;if(0===I.size+F.size+g.size)da({declaredDependencies:D,declaredDependenciesNode:l,componentScope:w,scope:p}).forEach(function(b){var c=
|
|
42
|
+
b.fn,d=b.suggestUseCallback;b="The '"+c.name.name+"' function makes the dependencies of "+(A+" Hook (at line "+l.loc.start.line+") ")+"change on every render.";b=d?b+(" To fix this, "+("wrap the '"+c.name.name+"' definition into its own useCallback() Hook.")):b+(" Move it inside the "+A+" callback. "+("Alternatively, wrap the '"+c.name.name+"' definition into its own useCallback() Hook."));a.report({node:c.node,message:b,fix:function(a){if(d&&"Variable"===c.type)return[a.insertTextBefore(c.node.init,
|
|
43
|
+
"useCallback("),a.insertTextAfter(c.node.init,")")]}})});else{!B&&0<F.size&&(T=V({dependencies:z,declaredDependencies:[],optionalDependencies:E,externalDependencies:L,isEffect:B}).suggestedDependencies);(function(){if(0===D.length)return!0;var a=D.map(function(a){return a.key}),b=a.slice().sort();return a.join(",")===b.join(",")})()&&T.sort();var x="";if(0<g.size){var M=null;Array.from(g.keys()).forEach(function(a){null===M&&a.endsWith(".current")&&(M=a)});if(null!==M)x=" Mutable values like '"+M+
|
|
44
|
+
"' aren't valid dependencies because mutating them doesn't re-render the component.";else if(0<L.size){var y=Array.from(L)[0];p.set.has(y)||(x=" Outer scope values like '"+y+"' aren't valid dependencies because mutating them doesn't re-render the component.")}}if(!x&&F.has("props")){p=z.get("props");if(null==p)return;p=p.references;if(!Array.isArray(p))return;y=!0;for(var U=0;U<p.length;U++){var N=Y(w.block,p[U].identifier);if(!N){y=!1;break}N=N.parent;if(null==N){y=!1;break}if("MemberExpression"!==
|
|
45
|
+
N.type){y=!1;break}}y&&(x=" However, 'props' will change when *any* prop changes, so the preferred fix is to destructure the 'props' object outside of "+("the "+A+" call and refer to those specific props ")+("inside "+a.getSource(v)+"."))}if(!x&&0<F.size){var P=null;F.forEach(function(a){if(!P){var b=w.set.get(a),c=z.get(a);if(c.references[0].resolved===b&&(b=b.defs[0],null!=b&&null!=b.name&&"Parameter"===b.type)){b=!1;for(var d,e=0;e<c.references.length;e++)if(d=c.references[e].identifier,null!=
|
|
46
|
+
d&&null!=d.parent&&"CallExpression"===d.parent.type&&d.parent.callee===d){b=!0;break}b&&(P=a)}}});null!==P&&(x=" If '"+P+"' changes too often, find the parent component that defines it and wrap that definition in useCallback.")}if(!x&&0<F.size){var k=null;F.forEach(function(a){if(null===k)for(var b=z.get(a).references,c,d,e=0;e<b.length;e++){c=b[e].identifier;for(d=c.parent;null!=d&&d!==w.block;){if("CallExpression"===d.type){var f=h.get(d.callee);if(null!=f){f.name===a?k={missingDep:a,setter:d.callee.name,
|
|
47
|
+
form:"updater"}:u.has(c)?k={missingDep:a,setter:d.callee.name,form:"reducer"}:(c=b[e].resolved,null!=c&&(c=c.defs[0],null!=c&&"Parameter"===c.type&&(k={missingDep:a,setter:d.callee.name,form:"inlineReducer"})));break}}d=d.parent}if(null!==k)break}});if(null!==k)switch(k.form){case "reducer":x=" You can also replace multiple useState variables with useReducer "+("if '"+k.setter+"' needs the ")+("current value of '"+k.missingDep+"'.");break;case "inlineReducer":x=" If '"+k.setter+"' needs the "+("current value of '"+
|
|
48
|
+
k.missingDep+"', ")+"you can also switch to useReducer instead of useState and "+("read '"+k.missingDep+"' in the reducer.");break;case "updater":x=" You can also do a functional update '"+k.setter+"("+k.missingDep.substring(0,1)+" => ...)' if you only need '"+k.missingDep+"'"+(" in the '"+k.setter+"' call.");break;default:throw Error("Unknown case.");}}a.report({node:l,message:"React Hook "+a.getSource(v)+" has "+(C(F,"a","missing","include")||C(g,"an","unnecessary","exclude")||C(I,"a","duplicate",
|
|
49
|
+
"omit"))+x,fix:function(a){return a.replaceText(l,"["+T.join(", ")+"]")}})}}else{var S=null;z.forEach(function(a,b){S||a.references.forEach(function(a){if(!S&&h.has(a.identifier)){for(a=a.from;"function"!==a.type;)a=a.upper;a.block===c&&(S=b)}})});if(S){var ha=V({dependencies:z,declaredDependencies:[],optionalDependencies:E,externalDependencies:new Set,isEffect:!0}).suggestedDependencies;a.report({node:c.parent.callee,message:"React Hook "+A+" contains a call to '"+S+"'. Without a list of dependencies, this can lead to an infinite chain of updates. To fix this, pass ["+
|
|
50
|
+
ha.join(", ")+("] as a second argument to the "+A+" Hook."),fix:function(a){return a.insertTextAfter(c,", ["+ha.join(", ")+"]")}})}}}}else"useMemo"!==A&&"useCallback"!==A||a.report({node:c.parent.callee,message:"React Hook "+A+" does nothing when called with only one argument. Did you forget to pass an array of dependencies?"})}}}var f={additionalHooks:a.options&&a.options[0]&&a.options[0].additionalHooks?new RegExp(a.options[0].additionalHooks):void 0},h=new WeakMap,u=new WeakSet,q=new WeakMap,t=
|
|
51
|
+
new WeakMap;return{FunctionExpression:e,ArrowFunctionExpression:e}}}}};
|