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.
- package/dist/index.js +64 -28
- 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.
|
|
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
|
|
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
|
|
7990
|
-
while (
|
|
7991
|
-
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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.
|
|
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.
|
|
40
|
-
"@eslint-react/core": "5.23.
|
|
41
|
-
"@eslint-react/eslint": "5.23.
|
|
42
|
-
"@eslint-react/jsx": "5.23.
|
|
43
|
-
"@eslint-react/shared": "5.23.
|
|
44
|
-
"@eslint-react/var": "5.23.
|
|
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",
|