eslint-plugin-react-x 3.0.0-next.57 → 3.0.0-next.59

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 +158 -155
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -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 = "3.0.0-next.57";
71
+ var version = "3.0.0-next.59";
72
72
 
73
73
  //#endregion
74
74
  //#region src/utils/create-rule.ts
@@ -255,27 +255,27 @@ function create$62(context) {
255
255
  if (ast.findParentNode(node, ast.isFunction) == null) continue;
256
256
  if (reported.has(node)) continue;
257
257
  context.report({
258
+ data: { name },
258
259
  messageId: "component",
259
- node,
260
- data: { name }
260
+ node
261
261
  });
262
262
  reported.add(node);
263
263
  }
264
264
  for (const { name = "unknown", node } of cComponents) {
265
265
  if (ast.findParentNode(node, ast.isFunction) == null) continue;
266
266
  context.report({
267
+ data: { name },
267
268
  messageId: "component",
268
- node,
269
- data: { name }
269
+ node
270
270
  });
271
271
  }
272
272
  for (const { name, node } of hooks) {
273
273
  if (ast.findParentNode(node, ast.isFunction) == null) continue;
274
274
  if (reported.has(node)) continue;
275
275
  context.report({
276
+ data: { name },
276
277
  messageId: "hook",
277
- node,
278
- data: { name }
278
+ node
279
279
  });
280
280
  reported.add(node);
281
281
  }
@@ -1337,13 +1337,13 @@ function create$60(context) {
1337
1337
  const isProps = isPropsObject(rootId);
1338
1338
  if (!isState && !isProps) return;
1339
1339
  violations.push({
1340
- messageId: "mutatingArrayMethod",
1341
- node,
1342
1340
  data: {
1343
1341
  name: context.sourceCode.getText(object),
1344
1342
  method: property.name
1345
1343
  },
1346
- func: enclosingFn
1344
+ func: enclosingFn,
1345
+ messageId: "mutatingArrayMethod",
1346
+ node
1347
1347
  });
1348
1348
  },
1349
1349
  AssignmentExpression(node) {
@@ -1357,17 +1357,17 @@ function create$60(context) {
1357
1357
  const isProps = isPropsObject(rootId);
1358
1358
  if (!isState && !isProps) return;
1359
1359
  violations.push({
1360
- messageId: "mutatingAssignment",
1361
- node,
1362
1360
  data: { name: context.sourceCode.getText(node.left.object) },
1363
- func: enclosingFn
1361
+ func: enclosingFn,
1362
+ messageId: "mutatingAssignment",
1363
+ node
1364
1364
  });
1365
1365
  },
1366
1366
  "Program:exit"(program) {
1367
1367
  const components = cCollector.ctx.getAllComponents(program);
1368
1368
  const hooks = hCollector.ctx.getAllHooks(program);
1369
1369
  const componentAndHookFns = new Set([...components.map((c) => c.node), ...hooks.map((h) => h.node)]);
1370
- for (const { messageId, node, data, func } of violations) {
1370
+ for (const { data, func, messageId, node } of violations) {
1371
1371
  let current = func;
1372
1372
  let insideComponentOrHook = false;
1373
1373
  while (current != null) {
@@ -1379,9 +1379,9 @@ function create$60(context) {
1379
1379
  }
1380
1380
  if (!insideComponentOrHook) continue;
1381
1381
  context.report({
1382
+ data,
1382
1383
  messageId,
1383
- node,
1384
- data
1384
+ node
1385
1385
  });
1386
1386
  }
1387
1387
  }
@@ -1419,8 +1419,6 @@ function create$59(context) {
1419
1419
  if (child.value === "$" && node.children.length === 2) continue;
1420
1420
  const pos = child.loc.end;
1421
1421
  context.report({
1422
- messageId: "default",
1423
- node: child,
1424
1422
  loc: {
1425
1423
  end: {
1426
1424
  column: pos.column,
@@ -1431,11 +1429,13 @@ function create$59(context) {
1431
1429
  line: pos.line
1432
1430
  }
1433
1431
  },
1432
+ messageId: "default",
1433
+ node: child,
1434
1434
  suggest: [{
1435
- messageId: "removeDollarSign",
1436
1435
  fix(fixer) {
1437
1436
  return fixer.removeRange([child.range[1] - 1, child.range[1]]);
1438
- }
1437
+ },
1438
+ messageId: "removeDollarSign"
1439
1439
  }]
1440
1440
  });
1441
1441
  }
@@ -1576,18 +1576,18 @@ function create$55(context) {
1576
1576
  switch (true) {
1577
1577
  case policy === 1 && value?.type === AST_NODE_TYPES.JSXExpressionContainer && value.expression.type === AST_NODE_TYPES.Literal && value.expression.value === true:
1578
1578
  context.report({
1579
- messageId: "default",
1580
- node,
1581
1579
  data: { message: `Omit attribute value for '${propName}'.` },
1582
- fix: (fixer) => fixer.removeRange([node.name.range[1], value.range[1]])
1580
+ fix: (fixer) => fixer.removeRange([node.name.range[1], value.range[1]]),
1581
+ messageId: "default",
1582
+ node
1583
1583
  });
1584
1584
  break;
1585
1585
  case policy === -1 && value == null:
1586
1586
  context.report({
1587
- messageId: "default",
1588
- node: node.value ?? node,
1589
1587
  data: { message: `Set attribute value for '${propName}'.` },
1590
- fix: (fixer) => fixer.insertTextAfter(node.name, `={true}`)
1588
+ fix: (fixer) => fixer.insertTextAfter(node.name, `={true}`),
1589
+ messageId: "default",
1590
+ node: node.value ?? node
1591
1591
  });
1592
1592
  break;
1593
1593
  }
@@ -1625,24 +1625,24 @@ function create$54(context) {
1625
1625
  if (!core.isJsxFragmentElement(context, node, jsxConfig)) return;
1626
1626
  if (node.openingElement.attributes.length > 0) return;
1627
1627
  context.report({
1628
- messageId: "default",
1629
- node,
1630
1628
  data: { message: "Use fragment shorthand syntax instead of 'Fragment' component." },
1631
1629
  fix: (fixer) => {
1632
1630
  const { closingElement, openingElement } = node;
1633
1631
  if (closingElement == null) return [];
1634
1632
  return [fixer.replaceTextRange([openingElement.range[0], openingElement.range[1]], "<>"), fixer.replaceTextRange([closingElement.range[0], closingElement.range[1]], "</>")];
1635
- }
1633
+ },
1634
+ messageId: "default",
1635
+ node
1636
1636
  });
1637
1637
  } })).with(-1, () => defineRuleListener({ JSXFragment(node) {
1638
1638
  context.report({
1639
- messageId: "default",
1640
- node,
1641
1639
  data: { message: "Use 'Fragment' component instead of fragment shorthand syntax." },
1642
1640
  fix: (fixer) => {
1643
1641
  const { closingFragment, openingFragment } = node;
1644
1642
  return [fixer.replaceTextRange([openingFragment.range[0], openingFragment.range[1]], `<${jsxFragmentFactory}>`), fixer.replaceTextRange([closingFragment.range[0], closingFragment.range[1]], `</${jsxFragmentFactory}>`)];
1645
- }
1643
+ },
1644
+ messageId: "default",
1645
+ node
1646
1646
  });
1647
1647
  } })).otherwise(() => ({}));
