eslint-plugin-react-x 2.7.4 → 2.7.5-beta.11

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 +34 -53
  2. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { AST_NODE_TYPES } from "@typescript-eslint/types";
3
3
  import { ESLintUtils } from "@typescript-eslint/utils";
4
4
  import { P, isMatching, match } from "ts-pattern";
5
5
  import ts from "typescript";
6
- import { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, JsxEmit, findParentJsxAttribute, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, isAssignmentToThisState, isCaptureOwnerStackCall, isChildrenCount, isChildrenForEach, isChildrenMap, isChildrenOnly, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUpdate, isCreateContextCall, isCreateElementCall, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRefCall, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isJsxFragmentElement, isJsxHostElement, isJsxText, isLazyCall, isReactHookCall, isReactHookName, isRenderFunctionLoose, isRenderMethodLike, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseCall, isUseCallbackCall, isUseContextCall, isUseEffectLikeCall, isUseMemoCall, isUseRefCall, isUseStateCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector } from "@eslint-react/core";
6
+ import { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, JsxEmit, findParentJsxAttribute, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, isAssignmentToThisState, isCaptureOwnerStackCall, isChildrenCount, isChildrenForEach, isChildrenMap, isChildrenOnly, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUpdate, isCreateContextCall, isCreateElementCall, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRefCall, isGetDerivedStateFromError, isGetDerivedStateFromProps, isHookCall, isHookName, isInitializedFromReact, isJsxFragmentElement, isJsxHostElement, isJsxText, isLazyCall, isRenderFunctionLoose, isRenderMethodLike, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseCall, isUseCallbackCall, isUseContextCall, isUseEffectLikeCall, isUseMemoCall, isUseRefCall, isUseStateCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector } from "@eslint-react/core";
7
7
  import * as AST from "@eslint-react/ast";
8
8
  import { findEnclosingAssignmentTarget, findVariable, getChildScopes, getObjectType, getVariableDefinitionNode, isAssignmentTargetEqual } from "@eslint-react/var";
9
9
  import { constFalse, constTrue, flow, getOrElseUpdate, identity, unit } from "@eslint-react/eff";
@@ -68,7 +68,7 @@ const rules$7 = {
68
68
  //#endregion
69
69
  //#region package.json
70
70
  var name$6 = "eslint-plugin-react-x";
71
- var version = "2.7.4";
71
+ var version = "2.7.5-beta.11";
72
72
 
73
73
  //#endregion
74
74
  //#region src/utils/create-rule.ts
@@ -1294,7 +1294,7 @@ function create$35(context) {
1294
1294
  } };
1295
1295
  }
1296
1296
  /**
1297
- * Determines whether the given CallExpression can be safely auto-fixed by replacing
1297
+ * Determine whether the given CallExpression can be safely auto-fixed by replacing
1298
1298
  * the usage of `forwardRef` with passing `ref` as a prop
1299
1299
  *
1300
1300
  * @param context The rule context object
@@ -1471,7 +1471,7 @@ const RULE_NAME$32 = "no-missing-component-display-name";
1471
1471
  var no_missing_component_display_name_default = createRule({
1472
1472
  meta: {
1473
1473
  type: "problem",
1474
- docs: { description: "Enforces that all components have a 'displayName' that can be used in devtools." },
1474
+ docs: { description: "Enforces that all components have a 'displayName' that can be used in DevTools." },
1475
1475
  messages: { noMissingComponentDisplayName: "Add missing 'displayName' for component." },
1476
1476
  schema: []
1477
1477
  },
@@ -1483,7 +1483,6 @@ function create$32(context) {
1483
1483
  if (!context.sourceCode.text.includes("memo") && !context.sourceCode.text.includes("forwardRef")) return {};
1484
1484
  const { ctx, visitor } = useComponentCollector(context, {
1485
1485
  collectDisplayName: true,
1486
- collectHookCalls: false,
1487
1486
  hint: DEFAULT_COMPONENT_DETECTION_HINT
1488
1487
  });
1489
1488
  return defineRuleListener(visitor, { "Program:exit"(program) {
@@ -1506,7 +1505,7 @@ const RULE_NAME$31 = "no-missing-context-display-name";
1506
1505
  var no_missing_context_display_name_default = createRule({
1507
1506
  meta: {
1508
1507
  type: "problem",
1509
- docs: { description: "Enforces that all contexts have a 'displayName' that can be used in devtools." },
1508
+ docs: { description: "Enforces that all contexts have a 'displayName' that can be used in DevTools." },
1510
1509
  fixable: "code",
1511
1510
  messages: { noMissingContextDisplayName: "Add missing 'displayName' for context." },
1512
1511
  schema: []
@@ -1776,7 +1775,7 @@ function create$28(context) {
1776
1775
  } });
1777
1776
  }
1778
1777
  /**
1779
- * Determines whether the node is inside JSX attribute value
1778
+ * Determine whether the node is inside JSX attribute value
1780
1779
  * @param node The AST node to check
1781
1780
  * @returns `true` if the node is inside JSX attribute value
1782
1781
  */
