eslint-plugin-react-x 5.23.4 → 5.23.5

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 +64 -28
  2. package/package.json +7 -7
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.23.4";
148
+ var version = "5.23.5";
149
149
 
150
150
  //#endregion
151
151
  //#region src/utils/create-rule.ts
@@ -7980,15 +7980,29 @@ function isInitializedFromRef(context, name, initialScope, seen = /* @__PURE__ *
7980
7980
  const { additionalRefHooks } = getSettingsFromContext(context);
7981
7981
  if (seen.has(name)) return false;
7982
7982
  seen.add(name);
7983
- for (const { node } of findVariable(initialScope, name)?.defs ?? []) {
7983
+ for (const def of findVariable(initialScope, name)?.defs ?? []) {
7984
+ if (def.type === DefinitionType.Parameter) {
7985
+ if (def.name.type === AST_NODE_TYPES.Identifier && (def.name.name === "ref" || def.name.name.endsWith("Ref"))) return true;
7986
+ continue;
7987
+ }
7988
+ const { node } = def;
7984
7989
  if (node.type !== AST_NODE_TYPES.VariableDeclarator) continue;
7985
7990
  const init = node.init == null ? null : Extract.unwrap(node.init);
7986
7991
  if (init == null) continue;
7987
7992
  switch (true) {
7988
7993
  case init.type === AST_NODE_TYPES.MemberExpression: {
7989
- let object = Extract.unwrap(init.object);
7990
- while (object.type === AST_NODE_TYPES.MemberExpression) object = Extract.unwrap(object.object);
7991
- return Check.isIdentifier(object) && (object.name === "ref" || object.name.endsWith("Ref"));
7994
+ let current = init;
7995
+ while (current.type === AST_NODE_TYPES.MemberExpression) {
7996
+ const property = Extract.unwrap(current.property);
7997
+ const object = Extract.unwrap(current.object);
7998
+ if (!current.computed && Check.isIdentifier(property, "current")) {
7999
+ const sourceName = getRefSourceName(object);
8000
+ if (sourceName === "ref" || sourceName?.endsWith("Ref") === true) return true;
8001
+ }
8002
+ current = object;
8003
+ }
8004
+ if (Check.isIdentifier(current) && (current.name === "ref" || current.name.endsWith("Ref"))) return true;
8005
+ return getNestedIdentifiers(init).some((id) => isInitializedFromRef(context, id.name, context.sourceCode.getScope(id), seen));
7992
8006
  }
7993
8007
  case init.type === AST_NODE_TYPES.CallExpression && core.isUseRefLikeCall(init, additionalRefHooks): return true;
7994
8008
  default: return getNestedIdentifiers(init).some((id) => isInitializedFromRef(context, id.name, context.sourceCode.getScope(id), seen));
@@ -7997,6 +8011,21 @@ function isInitializedFromRef(context, name, initialScope, seen = /* @__PURE__ *
7997
8011
  return false;
7998
8012
  }
7999
8013
  /**
8014
+ * Get the name that identifies the source of a `.current` member access.
8015
+ * @param node The object of the member expression
8016
+ * @returns The identifier name, the last property name of a member chain, or null
8017
+ */
8018
+ function getRefSourceName(node) {
8019
+ switch (node.type) {
8020
+ case AST_NODE_TYPES.Identifier: return node.name;
8021
+ case AST_NODE_TYPES.MemberExpression: {
8022
+ const property = Extract.unwrap(node.property);
8023
+ return !node.computed && property.type === AST_NODE_TYPES.Identifier ? property.name : null;
8024
+ }
8025
+ default: return null;
8026
+ }
8027
+ }
8028
+ /**
8000
8029
  * Check if a setState call is inside a conditional block whose test expression
8001
8030
  * is derived from a ref value (e.g. `if (prevRef.current !== value) setState(...)`).
8002
8031
  * @param context The ESLint rule context
@@ -8043,7 +8072,7 @@ function isRefInExpression(context, node) {
8043
8072
  * @returns The actual CallExpression node
8044
8073
  */
8045
8074
  function getSetStateCallExpression(node) {
8046
- return Check.isIdentifier(node) && node.parent.type === AST_NODE_TYPES.CallExpression ? node.parent : node;
8075
+ return Check.isIdentifier(node) && node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node ? node.parent : node;
8047
8076
  }
8048
8077
 
8049
8078
  //#endregion
@@ -8139,6 +8168,25 @@ function create$5(context) {
8139
8168
  default: return false;
8140
8169
  }
8141
8170
  }