1648
1648
  }
@@ -1684,9 +1684,9 @@ function create$53(context) {
1684
1684
  function debugReport(context, node, name) {
1685
1685
  if (process.env["ESLINT_REACT_DEBUG"] !== "1") return;
1686
1686
  context.report({
1687
+ data: { name },
1687
1688
  messageId: "default",
1688
- node,
1689
- data: { name }
1689
+ node
1690
1690
  });
1691
1691
  }
1692
1692
 
@@ -2084,9 +2084,9 @@ function create$43(context) {
2084
2084
  for (const { name = "anonymous", node: component } of ctx.getAllComponents(program)) {
2085
2085
  if (component.body.body.some((m) => core.isComponentDidCatch(m) || core.isGetDerivedStateFromError(m))) continue;
2086
2086
  context.report({
2087
+ data: { name },
2087
2088
  messageId: "default",
2088
- node: component,
2089
- data: { name }
2089
+ node: component
2090
2090
  });
2091
2091
  }
2092
2092
  } });
@@ -2137,12 +2137,12 @@ function create$41(context) {
2137
2137
  for (const { node: component } of ctx.getAllComponents(program)) {
2138
2138
  const { body } = component.body;
2139
2139
  for (const member of body) if (core.isComponentWillMount(member)) context.report({
2140
- messageId: "default",
2141
- node: member,
2142
2140
  fix(fixer) {
2143
2141
  if (!("key" in member)) return null;
2144
2142
  return fixer.replaceText(member.key, "UNSAFE_componentWillMount");
2145
- }
2143
+ },
2144
+ messageId: "default",
2145
+ node: member
2146
2146
  });
2147
2147
  }
2148
2148
  } });
@@ -2170,12 +2170,12 @@ function create$40(context) {
2170
2170
  for (const { node: component } of ctx.getAllComponents(program)) {
2171
2171
  const { body } = component.body;
2172
2172
  for (const member of body) if (core.isComponentWillReceiveProps(member)) context.report({
2173
- messageId: "default",
2174
- node: member,
2175
2173
  fix(fixer) {
2176
2174
  if (!("key" in member)) return null;
2177
2175
  return fixer.replaceText(member.key, "UNSAFE_componentWillReceiveProps");
2178
- }
2176
+ },
2177
+ messageId: "default",
2178
+ node: member
2179
2179
  });
2180
2180
  }
2181
2181
  } });
@@ -2203,12 +2203,12 @@ function create$39(context) {
2203
2203
  for (const { node: component } of ctx.getAllComponents(program)) {
2204
2204
  const { body } = component.body;
2205
2205
  for (const member of body) if (core.isComponentWillUpdate(member)) context.report({
2206
- messageId: "default",
2207
- node: member,
2208
2206
  fix(fixer) {
2209
2207
  if (!("key" in member)) return null;
2210
2208
  return fixer.replaceText(member.key, "UNSAFE_componentWillUpdate");
2211
- }
2209
+ },
2210
+ messageId: "default",
2211
+ node: member
2212
2212
  });
2213
2213
  }