@@ -1784,7 +1783,7 @@ function isInsideJSXAttributeValue(node) {
1784
1783
  return node.parent.type === AST_NODE_TYPES.JSXAttribute || findParentJsxAttribute(node, (n) => n.value?.type === AST_NODE_TYPES.JSXExpressionContainer) != null;
1785
1784
  }
1786
1785
  /**
1787
- * Checks whether a given node is declared inside a class component's render block
1786
+ * Check whether a given node is declared inside a class component's render block
1788
1787
  * Ex: class C extends React.Component { render() { const Nested = () => <div />; } }
1789
1788
  * @param node The AST node being checked
1790
1789
  * @returns `true` if the node is inside a class component's render block
@@ -1793,7 +1792,7 @@ function isInsideRenderMethod(node) {
1793
1792
  return AST.findParentNode(node, (n) => isRenderMethodLike(n) && isClassComponent(n.parent.parent)) != null;
1794
1793
  }
1795
1794
  /**
1796
- * Determines whether the node is inside `createElement`'s props argument
1795
+ * Determine whether the node is inside `createElement`'s props argument
1797
1796
  * @param context The rule context
1798
1797
  * @param node The AST node to check
1799
1798
  * @returns `true` if the node is inside `createElement`'s props
@@ -1835,7 +1834,7 @@ function create$27(context) {
1835
1834
  const classComponents = collectorLegacy.ctx.getAllComponents(program);
1836
1835
  for (const lazy of lazyComponentDeclarations) if (AST.findParentNode(lazy, (n) => {
1837
1836
  if (AST.isJSX(n)) return true;
1838
- if (n.type === AST_NODE_TYPES.CallExpression) return isReactHookCall(n) || isCreateElementCall(context, n) || isCreateContextCall(context, n);
1837
+ if (n.type === AST_NODE_TYPES.CallExpression) return isHookCall(n) || isCreateElementCall(context, n) || isCreateContextCall(context, n);
1839
1838
  if (AST.isFunction(n)) return functionComponents.some((c) => c.node === n);
1840
1839
  if (AST.isClass(n)) return classComponents.some((c) => c.node === n);
1841
1840
  return false;
@@ -2074,7 +2073,7 @@ const RULE_NAME$20 = "no-unnecessary-key";
2074
2073
  var no_unnecessary_key_default = createRule({
2075
2074
  meta: {
2076
2075
  type: "problem",
2077
- docs: { description: "Disallows unnecessary 'key' props on elements." },
2076
+ docs: { description: "Disallows unnecessary 'key' props on nested child elements when rendering lists." },
2078
2077
  messages: { noUnnecessaryKey: "Unnecessary `key` prop on this element. {{reason}}" },
2079
2078
  schema: []
2080
2079
  },
@@ -2088,44 +2087,26 @@ function create$20(context) {
2088
2087
  ...getJsxConfigFromContext(context),
2089
2088
  ...getJsxConfigFromAnnotation(context)
2090
2089
  };
2091
- const { ctx, visitor } = useComponentCollector(context);
2092
- const constantKeys = /* @__PURE__ */ new Set();
2093
- return defineRuleListener(visitor, {
2094
- JSXAttribute(node) {
2095
- if (node.name.name !== "key") return;
2096
- const jsxElement = node.parent.parent;
2097
- if (isJsxFragmentElement(context, jsxElement, jsxConfig)) return;
2098
- if (jsxElement.openingElement.attributes.some((attr) => attr.type === AST_NODE_TYPES.JSXSpreadAttribute)) return;
2099
- if (AST.findParentNode(jsxElement, (n) => isRenderFunctionLoose(context, n)) != null) return;
2100
- const mapCallback = AST.findParentNode(jsxElement, isArrayMethodCallback);
2101
- if (mapCallback == null || AST.findParentNode(jsxElement, AST.isFunction) !== mapCallback) {
2102
- constantKeys.add(node);
2103
- return;
2104
- }
2105
- if (context.sourceCode.getScope(mapCallback) !== context.sourceCode.getScope(jsxElement)) return;
2106
- const keyedElementOrElse = AST.findParentNode(jsxElement, (n) => {
2107
- if (n === mapCallback) return true;
2108
- return AST.isJSXElement(n) && getJsxAttribute(context, n)("key") != null;
2109
- });
2110
- if (keyedElementOrElse == null || keyedElementOrElse === mapCallback) return;
2111
- context.report({
2112
- messageId: "noUnnecessaryKey",
2113
- node,
2114
- data: { reason: "A parent element already has a `key` prop in the same list rendering context." }
2115
- });
2116
- },
2117
- "Program:exit"(node) {
2118
- const components = ctx.getAllComponents(node);
2119
- for (const key of constantKeys) {
2120
- if (AST.findParentNode(key, (n) => AST.isConditional(n) || AST.isControlFlow(n) || findEnclosingAssignmentTarget(n) != null || components.some((comp) => comp.node === n && comp.rets.length > 1)) != null) continue;
2121
- context.report({
2122
- messageId: "noUnnecessaryKey",
2123
- node: key,
2124
- data: { reason: "The `key` prop is not needed outside of dynamic rendering contexts." }
2125
- });
2126
- }
2127
- }
2128
- });
2090
+ return { JSXAttribute(node) {
2091
+ if (node.name.name !== "key") return;
2092
+ const jsxElement = node.parent.parent;
2093
+ if (isJsxFragmentElement(context, jsxElement, jsxConfig)) return;
2094
+ if (jsxElement.openingElement.attributes.some((attr) => attr.type === AST_NODE_TYPES.JSXSpreadAttribute)) return;
2095
+ if (AST.findParentNode(jsxElement, (n) => isRenderFunctionLoose(context, n)) != null) return;
2096
+ const mapCallback = AST.findParentNode(jsxElement, isArrayMethodCallback);
2097
+ if (mapCallback == null || AST.findParentNode(jsxElement, AST.isFunction) !== mapCallback) return;
2098
+ if (context.sourceCode.getScope(mapCallback) !== context.sourceCode.getScope(jsxElement)) return;
2099
+ const keyedElementOrElse = AST.findParentNode(jsxElement, (n) => {
2100
+ if (n === mapCallback) return true;
2101
+ return AST.isJSXElement(n) && getJsxAttribute(context, n)("key") != null;
2102
+ });
2103
+ if (keyedElementOrElse == null || keyedElementOrElse === mapCallback) return;
2104
+ context.report({
2105
+ messageId: "noUnnecessaryKey",
2106
+ node,
2107
+ data: { reason: "A parent element already has a `key` prop in the same list rendering context." }
2108
+ });
2109
+ } };
2129
2110
  }