8171
+ function isArgumentUsingRefValue(context, node) {
8172
+ const isUsingRefValue = (n) => {
8173
+ switch (n.type) {
8174
+ case AST_NODE_TYPES.Identifier: return isInitializedFromRef(context, n.name, context.sourceCode.getScope(n));
8175
+ case AST_NODE_TYPES.MemberExpression: return isUsingRefValue(n.object);
8176
+ case AST_NODE_TYPES.CallExpression: return isUsingRefValue(n.callee) || getNestedIdentifiers(n).some(isUsingRefValue);
8177
+ case AST_NODE_TYPES.BinaryExpression:
8178
+ case AST_NODE_TYPES.LogicalExpression: return isUsingRefValue(n.left) || isUsingRefValue(n.right);
8179
+ case AST_NODE_TYPES.UnaryExpression:
8180
+ case AST_NODE_TYPES.UpdateExpression: return isUsingRefValue(n.argument);
8181
+ case AST_NODE_TYPES.ConditionalExpression: return isUsingRefValue(n.consequent) || isUsingRefValue(n.alternate);
8182
+ case AST_NODE_TYPES.SequenceExpression: return n.expressions.some(isUsingRefValue);
8183
+ case AST_NODE_TYPES.AssignmentExpression: return isUsingRefValue(n.right);
8184
+ default: return false;
8185
+ }
8186
+ };
8187
+ if (isUsingRefValue(node)) return true;
8188
+ return Check.isFunction(node) && context.sourceCode.getScope(node.body).references.some((r) => isUsingRefValue(r.identifier));
8189
+ }
8142
8190
  return {
8143
8191
  ":function"(node) {
8144
8192
  const kind = getFunctionKind(node);
@@ -8165,25 +8213,6 @@ function create$5(context) {
8165
8213
  case entry.kind === "immediate" && Traverse.findParent(entry.node, Check.isFunction) === setupFunction: {
8166
8214
  const args0 = node.arguments.at(0);
8167
8215
  if (args0 == null) return;
8168
- function isArgumentUsingRefValue(context, node) {
8169
- const isUsingRefValue = (n) => {
8170
- switch (n.type) {
8171
- case AST_NODE_TYPES.Identifier: return isInitializedFromRef(context, n.name, context.sourceCode.getScope(n));
8172
- case AST_NODE_TYPES.MemberExpression: return isUsingRefValue(n.object);
8173
- case AST_NODE_TYPES.CallExpression: return isUsingRefValue(n.callee) || getNestedIdentifiers(n).some(isUsingRefValue);
8174
- case AST_NODE_TYPES.BinaryExpression:
8175
- case AST_NODE_TYPES.LogicalExpression: return isUsingRefValue(n.left) || isUsingRefValue(n.right);
8176
- case AST_NODE_TYPES.UnaryExpression:
8177
- case AST_NODE_TYPES.UpdateExpression: return isUsingRefValue(n.argument);
8178
- case AST_NODE_TYPES.ConditionalExpression: return isUsingRefValue(n.consequent) || isUsingRefValue(n.alternate);
8179
- case AST_NODE_TYPES.SequenceExpression: return n.expressions.some(isUsingRefValue);
8180
- case AST_NODE_TYPES.AssignmentExpression: return isUsingRefValue(n.right);
8181
- default: return false;
8182
- }
8183
- };
8184
- if (isUsingRefValue(node)) return true;
8185
- return Check.isFunction(node) && context.sourceCode.getScope(node.body).references.some((r) => isUsingRefValue(r.identifier));
8186
- }
8187
8216
  if (isArgumentUsingRefValue(context, args0)) return;
8188
8217
  if (isRefGatedContext(context, node)) return;
8189
8218
  context.report({
@@ -8230,6 +8259,13 @@ function create$5(context) {
8230
8259
  }
8231
8260
  },
8232
8261
  "Program:exit"() {
8262
+ const isExemptSetStateCall = (setStateCall) => {
8263
+ const callNode = getSetStateCallExpression(setStateCall);
8264
+ if (isRefGatedContext(context, callNode)) return true;
8265
+ if (callNode.type !== AST_NODE_TYPES.CallExpression) return false;
8266
+ const args0 = callNode.arguments.at(0);
8267
+ return args0 != null && isArgumentUsingRefValue(context, args0);
8268
+ };
8233
8269
  const getSetStateCalls = (context, id) => {
8234
8270
  const variable = findVariable(context.sourceCode.getScope(id), id);
8235
8271
  if (variable != null && variable.defs.some((def) => def.type === DefinitionType.Parameter)) return [];
@@ -8243,7 +8279,7 @@ function create$5(context) {
8243
8279
  return [];
8244
8280
  };
8245
8281
  for (const [, calls] of setStateInEffectSetup) for (const call of calls) {
8246
- if (isRefGatedContext(context, getSetStateCallExpression(call))) continue;
8282
+ if (isExemptSetStateCall(call)) continue;
8247
8283
  context.report({
8248
8284
  data: { name: call.name },
8249
8285
  messageId: "default",
@@ -8255,7 +8291,7 @@ function create$5(context) {
8255
8291
  if (!Check.isIdentifier(unwrappedCallee)) continue;
8256
8292
  const setStateCalls = getSetStateCalls(context, unwrappedCallee);
8257
8293
  for (const setStateCall of setStateCalls) {
8258
- if (isRefGatedContext(context, getSetStateCallExpression(setStateCall))) continue;
8294
+ if (isExemptSetStateCall(setStateCall)) continue;
8259
8295
  context.report({
8260
8296
  data: { name: getCallName(setStateCall) },
8261
8297
  messageId: "default",
@@ -8266,7 +8302,7 @@ function create$5(context) {
8266
8302
  for (const id of setupFnIds) {
8267
8303
  const setStateCalls = getSetStateCalls(context, id);
8268
8304
  for (const setStateCall of setStateCalls) {
8269
- if (isRefGatedContext(context, getSetStateCallExpression(setStateCall))) continue;
8305
+ if (isExemptSetStateCall(setStateCall)) continue;
8270
8306
  context.report({
8271
8307
  data: { name: getCallName(setStateCall) },
8272
8308
  messageId: "default",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "5.23.4",
3
+ "version": "5.23.5",
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,12 +36,12 @@
36
36
  "dist"
37
37
  ],
38
38
  "dependencies": {
39
- "@eslint-react/ast": "5.23.4",
40
- "@eslint-react/core": "5.23.4",
41
- "@eslint-react/eslint": "5.23.4",
42
- "@eslint-react/jsx": "5.23.4",
43
- "@eslint-react/shared": "5.23.4",
44
- "@eslint-react/var": "5.23.4",
39
+ "@eslint-react/ast": "5.23.5",
40
+ "@eslint-react/core": "5.23.5",
41
+ "@eslint-react/eslint": "5.23.5",
42
+ "@eslint-react/jsx": "5.23.5",
43
+ "@eslint-react/shared": "5.23.5",
44
+ "@eslint-react/var": "5.23.5",
45
45
  "@typescript-eslint/scope-manager": "^8.71.0",
46
46
  "@typescript-eslint/types": "^8.71.0",
47
47
  "@typescript-eslint/typescript-estree": "^8.71.0",