eslint-plugin-react-hooks 1.5.0-beta.1 → 1.6.1

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,17 @@ 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
+
1031
+ // Ignore Flow type parameters
1032
+ if (def.type === 'TypeParameter') {
1033
+ continue;
1034
+ }
1035
+
1017
1036
  // Add the dependency to a map so we can make sure it is referenced
1018
1037
  // again in our dependencies array. Remember whether it's static.
1019
1038
  if (!dependencies.has(dependency)) {
@@ -1096,10 +1115,99 @@ var ExhaustiveDeps = {
1096
1115
  }
1097
1116
  context.report({
1098
1117
  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.'
1118
+ 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.'
1100
1119
  });
1101
1120
  });
1102
1121
 
1122
+ // Warn about assigning to variables in the outer scope.
1123
+ // Those are usually bugs.
1124
+ var staleAssignments = new Set();
1125
+ function reportStaleAssignment(writeExpr, key) {
1126
+ if (staleAssignments.has(key)) {
1127
+ return;
1128
+ }
1129
+ staleAssignments.add(key);
1130
+ context.report({
1131
+ node: writeExpr,
1132
+ 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) + '.')
1133
+ });
1134
+ }
1135
+
1136
+ // Remember which deps are optional and report bad usage first.
1137
+ var optionalDependencies = new Set();
1138
+ dependencies.forEach(function (_ref2, key) {
1139
+ var isStatic = _ref2.isStatic,
1140
+ references = _ref2.references;
1141
+
1142
+ if (isStatic) {
1143
+ optionalDependencies.add(key);
1144
+ }
1145
+ references.forEach(function (reference) {
1146
+ if (reference.writeExpr) {
1147
+ reportStaleAssignment(reference.writeExpr, key);
1148
+ }
1149
+ });
1150
+ });
1151
+
1152
+ if (staleAssignments.size > 0) {
1153
+ // The intent isn't clear so we'll wait until you fix those first.
1154
+ return;
1155
+ }
1156
+
1157
+ if (!declaredDependenciesNode) {
1158
+ // Check if there are any top-level setState() calls.
1159
+ // Those tend to lead to infinite loops.
1160
+ var setStateInsideEffectWithoutDeps = null;
1161
+ dependencies.forEach(function (_ref3, key) {
1162
+ var isStatic = _ref3.isStatic,
1163
+ references = _ref3.references;
1164
+
1165
+ if (setStateInsideEffectWithoutDeps) {
1166
+ return;
1167
+ }
1168
+ references.forEach(function (reference) {
1169
+ if (setStateInsideEffectWithoutDeps) {
1170
+ return;
1171
+ }
1172
+
1173
+ var id = reference.identifier;
1174
+ var isSetState = setStateCallSites.has(id);
1175
+ if (!isSetState) {
1176
+ return;
1177
+ }
1178
+
1179
+ var fnScope = reference.from;
1180
+ while (fnScope.type !== 'function') {
1181
+ fnScope = fnScope.upper;
1182
+ }
1183
+ var isDirectlyInsideEffect = fnScope.block === node;
1184
+ if (isDirectlyInsideEffect) {
1185
+ // TODO: we could potentially ignore early returns.
1186
+ setStateInsideEffectWithoutDeps = key;
1187
+ }
1188
+ });
1189
+ });
1190
+ if (setStateInsideEffectWithoutDeps) {
1191
+ var _collectRecommendatio = collectRecommendations({
1192
+ dependencies: dependencies,
1193
+ declaredDependencies: [],
1194
+ optionalDependencies: optionalDependencies,
1195
+ externalDependencies: new Set(),
1196
+ isEffect: true
1197
+ }),
1198
+ _suggestedDependencies = _collectRecommendatio.suggestedDependencies;
1199
+
1200
+ context.report({
1201
+ node: node.parent.callee,
1202
+ 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.'),
1203
+ fix: function (fixer) {
1204
+ return fixer.insertTextAfter(node, ', [' + _suggestedDependencies.join(', ') + ']');
1205
+ }
1206
+ });
1207
+ }
1208
+ return;
1209
+ }
1210
+
1103
1211
  var declaredDependencies = [];
1104
1212
  var externalDependencies = new Set();
