eslint-plugin-react-x 5.23.3 → 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 +66 -29
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -123,7 +123,8 @@ const rules$7 = {
|
|
|
123
123
|
"react-x/no-unused-props": "off",
|
|
124
124
|
"react-x/no-unused-state": "off",
|
|
125
125
|
"react-x/refs": "off",
|
|
126
|
-
"react-x/set-state-in-render": "off"
|
|
126
|
+
"react-x/set-state-in-render": "off",
|
|
127
|
+
"react-x/static-components": "off"
|
|
127
128
|
};
|
|
128
129
|
|
|
129
130
|
//#endregion
|
|
@@ -144,7 +145,7 @@ const rules$6 = {
|
|
|
144
145
|
//#endregion
|
|
145
146
|
//#region package.json
|
|
146
147
|
var name$6 = "eslint-plugin-react-x";
|
|
147
|
-
var version = "5.23.
|
|
148
|
+
var version = "5.23.5";
|
|
148
149
|
|
|
149
150
|
//#endregion
|
|
150
151
|
//#region src/utils/create-rule.ts
|
|
@@ -7979,15 +7980,29 @@ function isInitializedFromRef(context, name, initialScope, seen = /* @__PURE__ *
|
|
|
7979
7980
|
const { additionalRefHooks } = getSettingsFromContext(context);
|
|
7980
7981
|
if (seen.has(name)) return false;
|
|
7981
7982
|
seen.add(name);
|
|
7982
|
-
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;
|
|
7983
7989
|
if (node.type !== AST_NODE_TYPES.VariableDeclarator) continue;
|
|
7984
7990
|
const init = node.init == null ? null : Extract.unwrap(node.init);
|
|
7985
7991
|
if (init == null) continue;
|
|
7986
7992
|
switch (true) {
|
|
7987
7993
|
case init.type === AST_NODE_TYPES.MemberExpression: {
|
|
7988
|
-
let
|
|
7989
|
-
while (
|
|
7990
|
-
|
|
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));
|
|
7991
8006
|
}
|
|
7992
8007
|
case init.type === AST_NODE_TYPES.CallExpression && core.isUseRefLikeCall(init, additionalRefHooks): return true;
|
|
7993
8008
|
default: return getNestedIdentifiers(init).some((id) => isInitializedFromRef(context, id.name, context.sourceCode.getScope(id), seen));
|
|
@@ -7996,6 +8011,21 @@ function isInitializedFromRef(context, name, initialScope, seen = /* @__PURE__ *
|
|
|
7996
8011
|
return false;
|
|
7997
8012
|
}
|
|
7998
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
|
+
/**
|
|
7999
8029
|
* Check if a setState call is inside a conditional block whose test expression
|
|
8000
8030
|
* is derived from a ref value (e.g. `if (prevRef.current !== value) setState(...)`).
|
|
8001
8031
|
* @param context The ESLint rule context
|
|
@@ -8042,7 +8072,7 @@ function isRefInExpression(context, node) {
|
|
|
8042
8072
|
* @returns The actual CallExpression node
|
|
8043
8073
|
*/
|
|
8044
8074
|
function getSetStateCallExpression(node) {
|
|
8045
|
-
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;
|
|
8046
8076
|
}
|
|
8047
8077
|
|
|
8048
8078
|
//#endregion
|
|
@@ -8138,6 +8168,25 @@ function create$5(context) {
|
|
|
8138
8168
|
default: return false;
|
|
8139
8169
|
}
|
|
8140
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
|
+
}
|
|
8141
8190
|
return {
|
|
8142
8191
|
":function"(node) {
|
|
8143
8192
|
const kind = getFunctionKind(node);
|
|
@@ -8164,25 +8213,6 @@ function create$5(context) {
|
|
|
8164
8213
|
case entry.kind === "immediate" && Traverse.findParent(entry.node, Check.isFunction) === setupFunction: {
|
|
8165
8214
|
const args0 = node.arguments.at(0);
|
|
8166
8215
|
if (args0 == null) return;
|
|
8167
|
-
function isArgumentUsingRefValue(context, node) {
|
|
8168
|
-
const isUsingRefValue = (n) => {
|
|
8169
|
-
switch (n.type) {
|
|
8170
|
-
case AST_NODE_TYPES.Identifier: return isInitializedFromRef(context, n.name, context.sourceCode.getScope(n));
|
|
8171
|
-
case AST_NODE_TYPES.MemberExpression: return isUsingRefValue(n.object);
|
|
8172
|
-
case AST_NODE_TYPES.CallExpression: return isUsingRefValue(n.callee) || getNestedIdentifiers(n).some(isUsingRefValue);
|
|
8173
|
-
case AST_NODE_TYPES.BinaryExpression:
|
|
8174
|
-
case AST_NODE_TYPES.LogicalExpression: return isUsingRefValue(n.left) || isUsingRefValue(n.right);
|
|
8175
|
-
case AST_NODE_TYPES.UnaryExpression:
|
|
8176
|
-
case AST_NODE_TYPES.UpdateExpression: return isUsingRefValue(n.argument);
|
|
8177
|
-
case AST_NODE_TYPES.ConditionalExpression: return isUsingRefValue(n.consequent) || isUsingRefValue(n.alternate);
|
|
8178
|
-
case AST_NODE_TYPES.SequenceExpression: return n.expressions.some(isUsingRefValue);
|
|
8179
|
-
case AST_NODE_TYPES.AssignmentExpression: return isUsingRefValue(n.right);
|
|
8180
|
-
default: return false;
|
|
8181
|
-
}
|
|
8182
|
-
};
|
|
8183
|
-
if (isUsingRefValue(node)) return true;
|
|
8184
|
-
return Check.isFunction(node) && context.sourceCode.getScope(node.body).references.some((r) => isUsingRefValue(r.identifier));
|
|
8185
|
-
}
|
|
8186
8216
|
if (isArgumentUsingRefValue(context, args0)) return;
|
|
8187
8217
|
if (isRefGatedContext(context, node)) return;
|
|
8188
8218
|
context.report({
|
|
@@ -8229,6 +8259,13 @@ function create$5(context) {
|
|
|
8229
8259
|
}
|
|
8230
8260
|
},
|
|
8231
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
|
+
};
|
|
8232
8269
|
const getSetStateCalls = (context, id) => {
|
|
8233
8270
|
const variable = findVariable(context.sourceCode.getScope(id), id);
|
|
8234
8271
|
if (variable != null && variable.defs.some((def) => def.type === DefinitionType.Parameter)) return [];
|
|
@@ -8242,7 +8279,7 @@ function create$5(context) {
|
|
|
8242
8279
|
return [];
|
|
8243
8280
|
};
|
|
8244
8281
|
for (const [, calls] of setStateInEffectSetup) for (const call of calls) {
|
|
8245
|
-
if (
|
|
8282
|
+
if (isExemptSetStateCall(call)) continue;
|
|
8246
8283
|
context.report({
|
|
8247
8284
|
data: { name: call.name },
|
|
8248
8285
|
messageId: "default",
|
|
@@ -8254,7 +8291,7 @@ function create$5(context) {
|
|
|
8254
8291
|
if (!Check.isIdentifier(unwrappedCallee)) continue;
|
|
8255
8292
|
const setStateCalls = getSetStateCalls(context, unwrappedCallee);
|
|
8256
8293
|
for (const setStateCall of setStateCalls) {
|
|
8257
|
-
if (
|
|
8294
|
+
if (isExemptSetStateCall(setStateCall)) continue;
|
|
8258
8295
|
context.report({
|
|
8259
8296
|
data: { name: getCallName(setStateCall) },
|
|
8260
8297
|
messageId: "default",
|
|
@@ -8265,7 +8302,7 @@ function create$5(context) {
|
|
|
8265
8302
|
for (const id of setupFnIds) {
|
|
8266
8303
|
const setStateCalls = getSetStateCalls(context, id);
|
|
8267
8304
|
for (const setStateCall of setStateCalls) {
|
|
8268
|
-
if (
|
|
8305
|
+
if (isExemptSetStateCall(setStateCall)) continue;
|
|
8269
8306
|
context.report({
|
|
8270
8307
|
data: { name: getCallName(setStateCall) },
|
|
8271
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",
|