@agilebot/eslint-plugin 0.5.3 → 0.5.5

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.
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"