2130
2111
  function getArrayMethodCallbackPosition(methodName) {
2131
2112
  switch (methodName) {
@@ -2496,7 +2477,7 @@ function create$12(context) {
2496
2477
  const valueExpression = value.expression;
2497
2478
  const construction = getObjectType(valueExpression, context.sourceCode.getScope(valueExpression));
2498
2479
  if (construction == null) return;
2499
- if (isReactHookCall(construction.node)) return;
2480
+ if (isHookCall(construction.node)) return;
2500
2481
  getOrElseUpdate(constructions, functionEntry.node, () => []).push(construction);
2501
2482
  },
2502
2483
  "Program:exit"(program) {
@@ -2577,7 +2558,7 @@ function create$11(context, [options]) {
2577
2558
  const { right } = value;
2578
2559
  const construction = getObjectType(value, context.sourceCode.getScope(value));
2579
2560
  if (construction == null) continue;
2580
- if (isReactHookCall(construction.node)) continue;
2561
+ if (isHookCall(construction.node)) continue;
2581
2562
  if (safePatterns.length > 0) {
2582
2563
  const identifier = extractIdentifier(right);
2583
2564
  if (identifier != null && safePatterns.some((pattern) => pattern.test(identifier))) continue;
@@ -2969,7 +2950,7 @@ function create$7(context) {
2969
2950
  const hookCalls = /* @__PURE__ */ new Set();
2970
2951
  return {
2971
2952
  CallExpression(node) {
2972
- if (!isReactHookCall(node)) return;
2953
+ if (!isHookCall(node)) return;
2973
2954
  hookCalls.add(node);
2974
2955
  },
2975
2956
  ImportDeclaration(node) {
@@ -3353,7 +3334,7 @@ function create$1(context) {
3353
3334
  }
3354
3335
  for (const expr of AST.getNestedCallExpressions(useStateInput)) {
3355
3336
  if (!("name" in expr.callee)) continue;
3356
- if (isReactHookName(expr.callee.name)) continue;
3337
+ if (isHookName(expr.callee.name)) continue;
3357
3338
  if (ALLOW_LIST.includes(expr.callee.name)) continue;
3358
3339
  if (AST.findParentNode(expr, isUseCall) != null) continue;
3359
3340
  context.report({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "2.7.4",
3
+ "version": "2.7.5-beta.11",
4
4
  "description": "A set of composable ESLint rules for for libraries and frameworks that use React as a UI runtime.",
5
5
  "keywords": [
6
6
  "react",
@@ -37,23 +37,23 @@
37
37
  "./package.json"
38
38
  ],
39
39
  "dependencies": {
40
- "@typescript-eslint/scope-manager": "^8.53.1",
41
- "@typescript-eslint/type-utils": "^8.53.1",
42
- "@typescript-eslint/types": "^8.53.1",
43
- "@typescript-eslint/utils": "^8.53.1",
40
+ "@typescript-eslint/scope-manager": "^8.54.0",
41
+ "@typescript-eslint/type-utils": "^8.54.0",
42
+ "@typescript-eslint/types": "^8.54.0",
43
+ "@typescript-eslint/utils": "^8.54.0",
44
44
  "compare-versions": "^6.1.1",
45
45
  "is-immutable-type": "^5.0.1",
46
46
  "string-ts": "^2.3.1",
47
47
  "ts-api-utils": "^2.4.0",
48
48
  "ts-pattern": "^5.9.0",
49
- "@eslint-react/ast": "2.7.4",
50
- "@eslint-react/core": "2.7.4",
51
- "@eslint-react/eff": "2.7.4",
52
- "@eslint-react/shared": "2.7.4",
53
- "@eslint-react/var": "2.7.4"
49
+ "@eslint-react/ast": "2.7.5-beta.11",
50
+ "@eslint-react/core": "2.7.5-beta.11",
51
+ "@eslint-react/eff": "2.7.5-beta.11",
52
+ "@eslint-react/shared": "2.7.5-beta.11",
53
+ "@eslint-react/var": "2.7.5-beta.11"
54
54
  },
55
55
  "devDependencies": {
56
- "@types/react": "^19.2.9",
56
+ "@types/react": "^19.2.10",
57
57
  "@types/react-dom": "^19.2.3",
58
58
  "tsdown": "^0.20.1",
59
59
  "@local/configs": "0.0.0"