@eslint-react/core 1.23.2-next.3 → 1.23.2-next.6
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.d.mts +22 -13
- package/dist/index.d.ts +22 -13
- package/dist/index.js +89 -77
- package/dist/index.mjs +90 -78
- package/package.json +11 -11
package/dist/index.d.mts
CHANGED
|
@@ -5,7 +5,6 @@ import * as _eslint_react_types from '@eslint-react/types';
|
|
|
5
5
|
import { RuleContext } from '@eslint-react/types';
|
|
6
6
|
import { TSESTree as TSESTree$1 } from '@typescript-eslint/utils';
|
|
7
7
|
import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
|
|
8
|
-
import { ESLintReactSettings } from '@eslint-react/shared';
|
|
9
8
|
import { Scope } from '@typescript-eslint/scope-manager';
|
|
10
9
|
import { SyntaxKind } from 'typescript';
|
|
11
10
|
|
|
@@ -80,14 +79,31 @@ type ERComponent = ERClassComponent | ERFunctionComponent;
|
|
|
80
79
|
declare function useComponentCollector(context: RuleContext, hint?: bigint): {
|
|
81
80
|
readonly ctx: {
|
|
82
81
|
readonly getAllComponents: (_: TSESTree.Program) => Map<string, ERFunctionComponent>;
|
|
83
|
-
readonly getCurrentFunction: () => O.Option<
|
|
84
|
-
|
|
82
|
+
readonly getCurrentFunction: () => O.Option<{
|
|
83
|
+
key: string;
|
|
84
|
+
node: AST.TSESTreeFunction;
|
|
85
|
+
hookCalls: TSESTree.CallExpression[];
|
|
86
|
+
isComponent: boolean;
|
|
87
|
+
}>;
|
|
88
|
+
readonly getCurrentFunctionStack: () => {
|
|
89
|
+
key: string;
|
|
90
|
+
node: AST.TSESTreeFunction;
|
|
91
|
+
hookCalls: TSESTree.CallExpression[];
|
|
92
|
+
isComponent: boolean;
|
|
93
|
+
}[];
|
|
85
94
|
};
|
|
86
95
|
readonly listeners: {
|
|
87
96
|
readonly ":function[type]": (node: AST.TSESTreeFunction) => void;
|
|
88
|
-
readonly ":function[type]:exit": () =>
|
|
97
|
+
readonly ":function[type]:exit": () => {
|
|
98
|
+
key: string;
|
|
99
|
+
node: AST.TSESTreeFunction;
|
|
100
|
+
hookCalls: TSESTree.CallExpression[];
|
|
101
|
+
isComponent: boolean;
|
|
102
|
+
} | undefined;
|
|
89
103
|
readonly "ArrowFunctionExpression[type][body.type!='BlockStatement']": () => void;
|
|
90
|
-
readonly "AssignmentExpression[type][operator='='][left.type='MemberExpression'][left.property.name='displayName']": (node: TSESTree.
|
|
104
|
+
readonly "AssignmentExpression[type][operator='='][left.type='MemberExpression'][left.property.name='displayName']": (node: TSESTree.AssignmentExpression & {
|
|
105
|
+
left: TSESTree.MemberExpression;
|
|
106
|
+
}) => void;
|
|
91
107
|
readonly "CallExpression[type]:exit": (node: TSESTree.CallExpression) => void;
|
|
92
108
|
readonly "ReturnStatement[type]": (node: TSESTree.ReturnStatement) => void;
|
|
93
109
|
};
|
|
@@ -329,14 +345,7 @@ type IsCallFromReactMember = {
|
|
|
329
345
|
};
|
|
330
346
|
declare function isCallFromReactMember(pragmaMemberName: string, name: string): IsCallFromReactMember;
|
|
331
347
|
|
|
332
|
-
|
|
333
|
-
* Check if an identifier is initialized from React
|
|
334
|
-
* @param name The top-level identifier's name
|
|
335
|
-
* @param initialScope Initial scope to search for the identifier
|
|
336
|
-
* @param settings ESLint React settings
|
|
337
|
-
* @returns Whether the identifier is initialized from React
|
|
338
|
-
*/
|
|
339
|
-
declare function isInitializedFromReact(name: string, initialScope: Scope, settings: ESLintReactSettings): boolean;
|
|
348
|
+
declare function isInitializedFromReact(name: string, initialScope: Scope, importSource?: string): boolean;
|
|
340
349
|
|
|
341
350
|
/**********************************************
|
|
342
351
|
* DO NOT MODIFY THIS FILE MANUALLY *
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ import * as _eslint_react_types from '@eslint-react/types';
|
|
|
5
5
|
import { RuleContext } from '@eslint-react/types';
|
|
6
6
|
import { TSESTree as TSESTree$1 } from '@typescript-eslint/utils';
|
|
7
7
|
import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
|
|
8
|
-
import { ESLintReactSettings } from '@eslint-react/shared';
|
|
9
8
|
import { Scope } from '@typescript-eslint/scope-manager';
|
|
10
9
|
import { SyntaxKind } from 'typescript';
|
|
11
10
|
|
|
@@ -80,14 +79,31 @@ type ERComponent = ERClassComponent | ERFunctionComponent;
|
|
|
80
79
|
declare function useComponentCollector(context: RuleContext, hint?: bigint): {
|
|
81
80
|
readonly ctx: {
|
|
82
81
|
readonly getAllComponents: (_: TSESTree.Program) => Map<string, ERFunctionComponent>;
|
|
83
|
-
readonly getCurrentFunction: () => O.Option<
|
|
84
|
-
|
|
82
|
+
readonly getCurrentFunction: () => O.Option<{
|
|
83
|
+
key: string;
|
|
84
|
+
node: AST.TSESTreeFunction;
|
|
85
|
+
hookCalls: TSESTree.CallExpression[];
|
|
86
|
+
isComponent: boolean;
|
|
87
|
+
}>;
|
|
88
|
+
readonly getCurrentFunctionStack: () => {
|
|
89
|
+
key: string;
|
|
90
|
+
node: AST.TSESTreeFunction;
|
|
91
|
+
hookCalls: TSESTree.CallExpression[];
|
|
92
|
+
isComponent: boolean;
|
|
93
|
+
}[];
|
|
85
94
|
};
|
|
86
95
|
readonly listeners: {
|
|
87
96
|
readonly ":function[type]": (node: AST.TSESTreeFunction) => void;
|
|
88
|
-
readonly ":function[type]:exit": () =>
|
|
97
|
+
readonly ":function[type]:exit": () => {
|
|
98
|
+
key: string;
|
|
99
|
+
node: AST.TSESTreeFunction;
|
|
100
|
+
hookCalls: TSESTree.CallExpression[];
|
|
101
|
+
isComponent: boolean;
|
|
102
|
+
} | undefined;
|
|
89
103
|
readonly "ArrowFunctionExpression[type][body.type!='BlockStatement']": () => void;
|
|
90
|
-
readonly "AssignmentExpression[type][operator='='][left.type='MemberExpression'][left.property.name='displayName']": (node: TSESTree.
|
|
104
|
+
readonly "AssignmentExpression[type][operator='='][left.type='MemberExpression'][left.property.name='displayName']": (node: TSESTree.AssignmentExpression & {
|
|
105
|
+
left: TSESTree.MemberExpression;
|
|
106
|
+
}) => void;
|
|
91
107
|
readonly "CallExpression[type]:exit": (node: TSESTree.CallExpression) => void;
|
|
92
108
|
readonly "ReturnStatement[type]": (node: TSESTree.ReturnStatement) => void;
|
|
93
109
|
};
|
|
@@ -329,14 +345,7 @@ type IsCallFromReactMember = {
|
|
|
329
345
|
};
|
|
330
346
|
declare function isCallFromReactMember(pragmaMemberName: string, name: string): IsCallFromReactMember;
|
|
331
347
|
|
|
332
|
-
|
|
333
|
-
* Check if an identifier is initialized from React
|
|
334
|
-
* @param name The top-level identifier's name
|
|
335
|
-
* @param initialScope Initial scope to search for the identifier
|
|
336
|
-
* @param settings ESLint React settings
|
|
337
|
-
* @returns Whether the identifier is initialized from React
|
|
338
|
-
*/
|
|
339
|
-
declare function isInitializedFromReact(name: string, initialScope: Scope, settings: ESLintReactSettings): boolean;
|
|
348
|
+
declare function isInitializedFromReact(name: string, initialScope: Scope, importSource?: string): boolean;
|
|
340
349
|
|
|
341
350
|
/**********************************************
|
|
342
351
|
* DO NOT MODIFY THIS FILE MANUALLY *
|
package/dist/index.js
CHANGED
|
@@ -50,34 +50,51 @@ function getElementRepresentName(node, context) {
|
|
|
50
50
|
// src/utils/get-id.ts
|
|
51
51
|
var id = 0n;
|
|
52
52
|
var getId = () => (id++).toString();
|
|
53
|
-
function isInitializedFromReact(name, initialScope,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
function isInitializedFromReact(name, initialScope, importSource = "react") {
|
|
54
|
+
return name.toLowerCase() === "react" || VAR__namespace.isInitializedFromSource(
|
|
55
|
+
name,
|
|
56
|
+
importSource,
|
|
57
|
+
initialScope
|
|
58
|
+
);
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
// src/utils/is-from-react.ts
|
|
61
62
|
function isFromReact(name) {
|
|
62
63
|
return (node, context) => {
|
|
63
|
-
const settings = shared.
|
|
64
|
+
const settings = shared.unsafeDecodeSettings(context.settings);
|
|
65
|
+
if (!settings.strictImportCheck) {
|
|
66
|
+
if (node.type === types.AST_NODE_TYPES.MemberExpression) {
|
|
67
|
+
return node.object.type === types.AST_NODE_TYPES.Identifier && node.property.type === types.AST_NODE_TYPES.Identifier && node.property.name === name;
|
|
68
|
+
}
|
|
69
|
+
return node.name === name;
|
|
70
|
+
}
|
|
64
71
|
const initialScope = context.sourceCode.getScope(node);
|
|
65
72
|
if (node.type === types.AST_NODE_TYPES.MemberExpression) {
|
|
66
|
-
return node.object.type === types.AST_NODE_TYPES.Identifier && node.property.type === types.AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name, initialScope, settings);
|
|
73
|
+
return node.object.type === types.AST_NODE_TYPES.Identifier && node.property.type === types.AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name, initialScope, settings.importSource);
|
|
74
|
+
}
|
|
75
|
+
if (node.name === name) {
|
|
76
|
+
return isInitializedFromReact(name, initialScope, settings.importSource);
|
|
67
77
|
}
|
|
68
|
-
if (node.name === name) return isInitializedFromReact(name, initialScope, settings);
|
|
69
78
|
return false;
|
|
70
79
|
};
|
|
71
80
|
}
|
|
72
81
|
function isFromReactMember(memberName, name) {
|
|
73
82
|
return (node, context) => {
|
|
74
|
-
const settings = shared.
|
|
83
|
+
const settings = shared.unsafeDecodeSettings(context.settings);
|
|
84
|
+
if (!settings.strictImportCheck) {
|
|
85
|
+
if (node.property.type !== types.AST_NODE_TYPES.Identifier || node.property.name !== name) return false;
|
|
86
|
+
if (node.object.type === types.AST_NODE_TYPES.Identifier && node.object.name === memberName) return true;
|
|
87
|
+
if (node.object.type === types.AST_NODE_TYPES.MemberExpression && node.object.object.type === types.AST_NODE_TYPES.Identifier && node.object.property.type === types.AST_NODE_TYPES.Identifier) {
|
|
88
|
+
return node.object.property.name === memberName;
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
75
92
|
const initialScope = context.sourceCode.getScope(node);
|
|
76
93
|
if (node.property.type !== types.AST_NODE_TYPES.Identifier || node.property.name !== name) return false;
|
|
77
94
|
if (node.object.type === types.AST_NODE_TYPES.Identifier && node.object.name === memberName) {
|
|
78
|
-
return isInitializedFromReact(node.object.name, initialScope, settings);
|
|
95
|
+
return isInitializedFromReact(node.object.name, initialScope, settings.importSource);
|
|
79
96
|
}
|
|
80
|
-
if (node.object.type === types.AST_NODE_TYPES.MemberExpression && node.object.object.type === types.AST_NODE_TYPES.Identifier && isInitializedFromReact(node.object.object.name, initialScope, settings) && node.object.property.type === types.AST_NODE_TYPES.Identifier) {
|
|
97
|
+
if (node.object.type === types.AST_NODE_TYPES.MemberExpression && node.object.object.type === types.AST_NODE_TYPES.Identifier && isInitializedFromReact(node.object.object.name, initialScope, settings.importSource) && node.object.property.type === types.AST_NODE_TYPES.Identifier) {
|
|
81
98
|
return node.object.property.name === memberName;
|
|
82
99
|
}
|
|
83
100
|
return false;
|
|
@@ -132,8 +149,8 @@ var isMemoCall = isReactAPICallWithName("memo");
|
|
|
132
149
|
function isInsideCreateElementProps(node, context) {
|
|
133
150
|
return eff.F.pipe(
|
|
134
151
|
eff.O.Do,
|
|
135
|
-
eff.O.bind("call", () => AST9__namespace.
|
|
136
|
-
eff.O.bind("prop", () => AST9__namespace.
|
|
152
|
+
eff.O.bind("call", () => AST9__namespace.findParentNodeGuard(node, isCreateElementCall(context))),
|
|
153
|
+
eff.O.bind("prop", () => AST9__namespace.findParentNodeGuard(node, AST9__namespace.is(types.AST_NODE_TYPES.ObjectExpression))),
|
|
137
154
|
eff.O.bind("arg1", ({ call }) => eff.O.fromNullable(call.arguments[1])),
|
|
138
155
|
eff.O.exists(({ arg1, prop }) => prop === arg1)
|
|
139
156
|
);
|
|
@@ -172,14 +189,14 @@ function isReactHookCall(node) {
|
|
|
172
189
|
return false;
|
|
173
190
|
}
|
|
174
191
|
function isReactHookCallWithName(node, context) {
|
|
175
|
-
const settings = shared.
|
|
192
|
+
const settings = shared.unsafeDecodeSettings(context.settings);
|
|
176
193
|
return (name) => {
|
|
177
194
|
const initialScope = context.sourceCode.getScope(node);
|
|
178
195
|
switch (true) {
|
|
179
196
|
case (node.callee.type === types.AST_NODE_TYPES.Identifier && node.callee.name === name):
|
|
180
|
-
return isInitializedFromReact(name, initialScope, settings);
|
|
197
|
+
return !settings.strictImportCheck || isInitializedFromReact(name, initialScope, settings.importSource);
|
|
181
198
|
case (node.callee.type === types.AST_NODE_TYPES.MemberExpression && node.callee.property.type === types.AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object):
|
|
182
|
-
return isInitializedFromReact(node.callee.object.name, initialScope, settings);
|
|
199
|
+
return !settings.strictImportCheck || isInitializedFromReact(node.callee.object.name, initialScope, settings.importSource);
|
|
183
200
|
default:
|
|
184
201
|
return false;
|
|
185
202
|
}
|
|
@@ -198,14 +215,14 @@ function isReactHookCallWithNameLoose(node) {
|
|
|
198
215
|
};
|
|
199
216
|
}
|
|
200
217
|
function isReactHookCallWithNameAlias(name, context, alias) {
|
|
201
|
-
const settings = shared.
|
|
218
|
+
const settings = shared.unsafeDecodeSettings(context);
|
|
202
219
|
return (node) => {
|
|
203
220
|
const initialScope = context.sourceCode.getScope(node);
|
|
204
221
|
switch (true) {
|
|
205
222
|
case (node.callee.type === types.AST_NODE_TYPES.Identifier && node.callee.name === name):
|
|
206
|
-
return isInitializedFromReact(name, initialScope, settings);
|
|
223
|
+
return !settings.strictImportCheck || isInitializedFromReact(name, initialScope, settings.importSource);
|
|
207
224
|
case (node.callee.type === types.AST_NODE_TYPES.MemberExpression && node.callee.property.type === types.AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object):
|
|
208
|
-
return isInitializedFromReact(node.callee.object.name, initialScope, settings);
|
|
225
|
+
return !settings.strictImportCheck || isInitializedFromReact(node.callee.object.name, initialScope, settings.importSource);
|
|
209
226
|
default:
|
|
210
227
|
return alias.some(isReactHookCallWithNameLoose(node));
|
|
211
228
|
}
|
|
@@ -240,7 +257,7 @@ var isUseTransitionCall = eff.F.flip(isReactHookCallWithName)("useTransition");
|
|
|
240
257
|
|
|
241
258
|
// src/hook/hierarchy.ts
|
|
242
259
|
function isInsideReactHook(node) {
|
|
243
|
-
return eff.O.exists(AST9__namespace.
|
|
260
|
+
return eff.O.exists(AST9__namespace.findParentNodeGuard(node, AST9__namespace.isFunction), isReactHook);
|
|
244
261
|
}
|
|
245
262
|
function useHookCollector() {
|
|
246
263
|
const hooks = /* @__PURE__ */ new Map();
|
|
@@ -452,21 +469,18 @@ function isFunctionOfRenderMethod(node) {
|
|
|
452
469
|
return isClassComponent(node.parent.parent.parent);
|
|
453
470
|
}
|
|
454
471
|
function isInsideRenderMethod(node) {
|
|
455
|
-
return eff.O.isSome(AST9__namespace.
|
|
472
|
+
return eff.O.isSome(AST9__namespace.findParentNode(node, (node2) => {
|
|
456
473
|
return isRenderMethodLike(node2) && isClassComponent(node2.parent.parent);
|
|
457
474
|
}));
|
|
458
475
|
}
|
|
459
476
|
function hasNoneOrValidComponentName(node, context) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
);
|
|
477
|
+
const mbIdentifier = getFunctionComponentIdentifier(node, context);
|
|
478
|
+
if (eff.O.isNone(mbIdentifier)) {
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
const id2 = mbIdentifier.value;
|
|
482
|
+
const name = Array.isArray(id2) ? id2.at(-1)?.name : id2.name;
|
|
483
|
+
return !!name && isComponentName(name);
|
|
470
484
|
}
|
|
471
485
|
|
|
472
486
|
// src/component/component-collector.ts
|
|
@@ -487,7 +501,7 @@ function hasValidHierarchy(node, context, hint) {
|
|
|
487
501
|
return false;
|
|
488
502
|
}
|
|
489
503
|
return !eff.O.exists(
|
|
490
|
-
AST9__namespace.
|
|
504
|
+
AST9__namespace.findParentNode(
|
|
491
505
|
node,
|
|
492
506
|
AST9__namespace.isOneOf([
|
|
493
507
|
types.AST_NODE_TYPES.JSXExpressionContainer,
|
|
@@ -513,20 +527,20 @@ function getComponentFlag(initPath) {
|
|
|
513
527
|
function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
514
528
|
const jsxCtx = { getScope: (node) => context.sourceCode.getScope(node) };
|
|
515
529
|
const components = /* @__PURE__ */ new Map();
|
|
516
|
-
const
|
|
517
|
-
const getCurrentFunction = () => eff.O.fromNullable(
|
|
530
|
+
const functionEntries = [];
|
|
531
|
+
const getCurrentFunction = () => eff.O.fromNullable(functionEntries.at(-1));
|
|
518
532
|
const onFunctionEnter = (node) => {
|
|
519
533
|
const key = getId();
|
|
520
|
-
|
|
534
|
+
functionEntries.push({ key, node, hookCalls: [], isComponent: false });
|
|
521
535
|
};
|
|
522
536
|
const onFunctionExit = () => {
|
|
523
|
-
const
|
|
524
|
-
if (!key || !
|
|
525
|
-
const shouldDrop = AST9__namespace.getNestedReturnStatements(
|
|
526
|
-
return context.sourceCode.getScope(r).block ===
|
|
537
|
+
const { key, node, isComponent } = functionEntries.at(-1) ?? {};
|
|
538
|
+
if (!key || !node || !isComponent) return functionEntries.pop();
|
|
539
|
+
const shouldDrop = AST9__namespace.getNestedReturnStatements(node.body).slice().reverse().some((r) => {
|
|
540
|
+
return context.sourceCode.getScope(r).block === node && r.argument !== null && !JSX4__namespace.isJSXValue(r.argument, jsxCtx, hint);
|
|
527
541
|
});
|
|
528
542
|
if (shouldDrop) components.delete(key);
|
|
529
|
-
return
|
|
543
|
+
return functionEntries.pop();
|
|
530
544
|
};
|
|
531
545
|
const ctx = {
|
|
532
546
|
getAllComponents(_) {
|
|
@@ -534,21 +548,21 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
534
548
|
},
|
|
535
549
|
getCurrentFunction,
|
|
536
550
|
getCurrentFunctionStack() {
|
|
537
|
-
return [...
|
|
551
|
+
return [...functionEntries];
|
|
538
552
|
}
|
|
539
553
|
};
|
|
540
554
|
const listeners = {
|
|
541
555
|
":function[type]": onFunctionEnter,
|
|
542
556
|
":function[type]:exit": onFunctionExit,
|
|
543
557
|
"ArrowFunctionExpression[type][body.type!='BlockStatement']"() {
|
|
544
|
-
const
|
|
545
|
-
if (eff.O.isNone(
|
|
546
|
-
const
|
|
547
|
-
const { body } =
|
|
548
|
-
const isComponent = hasNoneOrValidComponentName(
|
|
558
|
+
const mbEntry = getCurrentFunction();
|
|
559
|
+
if (eff.O.isNone(mbEntry)) return;
|
|
560
|
+
const entry = mbEntry.value;
|
|
561
|
+
const { body } = entry.node;
|
|
562
|
+
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX4__namespace.isJSXValue(body, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
549
563
|
if (!isComponent) return;
|
|
550
|
-
const initPath = AST9__namespace.getFunctionInitPath(
|
|
551
|
-
const id2 = getFunctionComponentIdentifier(
|
|
564
|
+
const initPath = AST9__namespace.getFunctionInitPath(entry.node);
|
|
565
|
+
const id2 = getFunctionComponentIdentifier(entry.node, context);
|
|
552
566
|
const name = eff.O.flatMapNullable(id2, getComponentNameFromIdentifier);
|
|
553
567
|
const key = getId();
|
|
554
568
|
components.set(key, {
|
|
@@ -556,21 +570,20 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
556
570
|
id: id2,
|
|
557
571
|
kind: "function",
|
|
558
572
|
name,
|
|
559
|
-
node:
|
|
573
|
+
node: entry.node,
|
|
560
574
|
displayName: eff.O.none(),
|
|
561
575
|
flag: getComponentFlag(initPath),
|
|
562
576
|
hint,
|
|
563
|
-
hookCalls,
|
|
577
|
+
hookCalls: entry.hookCalls,
|
|
564
578
|
initPath
|
|
565
579
|
});
|
|
566
580
|
},
|
|
567
581
|
"AssignmentExpression[type][operator='='][left.type='MemberExpression'][left.property.name='displayName']"(node) {
|
|
568
|
-
if (node.type !== types.AST_NODE_TYPES.AssignmentExpression) return;
|
|
569
582
|
const { left, right } = node;
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
const component = Array.from(components.values()).findLast(({ name }) => eff.O.exists(name, (n) => n ===
|
|
583
|
+
const mbComponentName = tsPattern.match(left.object).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => eff.O.some(n.name)).otherwise(eff.O.none);
|
|
584
|
+
if (eff.O.isNone(mbComponentName)) return;
|
|
585
|
+
const componentName = mbComponentName.value;
|
|
586
|
+
const component = Array.from(components.values()).findLast(({ name }) => eff.O.exists(name, (n) => n === componentName));
|
|
574
587
|
if (!component) return;
|
|
575
588
|
components.set(component._, {
|
|
576
589
|
...component,
|
|
@@ -579,34 +592,33 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
579
592
|
},
|
|
580
593
|
"CallExpression[type]:exit"(node) {
|
|
581
594
|
if (!isReactHookCall(node)) return;
|
|
582
|
-
const
|
|
583
|
-
if (eff.O.isNone(
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
595
|
+
const mbEntry = getCurrentFunction();
|
|
596
|
+
if (eff.O.isNone(mbEntry)) return;
|
|
597
|
+
const entry = mbEntry.value;
|
|
598
|
+
functionEntries.pop();
|
|
599
|
+
functionEntries.push({ ...entry, hookCalls: [...entry.hookCalls, node] });
|
|
587
600
|
},
|
|
588
601
|
"ReturnStatement[type]"(node) {
|
|
589
|
-
const
|
|
590
|
-
if (eff.O.isNone(
|
|
591
|
-
const
|
|
592
|
-
|
|
593
|
-
const isComponent = hasNoneOrValidComponentName(currentFn, context) && JSX4__namespace.isJSXValue(node.argument, jsxCtx, hint) && hasValidHierarchy(currentFn, context, hint);
|
|
602
|
+
const mbEntry = getCurrentFunction();
|
|
603
|
+
if (eff.O.isNone(mbEntry)) return;
|
|
604
|
+
const entry = mbEntry.value;
|
|
605
|
+
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX4__namespace.isJSXValue(node.argument, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
594
606
|
if (!isComponent) return;
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
const initPath = AST9__namespace.getFunctionInitPath(
|
|
598
|
-
const id2 = getFunctionComponentIdentifier(
|
|
607
|
+
functionEntries.pop();
|
|
608
|
+
functionEntries.push({ ...entry, isComponent });
|
|
609
|
+
const initPath = AST9__namespace.getFunctionInitPath(entry.node);
|
|
610
|
+
const id2 = getFunctionComponentIdentifier(entry.node, context);
|
|
599
611
|
const name = eff.O.flatMapNullable(id2, getComponentNameFromIdentifier);
|
|
600
|
-
components.set(key, {
|
|
601
|
-
_: key,
|
|
612
|
+
components.set(entry.key, {
|
|
613
|
+
_: entry.key,
|
|
602
614
|
id: id2,
|
|
603
615
|
kind: "function",
|
|
604
616
|
name,
|
|
605
|
-
node:
|
|
617
|
+
node: entry.node,
|
|
606
618
|
displayName: eff.O.none(),
|
|
607
619
|
flag: getComponentFlag(initPath),
|
|
608
620
|
hint,
|
|
609
|
-
hookCalls,
|
|
621
|
+
hookCalls: entry.hookCalls,
|
|
610
622
|
initPath
|
|
611
623
|
});
|
|
612
624
|
}
|
|
@@ -617,10 +629,10 @@ function isSetupFunction(node) {
|
|
|
617
629
|
return node.parent?.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee !== node && node.parent.callee.type === types.AST_NODE_TYPES.Identifier && node.parent.arguments.at(0) === node && isUseEffectCallLoose(node.parent);
|
|
618
630
|
}
|
|
619
631
|
function isCleanupFunction(node) {
|
|
620
|
-
const nearestRet = eff.O.getOrNull(AST9__namespace.
|
|
632
|
+
const nearestRet = eff.O.getOrNull(AST9__namespace.findParentNodeGuard(node, AST9__namespace.is(types.AST_NODE_TYPES.ReturnStatement)));
|
|
621
633
|
if (!nearestRet) return false;
|
|
622
|
-
const nearestFunction = eff.O.getOrNull(AST9__namespace.
|
|
623
|
-
const nearestFunctionOfRet = eff.O.getOrNull(AST9__namespace.
|
|
634
|
+
const nearestFunction = eff.O.getOrNull(AST9__namespace.findParentNodeGuard(node, AST9__namespace.isFunction));
|
|
635
|
+
const nearestFunctionOfRet = eff.O.getOrNull(AST9__namespace.findParentNodeGuard(nearestRet, AST9__namespace.isFunction));
|
|
624
636
|
if (!nearestFunction || !nearestFunctionOfRet) return false;
|
|
625
637
|
return nearestFunction === nearestFunctionOfRet && isSetupFunction(nearestFunction);
|
|
626
638
|
}
|
|
@@ -644,7 +656,7 @@ function isDeclaredInRenderPropLoose(node) {
|
|
|
644
656
|
return true;
|
|
645
657
|
}
|
|
646
658
|
return eff.F.pipe(
|
|
647
|
-
AST9__namespace.
|
|
659
|
+
AST9__namespace.findParentNodeGuard(node, AST9__namespace.is(types.AST_NODE_TYPES.JSXExpressionContainer)),
|
|
648
660
|
eff.O.flatMapNullable((c) => c.parent),
|
|
649
661
|
eff.O.filter(AST9__namespace.is(types.AST_NODE_TYPES.JSXAttribute)),
|
|
650
662
|
eff.O.flatMapNullable((a) => a.name),
|
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { F, isString, O } from '@eslint-react/eff';
|
|
|
3
3
|
import * as JSX4 from '@eslint-react/jsx';
|
|
4
4
|
import { AST_NODE_TYPES } from '@typescript-eslint/types';
|
|
5
5
|
import { isMatching, P, match } from 'ts-pattern';
|
|
6
|
-
import { getSettingsFromContext } from '@eslint-react/shared';
|
|
6
|
+
import { getSettingsFromContext, unsafeDecodeSettings } from '@eslint-react/shared';
|
|
7
7
|
import * as VAR from '@eslint-react/var';
|
|
8
8
|
import { birecord } from '@eslint-react/types';
|
|
9
9
|
|
|
@@ -26,34 +26,51 @@ function getElementRepresentName(node, context) {
|
|
|
26
26
|
// src/utils/get-id.ts
|
|
27
27
|
var id = 0n;
|
|
28
28
|
var getId = () => (id++).toString();
|
|
29
|
-
function isInitializedFromReact(name, initialScope,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
function isInitializedFromReact(name, initialScope, importSource = "react") {
|
|
30
|
+
return name.toLowerCase() === "react" || VAR.isInitializedFromSource(
|
|
31
|
+
name,
|
|
32
|
+
importSource,
|
|
33
|
+
initialScope
|
|
34
|
+
);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
// src/utils/is-from-react.ts
|
|
37
38
|
function isFromReact(name) {
|
|
38
39
|
return (node, context) => {
|
|
39
|
-
const settings =
|
|
40
|
+
const settings = unsafeDecodeSettings(context.settings);
|
|
41
|
+
if (!settings.strictImportCheck) {
|
|
42
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
43
|
+
return node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === name;
|
|
44
|
+
}
|
|
45
|
+
return node.name === name;
|
|
46
|
+
}
|
|
40
47
|
const initialScope = context.sourceCode.getScope(node);
|
|
41
48
|
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
42
|
-
return node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name, initialScope, settings);
|
|
49
|
+
return node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name, initialScope, settings.importSource);
|
|
50
|
+
}
|
|
51
|
+
if (node.name === name) {
|
|
52
|
+
return isInitializedFromReact(name, initialScope, settings.importSource);
|
|
43
53
|
}
|
|
44
|
-
if (node.name === name) return isInitializedFromReact(name, initialScope, settings);
|
|
45
54
|
return false;
|
|
46
55
|
};
|
|
47
56
|
}
|
|
48
57
|
function isFromReactMember(memberName, name) {
|
|
49
58
|
return (node, context) => {
|
|
50
|
-
const settings =
|
|
59
|
+
const settings = unsafeDecodeSettings(context.settings);
|
|
60
|
+
if (!settings.strictImportCheck) {
|
|
61
|
+
if (node.property.type !== AST_NODE_TYPES.Identifier || node.property.name !== name) return false;
|
|
62
|
+
if (node.object.type === AST_NODE_TYPES.Identifier && node.object.name === memberName) return true;
|
|
63
|
+
if (node.object.type === AST_NODE_TYPES.MemberExpression && node.object.object.type === AST_NODE_TYPES.Identifier && node.object.property.type === AST_NODE_TYPES.Identifier) {
|
|
64
|
+
return node.object.property.name === memberName;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
51
68
|
const initialScope = context.sourceCode.getScope(node);
|
|
52
69
|
if (node.property.type !== AST_NODE_TYPES.Identifier || node.property.name !== name) return false;
|
|
53
70
|
if (node.object.type === AST_NODE_TYPES.Identifier && node.object.name === memberName) {
|
|
54
|
-
return isInitializedFromReact(node.object.name, initialScope, settings);
|
|
71
|
+
return isInitializedFromReact(node.object.name, initialScope, settings.importSource);
|
|
55
72
|
}
|
|
56
|
-
if (node.object.type === AST_NODE_TYPES.MemberExpression && node.object.object.type === AST_NODE_TYPES.Identifier && isInitializedFromReact(node.object.object.name, initialScope, settings) && node.object.property.type === AST_NODE_TYPES.Identifier) {
|
|
73
|
+
if (node.object.type === AST_NODE_TYPES.MemberExpression && node.object.object.type === AST_NODE_TYPES.Identifier && isInitializedFromReact(node.object.object.name, initialScope, settings.importSource) && node.object.property.type === AST_NODE_TYPES.Identifier) {
|
|
57
74
|
return node.object.property.name === memberName;
|
|
58
75
|
}
|
|
59
76
|
return false;
|
|
@@ -108,8 +125,8 @@ var isMemoCall = isReactAPICallWithName("memo");
|
|
|
108
125
|
function isInsideCreateElementProps(node, context) {
|
|
109
126
|
return F.pipe(
|
|
110
127
|
O.Do,
|
|
111
|
-
O.bind("call", () => AST9.
|
|
112
|
-
O.bind("prop", () => AST9.
|
|
128
|
+
O.bind("call", () => AST9.findParentNodeGuard(node, isCreateElementCall(context))),
|
|
129
|
+
O.bind("prop", () => AST9.findParentNodeGuard(node, AST9.is(AST_NODE_TYPES.ObjectExpression))),
|
|
113
130
|
O.bind("arg1", ({ call }) => O.fromNullable(call.arguments[1])),
|
|
114
131
|
O.exists(({ arg1, prop }) => prop === arg1)
|
|
115
132
|
);
|
|
@@ -148,14 +165,14 @@ function isReactHookCall(node) {
|
|
|
148
165
|
return false;
|
|
149
166
|
}
|
|
150
167
|
function isReactHookCallWithName(node, context) {
|
|
151
|
-
const settings =
|
|
168
|
+
const settings = unsafeDecodeSettings(context.settings);
|
|
152
169
|
return (name) => {
|
|
153
170
|
const initialScope = context.sourceCode.getScope(node);
|
|
154
171
|
switch (true) {
|
|
155
172
|
case (node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === name):
|
|
156
|
-
return isInitializedFromReact(name, initialScope, settings);
|
|
173
|
+
return !settings.strictImportCheck || isInitializedFromReact(name, initialScope, settings.importSource);
|
|
157
174
|
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object):
|
|
158
|
-
return isInitializedFromReact(node.callee.object.name, initialScope, settings);
|
|
175
|
+
return !settings.strictImportCheck || isInitializedFromReact(node.callee.object.name, initialScope, settings.importSource);
|
|
159
176
|
default:
|
|
160
177
|
return false;
|
|
161
178
|
}
|
|
@@ -174,14 +191,14 @@ function isReactHookCallWithNameLoose(node) {
|
|
|
174
191
|
};
|
|
175
192
|
}
|
|
176
193
|
function isReactHookCallWithNameAlias(name, context, alias) {
|
|
177
|
-
const settings =
|
|
194
|
+
const settings = unsafeDecodeSettings(context);
|
|
178
195
|
return (node) => {
|
|
179
196
|
const initialScope = context.sourceCode.getScope(node);
|
|
180
197
|
switch (true) {
|
|
181
198
|
case (node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === name):
|
|
182
|
-
return isInitializedFromReact(name, initialScope, settings);
|
|
199
|
+
return !settings.strictImportCheck || isInitializedFromReact(name, initialScope, settings.importSource);
|
|
183
200
|
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object):
|
|
184
|
-
return isInitializedFromReact(node.callee.object.name, initialScope, settings);
|
|
201
|
+
return !settings.strictImportCheck || isInitializedFromReact(node.callee.object.name, initialScope, settings.importSource);
|
|
185
202
|
default:
|
|
186
203
|
return alias.some(isReactHookCallWithNameLoose(node));
|
|
187
204
|
}
|
|
@@ -216,7 +233,7 @@ var isUseTransitionCall = F.flip(isReactHookCallWithName)("useTransition");
|
|
|
216
233
|
|
|
217
234
|
// src/hook/hierarchy.ts
|
|
218
235
|
function isInsideReactHook(node) {
|
|
219
|
-
return O.exists(AST9.
|
|
236
|
+
return O.exists(AST9.findParentNodeGuard(node, AST9.isFunction), isReactHook);
|
|
220
237
|
}
|
|
221
238
|
function useHookCollector() {
|
|
222
239
|
const hooks = /* @__PURE__ */ new Map();
|
|
@@ -428,21 +445,18 @@ function isFunctionOfRenderMethod(node) {
|
|
|
428
445
|
return isClassComponent(node.parent.parent.parent);
|
|
429
446
|
}
|
|
430
447
|
function isInsideRenderMethod(node) {
|
|
431
|
-
return O.isSome(AST9.
|
|
448
|
+
return O.isSome(AST9.findParentNode(node, (node2) => {
|
|
432
449
|
return isRenderMethodLike(node2) && isClassComponent(node2.parent.parent);
|
|
433
450
|
}));
|
|
434
451
|
}
|
|
435
452
|
function hasNoneOrValidComponentName(node, context) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
);
|
|
453
|
+
const mbIdentifier = getFunctionComponentIdentifier(node, context);
|
|
454
|
+
if (O.isNone(mbIdentifier)) {
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
const id2 = mbIdentifier.value;
|
|
458
|
+
const name = Array.isArray(id2) ? id2.at(-1)?.name : id2.name;
|
|
459
|
+
return !!name && isComponentName(name);
|
|
446
460
|
}
|
|
447
461
|
|
|
448
462
|
// src/component/component-collector.ts
|
|
@@ -463,7 +477,7 @@ function hasValidHierarchy(node, context, hint) {
|
|
|
463
477
|
return false;
|
|
464
478
|
}
|
|
465
479
|
return !O.exists(
|
|
466
|
-
AST9.
|
|
480
|
+
AST9.findParentNode(
|
|
467
481
|
node,
|
|
468
482
|
AST9.isOneOf([
|
|
469
483
|
AST_NODE_TYPES.JSXExpressionContainer,
|
|
@@ -489,20 +503,20 @@ function getComponentFlag(initPath) {
|
|
|
489
503
|
function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
490
504
|
const jsxCtx = { getScope: (node) => context.sourceCode.getScope(node) };
|
|
491
505
|
const components = /* @__PURE__ */ new Map();
|
|
492
|
-
const
|
|
493
|
-
const getCurrentFunction = () => O.fromNullable(
|
|
506
|
+
const functionEntries = [];
|
|
507
|
+
const getCurrentFunction = () => O.fromNullable(functionEntries.at(-1));
|
|
494
508
|
const onFunctionEnter = (node) => {
|
|
495
509
|
const key = getId();
|
|
496
|
-
|
|
510
|
+
functionEntries.push({ key, node, hookCalls: [], isComponent: false });
|
|
497
511
|
};
|
|
498
512
|
const onFunctionExit = () => {
|
|
499
|
-
const
|
|
500
|
-
if (!key || !
|
|
501
|
-
const shouldDrop = AST9.getNestedReturnStatements(
|
|
502
|
-
return context.sourceCode.getScope(r).block ===
|
|
513
|
+
const { key, node, isComponent } = functionEntries.at(-1) ?? {};
|
|
514
|
+
if (!key || !node || !isComponent) return functionEntries.pop();
|
|
515
|
+
const shouldDrop = AST9.getNestedReturnStatements(node.body).slice().reverse().some((r) => {
|
|
516
|
+
return context.sourceCode.getScope(r).block === node && r.argument !== null && !JSX4.isJSXValue(r.argument, jsxCtx, hint);
|
|
503
517
|
});
|
|
504
518
|
if (shouldDrop) components.delete(key);
|
|
505
|
-
return
|
|
519
|
+
return functionEntries.pop();
|
|
506
520
|
};
|
|
507
521
|
const ctx = {
|
|
508
522
|
getAllComponents(_) {
|
|
@@ -510,21 +524,21 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
510
524
|
},
|
|
511
525
|
getCurrentFunction,
|
|
512
526
|
getCurrentFunctionStack() {
|
|
513
|
-
return [...
|
|
527
|
+
return [...functionEntries];
|
|
514
528
|
}
|
|
515
529
|
};
|
|
516
530
|
const listeners = {
|
|
517
531
|
":function[type]": onFunctionEnter,
|
|
518
532
|
":function[type]:exit": onFunctionExit,
|
|
519
533
|
"ArrowFunctionExpression[type][body.type!='BlockStatement']"() {
|
|
520
|
-
const
|
|
521
|
-
if (O.isNone(
|
|
522
|
-
const
|
|
523
|
-
const { body } =
|
|
524
|
-
const isComponent = hasNoneOrValidComponentName(
|
|
534
|
+
const mbEntry = getCurrentFunction();
|
|
535
|
+
if (O.isNone(mbEntry)) return;
|
|
536
|
+
const entry = mbEntry.value;
|
|
537
|
+
const { body } = entry.node;
|
|
538
|
+
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX4.isJSXValue(body, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
525
539
|
if (!isComponent) return;
|
|
526
|
-
const initPath = AST9.getFunctionInitPath(
|
|
527
|
-
const id2 = getFunctionComponentIdentifier(
|
|
540
|
+
const initPath = AST9.getFunctionInitPath(entry.node);
|
|
541
|
+
const id2 = getFunctionComponentIdentifier(entry.node, context);
|
|
528
542
|
const name = O.flatMapNullable(id2, getComponentNameFromIdentifier);
|
|
529
543
|
const key = getId();
|
|
530
544
|
components.set(key, {
|
|
@@ -532,21 +546,20 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
532
546
|
id: id2,
|
|
533
547
|
kind: "function",
|
|
534
548
|
name,
|
|
535
|
-
node:
|
|
549
|
+
node: entry.node,
|
|
536
550
|
displayName: O.none(),
|
|
537
551
|
flag: getComponentFlag(initPath),
|
|
538
552
|
hint,
|
|
539
|
-
hookCalls,
|
|
553
|
+
hookCalls: entry.hookCalls,
|
|
540
554
|
initPath
|
|
541
555
|
});
|
|
542
556
|
},
|
|
543
557
|
"AssignmentExpression[type][operator='='][left.type='MemberExpression'][left.property.name='displayName']"(node) {
|
|
544
|
-
if (node.type !== AST_NODE_TYPES.AssignmentExpression) return;
|
|
545
558
|
const { left, right } = node;
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
const component = Array.from(components.values()).findLast(({ name }) => O.exists(name, (n) => n ===
|
|
559
|
+
const mbComponentName = match(left.object).with({ type: AST_NODE_TYPES.Identifier }, (n) => O.some(n.name)).otherwise(O.none);
|
|
560
|
+
if (O.isNone(mbComponentName)) return;
|
|
561
|
+
const componentName = mbComponentName.value;
|
|
562
|
+
const component = Array.from(components.values()).findLast(({ name }) => O.exists(name, (n) => n === componentName));
|
|
550
563
|
if (!component) return;
|
|
551
564
|
components.set(component._, {
|
|
552
565
|
...component,
|
|
@@ -555,34 +568,33 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
555
568
|
},
|
|
556
569
|
"CallExpression[type]:exit"(node) {
|
|
557
570
|
if (!isReactHookCall(node)) return;
|
|
558
|
-
const
|
|
559
|
-
if (O.isNone(
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
571
|
+
const mbEntry = getCurrentFunction();
|
|
572
|
+
if (O.isNone(mbEntry)) return;
|
|
573
|
+
const entry = mbEntry.value;
|
|
574
|
+
functionEntries.pop();
|
|
575
|
+
functionEntries.push({ ...entry, hookCalls: [...entry.hookCalls, node] });
|
|
563
576
|
},
|
|
564
577
|
"ReturnStatement[type]"(node) {
|
|
565
|
-
const
|
|
566
|
-
if (O.isNone(
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
const isComponent = hasNoneOrValidComponentName(currentFn, context) && JSX4.isJSXValue(node.argument, jsxCtx, hint) && hasValidHierarchy(currentFn, context, hint);
|
|
578
|
+
const mbEntry = getCurrentFunction();
|
|
579
|
+
if (O.isNone(mbEntry)) return;
|
|
580
|
+
const entry = mbEntry.value;
|
|
581
|
+
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX4.isJSXValue(node.argument, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
570
582
|
if (!isComponent) return;
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
const initPath = AST9.getFunctionInitPath(
|
|
574
|
-
const id2 = getFunctionComponentIdentifier(
|
|
583
|
+
functionEntries.pop();
|
|
584
|
+
functionEntries.push({ ...entry, isComponent });
|
|
585
|
+
const initPath = AST9.getFunctionInitPath(entry.node);
|
|
586
|
+
const id2 = getFunctionComponentIdentifier(entry.node, context);
|
|
575
587
|
const name = O.flatMapNullable(id2, getComponentNameFromIdentifier);
|
|
576
|
-
components.set(key, {
|
|
577
|
-
_: key,
|
|
588
|
+
components.set(entry.key, {
|
|
589
|
+
_: entry.key,
|
|
578
590
|
id: id2,
|
|
579
591
|
kind: "function",
|
|
580
592
|
name,
|
|
581
|
-
node:
|
|
593
|
+
node: entry.node,
|
|
582
594
|
displayName: O.none(),
|
|
583
595
|
flag: getComponentFlag(initPath),
|
|
584
596
|
hint,
|
|
585
|
-
hookCalls,
|
|
597
|
+
hookCalls: entry.hookCalls,
|
|
586
598
|
initPath
|
|
587
599
|
});
|
|
588
600
|
}
|
|
@@ -593,10 +605,10 @@ function isSetupFunction(node) {
|
|
|
593
605
|
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && node.parent.callee.type === AST_NODE_TYPES.Identifier && node.parent.arguments.at(0) === node && isUseEffectCallLoose(node.parent);
|
|
594
606
|
}
|
|
595
607
|
function isCleanupFunction(node) {
|
|
596
|
-
const nearestRet = O.getOrNull(AST9.
|
|
608
|
+
const nearestRet = O.getOrNull(AST9.findParentNodeGuard(node, AST9.is(AST_NODE_TYPES.ReturnStatement)));
|
|
597
609
|
if (!nearestRet) return false;
|
|
598
|
-
const nearestFunction = O.getOrNull(AST9.
|
|
599
|
-
const nearestFunctionOfRet = O.getOrNull(AST9.
|
|
610
|
+
const nearestFunction = O.getOrNull(AST9.findParentNodeGuard(node, AST9.isFunction));
|
|
611
|
+
const nearestFunctionOfRet = O.getOrNull(AST9.findParentNodeGuard(nearestRet, AST9.isFunction));
|
|
600
612
|
if (!nearestFunction || !nearestFunctionOfRet) return false;
|
|
601
613
|
return nearestFunction === nearestFunctionOfRet && isSetupFunction(nearestFunction);
|
|
602
614
|
}
|
|
@@ -620,7 +632,7 @@ function isDeclaredInRenderPropLoose(node) {
|
|
|
620
632
|
return true;
|
|
621
633
|
}
|
|
622
634
|
return F.pipe(
|
|
623
|
-
AST9.
|
|
635
|
+
AST9.findParentNodeGuard(node, AST9.is(AST_NODE_TYPES.JSXExpressionContainer)),
|
|
624
636
|
O.flatMapNullable((c) => c.parent),
|
|
625
637
|
O.filter(AST9.is(AST_NODE_TYPES.JSXAttribute)),
|
|
626
638
|
O.flatMapNullable((a) => a.name),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/core",
|
|
3
|
-
"version": "1.23.2-next.
|
|
3
|
+
"version": "1.23.2-next.6",
|
|
4
4
|
"description": "ESLint React's ESLint utility module for static analysis of React core APIs and Patterns.",
|
|
5
5
|
"homepage": "https://github.com/rEl1cx/eslint-react",
|
|
6
6
|
"bugs": {
|
|
@@ -33,17 +33,17 @@
|
|
|
33
33
|
"./package.json"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@typescript-eslint/scope-manager": "^8.19.
|
|
37
|
-
"@typescript-eslint/type-utils": "^8.19.
|
|
38
|
-
"@typescript-eslint/types": "^8.19.
|
|
39
|
-
"@typescript-eslint/utils": "^8.19.
|
|
36
|
+
"@typescript-eslint/scope-manager": "^8.19.1",
|
|
37
|
+
"@typescript-eslint/type-utils": "^8.19.1",
|
|
38
|
+
"@typescript-eslint/types": "^8.19.1",
|
|
39
|
+
"@typescript-eslint/utils": "^8.19.1",
|
|
40
40
|
"ts-pattern": "^5.6.0",
|
|
41
|
-
"@eslint-react/
|
|
42
|
-
"@eslint-react/
|
|
43
|
-
"@eslint-react/
|
|
44
|
-
"@eslint-react/
|
|
45
|
-
"@eslint-react/
|
|
46
|
-
"@eslint-react/var": "1.23.2-next.
|
|
41
|
+
"@eslint-react/jsx": "1.23.2-next.6",
|
|
42
|
+
"@eslint-react/ast": "1.23.2-next.6",
|
|
43
|
+
"@eslint-react/eff": "1.23.2-next.6",
|
|
44
|
+
"@eslint-react/shared": "1.23.2-next.6",
|
|
45
|
+
"@eslint-react/types": "1.23.2-next.6",
|
|
46
|
+
"@eslint-react/var": "1.23.2-next.6"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"tsup": "^8.3.5",
|