1105
1213
  if (declaredDependenciesNode.type !== 'ArrayExpression') {
@@ -1108,7 +1216,7 @@ var ExhaustiveDeps = {
1108
1216
  // the user this in an error.
1109
1217
  context.report({
1110
1218
  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."
1219
+ 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
1220
  });
1113
1221
  } else {
1114
1222
  declaredDependenciesNode.elements.forEach(function (declaredDependencyNode) {
@@ -1132,15 +1240,15 @@ var ExhaustiveDeps = {
1132
1240
  } catch (error) {
1133
1241
  if (/Unsupported node type/.test(error.message)) {
1134
1242
  if (declaredDependencyNode.type === 'Literal') {
1135
- if (typeof declaredDependencyNode.value === 'string') {
1243
+ if (dependencies.has(declaredDependencyNode.value)) {
1136
1244
  context.report({
1137
1245
  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?')
1246
+ 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
1247
  });
1140
1248
  } else {
1141
1249
  context.report({
1142
1250
  node: declaredDependencyNode,
1143
- message: 'The \'' + declaredDependencyNode.raw + '\' literal is not a valid dependency ' + 'because it never changes. You can safely remove it.'
1251
+ message: 'The ' + declaredDependencyNode.raw + ' literal is not a valid dependency ' + 'because it never changes. You can safely remove it.'
1144
1252
  });
1145
1253
  }
1146
1254
  } else {
@@ -1176,51 +1284,17 @@ var ExhaustiveDeps = {
1176
1284
  });
1177
1285
  }
1178
1286
 
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({
1287
+ var _collectRecommendatio2 = collectRecommendations({
1214
1288
  dependencies: dependencies,
1215
1289
  declaredDependencies: declaredDependencies,
1216
1290
  optionalDependencies: optionalDependencies,
1217
1291
  externalDependencies: externalDependencies,
1218
1292
  isEffect: isEffect
1219
1293
  }),
1220
- suggestedDependencies = _collectRecommendatio.suggestedDependencies,
1221
- unnecessaryDependencies = _collectRecommendatio.unnecessaryDependencies,
1222
- missingDependencies = _collectRecommendatio.missingDependencies,
1223
- duplicateDependencies = _collectRecommendatio.duplicateDependencies;
1294
+ suggestedDependencies = _collectRecommendatio2.suggestedDependencies,
1295
+ unnecessaryDependencies = _collectRecommendatio2.unnecessaryDependencies,
1296
+ missingDependencies = _collectRecommendatio2.missingDependencies,
1297
+ duplicateDependencies = _collectRecommendatio2.duplicateDependencies;
1224
1298
 
1225
1299
  var problemCount = duplicateDependencies.size + missingDependencies.size + unnecessaryDependencies.size;
1226
1300
 
@@ -1233,9 +1307,9 @@ var ExhaustiveDeps = {
1233
1307
  componentScope: componentScope,
1234
1308
  scope: scope
1235
1309
  });
1236
- bareFunctions.forEach(function (_ref3) {
1237
- var fn = _ref3.fn,
1238
- suggestUseCallback = _ref3.suggestUseCallback;
1310
+ bareFunctions.forEach(function (_ref4) {
1311
+ var fn = _ref4.fn,
1312
+ suggestUseCallback = _ref4.suggestUseCallback;
1239
1313
 
1240
1314
  var message = 'The \'' + fn.name.name + '\' function makes the dependencies of ' + (reactiveHookName + ' Hook (at line ' + declaredDependenciesNode.loc.start.line + ') ') + 'change on every render.';
1241
1315
  if (suggestUseCallback) {
@@ -1243,7 +1317,10 @@ var ExhaustiveDeps = {
1243
1317
  } else {
1244
1318
  message += ' Move it inside the ' + reactiveHookName + ' callback. ' + ('Alternatively, wrap the \'' + fn.name.name + '\' definition into its own useCallback() Hook.');
1245
1319
  }
1320
+ // TODO: What if the function needs to change on every render anyway?
1321
+ // Should we suggest removing effect deps as an appropriate fix too?
1246
1322
  context.report({
1323
+ // TODO: Why not report this at the dependency site?
1247
1324
  node: fn.node,
1248
1325
  message: message,
1249
1326
  fix: function (fixer) {
@@ -1253,10 +1330,10 @@ var ExhaustiveDeps = {
1253
1330
  return [
1254
1331
  // TODO: also add an import?
1255
1332
  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.
1333
+ // TODO: ideally we'd gather deps here but it would require
1334
+ // restructuring the rule code. This will cause a new lint
1335
+ // error to appear immediately for useCallback. Note we're
1336
+ // not adding [] because would that changes semantics.
1260
1337
  fixer.insertTextAfter(fn.node.init, ')')];
1261
1338
  }
1262
1339
  }
@@ -1317,13 +1394,13 @@ var ExhaustiveDeps = {
1317
1394
  }
1318
1395
  });
1319
1396
  if (badRef !== null) {
1320
- extraWarning = ' Mutable values like \'' + badRef + '\' aren\'t valid dependencies ' + "because their mutation doesn't re-render the component.";
1397
+ extraWarning = ' Mutable values like \'' + badRef + '\' aren\'t valid dependencies ' + "because mutating them doesn't re-render the component.";
1321
1398
  } else if (externalDependencies.size > 0) {
1322
1399
  var dep = Array.from(externalDependencies)[0];
1323
1400
  // Don't show this warning for things that likely just got moved *inside* the callback
1324
1401
  // because in that case they're clearly not referring to globals.
1325
1402
  if (!scope.set.has(dep)) {
1326
- extraWarning = ' Outer scope values like \'' + dep + '\' aren\'t valid dependencies ' + 'because their mutation doesn\'t re-render the component.';
1403
+ extraWarning = ' Outer scope values like \'' + dep + '\' aren\'t valid dependencies ' + 'because mutating them doesn\'t re-render the component.';
1327
1404
  }
1328
1405
  }
1329
1406
  }
@@ -1359,7 +1436,7 @@ var ExhaustiveDeps = {
1359
1436
  }
1360
1437
  }
1361
1438
  if (isPropsOnlyUsedInMembers) {
1362
- 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.';
1439
+ 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) + '.');
1363
1440
  }
1364
1441
  }
1365
1442
 
@@ -1401,7 +1478,7 @@ var ExhaustiveDeps = {
1401
1478
  missingCallbackDep = missingDep;
1402
1479
  });
1403
1480
  if (missingCallbackDep !== null) {
1404
- extraWarning = ' If specifying \'' + missingCallbackDep + '\'' + ' makes the dependencies change too often, ' + 'find the parent component that defines it ' + 'and wrap that definition in useCallback.';
1481
+ extraWarning = ' If \'' + missingCallbackDep + '\' changes too often, ' + 'find the parent component that defines it ' + 'and wrap that definition in useCallback.';
1405
1482
  }
1406
1483
  }
1407
1484
 
@@ -1469,10 +1546,10 @@ var ExhaustiveDeps = {
1469
1546
  extraWarning = ' You can also replace multiple useState variables with useReducer ' + ('if \'' + setStateRecommendation.setter + '\' needs the ') + ('current value of \'' + setStateRecommendation.missingDep + '\'.');
1470
1547
  break;
1471
1548
  case 'inlineReducer':
1472
- extraWarning = ' You can also replace useState with an inline useReducer ' + ('if \'' + setStateRecommendation.setter + '\' needs the ') + ('current value of \'' + setStateRecommendation.missingDep + '\'.');
1549
+ 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.');
1473
1550
  break;
1474
1551
  case 'updater':
1475
- extraWarning = ' You can also write \'' + setStateRecommendation.setter + '(' + setStateRecommendation.missingDep + ' => ...)\' if you only use \'' + setStateRecommendation.missingDep + '\'' + (' for the \'' + setStateRecommendation.setter + '\' call.');
1552
+ 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.');
1476
1553
  break;
1477
1554
  default:
1478
1555
  throw new Error('Unknown case.');
@@ -1495,12 +1572,12 @@ var ExhaustiveDeps = {
1495
1572
  };
1496
1573
 
1497
1574
  // The meat of the logic.
1498
- function collectRecommendations(_ref4) {
1499
- var dependencies = _ref4.dependencies,
1500
- declaredDependencies = _ref4.declaredDependencies,
1501
- optionalDependencies = _ref4.optionalDependencies,
1502
- externalDependencies = _ref4.externalDependencies,
1503
- isEffect = _ref4.isEffect;
1575
+ function collectRecommendations(_ref5) {
1576
+ var dependencies = _ref5.dependencies,
1577
+ declaredDependencies = _ref5.declaredDependencies,
1578
+ optionalDependencies = _ref5.optionalDependencies,
1579
+ externalDependencies = _ref5.externalDependencies,
1580
+ isEffect = _ref5.isEffect;
1504
1581
 
1505
1582
  // Our primary data structure.
1506
1583
  // It is a logical representation of property chains:
@@ -1533,8 +1610,8 @@ function collectRecommendations(_ref4) {
1533
1610
 
1534
1611
  // Mark all satisfied nodes.
1535
1612
  // Imagine checkmarks next to each declared dependency.
1536
- declaredDependencies.forEach(function (_ref5) {
1537
- var key = _ref5.key;
1613
+ declaredDependencies.forEach(function (_ref6) {
1614
+ var key = _ref6.key;
1538
1615
 
1539
1616
  var node = getOrCreateNodeByPath(depTree, key);
1540
1617
  node.isSatisfiedRecursively = true;
@@ -1650,8 +1727,8 @@ function collectRecommendations(_ref4) {
1650
1727
  var suggestedDependencies = [];
1651
1728
  var unnecessaryDependencies = new Set();
1652
1729
  var duplicateDependencies = new Set();
1653
- declaredDependencies.forEach(function (_ref6) {
1654
- var key = _ref6.key;
1730
+ declaredDependencies.forEach(function (_ref7) {
1731
+ var key = _ref7.key;
1655
1732
 
1656
1733
  // Does this declared dep satsify a real need?
1657
1734
  if (satisfyingDependencies.has(key)) {
@@ -1693,14 +1770,14 @@ function collectRecommendations(_ref4) {
1693
1770
 
1694
1771
  // Finds functions declared as dependencies
1695
1772
  // that would invalidate on every render.
1696
- function scanForDeclaredBareFunctions(_ref7) {
1697
- var declaredDependencies = _ref7.declaredDependencies,
1698
- declaredDependenciesNode = _ref7.declaredDependenciesNode,
1699
- componentScope = _ref7.componentScope,
1700
- scope = _ref7.scope;
1701
-
1702
- var bareFunctions = declaredDependencies.map(function (_ref8) {
1703
- var key = _ref8.key;
1773
+ function scanForDeclaredBareFunctions(_ref8) {
1774
+ var declaredDependencies = _ref8.declaredDependencies,
1775
+ declaredDependenciesNode = _ref8.declaredDependenciesNode,
1776
+ componentScope = _ref8.componentScope,
1777
+ scope = _ref8.scope;
1778
+
1779
+ var bareFunctions = declaredDependencies.map(function (_ref9) {
1780
+ var key = _ref9.key;
1704
1781
 
1705
1782
  var fnRef = componentScope.set.get(key);
1706
1783
  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,l){l=l.split(".");var k=!0,e=!1,f=void 0;try{for(var g=l[Symbol.iterator](),p;!(k=(p=g.next()).done);k=!0){var t=p.value,h=a.children.get(t);h||(h=b(),a.children.set(t,h));a=h}}catch(D){e=!0,f=D}finally{try{!k&&g.return&&g.return()}finally{if(e)throw f;}}return a}function f(a,l,b){l=l.split(".");var k=!0,e=!1,f=void 0;try{for(var g=l[Symbol.iterator](),h;!(k=(h=g.next()).done);k=
13
- !0){var t=a.children.get(h.value);if(!t)break;b(t);a=t}}catch(D){e=!0,f=D}finally{try{!k&&g.return&&g.return()}finally{if(e)throw f;}}}function l(a,b,g,e){a.children.forEach(function(a,k){var f=e(k);a.isSatisfiedRecursively?a.hasRequiredNodesBelow&&g.add(f):a.isRequired?b.add(f):l(a,b,g,function(a){return f+"."+a})})}var t=a.dependencies,n=a.declaredDependencies,v=a.optionalDependencies,g=a.externalDependencies,r=a.isEffect,B=b();t.forEach(function(a,l){e(B,l).isRequired=!0;f(B,l,function(a){a.hasRequiredNodesBelow=
14
- !0})});n.forEach(function(a){e(B,a.key).isSatisfiedRecursively=!0});v.forEach(function(a){e(B,a).isSatisfiedRecursively=!0});a=new Set;var h=new Set;l(B,a,h,function(a){return a});var y=[],C=new Set,E=new Set;n.forEach(function(a){a=a.key;h.has(a)?-1===y.indexOf(a)?y.push(a):E.add(a):!r||a.endsWith(".current")||g.has(a)?C.add(a):-1===y.indexOf(a)&&y.push(a)});a.forEach(function(a){y.push(a)});return{suggestedDependencies:y,unnecessaryDependencies:C,duplicateDependencies:E,missingDependencies:a}}
15
- function ca(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 l=!1,v=
16
- 0;v<a.references.length;v++){var g=a.references[v];if(g.writeExpr)if(l){a=!0;break a}else{l=!0;continue}for(var r=g.from;r!==f&&null!=r;)r=r.upper;if(r!==f&&!da(b,g.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(f){if(/Unsupported node type/.test(f.message))return 0;throw f;}return b.additionalHooks.test(a)?0:-1}return-1}}
19
- function Z(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(da(f,b)){a=!0;var l=!1,t=void 0;try{for(var n=Object.entries(f)[Symbol.iterator](),v;!(a=(v=n.next()).done);a=!0){var g=v.value,r=g[1];"parent"!==g[0]&&(ja(r)?(r.parent=f,e.push(r)):Array.isArray(r)&&r.forEach(function(a){ja(a)&&(a.parent=f,e.push(a))}))}}catch(B){l=!0,t=B}finally{try{!a&&n.return&&n.return()}finally{if(l)throw t;}}}}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 f(a){var c=f.cache,d=c.get(a.id);if(null===d){if(!r.has(a.id)){r.add(a.id);c=!0;d=!1;var w=void 0;try{for(var q=a.prevSegments[Symbol.iterator](),b;!(c=(b=q.next()).done);c=!0)f(b.value)}catch(L){d=!0,w=L}finally{try{!c&&q.return&&
22
- q.return()}finally{if(d)throw w;}}}return 0}if(void 0!==d)return d;c.set(a.id,null);if(e.thrownSegments.includes(a))d=0;else if(0===a.prevSegments.length)d=1;else{d=0;q=!0;b=!1;var g=void 0;try{w=a.prevSegments[Symbol.iterator]();for(var m;!(q=(m=w.next()).done);q=!0)d+=f(m.value)}catch(L){b=!0,g=L}finally{try{!q&&w.return&&w.return()}finally{if(b)throw g;}}}a.reachable&&0===d?c.delete(a.id):c.set(a.id,d);return d}function n(a){var c=n.cache,d=c.get(a.id);if(null===d){if(!r.has(a.id)){r.add(a.id);
23
- c=!0;d=!1;var w=void 0;try{for(var q=a.nextSegments[Symbol.iterator](),b;!(c=(b=q.next()).done);c=!0)n(b.value)}catch(L){d=!0,w=L}finally{try{!c&&q.return&&q.return()}finally{if(d)throw w;}}}return 0}if(void 0!==d)return d;c.set(a.id,null);if(e.thrownSegments.includes(a))d=0;else if(0===a.nextSegments.length)d=1;else{d=0;q=!0;b=!1;var g=void 0;try{w=a.nextSegments[Symbol.iterator]();for(var f;!(q=(f=w.next()).done);q=!0)d+=n(f.value)}catch(L){b=!0,g=L}finally{try{!q&&w.return&&w.return()}finally{if(b)throw g;
24
- }}}c.set(a.id,d);return d}function v(a){var c=v.cache,d=c.get(a.id);if(null===d)return Infinity;if(void 0!==d)return d;c.set(a.id,null);if(0===a.prevSegments.length)d=1;else{d=Infinity;var w=!0,q=!1,b=void 0;try{for(var g=a.prevSegments[Symbol.iterator](),e;!(w=(e=g.next()).done);w=!0){var f=v(e.value);f<d&&(d=f)}}catch(la){q=!0,b=la}finally{try{!w&&g.return&&g.return()}finally{if(q)throw b;}}d+=1}c.set(a.id,d);return d}var g=b.pop();if(0!==g.size){var r=new Set;f.cache=new Map;n.cache=new Map;v.cache=
25
- new Map;var B=n(e.initialSegment),h=W(l),y=aa(l),C=h?U(h)||Q(h):!1,E=Infinity,k=!0,p=!1,H=void 0;try{for(var x=e.finalSegments[Symbol.iterator](),J;!(k=(J=x.next()).done);k=!0){var V=J.value;if(V.reachable){var P=v(V);P<E&&(E=P)}}}catch(m){p=!0,H=m}finally{try{!k&&x.return&&x.return()}finally{if(p)throw H;}}k=!0;p=!1;H=void 0;try{for(var A=g[Symbol.iterator](),K;!(k=(K=A.next()).done);k=!0){var D=K.value,F=D[0],R=D[1];if(F.reachable){var I=0===F.nextSegments.length?E<=v(F):E<v(F),S=f(F)*n(F),G=r.has(F.id);
26
- g=!0;x=!1;J=void 0;try{for(var z=R[Symbol.iterator](),M;!(g=(M=z.next()).done);g=!0){var u=M.value;G&&a.report({node:u,message:'React Hook "'+a.getSource(u)+'" 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(C){if(!G&&S!==B){var T='React Hook "'+a.getSource(u)+'" 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?":
27
- "");a.report({node:u,message:T})}}else if(!l.parent||"MethodDefinition"!==l.parent.type&&"ClassProperty"!==l.parent.type||l.parent.value!==l)if(h){var N='React Hook "'+a.getSource(u)+'" is called in '+('function "'+a.getSource(h)+'" ')+"which is neither a React function component or a custom React Hook function.";a.report({node:u,message:N})}else if("Program"!==l.type&&y){var O='React Hook "'+a.getSource(u)+'" 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:u,message:O})}}}catch(m){x=!0,J=m}finally{try{!g&&z.return&&z.return()}finally{if(x)throw J;}}}}}catch(m){p=!0,H=m}finally{try{!k&&A.return&&A.return()}finally{if(p)throw H;}}}},CallExpression:function(a){if(Q(a.callee)){var f=b[b.length-1],t=e[e.length-1],n=f.get(t);n||(n=[],f.set(t,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 g=a(e);b.set(e,g);return g}}function e(e){function g(a){var d=!0,c=!1,q=void 0;try{for(var b=a.references[Symbol.iterator](),f;!(d=(f=b.next()).done);d=!0){var h=f.value;if(h.resolved&&H.has(h.resolved.scope)){var l=Z(e,h.identifier),k=ea(l),m=Y(k),p;if(p=E&&"Identifier"===k.type&&"MemberExpression"===k.parent.type&&!k.parent.computed&&"Identifier"===k.parent.property.type&&"current"===k.parent.property.name){for(var n=h.from,r=!1;n.block!==e;)"function"===n.type&&(r=null!=n.block.parent&&"ReturnStatement"===
30
- n.block.parent.type),n=n.upper;p=r}p&&P.set(m,{reference:h,dependencyNode:k});if(A.has(m))A.get(m).references.push(h);else{var t=h.resolved,v=J(t)||V(t);A.set(m,{isStatic:v,references:[h]})}}}}catch(X){c=!0,q=X}finally{try{!d&&b.return&&b.return()}finally{if(c)throw q;}}d=!0;c=!1;q=void 0;try{for(var u=a.childScopes[Symbol.iterator](),x;!(d=(x=u.next()).done);d=!0)g(x.value)}catch(X){c=!0,q=X}finally{try{!d&&u.return&&u.return()}finally{if(c)throw q;}}}function B(a,d,w,b){return 0===a.size?null:(1<
31
- a.size?"":d+" ")+w+" "+(1<a.size?"dependencies":"dependency")+": "+ka(Array.from(a).sort().map(function(a){return"'"+a+"'"}))+(". Either "+b+" "+(1<a.size?"them":"it")+" or remove the dependency array.")}if(("FunctionExpression"===e.type||"ArrowFunctionExpression"===e.type)&&"CallExpression"===e.parent.type){var h=ia(e.parent.callee,f);if(e.parent.arguments[h]===e){var y=e.parent.callee,C=ha(y).name,E=C.endsWith("Effect"),k=e.parent.arguments[h+1];if(k){var p=a.getScope(),H=new Set,x=null;for(h=p.upper;h;){H.add(h);
32
- if("function"===h.type)break;h=h.upper}if(h){x=h;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 c=d.node.init;if(null==c)return!1;var b=d.node.parent;if(null==b&&(Z(x.block,d.node.id),b=d.node.parent,null==b))return!1;if("const"===b.kind&&"Literal"===c.type&&("string"===typeof c.value||"number"===typeof c.value||null===c.value))return!0;if("CallExpression"!==c.type)return!1;c=c.callee;"MemberExpression"!==c.type||
33
- "React"!==c.object.name||null==c.property||c.computed||(c=c.property);if("Identifier"!==c.type)return!1;d=d.node.id;c=c.name;if("useRef"===c&&"Identifier"===d.type)return!0;if(("useState"===c||"useReducer"===c)&&"ArrayPattern"===d.type&&2===d.elements.length&&Array.isArray(a.identifiers)){if(d.elements[1]===a.identifiers[0]){if("useState"===c)for(a=a.references,c=0;c<a.length;c++)l.set(a[c].identifier,d.elements[0]);return!0}if(d.elements[0]===a.identifiers[0]&&"useState"===c)for(a=a.references,d=
34
- 0;d<a.length;d++)t.add(a[d].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 d=a.node,c=x.childScopes;a=null;var b;for(b=0;b<c.length;b++){var e=c[b],f=e.block;if("FunctionDeclaration"===d.type&&f===d||"VariableDeclarator"===d.type&&f.parent===d){a=e;break}}if(null==a)return!1;for(b=0;b<a.through.length;b++)if(d=a.through[b],null!=d.resolved&&H.has(d.resolved.scope)&&!J(d.resolved))return!1;return!0},v),
35
- P=new Map,A=new Map;g(p);P.forEach(function(c,d){var b=c.dependencyNode;c=c.reference.resolved.references;for(var e=!1,f=0;f<c.length;f++){var g=c[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 '"+d+".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
- ("'"+d+".current' in a variable inside ")+"the effect itself and refer to that variable from the cleanup function."})});var K=[],D=new Set;"ArrayExpression"!==k.type?a.report({node:k,message:"React Hook "+a.getSource(y)+" has a second argument which is not an array literal. This means we can't statically verify whether you've passed the correct dependencies."}):k.elements.forEach(function(c){if(null!==c)if("SpreadElement"===c.type)a.report({node:c,message:"React Hook "+a.getSource(y)+" 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 d=void 0;try{d=Y(c)}catch(fa){if(/Unsupported node type/.test(fa.message)){"Literal"===c.type?"string"===typeof c.value?a.report({node:c,message:"The "+c.raw+" string literal is not a valid dependency because it never changes. Did you mean to "+("include "+c.value+" in the array instead?")}):a.report({node:c,message:"The '"+c.raw+"' literal is not a valid dependency because it never changes. You can safely remove it."}):a.report({node:c,message:"React Hook "+a.getSource(y)+" 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=c;"MemberExpression"===b.type;)b=b.object;var e=!x.through.some(function(a){return a.identifier===b});K.push({key:d,node:c});e||D.add(d)}});var F=new Set,R=new Set;A.forEach(function(c,d){var b=c.references;c.isStatic&&R.add(d);b.forEach(function(c){c.writeExpr&&(c=c.writeExpr,F.has(d)||(F.add(d),a.report({node:c,message:"Assignments to the '"+d+"' variable from inside a React "+a.getSource(y)+" 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<F.size)){var I=ba({dependencies:A,declaredDependencies:K,optionalDependencies:R,externalDependencies:D,isEffect:E}),S=I.suggestedDependencies;h=I.unnecessaryDependencies;var G=I.missingDependencies;I=I.duplicateDependencies;if(0===I.size+G.size+h.size)ca({declaredDependencies:K,declaredDependenciesNode:k,componentScope:x,scope:p}).forEach(function(c){var d=c.fn,b=c.suggestUseCallback;c="The '"+d.name.name+"' function makes the dependencies of "+(C+" Hook (at line "+k.loc.start.line+") ")+"change on every render.";
40
- c=b?c+(" To fix this, "+("wrap the '"+d.name.name+"' definition into its own useCallback() Hook.")):c+(" Move it inside the "+C+" callback. "+("Alternatively, wrap the '"+d.name.name+"' definition into its own useCallback() Hook."));a.report({node:d.node,message:c,fix:function(a){if(b&&"Variable"===d.type)return[a.insertTextBefore(d.node.init,"useCallback("),a.insertTextAfter(d.node.init,")")]}})});else{!E&&0<G.size&&(S=ba({dependencies:A,declaredDependencies:[],optionalDependencies:R,externalDependencies:D,
41
- isEffect:E}).suggestedDependencies);(function(){if(0===K.length)return!0;var a=K.map(function(a){return a.key}),d=a.slice().sort();return a.join(",")===d.join(",")})()&&S.sort();var z="";if(0<h.size){var M=null;Array.from(h.keys()).forEach(function(a){null===M&&a.endsWith(".current")&&(M=a)});if(null!==M)z=" Mutable values like '"+M+"' aren't valid dependencies because their mutation doesn't re-render the component.";else if(0<D.size){var u=Array.from(D)[0];p.set.has(u)||(z=" Outer scope values like '"+
42
- u+"' aren't valid dependencies because their mutation doesn't re-render the component.")}}if(!z&&G.has("props")){p=A.get("props");if(null==p)return;p=p.references;if(!Array.isArray(p))return;u=!0;for(var T=0;T<p.length;T++){var N=Z(x.block,p[T].identifier);if(!N){u=!1;break}N=N.parent;if(null==N){u=!1;break}if("MemberExpression"!==N.type){u=!1;break}}u&&(z=" However, the preferred fix is to destructure the 'props' "+("object outside of the "+C+" call and ")+"refer to specific props directly by their names.")}if(!z&&
43
- 0<G.size){var O=null;G.forEach(function(a){if(!O){var d=x.set.get(a),b=A.get(a);if(b.references[0].resolved===d&&(d=d.defs[0],null!=d&&null!=d.name&&"Parameter"===d.type)){d=!1;for(var c,e=0;e<b.references.length;e++)if(c=b.references[e].identifier,null!=c&&null!=c.parent&&"CallExpression"===c.parent.type&&c.parent.callee===c){d=!0;break}d&&(O=a)}}});null!==O&&(z=" If specifying '"+O+"' makes the dependencies change too often, find the parent component that defines it and wrap that definition in useCallback.")}if(!z&&
44
- 0<G.size){var m=null;G.forEach(function(a){if(null===m)for(var d=A.get(a).references,b,c,e=0;e<d.length;e++){b=d[e].identifier;for(c=b.parent;null!=c&&c!==x.block;){if("CallExpression"===c.type){var f=l.get(c.callee);if(null!=f){f.name===a?m={missingDep:a,setter:c.callee.name,form:"updater"}:t.has(b)?m={missingDep:a,setter:c.callee.name,form:"reducer"}:(b=d[e].resolved,null!=b&&(b=b.defs[0],null!=b&&"Parameter"===b.type&&(m={missingDep:a,setter:c.callee.name,form:"inlineReducer"})));break}}c=c.parent}if(null!==
45
- m)break}});if(null!==m)switch(m.form){case "reducer":z=" You can also replace multiple useState variables with useReducer "+("if '"+m.setter+"' needs the ")+("current value of '"+m.missingDep+"'.");break;case "inlineReducer":z=" You can also replace useState with an inline useReducer "+("if '"+m.setter+"' needs the ")+("current value of '"+m.missingDep+"'.");break;case "updater":z=" You can also write '"+m.setter+"("+m.missingDep+" => ...)' if you only use '"+m.missingDep+"'"+(" for the '"+m.setter+
46
- "' call.");break;default:throw Error("Unknown case.");}}a.report({node:k,message:"React Hook "+a.getSource(y)+" has "+(B(G,"a","missing","include")||B(h,"an","unnecessary","exclude")||B(I,"a","duplicate","omit"))+z,fix:function(a){return a.replaceText(k,"["+S.join(", ")+"]")}})}}}}else"useMemo"!==C&&"useCallback"!==C||a.report({node:e.parent.callee,message:"React Hook "+C+" 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 "+
47
- C+".")})}}}var f={additionalHooks:a.options&&a.options[0]&&a.options[0].additionalHooks?new RegExp(a.options[0].additionalHooks):void 0},l=new WeakMap,t=new WeakSet,n=new WeakMap,v=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,r=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});r.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,r=
17
+ 0;r<a.references.length;r++){var c=a.references[r];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](),r;!(a=(r=q.next()).done);a=!0){var c=r.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](),t;!(b=(t=m.next()).done);b=!0)f(t.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;t=!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){t=!0,H=K}finally{try{!m&&d.return&&d.return()}finally{if(t)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](),t;!(b=(t=m.next()).done);b=!0)q(t.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;t=!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){t=!0,H=K}finally{try{!m&&d.return&&d.return()}finally{if(t)throw H;
25
+ }}}b.set(a.id,c);return c}function r(a){var c=r.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,t=void 0;try{for(var H=a.prevSegments[Symbol.iterator](),e;!(d=(e=H.next()).done);d=!0){var f=r(e.value);f<b&&(b=f)}}catch(na){m=!0,t=na}finally{try{!d&&H.return&&H.return()}finally{if(m)throw t;}}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;r.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=r(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<=r(D):B<r(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,t=!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 r=g.resolved.defs[0];if((null==r||null==r.node||r.node.init!==c.parent)&&"TypeParameter"!==r.type)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){t=!0,b=Z}finally{try{!d&&f.return&&f.return()}finally{if(t)throw b;}}d=!0;t=!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){t=!0,b=Z}finally{try{!d&&
32
+ w.return&&w.return()}finally{if(t)throw b;}}}function C(a,b,t,c){return 0===a.size?null:(1<a.size?"":b+" ")+t+" "+(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"),
33
+ l=c.parent.arguments[g+1];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=
34
+ new Set,w=null;for(g=p.upper;g;){G.add(g);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;
35
+ b=b.callee;"MemberExpression"!==b.type||"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]&&
36
+ "useState"===b)for(a=a.references,d=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;
37
+ return!0},r),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,r=
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.1",
4
+ "version": "1.6.1",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/facebook/react.git",
@@ -29,6 +29,6 @@
29
29
  },
30
30
  "homepage": "https://reactjs.org/",
31
31
  "peerDependencies": {
32
- "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0"
32
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0"
33
33
  }
34
34
  }