eslint-plugin-react-x 5.18.3 → 5.18.4

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 +78 -75
  2. package/package.json +10 -10
package/dist/index.js CHANGED
@@ -145,7 +145,7 @@ const rules$6 = {
145
145
  //#endregion
146
146
  //#region package.json
147
147
  var name$6 = "eslint-plugin-react-x";
148
- var version = "5.18.3";
148
+ var version = "5.18.4";
149
149
 
150
150
  //#endregion
151
151
  //#region src/utils/create-rule.ts
@@ -531,15 +531,16 @@ const rule$1 = {
531
531
  declaredDependency = analyzePropertyChain(declaredDependencyNode, null);
532
532
  } catch (error) {
533
533
  if (error instanceof Error && /Unsupported node type/.test(error.message)) {
534
- if (declaredDependencyNode.type === "Literal") if (declaredDependencyNode.value && dependencies.has(declaredDependencyNode.value)) reportProblem({
535
- node: declaredDependencyNode,
536
- message: `The ${declaredDependencyNode.raw} literal is not a valid dependency because it never changes. Did you mean to include ${declaredDependencyNode.value} in the array instead?`
537
- });
538
- else reportProblem({
539
- node: declaredDependencyNode,
540
- message: `The ${declaredDependencyNode.raw} literal is not a valid dependency because it never changes. You can safely remove it.`
541
- });
542
- else reportProblem({
534
+ if (declaredDependencyNode.type === "Literal") {
535
+ if (declaredDependencyNode.value && dependencies.has(declaredDependencyNode.value)) reportProblem({
536
+ node: declaredDependencyNode,
537
+ message: `The ${declaredDependencyNode.raw} literal is not a valid dependency because it never changes. Did you mean to include ${declaredDependencyNode.value} in the array instead?`
538
+ });
539
+ else reportProblem({
540
+ node: declaredDependencyNode,
541
+ message: `The ${declaredDependencyNode.raw} literal is not a valid dependency because it never changes. You can safely remove it.`
542
+ });
543
+ } else reportProblem({
543
544
  node: declaredDependencyNode,
544
545
  message: `React Hook ${getSourceCode().getText(reactiveHook)} has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked.`
545
546
  });
@@ -813,7 +814,6 @@ const rule$1 = {
813
814
  visitFunctionWithDependencies(init, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect, isAutoDepsHook);
814
815
  return;
815
816
  }
816
- break;
817
817
  }
818
818
  break;
819
819
  default:
@@ -906,9 +906,10 @@ function collectRecommendations({ dependencies, declaredDependencies, stableDepe
906
906
  const unnecessaryDependencies = /* @__PURE__ */ new Set();
907
907
  const duplicateDependencies = /* @__PURE__ */ new Set();
908
908
  declaredDependencies.forEach(({ key }) => {
909
- if (satisfyingDependencies.has(key)) if (suggestedDependencies.indexOf(key) === -1) suggestedDependencies.push(key);
910
- else duplicateDependencies.add(key);
911
- else if (isEffect && !key.endsWith(".current") && !externalDependencies.has(key)) {
909
+ if (satisfyingDependencies.has(key)) {
910
+ if (suggestedDependencies.indexOf(key) === -1) suggestedDependencies.push(key);
911
+ else duplicateDependencies.add(key);
912
+ } else if (isEffect && !key.endsWith(".current") && !externalDependencies.has(key)) {
912
913
  if (suggestedDependencies.indexOf(key) === -1) suggestedDependencies.push(key);
913
914
  } else unnecessaryDependencies.add(key);
914
915
  });
@@ -967,10 +968,12 @@ function scanForConstructions({ declaredDependencies, declaredDependenciesNode,
967
968
  function isUsedOutsideOfHook(ref) {
968
969
  let foundWriteExpr = false;
969
970
  for (const reference of ref.references) {
970
- if (reference.writeExpr) if (foundWriteExpr) return true;
971
- else {
972
- foundWriteExpr = true;
973
- continue;
971
+ if (reference.writeExpr) {
972
+ if (foundWriteExpr) return true;
973
+ else {
974
+ foundWriteExpr = true;
975
+ continue;
976
+ }
974
977
  }
975
978
  let currentScope = reference.from;
976
979
  while (currentScope !== scope && currentScope != null) currentScope = currentScope.upper;
@@ -1005,9 +1008,11 @@ function getDependency(node) {
1005
1008
  * This particular node might still represent a required member, so check .optional field.
1006
1009
  */
1007
1010
  function markNode(node, optionalChains, result) {
1008
- if (optionalChains) if ("optional" in node && node.optional) {
1009
- if (!optionalChains.has(result)) optionalChains.set(result, true);
1010
- } else optionalChains.set(result, false);
1011
+ if (optionalChains) {
1012
+ if ("optional" in node && node.optional) {
1013
+ if (!optionalChains.has(result)) optionalChains.set(result, true);
1014
+ } else optionalChains.set(result, false);
1015
+ }
1011
1016
  }
1012
1017
  /**
1013
1018
  * Assuming () means the passed node.
@@ -1916,10 +1921,12 @@ function create$40(context) {
1916
1921
  if (!context.sourceCode.text.includes("Component")) return {};
1917
1922
  const { api, visitor } = core.getClassComponentCollector(context);
1918
1923
  return merge(visitor, { "Program:exit"(program) {
1919
- for (const { name = "anonymous", node: component } of api.getAllComponents(program)) {
1924
+ for (const { id, name = "anonymous", node: component } of api.getAllComponents(program)) {
1920
1925
  if (component.body.body.some((m) => core.isComponentDidCatch(m) || core.isGetDerivedStateFromError(m))) continue;
1926
+ const classToken = context.sourceCode.getFirstToken(component, { filter: (token) => token.value === "class" });
1921
1927
  context.report({
1922
1928
  data: { name },
1929
+ loc: (id ?? classToken ?? component).loc,
1923
1930
  messageId: "default",
1924
1931
  node: component
1925
1932
  });
@@ -4084,7 +4091,9 @@ function create$11(context) {
4084
4091
  for (const def of defs) {
4085
4092
  const methodName = def.name;
4086
4093
  if (usages?.has(methodName) ?? false) continue;
4087
- if (LIFECYCLE_METHODS.has(methodName)) if (methodName === "shouldComponentUpdate" && core.isPureComponent(currentClass)) {} else continue;
4094
+ if (LIFECYCLE_METHODS.has(methodName)) {
4095
+ if (methodName === "shouldComponentUpdate" && core.isPureComponent(currentClass)) {} else continue;
4096
+ }
4088
4097
  context.report({
4089
4098
  data: {
4090
4099
  className: id != null ? context.sourceCode.getText(id) : "Component",
@@ -4155,9 +4164,7 @@ function collectUsedPropKeysOfObjectPattern(context, usedPropKeys, objectPattern
4155
4164
  usedPropKeys.add(key);
4156
4165
  break;
4157
4166
  }
4158
- case AST_NODE_TYPES.RestElement:
4159
- if (!collectUsedPropsOfRestElement(context, usedPropKeys, property)) return false;
4160
- break;
4167
+ case AST_NODE_TYPES.RestElement: if (!collectUsedPropsOfRestElement(context, usedPropKeys, property)) return false;
4161
4168
  }
4162
4169
  return true;
4163
4170
  }
@@ -4189,18 +4196,14 @@ function collectUsedPropKeysOfReference(context, usedPropKeys, ref) {
4189
4196
  return true;
4190
4197
  }
4191
4198
  break;
4192
- case AST_NODE_TYPES.VariableDeclarator:
4193
- if (parent.id.type === AST_NODE_TYPES.ObjectPattern && parent.init === valueNode) return collectUsedPropKeysOfObjectPattern(context, usedPropKeys, parent.id);
4194
- break;
4199
+ case AST_NODE_TYPES.VariableDeclarator: if (parent.id.type === AST_NODE_TYPES.ObjectPattern && parent.init === valueNode) return collectUsedPropKeysOfObjectPattern(context, usedPropKeys, parent.id);
4195
4200
  }
4196
4201
  return false;
4197
4202
  }
4198
4203
  function getKeyOfExpression(expr) {
4199
4204
  switch (expr.type) {
4200
4205
  case AST_NODE_TYPES.Identifier: return expr.name;
4201
- case AST_NODE_TYPES.Literal:
4202
- if (typeof expr.value === "string") return expr.value;
4203
- break;
4206
+ case AST_NODE_TYPES.Literal: if (typeof expr.value === "string") return expr.value;
4204
4207
  }
4205
4208
  return null;
4206
4209
  }
@@ -4287,7 +4290,8 @@ function create$9(context) {
4287
4290
  },
4288
4291
  "Program:exit"() {
4289
4292
  for (const { name, node } of stateEntries) {
4290
- const variable = findVariable(context.sourceCode.getScope(node), name);
4293
+ const scope = context.sourceCode.getScope(node);
4294
+ const variable = findVariable(scope, name);
4291
4295
  if (variable == null) continue;
4292
4296
  let hasRead = false;
4293
4297
  for (const ref of variable.references) {
@@ -4643,7 +4647,8 @@ const IMPURE_CTORS = /* @__PURE__ */ new Set([
4643
4647
  function resolveBuiltinObjectName(context, node, seen = /* @__PURE__ */ new Set()) {
4644
4648
  if (seen.has(node.name)) return null;
4645
4649
  seen.add(node.name);
4646
- const variable = findVariable(context.sourceCode.getScope(node), node);
4650
+ const scope = context.sourceCode.getScope(node);
4651
+ const variable = findVariable(scope, node);
4647
4652
  if (variable == null) return node.name;
4648
4653
  const def = variable.defs[0];
4649
4654
  if (def == null) return node.name;
@@ -5860,10 +5865,12 @@ var CodePathState = class {
5860
5865
  this.forkBypassPath();
5861
5866
  const lastCaseSegments = forkContext.head;
5862
5867
  brokenForkContext.add(lastSegments);
5863
- if (!context.lastIsDefault) if (context.defaultBodySegments) {
5864
- removeConnection(context.defaultSegments, context.defaultBodySegments);
5865
- makeLooped(this, lastCaseSegments, context.defaultBodySegments);
5866
- } else brokenForkContext.add(lastCaseSegments);
5868
+ if (!context.lastIsDefault) {
5869
+ if (context.defaultBodySegments) {
5870
+ removeConnection(context.defaultSegments, context.defaultBodySegments);
5871
+ makeLooped(this, lastCaseSegments, context.defaultBodySegments);
5872
+ } else brokenForkContext.add(lastCaseSegments);
5873
+ }
5867
5874
  for (let i = 0; i < context.countForks; ++i) this.forkContext = this.forkContext.upper;
5868
5875
  this.forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
5869
5876
  }
@@ -6265,10 +6272,12 @@ var CodePathState = class {
6265
6272
  const forkContext = this.forkContext;
6266
6273
  if (!forkContext.reachable) return;
6267
6274
  const context = getContinueContext(this, label);
6268
- if (context) if (context.continueDestSegments != null) {
6269
- makeLooped(this, forkContext.head, context.continueDestSegments);
6270
- if (context.type === "ForInStatement" || context.type === "ForOfStatement") context.brokenForkContext.add(forkContext.head);
6271
- } else context.continueForkContext.add(forkContext.head);
6275
+ if (context) {
6276
+ if (context.continueDestSegments != null) {
6277
+ makeLooped(this, forkContext.head, context.continueDestSegments);
6278
+ if (context.type === "ForInStatement" || context.type === "ForOfStatement") context.brokenForkContext.add(forkContext.head);
6279
+ } else context.continueForkContext.add(forkContext.head);
6280
+ }
6272
6281
  forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
6273
6282
  }
6274
6283
  /**
@@ -6663,14 +6672,11 @@ function preprocess(analyzer, node) {
6663
6672
  state.makeForInOfBody();
6664
6673
  }
6665
6674
  break;
6666
- case "AssignmentPattern":
6667
- if (parent.right === node) {
6668
- state.pushForkContext();
6669
- state.forkBypassPath();
6670
- state.forkPath();
6671
- }
6672
- break;
6673
- default: break;
6675
+ case "AssignmentPattern": if (parent.right === node) {
6676
+ state.pushForkContext();
6677
+ state.forkBypassPath();
6678
+ state.forkPath();
6679
+ }
6674
6680
  }
6675
6681
  }
6676
6682
  /**
@@ -6745,10 +6751,7 @@ function processCodePathToEnter(analyzer, node) {
6745
6751
  case "ForOfStatement":
6746
6752
  state.pushLoopContext(node.type, getLabel(node));
6747
6753
  break;
6748
- case "LabeledStatement":
6749
- if (!breakableTypePattern.test(node.body.type)) state.pushBreakContext(false, node.label.name);
6750
- break;
6751
- default: break;
6754
+ case "LabeledStatement": if (!breakableTypePattern.test(node.body.type)) state.pushBreakContext(false, node.label.name);
6752
6755
  }
6753
6756
  forwardCurrentToHead(analyzer, node);
6754
6757
  }
@@ -6826,10 +6829,7 @@ function processCodePathToExit(analyzer, node) {
6826
6829
  case "AssignmentPattern":
6827
6830
  state.popForkContext();
6828
6831
  break;
6829
- case "LabeledStatement":
6830
- if (!breakableTypePattern.test(node.body.type)) state.popBreakContext();
6831
- break;
6832
- default: break;
6832
+ case "LabeledStatement": if (!breakableTypePattern.test(node.body.type)) state.popBreakContext();
6833
6833
  }
6834
6834
  if (!dontForward) forwardCurrentToHead(analyzer, node);
6835
6835
  }
@@ -6854,10 +6854,7 @@ function postprocess(analyzer, node) {
6854
6854
  case "StaticBlock":
6855
6855
  endCodePath();
6856
6856
  break;
6857
- case "CallExpression":
6858
- if (node.optional === true && node.arguments.length === 0) CodePath.getState(analyzer.codePath).makeOptionalRight();
6859
- break;
6860
- default: break;
6857
+ case "CallExpression": if (node.optional === true && node.arguments.length === 0) CodePath.getState(analyzer.codePath).makeOptionalRight();
6861
6858
  }
6862
6859
  if (isPropertyDefinitionValue(node)) endCodePath();
6863
6860
  }
@@ -7317,12 +7314,13 @@ const rule = {
7317
7314
  */
7318
7315
  function getFunctionName(node) {
7319
7316
  if (node.type === "ComponentDeclaration" || node.type === "HookDeclaration" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression" && node.id) return node.id;
7320
- else if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") if (node.parent?.type === "VariableDeclarator" && node.parent.init === node) return node.parent.id;
7321
- else if (node.parent?.type === "AssignmentExpression" && node.parent.right === node && node.parent.operator === "=") return node.parent.left;
7322
- else if (node.parent?.type === "Property" && node.parent.value === node && !node.parent.computed) return node.parent.key;
7323
- else if (node.parent?.type === "AssignmentPattern" && node.parent.right === node && !node.parent.computed) return node.parent.left;
7324
- else return;
7325
- else return;
7317
+ else if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
7318
+ if (node.parent?.type === "VariableDeclarator" && node.parent.init === node) return node.parent.id;
7319
+ else if (node.parent?.type === "AssignmentExpression" && node.parent.right === node && node.parent.operator === "=") return node.parent.left;
7320
+ else if (node.parent?.type === "Property" && node.parent.value === node && !node.parent.computed) return node.parent.key;
7321
+ else if (node.parent?.type === "AssignmentPattern" && node.parent.right === node && !node.parent.computed) return node.parent.left;
7322
+ else return;
7323
+ } else return;
7326
7324
  }
7327
7325
  /**
7328
7326
  * Convenience function for peeking the last item in a stack.
@@ -7554,13 +7552,15 @@ function create$5(context) {
7554
7552
  const isAt = Extract.getCalleeName(callee) === "at";
7555
7553
  const [index] = callee.arguments;
7556
7554
  if (!isAt || index == null) return false;
7557
- return getStaticValue(index, context.sourceCode.getScope(node))?.value === 1 && isIdFromUseStateCall(innerCallee.object);
7555
+ const indexScope = context.sourceCode.getScope(node);
7556
+ return getStaticValue(index, indexScope)?.value === 1 && isIdFromUseStateCall(innerCallee.object);
7558
7557
  }
7559
7558
  case AST_NODE_TYPES.Identifier: return isIdFromUseStateCall(callee, 1);
7560
7559
  case AST_NODE_TYPES.MemberExpression: {
7561
7560
  if (!("name" in callee.object)) return false;
7562
7561
  const property = callee.property;
7563
- return getStaticValue(property, context.sourceCode.getScope(node))?.value === 1 && isIdFromUseStateCall(callee.object, 1);
7562
+ const propertyScope = context.sourceCode.getScope(node);
7563
+ return getStaticValue(property, propertyScope)?.value === 1 && isIdFromUseStateCall(callee.object, 1);
7564
7564
  }
7565
7565
  default: return false;
7566
7566
  }
@@ -7713,7 +7713,6 @@ function isInsideConditional(node, stopAt) {
7713
7713
  case AST_NODE_TYPES.LogicalExpression:
7714
7714
  case AST_NODE_TYPES.SwitchStatement:
7715
7715
  case AST_NODE_TYPES.SwitchCase: return true;
7716
- default: break;
7717
7716
  }
7718
7717
  current = current.parent;
7719
7718
  }
@@ -7776,13 +7775,15 @@ function create$4(context) {
7776
7775
  const isAt = Extract.getCalleeName(callee) === "at";
7777
7776
  const [index] = callee.arguments;
7778
7777
  if (!isAt || index == null) return false;
7779
- return getStaticValue(index, context.sourceCode.getScope(node))?.value === 1 && isIdFromUseStateCall(innerCallee.object);
7778
+ const indexScope = context.sourceCode.getScope(node);
7779
+ return getStaticValue(index, indexScope)?.value === 1 && isIdFromUseStateCall(innerCallee.object);
7780
7780
  }
7781
7781
  case AST_NODE_TYPES.Identifier: return isIdFromUseStateCall(callee, 1);
7782
7782
  case AST_NODE_TYPES.MemberExpression: {
7783
7783
  if (!("name" in callee.object)) return false;
7784
7784
  const property = callee.property;
7785
- return getStaticValue(property, context.sourceCode.getScope(node))?.value === 1 && isIdFromUseStateCall(callee.object, 1);
7785
+ const propertyScope = context.sourceCode.getScope(node);
7786
+ return getStaticValue(property, propertyScope)?.value === 1 && isIdFromUseStateCall(callee.object, 1);
7786
7787
  }
7787
7788
  default: return false;
7788
7789
  }
@@ -7857,7 +7858,8 @@ const DYNAMIC_EXPRESSION_TYPES = /* @__PURE__ */ new Set([
7857
7858
  AST_NODE_TYPES.NewExpression
7858
7859
  ]);
7859
7860
  function findVariableForIdentifier(context, identifier) {
7860
- return findVariable(context.sourceCode.getScope(identifier), identifier.name);
7861
+ const scope = context.sourceCode.getScope(identifier);
7862
+ return findVariable(scope, identifier.name);
7861
7863
  }
7862
7864
  /**
7863
7865
  * Resolves an expression down to the node that dynamically created its value, if any.
@@ -8121,7 +8123,8 @@ function create$1(context) {
8121
8123
  const left = Extract.unwrap(node.left);
8122
8124
  if (left.type !== AST_NODE_TYPES.Identifier) return;
8123
8125
  if (Traverse.findParent(node, Check.isFunction, (n) => n === callback) != null) return;
8124
- const variable = findVariable(context.sourceCode.getScope(left), left);
8126
+ const scope = context.sourceCode.getScope(left);
8127
+ const variable = findVariable(scope, left);
8125
8128
  if (variable != null && variable.defs.length > 0 && isDeclaredInsideCallback(variable, callback)) return;
8126
8129
  violations.push({
8127
8130
  messageId: "noReassigningOuterVariables",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "5.18.3",
3
+ "version": "5.18.4",
4
4
  "description": "A set of composable ESLint rules for libraries and frameworks that use React as a UI runtime.",
5
5
  "keywords": [
6
6
  "react",
@@ -45,26 +45,26 @@
45
45
  "string-ts": "^2.3.1",
46
46
  "ts-api-utils": "^2.5.0",
47
47
  "ts-pattern": "^5.9.0",
48
- "@eslint-react/ast": "5.18.3",
49
- "@eslint-react/core": "5.18.3",
50
- "@eslint-react/eslint": "5.18.3",
51
- "@eslint-react/shared": "5.18.3",
52
- "@eslint-react/var": "5.18.3",
53
- "@eslint-react/jsx": "5.18.3"
48
+ "@eslint-react/ast": "5.18.4",
49
+ "@eslint-react/core": "5.18.4",
50
+ "@eslint-react/eslint": "5.18.4",
51
+ "@eslint-react/jsx": "5.18.4",
52
+ "@eslint-react/var": "5.18.4",
53
+ "@eslint-react/shared": "5.18.4"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/react": "^19.2.18",
57
57
  "@types/react-dom": "^19.2.4",
58
58
  "dedent": "^1.7.2",
59
- "eslint": "^10.8.0",
59
+ "eslint": "^10.8.1",
60
60
  "react": "^19.2.8",
61
61
  "react-dom": "^19.2.8",
62
62
  "tsdown": "^0.22.14",
63
63
  "tsl": "^1.0.30",
64
64
  "tsl-dx": "^0.13.3",
65
65
  "typescript": "6.0.3",
66
- "@local/eff": "0.0.0",
67
- "@local/configs": "0.0.0"
66
+ "@local/configs": "0.0.0",
67
+ "@local/eff": "0.0.0"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "eslint": "*",