eslint-plugin-react-x 2.3.8-next.1 → 2.3.9-next.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 +78 -16
- package/package.json +14 -14
package/dist/index.js
CHANGED
|
@@ -6,11 +6,12 @@ import { P, isMatching, match } from "ts-pattern";
|
|
|
6
6
|
import ts from "typescript";
|
|
7
7
|
import * as AST from "@eslint-react/ast";
|
|
8
8
|
import { findVariable, getChildScopes, getObjectType, getVariableDefinitionNode } from "@eslint-react/var";
|
|
9
|
-
import { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, JsxEmit, findParentJsxAttribute, getInstanceId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, isAssignmentToThisState, isCaptureOwnerStackCall, isChildrenCount, isChildrenForEach, isChildrenMap, isChildrenOnly, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUpdate, isCreateContextCall, isCreateElementCall, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRefCall, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInstanceIdEqual, isJsxFragmentElement, isJsxHostElement, isJsxText, isLazyCall, isReactHookCall, isReactHookName, isRenderMethodLike, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseCall, isUseCallbackCall, isUseContextCall, isUseMemoCall, isUseStateCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector } from "@eslint-react/core";
|
|
9
|
+
import { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, JsxEmit, findParentJsxAttribute, getInstanceId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, isAssignmentToThisState, isCaptureOwnerStackCall, isChildrenCount, isChildrenForEach, isChildrenMap, isChildrenOnly, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUpdate, isCreateContextCall, isCreateElementCall, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRefCall, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInstanceIdEqual, isJsxFragmentElement, isJsxHostElement, isJsxText, isLazyCall, isReactHookCall, isReactHookName, isRenderMethodLike, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseCall, isUseCallbackCall, isUseContextCall, isUseEffectLikeCall, isUseMemoCall, isUseStateCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector } from "@eslint-react/core";
|
|
10
10
|
import { constFalse, constTrue, flow, getOrElseUpdate, identity, unit } from "@eslint-react/eff";
|
|
11
11
|
import { compare } from "compare-versions";
|
|
12
12
|
import { getConstrainedTypeAtLocation, isTypeReadonly } from "@typescript-eslint/type-utils";
|
|
13
|
-
import { getStaticValue } from "@typescript-eslint/utils/ast-utils";
|
|
13
|
+
import { getStaticValue, isIdentifier, isVariableDeclarator } from "@typescript-eslint/utils/ast-utils";
|
|
14
|
+
import "@typescript-eslint/utils/ts-eslint";
|
|
14
15
|
import { getTypeImmutability, isImmutable, isReadonlyDeep, isReadonlyShallow, isUnknown } from "is-immutable-type";
|
|
15
16
|
import { camelCase } from "string-ts";
|
|
16
17
|
|
|
@@ -33,7 +34,7 @@ var __export = (all, symbols) => {
|
|
|
33
34
|
//#endregion
|
|
34
35
|
//#region package.json
|
|
35
36
|
var name$6 = "eslint-plugin-react-x";
|
|
36
|
-
var version = "2.3.
|
|
37
|
+
var version = "2.3.9-next.0";
|
|
37
38
|
|
|
38
39
|
//#endregion
|
|
39
40
|
//#region src/utils/create-rule.ts
|
|
@@ -2274,7 +2275,10 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
2274
2275
|
description: "Disallow unnecessary usage of `useCallback`.",
|
|
2275
2276
|
[Symbol.for("rule_features")]: RULE_FEATURES$16
|
|
2276
2277
|
},
|
|
2277
|
-
messages: {
|
|
2278
|
+
messages: {
|
|
2279
|
+
noUnnecessaryUseCallback: "An 'useCallback' with empty deps and no references to the component scope may be unnecessary.",
|
|
2280
|
+
noUnnecessaryUseCallbackInsideUseEffect: "{{name}} is only used inside 1 useEffect, which may be unnecessary. You can move the computation into useEffect directly and merge the dependency arrays."
|
|
2281
|
+
},
|
|
2278
2282
|
schema: []
|
|
2279
2283
|
},
|
|
2280
2284
|
name: RULE_NAME$18,
|
|
@@ -2285,6 +2289,7 @@ function create$18(context) {
|
|
|
2285
2289
|
if (!context.sourceCode.text.includes("useCallback")) return {};
|
|
2286
2290
|
return { CallExpression(node) {
|
|
2287
2291
|
if (!isUseCallbackCall(node)) return;
|
|
2292
|
+
const checkForUsageInsideUseEffectReport = checkForUsageInsideUseEffect$1(context.sourceCode, node);
|
|
2288
2293
|
const initialScope = context.sourceCode.getScope(node);
|
|
2289
2294
|
const component = context.sourceCode.getScope(node).block;
|
|
2290
2295
|
if (!AST.isFunction(component)) return;
|
|
@@ -2294,7 +2299,10 @@ function create$18(context) {
|
|
|
2294
2299
|
const variableNode = getVariableDefinitionNode(findVariable(n.name, initialScope), 0);
|
|
2295
2300
|
if (variableNode?.type !== AST_NODE_TYPES.ArrayExpression) return false;
|
|
2296
2301
|
return variableNode.elements.length === 0;
|
|
2297
|
-
}).otherwise(() => false))
|
|
2302
|
+
}).otherwise(() => false)) {
|
|
2303
|
+
report(context)(checkForUsageInsideUseEffectReport);
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2298
2306
|
const arg0Node = match(arg0).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
|
|
2299
2307
|
if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) return n.body;
|
|
2300
2308
|
return n;
|
|
@@ -2304,12 +2312,34 @@ function create$18(context) {
|
|
|
2304
2312
|
return variableNode;
|
|
2305
2313
|
}).otherwise(() => null);
|
|
2306
2314
|
if (arg0Node == null) return;
|
|
2307
|
-
if (!getChildScopes(context.sourceCode.getScope(arg0Node)).flatMap((x) => x.references).some((x) => x.resolved?.scope.block === component))
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2315
|
+
if (!getChildScopes(context.sourceCode.getScope(arg0Node)).flatMap((x) => x.references).some((x) => x.resolved?.scope.block === component)) {
|
|
2316
|
+
context.report({
|
|
2317
|
+
messageId: "noUnnecessaryUseCallback",
|
|
2318
|
+
node
|
|
2319
|
+
});
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
report(context)(checkForUsageInsideUseEffectReport);
|
|
2311
2323
|
} };
|
|
2312
2324
|
}
|
|
2325
|
+
function checkForUsageInsideUseEffect$1(sourceCode, node) {
|
|
2326
|
+
if (!/use\w*Effect/u.test(sourceCode.text)) return;
|
|
2327
|
+
if (!isVariableDeclarator(node.parent)) return;
|
|
2328
|
+
if (!isIdentifier(node.parent.id)) return;
|
|
2329
|
+
const usages = (sourceCode.getDeclaredVariables(node.parent)[0]?.references ?? []).filter((ref) => !(ref.init ?? false));
|
|
2330
|
+
const effectSet = /* @__PURE__ */ new Set();
|
|
2331
|
+
for (const usage of usages) {
|
|
2332
|
+
const effect = AST.findParentNode(usage.identifier, isUseEffectLikeCall);
|
|
2333
|
+
if (effect == null) return;
|
|
2334
|
+
effectSet.add(effect);
|
|
2335
|
+
if (effectSet.size > 1) return;
|
|
2336
|
+
}
|
|
2337
|
+
return {
|
|
2338
|
+
messageId: "noUnnecessaryUseCallbackInsideUseEffect",
|
|
2339
|
+
node,
|
|
2340
|
+
data: { name: node.parent.id.name }
|
|
2341
|
+
};
|
|
2342
|
+
}
|
|
2313
2343
|
|
|
2314
2344
|
//#endregion
|
|
2315
2345
|
//#region src/rules/no-unnecessary-use-memo.ts
|
|
@@ -2322,7 +2352,10 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
2322
2352
|
description: "Disallow unnecessary usage of `useMemo`.",
|
|
2323
2353
|
[Symbol.for("rule_features")]: RULE_FEATURES$15
|
|
2324
2354
|
},
|
|
2325
|
-
messages: {
|
|
2355
|
+
messages: {
|
|
2356
|
+
noUnnecessaryUseMemo: "An 'useMemo' with empty deps and no references to the component scope may be unnecessary.",
|
|
2357
|
+
noUnnecessaryUseMemoInsideUseEffect: "{{name}} is only used inside 1 useEffect, which may be unnecessary. You can move the computation into useEffect directly and merge the dependency arrays."
|
|
2358
|
+
},
|
|
2326
2359
|
schema: []
|
|
2327
2360
|
},
|
|
2328
2361
|
name: RULE_NAME$17,
|
|
@@ -2334,16 +2367,23 @@ function create$17(context) {
|
|
|
2334
2367
|
return { CallExpression(node) {
|
|
2335
2368
|
const initialScope = context.sourceCode.getScope(node);
|
|
2336
2369
|
if (!isUseMemoCall(node)) return;
|
|
2370
|
+
const checkForUsageInsideUseEffectReport = checkForUsageInsideUseEffect(context.sourceCode, node);
|
|
2337
2371
|
const component = context.sourceCode.getScope(node).block;
|
|
2338
2372
|
if (!AST.isFunction(component)) return;
|
|
2339
2373
|
const [arg0, arg1] = node.arguments;
|
|
2340
2374
|
if (arg0 == null || arg1 == null) return;
|
|
2341
|
-
if (AST.isFunction(arg0) && [...AST.getNestedCallExpressions(arg0.body), ...AST.getNestedNewExpressions(arg0.body)].length > 0)
|
|
2375
|
+
if (AST.isFunction(arg0) && [...AST.getNestedCallExpressions(arg0.body), ...AST.getNestedNewExpressions(arg0.body)].length > 0) {
|
|
2376
|
+
report(context)(checkForUsageInsideUseEffectReport);
|
|
2377
|
+
return;
|
|
2378
|
+
}
|
|
2342
2379
|
if (!match(arg1).with({ type: AST_NODE_TYPES.ArrayExpression }, (n) => n.elements.length === 0).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
|
|
2343
2380
|
const variableNode = getVariableDefinitionNode(findVariable(n.name, initialScope), 0);
|
|
2344
2381
|
if (variableNode?.type !== AST_NODE_TYPES.ArrayExpression) return false;
|
|
2345
2382
|
return variableNode.elements.length === 0;
|
|
2346
|
-
}).otherwise(() => false))
|
|
2383
|
+
}).otherwise(() => false)) {
|
|
2384
|
+
report(context)(checkForUsageInsideUseEffectReport);
|
|
2385
|
+
return;
|
|
2386
|
+
}
|
|
2347
2387
|
const arg0Node = match(arg0).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
|
|
2348
2388
|
if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) return n.body;
|
|
2349
2389
|
return n;
|
|
@@ -2353,12 +2393,34 @@ function create$17(context) {
|
|
|
2353
2393
|
return variableNode;
|
|
2354
2394
|
}).otherwise(() => null);
|
|
2355
2395
|
if (arg0Node == null) return;
|
|
2356
|
-
if (!getChildScopes(context.sourceCode.getScope(arg0Node)).flatMap((x) => x.references).some((x) => x.resolved?.scope.block === component))
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2396
|
+
if (!getChildScopes(context.sourceCode.getScope(arg0Node)).flatMap((x) => x.references).some((x) => x.resolved?.scope.block === component)) {
|
|
2397
|
+
context.report({
|
|
2398
|
+
messageId: "noUnnecessaryUseMemo",
|
|
2399
|
+
node
|
|
2400
|
+
});
|
|
2401
|
+
return;
|
|
2402
|
+
}
|
|
2403
|
+
report(context)(checkForUsageInsideUseEffectReport);
|
|
2360
2404
|
} };
|
|
2361
2405
|
}
|
|
2406
|
+
function checkForUsageInsideUseEffect(sourceCode, node) {
|
|
2407
|
+
if (!/use\w*Effect/u.test(sourceCode.text)) return;
|
|
2408
|
+
if (!isVariableDeclarator(node.parent)) return;
|
|
2409
|
+
if (!isIdentifier(node.parent.id)) return;
|
|
2410
|
+
const usages = (sourceCode.getDeclaredVariables(node.parent)[0]?.references ?? []).filter((ref) => !(ref.init ?? false));
|
|
2411
|
+
const effectSet = /* @__PURE__ */ new Set();
|
|
2412
|
+
for (const usage of usages) {
|
|
2413
|
+
const effect = AST.findParentNode(usage.identifier, isUseEffectLikeCall);
|
|
2414
|
+
if (effect == null) return;
|
|
2415
|
+
effectSet.add(effect);
|
|
2416
|
+
if (effectSet.size > 1) return;
|
|
2417
|
+
}
|
|
2418
|
+
return {
|
|
2419
|
+
messageId: "noUnnecessaryUseMemoInsideUseEffect",
|
|
2420
|
+
node,
|
|
2421
|
+
data: { name: node.parent.id.name }
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2362
2424
|
|
|
2363
2425
|
//#endregion
|
|
2364
2426
|
//#region src/rules/no-unnecessary-use-prefix.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-x",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.9-next.0",
|
|
4
4
|
"description": "A set of composable ESLint rules for for libraries and frameworks that use React as a UI runtime.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -37,30 +37,30 @@
|
|
|
37
37
|
"./package.json"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@typescript-eslint/scope-manager": "^8.
|
|
41
|
-
"@typescript-eslint/type-utils": "^8.
|
|
42
|
-
"@typescript-eslint/types": "^8.
|
|
43
|
-
"@typescript-eslint/utils": "^8.
|
|
40
|
+
"@typescript-eslint/scope-manager": "^8.48.0",
|
|
41
|
+
"@typescript-eslint/type-utils": "^8.48.0",
|
|
42
|
+
"@typescript-eslint/types": "^8.48.0",
|
|
43
|
+
"@typescript-eslint/utils": "^8.48.0",
|
|
44
44
|
"compare-versions": "^6.1.1",
|
|
45
45
|
"is-immutable-type": "^5.0.1",
|
|
46
46
|
"string-ts": "^2.2.1",
|
|
47
47
|
"ts-api-utils": "^2.1.0",
|
|
48
48
|
"ts-pattern": "^5.9.0",
|
|
49
|
-
"@eslint-react/ast": "2.3.
|
|
50
|
-
"@eslint-react/
|
|
51
|
-
"@eslint-react/
|
|
52
|
-
"@eslint-react/
|
|
53
|
-
"@eslint-react/
|
|
49
|
+
"@eslint-react/ast": "2.3.9-next.0",
|
|
50
|
+
"@eslint-react/eff": "2.3.9-next.0",
|
|
51
|
+
"@eslint-react/core": "2.3.9-next.0",
|
|
52
|
+
"@eslint-react/shared": "2.3.9-next.0",
|
|
53
|
+
"@eslint-react/var": "2.3.9-next.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@types/react": "^19.2.
|
|
56
|
+
"@types/react": "^19.2.7",
|
|
57
57
|
"@types/react-dom": "^19.2.3",
|
|
58
|
-
"tsdown": "^0.16.
|
|
58
|
+
"tsdown": "^0.16.7",
|
|
59
59
|
"@local/configs": "0.0.0"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"eslint": "^9.
|
|
63
|
-
"typescript": "
|
|
62
|
+
"eslint": "^8.57.0 || ^9.0.0",
|
|
63
|
+
"typescript": ">=4.8.4 <6.0.0"
|
|
64
64
|
},
|
|
65
65
|
"engines": {
|
|
66
66
|
"node": ">=20.19.0"
|