2214
2214
  } });
@@ -2248,14 +2248,14 @@ function create$38(context) {
2248
2248
  messageId: "default",
2249
2249
  node,
2250
2250
  suggest: [{
2251
- messageId: "replace",
2252
2251
  fix(fixer) {
2253
2252
  if (!core.isComponentNameLoose(contextSelfName)) return null;
2254
2253
  const openingElement = node.openingElement;
2255
2254
  const closingElement = node.closingElement;
2256
2255
  if (closingElement == null) return fixer.replaceText(openingElement.name, contextFullName);
2257
2256
  return [fixer.replaceText(openingElement.name, contextFullName), fixer.replaceText(closingElement.name, contextFullName)];
2258
- }
2257
+ },
2258
+ messageId: "replace"
2259
2259
  }]
2260
2260
  });
2261
2261
  } });
@@ -2371,9 +2371,9 @@ function create$35(context) {
2371
2371
  for (const { hasDuplicate, keys } of keyedEntries.values()) {
2372
2372
  if (!hasDuplicate) continue;
2373
2373
  for (const key of keys) context.report({
2374
+ data: { value: context.sourceCode.getText(key) },
2374
2375
  messageId: "default",
2375
- node: key,
2376
- data: { value: context.sourceCode.getText(key) }
2376
+ node: key
2377
2377
  });
2378
2378
  }
2379
2379
  }
@@ -2407,8 +2407,8 @@ function create$34(context) {
2407
2407
  if (!core.isForwardRefCall(context, node)) return;
2408
2408
  const id = ast.getFunctionId(node);
2409
2409
  const suggest = canFix(context, node) ? [{
2410
- messageId: "replace",
2411
- fix: getFix(context, node)
2410
+ fix: getFix(context, node),
2411
+ messageId: "replace"
2412
2412
  }] : [];
2413
2413
  context.report({
2414
2414
  messageId: "default",
@@ -2580,16 +2580,16 @@ function create$32(context) {
2580
2580
  if (left.type === AST_NODE_TYPES.UnaryExpression && left.operator === "!") return getReportDescriptor(right);
2581
2581
  const initialScope = context.sourceCode.getScope(left);
2582
2582
  if (ast.isIdentifier(left, "NaN") || getStaticValue(left, initialScope)?.value === "NaN") return {
2583
+ data: { value: context.sourceCode.getText(left) },
2583
2584
  messageId: "default",
2584
- node: left,
2585
- data: { value: context.sourceCode.getText(left) }
2585
+ node: left
2586
2586
  };
2587
2587
  const leftTypeVariants = getTypeVariants(unionConstituents(getConstrainedTypeAtLocation(services, left)));
2588
2588
  if (Array.from(leftTypeVariants.values()).every((type) => allowedVariants.some((allowed) => allowed === type))) return getReportDescriptor(right);
2589
2589
  return {
2590
+ data: { value: context.sourceCode.getText(left) },
2590
2591
  messageId: "default",
2591
- node: left,
2592
- data: { value: context.sourceCode.getText(left) }
2592
+ node: left
2593
2593
  };
2594
2594
  }).with({ type: AST_NODE_TYPES.ConditionalExpression }, ({ alternate, consequent }) => {
2595
2595
  return getReportDescriptor(consequent) ?? getReportDescriptor(alternate);
@@ -2622,7 +2622,7 @@ function create$31(context) {
2622
2622
  hint: core.DEFAULT_COMPONENT_DETECTION_HINT
2623
2623
  });
2624
2624
  return defineRuleListener(visitor, { "Program:exit"(program) {
2625
- for (const { node, displayName, flag } of ctx.getAllComponents(program)) {
2625
+ for (const { displayName, flag, node } of ctx.getAllComponents(program)) {
2626
2626
  const id = ast.getFunctionId(node);
2627
2627
  const isMemoOrForwardRef = (flag & (core.ComponentFlag.ForwardRef | core.ComponentFlag.Memo)) > 0n;
2628
2628
  if (id != null) continue;
@@ -2678,8 +2678,6 @@ function create$30(context) {
2678
2678
  const object = left.object;
2679
2679
  return isAssignmentTargetEqual(context, id, object);
2680
2680
  })) context.report({
2681
- messageId: "default",
2682
- node: id,
2683
2681
  fix(fixer) {
2684
2682
  if (id.type !== AST_NODE_TYPES.Identifier || id.parent !== call.parent) return [];
2685
2683
  return fixer.insertTextAfter(context.sourceCode.getTokenAfter(call) ?? call, [
@@ -2693,7 +2691,9 @@ function create$30(context) {
2693
2691
  JSON.stringify(id.name),
2694
2692
  ";"
2695
2693
  ].join(""));
2696
- }
2694
+ },
2695
+ messageId: "default",
2696
+ node: id
2697
2697
  });
2698
2698
  }
2699
2699
  }
@@ -2864,55 +2864,55 @@ function create$27(context) {
2864
2864
  if (name == null) continue;
2865
2865
  if (isInsideJSXAttributeValue(component)) {
2866
2866
  context.report({
2867
- messageId: "default",
2868
- node: component,
2869
2867
  data: {
2870
2868
  name,
2871
2869
  suggestion: "Move it to the top level or pass it as a prop."
2872
- }
2870
+ },
2871
+ messageId: "default",
2872
+ node: component
2873
2873
  });
2874
2874
  continue;
2875
2875
  }
2876
2876
  if (isInsideCreateElementProps(context, component)) {
2877
2877
  context.report({
2878
- messageId: "default",
2879
- node: component,
2880
2878
  data: {
2881
2879
  name,
2882
2880
  suggestion: "Move it to the top level or pass it as a prop."
2883
- }
2881
+ },
2882
+ messageId: "default",
2883
+ node: component
2884
2884
  });
2885
2885
  continue;
2886
2886
  }
2887
2887
  if (findEnclosingComponent(component) != null) {
2888
2888
  context.report({
2889
- messageId: "default",
2890
- node: component,
2891
2889
  data: {
2892
2890
  name,
2893
2891
  suggestion: component.parent.type === AST_NODE_TYPES.Property ? "Move it to the top level or pass it as a prop." : "Move it to the top level."
2894
- }
2892
+ },
2893
+ messageId: "default",
2894
+ node: component
2895
2895
  });
2896
2896
  continue;
2897
2897
  }
2898
2898
  if (isInsideRenderMethod(component)) context.report({
2899
- messageId: "default",
2900
- node: component,
2901
2899
  data: {
2902
2900
  name,
2903
2901
  suggestion: "Move it to the top level."
2904
- }
2902
+ },
2903
+ messageId: "default",
2904
+ node: component
2905
2905
  });
2906
2906
  }
