@agilebot/eslint-plugin 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. package/dist/index.js +40 -9
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license @agilebot/eslint-plugin v0.5.3
2
+ * @license @agilebot/eslint-plugin v0.5.4
3
3
  *
4
4
  * Copyright (c) Agilebot, Inc. and its affiliates.
5
5
  *
@@ -859,6 +859,7 @@ var reactBetterExhaustiveDeps = {
859
859
  const stateVariables = new WeakSet();
860
860
  const stableKnownValueCache = new WeakMap();
861
861
  const functionWithoutCapturedValueCache = new WeakMap();
862
+ const useEffectEventVariables = new WeakSet();
862
863
  function memoizeWithWeakMap(fn, map) {
863
864
  return function (arg) {
864
865
  if (map.has(arg)) {
@@ -882,7 +883,7 @@ var reactBetterExhaustiveDeps = {
882
883
  if (!isCustomHook) {
883
884
  reportProblem({
884
885
  node: node,
885
- 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://reactjs.org/link/hooks-data-fetching'
886
+ 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://react.dev/link/hooks-data-fetching'
886
887
  });
887
888
  }
888
889
  }
@@ -921,7 +922,7 @@ var reactBetterExhaustiveDeps = {
921
922
  if (init == null) {
922
923
  return false;
923
924
  }
924
- while (init.type === 'TSAsExpression') {
925
+ while (init.type === 'TSAsExpression' || init.type === 'AsExpression') {
925
926
  init = init.expression;
926
927
  }
927
928
  let declaration = def.node.parent;
@@ -951,7 +952,14 @@ var reactBetterExhaustiveDeps = {
951
952
  } = callee;
952
953
  if (name === 'useRef' && id.type === 'Identifier') {
953
954
  return true;
954
- } else if (name === 'useState' || name === 'useReducer') {
955
+ } else if (isUseEffectEventIdentifier() && id.type === 'Identifier') {
956
+ for (const ref of resolved.references) {
957
+ if (ref !== id) {
958
+ useEffectEventVariables.add(ref.identifier);
959
+ }
960
+ }
961
+ return true;
962
+ } else if (name === 'useState' || name === 'useReducer' || name === 'useActionState') {
955
963
  if (id.type === 'ArrayPattern' && id.elements.length === 2 && isArray(resolved.identifiers)) {
956
964
  if (id.elements[1] === resolved.identifiers[0]) {
957
965
  if (name === 'useState') {
@@ -1238,13 +1246,16 @@ var reactBetterExhaustiveDeps = {
1238
1246
  }
1239
1247
  const declaredDependencies = [];
1240
1248
  const externalDependencies = new Set();
1241
- if (declaredDependenciesNode.type !== 'ArrayExpression') {
1249
+ const isArrayExpression = declaredDependenciesNode.type === 'ArrayExpression';
1250
+ const isTSAsArrayExpression = declaredDependenciesNode.type === 'TSAsExpression' && declaredDependenciesNode.expression.type === 'ArrayExpression';
1251
+ if (!isArrayExpression && !isTSAsArrayExpression) {
1242
1252
  reportProblem({
1243
1253
  node: declaredDependenciesNode,
1244
1254
  message: "React Hook ".concat(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.'
1245
1255
  });
1246
1256
  } else {
1247
- declaredDependenciesNode.elements.forEach(declaredDependencyNode => {
1257
+ const arrayExpression = isTSAsArrayExpression ? declaredDependenciesNode.expression : declaredDependenciesNode;
1258
+ arrayExpression.elements.forEach(declaredDependencyNode => {
1248
1259
  if (declaredDependencyNode == null) {
1249
1260
  return;
1250
1261
  }
@@ -1255,6 +1266,18 @@ var reactBetterExhaustiveDeps = {
1255
1266
  });
1256
1267
  return;
1257
1268
  }
1269
+ if (useEffectEventVariables.has(declaredDependencyNode)) {
1270
+ reportProblem({
1271
+ node: declaredDependencyNode,
1272
+ message: 'Functions returned from `useEffectEvent` must not be included in the dependency array. ' + "Remove `".concat(getSource(declaredDependencyNode), "` from the list."),
1273
+ suggest: [{
1274
+ desc: "Remove the dependency `".concat(getSource(declaredDependencyNode), "`"),
1275
+ fix(fixer) {
1276
+ return fixer.removeRange(declaredDependencyNode.range);
1277
+ }
1278
+ }]
1279
+ });
1280
+ }
1258
1281
  let declaredDependency;
1259
1282
  try {
1260
1283
  declaredDependency = analyzePropertyChain(declaredDependencyNode, null);
@@ -1532,7 +1555,8 @@ var reactBetterExhaustiveDeps = {
1532
1555
  extraWarning = " If '".concat(setStateRecommendation.setter, "' needs the ") + "current value of '".concat(setStateRecommendation.missingDep, "', ") + "you can also switch to useReducer instead of useState and " + "read '".concat(setStateRecommendation.missingDep, "' in the reducer.");
1533
1556
  break;
1534
1557
  case 'updater':
1535
- extraWarning = " You can also do a functional update '".concat(setStateRecommendation.setter, "(").concat(setStateRecommendation.missingDep.slice(0, 1), " => ...)' if you only need '").concat(setStateRecommendation.missingDep, "' in the '").concat(setStateRecommendation.setter, "' call.");
1558
+ extraWarning = " You can also do a functional update '".concat(setStateRecommendation.setter, "(").concat(setStateRecommendation.missingDep.slice(0, 1), " => ...)' if you only need '").concat(setStateRecommendation.missingDep
1559
+ , "'") + " in the '".concat(setStateRecommendation.setter, "' call.");
1536
1560
  break;
1537
1561
  default:
1538
1562
  throw new Error('Unknown case.');
@@ -1559,7 +1583,8 @@ var reactBetterExhaustiveDeps = {
1559
1583
  const callback = node.arguments[callbackIndex];
1560
1584
  const reactiveHook = node.callee;
1561
1585
  const reactiveHookName = getNodeWithoutReactNamespace(reactiveHook).name;
1562
- const declaredDependenciesNode = node.arguments[callbackIndex + 1];
1586
+ const maybeNode = node.arguments[callbackIndex + 1];
1587
+ const declaredDependenciesNode = maybeNode && !(maybeNode.type === 'Identifier' && maybeNode.name === 'undefined') ? maybeNode : undefined;
1563
1588
  const isEffect = /Effect($|[^a-z])/g.test(reactiveHookName);
1564
1589
  if (!callback) {
1565
1590
  reportProblem({
@@ -1582,6 +1607,9 @@ var reactBetterExhaustiveDeps = {
1582
1607
  case 'ArrowFunctionExpression':
1583
1608
  visitFunctionWithDependencies(callback, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect);
1584
1609
  return;
1610
+ case 'TSAsExpression':
1611
+ visitFunctionWithDependencies(callback.expression, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect);
1612
+ return;
1585
1613
  case 'Identifier':
1586
1614
  if (!declaredDependenciesNode) {
1587
1615
  return;
@@ -1786,7 +1814,7 @@ function getConstructionExpressionType(node) {
1786
1814
  }
1787
1815
  return null;
1788
1816
  case 'TypeCastExpression':
1789
- return getConstructionExpressionType(node.expression);
1817
+ case 'AsExpression':
1790
1818
  case 'TSAsExpression':
1791
1819
  return getConstructionExpressionType(node.expression);
1792
1820
  }
@@ -2008,6 +2036,9 @@ function isSameIdentifier(a, b) {
2008
2036
  function isAncestorNodeOf(a, b) {
2009
2037
  return a.range[0] <= b.range[0] && a.range[1] >= b.range[1];
2010
2038
  }
2039
+ function isUseEffectEventIdentifier(node) {
2040
+ return false;
2041
+ }
2011
2042
 
2012
2043
  const Components = require('eslint-plugin-react/lib/util/Components');
2013
2044
  const RULE_NAME$7 = 'react-hook-use-ref';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agilebot/eslint-plugin",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Agilebot's ESLint plugin",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "eslint-plugin-deprecation": "^3.0.0",
24
24
  "eslint-plugin-react": "^7.35.0",
25
25
  "eslint-plugin-react-hooks": "^4.6.2",
26
- "@agilebot/eslint-utils": "0.5.3"
26
+ "@agilebot/eslint-utils": "0.5.4"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"