eslint-plugin-react-x 5.2.1-next.1 → 5.2.2-beta.0
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 +365 -123
- package/package.json +10 -9
package/dist/index.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { DEFAULT_ESLINT_REACT_SETTINGS, getSettingsFromContext, toRegExp } from "@eslint-react/shared";
|
|
2
|
-
import
|
|
2
|
+
import { Check, Compare, Extract, Select, Traverse, is, isOneOf } from "@eslint-react/ast";
|
|
3
3
|
import * as core from "@eslint-react/core";
|
|
4
4
|
import { isUseRefCall } from "@eslint-react/core";
|
|
5
5
|
import { merge } from "@eslint-react/eslint";
|
|
6
6
|
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
7
7
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
8
8
|
import { JsxDetectionHint, findParentAttribute, getElementFullType, hasAttribute, isJsxLike } from "@eslint-react/jsx";
|
|
9
|
-
import { computeObjectType,
|
|
9
|
+
import { computeObjectType, isAssignmentTargetEqual, resolve, resolveEnclosingAssignmentTarget } from "@eslint-react/var";
|
|
10
10
|
import { DefinitionType } from "@typescript-eslint/scope-manager";
|
|
11
11
|
import { findVariable, getStaticValue } from "@typescript-eslint/utils/ast-utils";
|
|
12
12
|
import { P, isMatching, match } from "ts-pattern";
|
|
13
13
|
import { compare } from "compare-versions";
|
|
14
14
|
import { getConstrainedTypeAtLocation } from "@typescript-eslint/type-utils";
|
|
15
15
|
import { unionConstituents } from "ts-api-utils";
|
|
16
|
+
import { simpleTraverse } from "@typescript-eslint/typescript-estree";
|
|
16
17
|
import { snakeCase } from "string-ts";
|
|
17
18
|
|
|
18
19
|
//#region \0rolldown/runtime.js
|
|
@@ -142,7 +143,7 @@ const rules$7 = {
|
|
|
142
143
|
//#endregion
|
|
143
144
|
//#region package.json
|
|
144
145
|
var name$6 = "eslint-plugin-react-x";
|
|
145
|
-
var version = "5.2.
|
|
146
|
+
var version = "5.2.2-beta.0";
|
|
146
147
|
|
|
147
148
|
//#endregion
|
|
148
149
|
//#region src/rules/component-hook-factories/lib.ts
|
|
@@ -182,6 +183,12 @@ function isHigherOrderComponent(fn) {
|
|
|
182
183
|
return false;
|
|
183
184
|
});
|
|
184
185
|
}
|
|
186
|
+
function isTestMock$1(node) {
|
|
187
|
+
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";
|
|
188
|
+
}
|
|
189
|
+
function isTestMockCallback$1(node) {
|
|
190
|
+
return node != null && Check.isFunction(node) && node.parent.type === AST_NODE_TYPES.CallExpression && isTestMock$1(node.parent.callee) && node.parent.arguments[1] === node;
|
|
191
|
+
}
|
|
185
192
|
|
|
186
193
|
//#endregion
|
|
187
194
|
//#region src/utils/create-rule.ts
|
|
@@ -219,9 +226,9 @@ function create$48(context) {
|
|
|
219
226
|
const hooks = [...hCollector.api.getAllHooks(program)];
|
|
220
227
|
for (const { name, node } of fComponents) {
|
|
221
228
|
if (name == null) continue;
|
|
222
|
-
const parentFn =
|
|
229
|
+
const parentFn = Traverse.findParent(node, Check.isFunction);
|
|
223
230
|
if (parentFn == null) continue;
|
|
224
|
-
if (
|
|
231
|
+
if (Traverse.findParent(node, isTestMockCallback$1) != null) continue;
|
|
225
232
|
if (isHigherOrderComponent(parentFn)) continue;
|
|
226
233
|
if (reported.has(node)) continue;
|
|
227
234
|
context.report({
|
|
@@ -232,9 +239,9 @@ function create$48(context) {
|
|
|
232
239
|
reported.add(node);
|
|
233
240
|
}
|
|
234
241
|
for (const { name = "unknown", node } of cComponents) {
|
|
235
|
-
const parentFn =
|
|
242
|
+
const parentFn = Traverse.findParent(node, Check.isFunction);
|
|
236
243
|
if (parentFn == null) continue;
|
|
237
|
-
if (
|
|
244
|
+
if (Traverse.findParent(node, isTestMockCallback$1) != null) continue;
|
|
238
245
|
if (isHigherOrderComponent(parentFn)) continue;
|
|
239
246
|
context.report({
|
|
240
247
|
data: { name },
|
|
@@ -243,8 +250,8 @@ function create$48(context) {
|
|
|
243
250
|
});
|
|
244
251
|
}
|
|
245
252
|
for (const { name, node } of hooks) {
|
|
246
|
-
if (
|
|
247
|
-
if (
|
|
253
|
+
if (Traverse.findParent(node, Check.isFunction) == null) continue;
|
|
254
|
+
if (Traverse.findParent(node, isTestMockCallback$1) != null) continue;
|
|
248
255
|
if (reported.has(node)) continue;
|
|
249
256
|
context.report({
|
|
250
257
|
data: { name },
|
|
@@ -290,8 +297,8 @@ function create$47(context) {
|
|
|
290
297
|
const hooks = hCollector.api.getAllHooks(node);
|
|
291
298
|
const funcs = [...comps, ...hooks];
|
|
292
299
|
for (const call of useCalls) {
|
|
293
|
-
const stmt =
|
|
294
|
-
const func =
|
|
300
|
+
const stmt = Traverse.findParent(call, is(AST_NODE_TYPES.TryStatement));
|
|
301
|
+
const func = Traverse.findParent(stmt, (n) => funcs.some((f) => f.node === n));
|
|
295
302
|
if (stmt != null && func != null && !reported.has(stmt)) {
|
|
296
303
|
context.report({
|
|
297
304
|
messageId: "tryCatchWithUse",
|
|
@@ -303,7 +310,7 @@ function create$47(context) {
|
|
|
303
310
|
for (const { rets } of funcs) for (const ret of rets) {
|
|
304
311
|
if (ret == null) continue;
|
|
305
312
|
if (!isJsxLike(context, ret, hint)) continue;
|
|
306
|
-
const stmt =
|
|
313
|
+
const stmt = Traverse.findParent(ret, is(AST_NODE_TYPES.TryStatement));
|
|
307
314
|
if (stmt != null && !reported.has(stmt)) {
|
|
308
315
|
context.report({
|
|
309
316
|
messageId: "tryCatchWithJsx",
|
|
@@ -1305,7 +1312,7 @@ function create$46(context) {
|
|
|
1305
1312
|
if (variable == null) return null;
|
|
1306
1313
|
for (const def of variable.defs) {
|
|
1307
1314
|
if (def.type !== DefinitionType.Parameter) continue;
|
|
1308
|
-
if (!
|
|
1315
|
+
if (!Check.isFunction(def.node)) continue;
|
|
1309
1316
|
const fn = def.node;
|
|
1310
1317
|
const firstParam = fn.params.at(0);
|
|
1311
1318
|
if (firstParam?.type === AST_NODE_TYPES.Identifier && firstParam.name === id.name) return fn;
|
|
@@ -1318,10 +1325,10 @@ function create$46(context) {
|
|
|
1318
1325
|
const { object, property } = node.callee;
|
|
1319
1326
|
if (property.type !== AST_NODE_TYPES.Identifier) return;
|
|
1320
1327
|
if (!MUTATING_ARRAY_METHODS.has(property.name)) return;
|
|
1321
|
-
const rootId =
|
|
1328
|
+
const rootId = Extract.rootIdentifier(object);
|
|
1322
1329
|
if (rootId == null) return;
|
|
1323
1330
|
if (rootId.name === "draft") return;
|
|
1324
|
-
const enclosingFn =
|
|
1331
|
+
const enclosingFn = Traverse.findParent(node, Check.isFunction);
|
|
1325
1332
|
if (enclosingFn == null) return;
|
|
1326
1333
|
const isState = isStateValue(rootId);
|
|
1327
1334
|
const propsDefiningFunc = !isState ? getPropsDefiningFunction(rootId) : null;
|
|
@@ -1339,10 +1346,10 @@ function create$46(context) {
|
|
|
1339
1346
|
},
|
|
1340
1347
|
AssignmentExpression(node) {
|
|
1341
1348
|
if (node.left.type !== AST_NODE_TYPES.MemberExpression) return;
|
|
1342
|
-
const rootId =
|
|
1349
|
+
const rootId = Extract.rootIdentifier(node.left);
|
|
1343
1350
|
if (rootId == null) return;
|
|
1344
1351
|
if (rootId.name === "draft") return;
|
|
1345
|
-
const enclosingFn =
|
|
1352
|
+
const enclosingFn = Traverse.findParent(node, Check.isFunction);
|
|
1346
1353
|
if (enclosingFn == null) return;
|
|
1347
1354
|
const isState = isStateValue(rootId);
|
|
1348
1355
|
const propsDefiningFunc = !isState ? getPropsDefiningFunction(rootId) : null;
|
|
@@ -1367,7 +1374,7 @@ function create$46(context) {
|
|
|
1367
1374
|
insideComponentOrHook = true;
|
|
1368
1375
|
break;
|
|
1369
1376
|
}
|
|
1370
|
-
current =
|
|
1377
|
+
current = Traverse.findParent(current, Check.isFunction);
|
|
1371
1378
|
}
|
|
1372
1379
|
if (!insideComponentOrHook) continue;
|
|
1373
1380
|
if (propsDefiningFunc != null) {
|
|
@@ -1606,14 +1613,14 @@ function create$45(context) {
|
|
|
1606
1613
|
classStack.pop();
|
|
1607
1614
|
},
|
|
1608
1615
|
MemberExpression(node) {
|
|
1609
|
-
if (!
|
|
1616
|
+
if (!Check.thisExpression(node.object)) return;
|
|
1610
1617
|
const [currClass, isComponent = false] = classStack.at(-1) ?? [];
|
|
1611
1618
|
if (currClass == null || !isComponent) return;
|
|
1612
1619
|
const [currMethod, isStatic = false] = methodStack.at(-1) ?? [];
|
|
1613
1620
|
if (currMethod == null || isStatic) return;
|
|
1614
1621
|
const [setState, hasThisState = false] = setStateStack.at(-1) ?? [];
|
|
1615
1622
|
if (setState == null || hasThisState) return;
|
|
1616
|
-
if (
|
|
1623
|
+
if (Extract.propertyName(node.property) !== "state") return;
|
|
1617
1624
|
context.report({
|
|
1618
1625
|
messageId: "default",
|
|
1619
1626
|
node
|
|
@@ -1638,8 +1645,8 @@ function create$45(context) {
|
|
|
1638
1645
|
if (currMethod == null || isStatic) return;
|
|
1639
1646
|
const [setState, hasThisState = false] = setStateStack.at(-1) ?? [];
|
|
1640
1647
|
if (setState == null || hasThisState) return;
|
|
1641
|
-
if (node.init == null || !
|
|
1642
|
-
if (!node.id.properties.some((prop) => prop.type === AST_NODE_TYPES.Property && isKeyLiteral$1(prop, prop.key) &&
|
|
1648
|
+
if (node.init == null || !Check.thisExpression(node.init) || node.id.type !== AST_NODE_TYPES.ObjectPattern) return;
|
|
1649
|
+
if (!node.id.properties.some((prop) => prop.type === AST_NODE_TYPES.Property && isKeyLiteral$1(prop, prop.key) && Extract.propertyName(prop.key) === "state")) return;
|
|
1643
1650
|
context.report({
|
|
1644
1651
|
messageId: "default",
|
|
1645
1652
|
node
|
|
@@ -1691,7 +1698,7 @@ function getMapIndexParamName(context, node) {
|
|
|
1691
1698
|
if (indexPosition === -1) return null;
|
|
1692
1699
|
const callbackArg = node.arguments[core.isChildrenMap(context, callee) || core.isChildrenForEach(context, callee) ? 1 : 0];
|
|
1693
1700
|
if (callbackArg == null) return null;
|
|
1694
|
-
if (!
|
|
1701
|
+
if (!isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(callbackArg)) return null;
|
|
1695
1702
|
const { params } = callbackArg;
|
|
1696
1703
|
if (params.length < indexPosition + 1) return null;
|
|
1697
1704
|
const param = params.at(indexPosition);
|
|
@@ -2106,7 +2113,7 @@ var no_create_ref_default = createRule({
|
|
|
2106
2113
|
});
|
|
2107
2114
|
function create$32(context) {
|
|
2108
2115
|
return merge({ CallExpression(node) {
|
|
2109
|
-
if (core.isCreateRefCall(context, node) &&
|
|
2116
|
+
if (core.isCreateRefCall(context, node) && Traverse.findParent(node, core.isClassComponent) == null) context.report({
|
|
2110
2117
|
messageId: "default",
|
|
2111
2118
|
node
|
|
2112
2119
|
});
|
|
@@ -2117,7 +2124,7 @@ function create$32(context) {
|
|
|
2117
2124
|
//#region src/rules/no-direct-mutation-state/no-direct-mutation-state.ts
|
|
2118
2125
|
const RULE_NAME$31 = "no-direct-mutation-state";
|
|
2119
2126
|
function isConstructorFunction(node) {
|
|
2120
|
-
return
|
|
2127
|
+
return isOneOf([AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression])(node) && Check.isMethodOrProperty(node.parent) && node.parent.key.type === AST_NODE_TYPES.Identifier && node.parent.key.name === "constructor";
|
|
2121
2128
|
}
|
|
2122
2129
|
var no_direct_mutation_state_default = createRule({
|
|
2123
2130
|
meta: {
|
|
@@ -2133,9 +2140,9 @@ var no_direct_mutation_state_default = createRule({
|
|
|
2133
2140
|
function create$31(context) {
|
|
2134
2141
|
return merge({ AssignmentExpression(node) {
|
|
2135
2142
|
if (!core.isAssignmentToThisState(node)) return;
|
|
2136
|
-
const parentClass =
|
|
2143
|
+
const parentClass = Traverse.findParent(node, isOneOf([AST_NODE_TYPES.ClassDeclaration, AST_NODE_TYPES.ClassExpression]));
|
|
2137
2144
|
if (parentClass == null) return;
|
|
2138
|
-
if (core.isClassComponent(parentClass) && context.sourceCode.getScope(node).block !==
|
|
2145
|
+
if (core.isClassComponent(parentClass) && context.sourceCode.getScope(node).block !== Traverse.findParent(node, isConstructorFunction)) context.report({
|
|
2139
2146
|
messageId: "default",
|
|
2140
2147
|
node
|
|
2141
2148
|
});
|
|
@@ -2163,7 +2170,7 @@ function create$30(context) {
|
|
|
2163
2170
|
const aValue = a.value;
|
|
2164
2171
|
const bValue = b.value;
|
|
2165
2172
|
if (aValue == null || bValue == null) return false;
|
|
2166
|
-
return
|
|
2173
|
+
return Compare.areEqual(aValue, bValue);
|
|
2167
2174
|
}
|
|
2168
2175
|
return merge({
|
|
2169
2176
|
"JSXAttribute[name.name='key']"(node) {
|
|
@@ -2182,12 +2189,12 @@ function create$30(context) {
|
|
|
2182
2189
|
break;
|
|
2183
2190
|
}
|
|
2184
2191
|
default: {
|
|
2185
|
-
const call =
|
|
2186
|
-
const iter =
|
|
2187
|
-
if (!
|
|
2192
|
+
const call = Traverse.findParent(jsxElement, (n) => n.type === AST_NODE_TYPES.CallExpression && n.callee.type === AST_NODE_TYPES.MemberExpression && n.callee.property.type === AST_NODE_TYPES.Identifier && n.callee.property.name === "map");
|
|
2193
|
+
const iter = Traverse.findParent(jsxElement, (n) => n === call || Check.isFunction(n));
|
|
2194
|
+
if (!Check.isFunction(iter)) return;
|
|
2188
2195
|
const arg0 = call?.arguments[0];
|
|
2189
2196
|
if (call == null || arg0 == null) return;
|
|
2190
|
-
if (
|
|
2197
|
+
if (Extract.unwrapped(arg0) !== iter) return;
|
|
2191
2198
|
keyedEntries.set(call, {
|
|
2192
2199
|
hasDuplicate: node.value?.type === AST_NODE_TYPES.Literal,
|
|
2193
2200
|
keys: [node],
|
|
@@ -2234,7 +2241,7 @@ function create$29(context) {
|
|
|
2234
2241
|
if (compare(version, "19.0.0", "<")) return {};
|
|
2235
2242
|
return merge({ CallExpression(node) {
|
|
2236
2243
|
if (!core.isForwardRefCall(context, node)) return;
|
|
2237
|
-
const id =
|
|
2244
|
+
const id = core.getFunctionId(node);
|
|
2238
2245
|
const suggest = canFix(context, node) ? [{
|
|
2239
2246
|
fix: getFix(context, node),
|
|
2240
2247
|
messageId: "replace"
|
|
@@ -2272,7 +2279,7 @@ function canFix(context, node) {
|
|
|
2272
2279
|
function getFix(context, node) {
|
|
2273
2280
|
return (fixer) => {
|
|
2274
2281
|
const [componentNode] = node.arguments;
|
|
2275
|
-
if (componentNode == null || !
|
|
2282
|
+
if (componentNode == null || !Check.isFunction(componentNode)) return [];
|
|
2276
2283
|
return [
|
|
2277
2284
|
fixer.removeRange([node.range[0], componentNode.range[0]]),
|
|
2278
2285
|
fixer.removeRange([componentNode.range[1], node.range[1]]),
|
|
@@ -2492,16 +2499,16 @@ function create$25(context) {
|
|
|
2492
2499
|
*/
|
|
2493
2500
|
function getReportDescriptor(node) {
|
|
2494
2501
|
if (node == null) return null;
|
|
2495
|
-
if (
|
|
2496
|
-
if (
|
|
2497
|
-
if (
|
|
2502
|
+
if (is(AST_NODE_TYPES.JSXExpressionContainer)(node)) return getReportDescriptor(node.expression);
|
|
2503
|
+
if (Check.isJSX(node)) return null;
|
|
2504
|
+
if (Check.isTypeExpression(node)) return getReportDescriptor(node.expression);
|
|
2498
2505
|
return match(node).with({
|
|
2499
2506
|
type: AST_NODE_TYPES.LogicalExpression,
|
|
2500
2507
|
operator: "&&"
|
|
2501
2508
|
}, ({ left, right }) => {
|
|
2502
2509
|
if (left.type === AST_NODE_TYPES.UnaryExpression && left.operator === "!") return getReportDescriptor(right);
|
|
2503
2510
|
const initialScope = context.sourceCode.getScope(left);
|
|
2504
|
-
if (
|
|
2511
|
+
if (Check.identifier(left, "NaN") || getStaticValue(left, initialScope)?.value === "NaN") return {
|
|
2505
2512
|
data: { value: context.sourceCode.getText(left) },
|
|
2506
2513
|
messageId: "default",
|
|
2507
2514
|
node: left
|
|
@@ -2546,7 +2553,7 @@ function create$24(context) {
|
|
|
2546
2553
|
});
|
|
2547
2554
|
return merge(visitor, { "Program:exit"(program) {
|
|
2548
2555
|
for (const { displayName, flag, node } of api.getAllComponents(program)) {
|
|
2549
|
-
const id =
|
|
2556
|
+
const id = core.getFunctionId(node);
|
|
2550
2557
|
const isMemoOrForwardRef = (flag & (core.FunctionComponentFlag.ForwardRef | core.FunctionComponentFlag.Memo)) > 0n;
|
|
2551
2558
|
if (id != null) continue;
|
|
2552
2559
|
if (!isMemoOrForwardRef) continue;
|
|
@@ -2578,16 +2585,13 @@ function create$23(context) {
|
|
|
2578
2585
|
const createCalls = [];
|
|
2579
2586
|
const displayNameAssignments = [];
|
|
2580
2587
|
return merge({
|
|
2581
|
-
[ast.SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION](node) {
|
|
2582
|
-
displayNameAssignments.push(node);
|
|
2583
|
-
},
|
|
2584
2588
|
CallExpression(node) {
|
|
2585
2589
|
if (!core.isCreateContextCall(context, node)) return;
|
|
2586
2590
|
createCalls.push(node);
|
|
2587
2591
|
},
|
|
2588
2592
|
"Program:exit"() {
|
|
2589
2593
|
for (const call of createCalls) {
|
|
2590
|
-
const id =
|
|
2594
|
+
const id = resolveEnclosingAssignmentTarget(call);
|
|
2591
2595
|
if (id == null) {
|
|
2592
2596
|
context.report({
|
|
2593
2597
|
messageId: "default",
|
|
@@ -2619,6 +2623,9 @@ function create$23(context) {
|
|
|
2619
2623
|
node: id
|
|
2620
2624
|
});
|
|
2621
2625
|
}
|
|
2626
|
+
},
|
|
2627
|
+
[Select.displayNameAssignment](node) {
|
|
2628
|
+
displayNameAssignments.push(node);
|
|
2622
2629
|
}
|
|
2623
2630
|
});
|
|
2624
2631
|
}
|
|
@@ -2636,6 +2643,21 @@ function report(context) {
|
|
|
2636
2643
|
return context.report(descriptor);
|
|
2637
2644
|
};
|
|
2638
2645
|
}
|
|
2646
|
+
/**
|
|
2647
|
+
* Gets the nested return statements in the node that are within the same function
|
|
2648
|
+
* @param node The AST node
|
|
2649
|
+
* @returns The nested return statements in the node
|
|
2650
|
+
*/
|
|
2651
|
+
function getNestedReturnStatements(node) {
|
|
2652
|
+
const statements = [];
|
|
2653
|
+
const boundaryNode = Check.isFunction(node) ? node : Traverse.findParent(node, Check.isFunction);
|
|
2654
|
+
simpleTraverse(node, { enter(node) {
|
|
2655
|
+
if (node.type !== AST_NODE_TYPES.ReturnStatement) return;
|
|
2656
|
+
if (Traverse.findParent(node, Check.isFunction) !== boundaryNode) return;
|
|
2657
|
+
statements.push(node);
|
|
2658
|
+
} });
|
|
2659
|
+
return statements;
|
|
2660
|
+
}
|
|
2639
2661
|
|
|
2640
2662
|
//#endregion
|
|
2641
2663
|
//#region src/rules/no-missing-key/no-missing-key.ts
|
|
@@ -2678,7 +2700,7 @@ function create$22(context) {
|
|
|
2678
2700
|
}
|
|
2679
2701
|
function checkBlock(node) {
|
|
2680
2702
|
const descriptors = [];
|
|
2681
|
-
for (const stmt of
|
|
2703
|
+
for (const stmt of getNestedReturnStatements(node)) {
|
|
2682
2704
|
if (stmt.argument == null) continue;
|
|
2683
2705
|
const desc = check(stmt.argument);
|
|
2684
2706
|
if (desc == null) continue;
|
|
@@ -2689,7 +2711,7 @@ function create$22(context) {
|
|
|
2689
2711
|
return merge({
|
|
2690
2712
|
ArrayExpression(node) {
|
|
2691
2713
|
if (inChildrenToArray) return;
|
|
2692
|
-
const elements = node.elements.filter(
|
|
2714
|
+
const elements = node.elements.filter(is(AST_NODE_TYPES.JSXElement));
|
|
2693
2715
|
if (elements.length === 0) return;
|
|
2694
2716
|
for (const el of elements) if (!hasAttribute(context, el, "key")) context.report({
|
|
2695
2717
|
messageId: "default",
|
|
@@ -2705,7 +2727,7 @@ function create$22(context) {
|
|
|
2705
2727
|
const idx = name === "from" ? 1 : name === "map" ? 0 : -1;
|
|
2706
2728
|
if (idx < 0) return;
|
|
2707
2729
|
const cb = node.arguments[idx];
|
|
2708
|
-
if (!
|
|
2730
|
+
if (!Check.isFunction(cb)) return;
|
|
2709
2731
|
if (cb.body.type === AST_NODE_TYPES.BlockStatement) checkBlock(cb.body).forEach(report(context));
|
|
2710
2732
|
else report(context)(checkExpr(cb.body));
|
|
2711
2733
|
},
|
|
@@ -2722,6 +2744,32 @@ function create$22(context) {
|
|
|
2722
2744
|
});
|
|
2723
2745
|
}
|
|
2724
2746
|
|
|
2747
|
+
//#endregion
|
|
2748
|
+
//#region src/rules/no-misused-capture-owner-stack/lib.ts
|
|
2749
|
+
/**
|
|
2750
|
+
* Check if the given node is a member expression that accesses `process.env.NODE_ENV`
|
|
2751
|
+
* @param node The AST node
|
|
2752
|
+
* @returns True if the node is a member expression that accesses `process.env.NODE_ENV`, false otherwise
|
|
2753
|
+
*/
|
|
2754
|
+
function isProcessEnvNodeEnv(node) {
|
|
2755
|
+
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";
|
|
2756
|
+
}
|
|
2757
|
+
/**
|
|
2758
|
+
* Check if the given node is a binary expression that compares `process.env.NODE_ENV` with a string literal.
|
|
2759
|
+
* @param node The AST node
|
|
2760
|
+
* @param operator The operator used in the comparison
|
|
2761
|
+
* @param value The string literal value to compare against
|
|
2762
|
+
* @returns True if the node is a binary expression that compares `process.env.NODE_ENV` with the specified value, false otherwise
|
|
2763
|
+
*/
|
|
2764
|
+
function isProcessEnvNodeEnvCompare(node, operator, value) {
|
|
2765
|
+
if (node == null) return false;
|
|
2766
|
+
if (node.type !== AST_NODE_TYPES.BinaryExpression) return false;
|
|
2767
|
+
if (node.operator !== operator) return false;
|
|
2768
|
+
if (isProcessEnvNodeEnv(node.left) && Check.literal(node.right, "string")) return node.right.value === value;
|
|
2769
|
+
if (Check.literal(node.left, "string") && isProcessEnvNodeEnv(node.right)) return node.left.value === value;
|
|
2770
|
+
return false;
|
|
2771
|
+
}
|
|
2772
|
+
|
|
2725
2773
|
//#endregion
|
|
2726
2774
|
//#region src/rules/no-misused-capture-owner-stack/no-misused-capture-owner-stack.ts
|
|
2727
2775
|
const RULE_NAME$21 = "no-misused-capture-owner-stack";
|
|
@@ -2745,7 +2793,7 @@ function create$21(context) {
|
|
|
2745
2793
|
return merge({
|
|
2746
2794
|
CallExpression(node) {
|
|
2747
2795
|
if (!core.isCaptureOwnerStackCall(context, node)) return;
|
|
2748
|
-
if (
|
|
2796
|
+
if (Traverse.findParent(node, isDevelopmentOnlyCheck) == null) context.report({
|
|
2749
2797
|
messageId: "missingDevelopmentOnlyCheck",
|
|
2750
2798
|
node
|
|
2751
2799
|
});
|
|
@@ -2765,7 +2813,7 @@ function create$21(context) {
|
|
|
2765
2813
|
}
|
|
2766
2814
|
function isDevelopmentOnlyCheck(node) {
|
|
2767
2815
|
if (node.type !== AST_NODE_TYPES.IfStatement) return false;
|
|
2768
|
-
return
|
|
2816
|
+
return isProcessEnvNodeEnvCompare(node.test, "!==", "production");
|
|
2769
2817
|
}
|
|
2770
2818
|
|
|
2771
2819
|
//#endregion
|
|
@@ -2790,9 +2838,9 @@ function create$20(context) {
|
|
|
2790
2838
|
const fComponents = [...fCollector.api.getAllComponents(program)];
|
|
2791
2839
|
const cComponents = [...cCollector.api.getAllComponents(program)];
|
|
2792
2840
|
function findEnclosingComponent(node) {
|
|
2793
|
-
return
|
|
2794
|
-
if (
|
|
2795
|
-
if (
|
|
2841
|
+
return Traverse.findParent(node, (n) => {
|
|
2842
|
+
if (Check.isFunction(n)) return fComponents.some((c) => c.node === n);
|
|
2843
|
+
if (Check.isClass(n)) return cComponents.some((c) => c.node === n);
|
|
2796
2844
|
return false;
|
|
2797
2845
|
});
|
|
2798
2846
|
}
|
|
@@ -2868,7 +2916,7 @@ function isInsideJSXAttributeValue(node) {
|
|
|
2868
2916
|
* @returns `true` if the node is inside a class component's render block
|
|
2869
2917
|
*/
|
|
2870
2918
|
function isInsideRenderMethod(node) {
|
|
2871
|
-
return
|
|
2919
|
+
return Traverse.findParent(node, (n) => core.isRenderMethodLike(n) && core.isClassComponent(n.parent.parent)) != null;
|
|
2872
2920
|
}
|
|
2873
2921
|
/**
|
|
2874
2922
|
* Determine whether the node is inside `createElement`'s props argument
|
|
@@ -2877,9 +2925,9 @@ function isInsideRenderMethod(node) {
|
|
|
2877
2925
|
* @returns `true` if the node is inside `createElement`'s props
|
|
2878
2926
|
*/
|
|
2879
2927
|
function isInsideCreateElementProps(context, node) {
|
|
2880
|
-
const call =
|
|
2928
|
+
const call = Traverse.findParent(node, core.isCreateElementCall(context));
|
|
2881
2929
|
if (call == null) return false;
|
|
2882
|
-
const prop =
|
|
2930
|
+
const prop = Traverse.findParent(node, is(AST_NODE_TYPES.ObjectExpression));
|
|
2883
2931
|
if (prop == null) return false;
|
|
2884
2932
|
return prop === call.arguments[1];
|
|
2885
2933
|
}
|
|
@@ -2905,7 +2953,7 @@ function create$19(context) {
|
|
|
2905
2953
|
const lazyCalls = /* @__PURE__ */ new Set();
|
|
2906
2954
|
return merge(fCollector.visitor, cCollector.visitor, hCollector.visitor, {
|
|
2907
2955
|
ImportExpression(node) {
|
|
2908
|
-
const lazyCall =
|
|
2956
|
+
const lazyCall = Traverse.findParent(node, (n) => core.isLazyCall(context, n));
|
|
2909
2957
|
if (lazyCall != null) lazyCalls.add(lazyCall);
|
|
2910
2958
|
},
|
|
2911
2959
|
"Program:exit"(program) {
|
|
@@ -2914,7 +2962,7 @@ function create$19(context) {
|
|
|
2914
2962
|
...hCollector.api.getAllHooks(program),
|
|
2915
2963
|
...cCollector.api.getAllComponents(program)
|
|
2916
2964
|
];
|
|
2917
|
-
for (const lazy of lazyCalls) if (
|
|
2965
|
+
for (const lazy of lazyCalls) if (Traverse.findParent(lazy, (n) => significantParents.some((p) => p.node === n))) context.report({
|
|
2918
2966
|
messageId: "default",
|
|
2919
2967
|
node: lazy
|
|
2920
2968
|
});
|
|
@@ -2940,8 +2988,8 @@ function create$18(context) {
|
|
|
2940
2988
|
if (!context.sourceCode.text.includes("componentDidMount")) return {};
|
|
2941
2989
|
return merge({ CallExpression(node) {
|
|
2942
2990
|
if (!core.isThisSetStateCall(node)) return;
|
|
2943
|
-
const enclosingClassNode =
|
|
2944
|
-
const enclosingMethodNode =
|
|
2991
|
+
const enclosingClassNode = Traverse.findParent(node, core.isClassComponent);
|
|
2992
|
+
const enclosingMethodNode = Traverse.findParent(node, (n) => n === enclosingClassNode || core.isComponentDidMount(n));
|
|
2945
2993
|
if (enclosingClassNode == null || enclosingMethodNode == null || enclosingMethodNode === enclosingClassNode) return;
|
|
2946
2994
|
const enclosingMethodScope = context.sourceCode.getScope(enclosingMethodNode);
|
|
2947
2995
|
const setStateCallParentScope = context.sourceCode.getScope(node).upper;
|
|
@@ -2970,8 +3018,8 @@ function create$17(context) {
|
|
|
2970
3018
|
if (!context.sourceCode.text.includes("componentDidUpdate")) return {};
|
|
2971
3019
|
return merge({ CallExpression(node) {
|
|
2972
3020
|
if (!core.isThisSetStateCall(node)) return;
|
|
2973
|
-
const enclosingClassNode =
|
|
2974
|
-
const enclosingMethodNode =
|
|
3021
|
+
const enclosingClassNode = Traverse.findParent(node, core.isClassComponent);
|
|
3022
|
+
const enclosingMethodNode = Traverse.findParent(node, (n) => n === enclosingClassNode || core.isComponentDidUpdate(n));
|
|
2975
3023
|
if (enclosingClassNode == null || enclosingMethodNode == null || enclosingMethodNode === enclosingClassNode) return;
|
|
2976
3024
|
const enclosingMethodScope = context.sourceCode.getScope(enclosingMethodNode);
|
|
2977
3025
|
const setStateCallParentScope = context.sourceCode.getScope(node).upper;
|
|
@@ -3000,8 +3048,8 @@ function create$16(context) {
|
|
|
3000
3048
|
if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
|
|
3001
3049
|
return merge({ CallExpression(node) {
|
|
3002
3050
|
if (!core.isThisSetStateCall(node)) return;
|
|
3003
|
-
const enclosingClassNode =
|
|
3004
|
-
const enclosingMethodNode =
|
|
3051
|
+
const enclosingClassNode = Traverse.findParent(node, core.isClassComponent);
|
|
3052
|
+
const enclosingMethodNode = Traverse.findParent(node, (n) => n === enclosingClassNode || core.isComponentWillUpdate(n));
|
|
3005
3053
|
if (enclosingClassNode == null || enclosingMethodNode == null || enclosingMethodNode === enclosingClassNode) return;
|
|
3006
3054
|
const enclosingMethodScope = context.sourceCode.getScope(enclosingMethodNode);
|
|
3007
3055
|
const setStateCallParentScope = context.sourceCode.getScope(node).upper;
|
|
@@ -3013,12 +3061,21 @@ function create$16(context) {
|
|
|
3013
3061
|
}
|
|
3014
3062
|
|
|
3015
3063
|
//#endregion
|
|
3016
|
-
//#region src/rules/no-unnecessary-use-prefix/
|
|
3017
|
-
const RULE_NAME$15 = "no-unnecessary-use-prefix";
|
|
3064
|
+
//#region src/rules/no-unnecessary-use-prefix/lib.ts
|
|
3018
3065
|
const WELL_KNOWN_HOOKS = ["useMDXComponents"];
|
|
3019
3066
|
function containsUseComments(context, node) {
|
|
3020
3067
|
return context.sourceCode.getCommentsInside(node).some(({ value }) => /use\([\s\S]*?\)/u.test(value) || /use[A-Z0-9]\w*\([\s\S]*?\)/u.test(value));
|
|
3021
3068
|
}
|
|
3069
|
+
function isTestMock(node) {
|
|
3070
|
+
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";
|
|
3071
|
+
}
|
|
3072
|
+
function isTestMockCallback(node) {
|
|
3073
|
+
return node != null && Check.isFunction(node) && node.parent.type === AST_NODE_TYPES.CallExpression && isTestMock(node.parent.callee) && node.parent.arguments[1] === node;
|
|
3074
|
+
}
|
|
3075
|
+
|
|
3076
|
+
//#endregion
|
|
3077
|
+
//#region src/rules/no-unnecessary-use-prefix/no-unnecessary-use-prefix.ts
|
|
3078
|
+
const RULE_NAME$15 = "no-unnecessary-use-prefix";
|
|
3022
3079
|
var no_unnecessary_use_prefix_default = createRule({
|
|
3023
3080
|
meta: {
|
|
3024
3081
|
type: "problem",
|
|
@@ -3036,10 +3093,10 @@ function create$15(context) {
|
|
|
3036
3093
|
for (const { id, name, hookCalls, node } of api.getAllHooks(program)) {
|
|
3037
3094
|
if (name == null) continue;
|
|
3038
3095
|
if (hookCalls.length > 0) continue;
|
|
3039
|
-
if (
|
|
3096
|
+
if (core.isFunctionEmpty(node)) continue;
|
|
3040
3097
|
if (WELL_KNOWN_HOOKS.includes(name)) continue;
|
|
3041
3098
|
if (containsUseComments(context, node)) continue;
|
|
3042
|
-
if (
|
|
3099
|
+
if (Traverse.findParent(node, isTestMockCallback) != null) continue;
|
|
3043
3100
|
context.report({
|
|
3044
3101
|
data: { name },
|
|
3045
3102
|
messageId: "default",
|
|
@@ -3150,7 +3207,7 @@ var no_unstable_context_value_default = createRule({
|
|
|
3150
3207
|
function create$11(context) {
|
|
3151
3208
|
const { compilationMode, version } = getSettingsFromContext(context);
|
|
3152
3209
|
if (compilationMode === "infer" || compilationMode === "all") return {};
|
|
3153
|
-
if (compilationMode === "annotation" &&
|
|
3210
|
+
if (compilationMode === "annotation" && context.sourceCode.ast.body.some((stmt) => Check.directive(stmt) && stmt.directive === "use memo")) return {};
|
|
3154
3211
|
const isReact18OrBelow = compare(version, "19.0.0", "<");
|
|
3155
3212
|
const { api, visitor } = core.getFunctionComponentCollector(context);
|
|
3156
3213
|
const constructions = /* @__PURE__ */ new WeakMap();
|
|
@@ -3159,9 +3216,9 @@ function create$11(context) {
|
|
|
3159
3216
|
const selfName = getElementFullType(node.parent).split(".").at(-1);
|
|
3160
3217
|
if (selfName == null) return;
|
|
3161
3218
|
if (!isContextName(selfName, isReact18OrBelow)) return;
|
|
3162
|
-
const enclosingFunction =
|
|
3219
|
+
const enclosingFunction = Traverse.findParent(node, Check.isFunction);
|
|
3163
3220
|
if (enclosingFunction == null) return;
|
|
3164
|
-
if (compilationMode === "annotation" &&
|
|
3221
|
+
if (compilationMode === "annotation" && core.isFunctionHasDirective(enclosingFunction, "use memo")) return;
|
|
3165
3222
|
const attribute = node.attributes.find((attribute) => attribute.type === AST_NODE_TYPES.JSXAttribute && attribute.name.name === "value");
|
|
3166
3223
|
if (attribute == null || !("value" in attribute)) return;
|
|
3167
3224
|
const value = attribute.value;
|
|
@@ -3180,7 +3237,7 @@ function create$11(context) {
|
|
|
3180
3237
|
const suggestion = kind === "function" ? "Consider wrapping it in a useCallback hook." : "Consider wrapping it in a useMemo hook.";
|
|
3181
3238
|
context.report({
|
|
3182
3239
|
data: {
|
|
3183
|
-
kind:
|
|
3240
|
+
kind: Extract.humanReadableKind(constructionNode),
|
|
3184
3241
|
suggestion
|
|
3185
3242
|
},
|
|
3186
3243
|
messageId: "unstableContextValue",
|
|
@@ -3231,17 +3288,17 @@ function extractIdentifier(node) {
|
|
|
3231
3288
|
function create$10(context, [options]) {
|
|
3232
3289
|
const { compilationMode } = getSettingsFromContext(context);
|
|
3233
3290
|
if (compilationMode === "infer" || compilationMode === "all") return {};
|
|
3234
|
-
if (compilationMode === "annotation" &&
|
|
3291
|
+
if (compilationMode === "annotation" && context.sourceCode.ast.body.some((stmt) => Check.directive(stmt) && stmt.directive === "use memo")) return {};
|
|
3235
3292
|
const { api, visitor } = core.getFunctionComponentCollector(context);
|
|
3293
|
+
const SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR = [
|
|
3294
|
+
"VariableDeclarator",
|
|
3295
|
+
"[id.type='ObjectPattern']",
|
|
3296
|
+
"[init.type='Identifier']"
|
|
3297
|
+
].join("");
|
|
3236
3298
|
const declarators = /* @__PURE__ */ new WeakMap();
|
|
3237
3299
|
const { safeDefaultProps = [] } = options;
|
|
3238
3300
|
const safePatterns = safeDefaultProps.map((s) => toRegExp(s));
|
|
3239
3301
|
return merge(visitor, {
|
|
3240
|
-
[ast.SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR](node) {
|
|
3241
|
-
const enclosingFunction = ast.findParent(node, ast.isFunction);
|
|
3242
|
-
if (enclosingFunction == null) return;
|
|
3243
|
-
getOrInsertComputed(declarators, enclosingFunction, () => []).push(node);
|
|
3244
|
-
},
|
|
3245
3302
|
"Program:exit"(program) {
|
|
3246
3303
|
for (const { node: component } of api.getAllComponents(program)) {
|
|
3247
3304
|
const { params } = component;
|
|
@@ -3262,12 +3319,17 @@ function create$10(context, [options]) {
|
|
|
3262
3319
|
if (identifier != null && safePatterns.some((pattern) => pattern.test(identifier))) continue;
|
|
3263
3320
|
}
|
|
3264
3321
|
context.report({
|
|
3265
|
-
data: { kind:
|
|
3322
|
+
data: { kind: Extract.humanReadableKind(right) },
|
|
3266
3323
|
messageId: "default",
|
|
3267
3324
|
node: right
|
|
3268
3325
|
});
|
|
3269
3326
|
}
|
|
3270
3327
|
}
|
|
3328
|
+
},
|
|
3329
|
+
[SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR](node) {
|
|
3330
|
+
const enclosingFunction = Traverse.findParent(node, Check.isFunction);
|
|
3331
|
+
if (enclosingFunction == null) return;
|
|
3332
|
+
getOrInsertComputed(declarators, enclosingFunction, () => []).push(node);
|
|
3271
3333
|
}
|
|
3272
3334
|
});
|
|
3273
3335
|
}
|
|
@@ -3323,12 +3385,12 @@ function create$9(context) {
|
|
|
3323
3385
|
function classExit() {
|
|
3324
3386
|
const currentClass = classStack.pop();
|
|
3325
3387
|
if (currentClass == null || !core.isClassComponent(currentClass)) return;
|
|
3326
|
-
const id =
|
|
3388
|
+
const id = core.getClassId(currentClass);
|
|
3327
3389
|
const defs = propertyDefs.get(currentClass);
|
|
3328
3390
|
const usages = propertyUsages.get(currentClass);
|
|
3329
3391
|
if (defs == null) return;
|
|
3330
3392
|
for (const def of defs) {
|
|
3331
|
-
const methodName =
|
|
3393
|
+
const methodName = Extract.propertyName(def);
|
|
3332
3394
|
if (methodName == null) continue;
|
|
3333
3395
|
if ((usages?.has(methodName) ?? false) || LIFECYCLE_METHODS.has(methodName)) continue;
|
|
3334
3396
|
context.report({
|
|
@@ -3361,12 +3423,12 @@ function create$9(context) {
|
|
|
3361
3423
|
const currentMethod = methodStack.at(-1);
|
|
3362
3424
|
if (currentClass == null || currentMethod == null) return;
|
|
3363
3425
|
if (!core.isClassComponent(currentClass) || currentMethod.static) return;
|
|
3364
|
-
if (!
|
|
3426
|
+
if (!Check.thisExpression(node.object) || !isKeyLiteral(node, node.property)) return;
|
|
3365
3427
|
if (node.parent.type === AST_NODE_TYPES.AssignmentExpression && node.parent.left === node) {
|
|
3366
3428
|
propertyDefs.get(currentClass)?.add(node.property);
|
|
3367
3429
|
return;
|
|
3368
3430
|
}
|
|
3369
|
-
const propertyName =
|
|
3431
|
+
const propertyName = Extract.propertyName(node.property);
|
|
3370
3432
|
if (propertyName != null) propertyUsages.get(currentClass)?.add(propertyName);
|
|
3371
3433
|
},
|
|
3372
3434
|
MethodDefinition: methodEnter,
|
|
@@ -3378,9 +3440,9 @@ function create$9(context) {
|
|
|
3378
3440
|
const currentMethod = methodStack.at(-1);
|
|
3379
3441
|
if (currentClass == null || currentMethod == null) return;
|
|
3380
3442
|
if (!core.isClassComponent(currentClass) || currentMethod.static) return;
|
|
3381
|
-
if (node.init != null &&
|
|
3443
|
+
if (node.init != null && Check.thisExpression(node.init) && node.id.type === AST_NODE_TYPES.ObjectPattern) {
|
|
3382
3444
|
for (const prop of node.id.properties) if (prop.type === AST_NODE_TYPES.Property && isKeyLiteral(prop, prop.key)) {
|
|
3383
|
-
const keyName =
|
|
3445
|
+
const keyName = Extract.propertyName(prop.key);
|
|
3384
3446
|
if (keyName != null) propertyUsages.get(currentClass)?.add(keyName);
|
|
3385
3447
|
}
|
|
3386
3448
|
}
|
|
@@ -3848,11 +3910,11 @@ function create$6(context) {
|
|
|
3848
3910
|
const nEntries = [];
|
|
3849
3911
|
return merge(hCollector.visitor, cCollector.visitor, {
|
|
3850
3912
|
CallExpression(node) {
|
|
3851
|
-
const expr =
|
|
3913
|
+
const expr = Extract.unwrapped(node.callee);
|
|
3852
3914
|
switch (true) {
|
|
3853
3915
|
case expr.type === AST_NODE_TYPES.Identifier: {
|
|
3854
3916
|
if (!IMPURE_FUNCS.get("globalThis")?.has(expr.name)) return;
|
|
3855
|
-
const func =
|
|
3917
|
+
const func = Traverse.findParent(node, Check.isFunction);
|
|
3856
3918
|
if (func == null) return;
|
|
3857
3919
|
cEntries.push({
|
|
3858
3920
|
func,
|
|
@@ -3864,7 +3926,7 @@ function create$6(context) {
|
|
|
3864
3926
|
const objectName = expr.object.name;
|
|
3865
3927
|
const propertyName = expr.property.name;
|
|
3866
3928
|
if (!IMPURE_FUNCS.get(objectName)?.has(propertyName)) return;
|
|
3867
|
-
const func =
|
|
3929
|
+
const func = Traverse.findParent(node, Check.isFunction);
|
|
3868
3930
|
if (func == null) return;
|
|
3869
3931
|
cEntries.push({
|
|
3870
3932
|
func,
|
|
@@ -3875,11 +3937,11 @@ function create$6(context) {
|
|
|
3875
3937
|
}
|
|
3876
3938
|
},
|
|
3877
3939
|
NewExpression(node) {
|
|
3878
|
-
const expr =
|
|
3940
|
+
const expr = Extract.unwrapped(node.callee);
|
|
3879
3941
|
if (expr.type !== AST_NODE_TYPES.Identifier) return;
|
|
3880
3942
|
if (!IMPURE_CTORS.has(expr.name)) return;
|
|
3881
3943
|
if (expr.name === "Date" && node.arguments.length > 0) return;
|
|
3882
|
-
const func =
|
|
3944
|
+
const func = Traverse.findParent(node, Check.isFunction);
|
|
3883
3945
|
if (func == null) return;
|
|
3884
3946
|
nEntries.push({
|
|
3885
3947
|
func,
|
|
@@ -3931,12 +3993,12 @@ function create$5(context) {
|
|
|
3931
3993
|
*/
|
|
3932
3994
|
function isInNullCheckTest(node) {
|
|
3933
3995
|
let parent = node.parent;
|
|
3934
|
-
while (
|
|
3996
|
+
while (Check.isTypeExpression(parent)) parent = parent.parent;
|
|
3935
3997
|
if (!isMatching({
|
|
3936
3998
|
type: AST_NODE_TYPES.BinaryExpression,
|
|
3937
3999
|
operator: P.union("===", "==", "!==", "!=")
|
|
3938
4000
|
}, parent)) return false;
|
|
3939
|
-
const otherSide = parent.left === node ||
|
|
4001
|
+
const otherSide = parent.left === node || Extract.unwrapped(parent.left) === node ? parent.right : parent.left;
|
|
3940
4002
|
if (otherSide.type !== AST_NODE_TYPES.Literal || otherSide.value != null) return false;
|
|
3941
4003
|
return parent.parent.type === AST_NODE_TYPES.IfStatement && parent.parent.test === parent;
|
|
3942
4004
|
}
|
|
@@ -3952,8 +4014,8 @@ function create$5(context) {
|
|
|
3952
4014
|
if (op !== "===" && op !== "==" && op !== "!==" && op !== "!=") return false;
|
|
3953
4015
|
const { left, right } = test;
|
|
3954
4016
|
const checkSides = (a, b) => {
|
|
3955
|
-
a =
|
|
3956
|
-
return a.type === AST_NODE_TYPES.MemberExpression && a.object.type === AST_NODE_TYPES.Identifier && a.object.name === refName && b.type === AST_NODE_TYPES.Literal && b.value == null &&
|
|
4017
|
+
a = Check.isTypeExpression(a) ? Extract.unwrapped(a) : a;
|
|
4018
|
+
return a.type === AST_NODE_TYPES.MemberExpression && a.object.type === AST_NODE_TYPES.Identifier && a.object.name === refName && b.type === AST_NODE_TYPES.Literal && b.value == null && Extract.propertyName(a.property) === "current";
|
|
3957
4019
|
};
|
|
3958
4020
|
return checkSides(left, right) || checkSides(right, left);
|
|
3959
4021
|
}
|
|
@@ -3978,12 +4040,12 @@ function create$5(context) {
|
|
|
3978
4040
|
}
|
|
3979
4041
|
},
|
|
3980
4042
|
MemberExpression(node) {
|
|
3981
|
-
if (!
|
|
4043
|
+
if (!Check.identifier(node.property, "current")) return;
|
|
3982
4044
|
refAccesses.push({
|
|
3983
4045
|
isWrite: (() => {
|
|
3984
4046
|
let parent = node.parent;
|
|
3985
|
-
while (
|
|
3986
|
-
return match(parent).with({ type: AST_NODE_TYPES.AssignmentExpression }, (p) => p.left === node ||
|
|
4047
|
+
while (Check.isTypeExpression(parent)) parent = parent.parent;
|
|
4048
|
+
return match(parent).with({ type: AST_NODE_TYPES.AssignmentExpression }, (p) => p.left === node || Extract.unwrapped(p.left) === node).with({ type: AST_NODE_TYPES.UpdateExpression }, (p) => p.argument === node || Extract.unwrapped(p.argument) === node).otherwise(() => false);
|
|
3987
4049
|
})(),
|
|
3988
4050
|
node
|
|
3989
4051
|
});
|
|
@@ -3992,7 +4054,7 @@ function create$5(context) {
|
|
|
3992
4054
|
const comps = cCollector.api.getAllComponents(program);
|
|
3993
4055
|
const hooks = hCollector.api.getAllHooks(program);
|
|
3994
4056
|
const funcs = new Set([...comps.map((c) => c.node), ...hooks.map((h) => h.node)]);
|
|
3995
|
-
const isCompOrHookFn = (n) =>
|
|
4057
|
+
const isCompOrHookFn = (n) => Check.isFunction(n) && funcs.has(n);
|
|
3996
4058
|
for (const { isWrite, node } of refAccesses) {
|
|
3997
4059
|
const obj = node.object;
|
|
3998
4060
|
if (obj.type !== AST_NODE_TYPES.Identifier) continue;
|
|
@@ -4002,9 +4064,9 @@ function create$5(context) {
|
|
|
4002
4064
|
case isInitializedFromRef(obj.name, context.sourceCode.getScope(node.object)): break;
|
|
4003
4065
|
default: continue;
|
|
4004
4066
|
}
|
|
4005
|
-
const boundary =
|
|
4067
|
+
const boundary = Traverse.findParent(node, isCompOrHookFn);
|
|
4006
4068
|
if (boundary == null) continue;
|
|
4007
|
-
if (
|
|
4069
|
+
if (Traverse.findParent(node, Check.isFunction) !== boundary) continue;
|
|
4008
4070
|
const refName = obj.name;
|
|
4009
4071
|
let isLazyInit = isInNullCheckTest(node);
|
|
4010
4072
|
if (!isLazyInit) {
|
|
@@ -6198,6 +6260,91 @@ function last(array) {
|
|
|
6198
6260
|
return array[array.length - 1];
|
|
6199
6261
|
}
|
|
6200
6262
|
|
|
6263
|
+
//#endregion
|
|
6264
|
+
//#region src/rules/set-state-in-effect/lib.ts
|
|
6265
|
+
/**
|
|
6266
|
+
* Get all nested identifiers in a expression like node
|
|
6267
|
+
* @param node The node to get the nested identifiers from
|
|
6268
|
+
* @returns All nested identifiers
|
|
6269
|
+
*/
|
|
6270
|
+
function getNestedIdentifiers(node) {
|
|
6271
|
+
const identifiers = [];
|
|
6272
|
+
if (node.type === AST_NODE_TYPES.Identifier) identifiers.push(node);
|
|
6273
|
+
if ("arguments" in node) {
|
|
6274
|
+
const chunk = node.arguments.flatMap(getNestedIdentifiers);
|
|
6275
|
+
identifiers.push(...chunk);
|
|
6276
|
+
}
|
|
6277
|
+
if ("elements" in node) {
|
|
6278
|
+
const chunk = node.elements.filter((x) => x != null).flatMap(getNestedIdentifiers);
|
|
6279
|
+
identifiers.push(...chunk);
|
|
6280
|
+
}
|
|
6281
|
+
if ("properties" in node) {
|
|
6282
|
+
const chunk = node.properties.flatMap(getNestedIdentifiers);
|
|
6283
|
+
identifiers.push(...chunk);
|
|
6284
|
+
}
|
|
6285
|
+
if ("expressions" in node) {
|
|
6286
|
+
const chunk = node.expressions.flatMap(getNestedIdentifiers);
|
|
6287
|
+
identifiers.push(...chunk);
|
|
6288
|
+
}
|
|
6289
|
+
if ("left" in node) {
|
|
6290
|
+
const chunk = getNestedIdentifiers(node.left);
|
|
6291
|
+
identifiers.push(...chunk);
|
|
6292
|
+
}
|
|
6293
|
+
if ("right" in node) {
|
|
6294
|
+
const chunk = getNestedIdentifiers(node.right);
|
|
6295
|
+
identifiers.push(...chunk);
|
|
6296
|
+
}
|
|
6297
|
+
if (node.type === AST_NODE_TYPES.Property) {
|
|
6298
|
+
const chunk = getNestedIdentifiers(node.value);
|
|
6299
|
+
identifiers.push(...chunk);
|
|
6300
|
+
}
|
|
6301
|
+
if (node.type === AST_NODE_TYPES.SpreadElement) {
|
|
6302
|
+
const chunk = getNestedIdentifiers(node.argument);
|
|
6303
|
+
identifiers.push(...chunk);
|
|
6304
|
+
}
|
|
6305
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
6306
|
+
identifiers.push(...getNestedIdentifiers(node.object));
|
|
6307
|
+
if (node.computed) identifiers.push(...getNestedIdentifiers(node.property));
|
|
6308
|
+
}
|
|
6309
|
+
if (node.type === AST_NODE_TYPES.UnaryExpression) {
|
|
6310
|
+
const chunk = getNestedIdentifiers(node.argument);
|
|
6311
|
+
identifiers.push(...chunk);
|
|
6312
|
+
}
|
|
6313
|
+
if (node.type === AST_NODE_TYPES.ChainExpression) {
|
|
6314
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
6315
|
+
identifiers.push(...chunk);
|
|
6316
|
+
}
|
|
6317
|
+
if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
|
|
6318
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
6319
|
+
identifiers.push(...chunk);
|
|
6320
|
+
}
|
|
6321
|
+
if (node.type === AST_NODE_TYPES.TSAsExpression) {
|
|
6322
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
6323
|
+
identifiers.push(...chunk);
|
|
6324
|
+
}
|
|
6325
|
+
if (node.type === AST_NODE_TYPES.TSSatisfiesExpression) {
|
|
6326
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
6327
|
+
identifiers.push(...chunk);
|
|
6328
|
+
}
|
|
6329
|
+
if (node.type === AST_NODE_TYPES.ConditionalExpression) {
|
|
6330
|
+
identifiers.push(...getNestedIdentifiers(node.test));
|
|
6331
|
+
identifiers.push(...getNestedIdentifiers(node.consequent));
|
|
6332
|
+
identifiers.push(...getNestedIdentifiers(node.alternate));
|
|
6333
|
+
}
|
|
6334
|
+
if (node.type === AST_NODE_TYPES.AwaitExpression) identifiers.push(...getNestedIdentifiers(node.argument));
|
|
6335
|
+
if (node.type === AST_NODE_TYPES.YieldExpression && node.argument != null) identifiers.push(...getNestedIdentifiers(node.argument));
|
|
6336
|
+
if (node.type === AST_NODE_TYPES.UpdateExpression) identifiers.push(...getNestedIdentifiers(node.argument));
|
|
6337
|
+
if (node.type === AST_NODE_TYPES.CallExpression || node.type === AST_NODE_TYPES.NewExpression) identifiers.push(...getNestedIdentifiers(node.callee));
|
|
6338
|
+
if (node.type === AST_NODE_TYPES.TaggedTemplateExpression) {
|
|
6339
|
+
identifiers.push(...getNestedIdentifiers(node.tag));
|
|
6340
|
+
identifiers.push(...getNestedIdentifiers(node.quasi));
|
|
6341
|
+
}
|
|
6342
|
+
if (node.type === AST_NODE_TYPES.ImportExpression) identifiers.push(...getNestedIdentifiers(node.source));
|
|
6343
|
+
if (node.type === AST_NODE_TYPES.TSTypeAssertion) identifiers.push(...getNestedIdentifiers(node.expression));
|
|
6344
|
+
if (node.type === AST_NODE_TYPES.TSInstantiationExpression) identifiers.push(...getNestedIdentifiers(node.expression));
|
|
6345
|
+
return identifiers;
|
|
6346
|
+
}
|
|
6347
|
+
|
|
6201
6348
|
//#endregion
|
|
6202
6349
|
//#region src/rules/set-state-in-effect/set-state-in-effect.ts
|
|
6203
6350
|
const RULE_NAME$4 = "set-state-in-effect";
|
|
@@ -6243,14 +6390,14 @@ function create$4(context) {
|
|
|
6243
6390
|
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectCall(node.parent);
|
|
6244
6391
|
}
|
|
6245
6392
|
function getCallName(node) {
|
|
6246
|
-
if (node.type === AST_NODE_TYPES.CallExpression) return
|
|
6247
|
-
return
|
|
6393
|
+
if (node.type === AST_NODE_TYPES.CallExpression) return Extract.fullyQualifiedName(node.callee, getText);
|
|
6394
|
+
return Extract.fullyQualifiedName(node, getText);
|
|
6248
6395
|
}
|
|
6249
6396
|
function getCallKind(node) {
|
|
6250
6397
|
return match(node).when(isUseStateCall, () => "useState").when(isUseEffectCall, () => "useEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
|
|
6251
6398
|
}
|
|
6252
6399
|
function getFunctionKind(node) {
|
|
6253
|
-
const parent =
|
|
6400
|
+
const parent = Traverse.findParent(node, not(Check.isTypeExpression)) ?? node.parent;
|
|
6254
6401
|
switch (true) {
|
|
6255
6402
|
case node.async:
|
|
6256
6403
|
case parent.type === AST_NODE_TYPES.CallExpression && isThenCall(parent): return "deferred";
|
|
@@ -6306,7 +6453,7 @@ function create$4(context) {
|
|
|
6306
6453
|
if (init == null) continue;
|
|
6307
6454
|
switch (true) {
|
|
6308
6455
|
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;
|
|
6456
|
+
case init.type === AST_NODE_TYPES.CallExpression && core.isUseRefCall(context, init): return true;
|
|
6310
6457
|
}
|
|
6311
6458
|
}
|
|
6312
6459
|
return false;
|
|
@@ -6334,7 +6481,7 @@ function create$4(context) {
|
|
|
6334
6481
|
case entry.kind === "deferred":
|
|
6335
6482
|
case entry.node.async: break;
|
|
6336
6483
|
case entry.node === setupFunction:
|
|
6337
|
-
case entry.kind === "immediate" &&
|
|
6484
|
+
case entry.kind === "immediate" && Traverse.findParent(entry.node, Check.isFunction) === setupFunction: {
|
|
6338
6485
|
const args0 = node.arguments.at(0);
|
|
6339
6486
|
if (args0 == null) return;
|
|
6340
6487
|
function isArgumentUsingRefValue(context, node) {
|
|
@@ -6342,12 +6489,12 @@ function create$4(context) {
|
|
|
6342
6489
|
switch (n.type) {
|
|
6343
6490
|
case AST_NODE_TYPES.Identifier: return isInitializedFromRef(n.name, context.sourceCode.getScope(n));
|
|
6344
6491
|
case AST_NODE_TYPES.MemberExpression: return isUsingRefValue(n.object);
|
|
6345
|
-
case AST_NODE_TYPES.CallExpression: return isUsingRefValue(n.callee) ||
|
|
6492
|
+
case AST_NODE_TYPES.CallExpression: return isUsingRefValue(n.callee) || getNestedIdentifiers(n).some(isUsingRefValue);
|
|
6346
6493
|
default: return false;
|
|
6347
6494
|
}
|
|
6348
6495
|
};
|
|
6349
6496
|
if (isUsingRefValue(node)) return true;
|
|
6350
|
-
return
|
|
6497
|
+
return Check.isFunction(node) && context.sourceCode.getScope(node.body).references.some((r) => isUsingRefValue(r.identifier));
|
|
6351
6498
|
}
|
|
6352
6499
|
if (isArgumentUsingRefValue(context, args0)) return;
|
|
6353
6500
|
context.report({
|
|
@@ -6358,14 +6505,14 @@ function create$4(context) {
|
|
|
6358
6505
|
return;
|
|
6359
6506
|
}
|
|
6360
6507
|
default: {
|
|
6361
|
-
const init =
|
|
6508
|
+
const init = Traverse.findParent(node, isHookDecl)?.init;
|
|
6362
6509
|
if (init == null) getOrInsertComputed(setStateCallsByFn, entry.node, () => []).push(node);
|
|
6363
6510
|
else getOrInsertComputed(setStateInHookCallbacks, init, () => []).push(node);
|
|
6364
6511
|
}
|
|
6365
6512
|
}
|
|
6366
6513
|
}).with("useEffect", () => {
|
|
6367
|
-
if (
|
|
6368
|
-
setupFnIds.push(...
|
|
6514
|
+
if (Check.isFunction(node.arguments.at(0))) return;
|
|
6515
|
+
setupFnIds.push(...getNestedIdentifiers(node));
|
|
6369
6516
|
}).with("other", () => {
|
|
6370
6517
|
if (entry.node !== setupFunction) return;
|
|
6371
6518
|
trackedFnCalls.push(node);
|
|
@@ -6379,14 +6526,14 @@ function create$4(context) {
|
|
|
6379
6526
|
const parent = node.parent.parent;
|
|
6380
6527
|
if (parent.type !== AST_NODE_TYPES.CallExpression) break;
|
|
6381
6528
|
if (!core.isUseMemoCall(context, parent)) break;
|
|
6382
|
-
const init =
|
|
6529
|
+
const init = Traverse.findParent(parent, isHookDecl)?.init;
|
|
6383
6530
|
if (init != null) getOrInsertComputed(setStateInEffectArg, init, () => []).push(node);
|
|
6384
6531
|
break;
|
|
6385
6532
|
}
|
|
6386
6533
|
case AST_NODE_TYPES.CallExpression:
|
|
6387
6534
|
if (node !== node.parent.arguments.at(0)) break;
|
|
6388
6535
|
if (core.isUseCallbackCall(context, node.parent)) {
|
|
6389
|
-
const init =
|
|
6536
|
+
const init = Traverse.findParent(node.parent, isHookDecl)?.init;
|
|
6390
6537
|
if (init != null) getOrInsertComputed(setStateInEffectArg, init, () => []).push(node);
|
|
6391
6538
|
break;
|
|
6392
6539
|
}
|
|
@@ -6499,13 +6646,13 @@ function create$3(context) {
|
|
|
6499
6646
|
function isInsideEventHandler(node, stopAt) {
|
|
6500
6647
|
let current = node.parent;
|
|
6501
6648
|
while (current != null && current !== stopAt) {
|
|
6502
|
-
if (
|
|
6649
|
+
if (Check.isFunction(current) && current !== stopAt) return true;
|
|
6503
6650
|
current = current.parent;
|
|
6504
6651
|
}
|
|
6505
6652
|
return false;
|
|
6506
6653
|
}
|
|
6507
6654
|
function isComponentOrHookLikeFunction(node) {
|
|
6508
|
-
const id =
|
|
6655
|
+
const id = core.getFunctionId(node);
|
|
6509
6656
|
if (id == null) return false;
|
|
6510
6657
|
if (id.type === AST_NODE_TYPES.Identifier) return core.isFunctionComponentName(id.name) || core.isHookName(id.name);
|
|
6511
6658
|
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);
|
|
@@ -6513,7 +6660,7 @@ function create$3(context) {
|
|
|
6513
6660
|
}
|
|
6514
6661
|
function getFunctionKind(node) {
|
|
6515
6662
|
if (isComponentOrHookLikeFunction(node)) return "component";
|
|
6516
|
-
const parent =
|
|
6663
|
+
const parent = Traverse.findParent(node, not(Check.isTypeExpression)) ?? node.parent;
|
|
6517
6664
|
if (parent.type === AST_NODE_TYPES.CallExpression && parent.callee !== node) return "callback";
|
|
6518
6665
|
return "other";
|
|
6519
6666
|
}
|
|
@@ -6599,7 +6746,7 @@ function create$2(context) {
|
|
|
6599
6746
|
return merge(hCollector.visitor, cCollector.visitor, {
|
|
6600
6747
|
CallExpression(node) {
|
|
6601
6748
|
if (!isEvalCall(node)) return;
|
|
6602
|
-
const func =
|
|
6749
|
+
const func = Traverse.findParent(node, Check.isFunction);
|
|
6603
6750
|
if (func == null) return;
|
|
6604
6751
|
evalCalls.push({
|
|
6605
6752
|
func,
|
|
@@ -6638,7 +6785,7 @@ function create$2(context) {
|
|
|
6638
6785
|
}
|
|
6639
6786
|
},
|
|
6640
6787
|
WithStatement(node) {
|
|
6641
|
-
const func =
|
|
6788
|
+
const func = Traverse.findParent(node, Check.isFunction);
|
|
6642
6789
|
if (func == null) return;
|
|
6643
6790
|
withStmts.push({
|
|
6644
6791
|
func,
|
|
@@ -6670,7 +6817,7 @@ function create$1(context) {
|
|
|
6670
6817
|
return merge({ CallExpression(node) {
|
|
6671
6818
|
if (!core.isUseMemoCall(context, node)) return;
|
|
6672
6819
|
let parent = node.parent;
|
|
6673
|
-
while (
|
|
6820
|
+
while (Check.isTypeExpression(parent)) parent = parent.parent;
|
|
6674
6821
|
if (!(parent.type === AST_NODE_TYPES.VariableDeclarator || parent.type === AST_NODE_TYPES.AssignmentExpression || parent.type === AST_NODE_TYPES.AssignmentPattern || parent.type === AST_NODE_TYPES.Property || parent.type === AST_NODE_TYPES.ReturnStatement || parent.type === AST_NODE_TYPES.JSXExpressionContainer || parent.type === AST_NODE_TYPES.CallExpression || parent.type === AST_NODE_TYPES.NewExpression || parent.type === AST_NODE_TYPES.ArrayExpression || parent.type === AST_NODE_TYPES.ConditionalExpression || parent.type === AST_NODE_TYPES.LogicalExpression || parent.type === AST_NODE_TYPES.SequenceExpression || parent.type === AST_NODE_TYPES.SpreadElement || parent.type === AST_NODE_TYPES.TemplateLiteral || parent.type === AST_NODE_TYPES.BinaryExpression || parent.type === AST_NODE_TYPES.UnaryExpression || parent.type === AST_NODE_TYPES.MemberExpression || parent.type === AST_NODE_TYPES.TaggedTemplateExpression || parent.type === AST_NODE_TYPES.ChainExpression || parent.type === AST_NODE_TYPES.ArrowFunctionExpression)) {
|
|
6675
6822
|
context.report({
|
|
6676
6823
|
messageId: "notAssignedToVariable",
|
|
@@ -6680,10 +6827,10 @@ function create$1(context) {
|
|
|
6680
6827
|
}
|
|
6681
6828
|
const [callbackArg] = node.arguments;
|
|
6682
6829
|
if (callbackArg == null) return;
|
|
6683
|
-
if (!
|
|
6830
|
+
if (!Check.isFunction(callbackArg)) return;
|
|
6684
6831
|
if (callbackArg.type === AST_NODE_TYPES.ArrowFunctionExpression && callbackArg.body.type !== AST_NODE_TYPES.BlockStatement) return;
|
|
6685
6832
|
if (callbackArg.body.type !== AST_NODE_TYPES.BlockStatement) return;
|
|
6686
|
-
const returnStatements =
|
|
6833
|
+
const returnStatements = getNestedReturnStatements(callbackArg);
|
|
6687
6834
|
if (returnStatements.length === 0) {
|
|
6688
6835
|
context.report({
|
|
6689
6836
|
messageId: "missingReturnValue",
|
|
@@ -6698,6 +6845,101 @@ function create$1(context) {
|
|
|
6698
6845
|
} });
|
|
6699
6846
|
}
|
|
6700
6847
|
|
|
6848
|
+
//#endregion
|
|
6849
|
+
//#region src/rules/use-state/lib.ts
|
|
6850
|
+
/**
|
|
6851
|
+
* Get all nested expressions of type T in an expression like node
|
|
6852
|
+
* @param type The type of the expression to retrieve within the node
|
|
6853
|
+
* @returns A partially applied function bound to a predicate of type AST. The returned function can be called passing a
|
|
6854
|
+
* node, and it will return an array of all nested expressions of type AST.
|
|
6855
|
+
*/
|
|
6856
|
+
function getNestedExpressionsOfType(type) {
|
|
6857
|
+
const isNodeOfType = is(type);
|
|
6858
|
+
const recurse = (node) => {
|
|
6859
|
+
const expressions = [];
|
|
6860
|
+
if (isNodeOfType(node)) expressions.push(node);
|
|
6861
|
+
if ("arguments" in node) {
|
|
6862
|
+
const chunk = node.arguments.flatMap(recurse);
|
|
6863
|
+
expressions.push(...chunk);
|
|
6864
|
+
}
|
|
6865
|
+
if ("expression" in node && node.expression !== true && node.expression !== false) {
|
|
6866
|
+
const chunk = recurse(node.expression);
|
|
6867
|
+
expressions.push(...chunk);
|
|
6868
|
+
}
|
|
6869
|
+
if ("left" in node) {
|
|
6870
|
+
const chunk = recurse(node.left);
|
|
6871
|
+
expressions.push(...chunk);
|
|
6872
|
+
}
|
|
6873
|
+
if ("right" in node) {
|
|
6874
|
+
const chunk = recurse(node.right);
|
|
6875
|
+
expressions.push(...chunk);
|
|
6876
|
+
}
|
|
6877
|
+
if ("test" in node && node.test != null) {
|
|
6878
|
+
const chunk = recurse(node.test);
|
|
6879
|
+
expressions.push(...chunk);
|
|
6880
|
+
}
|
|
6881
|
+
if ("consequent" in node) {
|
|
6882
|
+
const chunk = Array.isArray(node.consequent) ? node.consequent.flatMap(recurse) : recurse(node.consequent);
|
|
6883
|
+
expressions.push(...chunk);
|
|
6884
|
+
}
|
|
6885
|
+
if ("alternate" in node && node.alternate != null) {
|
|
6886
|
+
const chunk = Array.isArray(node.alternate) ? node.alternate.flatMap(recurse) : recurse(node.alternate);
|
|
6887
|
+
expressions.push(...chunk);
|
|
6888
|
+
}
|
|
6889
|
+
if ("elements" in node) {
|
|
6890
|
+
const chunk = node.elements.filter((x) => x != null).flatMap(recurse);
|
|
6891
|
+
expressions.push(...chunk);
|
|
6892
|
+
}
|
|
6893
|
+
if ("properties" in node) {
|
|
6894
|
+
const chunk = node.properties.flatMap(recurse);
|
|
6895
|
+
expressions.push(...chunk);
|
|
6896
|
+
}
|
|
6897
|
+
if ("expressions" in node) {
|
|
6898
|
+
const chunk = node.expressions.flatMap(recurse);
|
|
6899
|
+
expressions.push(...chunk);
|
|
6900
|
+
}
|
|
6901
|
+
if (node.type === AST_NODE_TYPES.Property) {
|
|
6902
|
+
const chunk = recurse(node.value);
|
|
6903
|
+
expressions.push(...chunk);
|
|
6904
|
+
}
|
|
6905
|
+
if (node.type === AST_NODE_TYPES.SpreadElement) {
|
|
6906
|
+
const chunk = recurse(node.argument);
|
|
6907
|
+
expressions.push(...chunk);
|
|
6908
|
+
}
|
|
6909
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
6910
|
+
expressions.push(...recurse(node.object));
|
|
6911
|
+
if (node.computed) expressions.push(...recurse(node.property));
|
|
6912
|
+
}
|
|
6913
|
+
if (node.type === AST_NODE_TYPES.UnaryExpression) {
|
|
6914
|
+
const chunk = recurse(node.argument);
|
|
6915
|
+
expressions.push(...chunk);
|
|
6916
|
+
}
|
|
6917
|
+
if (node.type === AST_NODE_TYPES.AwaitExpression) expressions.push(...recurse(node.argument));
|
|
6918
|
+
if (node.type === AST_NODE_TYPES.YieldExpression && node.argument != null) expressions.push(...recurse(node.argument));
|
|
6919
|
+
if (node.type === AST_NODE_TYPES.UpdateExpression) expressions.push(...recurse(node.argument));
|
|
6920
|
+
if (node.type === AST_NODE_TYPES.CallExpression || node.type === AST_NODE_TYPES.NewExpression) expressions.push(...recurse(node.callee));
|
|
6921
|
+
if (node.type === AST_NODE_TYPES.TaggedTemplateExpression) {
|
|
6922
|
+
expressions.push(...recurse(node.tag));
|
|
6923
|
+
expressions.push(...recurse(node.quasi));
|
|
6924
|
+
}
|
|
6925
|
+
if (node.type === AST_NODE_TYPES.ImportExpression) expressions.push(...recurse(node.source));
|
|
6926
|
+
return expressions;
|
|
6927
|
+
};
|
|
6928
|
+
return recurse;
|
|
6929
|
+
}
|
|
6930
|
+
/**
|
|
6931
|
+
* Get all nested new expressions in an expression like node
|
|
6932
|
+
* @param node The node to get the nested new expressions from
|
|
6933
|
+
* @returns All nested new expressions
|
|
6934
|
+
*/
|
|
6935
|
+
const getNestedNewExpressions = getNestedExpressionsOfType(AST_NODE_TYPES.NewExpression);
|
|
6936
|
+
/**
|
|
6937
|
+
* Get all nested call expressions in a expression like node
|
|
6938
|
+
* @param node The node to get the nested call expressions from
|
|
6939
|
+
* @returns All nested call expressions
|
|
6940
|
+
*/
|
|
6941
|
+
const getNestedCallExpressions = getNestedExpressionsOfType(AST_NODE_TYPES.CallExpression);
|
|
6942
|
+
|
|
6701
6943
|
//#endregion
|
|
6702
6944
|
//#region src/rules/use-state/use-state.ts
|
|
6703
6945
|
const RULE_NAME = "use-state";
|
|
@@ -6752,20 +6994,20 @@ function create(context) {
|
|
|
6752
6994
|
if (enforceLazyInitialization) {
|
|
6753
6995
|
const [useStateInput] = node.arguments;
|
|
6754
6996
|
if (useStateInput != null) {
|
|
6755
|
-
for (const expr of
|
|
6997
|
+
for (const expr of getNestedNewExpressions(useStateInput)) {
|
|
6756
6998
|
if (!("name" in expr.callee)) continue;
|
|
6757
6999
|
if (LAZY_INIT_ALLOW_LIST.includes(expr.callee.name)) continue;
|
|
6758
|
-
if (
|
|
7000
|
+
if (Traverse.findParent(expr, (n) => core.isUseCall(context, n)) != null) continue;
|
|
6759
7001
|
context.report({
|
|
6760
7002
|
messageId: "invalidInitialization",
|
|
6761
7003
|
node: expr
|
|
6762
7004
|
});
|
|
6763
7005
|
}
|
|
6764
|
-
for (const expr of
|
|
7006
|
+
for (const expr of getNestedCallExpressions(useStateInput)) {
|
|
6765
7007
|
if (!("name" in expr.callee)) continue;
|
|
6766
7008
|
if (core.isHookName(expr.callee.name)) continue;
|
|
6767
7009
|
if (LAZY_INIT_ALLOW_LIST.includes(expr.callee.name)) continue;
|
|
6768
|
-
if (
|
|
7010
|
+
if (Traverse.findParent(expr, (n) => core.isUseCall(context, n)) != null) continue;
|
|
6769
7011
|
context.report({
|
|
6770
7012
|
messageId: "invalidInitialization",
|
|
6771
7013
|
node: expr
|
|
@@ -6781,7 +7023,7 @@ function create(context) {
|
|
|
6781
7023
|
});
|
|
6782
7024
|
return;
|
|
6783
7025
|
}
|
|
6784
|
-
const id =
|
|
7026
|
+
const id = resolveEnclosingAssignmentTarget(node);
|
|
6785
7027
|
if (id?.type !== AST_NODE_TYPES.ArrayPattern) {
|
|
6786
7028
|
if (!enforceAssignment) return;
|
|
6787
7029
|
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.2-beta.0",
|
|
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",
|
|
@@ -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/core": "5.2.
|
|
50
|
-
"@eslint-react/eslint": "5.2.
|
|
51
|
-
"@eslint-react/
|
|
52
|
-
"@eslint-react/
|
|
53
|
-
"@eslint-react/
|
|
49
|
+
"@eslint-react/ast": "5.2.2-beta.0",
|
|
50
|
+
"@eslint-react/core": "5.2.2-beta.0",
|
|
51
|
+
"@eslint-react/eslint": "5.2.2-beta.0",
|
|
52
|
+
"@eslint-react/jsx": "5.2.2-beta.0",
|
|
53
|
+
"@eslint-react/var": "5.2.2-beta.0",
|
|
54
|
+
"@eslint-react/shared": "5.2.2-beta.0"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@types/react": "^19.2.14",
|
|
@@ -58,8 +59,8 @@
|
|
|
58
59
|
"eslint": "^10.2.0",
|
|
59
60
|
"tsdown": "^0.21.7",
|
|
60
61
|
"tsl-dx": "^0.10.3",
|
|
61
|
-
"@local/
|
|
62
|
-
"@local/
|
|
62
|
+
"@local/configs": "0.0.0",
|
|
63
|
+
"@local/eff": "3.0.0-beta.72"
|
|
63
64
|
},
|
|
64
65
|
"peerDependencies": {
|
|
65
66
|
"eslint": "^10.2.0",
|