eslint-plugin-react-x 5.2.0-next.0 → 5.2.1-beta.3
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 +264 -26
- package/package.json +9 -8
package/dist/index.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { DEFAULT_ESLINT_REACT_SETTINGS, getSettingsFromContext, toRegExp } from "@eslint-react/shared";
|
|
2
2
|
import * as ast from "@eslint-react/ast";
|
|
3
|
+
import { findParent, is, isFunction } from "@eslint-react/ast";
|
|
3
4
|
import * as core from "@eslint-react/core";
|
|
4
5
|
import { isUseRefCall } from "@eslint-react/core";
|
|
5
6
|
import { merge } from "@eslint-react/eslint";
|
|
6
7
|
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
7
8
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
8
9
|
import { JsxDetectionHint, findParentAttribute, getElementFullType, hasAttribute, isJsxLike } from "@eslint-react/jsx";
|
|
9
|
-
import { computeObjectType,
|
|
10
|
+
import { computeObjectType, isAssignmentTargetEqual, resolve, resolveEnclosingAssignmentTarget } from "@eslint-react/var";
|
|
10
11
|
import { DefinitionType } from "@typescript-eslint/scope-manager";
|
|
11
12
|
import { findVariable, getStaticValue } from "@typescript-eslint/utils/ast-utils";
|
|
12
13
|
import { P, isMatching, match } from "ts-pattern";
|
|
13
14
|
import { compare } from "compare-versions";
|
|
14
15
|
import { getConstrainedTypeAtLocation } from "@typescript-eslint/type-utils";
|
|
15
16
|
import { unionConstituents } from "ts-api-utils";
|
|
17
|
+
import { simpleTraverse } from "@typescript-eslint/typescript-estree";
|
|
16
18
|
import { snakeCase } from "string-ts";
|
|
17
19
|
|
|
18
20
|
//#region \0rolldown/runtime.js
|
|
@@ -142,7 +144,7 @@ const rules$7 = {
|
|
|
142
144
|
//#endregion
|
|
143
145
|
//#region package.json
|
|
144
146
|
var name$6 = "eslint-plugin-react-x";
|
|
145
|
-
var version = "5.2.
|
|
147
|
+
var version = "5.2.1-beta.3";
|
|
146
148
|
|
|
147
149
|
//#endregion
|
|
148
150
|
//#region src/rules/component-hook-factories/lib.ts
|
|
@@ -182,6 +184,12 @@ function isHigherOrderComponent(fn) {
|
|
|
182
184
|
return false;
|
|
183
185
|
});
|
|
184
186
|
}
|
|
187
|
+
function isTestMock$1(node) {
|
|
188
|
+
return node != null && node.type === AST_NODE_TYPES.MemberExpression && node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === "mock";
|
|
189
|
+
}
|
|
190
|
+
function isTestMockCallback$1(node) {
|
|
191
|
+
return node != null && ast.isFunction(node) && node.parent.type === AST_NODE_TYPES.CallExpression && isTestMock$1(node.parent.callee) && node.parent.arguments[1] === node;
|
|
192
|
+
}
|
|
185
193
|
|
|
186
194
|
//#endregion
|
|
187
195
|
//#region src/utils/create-rule.ts
|
|
@@ -221,7 +229,7 @@ function create$48(context) {
|
|
|
221
229
|
if (name == null) continue;
|
|
222
230
|
const parentFn = ast.findParent(node, ast.isFunction);
|
|
223
231
|
if (parentFn == null) continue;
|
|
224
|
-
if (ast.findParent(node,
|
|
232
|
+
if (ast.findParent(node, isTestMockCallback$1) != null) continue;
|
|
225
233
|
if (isHigherOrderComponent(parentFn)) continue;
|
|
226
234
|
if (reported.has(node)) continue;
|
|
227
235
|
context.report({
|
|
@@ -234,7 +242,7 @@ function create$48(context) {
|
|
|
234
242
|
for (const { name = "unknown", node } of cComponents) {
|
|
235
243
|
const parentFn = ast.findParent(node, ast.isFunction);
|
|
236
244
|
if (parentFn == null) continue;
|
|
237
|
-
if (ast.findParent(node,
|
|
245
|
+
if (ast.findParent(node, isTestMockCallback$1) != null) continue;
|
|
238
246
|
if (isHigherOrderComponent(parentFn)) continue;
|
|
239
247
|
context.report({
|
|
240
248
|
data: { name },
|
|
@@ -244,7 +252,7 @@ function create$48(context) {
|
|
|
244
252
|
}
|
|
245
253
|
for (const { name, node } of hooks) {
|
|
246
254
|
if (ast.findParent(node, ast.isFunction) == null) continue;
|
|
247
|
-
if (ast.findParent(node,
|
|
255
|
+
if (ast.findParent(node, isTestMockCallback$1) != null) continue;
|
|
248
256
|
if (reported.has(node)) continue;
|
|
249
257
|
context.report({
|
|
250
258
|
data: { name },
|
|
@@ -2234,7 +2242,7 @@ function create$29(context) {
|
|
|
2234
2242
|
if (compare(version, "19.0.0", "<")) return {};
|
|
2235
2243
|
return merge({ CallExpression(node) {
|
|
2236
2244
|
if (!core.isForwardRefCall(context, node)) return;
|
|
2237
|
-
const id =
|
|
2245
|
+
const id = core.getFunctionId(node);
|
|
2238
2246
|
const suggest = canFix(context, node) ? [{
|
|
2239
2247
|
fix: getFix(context, node),
|
|
2240
2248
|
messageId: "replace"
|
|
@@ -2546,7 +2554,7 @@ function create$24(context) {
|
|
|
2546
2554
|
});
|
|
2547
2555
|
return merge(visitor, { "Program:exit"(program) {
|
|
2548
2556
|
for (const { displayName, flag, node } of api.getAllComponents(program)) {
|
|
2549
|
-
const id =
|
|
2557
|
+
const id = core.getFunctionId(node);
|
|
2550
2558
|
const isMemoOrForwardRef = (flag & (core.FunctionComponentFlag.ForwardRef | core.FunctionComponentFlag.Memo)) > 0n;
|
|
2551
2559
|
if (id != null) continue;
|
|
2552
2560
|
if (!isMemoOrForwardRef) continue;
|
|
@@ -2587,7 +2595,7 @@ function create$23(context) {
|
|
|
2587
2595
|
},
|
|
2588
2596
|
"Program:exit"() {
|
|
2589
2597
|
for (const call of createCalls) {
|
|
2590
|
-
const id =
|
|
2598
|
+
const id = resolveEnclosingAssignmentTarget(call);
|
|
2591
2599
|
if (id == null) {
|
|
2592
2600
|
context.report({
|
|
2593
2601
|
messageId: "default",
|
|
@@ -2636,6 +2644,21 @@ function report(context) {
|
|
|
2636
2644
|
return context.report(descriptor);
|
|
2637
2645
|
};
|
|
2638
2646
|
}
|
|
2647
|
+
/**
|
|
2648
|
+
* Gets the nested return statements in the node that are within the same function
|
|
2649
|
+
* @param node The AST node
|
|
2650
|
+
* @returns The nested return statements in the node
|
|
2651
|
+
*/
|
|
2652
|
+
function getNestedReturnStatements(node) {
|
|
2653
|
+
const statements = [];
|
|
2654
|
+
const boundaryNode = isFunction(node) ? node : findParent(node, isFunction);
|
|
2655
|
+
simpleTraverse(node, { enter(node) {
|
|
2656
|
+
if (node.type !== AST_NODE_TYPES.ReturnStatement) return;
|
|
2657
|
+
if (findParent(node, isFunction) !== boundaryNode) return;
|
|
2658
|
+
statements.push(node);
|
|
2659
|
+
} });
|
|
2660
|
+
return statements;
|
|
2661
|
+
}
|
|
2639
2662
|
|
|
2640
2663
|
//#endregion
|
|
2641
2664
|
//#region src/rules/no-missing-key/no-missing-key.ts
|
|
@@ -2678,7 +2701,7 @@ function create$22(context) {
|
|
|
2678
2701
|
}
|
|
2679
2702
|
function checkBlock(node) {
|
|
2680
2703
|
const descriptors = [];
|
|
2681
|
-
for (const stmt of
|
|
2704
|
+
for (const stmt of getNestedReturnStatements(node)) {
|
|
2682
2705
|
if (stmt.argument == null) continue;
|
|
2683
2706
|
const desc = check(stmt.argument);
|
|
2684
2707
|
if (desc == null) continue;
|
|
@@ -2722,6 +2745,32 @@ function create$22(context) {
|
|
|
2722
2745
|
});
|
|
2723
2746
|
}
|
|
2724
2747
|
|
|
2748
|
+
//#endregion
|
|
2749
|
+
//#region src/rules/no-misused-capture-owner-stack/lib.ts
|
|
2750
|
+
/**
|
|
2751
|
+
* Check if the given node is a member expression that accesses `process.env.NODE_ENV`
|
|
2752
|
+
* @param node The AST node
|
|
2753
|
+
* @returns True if the node is a member expression that accesses `process.env.NODE_ENV`, false otherwise
|
|
2754
|
+
*/
|
|
2755
|
+
function isProcessEnvNodeEnv(node) {
|
|
2756
|
+
return node != null && node.type === AST_NODE_TYPES.MemberExpression && node.object.type === AST_NODE_TYPES.MemberExpression && node.object.object.type === AST_NODE_TYPES.Identifier && node.object.object.name === "process" && node.object.property.type === AST_NODE_TYPES.Identifier && node.object.property.name === "env" && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === "NODE_ENV";
|
|
2757
|
+
}
|
|
2758
|
+
/**
|
|
2759
|
+
* Check if the given node is a binary expression that compares `process.env.NODE_ENV` with a string literal.
|
|
2760
|
+
* @param node The AST node
|
|
2761
|
+
* @param operator The operator used in the comparison
|
|
2762
|
+
* @param value The string literal value to compare against
|
|
2763
|
+
* @returns True if the node is a binary expression that compares `process.env.NODE_ENV` with the specified value, false otherwise
|
|
2764
|
+
*/
|
|
2765
|
+
function isProcessEnvNodeEnvCompare(node, operator, value) {
|
|
2766
|
+
if (node == null) return false;
|
|
2767
|
+
if (node.type !== AST_NODE_TYPES.BinaryExpression) return false;
|
|
2768
|
+
if (node.operator !== operator) return false;
|
|
2769
|
+
if (isProcessEnvNodeEnv(node.left) && ast.isLiteral(node.right, "string")) return node.right.value === value;
|
|
2770
|
+
if (ast.isLiteral(node.left, "string") && isProcessEnvNodeEnv(node.right)) return node.left.value === value;
|
|
2771
|
+
return false;
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2725
2774
|
//#endregion
|
|
2726
2775
|
//#region src/rules/no-misused-capture-owner-stack/no-misused-capture-owner-stack.ts
|
|
2727
2776
|
const RULE_NAME$21 = "no-misused-capture-owner-stack";
|
|
@@ -2765,7 +2814,7 @@ function create$21(context) {
|
|
|
2765
2814
|
}
|
|
2766
2815
|
function isDevelopmentOnlyCheck(node) {
|
|
2767
2816
|
if (node.type !== AST_NODE_TYPES.IfStatement) return false;
|
|
2768
|
-
return
|
|
2817
|
+
return isProcessEnvNodeEnvCompare(node.test, "!==", "production");
|
|
2769
2818
|
}
|
|
2770
2819
|
|
|
2771
2820
|
//#endregion
|
|
@@ -3013,12 +3062,21 @@ function create$16(context) {
|
|
|
3013
3062
|
}
|
|
3014
3063
|
|
|
3015
3064
|
//#endregion
|
|
3016
|
-
//#region src/rules/no-unnecessary-use-prefix/
|
|
3017
|
-
const RULE_NAME$15 = "no-unnecessary-use-prefix";
|
|
3065
|
+
//#region src/rules/no-unnecessary-use-prefix/lib.ts
|
|
3018
3066
|
const WELL_KNOWN_HOOKS = ["useMDXComponents"];
|
|
3019
3067
|
function containsUseComments(context, node) {
|
|
3020
3068
|
return context.sourceCode.getCommentsInside(node).some(({ value }) => /use\([\s\S]*?\)/u.test(value) || /use[A-Z0-9]\w*\([\s\S]*?\)/u.test(value));
|
|
3021
3069
|
}
|
|
3070
|
+
function isTestMock(node) {
|
|
3071
|
+
return node != null && node.type === AST_NODE_TYPES.MemberExpression && node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === "mock";
|
|
3072
|
+
}
|
|
3073
|
+
function isTestMockCallback(node) {
|
|
3074
|
+
return node != null && ast.isFunction(node) && node.parent.type === AST_NODE_TYPES.CallExpression && isTestMock(node.parent.callee) && node.parent.arguments[1] === node;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
//#endregion
|
|
3078
|
+
//#region src/rules/no-unnecessary-use-prefix/no-unnecessary-use-prefix.ts
|
|
3079
|
+
const RULE_NAME$15 = "no-unnecessary-use-prefix";
|
|
3022
3080
|
var no_unnecessary_use_prefix_default = createRule({
|
|
3023
3081
|
meta: {
|
|
3024
3082
|
type: "problem",
|
|
@@ -3036,10 +3094,10 @@ function create$15(context) {
|
|
|
3036
3094
|
for (const { id, name, hookCalls, node } of api.getAllHooks(program)) {
|
|
3037
3095
|
if (name == null) continue;
|
|
3038
3096
|
if (hookCalls.length > 0) continue;
|
|
3039
|
-
if (
|
|
3097
|
+
if (core.isFunctionEmpty(node)) continue;
|
|
3040
3098
|
if (WELL_KNOWN_HOOKS.includes(name)) continue;
|
|
3041
3099
|
if (containsUseComments(context, node)) continue;
|
|
3042
|
-
if (ast.findParent(node,
|
|
3100
|
+
if (ast.findParent(node, isTestMockCallback) != null) continue;
|
|
3043
3101
|
context.report({
|
|
3044
3102
|
data: { name },
|
|
3045
3103
|
messageId: "default",
|
|
@@ -3150,7 +3208,7 @@ var no_unstable_context_value_default = createRule({
|
|
|
3150
3208
|
function create$11(context) {
|
|
3151
3209
|
const { compilationMode, version } = getSettingsFromContext(context);
|
|
3152
3210
|
if (compilationMode === "infer" || compilationMode === "all") return {};
|
|
3153
|
-
if (compilationMode === "annotation" && ast.
|
|
3211
|
+
if (compilationMode === "annotation" && ast.isFileHasDirective(context.sourceCode.ast, "use memo")) return {};
|
|
3154
3212
|
const isReact18OrBelow = compare(version, "19.0.0", "<");
|
|
3155
3213
|
const { api, visitor } = core.getFunctionComponentCollector(context);
|
|
3156
3214
|
const constructions = /* @__PURE__ */ new WeakMap();
|
|
@@ -3161,7 +3219,7 @@ function create$11(context) {
|
|
|
3161
3219
|
if (!isContextName(selfName, isReact18OrBelow)) return;
|
|
3162
3220
|
const enclosingFunction = ast.findParent(node, ast.isFunction);
|
|
3163
3221
|
if (enclosingFunction == null) return;
|
|
3164
|
-
if (compilationMode === "annotation" &&
|
|
3222
|
+
if (compilationMode === "annotation" && core.isFunctionHasDirective(enclosingFunction, "use memo")) return;
|
|
3165
3223
|
const attribute = node.attributes.find((attribute) => attribute.type === AST_NODE_TYPES.JSXAttribute && attribute.name.name === "value");
|
|
3166
3224
|
if (attribute == null || !("value" in attribute)) return;
|
|
3167
3225
|
const value = attribute.value;
|
|
@@ -3231,7 +3289,7 @@ function extractIdentifier(node) {
|
|
|
3231
3289
|
function create$10(context, [options]) {
|
|
3232
3290
|
const { compilationMode } = getSettingsFromContext(context);
|
|
3233
3291
|
if (compilationMode === "infer" || compilationMode === "all") return {};
|
|
3234
|
-
if (compilationMode === "annotation" && ast.
|
|
3292
|
+
if (compilationMode === "annotation" && ast.isFileHasDirective(context.sourceCode.ast, "use memo")) return {};
|
|
3235
3293
|
const { api, visitor } = core.getFunctionComponentCollector(context);
|
|
3236
3294
|
const declarators = /* @__PURE__ */ new WeakMap();
|
|
3237
3295
|
const { safeDefaultProps = [] } = options;
|
|
@@ -3323,7 +3381,7 @@ function create$9(context) {
|
|
|
3323
3381
|
function classExit() {
|
|
3324
3382
|
const currentClass = classStack.pop();
|
|
3325
3383
|
if (currentClass == null || !core.isClassComponent(currentClass)) return;
|
|
3326
|
-
const id =
|
|
3384
|
+
const id = core.getClassId(currentClass);
|
|
3327
3385
|
const defs = propertyDefs.get(currentClass);
|
|
3328
3386
|
const usages = propertyUsages.get(currentClass);
|
|
3329
3387
|
if (defs == null) return;
|
|
@@ -6198,6 +6256,91 @@ function last(array) {
|
|
|
6198
6256
|
return array[array.length - 1];
|
|
6199
6257
|
}
|
|
6200
6258
|
|
|
6259
|
+
//#endregion
|
|
6260
|
+
//#region src/rules/set-state-in-effect/lib.ts
|
|
6261
|
+
/**
|
|
6262
|
+
* Get all nested identifiers in a expression like node
|
|
6263
|
+
* @param node The node to get the nested identifiers from
|
|
6264
|
+
* @returns All nested identifiers
|
|
6265
|
+
*/
|
|
6266
|
+
function getNestedIdentifiers(node) {
|
|
6267
|
+
const identifiers = [];
|
|
6268
|
+
if (node.type === AST_NODE_TYPES.Identifier) identifiers.push(node);
|
|
6269
|
+
if ("arguments" in node) {
|
|
6270
|
+
const chunk = node.arguments.flatMap(getNestedIdentifiers);
|
|
6271
|
+
identifiers.push(...chunk);
|
|
6272
|
+
}
|
|
6273
|
+
if ("elements" in node) {
|
|
6274
|
+
const chunk = node.elements.filter((x) => x != null).flatMap(getNestedIdentifiers);
|
|
6275
|
+
identifiers.push(...chunk);
|
|
6276
|
+
}
|
|
6277
|
+
if ("properties" in node) {
|
|
6278
|
+
const chunk = node.properties.flatMap(getNestedIdentifiers);
|
|
6279
|
+
identifiers.push(...chunk);
|
|
6280
|
+
}
|
|
6281
|
+
if ("expressions" in node) {
|
|
6282
|
+
const chunk = node.expressions.flatMap(getNestedIdentifiers);
|
|
6283
|
+
identifiers.push(...chunk);
|
|
6284
|
+
}
|
|
6285
|
+
if ("left" in node) {
|
|
6286
|
+
const chunk = getNestedIdentifiers(node.left);
|
|
6287
|
+
identifiers.push(...chunk);
|
|
6288
|
+
}
|
|
6289
|
+
if ("right" in node) {
|
|
6290
|
+
const chunk = getNestedIdentifiers(node.right);
|
|
6291
|
+
identifiers.push(...chunk);
|
|
6292
|
+
}
|
|
6293
|
+
if (node.type === AST_NODE_TYPES.Property) {
|
|
6294
|
+
const chunk = getNestedIdentifiers(node.value);
|
|
6295
|
+
identifiers.push(...chunk);
|
|
6296
|
+
}
|
|
6297
|
+
if (node.type === AST_NODE_TYPES.SpreadElement) {
|
|
6298
|
+
const chunk = getNestedIdentifiers(node.argument);
|
|
6299
|
+
identifiers.push(...chunk);
|
|
6300
|
+
}
|
|
6301
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
6302
|
+
identifiers.push(...getNestedIdentifiers(node.object));
|
|
6303
|
+
if (node.computed) identifiers.push(...getNestedIdentifiers(node.property));
|
|
6304
|
+
}
|
|
6305
|
+
if (node.type === AST_NODE_TYPES.UnaryExpression) {
|
|
6306
|
+
const chunk = getNestedIdentifiers(node.argument);
|
|
6307
|
+
identifiers.push(...chunk);
|
|
6308
|
+
}
|
|
6309
|
+
if (node.type === AST_NODE_TYPES.ChainExpression) {
|
|
6310
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
6311
|
+
identifiers.push(...chunk);
|
|
6312
|
+
}
|
|
6313
|
+
if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
|
|
6314
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
6315
|
+
identifiers.push(...chunk);
|
|
6316
|
+
}
|
|
6317
|
+
if (node.type === AST_NODE_TYPES.TSAsExpression) {
|
|
6318
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
6319
|
+
identifiers.push(...chunk);
|
|
6320
|
+
}
|
|
6321
|
+
if (node.type === AST_NODE_TYPES.TSSatisfiesExpression) {
|
|
6322
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
6323
|
+
identifiers.push(...chunk);
|
|
6324
|
+
}
|
|
6325
|
+
if (node.type === AST_NODE_TYPES.ConditionalExpression) {
|
|
6326
|
+
identifiers.push(...getNestedIdentifiers(node.test));
|
|
6327
|
+
identifiers.push(...getNestedIdentifiers(node.consequent));
|
|
6328
|
+
identifiers.push(...getNestedIdentifiers(node.alternate));
|
|
6329
|
+
}
|
|
6330
|
+
if (node.type === AST_NODE_TYPES.AwaitExpression) identifiers.push(...getNestedIdentifiers(node.argument));
|
|
6331
|
+
if (node.type === AST_NODE_TYPES.YieldExpression && node.argument != null) identifiers.push(...getNestedIdentifiers(node.argument));
|
|
6332
|
+
if (node.type === AST_NODE_TYPES.UpdateExpression) identifiers.push(...getNestedIdentifiers(node.argument));
|
|
6333
|
+
if (node.type === AST_NODE_TYPES.CallExpression || node.type === AST_NODE_TYPES.NewExpression) identifiers.push(...getNestedIdentifiers(node.callee));
|
|
6334
|
+
if (node.type === AST_NODE_TYPES.TaggedTemplateExpression) {
|
|
6335
|
+
identifiers.push(...getNestedIdentifiers(node.tag));
|
|
6336
|
+
identifiers.push(...getNestedIdentifiers(node.quasi));
|
|
6337
|
+
}
|
|
6338
|
+
if (node.type === AST_NODE_TYPES.ImportExpression) identifiers.push(...getNestedIdentifiers(node.source));
|
|
6339
|
+
if (node.type === AST_NODE_TYPES.TSTypeAssertion) identifiers.push(...getNestedIdentifiers(node.expression));
|
|
6340
|
+
if (node.type === AST_NODE_TYPES.TSInstantiationExpression) identifiers.push(...getNestedIdentifiers(node.expression));
|
|
6341
|
+
return identifiers;
|
|
6342
|
+
}
|
|
6343
|
+
|
|
6201
6344
|
//#endregion
|
|
6202
6345
|
//#region src/rules/set-state-in-effect/set-state-in-effect.ts
|
|
6203
6346
|
const RULE_NAME$4 = "set-state-in-effect";
|
|
@@ -6306,7 +6449,7 @@ function create$4(context) {
|
|
|
6306
6449
|
if (init == null) continue;
|
|
6307
6450
|
switch (true) {
|
|
6308
6451
|
case init.type === AST_NODE_TYPES.MemberExpression && init.object.type === AST_NODE_TYPES.Identifier && (init.object.name === "ref" || init.object.name.endsWith("Ref")): return true;
|
|
6309
|
-
case init.type === AST_NODE_TYPES.CallExpression && isUseRefCall(context, init): return true;
|
|
6452
|
+
case init.type === AST_NODE_TYPES.CallExpression && core.isUseRefCall(context, init): return true;
|
|
6310
6453
|
}
|
|
6311
6454
|
}
|
|
6312
6455
|
return false;
|
|
@@ -6342,7 +6485,7 @@ function create$4(context) {
|
|
|
6342
6485
|
switch (n.type) {
|
|
6343
6486
|
case AST_NODE_TYPES.Identifier: return isInitializedFromRef(n.name, context.sourceCode.getScope(n));
|
|
6344
6487
|
case AST_NODE_TYPES.MemberExpression: return isUsingRefValue(n.object);
|
|
6345
|
-
case AST_NODE_TYPES.CallExpression: return isUsingRefValue(n.callee) ||
|
|
6488
|
+
case AST_NODE_TYPES.CallExpression: return isUsingRefValue(n.callee) || getNestedIdentifiers(n).some(isUsingRefValue);
|
|
6346
6489
|
default: return false;
|
|
6347
6490
|
}
|
|
6348
6491
|
};
|
|
@@ -6365,7 +6508,7 @@ function create$4(context) {
|
|
|
6365
6508
|
}
|
|
6366
6509
|
}).with("useEffect", () => {
|
|
6367
6510
|
if (ast.isFunction(node.arguments.at(0))) return;
|
|
6368
|
-
setupFnIds.push(...
|
|
6511
|
+
setupFnIds.push(...getNestedIdentifiers(node));
|
|
6369
6512
|
}).with("other", () => {
|
|
6370
6513
|
if (entry.node !== setupFunction) return;
|
|
6371
6514
|
trackedFnCalls.push(node);
|
|
@@ -6505,7 +6648,7 @@ function create$3(context) {
|
|
|
6505
6648
|
return false;
|
|
6506
6649
|
}
|
|
6507
6650
|
function isComponentOrHookLikeFunction(node) {
|
|
6508
|
-
const id =
|
|
6651
|
+
const id = core.getFunctionId(node);
|
|
6509
6652
|
if (id == null) return false;
|
|
6510
6653
|
if (id.type === AST_NODE_TYPES.Identifier) return core.isFunctionComponentName(id.name) || core.isHookName(id.name);
|
|
6511
6654
|
if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) return core.isFunctionComponentName(id.property.name) || core.isHookName(id.property.name);
|
|
@@ -6683,7 +6826,7 @@ function create$1(context) {
|
|
|
6683
6826
|
if (!ast.isFunction(callbackArg)) return;
|
|
6684
6827
|
if (callbackArg.type === AST_NODE_TYPES.ArrowFunctionExpression && callbackArg.body.type !== AST_NODE_TYPES.BlockStatement) return;
|
|
6685
6828
|
if (callbackArg.body.type !== AST_NODE_TYPES.BlockStatement) return;
|
|
6686
|
-
const returnStatements =
|
|
6829
|
+
const returnStatements = getNestedReturnStatements(callbackArg);
|
|
6687
6830
|
if (returnStatements.length === 0) {
|
|
6688
6831
|
context.report({
|
|
6689
6832
|
messageId: "missingReturnValue",
|
|
@@ -6698,6 +6841,101 @@ function create$1(context) {
|
|
|
6698
6841
|
} });
|
|
6699
6842
|
}
|
|
6700
6843
|
|
|
6844
|
+
//#endregion
|
|
6845
|
+
//#region src/rules/use-state/lib.ts
|
|
6846
|
+
/**
|
|
6847
|
+
* Get all nested expressions of type T in an expression like node
|
|
6848
|
+
* @param type The type of the expression to retrieve within the node
|
|
6849
|
+
* @returns A partially applied function bound to a predicate of type AST. The returned function can be called passing a
|
|
6850
|
+
* node, and it will return an array of all nested expressions of type AST.
|
|
6851
|
+
*/
|
|
6852
|
+
function getNestedExpressionsOfType(type) {
|
|
6853
|
+
const isNodeOfType = is(type);
|
|
6854
|
+
const recurse = (node) => {
|
|
6855
|
+
const expressions = [];
|
|
6856
|
+
if (isNodeOfType(node)) expressions.push(node);
|
|
6857
|
+
if ("arguments" in node) {
|
|
6858
|
+
const chunk = node.arguments.flatMap(recurse);
|
|
6859
|
+
expressions.push(...chunk);
|
|
6860
|
+
}
|
|
6861
|
+
if ("expression" in node && node.expression !== true && node.expression !== false) {
|
|
6862
|
+
const chunk = recurse(node.expression);
|
|
6863
|
+
expressions.push(...chunk);
|
|
6864
|
+
}
|
|
6865
|
+
if ("left" in node) {
|
|
6866
|
+
const chunk = recurse(node.left);
|
|
6867
|
+
expressions.push(...chunk);
|
|
6868
|
+
}
|
|
6869
|
+
if ("right" in node) {
|
|
6870
|
+
const chunk = recurse(node.right);
|
|
6871
|
+
expressions.push(...chunk);
|
|
6872
|
+
}
|
|
6873
|
+
if ("test" in node && node.test != null) {
|
|
6874
|
+
const chunk = recurse(node.test);
|
|
6875
|
+
expressions.push(...chunk);
|
|
6876
|
+
}
|
|
6877
|
+
if ("consequent" in node) {
|
|
6878
|
+
const chunk = Array.isArray(node.consequent) ? node.consequent.flatMap(recurse) : recurse(node.consequent);
|
|
6879
|
+
expressions.push(...chunk);
|
|
6880
|
+
}
|
|
6881
|
+
if ("alternate" in node && node.alternate != null) {
|
|
6882
|
+
const chunk = Array.isArray(node.alternate) ? node.alternate.flatMap(recurse) : recurse(node.alternate);
|
|
6883
|
+
expressions.push(...chunk);
|
|
6884
|
+
}
|
|
6885
|
+
if ("elements" in node) {
|
|
6886
|
+
const chunk = node.elements.filter((x) => x != null).flatMap(recurse);
|
|
6887
|
+
expressions.push(...chunk);
|
|
6888
|
+
}
|
|
6889
|
+
if ("properties" in node) {
|
|
6890
|
+
const chunk = node.properties.flatMap(recurse);
|
|
6891
|
+
expressions.push(...chunk);
|
|
6892
|
+
}
|
|
6893
|
+
if ("expressions" in node) {
|
|
6894
|
+
const chunk = node.expressions.flatMap(recurse);
|
|
6895
|
+
expressions.push(...chunk);
|
|
6896
|
+
}
|
|
6897
|
+
if (node.type === AST_NODE_TYPES.Property) {
|
|
6898
|
+
const chunk = recurse(node.value);
|
|
6899
|
+
expressions.push(...chunk);
|
|
6900
|
+
}
|
|
6901
|
+
if (node.type === AST_NODE_TYPES.SpreadElement) {
|
|
6902
|
+
const chunk = recurse(node.argument);
|
|
6903
|
+
expressions.push(...chunk);
|
|
6904
|
+
}
|
|
6905
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
6906
|
+
expressions.push(...recurse(node.object));
|
|
6907
|
+
if (node.computed) expressions.push(...recurse(node.property));
|
|
6908
|
+
}
|
|
6909
|
+
if (node.type === AST_NODE_TYPES.UnaryExpression) {
|
|
6910
|
+
const chunk = recurse(node.argument);
|
|
6911
|
+
expressions.push(...chunk);
|
|
6912
|
+
}
|
|
6913
|
+
if (node.type === AST_NODE_TYPES.AwaitExpression) expressions.push(...recurse(node.argument));
|
|
6914
|
+
if (node.type === AST_NODE_TYPES.YieldExpression && node.argument != null) expressions.push(...recurse(node.argument));
|
|
6915
|
+
if (node.type === AST_NODE_TYPES.UpdateExpression) expressions.push(...recurse(node.argument));
|
|
6916
|
+
if (node.type === AST_NODE_TYPES.CallExpression || node.type === AST_NODE_TYPES.NewExpression) expressions.push(...recurse(node.callee));
|
|
6917
|
+
if (node.type === AST_NODE_TYPES.TaggedTemplateExpression) {
|
|
6918
|
+
expressions.push(...recurse(node.tag));
|
|
6919
|
+
expressions.push(...recurse(node.quasi));
|
|
6920
|
+
}
|
|
6921
|
+
if (node.type === AST_NODE_TYPES.ImportExpression) expressions.push(...recurse(node.source));
|
|
6922
|
+
return expressions;
|
|
6923
|
+
};
|
|
6924
|
+
return recurse;
|
|
6925
|
+
}
|
|
6926
|
+
/**
|
|
6927
|
+
* Get all nested new expressions in an expression like node
|
|
6928
|
+
* @param node The node to get the nested new expressions from
|
|
6929
|
+
* @returns All nested new expressions
|
|
6930
|
+
*/
|
|
6931
|
+
const getNestedNewExpressions = getNestedExpressionsOfType(AST_NODE_TYPES.NewExpression);
|
|
6932
|
+
/**
|
|
6933
|
+
* Get all nested call expressions in a expression like node
|
|
6934
|
+
* @param node The node to get the nested call expressions from
|
|
6935
|
+
* @returns All nested call expressions
|
|
6936
|
+
*/
|
|
6937
|
+
const getNestedCallExpressions = getNestedExpressionsOfType(AST_NODE_TYPES.CallExpression);
|
|
6938
|
+
|
|
6701
6939
|
//#endregion
|
|
6702
6940
|
//#region src/rules/use-state/use-state.ts
|
|
6703
6941
|
const RULE_NAME = "use-state";
|
|
@@ -6752,7 +6990,7 @@ function create(context) {
|
|
|
6752
6990
|
if (enforceLazyInitialization) {
|
|
6753
6991
|
const [useStateInput] = node.arguments;
|
|
6754
6992
|
if (useStateInput != null) {
|
|
6755
|
-
for (const expr of
|
|
6993
|
+
for (const expr of getNestedNewExpressions(useStateInput)) {
|
|
6756
6994
|
if (!("name" in expr.callee)) continue;
|
|
6757
6995
|
if (LAZY_INIT_ALLOW_LIST.includes(expr.callee.name)) continue;
|
|
6758
6996
|
if (ast.findParent(expr, (n) => core.isUseCall(context, n)) != null) continue;
|
|
@@ -6761,7 +6999,7 @@ function create(context) {
|
|
|
6761
6999
|
node: expr
|
|
6762
7000
|
});
|
|
6763
7001
|
}
|
|
6764
|
-
for (const expr of
|
|
7002
|
+
for (const expr of getNestedCallExpressions(useStateInput)) {
|
|
6765
7003
|
if (!("name" in expr.callee)) continue;
|
|
6766
7004
|
if (core.isHookName(expr.callee.name)) continue;
|
|
6767
7005
|
if (LAZY_INIT_ALLOW_LIST.includes(expr.callee.name)) continue;
|
|
@@ -6781,7 +7019,7 @@ function create(context) {
|
|
|
6781
7019
|
});
|
|
6782
7020
|
return;
|
|
6783
7021
|
}
|
|
6784
|
-
const id =
|
|
7022
|
+
const id = resolveEnclosingAssignmentTarget(node);
|
|
6785
7023
|
if (id?.type !== AST_NODE_TYPES.ArrayPattern) {
|
|
6786
7024
|
if (!enforceAssignment) return;
|
|
6787
7025
|
context.report({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-x",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.1-beta.3",
|
|
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",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
18
|
"url": "git+https://github.com/Rel1cx/eslint-react.git",
|
|
19
|
-
"directory": "
|
|
19
|
+
"directory": "plugins/eslint-plugin-react-x"
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "Rel1cx",
|
|
@@ -40,17 +40,18 @@
|
|
|
40
40
|
"@typescript-eslint/scope-manager": "^8.58.1",
|
|
41
41
|
"@typescript-eslint/type-utils": "^8.58.1",
|
|
42
42
|
"@typescript-eslint/types": "^8.58.1",
|
|
43
|
+
"@typescript-eslint/typescript-estree": "^8.58.1",
|
|
43
44
|
"@typescript-eslint/utils": "^8.58.1",
|
|
44
45
|
"compare-versions": "^6.1.1",
|
|
45
46
|
"string-ts": "^2.3.1",
|
|
46
47
|
"ts-api-utils": "^2.5.0",
|
|
47
48
|
"ts-pattern": "^5.9.0",
|
|
48
|
-
"@eslint-react/ast": "5.2.
|
|
49
|
-
"@eslint-react/
|
|
50
|
-
"@eslint-react/
|
|
51
|
-
"@eslint-react/
|
|
52
|
-
"@eslint-react/
|
|
53
|
-
"@eslint-react/var": "5.2.
|
|
49
|
+
"@eslint-react/ast": "5.2.1-beta.3",
|
|
50
|
+
"@eslint-react/eslint": "5.2.1-beta.3",
|
|
51
|
+
"@eslint-react/jsx": "5.2.1-beta.3",
|
|
52
|
+
"@eslint-react/shared": "5.2.1-beta.3",
|
|
53
|
+
"@eslint-react/core": "5.2.1-beta.3",
|
|
54
|
+
"@eslint-react/var": "5.2.1-beta.3"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@types/react": "^19.2.14",
|