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 + ' doesn\'t serve any purpose ' + 'without a dependency array. To enable ' + 'this optimization, pass an array of values used by the ' + ('inner function as the second argument to ' + 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: 'Accessing \'' + dependency + '.current\' during the effect cleanup ' + 'will likely read a different ref value because by this time React ' + 'has already updated the ref. If this ref is managed by React, store ' + ('\'' + dependency + '.current\' in a variable inside ') + 'the effect itself and refer to that variable from the cleanup function.'
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) + ' has a second ' + "argument which is not an array literal. This means we can't " + "statically verify whether you've passed the correct dependencies."
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 (typeof declaredDependencyNode.value === 'string') {
1238
+ if (dependencies.has(declaredDependencyNode.value)) {
1136
1239
  context.report({
1137
1240
  node: declaredDependencyNode,
1138
- message: 'The ' + declaredDependencyNode.raw + ' string literal is not a valid dependency ' + 'because it never changes. Did you mean to ' + ('include ' + declaredDependencyNode.value + ' in the array instead?')
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 \'' + declaredDependencyNode.raw + '\' literal is not a valid dependency ' + 'because it never changes. You can safely remove it.'
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
- // Warn about assigning to variables in the outer scope.
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 = _collectRecommendatio.suggestedDependencies,
1221
- unnecessaryDependencies = _collectRecommendatio.unnecessaryDependencies,
1222
- missingDependencies = _collectRecommendatio.missingDependencies,
1223
- duplicateDependencies = _collectRecommendatio.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 (_ref3) {
1237
- var fn = _ref3.fn,
1238
- suggestUseCallback = _ref3.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 += ' To fix this, move the \'' + fn.name.name + '\' function ' + ('inside the ' + reactiveHookName + ' callback (at line ' + node.loc.start.line + '). ') + ('Alternatively, wrap the \'' + fn.name.name + '\' definition into its own useCallback() Hook.');
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
- // require restructuring the rule code. For now,
1258
- // this is fine. Note we're intentionally not adding
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 their mutation doesn't re-render the component.";
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
- extraWarning = ' Values like \'' + dep + '\' aren\'t valid dependencies ' + 'because their mutation doesn\'t re-render the component.';
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\' ' + ('object outside of the ' + reactiveHookName + ' call and ') + 'refer to specific props directly by their names.';
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 specifying \'' + missingCallbackDep + '\'' + ' makes the dependencies change too often, ' + 'find the parent component that defines it ' + 'and wrap that definition in useCallback.';
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
- suggestion = 'useReducer Hook. This lets you move the calculation ' + 'of next state outside the effect.';
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
- suggestion = 'useReducer Hook. This lets you move the calculation ' + 'of next state outside the effect. You can then ' + ('read \'' + setStateRecommendation.missingDep + '\' from the reducer ') + 'by putting it directly in your component.';
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
- suggestion = setStateRecommendation.setter + '(' + setStateRecommendation.missingDep + ' => ...) form ' + 'which doesn\'t need to depend on the state from outside.';
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(_ref4) {
1497
- var dependencies = _ref4.dependencies,
1498
- declaredDependencies = _ref4.declaredDependencies,
1499
- optionalDependencies = _ref4.optionalDependencies,
1500
- externalDependencies = _ref4.externalDependencies,
1501
- isEffect = _ref4.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 (_ref5) {
1535
- var key = _ref5.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 (_ref6) {
1652
- var key = _ref6.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(_ref7) {
1695
- var declaredDependencies = _ref7.declaredDependencies,
1696
- declaredDependenciesNode = _ref7.declaredDependenciesNode,
1697
- componentScope = _ref7.componentScope,
1698
- scope = _ref7.scope;
1699
-
1700
- var bareFunctions = declaredDependencies.map(function (_ref8) {
1701
- var key = _ref8.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 Q(a){return"Identifier"===a.type?/^use[A-Z0-9].*$/.test(a.name):"MemberExpression"===a.type&&!a.computed&&Q(a.property)?(a=a.object,"Identifier"===a.type&&"React"===a.name):!1}function U(a){return"Identifier"===a.type?!/^[a-z]/.test(a.name):!1}function aa(a){for(;a;){var b=W(a);if(b&&(U(b)||Q(b)))return!0;a=a.parent}return!1}
11
- function W(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:a.parent.key}
12
- function ba(a){function b(){return{isRequired:!1,isSatisfiedRecursively:!1,hasRequiredNodesBelow:!1,children:new Map}}function e(a,g){g=g.split(".");var m=!0,l=!1,e=void 0;try{for(var h=g[Symbol.iterator](),k;!(m=(k=h.next()).done);m=!0){var v=k.value,f=a.children.get(v);f||(f=b(),a.children.set(v,f));a=f}}catch(C){l=!0,e=C}finally{try{!m&&h.return&&h.return()}finally{if(l)throw e;}}return a}function h(a,g,l){g=g.split(".");var m=!0,b=!1,h=void 0;try{for(var e=g[Symbol.iterator](),k;!(m=(k=e.next()).done);m=
13
- !0){var f=a.children.get(k.value);if(!f)break;l(f);a=f}}catch(C){b=!0,h=C}finally{try{!m&&e.return&&e.return()}finally{if(b)throw h;}}}function l(a,b,e,h){a.children.forEach(function(a,m){var k=h(m);a.isSatisfiedRecursively?a.hasRequiredNodesBelow&&e.add(k):a.isRequired?b.add(k):l(a,b,e,function(a){return k+"."+a})})}var v=a.dependencies,n=a.declaredDependencies,p=a.optionalDependencies,k=a.externalDependencies,q=a.isEffect,y=b();v.forEach(function(a,b){e(y,b).isRequired=!0;h(y,b,function(a){a.hasRequiredNodesBelow=
14
- !0})});n.forEach(function(a){e(y,a.key).isSatisfiedRecursively=!0});p.forEach(function(a){e(y,a).isSatisfiedRecursively=!0});a=new Set;var f=new Set;l(y,a,f,function(a){return a});var w=[],A=new Set,D=new Set;n.forEach(function(a){a=a.key;f.has(a)?-1===w.indexOf(a)?w.push(a):D.add(a):!q||a.endsWith(".current")||k.has(a)?A.add(a):-1===w.indexOf(a)&&w.push(a)});a.forEach(function(a){w.push(a)});return{suggestedDependencies:w,unnecessaryDependencies:A,duplicateDependencies:D,missingDependencies:a}}
15
- function ca(a){var b=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 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 l=!1,p=
16
- 0;p<a.references.length;p++){var k=a.references[p];if(k.writeExpr)if(l){a=!0;break a}else{l=!0;continue}for(var q=k.from;q!==h&&null!=q;)q=q.upper;if(q!==h&&!da(b,k.identifier)){a=!0;break a}}a=!1}return{fn:e,suggestUseCallback:a}})}function ea(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:ea(a.parent)}
17
- function Y(a){if("Identifier"===a.type)return a.name;if("MemberExpression"!==a.type||a.computed)throw Error("Unsupported node type: "+a.type);var b=Y(a.object);a=Y(a.property);return b+"."+a}function ha(a){return"MemberExpression"!==a.type||"Identifier"!==a.object.type||"React"!==a.object.name||"Identifier"!==a.property.type||a.computed?a:a.property}
18
- function ia(a,b){var e=ha(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=Y(e)}catch(h){if(/Unsupported node type/.test(h.message))return 0;throw h;}return b.additionalHooks.test(a)?0:-1}return-1}}
19
- function Z(a,b){for(var e=[a],h=null;e.length;){h=e.shift();if("Identifier"===h.type&&h.name===b.name&&h.range[0]===b.range[0]&&h.range[1]===b.range[1])return h;if(da(h,b)){a=!0;var l=!1,v=void 0;try{for(var n=Object.entries(h)[Symbol.iterator](),p;!(a=(p=n.next()).done);a=!0){var k=p.value,q=k[1];"parent"!==k[0]&&(ja(q)?(q.parent=h,e.push(q)):Array.isArray(q)&&q.forEach(function(a){ja(a)&&(a.parent=h,e.push(a))}))}}catch(y){l=!0,v=y}finally{try{!a&&n.return&&n.return()}finally{if(l)throw v;}}}}return null}
20
- function ka(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 ja(a){return"object"===typeof a&&null!==a&&!Array.isArray(a)&&"string"===typeof a.type}function da(a,b){return a.range[0]<=b.range[0]&&a.range[1]>=b.range[1]}
21
- 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,l){function h(a){var d=h.cache,c=d.get(a.id);if(null===c){if(!q.has(a.id)){q.add(a.id);d=!0;c=!1;var x=void 0;try{for(var u=a.prevSegments[Symbol.iterator](),b;!(d=(b=u.next()).done);d=!0)h(b.value)}catch(M){c=!0,x=M}finally{try{!d&&u.return&&
22
- u.return()}finally{if(c)throw x;}}}return 0}if(void 0!==c)return c;d.set(a.id,null);if(e.thrownSegments.includes(a))c=0;else if(0===a.prevSegments.length)c=1;else{c=0;u=!0;b=!1;var k=void 0;try{x=a.prevSegments[Symbol.iterator]();for(var f;!(u=(f=x.next()).done);u=!0)c+=h(f.value)}catch(M){b=!0,k=M}finally{try{!u&&x.return&&x.return()}finally{if(b)throw k;}}}a.reachable&&0===c?d.delete(a.id):d.set(a.id,c);return c}function n(a){var d=n.cache,c=d.get(a.id);if(null===c){if(!q.has(a.id)){q.add(a.id);
23
- d=!0;c=!1;var x=void 0;try{for(var u=a.nextSegments[Symbol.iterator](),b;!(d=(b=u.next()).done);d=!0)n(b.value)}catch(M){c=!0,x=M}finally{try{!d&&u.return&&u.return()}finally{if(c)throw x;}}}return 0}if(void 0!==c)return c;d.set(a.id,null);if(e.thrownSegments.includes(a))c=0;else if(0===a.nextSegments.length)c=1;else{c=0;u=!0;b=!1;var k=void 0;try{x=a.nextSegments[Symbol.iterator]();for(var f;!(u=(f=x.next()).done);u=!0)c+=n(f.value)}catch(M){b=!0,k=M}finally{try{!u&&x.return&&x.return()}finally{if(b)throw k;
24
- }}}d.set(a.id,c);return c}function p(a){var d=p.cache,c=d.get(a.id);if(null===c)return Infinity;if(void 0!==c)return c;d.set(a.id,null);if(0===a.prevSegments.length)c=1;else{c=Infinity;var x=!0,u=!1,b=void 0;try{for(var e=a.prevSegments[Symbol.iterator](),k;!(x=(k=e.next()).done);x=!0){var f=p(k.value);f<c&&(c=f)}}catch(la){u=!0,b=la}finally{try{!x&&e.return&&e.return()}finally{if(u)throw b;}}c+=1}d.set(a.id,c);return c}var k=b.pop();if(0!==k.size){var q=new Set;h.cache=new Map;n.cache=new Map;p.cache=
25
- new Map;var y=n(e.initialSegment),f=W(l),w=aa(l),A=f?U(f)||Q(f):!1,D=Infinity,m=!0,g=!1,G=void 0;try{for(var t=e.finalSegments[Symbol.iterator](),J;!(m=(J=t.next()).done);m=!0){var V=J.value;if(V.reachable){var P=p(V);P<D&&(D=P)}}}catch(r){g=!0,G=r}finally{try{!m&&t.return&&t.return()}finally{if(g)throw G;}}m=!0;g=!1;G=void 0;try{for(var z=k[Symbol.iterator](),K;!(m=(K=z.next()).done);m=!0){var C=K.value,E=C[0],R=C[1];if(E.reachable){var H=0===E.nextSegments.length?D<=p(E):D<p(E),S=h(E)*n(E),F=q.has(E.id);
26
- k=!0;t=!1;J=void 0;try{for(var L=R[Symbol.iterator](),I;!(k=(I=L.next()).done);k=!0){var B=I.value;F&&a.report({node:B,message:'React Hook "'+a.getSource(B)+'" 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&&S!==y){var T='React Hook "'+a.getSource(B)+'" is called conditionally. React Hooks must be called in the exact same order in every component render.'+(H?" Did you accidentally call a React Hook after an early return?":
27
- "");a.report({node:B,message:T})}}else if(!l.parent||"MethodDefinition"!==l.parent.type&&"ClassProperty"!==l.parent.type||l.parent.value!==l)if(f){var N='React Hook "'+a.getSource(B)+'" is called in '+('function "'+a.getSource(f)+'" ')+"which is neither a React function component or a custom React Hook function.";a.report({node:B,message:N})}else if("Program"!==l.type&&w){var O='React Hook "'+a.getSource(B)+'" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.';
28
- a.report({node:B,message:O})}}}catch(r){t=!0,J=r}finally{try{!k&&L.return&&L.return()}finally{if(t)throw J;}}}}}catch(r){g=!0,G=r}finally{try{!m&&z.return&&z.return()}finally{if(g)throw G;}}}},CallExpression:function(a){if(Q(a.callee)){var h=b[b.length-1],v=e[e.length-1],n=h.get(v);n||(n=[],h.set(v,n));n.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(e){if(b.has(e))return b.get(e);
29
- var k=a(e);b.set(e,k);return k}}function e(e){function k(a){var c=!0,d=!1,b=void 0;try{for(var f=a.references[Symbol.iterator](),h;!(c=(h=f.next()).done);c=!0){var g=h.value;if(g.resolved&&G.has(g.resolved.scope)){var m=Z(e,g.identifier),l=ea(m),n=Y(l),q;if(q=D&&"Identifier"===l.type&&"MemberExpression"===l.parent.type&&!l.parent.computed&&"Identifier"===l.parent.property.type&&"current"===l.parent.property.name){for(var p=g.from,r=!1;p.block!==e;)"function"===p.type&&(r=null!=p.block.parent&&"ReturnStatement"===
30
- p.block.parent.type),p=p.upper;q=r}q&&P.set(n,{reference:g,dependencyNode:l});if(z.has(n))z.get(n).references.push(g);else{var t=g.resolved,w=J(t)||V(t);z.set(n,{isStatic:w,references:[g]})}}}}catch(X){d=!0,b=X}finally{try{!c&&f.return&&f.return()}finally{if(d)throw b;}}c=!0;d=!1;b=void 0;try{for(var v=a.childScopes[Symbol.iterator](),y;!(c=(y=v.next()).done);c=!0)k(y.value)}catch(X){d=!0,b=X}finally{try{!c&&v.return&&v.return()}finally{if(d)throw b;}}}function y(a,c,b,e){return 0===a.size?null:(1<
31
- a.size?"":c+" ")+b+" "+(1<a.size?"dependencies":"dependency")+": "+ka(Array.from(a).sort().map(function(a){return"'"+a+"'"}))+(". Either "+e+" "+(1<a.size?"them":"it")+" or remove the dependency array.")}if(("FunctionExpression"===e.type||"ArrowFunctionExpression"===e.type)&&"CallExpression"===e.parent.type){var f=ia(e.parent.callee,h);if(e.parent.arguments[f]===e){var w=e.parent.callee,A=ha(w).name,D=A.endsWith("Effect"),m=e.parent.arguments[f+1];if(m){var g=a.getScope(),G=new Set,t=null;for(f=g.upper;f;){G.add(f);
32
- if("function"===f.type)break;f=f.upper}if(f){t=f;var J=b(function(a){if(!Array.isArray(a.defs))return!1;var c=a.defs[0];if(null==c||"VariableDeclarator"!==c.node.type)return!1;var d=c.node.init;if(null==d)return!1;var b=c.node.parent;if(null==b&&(Z(t.block,c.node.id),b=c.node.parent,null==b))return!1;if("const"===b.kind&&"Literal"===d.type&&("string"===typeof d.value||"number"===typeof d.value||null===d.value))return!0;if("CallExpression"!==d.type)return!1;d=d.callee;"MemberExpression"!==d.type||
33
- "React"!==d.object.name||null==d.property||d.computed||(d=d.property);if("Identifier"!==d.type)return!1;c=c.node.id;d=d.name;if("useRef"===d&&"Identifier"===c.type)return!0;if(("useState"===d||"useReducer"===d)&&"ArrayPattern"===c.type&&2===c.elements.length&&Array.isArray(a.identifiers)){if(c.elements[1]===a.identifiers[0]){if("useState"===d)for(a=a.references,d=0;d<a.length;d++)l.set(a[d].identifier,c.elements[0]);return!0}if(c.elements[0]===a.identifiers[0]&&"useState"===d)for(a=a.references,c=
34
- 0;c<a.length;c++)v.add(a[c].identifier)}return!1},n),V=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 c=a.node,d=t.childScopes;a=null;var b;for(b=0;b<d.length;b++){var e=d[b],f=e.block;if("FunctionDeclaration"===c.type&&f===c||"VariableDeclarator"===c.type&&f.parent===c){a=e;break}}if(null==a)return!1;for(b=0;b<a.through.length;b++)if(c=a.through[b],null!=c.resolved&&G.has(c.resolved.scope)&&!J(c.resolved))return!1;return!0},p),
35
- P=new Map,z=new Map;k(g);P.forEach(function(d,c){var b=d.dependencyNode;d=d.reference.resolved.references;for(var e=!1,f=0;f<d.length;f++){var g=d[f].identifier.parent;if(null!=g&&"MemberExpression"===g.type&&!g.computed&&"Identifier"===g.property.type&&"current"===g.property.name&&"AssignmentExpression"===g.parent.type&&g.parent.left===g){e=!0;break}}e||a.report({node:b.parent.property,message:"Accessing '"+c+".current' during the effect cleanup will likely read a different ref value because by this time React has already updated the ref. If this ref is managed by React, store "+
36
- ("'"+c+".current' in a variable inside ")+"the effect itself and refer to that variable from the cleanup function."})});var K=[],C=new Set;"ArrayExpression"!==m.type?a.report({node:m,message:"React Hook "+a.getSource(w)+" has a second argument which is not an array literal. This means we can't statically verify whether you've passed the correct dependencies."}):m.elements.forEach(function(d){if(null!==d)if("SpreadElement"===d.type)a.report({node:d,message:"React Hook "+a.getSource(w)+" has a spread element in its dependency array. This means we can't statically verify whether you've passed the correct dependencies."});
37
- else{var c=void 0;try{c=Y(d)}catch(fa){if(/Unsupported node type/.test(fa.message)){"Literal"===d.type?"string"===typeof d.value?a.report({node:d,message:"The "+d.raw+" string literal is not a valid dependency because it never changes. Did you mean to "+("include "+d.value+" in the array instead?")}):a.report({node:d,message:"The '"+d.raw+"' literal is not a valid dependency because it never changes. You can safely remove it."}):a.report({node:d,message:"React Hook "+a.getSource(w)+" has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked."});
38
- return}throw fa;}for(var b=d;"MemberExpression"===b.type;)b=b.object;var e=!t.through.some(function(a){return a.identifier===b});K.push({key:c,node:d});e||C.add(c)}});var E=new Set,R=new Set;z.forEach(function(d,c){var b=d.references;d.isStatic&&R.add(c);b.forEach(function(d){d.writeExpr&&(d=d.writeExpr,E.has(c)||(E.add(c),a.report({node:d,message:"Assignments to the '"+c+"' variable from inside a React "+a.getSource(w)+" 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."})))})});
39
- if(!(0<E.size)){var H=ba({dependencies:z,declaredDependencies:K,optionalDependencies:R,externalDependencies:C,isEffect:D}),S=H.suggestedDependencies;f=H.unnecessaryDependencies;var F=H.missingDependencies;H=H.duplicateDependencies;if(0===H.size+F.size+f.size)ca({declaredDependencies:K,declaredDependenciesNode:m,componentScope:t,scope:g}).forEach(function(d){var c=d.fn,b=d.suggestUseCallback;d="The '"+c.name.name+"' function makes the dependencies of "+(A+" Hook (at line "+m.loc.start.line+") ")+"change on every render.";
40
- d=b?d+(" To fix this, "+("wrap the '"+c.name.name+"' definition into its own useCallback() Hook.")):d+(" To fix this, move the '"+c.name.name+"' function "+("inside the "+A+" callback (at line "+e.loc.start.line+"). ")+("Alternatively, wrap the '"+c.name.name+"' definition into its own useCallback() Hook."));a.report({node:c.node,message:d,fix:function(a){if(b&&"Variable"===c.type)return[a.insertTextBefore(c.node.init,"useCallback("),a.insertTextAfter(c.node.init,")")]}})});else{!D&&0<F.size&&(S=
41
- ba({dependencies:z,declaredDependencies:[],optionalDependencies:R,externalDependencies:C,isEffect:D}).suggestedDependencies);(function(){if(0===K.length)return!0;var a=K.map(function(a){return a.key}),c=a.slice().sort();return a.join(",")===c.join(",")})()&&S.sort();g="";if(0<f.size){var L=null;Array.from(f.keys()).forEach(function(a){null===L&&a.endsWith(".current")&&(L=a)});null!==L?g=" Mutable values like '"+L+"' aren't valid dependencies because their mutation doesn't re-render the component.":
42
- 0<C.size&&(g=" Values like '"+Array.from(C)[0]+"' aren't valid dependencies because their mutation doesn't re-render the component.")}if(!g&&F.has("props")){var I=z.get("props");if(null==I)return;I=I.references;if(!Array.isArray(I))return;for(var B=!0,T=0;T<I.length;T++){var N=Z(t.block,I[T].identifier);if(!N){B=!1;break}N=N.parent;if(null==N){B=!1;break}if("MemberExpression"!==N.type){B=!1;break}}B&&(g=" However, the preferred fix is to destructure the 'props' "+("object outside of the "+A+" call and ")+
43
- "refer to specific props directly by their names.")}if(!g&&0<F.size){var O=null;F.forEach(function(a){if(!O){var c=t.set.get(a),b=z.get(a);if(b.references[0].resolved===c&&(c=c.defs[0],null!=c&&null!=c.name&&"Parameter"===c.type)){c=!1;for(var d,e=0;e<b.references.length;e++)if(d=b.references[e].identifier,null!=d&&null!=d.parent&&"CallExpression"===d.parent.type&&d.parent.callee===d){c=!0;break}c&&(O=a)}}});null!==O&&(g=" If specifying '"+O+"' makes the dependencies change too often, find the parent component that defines it and wrap that definition in useCallback.")}if(!g&&
44
- 0<F.size){var r=null;F.forEach(function(a){if(null===r)for(var c=z.get(a).references,b,d,e=0;e<c.length;e++){b=c[e].identifier;for(d=b.parent;null!=d&&d!==t.block;){if("CallExpression"===d.type){var f=l.get(d.callee);if(null!=f){f.name===a?r={missingDep:a,setter:d.callee.name,form:"updater"}:v.has(b)?r={missingDep:a,setter:d.callee.name,form:"reducer"}:(b=c[e].resolved,null!=b&&(b=b.defs[0],null!=b&&"Parameter"===b.type&&(r={missingDep:a,setter:d.callee.name,form:"inlineReducer"})));break}}d=d.parent}if(null!==
45
- r)break}});if(null!==r){g=void 0;switch(r.form){case "reducer":g="useReducer Hook. This lets you move the calculation of next state outside the effect.";break;case "inlineReducer":g="useReducer Hook. This lets you move the calculation of next state outside the effect. You can then "+("read '"+r.missingDep+"' from the reducer ")+"by putting it directly in your component.";break;case "updater":g=r.setter+"("+r.missingDep+" => ...) form which doesn't need to depend on the state from outside.";break;
46
- default:throw Error("Unknown case.");}g=" If '"+r.missingDep+"' is only necessary for calculating the next state, "+("consider refactoring to the "+g)}}a.report({node:m,message:"React Hook "+a.getSource(w)+" has "+(y(F,"a","missing","include")||y(f,"an","unnecessary","exclude")||y(H,"a","duplicate","omit"))+g,fix:function(a){return a.replaceText(m,"["+S.join(", ")+"]")}})}}}}else"useMemo"!==A&&"useCallback"!==A||a.report({node:e.parent.callee,message:"React Hook "+A+" doesn't serve any purpose without a dependency array. To enable this optimization, pass an array of values used by the "+
47
- ("inner function as the second argument to "+A+".")})}}}var h={additionalHooks:a.options&&a.options[0]&&a.options[0].additionalHooks?new RegExp(a.options[0].additionalHooks):void 0},l=new WeakMap,v=new WeakSet,n=new WeakMap,p=new WeakMap;return{FunctionExpression:e,ArrowFunctionExpression:e}}}}};
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}}}}};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks",
3
3
  "description": "ESLint rules for React Hooks",
4
- "version": "1.5.0-beta.0",
4
+ "version": "1.6.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/facebook/react.git",