2907
2907
  for (const { name = "unknown", node: component } of cComponents) {
2908
2908
  if (findEnclosingComponent(component) == null) continue;
2909
2909
  context.report({
2910
- messageId: "default",
2911
- node: component,
2912
2910
  data: {
2913
2911
  name,
2914
2912
  suggestion: component.parent.type === AST_NODE_TYPES.Property ? "Move it to the top level or pass it as a prop." : "Move it to the top level."
2915
- }
2913
+ },
2914
+ messageId: "default",
2915
+ node: component
2916
2916
  });
2917
2917
  }
2918
2918
  } });
@@ -3010,13 +3010,13 @@ function create$25(context) {
3010
3010
  if (!context.sourceCode.text.includes("shouldComponentUpdate")) return {};
3011
3011
  const { ctx, visitor } = core.useComponentCollectorLegacy(context);
3012
3012
  return defineRuleListener(visitor, { "Program:exit"(program) {
3013
- for (const { name = "PureComponent", node: component, flag } of ctx.getAllComponents(program)) {
3013
+ for (const { name = "PureComponent", flag, node: component } of ctx.getAllComponents(program)) {
3014
3014
  if ((flag & core.ComponentFlag.PureComponent) === 0n) continue;
3015
3015
  const { body } = component.body;
3016
3016
  for (const member of body) if (isShouldComponentUpdate(member)) context.report({
3017
+ data: { componentName: name },
3017
3018
  messageId: "default",
3018
- node: member,
3019
- data: { componentName: name }
3019
+ node: member
3020
3020
  });
3021
3021
  }
3022
3022
  } });
@@ -3186,9 +3186,9 @@ function checkForUsageInsideUseEffect$1(sourceCode, node) {
3186
3186
  if (effectSet.size > 1) return;
3187
3187
  }
3188
3188
  return {
3189
+ data: { name: node.parent.id.name },
3189
3190
  messageId: "noUnnecessaryUseCallbackInsideUseEffect",
3190
- node,
3191
- data: { name: node.parent.id.name }
3191
+ node
3192
3192
  };
3193
3193
  }
3194
3194
 
@@ -3270,9 +3270,9 @@ function checkForUsageInsideUseEffect(sourceCode, node) {
3270
3270
  if (effectSet.size > 1) return;
3271
3271
  }
3272
3272
  return {
3273
+ data: { name: node.parent.id.name },
3273
3274
  messageId: "noUnnecessaryUseMemoInsideUseEffect",
3274
- node,
3275
- data: { name: node.parent.id.name }
3275
+ node
3276
3276
  };
3277
3277
  }
3278
3278
 
