eslint-plugin-react-x 5.18.2 → 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 +134 -124
  2. package/package.json +13 -13
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.2";
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
  });
@@ -3396,47 +3403,39 @@ function create$23(context) {
3396
3403
 
3397
3404
  //#endregion
3398
3405
  //#region src/rules/no-nested-component-definitions/lib.ts
3406
+ /** Check if the node is a call expression to react-redux's `connect`. */
3407
+ const isConnectCall = core.isAPICall("connect");
3408
+ /** Check if the node is a call expression to Relay's `createFragmentContainer`. */
3409
+ const isCreateFragmentContainerCall = core.isAPICall("createFragmentContainer");
3410
+ /** Check if the node is a call expression to Relay's `createPaginationContainer`. */
3411
+ const isCreatePaginationContainerCall = core.isAPICall("createPaginationContainer");
3412
+ /** Check if the node is a call expression to Relay's `createRefetchContainer`. */
3413
+ const isCreateRefetchContainerCall = core.isAPICall("createRefetchContainer");
3414
+ /** Check if the node is a call expression to React's `forwardRef`. */
3415
+ const isForwardRefCall = core.isAPICall("forwardRef");
3416
+ /** Check if the node is a call expression to a `graphql` tag function (e.g. from Relay or Apollo). */
3417
+ const isGraphqlCall = core.isAPICall("graphql");
3418
+ /** Check if the node is a call expression to React's `memo`. */
3419
+ const isMemoCall = core.isAPICall("memo");
3420
+ /** Check if the node is a call expression to MobX's `observer`. */
3421
+ const isObserverCall = core.isAPICall("observer");
3422
+ /** Check if the node is a call expression to React's `useCallback`. */
3423
+ const isUseCallbackCall = core.isAPICall("useCallback");
3424
+ /** Check if the node is a call expression to Formik's `withFormik`. */
3425
+ const isWithFormikCall = core.isAPICall("withFormik");
3426
+ /** Check if the node is a call expression to recompose's `withHandlers`. */
3427
+ const isWithHandlersCall = core.isAPICall("withHandlers");
3428
+ /** Check if the node is a call expression to recompose's `withLifecycle`. */
3429
+ const isWithLifecycleCall = core.isAPICall("withLifecycle");
3430
+ /** Check if the node is a call expression to recompose's `withProps`. */
3431
+ const isWithPropsCall = core.isAPICall("withProps");
3432
+ /** Check if the node is a call expression to react-router v5's `withRouter`. */
3433
+ const isWithRouterCall = core.isAPICall("withRouter");
3434
+ /** Check if the node is a call expression to recompose's `withState`. */
3435
+ const isWithStateCall = core.isAPICall("withState");
3399
3436
  /**
3400
- * Well-known component wrapper function names, matched by exact or `.`-suffixed fully
3401
- * qualified name (e.g. `memo`, `React.memo`, `mobx.observer`, `connect` from react-redux,
3402
- * or Relay's `create*Container` helpers). Only wrappers whose argument is a render function
3403
- * are listed; wrappers taking a component identifier (`styled`, `motion`) or a loader
3404
- * (`lazy`, `dynamic`) are irrelevant for name resolution.
3405
- */
3406
- const WELL_KNOWN_COMPONENT_WRAPPERS = [
3407
- "connect",
3408
- "createFragmentContainer",
3409
- "createPaginationContainer",
3410
- "createRefetchContainer",
3411
- "forwardRef",
3412
- "graphql",
3413
- "memo",
3414
- "observer",
3415
- "useCallback"
3416
- ];
3417
- /** Matches the HOC naming convention shared by recompose, react-router v5, Formik and custom HOCs (e.g. `withProps`, `withRouter`, `withFormik`, `withAuth`). */
3418
- const RE_HOC_WRAPPER_NAME = /^with[A-Z]/;
3419
- /**
3420
- * Check if a call expression is a well-known component wrapper call.
3421
- * Only calls whose callee's fully qualified name is (or ends with) a well-known wrapper
3422
- * name (e.g. `memo`, `React.memo`, `React.useCallback`, `mobx.observer`) are treated as
3423
- * wrappers; anything else, including member calls on data objects (e.g. `items.map`,
3424
- * `Array.from`), is not, so array method callbacks are never mistaken for wrapped components.
3425
- * Curried wrappers like `connect(...)(Component)` or `withFormik(...)(Component)` are
3426
- * recognized by unwrapping nested callee call expressions.
3427
- * @param context The rule context
3428
- * @param node The call expression to check
3429
- * @returns `true` if the call is a well-known component wrapper call
3430
- */
3431
- function isWellKnownComponentWrapperCall(context, node) {
3432
- let callee = Extract.unwrap(node.callee);
3433
- while (callee.type === AST_NODE_TYPES.CallExpression) callee = Extract.unwrap(callee.callee);
3434
- const name = Extract.getFullyQualifiedName(callee, (n) => context.sourceCode.getText(n));
3435
- const baseName = name.slice(name.lastIndexOf(".") + 1);
3436
- return RE_HOC_WRAPPER_NAME.test(baseName) || WELL_KNOWN_COMPONENT_WRAPPERS.some((wrapper) => name === wrapper || name.endsWith(`.${wrapper}`));
3437
- }
3438
- /**
3439
- * Check if a call expression is a component wrapper call for name resolution purposes.
3437
+ * Check if a call is a well-known component wrapper call (e.g. `memo`, `connect`, `withFormik`).
3438
+ * Curried forms like `connect(...)(Component)` are matched via the innermost callee call.
3440
3439
  * @param context The rule context
3441
3440
  * @param call The call expression to check
3442
3441
  * @param arg The function node passed to the call
@@ -3444,14 +3443,29 @@ function isWellKnownComponentWrapperCall(context, node) {
3444
3443
  */
3445
3444
  function isComponentWrapperCall(context, call, arg) {
3446
3445
  if (Extract.unwrap(call.callee) === arg) return false;
3447
- return isWellKnownComponentWrapperCall(context, call);
3446
+ call = Extract.getInnermostCall(call);
3447
+ if (isConnectCall(context, call)) return true;
3448
+ if (isCreateFragmentContainerCall(context, call)) return true;
3449
+ if (isCreatePaginationContainerCall(context, call)) return true;
3450
+ if (isCreateRefetchContainerCall(context, call)) return true;
3451
+ if (isForwardRefCall(context, call)) return true;
3452
+ if (isGraphqlCall(context, call)) return true;
3453
+ if (isMemoCall(context, call)) return true;
3454
+ if (isObserverCall(context, call)) return true;
3455
+ if (isUseCallbackCall(context, call)) return true;
3456
+ if (isWithFormikCall(context, call)) return true;
3457
+ if (isWithHandlersCall(context, call)) return true;
3458
+ if (isWithLifecycleCall(context, call)) return true;
3459
+ if (isWithPropsCall(context, call)) return true;
3460
+ if (isWithRouterCall(context, call)) return true;
3461
+ if (isWithStateCall(context, call)) return true;
3462
+ return false;
3448
3463
  }
3449
3464
  /**
3450
- * Resolve the name a function is bound to through a chain of wrapping call expressions,
3451
- * e.g. `const Component = useCallback(() => <div />, [])` resolves to `Component`.
3465
+ * Resolve the name a function is bound to through wrapping calls (e.g. `const C = useCallback(...)` → `C`).
3452
3466
  * @param context The rule context
3453
3467
  * @param node The function node to resolve the bound name for
3454
- * @returns The bound name if the call chain ends at a variable declarator with an identifier, `null` otherwise
3468
+ * @returns The bound name, or `null` if the call chain does not end at an identifier declarator
3455
3469
  */
3456
3470
  function getWrapperCallBoundName(context, node) {
3457
3471
  let current = node;
@@ -3472,7 +3486,7 @@ function getWrapperCallBoundName(context, node) {
3472
3486
  return parent.id.name;
3473
3487
  }
3474
3488
  /**
3475
- * Determine whether the node is inside `createElement`'s props argument
3489
+ * Check if the node is inside `createElement`'s props argument
3476
3490
  * @param context The rule context
3477
3491
  * @param node The AST node to check
3478
3492
  * @returns `true` if the node is inside `createElement`'s props
@@ -3485,17 +3499,17 @@ function isInsideCreateElementProps(context, node) {
3485
3499
  return prop === call.arguments[1];
3486
3500
  }
3487
3501
  /**
3488
- * Determine whether the node is inside JSX attribute value
3502
+ * Check if the node is inside a JSX attribute value
3489
3503
  * @param node The AST node to check
3490
- * @returns `true` if the node is inside JSX attribute value
3504
+ * @returns `true` if the node is inside a JSX attribute value
3491
3505
  */
3492
3506
  function isInsideJSXAttributeValue(node) {
3493
3507
  return node.parent.type === AST_NODE_TYPES.JSXAttribute || findParentAttribute(node, (n) => n.value?.type === AST_NODE_TYPES.JSXExpressionContainer) != null;
3494
3508
  }
3495
3509
  /**
3496
- * Check whether a given node is declared inside a class component's render block
3510
+ * Check if the node is declared inside a class component's render block
3497
3511
  * Ex: class C extends React.Component { render() { const Nested = () => <div />; } }
3498
- * @param node The AST node being checked
3512
+ * @param node The AST node to check
3499
3513
  * @returns `true` if the node is inside a class component's render block
3500
3514
  */
3501
3515
  function isInsideRenderMethod(node) {
@@ -4077,7 +4091,9 @@ function create$11(context) {
4077
4091
  for (const def of defs) {
4078
4092
  const methodName = def.name;
4079
4093
  if (usages?.has(methodName) ?? false) continue;
4080
- 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
+ }
4081
4097
  context.report({
4082
4098
  data: {
4083
4099
  className: id != null ? context.sourceCode.getText(id) : "Component",
@@ -4148,9 +4164,7 @@ function collectUsedPropKeysOfObjectPattern(context, usedPropKeys, objectPattern
4148
4164
  usedPropKeys.add(key);
4149
4165
  break;
4150
4166
  }
4151
- case AST_NODE_TYPES.RestElement:
4152
- if (!collectUsedPropsOfRestElement(context, usedPropKeys, property)) return false;
4153
- break;
4167
+ case AST_NODE_TYPES.RestElement: if (!collectUsedPropsOfRestElement(context, usedPropKeys, property)) return false;
4154
4168
  }
4155
4169
  return true;
4156
4170
  }
@@ -4182,18 +4196,14 @@ function collectUsedPropKeysOfReference(context, usedPropKeys, ref) {
4182
4196
  return true;
4183
4197
  }
4184
4198
  break;
4185
- case AST_NODE_TYPES.VariableDeclarator:
4186
- if (parent.id.type === AST_NODE_TYPES.ObjectPattern && parent.init === valueNode) return collectUsedPropKeysOfObjectPattern(context, usedPropKeys, parent.id);
4187
- break;
4199
+ case AST_NODE_TYPES.VariableDeclarator: if (parent.id.type === AST_NODE_TYPES.ObjectPattern && parent.init === valueNode) return collectUsedPropKeysOfObjectPattern(context, usedPropKeys, parent.id);
4188
4200
  }
4189
4201
  return false;
4190
4202
  }
4191
4203
  function getKeyOfExpression(expr) {
4192
4204
  switch (expr.type) {
4193
4205
  case AST_NODE_TYPES.Identifier: return expr.name;
4194
- case AST_NODE_TYPES.Literal:
4195
- if (typeof expr.value === "string") return expr.value;
4196
- break;
4206
+ case AST_NODE_TYPES.Literal: if (typeof expr.value === "string") return expr.value;
4197
4207
  }
4198
4208
  return null;
4199
4209
  }
@@ -4280,7 +4290,8 @@ function create$9(context) {
4280
4290
  },
4281
4291
  "Program:exit"() {
4282
4292
  for (const { name, node } of stateEntries) {
4283
- const variable = findVariable(context.sourceCode.getScope(node), name);
4293
+ const scope = context.sourceCode.getScope(node);
4294
+ const variable = findVariable(scope, name);
4284
4295
  if (variable == null) continue;
4285
4296
  let hasRead = false;
4286
4297
  for (const ref of variable.references) {
@@ -4636,7 +4647,8 @@ const IMPURE_CTORS = /* @__PURE__ */ new Set([
4636
4647
  function resolveBuiltinObjectName(context, node, seen = /* @__PURE__ */ new Set()) {
4637
4648
  if (seen.has(node.name)) return null;
4638
4649
  seen.add(node.name);
4639
- const variable = findVariable(context.sourceCode.getScope(node), node);
4650
+ const scope = context.sourceCode.getScope(node);
4651
+ const variable = findVariable(scope, node);
4640
4652
  if (variable == null) return node.name;
4641
4653
  const def = variable.defs[0];
4642
4654
  if (def == null) return node.name;
@@ -5853,10 +5865,12 @@ var CodePathState = class {
5853
5865
  this.forkBypassPath();
5854
5866
  const lastCaseSegments = forkContext.head;
5855
5867
  brokenForkContext.add(lastSegments);
5856
- if (!context.lastIsDefault) if (context.defaultBodySegments) {
5857
- removeConnection(context.defaultSegments, context.defaultBodySegments);
5858
- makeLooped(this, lastCaseSegments, context.defaultBodySegments);
5859
- } 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
+ }
5860
5874
  for (let i = 0; i < context.countForks; ++i) this.forkContext = this.forkContext.upper;
5861
5875
  this.forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
5862
5876
  }
@@ -6258,10 +6272,12 @@ var CodePathState = class {
6258
6272
  const forkContext = this.forkContext;
6259
6273
  if (!forkContext.reachable) return;
6260
6274
  const context = getContinueContext(this, label);
6261
- if (context) if (context.continueDestSegments != null) {
6262
- makeLooped(this, forkContext.head, context.continueDestSegments);
6263
- if (context.type === "ForInStatement" || context.type === "ForOfStatement") context.brokenForkContext.add(forkContext.head);
6264
- } 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
+ }
6265
6281
  forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
6266
6282
  }
6267
6283
  /**
@@ -6656,14 +6672,11 @@ function preprocess(analyzer, node) {
6656
6672
  state.makeForInOfBody();
6657
6673
  }
6658
6674
  break;
6659
- case "AssignmentPattern":
6660
- if (parent.right === node) {
6661
- state.pushForkContext();
6662
- state.forkBypassPath();
6663
- state.forkPath();
6664
- }
6665
- break;
6666
- default: break;
6675
+ case "AssignmentPattern": if (parent.right === node) {
6676
+ state.pushForkContext();
6677
+ state.forkBypassPath();
6678
+ state.forkPath();
6679
+ }
6667
6680
  }
6668
6681
  }
6669
6682
  /**
@@ -6738,10 +6751,7 @@ function processCodePathToEnter(analyzer, node) {
6738
6751
  case "ForOfStatement":
6739
6752
  state.pushLoopContext(node.type, getLabel(node));
6740
6753
  break;
6741
- case "LabeledStatement":
6742
- if (!breakableTypePattern.test(node.body.type)) state.pushBreakContext(false, node.label.name);
6743
- break;
6744
- default: break;
6754
+ case "LabeledStatement": if (!breakableTypePattern.test(node.body.type)) state.pushBreakContext(false, node.label.name);
6745
6755
  }
6746
6756
  forwardCurrentToHead(analyzer, node);
6747
6757
  }
@@ -6819,10 +6829,7 @@ function processCodePathToExit(analyzer, node) {
6819
6829
  case "AssignmentPattern":
6820
6830
  state.popForkContext();
6821
6831
  break;
6822
- case "LabeledStatement":
6823
- if (!breakableTypePattern.test(node.body.type)) state.popBreakContext();
6824
- break;
6825
- default: break;
6832
+ case "LabeledStatement": if (!breakableTypePattern.test(node.body.type)) state.popBreakContext();
6826
6833
  }
6827
6834
  if (!dontForward) forwardCurrentToHead(analyzer, node);
6828
6835
  }
@@ -6847,10 +6854,7 @@ function postprocess(analyzer, node) {
6847
6854
  case "StaticBlock":
6848
6855
  endCodePath();
6849
6856
  break;
6850
- case "CallExpression":
6851
- if (node.optional === true && node.arguments.length === 0) CodePath.getState(analyzer.codePath).makeOptionalRight();
6852
- break;
6853
- default: break;
6857
+ case "CallExpression": if (node.optional === true && node.arguments.length === 0) CodePath.getState(analyzer.codePath).makeOptionalRight();
6854
6858
  }
6855
6859
  if (isPropertyDefinitionValue(node)) endCodePath();
6856
6860
  }
@@ -7310,12 +7314,13 @@ const rule = {
7310
7314
  */
7311
7315
  function getFunctionName(node) {
7312
7316
  if (node.type === "ComponentDeclaration" || node.type === "HookDeclaration" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression" && node.id) return node.id;
7313
- else if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") if (node.parent?.type === "VariableDeclarator" && node.parent.init === node) return node.parent.id;
7314
- else if (node.parent?.type === "AssignmentExpression" && node.parent.right === node && node.parent.operator === "=") return node.parent.left;
7315
- else if (node.parent?.type === "Property" && node.parent.value === node && !node.parent.computed) return node.parent.key;
7316
- else if (node.parent?.type === "AssignmentPattern" && node.parent.right === node && !node.parent.computed) return node.parent.left;
7317
- else return;
7318
- 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;
7319
7324
  }
7320
7325
  /**
7321
7326
  * Convenience function for peeking the last item in a stack.
@@ -7547,13 +7552,15 @@ function create$5(context) {
7547
7552
  const isAt = Extract.getCalleeName(callee) === "at";
7548
7553
  const [index] = callee.arguments;
7549
7554
  if (!isAt || index == null) return false;
7550
- 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);
7551
7557
  }
7552
7558
  case AST_NODE_TYPES.Identifier: return isIdFromUseStateCall(callee, 1);
7553
7559
  case AST_NODE_TYPES.MemberExpression: {
7554
7560
  if (!("name" in callee.object)) return false;
7555
7561
  const property = callee.property;
7556
- 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);
7557
7564
  }
7558
7565
  default: return false;
7559
7566
  }
@@ -7706,7 +7713,6 @@ function isInsideConditional(node, stopAt) {
7706
7713
  case AST_NODE_TYPES.LogicalExpression:
7707
7714
  case AST_NODE_TYPES.SwitchStatement:
7708
7715
  case AST_NODE_TYPES.SwitchCase: return true;
7709
- default: break;
7710
7716
  }
7711
7717
  current = current.parent;
7712
7718
  }
@@ -7769,13 +7775,15 @@ function create$4(context) {
7769
7775
  const isAt = Extract.getCalleeName(callee) === "at";
7770
7776
  const [index] = callee.arguments;
7771
7777
  if (!isAt || index == null) return false;
7772
- 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);
7773
7780
  }
7774
7781
  case AST_NODE_TYPES.Identifier: return isIdFromUseStateCall(callee, 1);
7775
7782
  case AST_NODE_TYPES.MemberExpression: {
7776
7783
  if (!("name" in callee.object)) return false;
7777
7784
  const property = callee.property;
7778
- 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);
7779
7787
  }
7780
7788
  default: return false;
7781
7789
  }
@@ -7850,7 +7858,8 @@ const DYNAMIC_EXPRESSION_TYPES = /* @__PURE__ */ new Set([
7850
7858
  AST_NODE_TYPES.NewExpression
7851
7859
  ]);
7852
7860
  function findVariableForIdentifier(context, identifier) {
7853
- return findVariable(context.sourceCode.getScope(identifier), identifier.name);
7861
+ const scope = context.sourceCode.getScope(identifier);
7862
+ return findVariable(scope, identifier.name);
7854
7863
  }
7855
7864
  /**
7856
7865
  * Resolves an expression down to the node that dynamically created its value, if any.
@@ -8114,7 +8123,8 @@ function create$1(context) {
8114
8123
  const left = Extract.unwrap(node.left);
8115
8124
  if (left.type !== AST_NODE_TYPES.Identifier) return;
8116
8125
  if (Traverse.findParent(node, Check.isFunction, (n) => n === callback) != null) return;
8117
- const variable = findVariable(context.sourceCode.getScope(left), left);
8126
+ const scope = context.sourceCode.getScope(left);
8127
+ const variable = findVariable(scope, left);
8118
8128
  if (variable != null && variable.defs.length > 0 && isDeclaredInsideCallback(variable, callback)) return;
8119
8129
  violations.push({
8120
8130
  messageId: "noReassigningOuterVariables",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "5.18.2",
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",
@@ -36,27 +36,27 @@
36
36
  "dist"
37
37
  ],
38
38
  "dependencies": {
39
- "@typescript-eslint/scope-manager": "^8.65.0",
40
- "@typescript-eslint/type-utils": "^8.65.0",
41
- "@typescript-eslint/types": "^8.65.0",
42
- "@typescript-eslint/typescript-estree": "^8.65.0",
43
- "@typescript-eslint/utils": "^8.65.0",
39
+ "@typescript-eslint/scope-manager": "^8.66.0",
40
+ "@typescript-eslint/type-utils": "^8.66.0",
41
+ "@typescript-eslint/types": "^8.66.0",
42
+ "@typescript-eslint/typescript-estree": "^8.66.0",
43
+ "@typescript-eslint/utils": "^8.66.0",
44
44
  "compare-versions": "^6.1.1",
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.2",
49
- "@eslint-react/core": "5.18.2",
50
- "@eslint-react/eslint": "5.18.2",
51
- "@eslint-react/jsx": "5.18.2",
52
- "@eslint-react/var": "5.18.2",
53
- "@eslint-react/shared": "5.18.2"
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",