@eslint-react/core 2.7.5-beta.4 → 2.7.5-beta.9
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.ts +84 -69
- package/dist/index.js +81 -122
- package/package.json +5 -6
package/dist/index.d.ts
CHANGED
|
@@ -3,13 +3,12 @@ import { unit } from "@eslint-react/eff";
|
|
|
3
3
|
import { TSESTree } from "@typescript-eslint/types";
|
|
4
4
|
import { RegExpLike, RuleContext } from "@eslint-react/shared";
|
|
5
5
|
import { ESLintUtils, TSESTree as TSESTree$1 } from "@typescript-eslint/utils";
|
|
6
|
-
import * as birecord0 from "birecord";
|
|
7
6
|
import { Scope } from "@typescript-eslint/scope-manager";
|
|
8
7
|
import * as typescript0 from "typescript";
|
|
9
8
|
|
|
10
9
|
//#region src/api/is-from-react.d.ts
|
|
11
10
|
/**
|
|
12
|
-
*
|
|
11
|
+
* Check if a variable is initialized from React import
|
|
13
12
|
* @param name The variable name
|
|
14
13
|
* @param initialScope The initial scope
|
|
15
14
|
* @param importSource Alternative import source of React (e.g., "preact/compat")
|
|
@@ -19,7 +18,7 @@ declare function isInitializedFromReact(name: string, initialScope: Scope, impor
|
|
|
19
18
|
//#endregion
|
|
20
19
|
//#region src/api/is-from-react-native.d.ts
|
|
21
20
|
/**
|
|
22
|
-
*
|
|
21
|
+
* if a variable is initialized from React Native import
|
|
23
22
|
* @param name The variable name
|
|
24
23
|
* @param initialScope The initial scope
|
|
25
24
|
* @param importSource Alternative import source of React Native (e.g., "react-native-web")
|
|
@@ -35,7 +34,7 @@ declare namespace isReactAPI {
|
|
|
35
34
|
};
|
|
36
35
|
}
|
|
37
36
|
/**
|
|
38
|
-
*
|
|
37
|
+
* Check if the node is a React API identifier or member expression
|
|
39
38
|
* @param api The React API name to check against (e.g., "useState", "React.memo")
|
|
40
39
|
* @returns A predicate function to check if a node matches the API
|
|
41
40
|
*/
|
|
@@ -47,7 +46,7 @@ declare namespace isReactAPICall {
|
|
|
47
46
|
};
|
|
48
47
|
}
|
|
49
48
|
/**
|
|
50
|
-
*
|
|
49
|
+
* Check if the node is a call expression to a specific React API
|
|
51
50
|
* @param api The React API name to check against
|
|
52
51
|
* @returns A predicate function to check if a node is a call to the API
|
|
53
52
|
*/
|
|
@@ -152,20 +151,22 @@ interface SemanticFunc extends SemanticNode {
|
|
|
152
151
|
//#endregion
|
|
153
152
|
//#region src/component/component-flag.d.ts
|
|
154
153
|
type ComponentFlag = bigint;
|
|
154
|
+
/**
|
|
155
|
+
* Component flag constants
|
|
156
|
+
*/
|
|
155
157
|
declare const ComponentFlag: {
|
|
156
158
|
/** No flags set */None: bigint; /** Indicates the component is a pure component (e.g., extends PureComponent) */
|
|
157
159
|
PureComponent: bigint; /** Indicates the component creates elements using `createElement` instead of JSX */
|
|
158
160
|
CreateElement: bigint; /** Indicates the component is memoized (e.g., React.memo) */
|
|
159
161
|
Memo: bigint; /** Indicates the component forwards a ref (e.g., React.forwardRef) */
|
|
160
|
-
ForwardRef: bigint;
|
|
161
|
-
Async: bigint;
|
|
162
|
+
ForwardRef: bigint;
|
|
162
163
|
};
|
|
163
164
|
//#endregion
|
|
164
165
|
//#region src/component/component-semantic-node.d.ts
|
|
165
166
|
/**
|
|
166
|
-
* Represents a React
|
|
167
|
+
* Represents a React Function Component
|
|
167
168
|
*/
|
|
168
|
-
interface
|
|
169
|
+
interface FunctionComponentSemanticNode extends SemanticNode {
|
|
169
170
|
/**
|
|
170
171
|
* The identifier or identifier sequence of the component
|
|
171
172
|
*/
|
|
@@ -212,9 +213,9 @@ interface FunctionComponent extends SemanticNode {
|
|
|
212
213
|
displayName: unit | TSESTree.Expression;
|
|
213
214
|
}
|
|
214
215
|
/**
|
|
215
|
-
* Represents a React
|
|
216
|
+
* Represents a React Class Component
|
|
216
217
|
*/
|
|
217
|
-
interface
|
|
218
|
+
interface ClassComponentSemanticNode extends SemanticNode {
|
|
218
219
|
/**
|
|
219
220
|
* The identifier of the component
|
|
220
221
|
*/
|
|
@@ -245,20 +246,13 @@ interface ClassComponent extends SemanticNode {
|
|
|
245
246
|
displayName: unit | TSESTree.Expression;
|
|
246
247
|
}
|
|
247
248
|
/**
|
|
248
|
-
*
|
|
249
|
+
* Represents a React Component
|
|
249
250
|
*/
|
|
250
|
-
type
|
|
251
|
+
type ComponentSemanticNode = ClassComponentSemanticNode | FunctionComponentSemanticNode;
|
|
251
252
|
//#endregion
|
|
252
253
|
//#region src/component/component-collector.d.ts
|
|
253
|
-
type FunctionEntry$1 = {
|
|
254
|
-
key: string;
|
|
255
|
-
node: AST.TSESTreeFunction;
|
|
256
|
-
hookCalls: TSESTree.CallExpression[];
|
|
257
|
-
isComponent: boolean;
|
|
254
|
+
type FunctionEntry$1 = FunctionComponentSemanticNode & {
|
|
258
255
|
isComponentDefinition: boolean;
|
|
259
|
-
isExportDefault: boolean;
|
|
260
|
-
isExportDefaultDeclaration: boolean;
|
|
261
|
-
rets: TSESTree.ReturnStatement["argument"][];
|
|
262
256
|
};
|
|
263
257
|
declare namespace useComponentCollector {
|
|
264
258
|
type Options = {
|
|
@@ -268,7 +262,7 @@ declare namespace useComponentCollector {
|
|
|
268
262
|
};
|
|
269
263
|
type ReturnType = {
|
|
270
264
|
ctx: {
|
|
271
|
-
getAllComponents: (node: TSESTree.Program) =>
|
|
265
|
+
getAllComponents: (node: TSESTree.Program) => FunctionComponentSemanticNode[];
|
|
272
266
|
getCurrentEntries: () => FunctionEntry$1[];
|
|
273
267
|
getCurrentEntry: () => FunctionEntry$1 | unit;
|
|
274
268
|
};
|
|
@@ -276,7 +270,7 @@ declare namespace useComponentCollector {
|
|
|
276
270
|
};
|
|
277
271
|
}
|
|
278
272
|
/**
|
|
279
|
-
* Get a ctx and visitor for the rule to collect function components
|
|
273
|
+
* Get a ctx and visitor object for the rule to collect function components
|
|
280
274
|
* @param context The ESLint rule context
|
|
281
275
|
* @param options The options to use
|
|
282
276
|
* @returns The ctx and visitor of the collector
|
|
@@ -287,13 +281,13 @@ declare function useComponentCollector(context: RuleContext, options?: useCompon
|
|
|
287
281
|
declare namespace useComponentCollectorLegacy {
|
|
288
282
|
type ReturnType = {
|
|
289
283
|
ctx: {
|
|
290
|
-
getAllComponents: (node: TSESTree$1.Program) =>
|
|
284
|
+
getAllComponents: (node: TSESTree$1.Program) => ClassComponentSemanticNode[];
|
|
291
285
|
};
|
|
292
286
|
visitor: ESLintUtils.RuleListener;
|
|
293
287
|
};
|
|
294
288
|
}
|
|
295
289
|
/**
|
|
296
|
-
* Get a ctx and visitor object for the rule to collect class
|
|
290
|
+
* Get a ctx and visitor object for the rule to collect class componentss
|
|
297
291
|
* @param context The ESLint rule context
|
|
298
292
|
* @returns The ctx and visitor of the collector
|
|
299
293
|
*/
|
|
@@ -313,7 +307,7 @@ declare function isAssignmentToThisState(node: TSESTree$1.AssignmentExpression):
|
|
|
313
307
|
//#endregion
|
|
314
308
|
//#region src/component/component-definition.d.ts
|
|
315
309
|
/**
|
|
316
|
-
*
|
|
310
|
+
* Determine if a function node represents a valid React component definition
|
|
317
311
|
*
|
|
318
312
|
* @param context The rule context
|
|
319
313
|
* @param node The function node to analyze
|
|
@@ -323,10 +317,21 @@ declare function isAssignmentToThisState(node: TSESTree$1.AssignmentExpression):
|
|
|
323
317
|
declare function isComponentDefinition(context: RuleContext, node: AST.TSESTreeFunction, hint: bigint): boolean;
|
|
324
318
|
//#endregion
|
|
325
319
|
//#region src/component/component-id.d.ts
|
|
320
|
+
/**
|
|
321
|
+
* Get function component identifier from `const Component = memo(() => {});`
|
|
322
|
+
* @param context The rule context
|
|
323
|
+
* @param node The function node to analyze
|
|
324
|
+
* @returns The function identifier or `unit` if not found
|
|
325
|
+
*/
|
|
326
326
|
declare function getFunctionComponentId(context: RuleContext, node: AST.TSESTreeFunction): AST.FunctionID | unit;
|
|
327
327
|
//#endregion
|
|
328
328
|
//#region src/component/component-init-path.d.ts
|
|
329
|
-
|
|
329
|
+
/**
|
|
330
|
+
* Get component flag from init path
|
|
331
|
+
* @param initPath The init path of the function component
|
|
332
|
+
* @returns The component flag
|
|
333
|
+
*/
|
|
334
|
+
declare function getComponentFlagFromInitPath(initPath: FunctionComponentSemanticNode["initPath"]): bigint;
|
|
330
335
|
//#endregion
|
|
331
336
|
//#region src/component/component-is.d.ts
|
|
332
337
|
/**
|
|
@@ -338,24 +343,27 @@ declare function isClassComponent(node: TSESTree.Node): node is AST.TSESTreeClas
|
|
|
338
343
|
/**
|
|
339
344
|
* Check if a node is a React PureComponent
|
|
340
345
|
* @param node The AST node to check
|
|
341
|
-
* @returns `true` if the node is a
|
|
346
|
+
* @returns `true` if the node is a PureComponent, `false` otherwise
|
|
342
347
|
*/
|
|
343
348
|
declare function isPureComponent(node: TSESTree.Node): boolean;
|
|
344
349
|
//#endregion
|
|
345
350
|
//#region src/component/component-kind.d.ts
|
|
351
|
+
/**
|
|
352
|
+
* Represents the kind of a React component
|
|
353
|
+
*/
|
|
346
354
|
type ComponentKind = "classComponent" | "functionComponent";
|
|
347
355
|
//#endregion
|
|
348
356
|
//#region src/component/component-method-callback.d.ts
|
|
349
357
|
/**
|
|
350
|
-
*
|
|
351
|
-
* @param node The
|
|
352
|
-
* @returns
|
|
358
|
+
* Check if the given node is a componentDidMount callback
|
|
359
|
+
* @param node The node to check
|
|
360
|
+
* @returns True if the node is a componentDidMount callback, false otherwise
|
|
353
361
|
*/
|
|
354
362
|
declare function isComponentDidMountCallback(node: TSESTree.Node): boolean;
|
|
355
363
|
/**
|
|
356
|
-
*
|
|
357
|
-
* @param node The
|
|
358
|
-
* @returns
|
|
364
|
+
* Check if the given node is a componentWillUnmount callback
|
|
365
|
+
* @param node The node to check
|
|
366
|
+
* @returns True if the node is a componentWillUnmount callback, false otherwise
|
|
359
367
|
*/
|
|
360
368
|
declare function isComponentWillUnmountCallback(node: TSESTree.Node): boolean;
|
|
361
369
|
//#endregion
|
|
@@ -397,22 +405,6 @@ declare function isComponentNameLoose(name: string): boolean;
|
|
|
397
405
|
*/
|
|
398
406
|
declare function hasNoneOrLooseComponentName(context: RuleContext, fn: AST.TSESTreeFunction): boolean;
|
|
399
407
|
//#endregion
|
|
400
|
-
//#region src/component/component-phase.d.ts
|
|
401
|
-
type ComponentEffectPhaseKind = "cleanup" | "setup";
|
|
402
|
-
type ComponentLifecyclePhaseKind = "mount" | "unmount";
|
|
403
|
-
type ComponentPhaseKind = ComponentEffectPhaseKind | ComponentLifecyclePhaseKind;
|
|
404
|
-
declare const ComponentPhaseRelevance: birecord0.BiRecord<{
|
|
405
|
-
readonly mount: "unmount";
|
|
406
|
-
readonly setup: "cleanup";
|
|
407
|
-
}>;
|
|
408
|
-
//#endregion
|
|
409
|
-
//#region src/component/component-phase-helpers.d.ts
|
|
410
|
-
declare const isInversePhase: {
|
|
411
|
-
(a: ComponentPhaseKind): (b: ComponentPhaseKind) => boolean;
|
|
412
|
-
(a: ComponentPhaseKind, b: ComponentPhaseKind): boolean;
|
|
413
|
-
};
|
|
414
|
-
declare function getPhaseKindOfFunction(node: AST.TSESTreeFunction): ComponentPhaseKind | null;
|
|
415
|
-
//#endregion
|
|
416
408
|
//#region src/component/component-render-method.d.ts
|
|
417
409
|
/**
|
|
418
410
|
* Check whether given node is a render method of a class component
|
|
@@ -509,6 +501,30 @@ declare function isComponentWrapperCallback(context: RuleContext, node: TSESTree
|
|
|
509
501
|
*/
|
|
510
502
|
declare function isComponentWrapperCallbackLoose(context: RuleContext, node: TSESTree.Node): boolean;
|
|
511
503
|
//#endregion
|
|
504
|
+
//#region src/function/function-semantic-node.d.ts
|
|
505
|
+
/**
|
|
506
|
+
* Represents a React Client Function
|
|
507
|
+
*/
|
|
508
|
+
interface ClientFunctionSemanticNode extends SemanticFunc {
|
|
509
|
+
/**
|
|
510
|
+
* The kind of function
|
|
511
|
+
*/
|
|
512
|
+
kind: "client-function";
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Represents a React Server Function
|
|
516
|
+
*/
|
|
517
|
+
interface ServerFunctionSemanticNode extends SemanticFunc {
|
|
518
|
+
/**
|
|
519
|
+
* The kind of function
|
|
520
|
+
*/
|
|
521
|
+
kind: "server-function";
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Represents a React Function
|
|
525
|
+
*/
|
|
526
|
+
type FunctionSemanticNode = ClientFunctionSemanticNode | ServerFunctionSemanticNode;
|
|
527
|
+
//#endregion
|
|
512
528
|
//#region src/hierarchy/find-enclosing-component-or-hook.d.ts
|
|
513
529
|
type FindEnclosingComponentOrHookFilter = (n: TSESTree.Node, name: string | null) => boolean;
|
|
514
530
|
/**
|
|
@@ -521,7 +537,7 @@ declare function findEnclosingComponentOrHook(node: TSESTree.Node | unit, test?:
|
|
|
521
537
|
//#endregion
|
|
522
538
|
//#region src/hierarchy/is-inside-component-or-hook.d.ts
|
|
523
539
|
/**
|
|
524
|
-
*
|
|
540
|
+
* Check if a given AST node is inside a React component or hook
|
|
525
541
|
* @param node The AST node to check
|
|
526
542
|
* @returns True if the node is inside a component or hook, false otherwise
|
|
527
543
|
*/
|
|
@@ -529,18 +545,18 @@ declare function isInsideComponentOrHook(node: TSESTree.Node | unit): boolean;
|
|
|
529
545
|
//#endregion
|
|
530
546
|
//#region src/hook/hook-callback.d.ts
|
|
531
547
|
/**
|
|
532
|
-
*
|
|
548
|
+
* Determine if a node is the setup function passed to a useEffect-like hook
|
|
533
549
|
* @param node The AST node to check
|
|
534
550
|
*/
|
|
535
551
|
declare function isUseEffectSetupCallback(node: TSESTree.Node | unit): boolean;
|
|
536
552
|
/**
|
|
537
|
-
*
|
|
553
|
+
* Determine if a node is the cleanup function returned by a useEffect-like hook's setup function.
|
|
538
554
|
* @param node The AST node to check
|
|
539
555
|
*/
|
|
540
556
|
declare function isUseEffectCleanupCallback(node: TSESTree.Node | unit): boolean;
|
|
541
557
|
//#endregion
|
|
542
558
|
//#region src/hook/hook-semantic-node.d.ts
|
|
543
|
-
interface
|
|
559
|
+
interface HookSemanticNode extends SemanticNode {
|
|
544
560
|
id: AST.FunctionID | unit;
|
|
545
561
|
node: AST.TSESTreeFunction;
|
|
546
562
|
name: string;
|
|
@@ -551,12 +567,11 @@ interface Hook extends SemanticNode {
|
|
|
551
567
|
type FunctionEntry = {
|
|
552
568
|
key: string;
|
|
553
569
|
node: AST.TSESTreeFunction;
|
|
554
|
-
isHook: boolean;
|
|
555
570
|
};
|
|
556
571
|
declare namespace useHookCollector {
|
|
557
572
|
type ReturnType = {
|
|
558
573
|
ctx: {
|
|
559
|
-
getAllHooks(node: TSESTree$1.Program):
|
|
574
|
+
getAllHooks(node: TSESTree$1.Program): HookSemanticNode[];
|
|
560
575
|
getCurrentEntries(): FunctionEntry[];
|
|
561
576
|
getCurrentEntry(): FunctionEntry | unit;
|
|
562
577
|
};
|
|
@@ -564,7 +579,7 @@ declare namespace useHookCollector {
|
|
|
564
579
|
};
|
|
565
580
|
}
|
|
566
581
|
/**
|
|
567
|
-
* Get a ctx and visitor for the rule to collect hooks
|
|
582
|
+
* Get a ctx and visitor object for the rule to collect hooks
|
|
568
583
|
* @param context The ESLint rule context
|
|
569
584
|
* @returns The ctx and visitor of the collector
|
|
570
585
|
*/
|
|
@@ -575,7 +590,7 @@ declare function isHookId(id: TSESTree.Node): id is TSESTree.Identifier | TSESTr
|
|
|
575
590
|
//#endregion
|
|
576
591
|
//#region src/hook/hook-is.d.ts
|
|
577
592
|
/**
|
|
578
|
-
*
|
|
593
|
+
* Determine if a function node is a React Hook based on its name.
|
|
579
594
|
* @param node The function node to check
|
|
580
595
|
* @returns True if the function is a React Hook, false otherwise
|
|
581
596
|
*/
|
|
@@ -587,21 +602,21 @@ declare function isHook(node: AST.TSESTreeFunction | unit): boolean;
|
|
|
587
602
|
*/
|
|
588
603
|
declare function isHookCall(node: TSESTree.Node | unit): node is TSESTree.CallExpression;
|
|
589
604
|
/**
|
|
590
|
-
*
|
|
605
|
+
* Check if a node is a call to a specific React hook.
|
|
591
606
|
* Returns a function that accepts a hook name to check against.
|
|
592
607
|
* @param node The AST node to check
|
|
593
608
|
* @returns A function that takes a hook name and returns boolean
|
|
594
609
|
*/
|
|
595
610
|
declare function isHookCallWithName(node: TSESTree.Node | unit): (name: string) => boolean;
|
|
596
611
|
/**
|
|
597
|
-
*
|
|
612
|
+
* Detect useEffect calls and variations (useLayoutEffect, etc.) using a regex pattern
|
|
598
613
|
* @param node The AST node to check
|
|
599
614
|
* @param additionalEffectHooks Regex pattern matching custom hooks that should be treated as effect hooks
|
|
600
615
|
* @returns True if the node is a useEffect-like call
|
|
601
616
|
*/
|
|
602
617
|
declare function isUseEffectLikeCall(node: TSESTree.Node | unit, additionalEffectHooks?: RegExpLike): node is TSESTree.CallExpression;
|
|
603
618
|
/**
|
|
604
|
-
*
|
|
619
|
+
* Detect useState calls and variations (useCustomState, etc.) using a regex pattern
|
|
605
620
|
* @param node The AST node to check
|
|
606
621
|
* @param additionalStateHooks Regex pattern matching custom hooks that should be treated as state hooks
|
|
607
622
|
* @returns True if the node is a useState-like call
|
|
@@ -685,7 +700,7 @@ type JsxAttributeValue = {
|
|
|
685
700
|
toStatic(): unknown;
|
|
686
701
|
};
|
|
687
702
|
/**
|
|
688
|
-
*
|
|
703
|
+
* Resolve the static value of a JSX attribute or spread attribute
|
|
689
704
|
*
|
|
690
705
|
* @param context - The ESLint rule context
|
|
691
706
|
* @param attribute - The JSX attribute node to resolve
|
|
@@ -775,13 +790,13 @@ declare const JsxDetectionHint: {
|
|
|
775
790
|
*/
|
|
776
791
|
declare const DEFAULT_JSX_DETECTION_HINT: bigint;
|
|
777
792
|
/**
|
|
778
|
-
*
|
|
793
|
+
* Check if a node is a `JSXText` or a `Literal` node
|
|
779
794
|
* @param node The AST node to check
|
|
780
795
|
* @returns `true` if the node is a `JSXText` or a `Literal` node
|
|
781
796
|
*/
|
|
782
797
|
declare function isJsxText(node: TSESTree$1.Node | null | unit): node is TSESTree$1.JSXText | TSESTree$1.Literal;
|
|
783
798
|
/**
|
|
784
|
-
*
|
|
799
|
+
* Determine if a node represents JSX-like content based on heuristics
|
|
785
800
|
* Supports configuration through hint flags to customize detection behavior
|
|
786
801
|
*
|
|
787
802
|
* @param code The source code with scope lookup capability
|
|
@@ -796,7 +811,7 @@ declare function isJsxLike(code: {
|
|
|
796
811
|
//#endregion
|
|
797
812
|
//#region src/jsx/jsx-element-is.d.ts
|
|
798
813
|
/**
|
|
799
|
-
*
|
|
814
|
+
* Determine if a JSX element is a host element
|
|
800
815
|
* Host elements in React start with lowercase letters (e.g., div, span)
|
|
801
816
|
*
|
|
802
817
|
* @param context ESLint rule context
|
|
@@ -805,7 +820,7 @@ declare function isJsxLike(code: {
|
|
|
805
820
|
*/
|
|
806
821
|
declare function isJsxHostElement(context: RuleContext, node: TSESTree.Node): boolean;
|
|
807
822
|
/**
|
|
808
|
-
*
|
|
823
|
+
* Determine if a JSX element is a React Fragment
|
|
809
824
|
* Fragments can be imported from React and used like <Fragment> or <React.Fragment>
|
|
810
825
|
*
|
|
811
826
|
* @param context ESLint rule context
|
|
@@ -850,7 +865,7 @@ declare function stringifyJsx(node: TSESTree$1.JSXIdentifier | TSESTree$1.JSXNam
|
|
|
850
865
|
//#endregion
|
|
851
866
|
//#region src/ref/is-from-ref.d.ts
|
|
852
867
|
/**
|
|
853
|
-
*
|
|
868
|
+
* Check if the variable with the given name is initialized or derived from a ref
|
|
854
869
|
* @param name The variable name
|
|
855
870
|
* @param initialScope The initial scope
|
|
856
871
|
* @returns True if the variable is derived from a ref, false otherwise
|
|
@@ -859,10 +874,10 @@ declare function isInitializedFromRef(name: string, initialScope: Scope): boolea
|
|
|
859
874
|
//#endregion
|
|
860
875
|
//#region src/ref/ref-name.d.ts
|
|
861
876
|
/**
|
|
862
|
-
*
|
|
877
|
+
* Check if a given name corresponds to a ref name
|
|
863
878
|
* @param name The name to check
|
|
864
879
|
* @returns True if the name is "ref" or ends with "Ref"
|
|
865
880
|
*/
|
|
866
881
|
declare function isRefName(name: string): boolean;
|
|
867
882
|
//#endregion
|
|
868
|
-
export {
|
|
883
|
+
export { ClassComponentSemanticNode, ClientFunctionSemanticNode, ComponentDetectionHint, ComponentFlag, ComponentKind, ComponentSemanticNode, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, FindEnclosingComponentOrHookFilter, FunctionComponentSemanticNode, FunctionSemanticNode, HookSemanticNode, JsxAttributeValue, JsxConfig, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, SemanticFunc, SemanticNode, ServerFunctionSemanticNode, findEnclosingComponentOrHook, findParentJsxAttribute, getComponentFlagFromInitPath, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, hasNoneOrLooseComponentName, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHook, isHookCall, isHookCallWithName, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isInitializedFromRef, isInsideComponentOrHook, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRefName, isRender, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall, resolveJsxAttributeValue, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
|
package/dist/index.js
CHANGED
|
@@ -6,11 +6,10 @@ import { IdGenerator, RE_ANNOTATION_JSX, RE_ANNOTATION_JSX_FRAG, RE_ANNOTATION_J
|
|
|
6
6
|
import { getStaticValue } from "@typescript-eslint/utils/ast-utils";
|
|
7
7
|
import { P, match } from "ts-pattern";
|
|
8
8
|
import { AST_NODE_TYPES as AST_NODE_TYPES$1 } from "@typescript-eslint/utils";
|
|
9
|
-
import birecord from "birecord";
|
|
10
9
|
|
|
11
10
|
//#region src/api/is-from-react.ts
|
|
12
11
|
/**
|
|
13
|
-
*
|
|
12
|
+
* Check if a variable is initialized from React import
|
|
14
13
|
* @param name The variable name
|
|
15
14
|
* @param initialScope The initial scope
|
|
16
15
|
* @param importSource Alternative import source of React (e.g., "preact/compat")
|
|
@@ -23,7 +22,7 @@ function isInitializedFromReact(name, initialScope, importSource = "react") {
|
|
|
23
22
|
//#endregion
|
|
24
23
|
//#region src/api/is-from-react-native.ts
|
|
25
24
|
/**
|
|
26
|
-
*
|
|
25
|
+
* if a variable is initialized from React Native import
|
|
27
26
|
* @param name The variable name
|
|
28
27
|
* @param initialScope The initial scope
|
|
29
28
|
* @param importSource Alternative import source of React Native (e.g., "react-native-web")
|
|
@@ -40,7 +39,7 @@ function isInitializedFromReactNative(name, initialScope, importSource = "react-
|
|
|
40
39
|
//#endregion
|
|
41
40
|
//#region src/api/is-react-api.ts
|
|
42
41
|
/**
|
|
43
|
-
*
|
|
42
|
+
* Check if the node is a React API identifier or member expression
|
|
44
43
|
* @param api The React API name to check against (e.g., "useState", "React.memo")
|
|
45
44
|
* @returns A predicate function to check if a node matches the API
|
|
46
45
|
*/
|
|
@@ -56,7 +55,7 @@ function isReactAPI(api) {
|
|
|
56
55
|
return dual(2, func);
|
|
57
56
|
}
|
|
58
57
|
/**
|
|
59
|
-
*
|
|
58
|
+
* Check if the node is a call expression to a specific React API
|
|
60
59
|
* @param api The React API name to check against
|
|
61
60
|
* @returns A predicate function to check if a node is a call to the API
|
|
62
61
|
*/
|
|
@@ -131,7 +130,7 @@ function isHookName(name) {
|
|
|
131
130
|
//#endregion
|
|
132
131
|
//#region src/hook/hook-is.ts
|
|
133
132
|
/**
|
|
134
|
-
*
|
|
133
|
+
* Determine if a function node is a React Hook based on its name.
|
|
135
134
|
* @param node The function node to check
|
|
136
135
|
* @returns True if the function is a React Hook, false otherwise
|
|
137
136
|
*/
|
|
@@ -157,7 +156,7 @@ function isHookCall(node) {
|
|
|
157
156
|
return false;
|
|
158
157
|
}
|
|
159
158
|
/**
|
|
160
|
-
*
|
|
159
|
+
* Check if a node is a call to a specific React hook.
|
|
161
160
|
* Returns a function that accepts a hook name to check against.
|
|
162
161
|
* @param node The AST node to check
|
|
163
162
|
* @returns A function that takes a hook name and returns boolean
|
|
@@ -173,7 +172,7 @@ function isHookCallWithName(node) {
|
|
|
173
172
|
};
|
|
174
173
|
}
|
|
175
174
|
/**
|
|
176
|
-
*
|
|
175
|
+
* Detect useEffect calls and variations (useLayoutEffect, etc.) using a regex pattern
|
|
177
176
|
* @param node The AST node to check
|
|
178
177
|
* @param additionalEffectHooks Regex pattern matching custom hooks that should be treated as effect hooks
|
|
179
178
|
* @returns True if the node is a useEffect-like call
|
|
@@ -188,7 +187,7 @@ function isUseEffectLikeCall(node, additionalEffectHooks = { test: constFalse })
|
|
|
188
187
|
});
|
|
189
188
|
}
|
|
190
189
|
/**
|
|
191
|
-
*
|
|
190
|
+
* Detect useState calls and variations (useCustomState, etc.) using a regex pattern
|
|
192
191
|
* @param node The AST node to check
|
|
193
192
|
* @param additionalStateHooks Regex pattern matching custom hooks that should be treated as state hooks
|
|
194
193
|
* @returns True if the node is a useState-like call
|
|
@@ -225,7 +224,7 @@ const isUseTransitionCall = flip(isHookCallWithName)("useTransition");
|
|
|
225
224
|
//#endregion
|
|
226
225
|
//#region src/hook/hook-callback.ts
|
|
227
226
|
/**
|
|
228
|
-
*
|
|
227
|
+
* Determine if a node is the setup function passed to a useEffect-like hook
|
|
229
228
|
* @param node The AST node to check
|
|
230
229
|
*/
|
|
231
230
|
function isUseEffectSetupCallback(node) {
|
|
@@ -233,7 +232,7 @@ function isUseEffectSetupCallback(node) {
|
|
|
233
232
|
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.arguments.at(0) === node && isUseEffectLikeCall(node.parent);
|
|
234
233
|
}
|
|
235
234
|
/**
|
|
236
|
-
*
|
|
235
|
+
* Determine if a node is the cleanup function returned by a useEffect-like hook's setup function.
|
|
237
236
|
* @param node The AST node to check
|
|
238
237
|
*/
|
|
239
238
|
function isUseEffectCleanupCallback(node) {
|
|
@@ -258,7 +257,7 @@ function isHookId(id) {
|
|
|
258
257
|
//#region src/hook/hook-collector.ts
|
|
259
258
|
const idGen$2 = new IdGenerator("hook_");
|
|
260
259
|
/**
|
|
261
|
-
* Get a ctx and visitor for the rule to collect hooks
|
|
260
|
+
* Get a ctx and visitor object for the rule to collect hooks
|
|
262
261
|
* @param context The ESLint rule context
|
|
263
262
|
* @returns The ctx and visitor of the collector
|
|
264
263
|
*/
|
|
@@ -270,28 +269,20 @@ function useHookCollector(context) {
|
|
|
270
269
|
const onFunctionEnter = (node) => {
|
|
271
270
|
const id = AST.getFunctionId(node);
|
|
272
271
|
const key = idGen$2.next();
|
|
273
|
-
if (id != null && isHookId(id)) {
|
|
274
|
-
functionEntries.push({
|
|
275
|
-
key,
|
|
276
|
-
node,
|
|
277
|
-
isHook: true
|
|
278
|
-
});
|
|
279
|
-
hooks.set(key, {
|
|
280
|
-
id,
|
|
281
|
-
key,
|
|
282
|
-
kind: "function",
|
|
283
|
-
name: AST.toStringFormat(id, getText),
|
|
284
|
-
node,
|
|
285
|
-
flag: 0n,
|
|
286
|
-
hint: 0n,
|
|
287
|
-
hookCalls: []
|
|
288
|
-
});
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
272
|
functionEntries.push({
|
|
292
273
|
key,
|
|
274
|
+
node
|
|
275
|
+
});
|
|
276
|
+
if (id == null || !isHookId(id)) return;
|
|
277
|
+
hooks.set(key, {
|
|
278
|
+
id,
|
|
279
|
+
key,
|
|
280
|
+
kind: "function",
|
|
281
|
+
name: AST.toStringFormat(id, getText),
|
|
293
282
|
node,
|
|
294
|
-
|
|
283
|
+
flag: 0n,
|
|
284
|
+
hint: 0n,
|
|
285
|
+
hookCalls: []
|
|
295
286
|
});
|
|
296
287
|
};
|
|
297
288
|
const onFunctionExit = () => {
|
|
@@ -310,11 +301,9 @@ function useHookCollector(context) {
|
|
|
310
301
|
":function:exit": onFunctionExit,
|
|
311
302
|
CallExpression(node) {
|
|
312
303
|
if (!isHookCall(node)) return;
|
|
313
|
-
const
|
|
314
|
-
if (
|
|
315
|
-
|
|
316
|
-
if (hook == null) return;
|
|
317
|
-
hook.hookCalls.push(node);
|
|
304
|
+
const entry = getCurrentEntry();
|
|
305
|
+
if (entry == null) return;
|
|
306
|
+
hooks.get(entry.key)?.hookCalls.push(node);
|
|
318
307
|
}
|
|
319
308
|
}
|
|
320
309
|
};
|
|
@@ -388,7 +377,7 @@ function getJsxAttribute(context, node, initialScope) {
|
|
|
388
377
|
//#endregion
|
|
389
378
|
//#region src/jsx/jsx-attribute-value.ts
|
|
390
379
|
/**
|
|
391
|
-
*
|
|
380
|
+
* Resolve the static value of a JSX attribute or spread attribute
|
|
392
381
|
*
|
|
393
382
|
* @param context - The ESLint rule context
|
|
394
383
|
* @param attribute - The JSX attribute node to resolve
|
|
@@ -536,7 +525,7 @@ const JsxDetectionHint = {
|
|
|
536
525
|
*/
|
|
537
526
|
const DEFAULT_JSX_DETECTION_HINT = 0n | JsxDetectionHint.SkipUndefined | JsxDetectionHint.SkipBooleanLiteral;
|
|
538
527
|
/**
|
|
539
|
-
*
|
|
528
|
+
* Check if a node is a `JSXText` or a `Literal` node
|
|
540
529
|
* @param node The AST node to check
|
|
541
530
|
* @returns `true` if the node is a `JSXText` or a `Literal` node
|
|
542
531
|
*/
|
|
@@ -545,7 +534,7 @@ function isJsxText(node) {
|
|
|
545
534
|
return node.type === AST_NODE_TYPES.JSXText || node.type === AST_NODE_TYPES.Literal;
|
|
546
535
|
}
|
|
547
536
|
/**
|
|
548
|
-
*
|
|
537
|
+
* Determine if a node represents JSX-like content based on heuristics
|
|
549
538
|
* Supports configuration through hint flags to customize detection behavior
|
|
550
539
|
*
|
|
551
540
|
* @param code The source code with scope lookup capability
|
|
@@ -627,7 +616,7 @@ function getJsxElementType(context, node) {
|
|
|
627
616
|
//#endregion
|
|
628
617
|
//#region src/jsx/jsx-element-is.ts
|
|
629
618
|
/**
|
|
630
|
-
*
|
|
619
|
+
* Determine if a JSX element is a host element
|
|
631
620
|
* Host elements in React start with lowercase letters (e.g., div, span)
|
|
632
621
|
*
|
|
633
622
|
* @param context ESLint rule context
|
|
@@ -638,7 +627,7 @@ function isJsxHostElement(context, node) {
|
|
|
638
627
|
return node.type === AST_NODE_TYPES.JSXElement && node.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier && /^[a-z]/u.test(node.openingElement.name.name);
|
|
639
628
|
}
|
|
640
629
|
/**
|
|
641
|
-
*
|
|
630
|
+
* Determine if a JSX element is a React Fragment
|
|
642
631
|
* Fragments can be imported from React and used like <Fragment> or <React.Fragment>
|
|
643
632
|
*
|
|
644
633
|
* @param context ESLint rule context
|
|
@@ -709,7 +698,7 @@ function isClassComponent(node) {
|
|
|
709
698
|
/**
|
|
710
699
|
* Check if a node is a React PureComponent
|
|
711
700
|
* @param node The AST node to check
|
|
712
|
-
* @returns `true` if the node is a
|
|
701
|
+
* @returns `true` if the node is a PureComponent, `false` otherwise
|
|
713
702
|
*/
|
|
714
703
|
function isPureComponent(node) {
|
|
715
704
|
if ("superClass" in node && node.superClass != null) {
|
|
@@ -743,7 +732,7 @@ function isRenderMethodLike(node) {
|
|
|
743
732
|
//#endregion
|
|
744
733
|
//#region src/component/component-definition.ts
|
|
745
734
|
/**
|
|
746
|
-
*
|
|
735
|
+
* Check if the given node is a function within a render method of a class component.
|
|
747
736
|
*
|
|
748
737
|
* @param node The AST node to check
|
|
749
738
|
* @returns `true` if the node is a render function inside a class component
|
|
@@ -761,7 +750,7 @@ function isRenderMethodCallback(node) {
|
|
|
761
750
|
return greatGrandparent != null && isRenderMethodLike(parent) && isClassComponent(greatGrandparent);
|
|
762
751
|
}
|
|
763
752
|
/**
|
|
764
|
-
*
|
|
753
|
+
* Check if a function node should be excluded based on provided detection hints
|
|
765
754
|
*
|
|
766
755
|
* @param node The function node to check
|
|
767
756
|
* @param hint Component detection hints as bit flags
|
|
@@ -779,7 +768,7 @@ function shouldExcludeBasedOnHint(node, hint) {
|
|
|
779
768
|
return false;
|
|
780
769
|
}
|
|
781
770
|
/**
|
|
782
|
-
*
|
|
771
|
+
* Determine if the node is an argument within `createElement`'s children list (3rd argument onwards)
|
|
783
772
|
*
|
|
784
773
|
* @param context The rule context
|
|
785
774
|
* @param node The AST node to check
|
|
@@ -792,7 +781,7 @@ function isChildrenOfCreateElement(context, node) {
|
|
|
792
781
|
return parent.arguments.slice(2).some((arg) => arg === node);
|
|
793
782
|
}
|
|
794
783
|
/**
|
|
795
|
-
*
|
|
784
|
+
* Determine if a function node represents a valid React component definition
|
|
796
785
|
*
|
|
797
786
|
* @param context The rule context
|
|
798
787
|
* @param node The function node to analyze
|
|
@@ -863,6 +852,12 @@ function isComponentWrapperCallbackLoose(context, node) {
|
|
|
863
852
|
|
|
864
853
|
//#endregion
|
|
865
854
|
//#region src/component/component-id.ts
|
|
855
|
+
/**
|
|
856
|
+
* Get function component identifier from `const Component = memo(() => {});`
|
|
857
|
+
* @param context The rule context
|
|
858
|
+
* @param node The function node to analyze
|
|
859
|
+
* @returns The function identifier or `unit` if not found
|
|
860
|
+
*/
|
|
866
861
|
function getFunctionComponentId(context, node) {
|
|
867
862
|
const functionId = AST.getFunctionId(node);
|
|
868
863
|
if (functionId != null) return functionId;
|
|
@@ -874,17 +869,24 @@ function getFunctionComponentId(context, node) {
|
|
|
874
869
|
|
|
875
870
|
//#endregion
|
|
876
871
|
//#region src/component/component-flag.ts
|
|
872
|
+
/**
|
|
873
|
+
* Component flag constants
|
|
874
|
+
*/
|
|
877
875
|
const ComponentFlag = {
|
|
878
876
|
None: 0n,
|
|
879
877
|
PureComponent: 1n << 0n,
|
|
880
878
|
CreateElement: 1n << 1n,
|
|
881
879
|
Memo: 1n << 2n,
|
|
882
|
-
ForwardRef: 1n << 3n
|
|
883
|
-
Async: 1n << 4n
|
|
880
|
+
ForwardRef: 1n << 3n
|
|
884
881
|
};
|
|
885
882
|
|
|
886
883
|
//#endregion
|
|
887
884
|
//#region src/component/component-init-path.ts
|
|
885
|
+
/**
|
|
886
|
+
* Get component flag from init path
|
|
887
|
+
* @param initPath The init path of the function component
|
|
888
|
+
* @returns The component flag
|
|
889
|
+
*/
|
|
888
890
|
function getComponentFlagFromInitPath(initPath) {
|
|
889
891
|
let flag = ComponentFlag.None;
|
|
890
892
|
if (initPath != null && AST.hasCallInFunctionInitPath("memo", initPath)) flag |= ComponentFlag.Memo;
|
|
@@ -925,7 +927,7 @@ function hasNoneOrLooseComponentName(context, fn) {
|
|
|
925
927
|
//#region src/component/component-collector.ts
|
|
926
928
|
const idGen$1 = new IdGenerator("function_component_");
|
|
927
929
|
/**
|
|
928
|
-
* Get a ctx and visitor for the rule to collect function components
|
|
930
|
+
* Get a ctx and visitor object for the rule to collect function components
|
|
929
931
|
* @param context The ESLint rule context
|
|
930
932
|
* @param options The options to use
|
|
931
933
|
* @returns The ctx and visitor of the collector
|
|
@@ -941,12 +943,21 @@ function useComponentCollector(context, options = {}) {
|
|
|
941
943
|
const exp = AST.findParentNode(node, (n) => n.type === AST_NODE_TYPES.ExportDefaultDeclaration);
|
|
942
944
|
const isExportDefault = exp != null;
|
|
943
945
|
const isExportDefaultDeclaration = exp != null && AST.getUnderlyingExpression(exp.declaration) === node;
|
|
946
|
+
const id = getFunctionComponentId(context, node);
|
|
947
|
+
const name = id == null ? unit : AST.toStringFormat(id, getText);
|
|
948
|
+
const initPath = AST.getFunctionInitPath(node);
|
|
944
949
|
functionEntries.push({
|
|
950
|
+
id: getFunctionComponentId(context, node),
|
|
945
951
|
key,
|
|
952
|
+
kind: "function",
|
|
953
|
+
name,
|
|
946
954
|
node,
|
|
955
|
+
displayName: unit,
|
|
956
|
+
flag: getComponentFlagFromInitPath(initPath),
|
|
957
|
+
hint,
|
|
947
958
|
hookCalls: [],
|
|
948
|
-
|
|
949
|
-
isComponentDefinition: isComponentDefinition(context, node, hint),
|
|
959
|
+
initPath,
|
|
960
|
+
isComponentDefinition: hasNoneOrLooseComponentName(context, node) && isComponentDefinition(context, node, hint),
|
|
950
961
|
isExportDefault,
|
|
951
962
|
isExportDefaultDeclaration,
|
|
952
963
|
rets: []
|
|
@@ -971,29 +982,12 @@ function useComponentCollector(context, options = {}) {
|
|
|
971
982
|
"ArrowFunctionExpression[body.type!='BlockStatement']"() {
|
|
972
983
|
const entry = getCurrentEntry();
|
|
973
984
|
if (entry == null) return;
|
|
974
|
-
if (!entry.isComponentDefinition) return;
|
|
975
985
|
const { body } = entry.node;
|
|
976
986
|
if (body.type === AST_NODE_TYPES.BlockStatement) return;
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
const name = id == null ? unit : AST.toStringFormat(id, getText);
|
|
982
|
-
components.set(key, {
|
|
983
|
-
id,
|
|
984
|
-
key,
|
|
985
|
-
kind: "function",
|
|
986
|
-
name,
|
|
987
|
-
node: entry.node,
|
|
988
|
-
displayName: unit,
|
|
989
|
-
flag: getComponentFlagFromInitPath(initPath),
|
|
990
|
-
hint,
|
|
991
|
-
hookCalls: entry.hookCalls,
|
|
992
|
-
initPath,
|
|
993
|
-
isExportDefault: entry.isExportDefault,
|
|
994
|
-
isExportDefaultDeclaration: entry.isExportDefaultDeclaration,
|
|
995
|
-
rets: [body]
|
|
996
|
-
});
|
|
987
|
+
entry.rets.push(body);
|
|
988
|
+
if (!entry.isComponentDefinition) return;
|
|
989
|
+
if (!components.has(entry.key) && !isJsxLike(context.sourceCode, body, hint)) return;
|
|
990
|
+
components.set(entry.key, entry);
|
|
997
991
|
},
|
|
998
992
|
...collectDisplayName ? { [AST.SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION](node) {
|
|
999
993
|
const { left, right } = node;
|
|
@@ -1012,30 +1006,11 @@ function useComponentCollector(context, options = {}) {
|
|
|
1012
1006
|
ReturnStatement(node) {
|
|
1013
1007
|
const entry = getCurrentEntry();
|
|
1014
1008
|
if (entry == null) return;
|
|
1009
|
+
entry.rets.push(node.argument);
|
|
1015
1010
|
if (!entry.isComponentDefinition) return;
|
|
1016
1011
|
const { argument } = node;
|
|
1017
|
-
entry.
|
|
1018
|
-
|
|
1019
|
-
entry.isComponent = true;
|
|
1020
|
-
const initPath = AST.getFunctionInitPath(entry.node);
|
|
1021
|
-
const id = getFunctionComponentId(context, entry.node);
|
|
1022
|
-
const key = entry.key;
|
|
1023
|
-
const name = id == null ? unit : AST.toStringFormat(id, getText);
|
|
1024
|
-
components.set(key, {
|
|
1025
|
-
id,
|
|
1026
|
-
key,
|
|
1027
|
-
kind: "function",
|
|
1028
|
-
name,
|
|
1029
|
-
node: entry.node,
|
|
1030
|
-
displayName: unit,
|
|
1031
|
-
flag: getComponentFlagFromInitPath(initPath),
|
|
1032
|
-
hint,
|
|
1033
|
-
hookCalls: entry.hookCalls,
|
|
1034
|
-
initPath,
|
|
1035
|
-
isExportDefault: entry.isExportDefault,
|
|
1036
|
-
isExportDefaultDeclaration: entry.isExportDefaultDeclaration,
|
|
1037
|
-
rets: entry.rets
|
|
1038
|
-
});
|
|
1012
|
+
if (!components.has(entry.key) && !isJsxLike(context.sourceCode, argument, hint)) return;
|
|
1013
|
+
components.set(entry.key, entry);
|
|
1039
1014
|
}
|
|
1040
1015
|
}
|
|
1041
1016
|
};
|
|
@@ -1045,7 +1020,7 @@ function useComponentCollector(context, options = {}) {
|
|
|
1045
1020
|
//#region src/component/component-collector-legacy.ts
|
|
1046
1021
|
const idGen = new IdGenerator("class_component_");
|
|
1047
1022
|
/**
|
|
1048
|
-
* Get a ctx and visitor object for the rule to collect class
|
|
1023
|
+
* Get a ctx and visitor object for the rule to collect class componentss
|
|
1049
1024
|
* @param context The ESLint rule context
|
|
1050
1025
|
* @returns The ctx and visitor of the collector
|
|
1051
1026
|
*/
|
|
@@ -1108,9 +1083,7 @@ function isAssignmentToThisState(node) {
|
|
|
1108
1083
|
* @param isStatic Whether the method is static
|
|
1109
1084
|
*/
|
|
1110
1085
|
function createLifecycleChecker(methodName, isStatic = false) {
|
|
1111
|
-
return
|
|
1112
|
-
return AST.isMethodOrProperty(node) && node.static === isStatic && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === methodName;
|
|
1113
|
-
};
|
|
1086
|
+
return (node) => AST.isMethodOrProperty(node) && node.static === isStatic && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === methodName;
|
|
1114
1087
|
}
|
|
1115
1088
|
const isRender = createLifecycleChecker("render");
|
|
1116
1089
|
const isComponentDidCatch = createLifecycleChecker("componentDidCatch");
|
|
@@ -1134,36 +1107,22 @@ const isGetDerivedStateFromError = createLifecycleChecker("getDerivedStateFromEr
|
|
|
1134
1107
|
//#endregion
|
|
1135
1108
|
//#region src/component/component-method-callback.ts
|
|
1136
1109
|
/**
|
|
1137
|
-
*
|
|
1138
|
-
* @param node The
|
|
1139
|
-
* @returns
|
|
1110
|
+
* Check if the given node is a componentDidMount callback
|
|
1111
|
+
* @param node The node to check
|
|
1112
|
+
* @returns True if the node is a componentDidMount callback, false otherwise
|
|
1140
1113
|
*/
|
|
1141
1114
|
function isComponentDidMountCallback(node) {
|
|
1142
1115
|
return AST.isFunction(node) && isComponentDidMount(node.parent) && node.parent.value === node;
|
|
1143
1116
|
}
|
|
1144
1117
|
/**
|
|
1145
|
-
*
|
|
1146
|
-
* @param node The
|
|
1147
|
-
* @returns
|
|
1118
|
+
* Check if the given node is a componentWillUnmount callback
|
|
1119
|
+
* @param node The node to check
|
|
1120
|
+
* @returns True if the node is a componentWillUnmount callback, false otherwise
|
|
1148
1121
|
*/
|
|
1149
1122
|
function isComponentWillUnmountCallback(node) {
|
|
1150
1123
|
return AST.isFunction(node) && isComponentWillUnmount(node.parent) && node.parent.value === node;
|
|
1151
1124
|
}
|
|
1152
1125
|
|
|
1153
|
-
//#endregion
|
|
1154
|
-
//#region src/component/component-phase.ts
|
|
1155
|
-
const ComponentPhaseRelevance = birecord({
|
|
1156
|
-
mount: "unmount",
|
|
1157
|
-
setup: "cleanup"
|
|
1158
|
-
});
|
|
1159
|
-
|
|
1160
|
-
//#endregion
|
|
1161
|
-
//#region src/component/component-phase-helpers.ts
|
|
1162
|
-
const isInversePhase = dual(2, (a, b) => ComponentPhaseRelevance.get(a) === b);
|
|
1163
|
-
function getPhaseKindOfFunction(node) {
|
|
1164
|
-
return match(node).when(isUseEffectSetupCallback, () => "setup").when(isUseEffectCleanupCallback, () => "cleanup").when(isComponentDidMountCallback, () => "mount").when(isComponentWillUnmountCallback, () => "unmount").otherwise(() => null);
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
1126
|
//#endregion
|
|
1168
1127
|
//#region src/component/component-render-prop.ts
|
|
1169
1128
|
/**
|
|
@@ -1263,7 +1222,7 @@ function findEnclosingComponentOrHook(node, test = (n, name) => {
|
|
|
1263
1222
|
//#endregion
|
|
1264
1223
|
//#region src/hierarchy/is-inside-component-or-hook.ts
|
|
1265
1224
|
/**
|
|
1266
|
-
*
|
|
1225
|
+
* Check if a given AST node is inside a React component or hook
|
|
1267
1226
|
* @param node The AST node to check
|
|
1268
1227
|
* @returns True if the node is inside a component or hook, false otherwise
|
|
1269
1228
|
*/
|
|
@@ -1274,7 +1233,7 @@ function isInsideComponentOrHook(node) {
|
|
|
1274
1233
|
//#endregion
|
|
1275
1234
|
//#region src/ref/ref-name.ts
|
|
1276
1235
|
/**
|
|
1277
|
-
*
|
|
1236
|
+
* Check if a given name corresponds to a ref name
|
|
1278
1237
|
* @param name The name to check
|
|
1279
1238
|
* @returns True if the name is "ref" or ends with "Ref"
|
|
1280
1239
|
*/
|
|
@@ -1285,7 +1244,7 @@ function isRefName(name) {
|
|
|
1285
1244
|
//#endregion
|
|
1286
1245
|
//#region src/ref/is-from-ref.ts
|
|
1287
1246
|
/**
|
|
1288
|
-
*
|
|
1247
|
+
* Check if the variable with the given name is initialized or derived from a ref
|
|
1289
1248
|
* @param name The variable name
|
|
1290
1249
|
* @param initialScope The initial scope
|
|
1291
1250
|
* @returns True if the variable is derived from a ref, false otherwise
|
|
@@ -1304,4 +1263,4 @@ function isInitializedFromRef(name, initialScope) {
|
|
|
1304
1263
|
}
|
|
1305
1264
|
|
|
1306
1265
|
//#endregion
|
|
1307
|
-
export { ComponentDetectionHint, ComponentFlag,
|
|
1266
|
+
export { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, findEnclosingComponentOrHook, findParentJsxAttribute, getComponentFlagFromInitPath, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, hasNoneOrLooseComponentName, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHook, isHookCall, isHookCallWithName, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isInitializedFromRef, isInsideComponentOrHook, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRefName, isRender, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall, resolveJsxAttributeValue, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/core",
|
|
3
|
-
"version": "2.7.5-beta.
|
|
3
|
+
"version": "2.7.5-beta.9",
|
|
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,12 +33,11 @@
|
|
|
33
33
|
"@typescript-eslint/scope-manager": "^8.54.0",
|
|
34
34
|
"@typescript-eslint/types": "^8.54.0",
|
|
35
35
|
"@typescript-eslint/utils": "^8.54.0",
|
|
36
|
-
"birecord": "^0.1.1",
|
|
37
36
|
"ts-pattern": "^5.9.0",
|
|
38
|
-
"@eslint-react/
|
|
39
|
-
"@eslint-react/ast": "2.7.5-beta.
|
|
40
|
-
"@eslint-react/var": "2.7.5-beta.
|
|
41
|
-
"@eslint-react/
|
|
37
|
+
"@eslint-react/eff": "2.7.5-beta.9",
|
|
38
|
+
"@eslint-react/ast": "2.7.5-beta.9",
|
|
39
|
+
"@eslint-react/var": "2.7.5-beta.9",
|
|
40
|
+
"@eslint-react/shared": "2.7.5-beta.9"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"tsdown": "^0.20.1",
|