eslint-plugin-react-x 5.2.5-next.1 → 5.3.0-beta.1

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 +263 -239
  2. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -142,7 +142,7 @@ const rules$7 = {
142
142
  //#endregion
143
143
  //#region package.json
144
144
  var name$6 = "eslint-plugin-react-x";
145
- var version = "5.2.5-next.1";
145
+ var version = "5.3.0-beta.1";
146
146
 
147
147
  //#endregion
148
148
  //#region src/rules/component-hook-factories/lib.ts
@@ -215,14 +215,14 @@ var component_hook_factories_default = createRule({
215
215
  });
216
216
  function create$48(context) {
217
217
  const hint = core.FunctionComponentDetectionHint.DoNotIncludeJsxWithNumberValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithBooleanValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithNullValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithStringValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithUndefinedValue | core.FunctionComponentDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx | core.FunctionComponentDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx | core.FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayPatternElement | core.FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayExpressionElement | core.FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback;
218
- const fCollector = core.getFunctionComponentCollector(context, { hint });
219
- const cCollector = core.getClassComponentCollector(context);
220
- const hCollector = core.getHookCollector(context);
218
+ const fc = core.getFunctionComponentCollector(context, { hint });
219
+ const cc = core.getClassComponentCollector(context);
220
+ const hc = core.getHookCollector(context);
221
221
  const reported = /* @__PURE__ */ new Set();
222
- return merge(fCollector.visitor, cCollector.visitor, hCollector.visitor, { "Program:exit"(program) {
223
- const fComponents = [...fCollector.api.getAllComponents(program)];
224
- const cComponents = [...cCollector.api.getAllComponents(program)];
225
- const hooks = [...hCollector.api.getAllHooks(program)];
222
+ return merge(fc.visitor, cc.visitor, hc.visitor, { "Program:exit"(program) {
223
+ const fComponents = [...fc.api.getAllComponents(program)];
224
+ const cComponents = [...cc.api.getAllComponents(program)];
225
+ const hooks = [...hc.api.getAllHooks(program)];
226
226
  for (const { name, node } of fComponents) {
227
227
  if (name == null) continue;
228
228
  const parentFn = Traverse.findParent(node, Check.isFunction);
@@ -282,18 +282,18 @@ var error_boundaries_default = createRule({
282
282
  function create$47(context) {
283
283
  if (!context.sourceCode.text.includes("try")) return {};
284
284
  const hint = JsxDetectionHint.DoNotIncludeJsxWithNullValue | JsxDetectionHint.DoNotIncludeJsxWithNumberValue | JsxDetectionHint.DoNotIncludeJsxWithBigIntValue | JsxDetectionHint.DoNotIncludeJsxWithStringValue | JsxDetectionHint.DoNotIncludeJsxWithBooleanValue | JsxDetectionHint.DoNotIncludeJsxWithUndefinedValue | JsxDetectionHint.DoNotIncludeJsxWithEmptyArrayValue;
285
- const fCollector = core.getFunctionComponentCollector(context);
286
- const hCollector = core.getHookCollector(context);
285
+ const fc = core.getFunctionComponentCollector(context);
286
+ const hc = core.getHookCollector(context);
287
287
  const reported = /* @__PURE__ */ new Set();
288
288
  const useCalls = /* @__PURE__ */ new Set();
289
- return merge(fCollector.visitor, hCollector.visitor, {
289
+ return merge(fc.visitor, hc.visitor, {
290
290
  CallExpression(node) {
291
291
  if (!core.isUseCall(context, node)) return;
292
292
  useCalls.add(node);
293
293
  },
294
294
  "Program:exit"(node) {
295
- const comps = fCollector.api.getAllComponents(node);
296
- const hooks = hCollector.api.getAllHooks(node);
295
+ const comps = fc.api.getAllComponents(node);
296
+ const hooks = hc.api.getAllHooks(node);
297
297
  const funcs = [...comps, ...hooks];
298
298
  for (const call of useCalls) {
299
299
  const stmt = Traverse.findParent(call, is(AST_NODE_TYPES.TryStatement));
@@ -1229,8 +1229,7 @@ function getUnknownDependenciesMessage(reactiveHookName) {
1229
1229
  }
1230
1230
 
1231
1231
  //#endregion
1232
- //#region src/rules/immutability/immutability.ts
1233
- const RULE_NAME$46 = "immutability";
1232
+ //#region src/rules/immutability/lib.ts
1234
1233
  /**
1235
1234
  * Array methods that mutate the array in place.
1236
1235
  * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
@@ -1246,6 +1245,10 @@ const MUTATING_ARRAY_METHODS = new Set([
1246
1245
  "splice",
1247
1246
  "unshift"
1248
1247
  ]);
1248
+
1249
+ //#endregion
1250
+ //#region src/rules/immutability/immutability.ts
1251
+ const RULE_NAME$46 = "immutability";
1249
1252
  var immutability_default = createRule({
1250
1253
  meta: {
1251
1254
  type: "problem",
@@ -1262,8 +1265,8 @@ var immutability_default = createRule({
1262
1265
  });
1263
1266
  function create$46(context) {
1264
1267
  const { additionalStateHooks } = getSettingsFromContext(context);
1265
- const hCollector = core.getHookCollector(context);
1266
- const cCollector = core.getFunctionComponentCollector(context);
1268
+ const hc = core.getHookCollector(context);
1269
+ const fc = core.getFunctionComponentCollector(context);
1267
1270
  /**
1268
1271
  * Violations accumulated while traversing. Each entry records the node to
1269
1272
  * report and the enclosing function so we can filter at Program:exit.
@@ -1318,7 +1321,7 @@ function create$46(context) {
1318
1321
  }
1319
1322
  return null;
1320
1323
  }
1321
- return merge(hCollector.visitor, cCollector.visitor, {
1324
+ return merge(hc.visitor, fc.visitor, {
1322
1325
  CallExpression(node) {
1323
1326
  if (node.callee.type !== AST_NODE_TYPES.MemberExpression) return;
1324
1327
  const { object, property } = node.callee;
@@ -1362,8 +1365,8 @@ function create$46(context) {
1362
1365
  });
1363
1366
  },
1364
1367
  "Program:exit"(node) {
1365
- const comps = cCollector.api.getAllComponents(node);
1366
- const hooks = hCollector.api.getAllHooks(node);
1368
+ const comps = fc.api.getAllComponents(node);
1369
+ const hooks = hc.api.getAllHooks(node);
1367
1370
  const funcs = [...comps, ...hooks];
1368
1371
  for (const { data, func, messageId, node, propsDefiningFunc } of violations) {
1369
1372
  let current = func;
@@ -1667,10 +1670,6 @@ function report$2(context) {
1667
1670
  return context.report(descriptor);
1668
1671
  };
1669
1672
  }
1670
-
1671
- //#endregion
1672
- //#region src/rules/no-array-index-key/no-array-index-key.ts
1673
- const RULE_NAME$44 = "no-array-index-key";
1674
1673
  function getIndexParamPosition(methodName) {
1675
1674
  switch (methodName) {
1676
1675
  case "every":
@@ -1708,6 +1707,10 @@ function getIdentifiersFromBinaryExpression(side) {
1708
1707
  if (side.type === AST_NODE_TYPES.BinaryExpression) return [...getIdentifiersFromBinaryExpression(side.left), ...getIdentifiersFromBinaryExpression(side.right)];
1709
1708
  return [];
1710
1709
  }
1710
+
1711
+ //#endregion
1712
+ //#region src/rules/no-array-index-key/no-array-index-key.ts
1713
+ const RULE_NAME$44 = "no-array-index-key";
1711
1714
  var no_array_index_key_default = createRule({
1712
1715
  meta: {
1713
1716
  type: "suggestion",
@@ -2768,6 +2771,10 @@ function isProcessEnvNodeEnvCompare(node, operator, value) {
2768
2771
  if (Check.isLiteral("string")(node.left) && isProcessEnvNodeEnv(node.right)) return node.left.value === value;
2769
2772
  return false;
2770
2773
  }
2774
+ function isDevelopmentOnlyCheck(node) {
2775
+ if (node.type !== AST_NODE_TYPES.IfStatement) return false;
2776
+ return isProcessEnvNodeEnvCompare(node.test, "!==", "production");
2777
+ }
2771
2778
 
2772
2779
  //#endregion
2773
2780
  //#region src/rules/no-misused-capture-owner-stack/no-misused-capture-owner-stack.ts
@@ -2810,9 +2817,38 @@ function create$21(context) {
2810
2817
  }
2811
2818
  });
2812
2819
  }
2813
- function isDevelopmentOnlyCheck(node) {
2814
- if (node.type !== AST_NODE_TYPES.IfStatement) return false;
2815
- return isProcessEnvNodeEnvCompare(node.test, "!==", "production");
2820
+
2821
+ //#endregion
2822
+ //#region src/rules/no-nested-component-definitions/lib.ts
2823
+ /**
2824
+ * Determine whether the node is inside JSX attribute value
2825
+ * @param node The AST node to check
2826
+ * @returns `true` if the node is inside JSX attribute value
2827
+ */
2828
+ function isInsideJSXAttributeValue(node) {
2829
+ return node.parent.type === AST_NODE_TYPES.JSXAttribute || findParentAttribute(node, (n) => n.value?.type === AST_NODE_TYPES.JSXExpressionContainer) != null;
2830
+ }
2831
+ /**
2832
+ * Check whether a given node is declared inside a class component's render block
2833
+ * Ex: class C extends React.Component { render() { const Nested = () => <div />; } }
2834
+ * @param node The AST node being checked
2835
+ * @returns `true` if the node is inside a class component's render block
2836
+ */
2837
+ function isInsideRenderMethod(node) {
2838
+ return Traverse.findParent(node, (n) => core.isRenderMethodLike(n) && core.isClassComponent(n.parent.parent)) != null;
2839
+ }
2840
+ /**
2841
+ * Determine whether the node is inside `createElement`'s props argument
2842
+ * @param context The rule context
2843
+ * @param node The AST node to check
2844
+ * @returns `true` if the node is inside `createElement`'s props
2845
+ */
2846
+ function isInsideCreateElementProps(context, node) {
2847
+ const call = Traverse.findParent(node, core.isCreateElementCall(context));
2848
+ if (call == null) return false;
2849
+ const prop = Traverse.findParent(node, is(AST_NODE_TYPES.ObjectExpression));
2850
+ if (prop == null) return false;
2851
+ return prop === call.arguments[1];
2816
2852
  }
2817
2853
 
2818
2854
  //#endregion
@@ -2831,11 +2867,11 @@ var no_nested_component_definitions_default = createRule({
2831
2867
  });
2832
2868
  function create$20(context) {
2833
2869
  const hint = core.FunctionComponentDetectionHint.DoNotIncludeJsxWithNumberValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithBooleanValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithNullValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithStringValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithUndefinedValue | core.FunctionComponentDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx | core.FunctionComponentDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx | core.FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayPatternElement | core.FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayExpressionElement | core.FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback;
2834
- const fCollector = core.getFunctionComponentCollector(context, { hint });
2835
- const cCollector = core.getClassComponentCollector(context);
2836
- return merge(fCollector.visitor, cCollector.visitor, { "Program:exit"(program) {
2837
- const fComponents = [...fCollector.api.getAllComponents(program)];
2838
- const cComponents = [...cCollector.api.getAllComponents(program)];
2870
+ const fc = core.getFunctionComponentCollector(context, { hint });
2871
+ const cc = core.getClassComponentCollector(context);
2872
+ return merge(fc.visitor, cc.visitor, { "Program:exit"(program) {
2873
+ const fComponents = [...fc.api.getAllComponents(program)];
2874
+ const cComponents = [...cc.api.getAllComponents(program)];
2839
2875
  function findEnclosingComponent(node) {
2840
2876
  return Traverse.findParent(node, (n) => {
2841
2877
  if (Check.isFunction(n)) return fComponents.some((c) => c.node === n);
@@ -2900,36 +2936,6 @@ function create$20(context) {
2900
2936
  }
2901
2937
  } });
2902
2938
  }
2903
- /**
2904
- * Determine whether the node is inside JSX attribute value
2905
- * @param node The AST node to check
2906
- * @returns `true` if the node is inside JSX attribute value
2907
- */
2908
- function isInsideJSXAttributeValue(node) {
2909
- return node.parent.type === AST_NODE_TYPES.JSXAttribute || findParentAttribute(node, (n) => n.value?.type === AST_NODE_TYPES.JSXExpressionContainer) != null;
2910
- }
2911
- /**
2912
- * Check whether a given node is declared inside a class component's render block
2913
- * Ex: class C extends React.Component { render() { const Nested = () => <div />; } }
2914
- * @param node The AST node being checked
2915
- * @returns `true` if the node is inside a class component's render block
2916
- */
2917
- function isInsideRenderMethod(node) {
2918
- return Traverse.findParent(node, (n) => core.isRenderMethodLike(n) && core.isClassComponent(n.parent.parent)) != null;
2919
- }
2920
- /**
2921
- * Determine whether the node is inside `createElement`'s props argument
2922
- * @param context The rule context
2923
- * @param node The AST node to check
2924
- * @returns `true` if the node is inside `createElement`'s props
2925
- */
2926
- function isInsideCreateElementProps(context, node) {
2927
- const call = Traverse.findParent(node, core.isCreateElementCall(context));
2928
- if (call == null) return false;
2929
- const prop = Traverse.findParent(node, is(AST_NODE_TYPES.ObjectExpression));
2930
- if (prop == null) return false;
2931
- return prop === call.arguments[1];
2932
- }
2933
2939
 
2934
2940
  //#endregion
2935
2941
  //#region src/rules/no-nested-lazy-component-declarations/no-nested-lazy-component-declarations.ts
@@ -2946,20 +2952,20 @@ var no_nested_lazy_component_declarations_default = createRule({
2946
2952
  defaultOptions: []
2947
2953
  });
2948
2954
  function create$19(context) {
2949
- const fCollector = core.getFunctionComponentCollector(context);
2950
- const cCollector = core.getClassComponentCollector(context);
2951
- const hCollector = core.getHookCollector(context);
2955
+ const fc = core.getFunctionComponentCollector(context);
2956
+ const cc = core.getClassComponentCollector(context);
2957
+ const hc = core.getHookCollector(context);
2952
2958
  const lazyCalls = /* @__PURE__ */ new Set();
2953
- return merge(fCollector.visitor, cCollector.visitor, hCollector.visitor, {
2959
+ return merge(fc.visitor, cc.visitor, hc.visitor, {
2954
2960
  ImportExpression(node) {
2955
2961
  const lazyCall = Traverse.findParent(node, (n) => core.isLazyCall(context, n));
2956
2962
  if (lazyCall != null) lazyCalls.add(lazyCall);
2957
2963
  },
2958
2964
  "Program:exit"(program) {
2959
2965
  const significantParents = [
2960
- ...fCollector.api.getAllComponents(program),
2961
- ...hCollector.api.getAllHooks(program),
2962
- ...cCollector.api.getAllComponents(program)
2966
+ ...fc.api.getAllComponents(program),
2967
+ ...hc.api.getAllHooks(program),
2968
+ ...cc.api.getAllComponents(program)
2963
2969
  ];
2964
2970
  for (const lazy of lazyCalls) if (Traverse.findParent(lazy, (n) => significantParents.some((p) => p.node === n))) context.report({
2965
2971
  messageId: "default",
@@ -3189,6 +3195,14 @@ function create$12(context) {
3189
3195
  } });
3190
3196
  }
3191
3197
 
3198
+ //#endregion
3199
+ //#region src/rules/no-unstable-context-value/lib.ts
3200
+ function isContextName(name, isReact18OrBelow) {
3201
+ if (name === "Provider") return true;
3202
+ if (!isReact18OrBelow) return name.endsWith("Context") || name.endsWith("CONTEXT");
3203
+ return false;
3204
+ }
3205
+
3192
3206
  //#endregion
3193
3207
  //#region src/rules/no-unstable-context-value/no-unstable-context-value.ts
3194
3208
  const RULE_NAME$11 = "no-unstable-context-value";
@@ -3247,11 +3261,6 @@ function create$11(context) {
3247
3261
  }
3248
3262
  });
3249
3263
  }
3250
- function isContextName(name, isReact18OrBelow) {
3251
- if (name === "Provider") return true;
3252
- if (!isReact18OrBelow) return name.endsWith("Context") || name.endsWith("CONTEXT");
3253
- return false;
3254
- }
3255
3264
 
3256
3265
  //#endregion
3257
3266
  //#region src/rules/no-unstable-default-props/lib.ts
@@ -3337,8 +3346,7 @@ function create$10(context, [options]) {
3337
3346
  }
3338
3347
 
3339
3348
  //#endregion
3340
- //#region src/rules/no-unused-class-component-members/no-unused-class-component-members.ts
3341
- const RULE_NAME$9 = "no-unused-class-component-members";
3349
+ //#region src/rules/no-unused-class-component-members/lib.ts
3342
3350
  const LIFECYCLE_METHODS = new Set([
3343
3351
  "componentDidCatch",
3344
3352
  "componentDidMount",
@@ -3362,6 +3370,10 @@ function isKeyLiteral(node, key) {
3362
3370
  expressions: []
3363
3371
  }, constTrue).with({ type: AST_NODE_TYPES.Identifier }, () => !node.computed).otherwise(constFalse);
3364
3372
  }
3373
+
3374
+ //#endregion
3375
+ //#region src/rules/no-unused-class-component-members/no-unused-class-component-members.ts
3376
+ const RULE_NAME$9 = "no-unused-class-component-members";
3365
3377
  var no_unused_class_component_members_default = createRule({
3366
3378
  meta: {
3367
3379
  type: "suggestion",
@@ -3453,43 +3465,7 @@ function create$9(context) {
3453
3465
  }
3454
3466
 
3455
3467
  //#endregion
3456
- //#region src/rules/no-unused-props/no-unused-props.ts
3457
- const RULE_NAME$8 = "no-unused-props";
3458
- var no_unused_props_default = createRule({
3459
- meta: {
3460
- type: "suggestion",
3461
- docs: { description: "Warns about component props that are defined but never used." },
3462
- messages: { default: "Prop `{{name}}` is declared but never used" },
3463
- schema: []
3464
- },
3465
- name: RULE_NAME$8,
3466
- create: create$8,
3467
- defaultOptions: []
3468
- });
3469
- function create$8(context) {
3470
- const services = ESLintUtils.getParserServices(context, false);
3471
- const checker = services.program.getTypeChecker();
3472
- const { api, visitor } = core.getFunctionComponentCollector(context);
3473
- return merge(visitor, { "Program:exit"(program) {
3474
- const totalDeclaredProps = /* @__PURE__ */ new Map();
3475
- const totalUsedDeclarations = /* @__PURE__ */ new Set();
3476
- for (const component of api.getAllComponents(program)) {
3477
- const [props] = component.node.params;
3478
- if (props == null) continue;
3479
- const usedPropKeys = /* @__PURE__ */ new Set();
3480
- if (!collectUsedPropKeysOfParameter(context, usedPropKeys, props)) continue;
3481
- const tsNode = services.esTreeNodeToTSNodeMap.get(props);
3482
- const declaredProps = checker.getTypeAtLocation(tsNode).getProperties();
3483
- for (const declaredProp of declaredProps) {
3484
- const declaration = declaredProp.getDeclarations()?.[0];
3485
- if (declaration == null) continue;
3486
- if (!totalDeclaredProps.has(declaration)) totalDeclaredProps.set(declaration, declaredProp);
3487
- if (usedPropKeys.has(declaredProp.name)) totalUsedDeclarations.add(declaration);
3488
- }
3489
- }
3490
- for (const [declaration, symbol] of totalDeclaredProps.entries()) if (!totalUsedDeclarations.has(declaration)) reportUnusedProp(context, services, symbol);
3491
- } });
3492
- }
3468
+ //#region src/rules/no-unused-props/lib.ts
3493
3469
  function collectUsedPropKeysOfParameter(context, usedPropKeys, parameter) {
3494
3470
  switch (parameter.type) {
3495
3471
  case AST_NODE_TYPES.Identifier: return collectUsedPropKeysOfIdentifier(context, usedPropKeys, parameter);
@@ -3552,6 +3528,45 @@ function getKeyOfExpression(expr) {
3552
3528
  }
3553
3529
  return null;
3554
3530
  }
3531
+
3532
+ //#endregion
3533
+ //#region src/rules/no-unused-props/no-unused-props.ts
3534
+ const RULE_NAME$8 = "no-unused-props";
3535
+ var no_unused_props_default = createRule({
3536
+ meta: {
3537
+ type: "suggestion",
3538
+ docs: { description: "Warns about component props that are defined but never used." },
3539
+ messages: { default: "Prop `{{name}}` is declared but never used" },
3540
+ schema: []
3541
+ },
3542
+ name: RULE_NAME$8,
3543
+ create: create$8,
3544
+ defaultOptions: []
3545
+ });
3546
+ function create$8(context) {
3547
+ const services = ESLintUtils.getParserServices(context, false);
3548
+ const checker = services.program.getTypeChecker();
3549
+ const { api, visitor } = core.getFunctionComponentCollector(context);
3550
+ return merge(visitor, { "Program:exit"(program) {
3551
+ const totalDeclaredProps = /* @__PURE__ */ new Map();
3552
+ const totalUsedDeclarations = /* @__PURE__ */ new Set();
3553
+ for (const component of api.getAllComponents(program)) {
3554
+ const [props] = component.node.params;
3555
+ if (props == null) continue;
3556
+ const usedPropKeys = /* @__PURE__ */ new Set();
3557
+ if (!collectUsedPropKeysOfParameter(context, usedPropKeys, props)) continue;
3558
+ const tsNode = services.esTreeNodeToTSNodeMap.get(props);
3559
+ const declaredProps = checker.getTypeAtLocation(tsNode).getProperties();
3560
+ for (const declaredProp of declaredProps) {
3561
+ const declaration = declaredProp.getDeclarations()?.[0];
3562
+ if (declaration == null) continue;
3563
+ if (!totalDeclaredProps.has(declaration)) totalDeclaredProps.set(declaration, declaredProp);
3564
+ if (usedPropKeys.has(declaredProp.name)) totalUsedDeclarations.add(declaration);
3565
+ }
3566
+ }
3567
+ for (const [declaration, symbol] of totalDeclaredProps.entries()) if (!totalUsedDeclarations.has(declaration)) reportUnusedProp(context, services, symbol);
3568
+ } });
3569
+ }
3555
3570
  function reportUnusedProp(context, services, prop) {
3556
3571
  const declaration = prop.getDeclarations()?.[0];
3557
3572
  if (declaration == null) return;
@@ -3906,11 +3921,11 @@ var purity_default = createRule({
3906
3921
  defaultOptions: []
3907
3922
  });
3908
3923
  function create$6(context) {
3909
- const hCollector = core.getHookCollector(context);
3910
- const cCollector = core.getFunctionComponentCollector(context);
3924
+ const hc = core.getHookCollector(context);
3925
+ const fc = core.getFunctionComponentCollector(context);
3911
3926
  const cEntries = [];
3912
3927
  const nEntries = [];
3913
- return merge(hCollector.visitor, cCollector.visitor, {
3928
+ return merge(hc.visitor, fc.visitor, {
3914
3929
  CallExpression(node) {
3915
3930
  const expr = Extract.unwrap(node.callee);
3916
3931
  switch (true) {
@@ -3951,8 +3966,8 @@ function create$6(context) {
3951
3966
  });
3952
3967
  },
3953
3968
  "Program:exit"(node) {
3954
- const comps = cCollector.api.getAllComponents(node);
3955
- const hooks = hCollector.api.getAllHooks(node);
3969
+ const comps = fc.api.getAllComponents(node);
3970
+ const hooks = hc.api.getAllHooks(node);
3956
3971
  const funcs = [...comps, ...hooks];
3957
3972
  for (const { func, node } of [...cEntries, ...nEntries]) {
3958
3973
  if (!funcs.some((f) => f.node === func)) continue;
@@ -3966,6 +3981,54 @@ function create$6(context) {
3966
3981
  });
3967
3982
  }
3968
3983
 
3984
+ //#endregion
3985
+ //#region src/rules/refs/lib.ts
3986
+ /**
3987
+ * Check if the node is the operand of a `ref.current === null` test inside an IfStatement.
3988
+ * @param node The MemberExpression node for ref.current
3989
+ * @returns true if the node is part of a null check test in an if statement
3990
+ */
3991
+ function isInNullCheckTest(node) {
3992
+ let parent = node.parent;
3993
+ while (Check.isTypeExpression(parent)) parent = parent.parent;
3994
+ if (!isMatching({
3995
+ type: AST_NODE_TYPES.BinaryExpression,
3996
+ operator: P.union("===", "==", "!==", "!=")
3997
+ }, parent)) return false;
3998
+ const otherSide = parent.left === node || Extract.unwrap(parent.left) === node ? parent.right : parent.left;
3999
+ if (otherSide.type !== AST_NODE_TYPES.Literal || otherSide.value != null) return false;
4000
+ return parent.parent.type === AST_NODE_TYPES.IfStatement && parent.parent.test === parent;
4001
+ }
4002
+ /**
4003
+ * Check if a test expression is a null check on `ref.current` for a given ref name.
4004
+ * Matches forms like `ref.current === null`, `null === ref.current`, and their != variants.
4005
+ * @param test The test expression to check.
4006
+ * @param refName The name of the ref variable.
4007
+ */
4008
+ function isRefCurrentNullCheck(test, refName) {
4009
+ if (test.type !== AST_NODE_TYPES.BinaryExpression) return false;
4010
+ const op = test.operator;
4011
+ if (op !== "===" && op !== "==" && op !== "!==" && op !== "!=") return false;
4012
+ const { left, right } = test;
4013
+ const checkSides = (a, b) => {
4014
+ a = Check.isTypeExpression(a) ? Extract.unwrap(a) : a;
4015
+ return a.type === AST_NODE_TYPES.MemberExpression && a.object.type === AST_NODE_TYPES.Identifier && a.object.name === refName && b.type === AST_NODE_TYPES.Literal && b.value == null && Extract.getPropertyName(a.property) === "current";
4016
+ };
4017
+ return checkSides(left, right) || checkSides(right, left);
4018
+ }
4019
+ function isInitializedFromRef$1(context, name, initialScope) {
4020
+ for (const { node } of findVariable(initialScope, name)?.defs ?? []) {
4021
+ if (node.type !== AST_NODE_TYPES.VariableDeclarator) continue;
4022
+ const init = node.init;
4023
+ if (init == null) continue;
4024
+ switch (true) {
4025
+ case init.type === AST_NODE_TYPES.MemberExpression && init.object.type === AST_NODE_TYPES.Identifier && (init.object.name === "ref" || init.object.name.endsWith("Ref")): return true;
4026
+ case init.type === AST_NODE_TYPES.CallExpression && core.isUseRefCall(context, init): return true;
4027
+ }
4028
+ }
4029
+ return false;
4030
+ }
4031
+
3969
4032
  //#endregion
3970
4033
  //#region src/rules/refs/refs.ts
3971
4034
  const RULE_NAME$5 = "refs";
@@ -3984,56 +4047,11 @@ var refs_default = createRule({
3984
4047
  defaultOptions: []
3985
4048
  });
3986
4049
  function create$5(context) {
3987
- const hCollector = core.getHookCollector(context);
3988
- const cCollector = core.getFunctionComponentCollector(context);
4050
+ const hc = core.getHookCollector(context);
4051
+ const fc = core.getFunctionComponentCollector(context);
3989
4052
  const refAccesses = [];
3990
4053
  const jsxRefIdentifiers = /* @__PURE__ */ new Set();
3991
- /**
3992
- * Check if the node is the operand of a `ref.current === null` test inside an IfStatement.
3993
- * @param node The MemberExpression node for ref.current
3994
- * @returns true if the node is part of a null check test in an if statement
3995
- */
3996
- function isInNullCheckTest(node) {
3997
- let parent = node.parent;
3998
- while (Check.isTypeExpression(parent)) parent = parent.parent;
3999
- if (!isMatching({
4000
- type: AST_NODE_TYPES.BinaryExpression,
4001
- operator: P.union("===", "==", "!==", "!=")
4002
- }, parent)) return false;
4003
- const otherSide = parent.left === node || Extract.unwrap(parent.left) === node ? parent.right : parent.left;
4004
- if (otherSide.type !== AST_NODE_TYPES.Literal || otherSide.value != null) return false;
4005
- return parent.parent.type === AST_NODE_TYPES.IfStatement && parent.parent.test === parent;
4006
- }
4007
- /**
4008
- * Check if a test expression is a null check on `ref.current` for a given ref name.
4009
- * Matches forms like `ref.current === null`, `null === ref.current`, and their != variants.
4010
- * @param test The test expression to check.
4011
- * @param refName The name of the ref variable.
4012
- */
4013
- function isRefCurrentNullCheck(test, refName) {
4014
- if (test.type !== AST_NODE_TYPES.BinaryExpression) return false;
4015
- const op = test.operator;
4016
- if (op !== "===" && op !== "==" && op !== "!==" && op !== "!=") return false;
4017
- const { left, right } = test;
4018
- const checkSides = (a, b) => {
4019
- a = Check.isTypeExpression(a) ? Extract.unwrap(a) : a;
4020
- return a.type === AST_NODE_TYPES.MemberExpression && a.object.type === AST_NODE_TYPES.Identifier && a.object.name === refName && b.type === AST_NODE_TYPES.Literal && b.value == null && Extract.getPropertyName(a.property) === "current";
4021
- };
4022
- return checkSides(left, right) || checkSides(right, left);
4023
- }
4024
- function isInitializedFromRef(name, initialScope) {
4025
- for (const { node } of findVariable(initialScope, name)?.defs ?? []) {
4026
- if (node.type !== AST_NODE_TYPES.VariableDeclarator) continue;
4027
- const init = node.init;
4028
- if (init == null) continue;
4029
- switch (true) {
4030
- case init.type === AST_NODE_TYPES.MemberExpression && init.object.type === AST_NODE_TYPES.Identifier && (init.object.name === "ref" || init.object.name.endsWith("Ref")): return true;
4031
- case init.type === AST_NODE_TYPES.CallExpression && core.isUseRefCall(context, init): return true;
4032
- }
4033
- }
4034
- return false;
4035
- }
4036
- return merge(hCollector.visitor, cCollector.visitor, {
4054
+ return merge(hc.visitor, fc.visitor, {
4037
4055
  JSXAttribute(node) {
4038
4056
  switch (true) {
4039
4057
  case node.name.type === AST_NODE_TYPES.JSXIdentifier && node.name.name === "ref" && node.value?.type === AST_NODE_TYPES.JSXExpressionContainer && node.value.expression.type === AST_NODE_TYPES.Identifier:
@@ -4053,8 +4071,8 @@ function create$5(context) {
4053
4071
  });
4054
4072
  },
4055
4073
  "Program:exit"(program) {
4056
- const comps = cCollector.api.getAllComponents(program);
4057
- const hooks = hCollector.api.getAllHooks(program);
4074
+ const comps = fc.api.getAllComponents(program);
4075
+ const hooks = hc.api.getAllHooks(program);
4058
4076
  const funcs = new Set([...comps.map((c) => c.node), ...hooks.map((h) => h.node)]);
4059
4077
  const isCompOrHookFn = (n) => Check.isFunction(n) && funcs.has(n);
4060
4078
  for (const { isWrite, node } of refAccesses) {
@@ -4063,7 +4081,7 @@ function create$5(context) {
4063
4081
  switch (true) {
4064
4082
  case obj.name === "ref" || obj.name.endsWith("Ref"):
4065
4083
  case jsxRefIdentifiers.has(obj.name):
4066
- case isInitializedFromRef(obj.name, context.sourceCode.getScope(node.object)): break;
4084
+ case isInitializedFromRef$1(context, obj.name, context.sourceCode.getScope(node.object)): break;
4067
4085
  default: continue;
4068
4086
  }
4069
4087
  const boundary = Traverse.findParent(node, isCompOrHookFn);
@@ -6346,6 +6364,29 @@ function getNestedIdentifiers(node) {
6346
6364
  if (node.type === AST_NODE_TYPES.TSInstantiationExpression) identifiers.push(...getNestedIdentifiers(node.expression));
6347
6365
  return identifiers;
6348
6366
  }
6367
+ function isHookDecl(node) {
6368
+ if (node.type !== AST_NODE_TYPES.VariableDeclarator) return false;
6369
+ if (node.id.type !== AST_NODE_TYPES.Identifier) return false;
6370
+ const init = node.init;
6371
+ if (init == null || init.type !== AST_NODE_TYPES.CallExpression) return false;
6372
+ switch (init.callee.type) {
6373
+ case AST_NODE_TYPES.Identifier: return core.isHookName(init.callee.name);
6374
+ case AST_NODE_TYPES.MemberExpression: return init.callee.property.type === AST_NODE_TYPES.Identifier && core.isHookName(init.callee.property.name);
6375
+ default: return false;
6376
+ }
6377
+ }
6378
+ function isInitializedFromRef(context, name, initialScope) {
6379
+ for (const { node } of findVariable(initialScope, name)?.defs ?? []) {
6380
+ if (node.type !== AST_NODE_TYPES.VariableDeclarator) continue;
6381
+ const init = node.init;
6382
+ if (init == null) continue;
6383
+ switch (true) {
6384
+ case init.type === AST_NODE_TYPES.MemberExpression && init.object.type === AST_NODE_TYPES.Identifier && (init.object.name === "ref" || init.object.name.endsWith("Ref")): return true;
6385
+ case init.type === AST_NODE_TYPES.CallExpression && core.isUseRefCall(context, init): return true;
6386
+ }
6387
+ }
6388
+ return false;
6389
+ }
6349
6390
 
6350
6391
  //#endregion
6351
6392
  //#region src/rules/set-state-in-effect/set-state-in-effect.ts
@@ -6437,29 +6478,6 @@ function create$4(context) {
6437
6478
  default: return false;
6438
6479
  }
6439
6480
  }
6440
- function isHookDecl(node) {
6441
- if (node.type !== AST_NODE_TYPES.VariableDeclarator) return false;
6442
- if (node.id.type !== AST_NODE_TYPES.Identifier) return false;
6443
- const init = node.init;
6444
- if (init == null || init.type !== AST_NODE_TYPES.CallExpression) return false;
6445
- switch (init.callee.type) {
6446
- case AST_NODE_TYPES.Identifier: return core.isHookName(init.callee.name);
6447
- case AST_NODE_TYPES.MemberExpression: return init.callee.property.type === AST_NODE_TYPES.Identifier && core.isHookName(init.callee.property.name);
6448
- default: return false;
6449
- }
6450
- }
6451
- function isInitializedFromRef(name, initialScope) {
6452
- for (const { node } of findVariable(initialScope, name)?.defs ?? []) {
6453
- if (node.type !== AST_NODE_TYPES.VariableDeclarator) continue;
6454
- const init = node.init;
6455
- if (init == null) continue;
6456
- switch (true) {
6457
- case init.type === AST_NODE_TYPES.MemberExpression && init.object.type === AST_NODE_TYPES.Identifier && (init.object.name === "ref" || init.object.name.endsWith("Ref")): return true;
6458
- case init.type === AST_NODE_TYPES.CallExpression && core.isUseRefCall(context, init): return true;
6459
- }
6460
- }
6461
- return false;
6462
- }
6463
6481
  return merge({
6464
6482
  ":function"(node) {
6465
6483
  const kind = getFunctionKind(node);
@@ -6489,7 +6507,7 @@ function create$4(context) {
6489
6507
  function isArgumentUsingRefValue(context, node) {
6490
6508
  const isUsingRefValue = (n) => {
6491
6509
  switch (n.type) {
6492
- case AST_NODE_TYPES.Identifier: return isInitializedFromRef(n.name, context.sourceCode.getScope(n));
6510
+ case AST_NODE_TYPES.Identifier: return isInitializedFromRef(context, n.name, context.sourceCode.getScope(n));
6493
6511
  case AST_NODE_TYPES.MemberExpression: return isUsingRefValue(n.object);
6494
6512
  case AST_NODE_TYPES.CallExpression: return isUsingRefValue(n.callee) || getNestedIdentifiers(n).some(isUsingRefValue);
6495
6513
  default: return false;
@@ -6579,6 +6597,39 @@ function create$4(context) {
6579
6597
  });
6580
6598
  }
6581
6599
 
6600
+ //#endregion
6601
+ //#region src/rules/set-state-in-render/lib.ts
6602
+ function isInsideConditional(node, stopAt) {
6603
+ let current = node.parent;
6604
+ while (current != null && current !== stopAt) {
6605
+ switch (current.type) {
6606
+ case AST_NODE_TYPES.IfStatement:
6607
+ case AST_NODE_TYPES.ConditionalExpression:
6608
+ case AST_NODE_TYPES.LogicalExpression:
6609
+ case AST_NODE_TYPES.SwitchStatement:
6610
+ case AST_NODE_TYPES.SwitchCase: return true;
6611
+ default: break;
6612
+ }
6613
+ current = current.parent;
6614
+ }
6615
+ return false;
6616
+ }
6617
+ function isInsideEventHandler(node, stopAt) {
6618
+ let current = node.parent;
6619
+ while (current != null && current !== stopAt) {
6620
+ if (Check.isFunction(current) && current !== stopAt) return true;
6621
+ current = current.parent;
6622
+ }
6623
+ return false;
6624
+ }
6625
+ function isComponentOrHookLikeFunction(node) {
6626
+ const id = core.getFunctionId(node);
6627
+ if (id == null) return false;
6628
+ if (id.type === AST_NODE_TYPES.Identifier) return core.isFunctionComponentName(id.name) || core.isHookName(id.name);
6629
+ if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) return core.isFunctionComponentName(id.property.name) || core.isHookName(id.property.name);
6630
+ return false;
6631
+ }
6632
+
6582
6633
  //#endregion
6583
6634
  //#region src/rules/set-state-in-render/set-state-in-render.ts
6584
6635
  const RULE_NAME$3 = "set-state-in-render";
@@ -6630,36 +6681,6 @@ function create$3(context) {
6630
6681
  default: return false;
6631
6682
  }
6632
6683
  }
6633
- function isInsideConditional(node, stopAt) {
6634
- let current = node.parent;
6635
- while (current != null && current !== stopAt) {
6636
- switch (current.type) {
6637
- case AST_NODE_TYPES.IfStatement:
6638
- case AST_NODE_TYPES.ConditionalExpression:
6639
- case AST_NODE_TYPES.LogicalExpression:
6640
- case AST_NODE_TYPES.SwitchStatement:
6641
- case AST_NODE_TYPES.SwitchCase: return true;
6642
- default: break;
6643
- }
6644
- current = current.parent;
6645
- }
6646
- return false;
6647
- }
6648
- function isInsideEventHandler(node, stopAt) {
6649
- let current = node.parent;
6650
- while (current != null && current !== stopAt) {
6651
- if (Check.isFunction(current) && current !== stopAt) return true;
6652
- current = current.parent;
6653
- }
6654
- return false;
6655
- }
6656
- function isComponentOrHookLikeFunction(node) {
6657
- const id = core.getFunctionId(node);
6658
- if (id == null) return false;
6659
- if (id.type === AST_NODE_TYPES.Identifier) return core.isFunctionComponentName(id.name) || core.isHookName(id.name);
6660
- if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) return core.isFunctionComponentName(id.property.name) || core.isHookName(id.property.name);
6661
- return false;
6662
- }
6663
6684
  function getFunctionKind(node) {
6664
6685
  if (isComponentOrHookLikeFunction(node)) return "component";
6665
6686
  const parent = Traverse.findParent(node, not(Check.isTypeExpression)) ?? node.parent;
@@ -6716,6 +6737,15 @@ function create$3(context) {
6716
6737
  });
6717
6738
  }
6718
6739
 
6740
+ //#endregion
6741
+ //#region src/rules/unsupported-syntax/lib.ts
6742
+ function isEvalCall(node) {
6743
+ return node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === "eval";
6744
+ }
6745
+ function isIifeCall(node) {
6746
+ return node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node;
6747
+ }
6748
+
6719
6749
  //#endregion
6720
6750
  //#region src/rules/unsupported-syntax/unsupported-syntax.ts
6721
6751
  const RULE_NAME$2 = "unsupported-syntax";
@@ -6734,18 +6764,12 @@ var unsupported_syntax_default = createRule({
6734
6764
  create: create$2,
6735
6765
  defaultOptions: []
6736
6766
  });
6737
- function isEvalCall(node) {
6738
- return node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === "eval";
6739
- }
6740
- function isIifeCall(node) {
6741
- return node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node;
6742
- }
6743
6767
  function create$2(context) {
6744
- const hCollector = core.getHookCollector(context);
6745
- const cCollector = core.getFunctionComponentCollector(context);
6768
+ const hc = core.getHookCollector(context);
6769
+ const fc = core.getFunctionComponentCollector(context);
6746
6770
  const evalCalls = [];
6747
6771
  const withStmts = [];
6748
- return merge(hCollector.visitor, cCollector.visitor, {
6772
+ return merge(hc.visitor, fc.visitor, {
6749
6773
  CallExpression(node) {
6750
6774
  if (!isEvalCall(node)) return;
6751
6775
  const func = Traverse.findParent(node, Check.isFunction);
@@ -6768,8 +6792,8 @@ function create$2(context) {
6768
6792
  });
6769
6793
  },
6770
6794
  "Program:exit"(node) {
6771
- const components = cCollector.api.getAllComponents(node);
6772
- const hooks = hCollector.api.getAllHooks(node);
6795
+ const components = fc.api.getAllComponents(node);
6796
+ const hooks = hc.api.getAllHooks(node);
6773
6797
  const funcs = [...components, ...hooks];
6774
6798
  for (const { func, node } of evalCalls) {
6775
6799
  if (!funcs.some((f) => f.node === func)) continue;
@@ -6849,6 +6873,11 @@ function create$1(context) {
6849
6873
 
6850
6874
  //#endregion
6851
6875
  //#region src/rules/use-state/lib.ts
6876
+ const LAZY_INIT_ALLOW_LIST = [
6877
+ "Boolean",
6878
+ "String",
6879
+ "Number"
6880
+ ];
6852
6881
  /**
6853
6882
  * Get all nested expressions of type T in an expression like node
6854
6883
  * @param type The type of the expression to retrieve within the node
@@ -6968,11 +6997,6 @@ const schema = [{
6968
6997
  }
6969
6998
  }
6970
6999
  }];
6971
- const LAZY_INIT_ALLOW_LIST = [
6972
- "Boolean",
6973
- "String",
6974
- "Number"
6975
- ];
6976
7000
  var use_state_default = createRule({
6977
7001
  meta: {
6978
7002
  type: "suggestion",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "5.2.5-next.1",
3
+ "version": "5.3.0-beta.1",
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",
@@ -46,24 +46,24 @@
46
46
  "string-ts": "^2.3.1",
47
47
  "ts-api-utils": "^2.5.0",
48
48
  "ts-pattern": "^5.9.0",
49
- "@eslint-react/ast": "5.2.5-next.1",
50
- "@eslint-react/eslint": "5.2.5-next.1",
51
- "@eslint-react/jsx": "5.2.5-next.1",
52
- "@eslint-react/shared": "5.2.5-next.1",
53
- "@eslint-react/core": "5.2.5-next.1",
54
- "@eslint-react/var": "5.2.5-next.1"
49
+ "@eslint-react/ast": "5.3.0-beta.1",
50
+ "@eslint-react/eslint": "5.3.0-beta.1",
51
+ "@eslint-react/core": "5.3.0-beta.1",
52
+ "@eslint-react/jsx": "5.3.0-beta.1",
53
+ "@eslint-react/shared": "5.3.0-beta.1",
54
+ "@eslint-react/var": "5.3.0-beta.1"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/react": "^19.2.14",
58
58
  "@types/react-dom": "^19.2.3",
59
- "eslint": "^10.2.0",
59
+ "eslint": "^10.2.1",
60
60
  "tsdown": "^0.21.9",
61
61
  "tsl-dx": "^0.11.0",
62
- "@local/configs": "0.0.0",
63
- "@local/eff": "3.0.0-beta.72"
62
+ "@local/eff": "3.0.0-beta.72",
63
+ "@local/configs": "0.0.0"
64
64
  },
65
65
  "peerDependencies": {
66
- "eslint": "^10.2.0",
66
+ "eslint": "^10.2.1",
67
67
  "typescript": "*"
68
68
  },
69
69
  "engines": {