eslint-plugin-react-x 2.6.4 → 2.6.5-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 +84 -62
  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 = "2.6.4";
71
+ var version = "2.6.5-beta.1";
72
72
 
73
73
  //#endregion
74
74
  //#region src/utils/create-rule.ts
@@ -937,7 +937,7 @@ 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();
940
+ const { ctx, listeners } = useComponentCollectorLegacy(context);
941
941
  return {
942
942
  ...listeners,
943
943
  "Program:exit"(program) {
@@ -993,7 +993,7 @@ var no_component_will_mount_default = createRule({
993
993
  });
994
994
  function create$43(context) {
995
995
  if (!context.sourceCode.text.includes("componentWillMount")) return {};
996
- const { ctx, listeners } = useComponentCollectorLegacy();
996
+ const { ctx, listeners } = useComponentCollectorLegacy(context);
997
997
  return {
998
998
  ...listeners,
999
999
  "Program:exit"(program) {
@@ -1029,7 +1029,7 @@ var no_component_will_receive_props_default = createRule({
1029
1029
  });
1030
1030
  function create$42(context) {
1031
1031
  if (!context.sourceCode.text.includes("componentWillReceiveProps")) return {};
1032
- const { ctx, listeners } = useComponentCollectorLegacy();
1032
+ const { ctx, listeners } = useComponentCollectorLegacy(context);
1033
1033
  return {
1034
1034
  ...listeners,
1035
1035
  "Program:exit"(program) {
@@ -1065,7 +1065,7 @@ var no_component_will_update_default = createRule({
1065
1065
  });
1066
1066
  function create$41(context) {
1067
1067
  if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
1068
- const { ctx, listeners } = useComponentCollectorLegacy();
1068
+ const { ctx, listeners } = useComponentCollectorLegacy(context);
1069
1069
  return {
1070
1070
  ...listeners,
1071
1071
  "Program:exit"(program) {
@@ -1733,8 +1733,8 @@ var no_nested_component_definitions_default = createRule({
1733
1733
  defaultOptions: []
1734
1734
  });
1735
1735
  function create$28(context) {
1736
- const fCollector = useComponentCollector(context, { hint: ComponentDetectionHint.SkipArrayMapArgument | ComponentDetectionHint.SkipNullLiteral | ComponentDetectionHint.SkipUndefined | ComponentDetectionHint.SkipBooleanLiteral | ComponentDetectionHint.SkipStringLiteral | ComponentDetectionHint.SkipNumberLiteral | ComponentDetectionHint.StrictLogical | ComponentDetectionHint.StrictConditional });
1737
- const cCollector = useComponentCollectorLegacy();
1736
+ const fCollector = useComponentCollector(context, { hint: ComponentDetectionHint.SkipArrayMapCallback | ComponentDetectionHint.SkipNullLiteral | ComponentDetectionHint.SkipUndefined | ComponentDetectionHint.SkipBooleanLiteral | ComponentDetectionHint.SkipStringLiteral | ComponentDetectionHint.SkipNumberLiteral | ComponentDetectionHint.StrictLogical | ComponentDetectionHint.StrictConditional });
1737
+ const cCollector = useComponentCollectorLegacy(context);
1738
1738
  return {
1739
1739
  ...fCollector.listeners,
1740
1740
  ...cCollector.listeners,
@@ -1855,7 +1855,7 @@ var no_nested_lazy_component_declarations_default = createRule({
1855
1855
  function create$27(context) {
1856
1856
  const hint = ComponentDetectionHint.None;
1857
1857
  const collector = useComponentCollector(context, { hint });
1858
- const collectorLegacy = useComponentCollectorLegacy();
1858
+ const collectorLegacy = useComponentCollectorLegacy(context);
1859
1859
  const lazyComponentDeclarations = /* @__PURE__ */ new Set();
1860
1860
  return {
1861
1861
  ...collector.listeners,
@@ -1940,7 +1940,7 @@ var no_redundant_should_component_update_default = createRule({
1940
1940
  });
1941
1941
  function create$25(context) {
1942
1942
  if (!context.sourceCode.text.includes("shouldComponentUpdate")) return {};
1943
- const { ctx, listeners } = useComponentCollectorLegacy();
1943
+ const { ctx, listeners } = useComponentCollectorLegacy(context);
1944
1944
  return {
1945
1945
  ...listeners,
1946
1946
  "Program:exit"(program) {
@@ -2125,33 +2125,45 @@ function create$20(context) {
2125
2125
  ...getJsxConfigFromContext(context),
2126
2126
  ...getJsxConfigFromAnnotation(context)
2127
2127
  };
2128
- return { JSXAttribute(node) {
2129
- if (node.name.name !== "key") return;
2130
- const jsxElement = node.parent.parent;
2131
- if (isJsxFragmentElement(context, jsxElement, jsxConfig)) return;
2132
- if (jsxElement.openingElement.attributes.some((attr) => attr.type === AST_NODE_TYPES.JSXSpreadAttribute)) return;
2133
- if (AST.findParentNode(jsxElement, (n) => isRenderFunctionLoose(context, n)) != null) return;
2134
- const mapCallback = AST.findParentNode(jsxElement, isArrayMethodCallback);
2135
- if (mapCallback == null || AST.findParentNode(jsxElement, AST.isFunction) !== mapCallback) {
2136
- if (!(AST.findParentNode(jsxElement, (n) => AST.isConditional(n) || AST.isControlFlow(n) || findEnclosingAssignmentTarget(n) != null) != null)) context.report({
2128
+ const { ctx, listeners } = useComponentCollector(context);
2129
+ const constantKeys = /* @__PURE__ */ new Set();
2130
+ return {
2131
+ ...listeners,
2132
+ JSXAttribute(node) {
2133
+ if (node.name.name !== "key") return;
2134
+ const jsxElement = node.parent.parent;
2135
+ if (isJsxFragmentElement(context, jsxElement, jsxConfig)) return;
2136
+ if (jsxElement.openingElement.attributes.some((attr) => attr.type === AST_NODE_TYPES.JSXSpreadAttribute)) return;
2137
+ if (AST.findParentNode(jsxElement, (n) => isRenderFunctionLoose(context, n)) != null) return;
2138
+ const mapCallback = AST.findParentNode(jsxElement, isArrayMethodCallback);
2139
+ if (mapCallback == null || AST.findParentNode(jsxElement, AST.isFunction) !== mapCallback) {
2140
+ constantKeys.add(node);
2141
+ return;
2142
+ }
2143
+ if (context.sourceCode.getScope(mapCallback) !== context.sourceCode.getScope(jsxElement)) return;
2144
+ const keyedElementOrElse = AST.findParentNode(jsxElement, (n) => {
2145
+ if (n === mapCallback) return true;
2146
+ return AST.isJSXElement(n) && getJsxAttribute(context, n)("key") != null;
2147
+ });
2148
+ if (keyedElementOrElse == null || keyedElementOrElse === mapCallback) return;
2149
+ context.report({
2137
2150
  messageId: "noUnnecessaryKey",
2138
2151
  node,
2139
- data: { reason: "The `key` prop is not needed outside of dynamic rendering contexts." }
2152
+ data: { reason: "A parent element already has a `key` prop in the same list rendering context." }
2140
2153
  });
2141
- return;
2154
+ },
2155
+ "Program:exit"(node) {
2156
+ const components = ctx.getAllComponents(node);
2157
+ for (const key of constantKeys) {
2158
+ if (AST.findParentNode(key, (n) => AST.isConditional(n) || AST.isControlFlow(n) || findEnclosingAssignmentTarget(n) != null || components.some((comp) => comp.node === n && comp.rets.length > 1)) != null) return;
2159
+ context.report({
2160
+ messageId: "noUnnecessaryKey",
2161
+ node,
2162
+ data: { reason: "The `key` prop is not needed outside of dynamic rendering contexts." }
2163
+ });
2164
+ }
2142
2165
  }
2143
- if (context.sourceCode.getScope(mapCallback) !== context.sourceCode.getScope(jsxElement)) return;
2144
- const keyedElementOrElse = AST.findParentNode(jsxElement, (n) => {
2145
- if (n === mapCallback) return true;
2146
- return AST.isJSXElement(n) && getJsxAttribute(context, n)("key") != null;
2147
- });
2148
- if (keyedElementOrElse == null || keyedElementOrElse === mapCallback) return;
2149
- context.report({
2150
- messageId: "noUnnecessaryKey",
2151
- node,
2152
- data: { reason: "A parent element already has a `key` prop in the same list rendering context." }
2153
- });
2154
- } };
2166
+ };
2155
2167
  }
2156
2168
  function isArrayMethodCallback(node) {
2157
2169
  const parent = node.parent;
@@ -2179,16 +2191,19 @@ var no_unnecessary_use_callback_default = createRule({
2179
2191
  });
2180
2192
  function create$19(context) {
2181
2193
  if (!context.sourceCode.text.includes("useCallback")) return {};
2182
- return { CallExpression(node) {
2183
- if (!isUseCallbackCall(node)) return;
2184
- const checkForUsageInsideUseEffectReport = checkForUsageInsideUseEffect$1(context.sourceCode, node);
2185
- const initialScope = context.sourceCode.getScope(node);
2186
- const component = context.sourceCode.getScope(node).block;
2194
+ return { VariableDeclarator(node) {
2195
+ const { id, init } = node;
2196
+ if (id.type !== AST_NODE_TYPES.Identifier || init?.type !== AST_NODE_TYPES.CallExpression || !isUseCallbackCall(init)) return;
2197
+ const [cbk, ...rest] = context.sourceCode.getDeclaredVariables(node);
2198
+ if (cbk == null || rest.length > 0) return;
2199
+ const checkForUsageInsideUseEffectReport = checkForUsageInsideUseEffect$1(context.sourceCode, init);
2200
+ const scope = context.sourceCode.getScope(init);
2201
+ const component = context.sourceCode.getScope(init).block;
2187
2202
  if (!AST.isFunction(component)) return;
2188
- const [arg0, arg1] = node.arguments;
2203
+ const [arg0, arg1] = init.arguments;
2189
2204
  if (arg0 == null || arg1 == null) return;
2190
2205
  if (!match(arg1).with({ type: AST_NODE_TYPES.ArrayExpression }, (n) => n.elements.length === 0).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
2191
- const variableNode = getVariableDefinitionNode(findVariable(n.name, initialScope), 0);
2206
+ const variableNode = getVariableDefinitionNode(findVariable(n.name, scope), 0);
2192
2207
  if (variableNode?.type !== AST_NODE_TYPES.ArrayExpression) return false;
2193
2208
  return variableNode.elements.length === 0;
2194
2209
  }).otherwise(() => false)) {
@@ -2199,7 +2214,7 @@ function create$19(context) {
2199
2214
  if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) return n.body;
2200
2215
  return n;
2201
2216
  }).with({ type: AST_NODE_TYPES.FunctionExpression }, identity).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
2202
- const variableNode = getVariableDefinitionNode(findVariable(n.name, initialScope), 0);
2217
+ const variableNode = getVariableDefinitionNode(findVariable(n.name, scope), 0);
2203
2218
  if (variableNode?.type !== AST_NODE_TYPES.ArrowFunctionExpression && variableNode?.type !== AST_NODE_TYPES.FunctionExpression) return null;
2204
2219
  return variableNode;
2205
2220
  }).otherwise(() => null);
@@ -2218,7 +2233,8 @@ function checkForUsageInsideUseEffect$1(sourceCode, node) {
2218
2233
  if (!/use\w*Effect/u.test(sourceCode.text)) return;
2219
2234
  if (!isVariableDeclarator(node.parent)) return;
2220
2235
  if (!isIdentifier(node.parent.id)) return;
2221
- const usages = (sourceCode.getDeclaredVariables(node.parent)[0]?.references ?? []).filter((ref) => !(ref.init ?? false));
2236
+ const usages = (sourceCode.getDeclaredVariables(node.parent)[0]?.references ?? []).filter((ref) => ref.init !== true);
2237
+ if (usages.length === 0) return;
2222
2238
  const effectSet = /* @__PURE__ */ new Set();
2223
2239
  for (const usage of usages) {
2224
2240
  const effect = AST.findParentNode(usage.identifier, isUseEffectLikeCall);
@@ -2252,20 +2268,23 @@ var no_unnecessary_use_memo_default = createRule({
2252
2268
  });
2253
2269
  function create$18(context) {
2254
2270
  if (!context.sourceCode.text.includes("useMemo")) return {};
2255
- return { CallExpression(node) {
2256
- const initialScope = context.sourceCode.getScope(node);
2257
- if (!isUseMemoCall(node)) return;
2258
- const checkForUsageInsideUseEffectReport = checkForUsageInsideUseEffect(context.sourceCode, node);
2259
- const component = context.sourceCode.getScope(node).block;
2271
+ return { VariableDeclarator(node) {
2272
+ const { id, init } = node;
2273
+ if (id.type !== AST_NODE_TYPES.Identifier || init?.type !== AST_NODE_TYPES.CallExpression || !isUseMemoCall(init)) return;
2274
+ const [mem, ...rest] = context.sourceCode.getDeclaredVariables(node);
2275
+ if (mem == null || rest.length > 0) return;
2276
+ const checkForUsageInsideUseEffectReport = checkForUsageInsideUseEffect(context.sourceCode, init);
2277
+ const scope = context.sourceCode.getScope(init);
2278
+ const component = scope.block;
2260
2279
  if (!AST.isFunction(component)) return;
2261
- const [arg0, arg1] = node.arguments;
2280
+ const [arg0, arg1] = init.arguments;
2262
2281
  if (arg0 == null || arg1 == null) return;
2263
2282
  if (AST.isFunction(arg0) && [...AST.getNestedCallExpressions(arg0.body), ...AST.getNestedNewExpressions(arg0.body)].length > 0) {
2264
2283
  report(context)(checkForUsageInsideUseEffectReport);
2265
2284
  return;
2266
2285
  }
2267
2286
  if (!match(arg1).with({ type: AST_NODE_TYPES.ArrayExpression }, (n) => n.elements.length === 0).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
2268
- const variableNode = getVariableDefinitionNode(findVariable(n.name, initialScope), 0);
2287
+ const variableNode = getVariableDefinitionNode(findVariable(n.name, scope), 0);
2269
2288
  if (variableNode?.type !== AST_NODE_TYPES.ArrayExpression) return false;
2270
2289
  return variableNode.elements.length === 0;
2271
2290
  }).otherwise(() => false)) {
@@ -2276,7 +2295,7 @@ function create$18(context) {
2276
2295
  if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) return n.body;
2277
2296
  return n;
2278
2297
  }).with({ type: AST_NODE_TYPES.FunctionExpression }, identity).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
2279
- const variableNode = getVariableDefinitionNode(findVariable(n.name, initialScope), 0);
2298
+ const variableNode = getVariableDefinitionNode(findVariable(n.name, scope), 0);
2280
2299
  if (variableNode?.type !== AST_NODE_TYPES.ArrowFunctionExpression && variableNode?.type !== AST_NODE_TYPES.FunctionExpression) return null;
2281
2300
  return variableNode;
2282
2301
  }).otherwise(() => null);
@@ -2295,7 +2314,8 @@ function checkForUsageInsideUseEffect(sourceCode, node) {
2295
2314
  if (!/use\w*Effect/u.test(sourceCode.text)) return;
2296
2315
  if (!isVariableDeclarator(node.parent)) return;
2297
2316
  if (!isIdentifier(node.parent.id)) return;
2298
- const usages = (sourceCode.getDeclaredVariables(node.parent)[0]?.references ?? []).filter((ref) => !(ref.init ?? false));
2317
+ const usages = (sourceCode.getDeclaredVariables(node.parent)[0]?.references ?? []).filter((ref) => ref.init !== true);
2318
+ if (usages.length === 0) return;
2299
2319
  const effectSet = /* @__PURE__ */ new Set();
2300
2320
  for (const usage of usages) {
2301
2321
  const effect = AST.findParentNode(usage.identifier, isUseEffectLikeCall);
@@ -2329,7 +2349,7 @@ var no_unnecessary_use_prefix_default = createRule({
2329
2349
  defaultOptions: []
2330
2350
  });
2331
2351
  function create$17(context) {
2332
- const { ctx, listeners } = useHookCollector();
2352
+ const { ctx, listeners } = useHookCollector(context);
2333
2353
  return {
2334
2354
  ...listeners,
2335
2355
  "Program:exit"(program) {
@@ -2402,7 +2422,7 @@ var no_unsafe_component_will_mount_default = createRule({
2402
2422
  });
2403
2423
  function create$15(context) {
2404
2424
  if (!context.sourceCode.text.includes("UNSAFE_componentWillMount")) return {};
2405
- const { ctx, listeners } = useComponentCollectorLegacy();
2425
+ const { ctx, listeners } = useComponentCollectorLegacy(context);
2406
2426
  return {
2407
2427
  ...listeners,
2408
2428
  "Program:exit"(program) {
@@ -2433,7 +2453,7 @@ var no_unsafe_component_will_receive_props_default = createRule({
2433
2453
  });
2434
2454
  function create$14(context) {
2435
2455
  if (!context.sourceCode.text.includes("UNSAFE_componentWillReceiveProps")) return {};
2436
- const { ctx, listeners } = useComponentCollectorLegacy();
2456
+ const { ctx, listeners } = useComponentCollectorLegacy(context);
2437
2457
  return {
2438
2458
  ...listeners,
2439
2459
  "Program:exit"(program) {
@@ -2464,7 +2484,7 @@ var no_unsafe_component_will_update_default = createRule({
2464
2484
  });
2465
2485
  function create$13(context) {
2466
2486
  if (!context.sourceCode.text.includes("UNSAFE_componentWillUpdate")) return {};
2467
- const { ctx, listeners } = useComponentCollectorLegacy();
2487
+ const { ctx, listeners } = useComponentCollectorLegacy(context);
2468
2488
  return {
2469
2489
  ...listeners,
2470
2490
  "Program:exit"(program) {
@@ -2663,7 +2683,7 @@ function create$10(context) {
2663
2683
  function classExit() {
2664
2684
  const currentClass = classStack.pop();
2665
2685
  if (currentClass == null || !isClassComponent(currentClass)) return;
2666
- const className = AST.getClassId(currentClass)?.name;
2686
+ const id = AST.getClassId(currentClass);
2667
2687
  const defs = propertyDefs.get(currentClass);
2668
2688
  const usages = propertyUsages.get(currentClass);
2669
2689
  if (defs == null) return;
@@ -2675,7 +2695,7 @@ function create$10(context) {
2675
2695
  messageId: "noUnusedClassComponentMembers",
2676
2696
  node: def,
2677
2697
  data: {
2678
- className: className ?? "Component",
2698
+ className: id != null ? context.sourceCode.getText(id) : "Component",
2679
2699
  methodName
2680
2700
  }
2681
2701
  });
@@ -2872,13 +2892,13 @@ function create$8(context) {
2872
2892
  function classExit() {
2873
2893
  const currentClass = classStack.pop();
2874
2894
  if (currentClass == null || !isClassComponent(currentClass)) return;
2875
- const className = AST.getClassId(currentClass)?.name;
2895
+ const id = AST.getClassId(currentClass);
2876
2896
  const { node: defNode, isUsed = false } = stateDefs.get(currentClass) ?? {};
2877
2897
  if (defNode == null || isUsed) return;
2878
2898
  context.report({
2879
2899
  messageId: "noUnusedState",
2880
2900
  node: defNode,
2881
- data: { className: className ?? "Component" }
2901
+ data: { className: id != null ? context.sourceCode.getText(id) : "Component" }
2882
2902
  });
2883
2903
  }
2884
2904
  function methodEnter(node) {
@@ -3242,11 +3262,13 @@ function create$4(context) {
3242
3262
  }
3243
3263
  },
3244
3264
  "Program:exit"(program) {
3245
- const componentBlocks = new Set(ctx.getAllComponents(program).map((component) => component.node));
3265
+ const components = ctx.getAllComponents(program);
3246
3266
  function isFunctionComponent(block) {
3247
- if (!AST.isFunction(block)) return false;
3248
- const id = AST.getFunctionId(block);
3249
- return id != null && isComponentNameLoose(id.name) && componentBlocks.has(block);
3267
+ return components.some((comp) => {
3268
+ if (comp.node !== block) return false;
3269
+ if (comp.name == null && AST.findParentNode(comp.node, (n) => n.type === AST_NODE_TYPES.ExportDefaultDeclaration) != null) return false;
3270
+ return true;
3271
+ });
3250
3272
  }
3251
3273
  for (const [initialScope, expr] of exprs) {
3252
3274
  let scope = initialScope;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "2.6.4",
3
+ "version": "2.6.5-beta.1",
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.6.4",
50
- "@eslint-react/eff": "2.6.4",
51
- "@eslint-react/core": "2.6.4",
52
- "@eslint-react/shared": "2.6.4",
53
- "@eslint-react/var": "2.6.4"
49
+ "@eslint-react/ast": "2.6.5-beta.1",
50
+ "@eslint-react/core": "2.6.5-beta.1",
51
+ "@eslint-react/eff": "2.6.5-beta.1",
52
+ "@eslint-react/shared": "2.6.5-beta.1",
53
+ "@eslint-react/var": "2.6.5-beta.1"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/react": "^19.2.8",