@@ -3297,16 +3297,16 @@ var no_unnecessary_use_prefix_default = createRule({
3297
3297
  function create$19(context) {
3298
3298
  const { ctx, visitor } = core.useHookCollector(context);
3299
3299
  return defineRuleListener(visitor, { "Program:exit"(program) {
3300
- for (const { id, name, node, hookCalls } of ctx.getAllHooks(program)) {
3300
+ for (const { id, name, hookCalls, node } of ctx.getAllHooks(program)) {
3301
3301
  if (hookCalls.length > 0) continue;
3302
3302
  if (ast.isFunctionEmpty(node)) continue;
3303
3303
  if (WELL_KNOWN_HOOKS.includes(name)) continue;
3304
3304
  if (containsUseComments(context, node)) continue;
3305
3305
  if (ast.findParentNode(node, ast.isViMockCallback) != null) continue;
3306
3306
  context.report({
3307
+ data: { name },
3307
3308
  messageId: "default",
3308
- node: id ?? node,
3309
- data: { name }
3309
+ node: id ?? node
3310
3310
  });
3311
3311
  }
3312
3312
  } });
@@ -3436,18 +3436,18 @@ function create$15(context) {
3436
3436
  getOrElseUpdate(constructions, functionEntry.node, () => []).push(construction);
3437
3437
  },
3438
3438
  "Program:exit"(program) {
3439
- for (const { node: component, directives } of ctx.getAllComponents(program)) {
3439
+ for (const { directives, node: component } of ctx.getAllComponents(program)) {
3440
3440
  if (compilationMode === "annotation" && directives.some((d) => d.directive === "use memo")) continue;
3441
3441
  for (const construction of constructions.get(component) ?? []) {
3442
3442
  const { kind, node: constructionNode } = construction;
3443
3443
  const suggestion = kind === "function" ? "Consider wrapping it in a useCallback hook." : "Consider wrapping it in a useMemo hook.";
3444
3444
  context.report({
3445
- messageId: "unstableContextValue",
3446
- node: constructionNode,
3447
3445
  data: {
3448
3446
  kind: ast.getHumanReadableKind(constructionNode),
3449
3447
  suggestion
3450
- }
3448
+ },
3449
+ messageId: "unstableContextValue",
3450
+ node: constructionNode
3451
3451
  });
3452
3452
  }
3453
3453
  }
@@ -3525,9 +3525,9 @@ function create$14(context, [options]) {
3525
3525
  if (identifier != null && safePatterns.some((pattern) => pattern.test(identifier))) continue;
3526
3526
  }
3527
3527
  context.report({
3528
+ data: { kind: ast.getHumanReadableKind(right) },
3528
3529
  messageId: "default",
3529
- node: right,
3530
- data: { kind: ast.getHumanReadableKind(right) }
3530
+ node: right
3531
3531
  });
3532
3532
  }
3533
3533
  }
@@ -3595,12 +3595,12 @@ function create$13(context) {
3595
3595
  if (methodName == null) continue;
3596
3596
  if ((usages?.has(methodName) ?? false) || LIFECYCLE_METHODS.has(methodName)) continue;
3597
3597
  context.report({
3598
- messageId: "default",
3599
- node: def,
3600
3598
  data: {
3601
3599
  className: id != null ? context.sourceCode.getText(id) : "Component",
3602
3600
  methodName
3603
- }
3601
+ },
3602
+ messageId: "default",
3603
+ node: def
3604
3604
  });
3605
3605
  }
3606
3606
  }
@@ -3757,9 +3757,9 @@ function reportUnusedProp(context, services, prop) {
3757
3757
  if (declarationNode == null) return;
3758
3758
  const nodeToReport = declarationNode.type === AST_NODE_TYPES.TSPropertySignature ? declarationNode.key : declarationNode;
3759
3759
  context.report({
3760
+ data: { name: prop.name },
3760
3761
  messageId: "default",
3761
- node: nodeToReport,
3762
- data: { name: prop.name }
3762
+ node: nodeToReport
3763
3763
  });
3764
3764
  }
3765
3765
 
@@ -3795,12 +3795,12 @@ function create$11(context) {
3795
3795
  const currentClass = classStack.pop();
3796
3796
  if (currentClass == null || !core.isClassComponent(currentClass)) return;
3797
3797
  const id = ast.getClassId(currentClass);
3798
- const { node: defNode, isUsed = false } = stateDefs.get(currentClass) ?? {};
3798
+ const { isUsed = false, node: defNode } = stateDefs.get(currentClass) ?? {};
3799
3799
  if (defNode == null || isUsed) return;
3800
3800
  context.report({
3801
+ data: { className: id != null ? context.sourceCode.getText(id) : "Component" },
3801
3802
  messageId: "default",
3802
- node: defNode,
3803
- data: { className: id != null ? context.sourceCode.getText(id) : "Component" }
3803
+ node: defNode
3804
3804
  });
3805
3805
  }
3806
3806
  function methodEnter(node) {
@@ -3811,15 +3811,15 @@ function create$11(context) {
3811
3811
  if (core.isGetDerivedStateFromProps(node) && isMatching({ params: [P.nonNullable, ...P.array()] })(node.value)) {
3812
3812
  const defNode = stateDefs.get(currentClass)?.node;
3813
3813
  stateDefs.set(currentClass, {
3814
- node: defNode,
3815
- isUsed: true
3814
+ isUsed: true,
3815
+ node: defNode
3816
3816
  });
3817
3817
  }
3818
3818
  return;
3819
3819
  }
3820
3820
  if (ast.getPropertyName(node.key) === "state") stateDefs.set(currentClass, {
3821
- node: node.key,
3822
- isUsed: false
3821
+ isUsed: false,
3822
+ node: node.key
3823
3823
  });
3824
3824
  }
3825
3825
  function methodExit() {
@@ -3840,8 +3840,8 @@ function create$11(context) {
3840
3840
  if (currentConstructor == null || !currentClass.body.body.includes(currentConstructor)) return;
3841
3841
  const isUsed = stateDefs.get(currentClass)?.isUsed ?? false;
3842
3842
  stateDefs.set(currentClass, {
3843
- node: node.left,
3844
- isUsed
3843
+ isUsed,
3844
+ node: node.left
3845
3845
  });
3846
3846
  },
3847
3847
  ClassDeclaration: classEnter,
@@ -3859,8 +3859,8 @@ function create$11(context) {
3859
3859
  if (!currentClass.body.body.includes(currentMethod)) return;
3860
3860
  const defNode = stateDefs.get(currentClass)?.node;
3861
3861
  stateDefs.set(currentClass, {
3862
- node: defNode,
3863
- isUsed: true
3862
+ isUsed: true,
3863
+ node: defNode
3864
3864
  });
3865
3865
  },
3866
3866
  MethodDefinition: methodEnter,
@@ -3883,8 +3883,8 @@ function create$11(context) {
3883
3883
  })) return;
