eslint-plugin-react-x 2.7.2-beta.2 → 2.7.2-beta.3

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 +212 -258
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { DEFAULT_ESLINT_REACT_SETTINGS, WEBSITE_URL, coerceSettings, getConfigAdapters, getSettingsFromContext, report, toRegExp } from "@eslint-react/shared";
1
+ import { DEFAULT_ESLINT_REACT_SETTINGS, WEBSITE_URL, coerceSettings, defineRuleListener, getConfigAdapters, getSettingsFromContext, report, toRegExp } from "@eslint-react/shared";
2
2
  import { AST_NODE_TYPES } from "@typescript-eslint/types";
3
3
  import { ESLintUtils } from "@typescript-eslint/utils";
4
4
  import { P, isMatching, match } from "ts-pattern";
@@ -68,7 +68,7 @@ const rules$7 = {
68
68
  //#endregion
69
69
  //#region package.json
70
70
  var name$6 = "eslint-plugin-react-x";
71
- var version = "2.7.2-beta.2";
71
+ var version = "2.7.2-beta.3";
72
72
 
73
73
  //#endregion
74
74
  //#region src/utils/create-rule.ts
@@ -937,20 +937,17 @@ var no_class_component_default = createRule({
937
937
  });
938
938
  function create$45(context) {
939
939
  if (!context.sourceCode.text.includes("Component")) return {};
940
- const { ctx, listeners } = useComponentCollectorLegacy(context);
941
- return {
942
- ...listeners,
943
- "Program:exit"(program) {
944
- for (const { name: name$9 = "anonymous", node: component } of ctx.getAllComponents(program)) {
945
- if (component.body.body.some((m) => isComponentDidCatch(m) || isGetDerivedStateFromError(m))) continue;
946
- context.report({
947
- messageId: "noClassComponent",
948
- node: component,
949
- data: { name: name$9 }
950
- });
951
- }
940
+ const { ctx, visitors } = useComponentCollectorLegacy(context);
941
+ return defineRuleListener(visitors, { "Program:exit"(program) {
942
+ for (const { name: name$9 = "anonymous", node: component } of ctx.getAllComponents(program)) {
943
+ if (component.body.body.some((m) => isComponentDidCatch(m) || isGetDerivedStateFromError(m))) continue;
944
+ context.report({
945
+ messageId: "noClassComponent",
946
+ node: component,
947
+ data: { name: name$9 }
948
+ });
952
949
  }
953
- };
950
+ } });
954
951
  }
955
952
 
956
953
  //#endregion
@@ -993,23 +990,20 @@ var no_component_will_mount_default = createRule({
993
990
  });
994
991
  function create$43(context) {
995
992
  if (!context.sourceCode.text.includes("componentWillMount")) return {};
996
- const { ctx, listeners } = useComponentCollectorLegacy(context);
997
- return {
998
- ...listeners,
999
- "Program:exit"(program) {
1000
- for (const { node: component } of ctx.getAllComponents(program)) {
1001
- const { body } = component.body;
1002
- for (const member of body) if (isComponentWillMount(member)) context.report({
1003
- messageId: "noComponentWillMount",
1004
- node: member,
1005
- fix(fixer) {
1006
- if (!("key" in member)) return null;
1007
- return fixer.replaceText(member.key, "UNSAFE_componentWillMount");
1008
- }
1009
- });
1010
- }
993
+ const { ctx, visitors } = useComponentCollectorLegacy(context);
994
+ return defineRuleListener(visitors, { "Program:exit"(program) {
995
+ for (const { node: component } of ctx.getAllComponents(program)) {
996
+ const { body } = component.body;
997
+ for (const member of body) if (isComponentWillMount(member)) context.report({
998
+ messageId: "noComponentWillMount",
999
+ node: member,
1000
+ fix(fixer) {
1001
+ if (!("key" in member)) return null;
1002
+ return fixer.replaceText(member.key, "UNSAFE_componentWillMount");
1003
+ }
1004
+ });
1011
1005
  }
1012
- };
1006
+ } });
1013
1007
  }
1014
1008
 
1015
1009
  //#endregion
@@ -1029,23 +1023,20 @@ var no_component_will_receive_props_default = createRule({
1029
1023
  });
1030
1024
  function create$42(context) {
1031
1025
  if (!context.sourceCode.text.includes("componentWillReceiveProps")) return {};
1032
- const { ctx, listeners } = useComponentCollectorLegacy(context);
1033
- return {
1034
- ...listeners,
1035
- "Program:exit"(program) {
1036
- for (const { node: component } of ctx.getAllComponents(program)) {
1037
- const { body } = component.body;
1038
- for (const member of body) if (isComponentWillReceiveProps(member)) context.report({
1039
- messageId: "noComponentWillReceiveProps",
1040
- node: member,
1041
- fix(fixer) {
1042
- if (!("key" in member)) return null;
1043
- return fixer.replaceText(member.key, "UNSAFE_componentWillReceiveProps");
1044
- }
1045
- });
1046
- }
1026
+ const { ctx, visitors } = useComponentCollectorLegacy(context);
1027
+ return defineRuleListener(visitors, { "Program:exit"(program) {
1028
+ for (const { node: component } of ctx.getAllComponents(program)) {
1029
+ const { body } = component.body;
1030
+ for (const member of body) if (isComponentWillReceiveProps(member)) context.report({
1031
+ messageId: "noComponentWillReceiveProps",
1032
+ node: member,
1033
+ fix(fixer) {
1034
+ if (!("key" in member)) return null;
1035
+ return fixer.replaceText(member.key, "UNSAFE_componentWillReceiveProps");
1036
+ }
1037
+ });
1047
1038
  }
1048
- };
1039
+ } });
1049
1040
  }
1050
1041
 
1051
1042
  //#endregion
@@ -1065,23 +1056,20 @@ var no_component_will_update_default = createRule({
1065
1056
  });
1066
1057
  function create$41(context) {
1067
1058
  if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
1068
- const { ctx, listeners } = useComponentCollectorLegacy(context);
1069
- return {
1070
- ...listeners,
1071
- "Program:exit"(program) {
1072
- for (const { node: component } of ctx.getAllComponents(program)) {
1073
- const { body } = component.body;
1074
- for (const member of body) if (isComponentWillUpdate(member)) context.report({
1075
- messageId: "noComponentWillUpdate",
1076
- node: member,
1077
- fix(fixer) {
1078
- if (!("key" in member)) return null;
1079
- return fixer.replaceText(member.key, "UNSAFE_componentWillUpdate");
1080
- }
1081
- });
1082
- }
1059
+ const { ctx, visitors } = useComponentCollectorLegacy(context);
1060
+ return defineRuleListener(visitors, { "Program:exit"(program) {
1061
+ for (const { node: component } of ctx.getAllComponents(program)) {
1062
+ const { body } = component.body;
1063
+ for (const member of body) if (isComponentWillUpdate(member)) context.report({
1064
+ messageId: "noComponentWillUpdate",
1065
+ node: member,
1066
+ fix(fixer) {
1067
+ if (!("key" in member)) return null;
1068
+ return fixer.replaceText(member.key, "UNSAFE_componentWillUpdate");
1069
+ }
1070
+ });
1083
1071
  }
1084
- };
1072
+ } });
1085
1073
  }
1086
1074
 
1087
1075
  //#endregion
@@ -1492,26 +1480,23 @@ var no_missing_component_display_name_default = createRule({
1492
1480
  });
1493
1481
  function create$32(context) {
1494
1482
  if (!context.sourceCode.text.includes("memo") && !context.sourceCode.text.includes("forwardRef")) return {};
1495
- const { ctx, listeners } = useComponentCollector(context, {
1483
+ const { ctx, visitors } = useComponentCollector(context, {
1496
1484
  collectDisplayName: true,
1497
1485
  collectHookCalls: false,
1498
1486
  hint: DEFAULT_COMPONENT_DETECTION_HINT
1499
1487
  });
1500
- return {
1501
- ...listeners,
1502
- "Program:exit"(program) {
1503
- for (const { node, displayName, flag } of ctx.getAllComponents(program)) {
1504
- const id = AST.getFunctionId(node);
1505
- const isMemoOrForwardRef = (flag & (ComponentFlag.ForwardRef | ComponentFlag.Memo)) > 0n;
1506
- if (id != null) continue;
1507
- if (!isMemoOrForwardRef) continue;
1508
- if (displayName == null) context.report({
1509
- messageId: "noMissingComponentDisplayName",
1510
- node
1511
- });
1512
- }
1488
+ return defineRuleListener(visitors, { "Program:exit"(program) {
1489
+ for (const { node, displayName, flag } of ctx.getAllComponents(program)) {
1490
+ const id = AST.getFunctionId(node);
1491
+ const isMemoOrForwardRef = (flag & (ComponentFlag.ForwardRef | ComponentFlag.Memo)) > 0n;
1492
+ if (id != null) continue;
1493
+ if (!isMemoOrForwardRef) continue;
1494
+ if (displayName == null) context.report({
1495
+ messageId: "noMissingComponentDisplayName",
1496
+ node
1497
+ });
1513
1498
  }
1514
- };
1499
+ } });
1515
1500
  }
1516
1501
 
1517
1502
  //#endregion
@@ -1721,66 +1706,42 @@ var no_nested_component_definitions_default = createRule({
1721
1706
  function create$28(context) {
1722
1707
  const fCollector = useComponentCollector(context, { hint: ComponentDetectionHint.SkipArrayMapCallback | ComponentDetectionHint.SkipNullLiteral | ComponentDetectionHint.SkipUndefined | ComponentDetectionHint.SkipBooleanLiteral | ComponentDetectionHint.SkipStringLiteral | ComponentDetectionHint.SkipNumberLiteral | ComponentDetectionHint.StrictLogical | ComponentDetectionHint.StrictConditional });
1723
1708
  const cCollector = useComponentCollectorLegacy(context);
1724
- return {
1725
- ...fCollector.listeners,
1726
- ...cCollector.listeners,
1727
- "Program:exit"(program) {
1728
- const fComponents = [...fCollector.ctx.getAllComponents(program)];
1729
- const cComponents = [...cCollector.ctx.getAllComponents(program)];
1730
- const isFunctionComponent = (node) => {
1731
- return AST.isFunction(node) && fComponents.some((component) => component.node === node);
1732
- };
1733
- const isClassComponent$1 = (node) => {
1734
- return AST.isClass(node) && cComponents.some((component) => component.node === node);
1735
- };
1736
- for (const { name: name$9, node: component } of fComponents) {
1737
- if (name$9 == null) continue;
1738
- if (isDirectValueOfRenderPropertyLoose(component)) continue;
1739
- if (isInsideJSXAttributeValue(component)) {
1740
- if (!isDeclaredInRenderPropLoose(component)) context.report({
1741
- messageId: "noNestedComponentDefinitions",
1742
- node: component,
1743
- data: {
1744
- name: name$9,
1745
- suggestion: "Move it to the top level or pass it as a prop."
1746
- }
1747
- });
1748
- continue;
1749
- }
1750
- if (isInsideCreateElementProps(context, component)) {
1751
- context.report({
1752
- messageId: "noNestedComponentDefinitions",
1753
- node: component,
1754
- data: {
1755
- name: name$9,
1756
- suggestion: "Move it to the top level or pass it as a prop."
1757
- }
1758
- });
1759
- continue;
1760
- }
1761
- const parentComponent = AST.findParentNode(component, isFunctionComponent);
1762
- if (parentComponent != null && !isDirectValueOfRenderPropertyLoose(parentComponent)) {
1763
- context.report({
1764
- messageId: "noNestedComponentDefinitions",
1765
- node: component,
1766
- data: {
1767
- name: name$9,
1768
- 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."
1769
- }
1770
- });
1771
- continue;
1772
- }
1773
- if (isInsideRenderMethod(component)) context.report({
1709
+ return defineRuleListener(fCollector.visitors, cCollector.visitors, { "Program:exit"(program) {
1710
+ const fComponents = [...fCollector.ctx.getAllComponents(program)];
1711
+ const cComponents = [...cCollector.ctx.getAllComponents(program)];
1712
+ const isFunctionComponent = (node) => {
1713
+ return AST.isFunction(node) && fComponents.some((component) => component.node === node);
1714
+ };
1715
+ const isClassComponent$1 = (node) => {
1716
+ return AST.isClass(node) && cComponents.some((component) => component.node === node);
1717
+ };
1718
+ for (const { name: name$9, node: component } of fComponents) {
1719
+ if (name$9 == null) continue;
1720
+ if (isDirectValueOfRenderPropertyLoose(component)) continue;
1721
+ if (isInsideJSXAttributeValue(component)) {
1722
+ if (!isDeclaredInRenderPropLoose(component)) context.report({
1723
+ messageId: "noNestedComponentDefinitions",
1724
+ node: component,
1725
+ data: {
1726
+ name: name$9,
1727
+ suggestion: "Move it to the top level or pass it as a prop."
1728
+ }
1729
+ });
1730
+ continue;
1731
+ }
1732
+ if (isInsideCreateElementProps(context, component)) {
1733
+ context.report({
1774
1734
  messageId: "noNestedComponentDefinitions",
1775
1735
  node: component,
1776
1736
  data: {
1777
1737
  name: name$9,
1778
- suggestion: "Move it to the top level."
1738
+ suggestion: "Move it to the top level or pass it as a prop."
1779
1739
  }
1780
1740
  });
1741
+ continue;
1781
1742
  }
1782
- for (const { name: name$9 = "unknown", node: component } of cComponents) {
1783
- if (AST.findParentNode(component, (n) => isClassComponent$1(n) || isFunctionComponent(n)) == null) continue;
1743
+ const parentComponent = AST.findParentNode(component, isFunctionComponent);
1744
+ if (parentComponent != null && !isDirectValueOfRenderPropertyLoose(parentComponent)) {
1784
1745
  context.report({
1785
1746
  messageId: "noNestedComponentDefinitions",
1786
1747
  node: component,
@@ -1789,9 +1750,29 @@ function create$28(context) {
1789
1750
  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."
1790
1751
  }
1791
1752
  });
1753
+ continue;
1792
1754
  }
1755
+ if (isInsideRenderMethod(component)) context.report({
1756
+ messageId: "noNestedComponentDefinitions",
1757
+ node: component,
1758
+ data: {
1759
+ name: name$9,
1760
+ suggestion: "Move it to the top level."
1761
+ }
1762
+ });
1793
1763
  }
1794
- };
1764
+ for (const { name: name$9 = "unknown", node: component } of cComponents) {
1765
+ if (AST.findParentNode(component, (n) => isClassComponent$1(n) || isFunctionComponent(n)) == null) continue;
1766
+ context.report({
1767
+ messageId: "noNestedComponentDefinitions",
1768
+ node: component,
1769
+ data: {
1770
+ name: name$9,
1771
+ 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."
1772
+ }
1773
+ });
1774
+ }
1775
+ } });
1795
1776
  }
1796
1777
  /**
1797
1778
  * Determines whether the node is inside JSX attribute value
@@ -1843,9 +1824,7 @@ function create$27(context) {
1843
1824
  const collector = useComponentCollector(context, { hint });
1844
1825
  const collectorLegacy = useComponentCollectorLegacy(context);
1845
1826
  const lazyComponentDeclarations = /* @__PURE__ */ new Set();
1846
- return {
1847
- ...collector.listeners,
1848
- ...collectorLegacy.listeners,
1827
+ return defineRuleListener(collector.visitors, collectorLegacy.visitors, {
1849
1828
  ImportExpression(node) {
1850
1829
  const lazyCall = AST.findParentNode(node, (n) => isLazyCall(context, n));
1851
1830
  if (lazyCall != null) lazyComponentDeclarations.add(lazyCall);
@@ -1864,7 +1843,7 @@ function create$27(context) {
1864
1843
  node: lazy
1865
1844
  });
1866
1845
  }
1867
- };
1846
+ });
1868
1847
  }
1869
1848
 
1870
1849
  //#endregion
@@ -1926,21 +1905,18 @@ var no_redundant_should_component_update_default = createRule({
1926
1905
  });
1927
1906
  function create$25(context) {
1928
1907
  if (!context.sourceCode.text.includes("shouldComponentUpdate")) return {};
1929
- const { ctx, listeners } = useComponentCollectorLegacy(context);
1930
- return {
1931
- ...listeners,
1932
- "Program:exit"(program) {
1933
- for (const { name: name$9 = "PureComponent", node: component, flag } of ctx.getAllComponents(program)) {
1934
- if ((flag & ComponentFlag.PureComponent) === 0n) continue;
1935
- const { body } = component.body;
1936
- for (const member of body) if (isShouldComponentUpdate(member)) context.report({
1937
- messageId: "noRedundantShouldComponentUpdate",
1938
- node: member,
1939
- data: { componentName: name$9 }
1940
- });
1941
- }
1908
+ const { ctx, visitors } = useComponentCollectorLegacy(context);
1909
+ return defineRuleListener(visitors, { "Program:exit"(program) {
1910
+ for (const { name: name$9 = "PureComponent", node: component, flag } of ctx.getAllComponents(program)) {
1911
+ if ((flag & ComponentFlag.PureComponent) === 0n) continue;
1912
+ const { body } = component.body;
1913
+ for (const member of body) if (isShouldComponentUpdate(member)) context.report({
1914
+ messageId: "noRedundantShouldComponentUpdate",
1915
+ node: member,
1916
+ data: { componentName: name$9 }
1917
+ });
1942
1918
  }
1943
- };
1919
+ } });
1944
1920
  }
1945
1921
 
1946
1922
  //#endregion
@@ -2111,10 +2087,9 @@ function create$20(context) {
2111
2087
  ...getJsxConfigFromContext(context),
2112
2088
  ...getJsxConfigFromAnnotation(context)
2113
2089
  };
2114
- const { ctx, listeners } = useComponentCollector(context);
2090
+ const { ctx, visitors } = useComponentCollector(context);
2115
2091
  const constantKeys = /* @__PURE__ */ new Set();
2116
- return {
2117
- ...listeners,
2092
+ return defineRuleListener(visitors, {
2118
2093
  JSXAttribute(node) {
2119
2094
  if (node.name.name !== "key") return;
2120
2095
  const jsxElement = node.parent.parent;
@@ -2149,7 +2124,7 @@ function create$20(context) {
2149
2124
  });
2150
2125
  }
2151
2126
  }
2152
- };
2127
+ });
2153
2128
  }
2154
2129
  function getArrayMethodCallbackPosition(methodName) {
2155
2130
  switch (methodName) {
@@ -2348,24 +2323,21 @@ var no_unnecessary_use_prefix_default = createRule({
2348
2323
  defaultOptions: []
2349
2324
  });
2350
2325
  function create$17(context) {
2351
- const { ctx, listeners } = useHookCollector(context);
2352
- return {
2353
- ...listeners,
2354
- "Program:exit"(program) {
2355
- for (const { id, name: name$9, node, hookCalls } of ctx.getAllHooks(program)) {
2356
- if (hookCalls.length > 0) continue;
2357
- if (AST.isFunctionEmpty(node)) continue;
2358
- if (WELL_KNOWN_HOOKS.includes(name$9)) continue;
2359
- if (containsUseComments(context, node)) continue;
2360
- if (AST.findParentNode(node, AST.isViMockCallback) != null) continue;
2361
- context.report({
2362
- messageId: "noUnnecessaryUsePrefix",
2363
- node: id ?? node,
2364
- data: { name: name$9 }
2365
- });
2366
- }
2326
+ const { ctx, visitors } = useHookCollector(context);
2327
+ return defineRuleListener(visitors, { "Program:exit"(program) {
2328
+ for (const { id, name: name$9, node, hookCalls } of ctx.getAllHooks(program)) {
2329
+ if (hookCalls.length > 0) continue;
2330
+ if (AST.isFunctionEmpty(node)) continue;
2331
+ if (WELL_KNOWN_HOOKS.includes(name$9)) continue;
2332
+ if (containsUseComments(context, node)) continue;
2333
+ if (AST.findParentNode(node, AST.isViMockCallback) != null) continue;
2334
+ context.report({
2335
+ messageId: "noUnnecessaryUsePrefix",
2336
+ node: id ?? node,
2337
+ data: { name: name$9 }
2338
+ });
2367
2339
  }
2368
- };
2340
+ } });
2369
2341
  }
2370
2342
 
2371
2343
  //#endregion
@@ -2422,19 +2394,16 @@ var no_unsafe_component_will_mount_default = createRule({
2422
2394
  });
2423
2395
  function create$15(context) {
2424
2396
  if (!context.sourceCode.text.includes("UNSAFE_componentWillMount")) return {};
2425
- const { ctx, listeners } = useComponentCollectorLegacy(context);
2426
- return {
2427
- ...listeners,
2428
- "Program:exit"(program) {
2429
- for (const { node: component } of ctx.getAllComponents(program)) {
2430
- const { body } = component.body;
2431
- for (const member of body) if (isUnsafeComponentWillMount(member)) context.report({
2432
- messageId: "noUnsafeComponentWillMount",
2433
- node: member
2434
- });
2435
- }
2397
+ const { ctx, visitors } = useComponentCollectorLegacy(context);
2398
+ return defineRuleListener(visitors, { "Program:exit"(program) {
2399
+ for (const { node: component } of ctx.getAllComponents(program)) {
2400
+ const { body } = component.body;
2401
+ for (const member of body) if (isUnsafeComponentWillMount(member)) context.report({
2402
+ messageId: "noUnsafeComponentWillMount",
2403
+ node: member
2404
+ });
2436
2405
  }
2437
- };
2406
+ } });
2438
2407
  }
2439
2408
 
2440
2409
  //#endregion
@@ -2453,19 +2422,16 @@ var no_unsafe_component_will_receive_props_default = createRule({
2453
2422
  });
2454
2423
  function create$14(context) {
2455
2424
  if (!context.sourceCode.text.includes("UNSAFE_componentWillReceiveProps")) return {};
2456
- const { ctx, listeners } = useComponentCollectorLegacy(context);
2457
- return {
2458
- ...listeners,
2459
- "Program:exit"(program) {
2460
- for (const { node: component } of ctx.getAllComponents(program)) {
2461
- const { body } = component.body;
2462
- for (const member of body) if (isUnsafeComponentWillReceiveProps(member)) context.report({
2463
- messageId: "noUnsafeComponentWillReceiveProps",
2464
- node: member
2465
- });
2466
- }
2425
+ const { ctx, visitors } = useComponentCollectorLegacy(context);
2426
+ return defineRuleListener(visitors, { "Program:exit"(program) {
2427
+ for (const { node: component } of ctx.getAllComponents(program)) {
2428
+ const { body } = component.body;
2429
+ for (const member of body) if (isUnsafeComponentWillReceiveProps(member)) context.report({
2430
+ messageId: "noUnsafeComponentWillReceiveProps",
2431
+ node: member
2432
+ });
2467
2433
  }
2468
- };
2434
+ } });
2469
2435
  }
2470
2436
 
2471
2437
  //#endregion
@@ -2484,19 +2450,16 @@ var no_unsafe_component_will_update_default = createRule({
2484
2450
  });
2485
2451
  function create$13(context) {
2486
2452
  if (!context.sourceCode.text.includes("UNSAFE_componentWillUpdate")) return {};
2487
- const { ctx, listeners } = useComponentCollectorLegacy(context);
2488
- return {
2489
- ...listeners,
2490
- "Program:exit"(program) {
2491
- for (const { node: component } of ctx.getAllComponents(program)) {
2492
- const { body } = component.body;
2493
- for (const member of body) if (isUnsafeComponentWillUpdate(member)) context.report({
2494
- messageId: "noUnsafeComponentWillUpdate",
2495
- node: member
2496
- });
2497
- }
2453
+ const { ctx, visitors } = useComponentCollectorLegacy(context);
2454
+ return defineRuleListener(visitors, { "Program:exit"(program) {
2455
+ for (const { node: component } of ctx.getAllComponents(program)) {
2456
+ const { body } = component.body;
2457
+ for (const member of body) if (isUnsafeComponentWillUpdate(member)) context.report({
2458
+ messageId: "noUnsafeComponentWillUpdate",
2459
+ node: member
2460
+ });
2498
2461
  }
2499
- };
2462
+ } });
2500
2463
  }
2501
2464
 
2502
2465
  //#endregion
@@ -2516,10 +2479,9 @@ var no_unstable_context_value_default = createRule({
2516
2479
  function create$12(context) {
2517
2480
  const { version: version$1 } = getSettingsFromContext(context);
2518
2481
  const isReact18OrBelow = compare(version$1, "19.0.0", "<");
2519
- const { ctx, listeners } = useComponentCollector(context);
2482
+ const { ctx, visitors } = useComponentCollector(context);
2520
2483
  const constructions = /* @__PURE__ */ new WeakMap();
2521
- return {
2522
- ...listeners,
2484
+ return defineRuleListener(visitors, {
2523
2485
  JSXOpeningElement(node) {
2524
2486
  const selfName = getJsxElementType(context, node.parent).split(".").at(-1);
2525
2487
  if (selfName == null) return;
@@ -2550,7 +2512,7 @@ function create$12(context) {
2550
2512
  });
2551
2513
  }
2552
2514
  }
2553
- };
2515
+ });
2554
2516
  }
2555
2517
  function isContextName(name$9, isReact18OrBelow) {
2556
2518
  if (name$9 === "Provider") return true;
@@ -2590,12 +2552,11 @@ function extractIdentifier(node) {
2590
2552
  return null;
2591
2553
  }
2592
2554
  function create$11(context, [options]) {
2593
- const { ctx, listeners } = useComponentCollector(context);
2555
+ const { ctx, visitors } = useComponentCollector(context);
2594
2556
  const declarators = /* @__PURE__ */ new WeakMap();
2595
2557
  const { safeDefaultProps = [] } = options;
2596
2558
  const safePatterns = safeDefaultProps.map((s) => toRegExp(s));
2597
- return {
2598
- ...listeners,
2559
+ return defineRuleListener(visitors, {
2599
2560
  [AST.SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR](node) {
2600
2561
  const functionEntry = ctx.getCurrentEntry();
2601
2562
  if (functionEntry == null) return;
@@ -2629,7 +2590,7 @@ function create$11(context, [options]) {
2629
2590
  }
2630
2591
  }
2631
2592
  }
2632
- };
2593
+ });
2633
2594
  }
2634
2595
 
2635
2596
  //#endregion
@@ -2764,29 +2725,26 @@ var no_unused_props_default = createRule({
2764
2725
  });
2765
2726
  function create$9(context) {
2766
2727
  const services = ESLintUtils.getParserServices(context, false);
2767
- const { ctx, listeners } = useComponentCollector(context);
2768
- return {
2769
- ...listeners,
2770
- "Program:exit"(program) {
2771
- const checker = services.program.getTypeChecker();
2772
- const totalDeclaredProps = /* @__PURE__ */ new Set();
2773
- const totalUsedProps = /* @__PURE__ */ new Set();
2774
- for (const component of ctx.getAllComponents(program)) {
2775
- const [props] = component.node.params;
2776
- if (props == null) continue;
2777
- const usedPropKeys = /* @__PURE__ */ new Set();
2778
- if (!collectUsedPropKeysOfParameter(context, usedPropKeys, props)) continue;
2779
- const tsNode = services.esTreeNodeToTSNodeMap.get(props);
2780
- const declaredProps = checker.getTypeAtLocation(tsNode).getProperties();
2781
- for (const declaredProp of declaredProps) {
2782
- totalDeclaredProps.add(declaredProp);
2783
- if (usedPropKeys.has(declaredProp.name)) totalUsedProps.add(declaredProp);
2784
- }
2728
+ const { ctx, visitors } = useComponentCollector(context);
2729
+ return defineRuleListener(visitors, { "Program:exit"(program) {
2730
+ const checker = services.program.getTypeChecker();
2731
+ const totalDeclaredProps = /* @__PURE__ */ new Set();
2732
+ const totalUsedProps = /* @__PURE__ */ new Set();
2733
+ for (const component of ctx.getAllComponents(program)) {
2734
+ const [props] = component.node.params;
2735
+ if (props == null) continue;
2736
+ const usedPropKeys = /* @__PURE__ */ new Set();
2737
+ if (!collectUsedPropKeysOfParameter(context, usedPropKeys, props)) continue;
2738
+ const tsNode = services.esTreeNodeToTSNodeMap.get(props);
2739
+ const declaredProps = checker.getTypeAtLocation(tsNode).getProperties();
2740
+ for (const declaredProp of declaredProps) {
2741
+ totalDeclaredProps.add(declaredProp);
2742
+ if (usedPropKeys.has(declaredProp.name)) totalUsedProps.add(declaredProp);
2785
2743
  }
2786
- const unusedProps = [...totalDeclaredProps].filter((x) => !totalUsedProps.has(x));
2787
- for (const unusedProp of unusedProps) reportUnusedProp(context, services, unusedProp);
2788
2744
  }
2789
- };
2745
+ const unusedProps = [...totalDeclaredProps].filter((x) => !totalUsedProps.has(x));
2746
+ for (const unusedProp of unusedProps) reportUnusedProp(context, services, unusedProp);
2747
+ } });
2790
2748
  }
2791
2749
  function collectUsedPropKeysOfParameter(context, usedPropKeys, parameter) {
2792
2750
  switch (parameter.type) {
@@ -3251,10 +3209,9 @@ var prefer_destructuring_assignment_default = createRule({
3251
3209
  defaultOptions: []
3252
3210
  });
3253
3211
  function create$4(context) {
3254
- const { ctx, listeners } = useComponentCollector(context);
3212
+ const { ctx, visitors } = useComponentCollector(context);
3255
3213
  const exprs = [];
3256
- return {
3257
- ...listeners,
3214
+ return defineRuleListener(visitors, {
3258
3215
  MemberExpression(node) {
3259
3216
  if (!isInsideComponentOrHook(node)) return;
3260
3217
  if (!isMemberExpressionWithObjectName(node)) return;
@@ -3288,7 +3245,7 @@ function create$4(context) {
3288
3245
  });
3289
3246
  }
3290
3247
  }
3291
- };
3248
+ });
3292
3249
  }
3293
3250
 
3294
3251
  //#endregion
@@ -3345,25 +3302,22 @@ var prefer_read_only_props_default = createRule({
3345
3302
  function create$2(context) {
3346
3303
  const services = ESLintUtils.getParserServices(context, false);
3347
3304
  const checker = services.program.getTypeChecker();
3348
- const { ctx, listeners } = useComponentCollector(context);
3349
- return {
3350
- ...listeners,
3351
- "Program:exit"(program) {
3352
- for (const component of ctx.getAllComponents(program)) {
3353
- const [props] = component.node.params;
3354
- if (component.id == null || component.name == null) continue;
3355
- if (props == null) continue;
3356
- const propsType = getConstrainedTypeAtLocation(services, props);
3357
- if (isTypeReadonly(services.program, propsType)) continue;
3358
- if (isTypeReadonlyLoose(services, propsType)) continue;
3359
- if (propsType.isClassOrInterface() && isClassOrInterfaceReadonlyLoose(checker, propsType)) continue;
3360
- context.report({
3361
- messageId: "preferReadOnlyProps",
3362
- node: props
3363
- });
3364
- }
3305
+ const { ctx, visitors } = useComponentCollector(context);
3306
+ return defineRuleListener(visitors, { "Program:exit"(program) {
3307
+ for (const component of ctx.getAllComponents(program)) {
3308
+ const [props] = component.node.params;
3309
+ if (component.id == null || component.name == null) continue;
3310
+ if (props == null) continue;
3311
+ const propsType = getConstrainedTypeAtLocation(services, props);
3312
+ if (isTypeReadonly(services.program, propsType)) continue;
3313
+ if (isTypeReadonlyLoose(services, propsType)) continue;
3314
+ if (propsType.isClassOrInterface() && isClassOrInterfaceReadonlyLoose(checker, propsType)) continue;
3315
+ context.report({
3316
+ messageId: "preferReadOnlyProps",
3317
+ node: props
3318
+ });
3365
3319
  }
3366
- };
3320
+ } });
3367
3321
  }
3368
3322
  function isTypeReadonlyLoose(services, type) {
3369
3323
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "2.7.2-beta.2",
3
+ "version": "2.7.2-beta.3",
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",
@@ -46,11 +46,11 @@
46
46
  "string-ts": "^2.3.1",
47
47
  "ts-api-utils": "^2.4.0",
48
48
  "ts-pattern": "^5.9.0",
49
- "@eslint-react/ast": "2.7.2-beta.2",
50
- "@eslint-react/core": "2.7.2-beta.2",
51
- "@eslint-react/shared": "2.7.2-beta.2",
52
- "@eslint-react/var": "2.7.2-beta.2",
53
- "@eslint-react/eff": "2.7.2-beta.2"
49
+ "@eslint-react/ast": "2.7.2-beta.3",
50
+ "@eslint-react/core": "2.7.2-beta.3",
51
+ "@eslint-react/eff": "2.7.2-beta.3",
52
+ "@eslint-react/shared": "2.7.2-beta.3",
53
+ "@eslint-react/var": "2.7.2-beta.3"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/react": "^19.2.8",