eslint-plugin-react-x 2.0.5-next.3 → 2.0.5-next.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 +76 -59
  2. package/package.json +9 -9
package/dist/index.js CHANGED
@@ -115,7 +115,7 @@ const settings = { ...settings$1 };
115
115
  //#endregion
116
116
  //#region package.json
117
117
  var name = "eslint-plugin-react-x";
118
- var version = "2.0.5-next.3";
118
+ var version = "2.0.5-next.5";
119
119
 
120
120
  //#endregion
121
121
  //#region src/utils/create-rule.ts
@@ -208,10 +208,10 @@ var jsx_key_before_spread_default = createRule({
208
208
  meta: {
209
209
  type: "problem",
210
210
  docs: {
211
- description: "Enforces that the 'key' attribute is placed before the spread attribute in JSX elements.",
211
+ description: "Enforces that the 'key' prop is placed before the spread prop in JSX elements.",
212
212
  [Symbol.for("rule_features")]: RULE_FEATURES$59
213
213
  },
214
- messages: { jsxKeyBeforeSpread: "The 'key' attribute must be placed before the spread attribute." },
214
+ messages: { jsxKeyBeforeSpread: "The 'key' prop must be placed before any spread props." },
215
215
  schema: []
216
216
  },
217
217
  name: RULE_NAME$61,
@@ -220,16 +220,16 @@ var jsx_key_before_spread_default = createRule({
220
220
  });
221
221
  function create$61(context) {
222
222
  return { JSXOpeningElement(node) {
223
- let firstSpreadAttributeIndex = null;
224
- for (const [index, attr] of node.attributes.entries()) {
225
- if (attr.type === AST_NODE_TYPES.JSXSpreadAttribute) {
226
- firstSpreadAttributeIndex ??= index;
223
+ let firstSpreadPropIndex = null;
224
+ for (const [index, prop] of node.attributes.entries()) {
225
+ if (prop.type === AST_NODE_TYPES.JSXSpreadAttribute) {
226
+ firstSpreadPropIndex ??= index;
227
227
  continue;
228
228
  }
229
- if (firstSpreadAttributeIndex == null) continue;
230
- if (attr.name.name === "key" && index > firstSpreadAttributeIndex) context.report({
229
+ if (firstSpreadPropIndex == null) continue;
230
+ if (prop.name.name === "key" && index > firstSpreadPropIndex) context.report({
231
231
  messageId: "jsxKeyBeforeSpread",
232
- node: attr
232
+ node: prop
233
233
  });
234
234
  }
235
235
  } };
@@ -262,7 +262,6 @@ function create$60(context) {
262
262
  const visitorFunction = (node) => {
263
263
  if (!AST.isOneOf([AST_NODE_TYPES.JSXElement, AST_NODE_TYPES.JSXFragment])(node.parent)) return;
264
264
  if (!hasCommentLike(node)) return;
265
- if (!node.parent.type.includes("JSX")) return;
266
265
  context.report({
267
266
  messageId: "jsxNoCommentTextnodes",
268
267
  node
@@ -1287,7 +1286,7 @@ var no_duplicate_key_default = createRule({
1287
1286
  defaultOptions: []
1288
1287
  });
1289
1288
  function create$35(context) {
1290
- if (!context.sourceCode.getText().includes("key=")) return {};
1289
+ if (!context.sourceCode.text.includes("key=")) return {};
1291
1290
  const keyedEntries = /* @__PURE__ */ new Map();
1292
1291
  function isKeyValueEqual(a, b) {
1293
1292
  const aValue = a.value;
@@ -1452,11 +1451,11 @@ function create$33(context) {
1452
1451
  }
1453
1452
  /**
1454
1453
  * Determines whether the given CallExpression can be safely auto-fixed by replacing
1455
- * the usage of `forwardRef` with passing `ref` as a prop.
1454
+ * the usage of `forwardRef` with passing `ref` as a prop
1456
1455
  *
1457
- * @param context - The rule context object.
1458
- * @param node - The CallExpression node to check.
1459
- * @returns True if the call can be auto-fixed, false otherwise.
1456
+ * @param context - The rule context object
1457
+ * @param node - The CallExpression node to check
1458
+ * @returns True if the call can be auto-fixed, false otherwise
1460
1459
  */
1461
1460
  function canFix$1(context, node) {
1462
1461
  const { importSource } = getSettingsFromContext(context);
@@ -1467,6 +1466,12 @@ function canFix$1(context, node) {
1467
1466
  default: return false;
1468
1467
  }
1469
1468
  }
1469
+ /**
1470
+ * Generates the fix for the `forwardRef` call
1471
+ * @param context - The rule context
1472
+ * @param node - The `forwardRef` call expression
1473
+ * @returns A fixer function that applies the changes
1474
+ */
1470
1475
  function getFix$1(context, node) {
1471
1476
  return (fixer) => {
1472
1477
  const [componentNode] = node.arguments;
@@ -1478,6 +1483,14 @@ function getFix$1(context, node) {
1478
1483
  ];
1479
1484
  };
1480
1485
  }
1486
+ /**
1487
+ * Generates fixes for the component's props and ref arguments
1488
+ * @param context - The rule context
1489
+ * @param fixer - The rule fixer
1490
+ * @param node - The function component node
1491
+ * @param typeArguments - The type arguments from the `forwardRef` call
1492
+ * @returns An array of fixes for the component's signature
1493
+ */
1481
1494
  function getComponentPropsFixes(context, fixer, node, typeArguments) {
1482
1495
  const getText = (node$1) => context.sourceCode.getText(node$1);
1483
1496
  const [arg0, arg1] = node.params;
@@ -1577,6 +1590,11 @@ function create$31(context) {
1577
1590
  ...compare(version$1, "18.0.0", "<") ? [] : ["string", "falsy string"]
1578
1591
  ];
1579
1592
  const services = ESLintUtils.getParserServices(context, false);
1593
+ /**
1594
+ * Recursively inspects a node to find potential leaked conditional rendering
1595
+ * @param node The AST node to inspect
1596
+ * @returns A report descriptor if a problem is found, otherwise `unit`
1597
+ */
1580
1598
  function getReportDescriptor(node) {
1581
1599
  if (node == null) return unit;
1582
1600
  if (AST.is(AST_NODE_TYPES.JSXExpressionContainer)(node)) return getReportDescriptor(node.expression);
@@ -1835,8 +1853,8 @@ var no_misused_capture_owner_stack_default = createRule({
1835
1853
  },
1836
1854
  fixable: "code",
1837
1855
  messages: {
1838
- useNamespaceImport: "Don't use named imports of 'captureOwnerStack' in files that are bundled for development and production. Use a namespace import instead.",
1839
- missingDevelopmentOnlyCheck: `Don't call 'captureOwnerStack' directly. Use 'if (process.env.NODE_ENV !== "production") {...}' to conditionally access it.`
1856
+ missingDevelopmentOnlyCheck: `Don't call 'captureOwnerStack' directly. Use 'if (process.env.NODE_ENV !== "production") {...}' to conditionally access it.`,
1857
+ useNamespaceImport: "Don't use named imports of 'captureOwnerStack' in files that are bundled for development and production. Use a namespace import instead."
1840
1858
  },
1841
1859
  schema: []
1842
1860
  },
@@ -1977,28 +1995,19 @@ function isInsideJSXAttributeValue(node) {
1977
1995
  return node.parent.type === AST_NODE_TYPES.JSXAttribute || findParentJsxAttribute(node, (n) => n.value?.type === AST_NODE_TYPES.JSXExpressionContainer) != null;
1978
1996
  }
1979
1997
  /**
1980
- * Check whether given node is declared inside class component's render block
1981
- * ```tsx
1982
- * class Component extends React.Component {
1983
- * render() {
1984
- * class NestedClassComponent extends React.Component {
1985
- * render() { return <div />; }
1986
- * }
1987
- * const nestedFunctionComponent = () => <div />;
1988
- * }
1989
- * }
1990
- * ```
1998
+ * Checks whether a given node is declared inside a class component's render block
1999
+ * Ex: class C extends React.Component { render() { const Nested = () => <div />; } }
1991
2000
  * @param node The AST node being checked
1992
- * @returns `true` if node is inside class component's render block, `false` if not
2001
+ * @returns `true` if the node is inside a class component's render block
1993
2002
  */
1994
2003
  function isInsideRenderMethod(node) {
1995
2004
  return AST.findParentNode(node, (n) => isRenderMethodLike(n) && isClassComponent(n.parent.parent)) != null;
1996
2005
  }
1997
2006
  /**
1998
- * Determines whether inside `createElement`'s props.
2007
+ * Determines whether the node is inside `createElement`'s props argument
1999
2008
  * @param context The rule context
2000
2009
  * @param node The AST node to check
2001
- * @returns `true` if the node is inside createElement's props
2010
+ * @returns `true` if the node is inside `createElement`'s props
2002
2011
  */
2003
2012
  function isInsideCreateElementProps(context, node) {
2004
2013
  const call = AST.findParentNode(node, isCreateElementCall(context));
@@ -2163,12 +2172,12 @@ function create$22(context) {
2163
2172
  if (!context.sourceCode.text.includes("componentDidMount")) return {};
2164
2173
  return { CallExpression(node) {
2165
2174
  if (!isThisSetState(node)) return;
2166
- const clazz = AST.findParentNode(node, isClassComponent);
2167
- const method = AST.findParentNode(node, (n) => n === clazz || isComponentDidMount(n));
2168
- if (clazz == null || method == null || method === clazz) return;
2169
- const methodScope = context.sourceCode.getScope(method);
2170
- const upperScope = context.sourceCode.getScope(node).upper;
2171
- if (method.parent === clazz.body && upperScope === methodScope) context.report({
2175
+ const enclosingClassNode = AST.findParentNode(node, isClassComponent);
2176
+ const enclosingMethodNode = AST.findParentNode(node, (n) => n === enclosingClassNode || isComponentDidMount(n));
2177
+ if (enclosingClassNode == null || enclosingMethodNode == null || enclosingMethodNode === enclosingClassNode) return;
2178
+ const enclosingMethodScope = context.sourceCode.getScope(enclosingMethodNode);
2179
+ const setStateCallParentScope = context.sourceCode.getScope(node).upper;
2180
+ if (enclosingMethodNode.parent === enclosingClassNode.body && setStateCallParentScope === enclosingMethodScope) context.report({
2172
2181
  messageId: "noSetStateInComponentDidMount",
2173
2182
  node
2174
2183
  });
@@ -2197,12 +2206,12 @@ function create$21(context) {
2197
2206
  if (!context.sourceCode.text.includes("componentDidUpdate")) return {};
2198
2207
  return { CallExpression(node) {
2199
2208
  if (!isThisSetState(node)) return;
2200
- const clazz = AST.findParentNode(node, isClassComponent);
2201
- const method = AST.findParentNode(node, (n) => n === clazz || isComponentDidUpdate(n));
2202
- if (clazz == null || method == null || method === clazz) return;
2203
- const methodScope = context.sourceCode.getScope(method);
2204
- const upperScope = context.sourceCode.getScope(node).upper;
2205
- if (method.parent === clazz.body && upperScope === methodScope) context.report({
2209
+ const enclosingClassNode = AST.findParentNode(node, isClassComponent);
2210
+ const enclosingMethodNode = AST.findParentNode(node, (n) => n === enclosingClassNode || isComponentDidUpdate(n));
2211
+ if (enclosingClassNode == null || enclosingMethodNode == null || enclosingMethodNode === enclosingClassNode) return;
2212
+ const enclosingMethodScope = context.sourceCode.getScope(enclosingMethodNode);
2213
+ const setStateCallParentScope = context.sourceCode.getScope(node).upper;
2214
+ if (enclosingMethodNode.parent === enclosingClassNode.body && setStateCallParentScope === enclosingMethodScope) context.report({
2206
2215
  messageId: "noSetStateInComponentDidUpdate",
2207
2216
  node
2208
2217
  });
@@ -2217,7 +2226,7 @@ var no_set_state_in_component_will_update_default = createRule({
2217
2226
  meta: {
2218
2227
  type: "problem",
2219
2228
  docs: {
2220
- description: "Disallows calling `this.setState` in `componentWillUpdate` outside of functions, such as callbacks.",
2229
+ description: "Disallow calling `this.setState` in `componentWillUpdate` outside of functions, such as callbacks.",
2221
2230
  [Symbol.for("rule_features")]: RULE_FEATURES$19
2222
2231
  },
2223
2232
  messages: { noSetStateInComponentWillUpdate: "Do not call `this.setState` in `componentWillUpdate` outside of functions, such as callbacks." },
@@ -2231,12 +2240,12 @@ function create$20(context) {
2231
2240
  if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
2232
2241
  return { CallExpression(node) {
2233
2242
  if (!isThisSetState(node)) return;
2234
- const clazz = AST.findParentNode(node, isClassComponent);
2235
- const method = AST.findParentNode(node, (n) => n === clazz || isComponentWillUpdate(n));
2236
- if (clazz == null || method == null || method === clazz) return;
2237
- const methodScope = context.sourceCode.getScope(method);
2238
- const upperScope = context.sourceCode.getScope(node).upper;
2239
- if (method.parent === clazz.body && upperScope === methodScope) context.report({
2243
+ const enclosingClassNode = AST.findParentNode(node, isClassComponent);
2244
+ const enclosingMethodNode = AST.findParentNode(node, (n) => n === enclosingClassNode || isComponentWillUpdate(n));
2245
+ if (enclosingClassNode == null || enclosingMethodNode == null || enclosingMethodNode === enclosingClassNode) return;
2246
+ const enclosingMethodScope = context.sourceCode.getScope(enclosingMethodNode);
2247
+ const setStateCallParentScope = context.sourceCode.getScope(node).upper;
2248
+ if (enclosingMethodNode.parent === enclosingClassNode.body && setStateCallParentScope === enclosingMethodScope) context.report({
2240
2249
  messageId: "noSetStateInComponentWillUpdate",
2241
2250
  node
2242
2251
  });
@@ -2275,21 +2284,27 @@ function create$19(context) {
2275
2284
  "ClassBody:exit": onClassBodyExit,
2276
2285
  JSXAttribute(node) {
2277
2286
  if (node.name.name !== "ref") return;
2278
- const refNameText = getAttributeValueText(context, node.value);
2279
- if (refNameText == null) return;
2287
+ const refName = getJsxAttributeValueText(context, node.value);
2288
+ if (refName == null) return;
2280
2289
  context.report({
2281
2290
  messageId: "noStringRefs",
2282
2291
  node,
2283
2292
  fix(fixer) {
2284
2293
  if (node.value == null) return null;
2285
2294
  if (!state.isWithinClassComponent) return null;
2286
- return fixer.replaceText(node.value, `{(ref) => { this.refs[${refNameText}] = ref; }}`);
2295
+ return fixer.replaceText(node.value, `{(ref) => { this.refs[${refName}] = ref; }}`);
2287
2296
  }
2288
2297
  });
2289
2298
  }
2290
2299
  };
2291
2300
  }
2292
- function getAttributeValueText(context, node) {
2301
+ /**
2302
+ * Extracts the text content from a JSX attribute's value
2303
+ * @param context - The rule context
2304
+ * @param node - The JSX attribute value node
2305
+ * @returns The text of the attribute value, or null if not a string-like value
2306
+ */
2307
+ function getJsxAttributeValueText(context, node) {
2293
2308
  if (node == null) return null;
2294
2309
  switch (true) {
2295
2310
  case node.type === AST_NODE_TYPES.Literal && typeof node.value === "string": return context.sourceCode.getText(node);
@@ -2336,6 +2351,11 @@ function create$18(context) {
2336
2351
  });
2337
2352
  } };
2338
2353
  }
2354
+ /**
2355
+ * Checks if a node is a callback function passed to an array's `.map()` method
2356
+ * @param node The node to check
2357
+ * @returns `true` if the node is a map callback, `false` otherwise
2358
+ */
2339
2359
  function isMapCallback(node) {
2340
2360
  if (node.parent == null) return false;
2341
2361
  if (!AST.isArrayMapCall(node.parent)) return false;
@@ -2781,7 +2801,7 @@ function create$9(context) {
2781
2801
  for (const def of defs) {
2782
2802
  const methodName = AST.getPropertyName(def);
2783
2803
  if (methodName == null) continue;
2784
- if (usages?.has(methodName) || LIFECYCLE_METHODS.has(methodName)) continue;
2804
+ if ((usages?.has(methodName) ?? false) || LIFECYCLE_METHODS.has(methodName)) continue;
2785
2805
  context.report({
2786
2806
  messageId: "noUnusedClassComponentMembers",
2787
2807
  node: def,
@@ -3308,9 +3328,6 @@ function checkNode(context, node, allowExpressions) {
3308
3328
  fix: getFix(context, node)
3309
3329
  });
3310
3330
  }
3311
- /**
3312
- * Generate fix for removing useless fragment
3313
- */
3314
3331
  function getFix(context, node) {
3315
3332
  if (!canFix(context, node)) return null;
3316
3333
  return (fixer) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "2.0.5-next.3",
3
+ "version": "2.0.5-next.5",
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",
@@ -43,16 +43,16 @@
43
43
  "string-ts": "^2.2.1",
44
44
  "ts-api-utils": "^2.1.0",
45
45
  "ts-pattern": "^5.8.0",
46
- "@eslint-react/ast": "2.0.5-next.3",
47
- "@eslint-react/eff": "2.0.5-next.3",
48
- "@eslint-react/kit": "2.0.5-next.3",
49
- "@eslint-react/shared": "2.0.5-next.3",
50
- "@eslint-react/core": "2.0.5-next.3",
51
- "@eslint-react/var": "2.0.5-next.3"
46
+ "@eslint-react/ast": "2.0.5-next.5",
47
+ "@eslint-react/eff": "2.0.5-next.5",
48
+ "@eslint-react/kit": "2.0.5-next.5",
49
+ "@eslint-react/var": "2.0.5-next.5",
50
+ "@eslint-react/shared": "2.0.5-next.5",
51
+ "@eslint-react/core": "2.0.5-next.5"
52
52
  },
53
53
  "devDependencies": {
54
- "@types/react": "^19.1.16",
55
- "@types/react-dom": "^19.1.9",
54
+ "@types/react": "^19.2.0",
55
+ "@types/react-dom": "^19.2.0",
56
56
  "tsdown": "^0.15.6",
57
57
  "@local/configs": "0.0.0"
58
58
  },