eslint-plugin-react-x 5.21.1 → 5.21.2
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 +61 -20
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -144,7 +144,7 @@ const rules$6 = {
|
|
|
144
144
|
//#endregion
|
|
145
145
|
//#region package.json
|
|
146
146
|
var name$6 = "eslint-plugin-react-x";
|
|
147
|
-
var version = "5.21.
|
|
147
|
+
var version = "5.21.2";
|
|
148
148
|
|
|
149
149
|
//#endregion
|
|
150
150
|
//#region src/utils/create-rule.ts
|
|
@@ -1807,7 +1807,7 @@ function create$47(context) {
|
|
|
1807
1807
|
if (!context.sourceCode.text.includes("setState")) return {};
|
|
1808
1808
|
return { MemberExpression(node) {
|
|
1809
1809
|
if (!core.isAPI("this.state")(context, node)) return;
|
|
1810
|
-
const fact = Traverse.findParent(Traverse.findParent(node, (n) => Check.
|
|
1810
|
+
const fact = Traverse.findParent(Traverse.findParent(node, (n) => Check.isCallExpression(n) && core.isThisSetStateCall(n)), Check.isClass);
|
|
1811
1811
|
if (fact == null || !core.isClassComponent(fact)) return;
|
|
1812
1812
|
context.report({
|
|
1813
1813
|
messageId: "default",
|
|
@@ -2329,7 +2329,7 @@ var no_direct_mutation_state_default = createRule({
|
|
|
2329
2329
|
defaultOptions: []
|
|
2330
2330
|
});
|
|
2331
2331
|
function isConstructorFunction(node) {
|
|
2332
|
-
return Check.isOneOf([AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression])(node) && Check.isPropertyOrMethod(node.parent) && Check.isIdentifier(node.parent.key
|
|
2332
|
+
return Check.isOneOf([AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression])(node) && Check.isPropertyOrMethod(node.parent) && Check.isIdentifier(node.parent.key, "constructor");
|
|
2333
2333
|
}
|
|
2334
2334
|
function isAssignmentToThisState(node) {
|
|
2335
2335
|
const { left } = node;
|
|
@@ -2345,7 +2345,7 @@ function isAssignmentToThisState(node) {
|
|
|
2345
2345
|
function create$33(context) {
|
|
2346
2346
|
return { AssignmentExpression(node) {
|
|
2347
2347
|
if (!isAssignmentToThisState(node)) return;
|
|
2348
|
-
const fact = Traverse.findParent(node, Check.
|
|
2348
|
+
const fact = Traverse.findParent(node, Check.isClass);
|
|
2349
2349
|
if (fact == null) return;
|
|
2350
2350
|
if (core.isClassComponent(fact) && context.sourceCode.getScope(node).block !== Traverse.findParent(node, isConstructorFunction)) context.report({
|
|
2351
2351
|
messageId: "default",
|
|
@@ -2397,7 +2397,8 @@ function create$32(context) {
|
|
|
2397
2397
|
const call = Traverse.findParent(jsxElement, (n) => {
|
|
2398
2398
|
if (n.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
2399
2399
|
const callee = Extract.unwrap(n.callee);
|
|
2400
|
-
|
|
2400
|
+
if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;
|
|
2401
|
+
return Check.isIdentifier(callee.property, "map");
|
|
2401
2402
|
});
|
|
2402
2403
|
const iter = Traverse.findParent(jsxElement, Check.isFunction, (n) => n === call);
|
|
2403
2404
|
if (!Check.isFunction(iter)) return;
|
|
@@ -3242,7 +3243,7 @@ function create$27(context) {
|
|
|
3242
3243
|
*/
|
|
3243
3244
|
function visit(node, seen = /* @__PURE__ */ new Set()) {
|
|
3244
3245
|
if (node == null) return null;
|
|
3245
|
-
if (Check.
|
|
3246
|
+
if (Check.isJSXExpressionContainer(node)) return visit(node.expression, seen);
|
|
3246
3247
|
if (Check.isJSX(node)) return null;
|
|
3247
3248
|
if (Check.isTypeExpression(node)) return visit(node.expression, seen);
|
|
3248
3249
|
return match(node).with({
|
|
@@ -3560,8 +3561,8 @@ function create$23(context) {
|
|
|
3560
3561
|
if (node.source.value !== importSource) return;
|
|
3561
3562
|
for (const specifier of node.specifiers) {
|
|
3562
3563
|
if (specifier.type !== AST_NODE_TYPES.ImportSpecifier) continue;
|
|
3563
|
-
if (specifier.imported
|
|
3564
|
-
|
|
3564
|
+
if (!Check.isIdentifier(specifier.imported, "captureOwnerStack")) continue;
|
|
3565
|
+
context.report({
|
|
3565
3566
|
messageId: "useNamespaceImport",
|
|
3566
3567
|
node: specifier
|
|
3567
3568
|
});
|
|
@@ -3906,15 +3907,22 @@ function create$18(context) {
|
|
|
3906
3907
|
|
|
3907
3908
|
//#endregion
|
|
3908
3909
|
//#region src/rules/no-unnecessary-use-prefix/lib.ts
|
|
3909
|
-
const WELL_KNOWN_HOOKS = ["useMDXComponents"];
|
|
3910
|
+
const WELL_KNOWN_HOOKS = ["use", "useMDXComponents"];
|
|
3910
3911
|
function containsUseComments(context, node) {
|
|
3911
3912
|
return context.sourceCode.getCommentsInside(node).some(({ value }) => /use\([\s\S]*?\)/u.test(value) || /use[A-Z0-9]\w*\([\s\S]*?\)/u.test(value));
|
|
3912
3913
|
}
|
|
3913
|
-
function
|
|
3914
|
-
|
|
3914
|
+
function isTestMockCall(node) {
|
|
3915
|
+
if (node == null || node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
3916
|
+
const { callee } = node;
|
|
3917
|
+
if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;
|
|
3918
|
+
if (Check.isIdentifier(callee.object) && Check.isIdentifier(callee.property, "mock")) return true;
|
|
3919
|
+
return Check.isIdentifier(callee.object, "mock") && Check.isIdentifier(callee.property, "module");
|
|
3915
3920
|
}
|
|
3916
|
-
function
|
|
3917
|
-
return
|
|
3921
|
+
function isInTestMock(node) {
|
|
3922
|
+
return Traverse.findParent(node, (n) => {
|
|
3923
|
+
if (!isTestMockCall(n)) return false;
|
|
3924
|
+
return n.arguments.slice(1).some((arg) => arg.range[0] <= node.range[0] && node.range[1] <= arg.range[1]);
|
|
3925
|
+
}) != null;
|
|
3918
3926
|
}
|
|
3919
3927
|
|
|
3920
3928
|
//#endregion
|
|
@@ -3940,7 +3948,7 @@ function create$17(context) {
|
|
|
3940
3948
|
if (core.isFunctionEmpty(node)) continue;
|
|
3941
3949
|
if (WELL_KNOWN_HOOKS.includes(name)) continue;
|
|
3942
3950
|
if (containsUseComments(context, node)) continue;
|
|
3943
|
-
if (
|
|
3951
|
+
if (isInTestMock(node)) continue;
|
|
3944
3952
|
context.report({
|
|
3945
3953
|
data: { name },
|
|
3946
3954
|
messageId: "default",
|
|
@@ -4175,7 +4183,7 @@ function create$12(context, [options]) {
|
|
|
4175
4183
|
if (safePatterns.length > 0) {
|
|
4176
4184
|
const getName = (n) => Check.isIdentifier(n) ? n.name : null;
|
|
4177
4185
|
const name = match(right).with({ type: AST_NODE_TYPES.NewExpression }, (n) => getName(n.callee)).with({ type: AST_NODE_TYPES.CallExpression }, (n) => {
|
|
4178
|
-
return match(Extract.unwrap(n.callee)).when(Check.isIdentifier, ({ name }) => name).when(Check.
|
|
4186
|
+
return match(Extract.unwrap(n.callee)).when(Check.isIdentifier, ({ name }) => name).when(Check.isMemberExpression, ({ object }) => getName(object)).otherwise(() => null);
|
|
4179
4187
|
}).otherwise(() => null);
|
|
4180
4188
|
if (name != null && safePatterns.some((pattern) => pattern.test(name))) continue;
|
|
4181
4189
|
}
|
|
@@ -4214,6 +4222,14 @@ const LIFECYCLE_METHODS = /* @__PURE__ */ new Set([
|
|
|
4214
4222
|
"UNSAFE_componentWillReceiveProps",
|
|
4215
4223
|
"UNSAFE_componentWillUpdate"
|
|
4216
4224
|
]);
|
|
4225
|
+
const HOST_CONVENTION_METHODS = /* @__PURE__ */ new Set([
|
|
4226
|
+
"blur",
|
|
4227
|
+
"focus",
|
|
4228
|
+
"measure",
|
|
4229
|
+
"measureInWindow",
|
|
4230
|
+
"measureLayout",
|
|
4231
|
+
"setNativeProps"
|
|
4232
|
+
]);
|
|
4217
4233
|
|
|
4218
4234
|
//#endregion
|
|
4219
4235
|
//#region src/rules/no-unused-class-component-members/no-unused-class-component-members.ts
|
|
@@ -4244,6 +4260,7 @@ function create$11(context) {
|
|
|
4244
4260
|
if (LIFECYCLE_METHODS.has(methodName)) {
|
|
4245
4261
|
if (methodName === "shouldComponentUpdate" && core.isPureComponent(node)) {} else continue;
|
|
4246
4262
|
}
|
|
4263
|
+
if (HOST_CONVENTION_METHODS.has(methodName)) continue;
|
|
4247
4264
|
context.report({
|
|
4248
4265
|
data: {
|
|
4249
4266
|
className: id != null ? context.sourceCode.getText(id) : "Component",
|
|
@@ -4888,6 +4905,23 @@ function isCatalogObject(name) {
|
|
|
4888
4905
|
return IMPURE_FUNCS.has(name) || PURE_FUNCS.has(name);
|
|
4889
4906
|
}
|
|
4890
4907
|
/**
|
|
4908
|
+
* Check if the program has a top-level `use client` directive, marking the
|
|
4909
|
+
* module as a client module in React Server Components conventions.
|
|
4910
|
+
*/
|
|
4911
|
+
function hasUseClientDirective(program) {
|
|
4912
|
+
return program.body.some((stmt) => stmt.type === AST_NODE_TYPES.ExpressionStatement && stmt.directive === "use client");
|
|
4913
|
+
}
|
|
4914
|
+
/**
|
|
4915
|
+
* Check if the node is an argument of a `useRef`-like call, e.g.
|
|
4916
|
+
* `useRef(document.createElement("div"))`. The initializer is evaluated on
|
|
4917
|
+
* every render but stored only on the first one, which is a widely used idiom
|
|
4918
|
+
* (ex: portals), so impure calls in this position are exempted.
|
|
4919
|
+
*/
|
|
4920
|
+
function isUseRefInitializerArgument(node) {
|
|
4921
|
+
const { parent } = node;
|
|
4922
|
+
return parent.type === AST_NODE_TYPES.CallExpression && parent.arguments.some((arg) => arg === node) && core.isUseRefLikeCall(parent);
|
|
4923
|
+
}
|
|
4924
|
+
/**
|
|
4891
4925
|
* Find the property key under which `name` is bound in an object destructuring
|
|
4892
4926
|
* pattern, e.g. `"random"` for `random` in `const { random } = Math` or for
|
|
4893
4927
|
* `r` in `const { random: r } = Math`.
|
|
@@ -5000,6 +5034,7 @@ function create$7(context) {
|
|
|
5000
5034
|
const resolved = resolveBuiltinObjectName(context, expr);
|
|
5001
5035
|
if (resolved == null) return;
|
|
5002
5036
|
if (!(resolved.property != null ? IMPURE_FUNCS.get(resolved.object)?.has(resolved.property) ?? false : IMPURE_FUNCS.get("globalThis")?.has(resolved.object) ?? false)) return;
|
|
5037
|
+
if (isUseRefInitializerArgument(node)) return;
|
|
5003
5038
|
const func = Traverse.findParent(node, Check.isFunction);
|
|
5004
5039
|
if (func == null) return;
|
|
5005
5040
|
cEntries.push({
|
|
@@ -5012,6 +5047,7 @@ function create$7(context) {
|
|
|
5012
5047
|
const resolved = resolveBuiltinMember(context, expr);
|
|
5013
5048
|
if (resolved == null || resolved.property == null) return;
|
|
5014
5049
|
if (!IMPURE_FUNCS.get(resolved.object)?.has(resolved.property)) return;
|
|
5050
|
+
if (isUseRefInitializerArgument(node)) return;
|
|
5015
5051
|
const func = Traverse.findParent(node, Check.isFunction);
|
|
5016
5052
|
if (func == null) return;
|
|
5017
5053
|
cEntries.push({
|
|
@@ -5030,6 +5066,7 @@ function create$7(context) {
|
|
|
5030
5066
|
const ctorName = resolved.property != null && isCatalogObject(resolved.object) ? resolved.property : resolved.object;
|
|
5031
5067
|
if (!IMPURE_CTORS.has(ctorName)) return;
|
|
5032
5068
|
if (ctorName === "Date" && node.arguments.length > 0) return;
|
|
5069
|
+
if (isUseRefInitializerArgument(node)) return;
|
|
5033
5070
|
const func = Traverse.findParent(node, Check.isFunction);
|
|
5034
5071
|
if (func == null) return;
|
|
5035
5072
|
nEntries.push({
|
|
@@ -5041,8 +5078,10 @@ function create$7(context) {
|
|
|
5041
5078
|
const comps = fc.api.getAllComponents(node);
|
|
5042
5079
|
const hooks = hc.api.getAllHooks(node);
|
|
5043
5080
|
const funcs = [...comps, ...hooks];
|
|
5081
|
+
const isClientModule = hasUseClientDirective(node);
|
|
5044
5082
|
for (const { func, node } of [...cEntries, ...nEntries]) {
|
|
5045
5083
|
if (!funcs.some((f) => f.node === func)) continue;
|
|
5084
|
+
if (!isClientModule && func.async && comps.some((comp) => comp.node === func)) continue;
|
|
5046
5085
|
context.report({
|
|
5047
5086
|
data: { name: context.sourceCode.getText(node) },
|
|
5048
5087
|
messageId: "default",
|
|
@@ -5347,9 +5386,7 @@ function createFactCollector() {
|
|
|
5347
5386
|
//#region src/rules/refs/effects.ts
|
|
5348
5387
|
/** The nearest strict ancestor of `node` that is a component or hook. */
|
|
5349
5388
|
function findBoundary(node, boundaries) {
|
|
5350
|
-
return Traverse.findParent(node, (candidate) =>
|
|
5351
|
-
return Check.isFunction(candidate) && boundaries.has(candidate);
|
|
5352
|
-
});
|
|
5389
|
+
return Traverse.findParent(node, (candidate) => Check.isFunction(candidate) && boundaries.has(candidate));
|
|
5353
5390
|
}
|
|
5354
5391
|
/** The boundary containing `node`, where `node` is the nearest enclosing function of the fact. */
|
|
5355
5392
|
function getBoundaryOf(node, boundaries) {
|
|
@@ -7941,10 +7978,14 @@ function isInitializedFromRef(context, name, initialScope, seen = /* @__PURE__ *
|
|
|
7941
7978
|
seen.add(name);
|
|
7942
7979
|
for (const { node } of findVariable(initialScope, name)?.defs ?? []) {
|
|
7943
7980
|
if (node.type !== AST_NODE_TYPES.VariableDeclarator) continue;
|
|
7944
|
-
const init = node.init;
|
|
7981
|
+
const init = node.init == null ? null : Extract.unwrap(node.init);
|
|
7945
7982
|
if (init == null) continue;
|
|
7946
7983
|
switch (true) {
|
|
7947
|
-
case init.type === AST_NODE_TYPES.MemberExpression
|
|
7984
|
+
case init.type === AST_NODE_TYPES.MemberExpression: {
|
|
7985
|
+
let object = Extract.unwrap(init.object);
|
|
7986
|
+
while (object.type === AST_NODE_TYPES.MemberExpression) object = Extract.unwrap(object.object);
|
|
7987
|
+
return Check.isIdentifier(object) && (object.name === "ref" || object.name.endsWith("Ref"));
|
|
7988
|
+
}
|
|
7948
7989
|
case init.type === AST_NODE_TYPES.CallExpression && core.isUseRefLikeCall(init, additionalRefHooks): return true;
|
|
7949
7990
|
case init.type === AST_NODE_TYPES.CallExpression: return getNestedIdentifiers(init).some((id) => isInitializedFromRef(context, id.name, context.sourceCode.getScope(id), seen));
|
|
7950
7991
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-x",
|
|
3
|
-
"version": "5.21.
|
|
3
|
+
"version": "5.21.2",
|
|
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.21.
|
|
40
|
-
"@eslint-react/core": "5.21.
|
|
41
|
-
"@eslint-react/eslint": "5.21.
|
|
42
|
-
"@eslint-react/jsx": "5.21.
|
|
43
|
-
"@eslint-react/shared": "5.21.
|
|
44
|
-
"@eslint-react/var": "5.21.
|
|
39
|
+
"@eslint-react/ast": "5.21.2",
|
|
40
|
+
"@eslint-react/core": "5.21.2",
|
|
41
|
+
"@eslint-react/eslint": "5.21.2",
|
|
42
|
+
"@eslint-react/jsx": "5.21.2",
|
|
43
|
+
"@eslint-react/shared": "5.21.2",
|
|
44
|
+
"@eslint-react/var": "5.21.2",
|
|
45
45
|
"@typescript-eslint/scope-manager": "^8.70.1",
|
|
46
46
|
"@typescript-eslint/types": "^8.70.1",
|
|
47
47
|
"@typescript-eslint/typescript-estree": "^8.70.1",
|