@agilebot/eslint-plugin 0.5.3 → 0.5.5

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 +43 -18
  2. package/package.json +4 -5
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.5
3
3
  *
4
4
  * Copyright (c) Agilebot, Inc. and its affiliates.
5
5
  *
@@ -34,8 +34,8 @@ function _interopNamespaceDefault(e) {
34
34
  var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
35
35
  var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
36
36
 
37
- const rule$1 = require('eslint-plugin-deprecation/dist/rules/deprecation')["default"];
38
- const compatRule$1 = compat.fixupRule(rule$1);
37
+ const rule = require('eslint-plugin-deprecation/dist/rules/deprecation')["default"];
38
+ const compatRule = compat.fixupRule(rule);
39
39
 
40
40
  const docBaseUrl = 'https://github.com/sh-agilebot/frontend-toolkit/blob/master/packages/eslint-plugin/src/rules/';
41
41
  const hasDocs = typeof ["enforce-mui-icon-alias","intl-id-missing","intl-id-prefix","intl-no-default","react-better-exhaustive-deps"] !== 'undefined' ?
@@ -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';
@@ -2203,11 +2234,6 @@ var reactPreferSxProp = createRule({
2203
2234
  }
2204
2235
  });
2205
2236
 
2206
- const pluginReactHooks = require('eslint-plugin-react-hooks');
2207
- const rule = pluginReactHooks.rules['rules-of-hooks'];
2208
- const compatRule = compat.fixupRule(rule);
2209
- compatRule.meta.docs.recommended = false;
2210
-
2211
2237
  function getBasicIdentifier(node) {
2212
2238
  if (node.type === 'Identifier') {
2213
2239
  return node.name;
@@ -2903,7 +2929,7 @@ var varNaming = createRule({
2903
2929
 
2904
2930
  var ruleFiles = /*#__PURE__*/Object.freeze({
2905
2931
  __proto__: null,
2906
- rules_deprecation: compatRule$1,
2932
+ rules_deprecation: compatRule,
2907
2933
  rules_enforce_mui_icon_alias: enforceMuiIconAlias,
2908
2934
  rules_import_monorepo: importMonorepo,
2909
2935
  rules_intl_id_missing: intlIdMissing,
@@ -2919,7 +2945,6 @@ var ruleFiles = /*#__PURE__*/Object.freeze({
2919
2945
  rules_react_hook_use_ref: reactHookUseRef,
2920
2946
  rules_react_prefer_named_property_access: reactPreferNamedPropertyAccess,
2921
2947
  rules_react_prefer_sx_prop: reactPreferSxProp,
2922
- rules_react_rules_of_hooks: compatRule,
2923
2948
  rules_tss_class_naming: tssClassNaming,
2924
2949
  rules_tss_no_color_name: tssNoColorName,
2925
2950
  rules_tss_no_color_value: tssNoColorValue,
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.5",
4
4
  "description": "Agilebot's ESLint plugin",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,12 +18,11 @@
18
18
  "node": "^18.18.0 || >=20.0.0"
19
19
  },
20
20
  "dependencies": {
21
- "@eslint/compat": "^1.1.1",
21
+ "@eslint/compat": "^1.2.1",
22
22
  "@typescript-eslint/utils": "~8.7.0",
23
23
  "eslint-plugin-deprecation": "^3.0.0",
24
- "eslint-plugin-react": "^7.35.0",
25
- "eslint-plugin-react-hooks": "^4.6.2",
26
- "@agilebot/eslint-utils": "0.5.3"
24
+ "eslint-plugin-react": "^7.37.2",
25
+ "@agilebot/eslint-utils": "0.5.5"
27
26
  },
28
27
  "peerDependencies": {
29
28
  "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"