3884
3884
  const defNode = stateDefs.get(currentClass)?.node;
3885
3885
  stateDefs.set(currentClass, {
3886
- node: defNode,
3887
- isUsed: true
3886
+ isUsed: true,
3887
+ node: defNode
3888
3888
  });
3889
3889
  }
3890
3890
  });
@@ -3919,14 +3919,14 @@ function create$10(context) {
3919
3919
  messageId: "default",
3920
3920
  node: node.callee,
3921
3921
  suggest: [{
3922
- messageId: "replace",
3923
3922
  fix(fixer) {
3924
3923
  switch (node.callee.type) {
3925
3924
  case AST_NODE_TYPES.Identifier: return fixer.replaceText(node.callee, "use");
3926
3925
  case AST_NODE_TYPES.MemberExpression: return fixer.replaceText(node.callee.property, "use");
3927
3926
  }
3928
3927
  return null;
3929
- }
3928
+ },
3929
+ messageId: "replace"
3930
3930
  }]
3931
3931
  });
3932
3932
  } });
@@ -3976,20 +3976,19 @@ function create$9(context, [option]) {
3976
3976
  * Check if a fragment node is useless and should be reported
3977
3977
  */
3978
3978
  function checkNode(context, node) {
3979
- if (node.type === AST_NODE_TYPES.JSXElement && core.getJsxAttribute(context, node)("key") != null) return;
3980
3979
  if (core.isJsxHostElement(context, node.parent)) context.report({
3981
- messageId: "default",
3982
- node,
3983
3980
  data: { reason: "placed inside a host component" },
3984
- fix: getFix(context, node)
3981
+ fix: getFix(context, node),
3982
+ messageId: "default",
3983
+ node
3985
3984
  });
3986
3985
  if (node.children.length === 0) {
3987
3986
  if (allowEmptyFragment) return;
3988
3987
  context.report({
3989
- messageId: "default",
3990
- node,
3991
3988
  data: { reason: "contains less than two children" },
3992
- fix: getFix(context, node)
3989
+ fix: getFix(context, node),
3990
+ messageId: "default",
3991
+ node
3993
3992
  });
3994
3993
  return;
3995
3994
  }
@@ -3998,28 +3997,28 @@ function create$9(context, [option]) {
3998
3997
  case allowExpressions && !isChildElement && node.children.length === 1 && core.isJsxText(node.children.at(0)): return;
3999
3998
  case !allowExpressions && isChildElement:
4000
3999
  context.report({
4001
- messageId: "default",
4002
- node,
4003
4000
  data: { reason: "contains less than two children" },
4004
- fix: getFix(context, node)
4001
+ fix: getFix(context, node),
4002
+ messageId: "default",
4003
+ node
4005
4004
  });
4006
4005
  return;
4007
4006
  case !allowExpressions && !isChildElement && node.children.length === 1:
4008
4007
  context.report({
4009
- messageId: "default",
4010
- node,
4011
4008
  data: { reason: "contains less than two children" },
4012
- fix: getFix(context, node)
4009
+ fix: getFix(context, node),
4010
+ messageId: "default",
4011
+ node
4013
4012
  });
4014
4013
  return;
4015
4014
  }
4016
4015
  const nonPaddingChildren = node.children.filter((child) => !isPaddingSpaces(child));
4017
4016
  const firstNonPaddingChild = nonPaddingChildren.at(0);
4018
4017
  if (nonPaddingChildren.length === 0 || nonPaddingChildren.length === 1 && firstNonPaddingChild?.type !== AST_NODE_TYPES.JSXExpressionContainer) context.report({
4019
- messageId: "default",
4020
- node,
4021
4018
  data: { reason: "contains less than two children" },
4022
- fix: getFix(context, node)
4019
+ fix: getFix(context, node),
4020
+ messageId: "default",
4021
+ node
4023
4022
  });
4024
4023
  }
4025
4024
  function getFix(context, node) {
@@ -4042,6 +4041,8 @@ function create$9(context, [option]) {
4042
4041
  return defineRuleListener({
4043
4042
  JSXElement(node) {
4044
4043
  if (!core.isJsxFragmentElement(context, node, jsxConfig)) return;
4044
+ if (core.getJsxAttribute(context, node)("key") != null) return;
4045
+ if (core.getJsxAttribute(context, node)("ref") != null) return;
4045
4046
  checkNode(context, node);
4046
4047
  },
4047
4048
  JSXFragment(node) {
@@ -4128,8 +4129,6 @@ function create$7(context) {
4128
4129
  return defineRuleListener({ [`ImportDeclaration[source.value="${importSource}"] ImportDefaultSpecifier`](node) {
4129
4130
  const hasOtherSpecifiers = node.parent.specifiers.length > 1;
4130
4131
  context.report({
4131
- messageId: "default",
4132
- node: hasOtherSpecifiers ? node : node.parent,
4133
4132
  data: { importSource },
4134
4133
  fix(fixer) {
4135
4134
  const importDeclarationText = context.sourceCode.getText(node.parent);
@@ -4140,7 +4139,9 @@ function create$7(context) {
4140
4139
  if (!hasOtherSpecifiers) return fixer.replaceText(node.parent, `${importStringPrefix} * as ${node.local.name} from ${importSourceQuoted}${semi}`);
4141
4140
  const specifiers = importDeclarationText.slice(importDeclarationText.indexOf("{"), importDeclarationText.indexOf("}") + 1);
4142
4141
  return fixer.replaceText(node.parent, [`${importStringPrefix} * as ${node.local.name} from ${importSourceQuoted}${semi}`, `${importStringPrefix} ${specifiers} from ${importSourceQuoted}${semi}`].join("\n"));
4143
- }
4142
+ },
4143
+ messageId: "default",
4144
+ node: hasOtherSpecifiers ? node : node.parent
4144
4145
  });
4145
4146
  } });
4146
4147
  }
@@ -4177,8 +4178,8 @@ function create$6(context) {
4177
4178
  const func = ast.findParentNode(node, ast.isFunction);
4178
4179
  if (func == null) return;
4179
4180
  cExprs.push({
4180
- node,
4181
- func
4181
+ func,
4182
+ node
4182
4183
  });
4183
4184
  },
4184
4185
  NewExpression(node) {
@@ -4188,20 +4189,20 @@ function create$6(context) {
4188
4189
  const func = ast.findParentNode(node, ast.isFunction);
4189
4190
  if (func == null) return;
4190
4191
  nExprs.push({
4191
- node,
4192
- func
4192
+ func,
4193
+ node
4193
4194
  });
4194
4195
  },
4195
4196
  "Program:exit"(node) {
4196
4197
  const components = cCollector.ctx.getAllComponents(node);
4197
4198
  const hooks = hCollector.ctx.getAllHooks(node);
4198
4199
  const funcs = [...components, ...hooks];
4199
- for (const { node, func } of [...cExprs, ...nExprs]) {
4200
+ for (const { func, node } of [...cExprs, ...nExprs]) {
4200
4201
  if (!funcs.some((f) => f.node === func)) continue;
4201
4202
  context.report({
4203
+ data: { name: context.sourceCode.getText(node) },
4202
4204
  messageId: "default",
4203
- node,
4204
- data: { name: context.sourceCode.getText(node) }
4205
+ node
4205
4206
  });
4206
4207
  }
4207
4208
  }
@@ -4248,6 +4249,8 @@ function create$5(context) {
4248
4249
  /**
4249
4250
  * Check if a test expression is a null check on `ref.current` for a given ref name.
4250
4251
  * Matches forms like `ref.current === null`, `null === ref.current`, and their != variants.
4252
+ * @param test
4253
+ * @param refName
4251
4254
  */
4252
4255
  function isRefCurrentNullCheck(test, refName) {
4253
4256
  if (test.type !== AST_NODE_TYPES.BinaryExpression) return false;
@@ -4268,8 +4271,8 @@ function create$5(context) {
4268
4271
  MemberExpression(node) {
4269
4272
  if (!ast.isIdentifier(node.property, "current")) return;
4270
4273
  refAccesses.push({
4271
- node,
4272
- isWrite: match(node.parent).with({ type: AST_NODE_TYPES.AssignmentExpression }, (p) => p.left === node).with({ type: AST_NODE_TYPES.UpdateExpression }, (p) => p.argument === node).otherwise(() => false)
4274
+ isWrite: match(node.parent).with({ type: AST_NODE_TYPES.AssignmentExpression }, (p) => p.left === node).with({ type: AST_NODE_TYPES.UpdateExpression }, (p) => p.argument === node).otherwise(() => false),
4275
+ node
4273
4276
  });
4274
4277
  },
4275
4278
  "Program:exit"(program) {
@@ -4277,7 +4280,7 @@ function create$5(context) {
4277
4280
  const hooks = hCollector.ctx.getAllHooks(program);
4278
4281
  const funcs = new Set([...comps.map((c) => c.node), ...hooks.map((h) => h.node)]);
4279
4282
  const isCompOrHookFn = (n) => ast.isFunction(n) && funcs.has(n);
4280
- for (const { node, isWrite } of refAccesses) {
4283
+ for (const { isWrite, node } of refAccesses) {
4281
4284
  const obj = node.object;
4282
4285
  if (obj.type !== AST_NODE_TYPES.Identifier) continue;
4283
4286
  switch (true) {
@@ -6620,9 +6623,9 @@ function create$4(context) {
6620
6623
  }
6621
6624
  if (isArgumentUsingRefValue(context, args0)) return;
6622
6625
  context.report({
6626
+ data: { name: context.sourceCode.getText(node.callee) },
6623
6627
  messageId: "default",
6624
- node,
6625
- data: { name: context.sourceCode.getText(node.callee) }
6628
+ node
6626
6629
  });
6627
6630
  return;
6628
6631
  }
@@ -6674,26 +6677,26 @@ function create$4(context) {
6674
6677
  return [];
6675
6678
  };
6676
6679
  for (const [, calls] of setStateInEffectSetup) for (const call of calls) context.report({
6680
+ data: { name: call.name },
6677
6681
  messageId: "default",
6678
- node: call,
6679
- data: { name: call.name }
6682
+ node: call
6680
6683
  });
6681
6684
  for (const { callee } of trackedFnCalls) {
6682
6685
  if (!("name" in callee)) continue;
6683
6686
  const { name } = callee;
6684
6687
  const setStateCalls = getSetStateCalls(name, context.sourceCode.getScope(callee));
6685
6688
  for (const setStateCall of setStateCalls) context.report({
6689
+ data: { name: getCallName(setStateCall) },
6686
6690
  messageId: "default",
6687
- node: setStateCall,
6688
- data: { name: getCallName(setStateCall) }
6691
+ node: setStateCall
6689
6692
  });
6690
6693
  }
6691
6694
  for (const id of setupFnIds) {
6692
6695
  const setStateCalls = getSetStateCalls(id.name, context.sourceCode.getScope(id));
6693
6696
  for (const setStateCall of setStateCalls) context.report({
6697
+ data: { name: getCallName(setStateCall) },
6694
6698
  messageId: "default",
6695
- node: setStateCall,
6696
- data: { name: getCallName(setStateCall) }
6699
+ node: setStateCall
6697
6700
  });
6698
6701
  }
6699
6702
  }
@@ -6814,9 +6817,9 @@ function create$3(context) {
6814
6817
  if (isInsideConditional(node, componentFn)) return;
6815
6818
  if (componentHasEarlyReturn.current) return;
6816
6819
  context.report({
6820
+ data: { name: context.sourceCode.getText(node.callee) },
6817
6821
  messageId: "default",
6818
- node,
6819
- data: { name: context.sourceCode.getText(node.callee) }
6822
+ node
6820
6823
  });
6821
6824
  },
6822
6825
  ReturnStatement(node) {
@@ -6872,8 +6875,8 @@ function create$2(context) {
6872
6875
  const func = ast.findParentNode(node, ast.isFunction);
6873
6876
  if (func == null) return;
6874
6877
  evalCalls.push({
6875
- node,
6876
- func
6878
+ func,
6879
+ node
6877
6880
  });
6878
6881
  },
6879
6882
  "JSXElement :function"(node) {
@@ -6892,14 +6895,14 @@ function create$2(context) {
6892
6895
  const components = cCollector.ctx.getAllComponents(node);
6893
6896
  const hooks = hCollector.ctx.getAllHooks(node);
6894
6897
  const funcs = [...components, ...hooks];
6895
- for (const { node, func } of evalCalls) {
6898
+ for (const { func, node } of evalCalls) {
6896
6899
  if (!funcs.some((f) => f.node === func)) continue;
6897
6900
  context.report({
6898
6901
  messageId: "eval",
6899
6902
  node
6900
6903
  });
6901
6904
  }
6902
- for (const { node, func } of withStmts) {
6905
+ for (const { func, node } of withStmts) {
6903
6906
  if (!funcs.some((f) => f.node === func)) continue;
6904
6907
  context.report({
6905
6908
  messageId: "with",
@@ -6911,8 +6914,8 @@ function create$2(context) {
6911
6914
  const func = ast.findParentNode(node, ast.isFunction);
6912
6915
  if (func == null) return;
6913
6916
  withStmts.push({
6914
- node,
6915
- func
6917
+ func,
6918
+ node
6916
6919
  });
6917
6920
  }
6918
6921
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "3.0.0-next.57",
3
+ "version": "3.0.0-next.59",
4
4
  "description": "A set of composable ESLint rules for libraries and frameworks that use React as a UI runtime.",
5
5
  "keywords": [
6
6
  "react",
@@ -45,11 +45,11 @@
45
45
  "string-ts": "^2.3.1",
46
46
  "ts-api-utils": "^2.4.0",
47
47
  "ts-pattern": "^5.9.0",
48
- "@eslint-react/ast": "3.0.0-next.57",
49
- "@eslint-react/eff": "3.0.0-next.57",
50
- "@eslint-react/shared": "3.0.0-next.57",
51
- "@eslint-react/var": "3.0.0-next.57",
52
- "@eslint-react/core": "3.0.0-next.57"
48
+ "@eslint-react/ast": "3.0.0-next.59",
49
+ "@eslint-react/core": "3.0.0-next.59",
50
+ "@eslint-react/eff": "3.0.0-next.59",
51
+ "@eslint-react/shared": "3.0.0-next.59",
52
+ "@eslint-react/var": "3.0.0-next.59"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/react": "^19.2.14",