@eslint-react/core 2.6.4 → 2.6.5-beta.1

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 CHANGED
@@ -13,18 +13,6 @@ type ComponentDetectionHint = bigint;
13
13
  * Hints for component collector
14
14
  */
15
15
  declare const ComponentDetectionHint: {
16
- /**
17
- * Skip function component created by React.memo
18
- */
19
- readonly SkipMemo: bigint;
20
- /**
21
- * Skip function component created by React.forwardRef
22
- */
23
- readonly SkipForwardRef: bigint;
24
- /**
25
- * Skip function component defined as array map argument
26
- */
27
- readonly SkipArrayMapArgument: bigint;
28
16
  /**
29
17
  * Skip function component defined on object method
30
18
  */
@@ -37,6 +25,10 @@ declare const ComponentDetectionHint: {
37
25
  * Skip function component defined on class property
38
26
  */
39
27
  readonly SkipClassProperty: bigint;
28
+ /**
29
+ * Skip function component defined as array map callback
30
+ */
31
+ readonly SkipArrayMapCallback: bigint;
40
32
  readonly None: 0n;
41
33
  readonly SkipUndefined: bigint;
42
34
  readonly SkipNullLiteral: bigint;
@@ -72,7 +64,7 @@ interface SemanticEntry {
72
64
  //#endregion
73
65
  //#region src/semantic/semantic-node.d.ts
74
66
  interface SemanticNode {
75
- id: unit | TSESTree.Identifier | TSESTree.Identifier[];
67
+ id: unit | TSESTree.Node;
76
68
  key: string;
77
69
  kind: string;
78
70
  name: unit | string;
@@ -100,7 +92,7 @@ interface FunctionComponent extends SemanticNode {
100
92
  /**
101
93
  * The identifier or identifier sequence of the component
102
94
  */
103
- id: unit | TSESTree.Identifier | TSESTree.Identifier[];
95
+ id: unit | AST.FunctionID;
104
96
  /**
105
97
  * The kind of component
106
98
  */
@@ -117,6 +109,10 @@ interface FunctionComponent extends SemanticNode {
117
109
  * Hint for how the component was detected
118
110
  */
119
111
  hint: ComponentDetectionHint;
112
+ /**
113
+ * List of expressions returned by the component
114
+ */
115
+ rets: TSESTree.ReturnStatement["argument"][];
120
116
  /**
121
117
  * The initialization path of the function
122
118
  */
@@ -137,7 +133,7 @@ interface ClassComponent extends SemanticNode {
137
133
  /**
138
134
  * The identifier of the component
139
135
  */
140
- id: unit | TSESTree.Identifier;
136
+ id: unit | TSESTree.BindingName;
141
137
  /**
142
138
  * The kind of component
143
139
  */
@@ -174,6 +170,7 @@ type FunctionEntry$1 = {
174
170
  node: AST.TSESTreeFunction;
175
171
  hookCalls: TSESTree.CallExpression[];
176
172
  isComponent: boolean;
173
+ rets: TSESTree.ReturnStatement["argument"][];
177
174
  };
178
175
  declare namespace useComponentCollector {
179
176
  type Options = {
@@ -209,9 +206,10 @@ declare namespace useComponentCollectorLegacy {
209
206
  }
210
207
  /**
211
208
  * Get a ctx and listeners object for the rule to collect class components
209
+ * @param context The ESLint rule context
212
210
  * @returns The context and listeners for the rule
213
211
  */
214
- declare function useComponentCollectorLegacy(): useComponentCollectorLegacy.ReturnType;
212
+ declare function useComponentCollectorLegacy(context: RuleContext): useComponentCollectorLegacy.ReturnType;
215
213
  /**
216
214
  * Check whether the given node is a this.setState() call
217
215
  * @param node The node to check
@@ -237,7 +235,7 @@ declare function isAssignmentToThisState(node: TSESTree$1.AssignmentExpression):
237
235
  declare function isComponentDefinition(context: RuleContext, node: AST.TSESTreeFunction, hint: bigint): boolean;
238
236
  //#endregion
239
237
  //#region src/component/component-id.d.ts
240
- declare function getFunctionComponentId(context: RuleContext, node: AST.TSESTreeFunction): TSESTree.Identifier | TSESTree.Identifier[] | unit;
238
+ declare function getFunctionComponentId(context: RuleContext, node: AST.TSESTreeFunction): AST.FunctionID | unit;
241
239
  //#endregion
242
240
  //#region src/component/component-init-path.d.ts
243
241
  declare function getComponentFlagFromInitPath(initPath: FunctionComponent["initPath"]): bigint;
@@ -304,11 +302,6 @@ declare function isComponentName(name: string): boolean;
304
302
  * @param name The name to check
305
303
  */
306
304
  declare function isComponentNameLoose(name: string): boolean;
307
- /**
308
- * Get component name from an identifier or identifier sequence (e.g., MemberExpression)
309
- * @param id The identifier or identifier sequence
310
- */
311
- declare function getComponentNameFromId(id: TSESTree.Identifier | TSESTree.Identifier[] | unit): string | undefined;
312
305
  /**
313
306
  * Check if the function has no name or a loose component name
314
307
  * @param context The rule context
@@ -404,10 +397,56 @@ declare function isComponentWrapperCall(context: RuleContext, node: TSESTree.Nod
404
397
  * @returns `true` if the node is a call expression for a component wrapper loosely
405
398
  */
406
399
  declare function isComponentWrapperCallLoose(context: RuleContext, node: TSESTree.Node): boolean;
400
+ /**
401
+ * Check if the node is a callback function passed to a component wrapper
402
+ * @param context The ESLint rule context
403
+ * @param node The node to check
404
+ * @returns `true` if the node is a callback function passed to a component wrapper
405
+ */
406
+ declare function isComponentWrapperCallback(context: RuleContext, node: TSESTree.Node): boolean;
407
+ /**
408
+ * Check if the node is a callback function passed to a component wrapper loosely
409
+ * @param context The ESLint rule context
410
+ * @param node The node to check
411
+ * @returns `true` if the node is a callback function passed to a component wrapper loosely
412
+ */
413
+ declare function isComponentWrapperCallbackLoose(context: RuleContext, node: TSESTree.Node): boolean;
414
+ //#endregion
415
+ //#region src/hierarchy/find-enclosing-assignment-target.d.ts
416
+ /**
417
+ * Finds the enclosing assignment target (variable, property, etc.) for a given node
418
+ *
419
+ * @todo Verify correctness and completeness of this function
420
+ * @param node The starting node
421
+ * @returns The enclosing assignment target node, or undefined if not found
422
+ */
423
+ declare function findEnclosingAssignmentTarget(node: TSESTree.Node): TSESTree.ArrayExpression | TSESTree.ArrayPattern | TSESTree.ArrowFunctionExpression | TSESTree.AssignmentExpression | TSESTree.AwaitExpression | TSESTree.PrivateInExpression | TSESTree.SymmetricBinaryExpression | TSESTree.CallExpression | TSESTree.ChainExpression | TSESTree.ClassExpression | TSESTree.ConditionalExpression | TSESTree.FunctionExpression | TSESTree.Identifier | TSESTree.ImportExpression | TSESTree.JSXElement | TSESTree.JSXFragment | TSESTree.BigIntLiteral | TSESTree.BooleanLiteral | TSESTree.NullLiteral | TSESTree.NumberLiteral | TSESTree.RegExpLiteral | TSESTree.StringLiteral | TSESTree.LogicalExpression | TSESTree.MemberExpressionComputedName | TSESTree.MemberExpressionNonComputedName | TSESTree.MetaProperty | TSESTree.NewExpression | TSESTree.ObjectExpression | TSESTree.ObjectPattern | TSESTree.PrivateIdentifier | TSESTree.SequenceExpression | TSESTree.Super | TSESTree.TaggedTemplateExpression | TSESTree.TemplateLiteral | TSESTree.ThisExpression | TSESTree.TSAsExpression | TSESTree.TSInstantiationExpression | TSESTree.TSNonNullExpression | TSESTree.TSSatisfiesExpression | TSESTree.TSTypeAssertion | TSESTree.UnaryExpressionBitwiseNot | TSESTree.UnaryExpressionDelete | TSESTree.UnaryExpressionMinus | TSESTree.UnaryExpressionNot | TSESTree.UnaryExpressionPlus | TSESTree.UnaryExpressionTypeof | TSESTree.UnaryExpressionVoid | TSESTree.UpdateExpression | TSESTree.YieldExpression | undefined;
424
+ /**
425
+ * Type representing the possible assignment targets returned by `findEnclosingAssignmentTarget`
426
+ */
427
+ type AssignmentTarget = ReturnType<typeof findEnclosingAssignmentTarget>;
428
+ //#endregion
429
+ //#region src/hierarchy/find-enclosing-component-or-hook.d.ts
430
+ type FindEnclosingComponentOrHookFilter = (n: TSESTree.Node, name: string | null) => boolean;
431
+ /**
432
+ * Find the enclosing React component or hook for a given AST node
433
+ * @param node The AST node to start the search from
434
+ * @param test Optional test function to customize component or hook identification
435
+ * @returns The enclosing component or hook node, or `null` if none is found
436
+ */
437
+ declare function findEnclosingComponentOrHook(node: TSESTree.Node | unit, test?: FindEnclosingComponentOrHookFilter): TSESTree.ArrowFunctionExpression | TSESTree.FunctionDeclarationWithName | TSESTree.FunctionDeclarationWithOptionalName | TSESTree.FunctionExpression | undefined;
438
+ //#endregion
439
+ //#region src/hierarchy/is-inside-component-or-hook.d.ts
440
+ /**
441
+ * Checks if a given AST node is inside a React component or hook
442
+ * @param node The AST node to check
443
+ * @returns True if the node is inside a component or hook, false otherwise
444
+ */
445
+ declare function isInsideComponentOrHook(node: TSESTree.Node | unit): boolean;
407
446
  //#endregion
408
447
  //#region src/hook/hook-semantic-node.d.ts
409
448
  interface Hook extends SemanticNode {
410
- id: TSESTree.Identifier | unit;
449
+ id: AST.FunctionID | unit;
411
450
  node: AST.TSESTreeFunction;
412
451
  name: string;
413
452
  hookCalls: TSESTree.CallExpression[];
@@ -429,10 +468,10 @@ declare namespace useHookCollector {
429
468
  listeners: ESLintUtils.RuleListener;
430
469
  };
431
470
  }
432
- declare function useHookCollector(): useHookCollector.ReturnType;
471
+ declare function useHookCollector(context: RuleContext): useHookCollector.ReturnType;
433
472
  //#endregion
434
473
  //#region src/hook/hook-id.d.ts
435
- declare function isReactHookId(id: TSESTree.Identifier | TSESTree.MemberExpression): boolean;
474
+ declare function isReactHookId(id: TSESTree.Node): id is TSESTree.Identifier | TSESTree.MemberExpression;
436
475
  //#endregion
437
476
  //#region src/hook/hook-is.d.ts
438
477
  /**
@@ -720,20 +759,6 @@ declare function findParentJsxAttribute(node: TSESTree.Node, test?: (node: TSEST
720
759
  */
721
760
  declare function stringifyJsx(node: TSESTree$1.JSXIdentifier | TSESTree$1.JSXNamespacedName | TSESTree$1.JSXMemberExpression | TSESTree$1.JSXOpeningElement | TSESTree$1.JSXClosingElement | TSESTree$1.JSXOpeningFragment | TSESTree$1.JSXClosingFragment | TSESTree$1.JSXText): string;
722
761
  //#endregion
723
- //#region src/utils/find-enclosing-assignment-target.d.ts
724
- /**
725
- * Finds the enclosing assignment target (variable, property, etc.) for a given node
726
- *
727
- * @todo Verify correctness and completeness of this function
728
- * @param node The starting node
729
- * @returns The enclosing assignment target node, or undefined if not found
730
- */
731
- declare function findEnclosingAssignmentTarget(node: TSESTree.Node): TSESTree.ArrayExpression | TSESTree.ArrayPattern | TSESTree.ArrowFunctionExpression | TSESTree.AssignmentExpression | TSESTree.AwaitExpression | TSESTree.PrivateInExpression | TSESTree.SymmetricBinaryExpression | TSESTree.CallExpression | TSESTree.ChainExpression | TSESTree.ClassExpression | TSESTree.ConditionalExpression | TSESTree.FunctionExpression | TSESTree.Identifier | TSESTree.ImportExpression | TSESTree.JSXElement | TSESTree.JSXFragment | TSESTree.BigIntLiteral | TSESTree.BooleanLiteral | TSESTree.NullLiteral | TSESTree.NumberLiteral | TSESTree.RegExpLiteral | TSESTree.StringLiteral | TSESTree.LogicalExpression | TSESTree.MemberExpressionComputedName | TSESTree.MemberExpressionNonComputedName | TSESTree.MetaProperty | TSESTree.NewExpression | TSESTree.ObjectExpression | TSESTree.ObjectPattern | TSESTree.PrivateIdentifier | TSESTree.SequenceExpression | TSESTree.Super | TSESTree.TaggedTemplateExpression | TSESTree.TemplateLiteral | TSESTree.ThisExpression | TSESTree.TSAsExpression | TSESTree.TSInstantiationExpression | TSESTree.TSNonNullExpression | TSESTree.TSSatisfiesExpression | TSESTree.TSTypeAssertion | TSESTree.UnaryExpressionBitwiseNot | TSESTree.UnaryExpressionDelete | TSESTree.UnaryExpressionMinus | TSESTree.UnaryExpressionNot | TSESTree.UnaryExpressionPlus | TSESTree.UnaryExpressionTypeof | TSESTree.UnaryExpressionVoid | TSESTree.UpdateExpression | TSESTree.YieldExpression | undefined;
732
- /**
733
- * Type representing the possible assignment targets returned by `findEnclosingAssignmentTarget`
734
- */
735
- type AssignmentTarget = ReturnType<typeof findEnclosingAssignmentTarget>;
736
- //#endregion
737
762
  //#region src/utils/is-from-react.d.ts
738
763
  /**
739
764
  * Checks if a variable is initialized from React import
@@ -810,4 +835,4 @@ declare const isForwardRefCall: isReactAPICall.ReturnType;
810
835
  declare const isMemoCall: isReactAPICall.ReturnType;
811
836
  declare const isLazyCall: isReactAPICall.ReturnType;
812
837
  //#endregion
813
- export { AssignmentTarget, ClassComponent, Component, ComponentDetectionHint, ComponentEffectPhaseKind, ComponentFlag, ComponentKind, ComponentLifecyclePhaseKind, ComponentPhaseKind, ComponentPhaseRelevance, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, FunctionComponent, Hook, JsxAttributeValue, JsxConfig, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, SemanticEntry, SemanticNode, findEnclosingAssignmentTarget, findParentJsxAttribute, getComponentFlagFromInitPath, getComponentNameFromId, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, getPhaseKindOfFunction, hasNoneOrLooseComponentName, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isInitializedFromReact, isInitializedFromReactNative, isInstanceIdEqual, isInversePhase, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookId, isReactHookName, isRender, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectLikeCall, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, resolveJsxAttributeValue, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
838
+ export { AssignmentTarget, ClassComponent, Component, ComponentDetectionHint, ComponentEffectPhaseKind, ComponentFlag, ComponentKind, ComponentLifecyclePhaseKind, ComponentPhaseKind, ComponentPhaseRelevance, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, FindEnclosingComponentOrHookFilter, FunctionComponent, Hook, JsxAttributeValue, JsxConfig, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, SemanticEntry, SemanticNode, findEnclosingAssignmentTarget, findEnclosingComponentOrHook, findParentJsxAttribute, getComponentFlagFromInitPath, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, getPhaseKindOfFunction, hasNoneOrLooseComponentName, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isInitializedFromReact, isInitializedFromReactNative, isInsideComponentOrHook, isInstanceIdEqual, isInversePhase, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookId, isReactHookName, isRender, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectLikeCall, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, resolveJsxAttributeValue, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
package/dist/index.js CHANGED
@@ -40,6 +40,16 @@ function isReactHookName(name) {
40
40
  return name === "use" || /^use[A-Z0-9]/.test(name);
41
41
  }
42
42
 
43
+ //#endregion
44
+ //#region src/hook/hook-id.ts
45
+ function isReactHookId(id) {
46
+ switch (id.type) {
47
+ case AST_NODE_TYPES.Identifier: return isReactHookName(id.name);
48
+ case AST_NODE_TYPES.MemberExpression: return "name" in id.property && isReactHookName(id.property.name);
49
+ default: return false;
50
+ }
51
+ }
52
+
43
53
  //#endregion
44
54
  //#region src/hook/hook-is.ts
45
55
  /**
@@ -50,7 +60,11 @@ function isReactHookName(name) {
50
60
  function isReactHook(node) {
51
61
  if (node == null) return false;
52
62
  const id = AST.getFunctionId(node);
53
- return id?.name != null && isReactHookName(id.name);
63
+ switch (id?.type) {
64
+ case AST_NODE_TYPES.Identifier: return isReactHookName(id.name);
65
+ case AST_NODE_TYPES.MemberExpression: return "name" in id.property && isReactHookName(id.property.name);
66
+ default: return false;
67
+ }
54
68
  }
55
69
  /**
56
70
  * Check if the given node is a React Hook call by its name.
@@ -132,15 +146,15 @@ const isUseTransitionCall = flip(isReactHookCallWithName)("useTransition");
132
146
  //#endregion
133
147
  //#region src/hook/hook-collector.ts
134
148
  const idGen$2 = new IdGenerator("hook_");
135
- function useHookCollector() {
149
+ function useHookCollector(context) {
136
150
  const hooks = /* @__PURE__ */ new Map();
137
151
  const functionEntries = [];
152
+ const getText = (n) => context.sourceCode.getText(n);
138
153
  const getCurrentEntry = () => functionEntries.at(-1);
139
154
  const onFunctionEnter = (node) => {
140
155
  const id = AST.getFunctionId(node);
141
156
  const key = idGen$2.next();
142
- const name = id?.name;
143
- if (name != null && isReactHookName(name)) {
157
+ if (id != null && isReactHookId(id)) {
144
158
  functionEntries.push({
145
159
  key,
146
160
  node,
@@ -150,7 +164,7 @@ function useHookCollector() {
150
164
  id,
151
165
  key,
152
166
  kind: "function",
153
- name,
167
+ name: AST.toStringFormat(id, getText),
154
168
  node,
155
169
  flag: 0n,
156
170
  hint: 0n,
@@ -190,16 +204,6 @@ function useHookCollector() {
190
204
  };
191
205
  }
192
206
 
193
- //#endregion
194
- //#region src/hook/hook-id.ts
195
- function isReactHookId(id) {
196
- switch (id.type) {
197
- case AST_NODE_TYPES.Identifier: return isReactHookName(id.name);
198
- case AST_NODE_TYPES.MemberExpression: return "name" in id.property && isReactHookName(id.property.name);
199
- default: return false;
200
- }
201
- }
202
-
203
207
  //#endregion
204
208
  //#region src/hook/hook-parts.ts
205
209
  /**
@@ -572,26 +576,6 @@ function findParentJsxAttribute(node, test = constTrue) {
572
576
  return AST.findParentNode(node, guard);
573
577
  }
574
578
 
575
- //#endregion
576
- //#region src/utils/find-enclosing-assignment-target.ts
577
- /** eslint-disable jsdoc/require-param */
578
- /**
579
- * Finds the enclosing assignment target (variable, property, etc.) for a given node
580
- *
581
- * @todo Verify correctness and completeness of this function
582
- * @param node The starting node
583
- * @returns The enclosing assignment target node, or undefined if not found
584
- */
585
- function findEnclosingAssignmentTarget(node) {
586
- switch (true) {
587
- case node.type === AST_NODE_TYPES.VariableDeclarator: return node.id;
588
- case node.type === AST_NODE_TYPES.AssignmentExpression: return node.left;
589
- case node.type === AST_NODE_TYPES.PropertyDefinition: return node.key;
590
- case node.type === AST_NODE_TYPES.BlockStatement || node.type === AST_NODE_TYPES.Program || node.parent === node: return unit;
591
- default: return findEnclosingAssignmentTarget(node.parent);
592
- }
593
- }
594
-
595
579
  //#endregion
596
580
  //#region src/utils/is-from-react.ts
597
581
  /**
@@ -694,17 +678,15 @@ const isLazyCall = isReactAPICall("lazy");
694
678
  */
695
679
  const ComponentDetectionHint = {
696
680
  ...JsxDetectionHint,
697
- SkipMemo: 1n << 64n,
698
- SkipForwardRef: 1n << 65n,
699
- SkipArrayMapArgument: 1n << 66n,
700
- SkipObjectMethod: 1n << 67n,
701
- SkipClassMethod: 1n << 68n,
702
- SkipClassProperty: 1n << 69n
681
+ SkipObjectMethod: 1n << 64n,
682
+ SkipClassMethod: 1n << 65n,
683
+ SkipClassProperty: 1n << 66n,
684
+ SkipArrayMapCallback: 1n << 67n
703
685
  };
704
686
  /**
705
687
  * Default component detection hint
706
688
  */
707
- const DEFAULT_COMPONENT_DETECTION_HINT = 0n | ComponentDetectionHint.SkipBooleanLiteral | ComponentDetectionHint.SkipEmptyArray | ComponentDetectionHint.SkipArrayMapArgument | ComponentDetectionHint.SkipNumberLiteral | ComponentDetectionHint.SkipStringLiteral | ComponentDetectionHint.SkipUndefined | ComponentDetectionHint.StrictArray | ComponentDetectionHint.StrictConditional | ComponentDetectionHint.StrictLogical;
689
+ const DEFAULT_COMPONENT_DETECTION_HINT = 0n | ComponentDetectionHint.SkipArrayMapCallback | ComponentDetectionHint.SkipBooleanLiteral | ComponentDetectionHint.SkipEmptyArray | ComponentDetectionHint.SkipNumberLiteral | ComponentDetectionHint.SkipStringLiteral | ComponentDetectionHint.SkipUndefined | ComponentDetectionHint.StrictArray | ComponentDetectionHint.StrictConditional | ComponentDetectionHint.StrictLogical;
708
690
 
709
691
  //#endregion
710
692
  //#region src/component/component-is.ts
@@ -809,7 +791,7 @@ function shouldExcludeBasedOnHint(node, hint) {
809
791
  if (hint & ComponentDetectionHint.SkipObjectMethod && isMatching(FUNCTION_PATTERNS.OBJECT_METHOD)(node)) return true;
810
792
  if (hint & ComponentDetectionHint.SkipClassMethod && isMatching(FUNCTION_PATTERNS.CLASS_METHOD)(node)) return true;
811
793
  if (hint & ComponentDetectionHint.SkipClassProperty && isMatching(FUNCTION_PATTERNS.CLASS_PROPERTY)(node)) return true;
812
- if (hint & ComponentDetectionHint.SkipArrayMapArgument && AST.isArrayMapCallLoose(node.parent)) return true;
794
+ if (hint & ComponentDetectionHint.SkipArrayMapCallback && AST.isArrayMapCallLoose(node.parent)) return true;
813
795
  return false;
814
796
  }
815
797
  /**
@@ -868,6 +850,30 @@ function isComponentWrapperCallLoose(context, node) {
868
850
  if (node.type !== AST_NODE_TYPES.CallExpression) return false;
869
851
  return isComponentWrapperCall(context, node) || isUseCallbackCall(node);
870
852
  }
853
+ /**
854
+ * Check if the node is a callback function passed to a component wrapper
855
+ * @param context The ESLint rule context
856
+ * @param node The node to check
857
+ * @returns `true` if the node is a callback function passed to a component wrapper
858
+ */
859
+ function isComponentWrapperCallback(context, node) {
860
+ if (!AST.isFunction(node)) return false;
861
+ const parent = node.parent;
862
+ if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
863
+ return isComponentWrapperCall(context, parent);
864
+ }
865
+ /**
866
+ * Check if the node is a callback function passed to a component wrapper loosely
867
+ * @param context The ESLint rule context
868
+ * @param node The node to check
869
+ * @returns `true` if the node is a callback function passed to a component wrapper loosely
870
+ */
871
+ function isComponentWrapperCallbackLoose(context, node) {
872
+ if (!AST.isFunction(node)) return false;
873
+ const parent = node.parent;
874
+ if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
875
+ return isComponentWrapperCallLoose(context, parent);
876
+ }
871
877
 
872
878
  //#endregion
873
879
  //#region src/component/component-id.ts
@@ -875,8 +881,8 @@ function getFunctionComponentId(context, node) {
875
881
  const functionId = AST.getFunctionId(node);
876
882
  if (functionId != null) return functionId;
877
883
  const { parent } = node;
878
- if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === AST_NODE_TYPES.VariableDeclarator && parent.parent.id.type === AST_NODE_TYPES.Identifier) return parent.parent.id;
879
- if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent.parent) && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator && parent.parent.parent.id.type === AST_NODE_TYPES.Identifier) return parent.parent.parent.id;
884
+ if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === AST_NODE_TYPES.VariableDeclarator) return parent.parent.id;
885
+ if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent.parent) && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator) return parent.parent.parent.id;
880
886
  return unit;
881
887
  }
882
888
 
@@ -917,14 +923,6 @@ function isComponentNameLoose(name) {
917
923
  return RE_COMPONENT_NAME_LOOSE.test(name);
918
924
  }
919
925
  /**
920
- * Get component name from an identifier or identifier sequence (e.g., MemberExpression)
921
- * @param id The identifier or identifier sequence
922
- */
923
- function getComponentNameFromId(id) {
924
- if (id == null) return unit;
925
- return Array.isArray(id) ? id.map((n) => n.name).join(".") : id.name;
926
- }
927
- /**
928
926
  * Check if the function has no name or a loose component name
929
927
  * @param context The rule context
930
928
  * @param fn The function node
@@ -932,8 +930,9 @@ function getComponentNameFromId(id) {
932
930
  function hasNoneOrLooseComponentName(context, fn) {
933
931
  const id = getFunctionComponentId(context, fn);
934
932
  if (id == null) return true;
935
- const name = Array.isArray(id) ? id.at(-1)?.name : id.name;
936
- return name != null && isComponentNameLoose(name);
933
+ if (id.type === AST_NODE_TYPES.Identifier) return isComponentNameLoose(id.name);
934
+ if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) return isComponentNameLoose(id.property.name);
935
+ return false;
937
936
  }
938
937
 
939
938
  //#endregion
@@ -949,6 +948,7 @@ function useComponentCollector(context, options = {}) {
949
948
  const { collectDisplayName = false, collectHookCalls = false, hint = DEFAULT_COMPONENT_DETECTION_HINT } = options;
950
949
  const functionEntries = [];
951
950
  const components = /* @__PURE__ */ new Map();
951
+ const getText = (n) => context.sourceCode.getText(n);
952
952
  const getCurrentEntry = () => functionEntries.at(-1);
953
953
  const onFunctionEnter = (node) => {
954
954
  const key = idGen$1.next();
@@ -956,7 +956,8 @@ function useComponentCollector(context, options = {}) {
956
956
  key,
957
957
  node,
958
958
  hookCalls: [],
959
- isComponent: false
959
+ isComponent: false,
960
+ rets: []
960
961
  });
961
962
  };
962
963
  const onFunctionExit = () => {
@@ -979,11 +980,12 @@ function useComponentCollector(context, options = {}) {
979
980
  const entry = getCurrentEntry();
980
981
  if (entry == null) return;
981
982
  const { body } = entry.node;
983
+ if (body.type === AST_NODE_TYPES.BlockStatement) return;
982
984
  if (!(hasNoneOrLooseComponentName(context, entry.node) && isJsxLike(context.sourceCode, body, hint) && isComponentDefinition(context, entry.node, hint))) return;
983
985
  const initPath = AST.getFunctionInitPath(entry.node);
984
986
  const id = getFunctionComponentId(context, entry.node);
985
987
  const key = entry.key;
986
- const name = getComponentNameFromId(id);
988
+ const name = id == null ? unit : AST.toStringFormat(id, getText);
987
989
  components.set(key, {
988
990
  id,
989
991
  key,
@@ -994,7 +996,8 @@ function useComponentCollector(context, options = {}) {
994
996
  flag: getComponentFlagFromInitPath(initPath),
995
997
  hint,
996
998
  hookCalls: entry.hookCalls,
997
- initPath
999
+ initPath,
1000
+ rets: [body]
998
1001
  });
999
1002
  },
1000
1003
  ...collectDisplayName ? { [AST.SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION](node) {
@@ -1014,12 +1017,13 @@ function useComponentCollector(context, options = {}) {
1014
1017
  "ReturnStatement[type]"(node) {
1015
1018
  const entry = getCurrentEntry();
1016
1019
  if (entry == null) return;
1020
+ entry.rets.push(node.argument);
1017
1021
  if (!(hasNoneOrLooseComponentName(context, entry.node) && isJsxLike(context.sourceCode, node.argument, hint) && isComponentDefinition(context, entry.node, hint))) return;
1018
1022
  entry.isComponent = true;
1019
1023
  const initPath = AST.getFunctionInitPath(entry.node);
1020
1024
  const id = getFunctionComponentId(context, entry.node);
1021
1025
  const key = entry.key;
1022
- const name = getComponentNameFromId(id);
1026
+ const name = id == null ? unit : AST.toStringFormat(id, getText);
1023
1027
  components.set(key, {
1024
1028
  id,
1025
1029
  key,
@@ -1030,7 +1034,8 @@ function useComponentCollector(context, options = {}) {
1030
1034
  flag: getComponentFlagFromInitPath(initPath),
1031
1035
  hint,
1032
1036
  hookCalls: entry.hookCalls,
1033
- initPath
1037
+ initPath,
1038
+ rets: entry.rets
1034
1039
  });
1035
1040
  }
1036
1041
  }
@@ -1042,23 +1047,26 @@ function useComponentCollector(context, options = {}) {
1042
1047
  const idGen = new IdGenerator("class_component_");
1043
1048
  /**
1044
1049
  * Get a ctx and listeners object for the rule to collect class components
1050
+ * @param context The ESLint rule context
1045
1051
  * @returns The context and listeners for the rule
1046
1052
  */
1047
- function useComponentCollectorLegacy() {
1053
+ function useComponentCollectorLegacy(context) {
1048
1054
  const components = /* @__PURE__ */ new Map();
1049
1055
  const ctx = { getAllComponents(node) {
1050
1056
  return [...components.values()];
1051
1057
  } };
1058
+ const getText = (n) => context.sourceCode.getText(n);
1052
1059
  const collect = (node) => {
1053
1060
  if (!isClassComponent(node)) return;
1054
1061
  const id = AST.getClassId(node);
1055
1062
  const key = idGen.next();
1063
+ const name = id == null ? unit : AST.toStringFormat(id, getText);
1056
1064
  const flag = isPureComponent(node) ? ComponentFlag.PureComponent : ComponentFlag.None;
1057
1065
  components.set(key, {
1058
1066
  id,
1059
1067
  key,
1060
1068
  kind: "class",
1061
- name: id?.name,
1069
+ name,
1062
1070
  node,
1063
1071
  displayName: unit,
1064
1072
  flag,
@@ -1173,8 +1181,13 @@ function getPhaseKindOfFunction(node) {
1173
1181
  */
1174
1182
  function isRenderFunctionLoose(context, node) {
1175
1183
  if (!AST.isFunction(node)) return false;
1176
- if (AST.getFunctionId(node)?.name.startsWith("render") ?? false) return true;
1177
- return node.parent.type === AST_NODE_TYPES.JSXExpressionContainer && node.parent.parent.type === AST_NODE_TYPES.JSXAttribute && node.parent.parent.name.type === AST_NODE_TYPES.JSXIdentifier && node.parent.parent.name.name.startsWith("render");
1184
+ const id = AST.getFunctionId(node);
1185
+ switch (true) {
1186
+ case id?.type === AST_NODE_TYPES.Identifier: return id.name.startsWith("render");
1187
+ case id?.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier: return id.property.name.startsWith("render");
1188
+ case node.parent.type === AST_NODE_TYPES.JSXExpressionContainer && node.parent.parent.type === AST_NODE_TYPES.JSXAttribute && node.parent.parent.name.type === AST_NODE_TYPES.JSXIdentifier: return node.parent.parent.name.name.startsWith("render");
1189
+ }
1190
+ return false;
1178
1191
  }
1179
1192
  /**
1180
1193
  * Unsafe check whether given JSXAttribute is a render prop
@@ -1227,4 +1240,57 @@ function isDeclaredInRenderPropLoose(node) {
1227
1240
  }
1228
1241
 
1229
1242
  //#endregion
1230
- export { ComponentDetectionHint, ComponentFlag, ComponentPhaseRelevance, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, findEnclosingAssignmentTarget, findParentJsxAttribute, getComponentFlagFromInitPath, getComponentNameFromId, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, getPhaseKindOfFunction, hasNoneOrLooseComponentName, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isInitializedFromReact, isInitializedFromReactNative, isInstanceIdEqual, isInversePhase, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookId, isReactHookName, isRender, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectLikeCall, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, resolveJsxAttributeValue, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
1243
+ //#region src/hierarchy/find-enclosing-assignment-target.ts
1244
+ /** eslint-disable jsdoc/require-param */
1245
+ /**
1246
+ * Finds the enclosing assignment target (variable, property, etc.) for a given node
1247
+ *
1248
+ * @todo Verify correctness and completeness of this function
1249
+ * @param node The starting node
1250
+ * @returns The enclosing assignment target node, or undefined if not found
1251
+ */
1252
+ function findEnclosingAssignmentTarget(node) {
1253
+ switch (true) {
1254
+ case node.type === AST_NODE_TYPES.VariableDeclarator: return node.id;
1255
+ case node.type === AST_NODE_TYPES.AssignmentExpression: return node.left;
1256
+ case node.type === AST_NODE_TYPES.PropertyDefinition: return node.key;
1257
+ case node.type === AST_NODE_TYPES.BlockStatement || node.type === AST_NODE_TYPES.Program || node.parent === node: return unit;
1258
+ default: return findEnclosingAssignmentTarget(node.parent);
1259
+ }
1260
+ }
1261
+
1262
+ //#endregion
1263
+ //#region src/hierarchy/find-enclosing-component-or-hook.ts
1264
+ /**
1265
+ * Find the enclosing React component or hook for a given AST node
1266
+ * @param node The AST node to start the search from
1267
+ * @param test Optional test function to customize component or hook identification
1268
+ * @returns The enclosing component or hook node, or `null` if none is found
1269
+ */
1270
+ function findEnclosingComponentOrHook(node, test = (n, name) => {
1271
+ if (name == null) return false;
1272
+ return isComponentNameLoose(name) || isReactHookName(name);
1273
+ }) {
1274
+ const enclosingNode = AST.findParentNode(node, (n) => {
1275
+ if (!AST.isFunction(n)) return false;
1276
+ return test(n, match(AST.getFunctionId(n)).with({ type: AST_NODE_TYPES.Identifier }, (id) => id.name).with({
1277
+ type: AST_NODE_TYPES.MemberExpression,
1278
+ property: { type: AST_NODE_TYPES.Identifier }
1279
+ }, (me) => me.property.name).otherwise(() => null));
1280
+ });
1281
+ return AST.isFunction(enclosingNode) ? enclosingNode : unit;
1282
+ }
1283
+
1284
+ //#endregion
1285
+ //#region src/hierarchy/is-inside-component-or-hook.ts
1286
+ /**
1287
+ * Checks if a given AST node is inside a React component or hook
1288
+ * @param node The AST node to check
1289
+ * @returns True if the node is inside a component or hook, false otherwise
1290
+ */
1291
+ function isInsideComponentOrHook(node) {
1292
+ return findEnclosingComponentOrHook(node) != null;
1293
+ }
1294
+
1295
+ //#endregion
1296
+ export { ComponentDetectionHint, ComponentFlag, ComponentPhaseRelevance, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, findEnclosingAssignmentTarget, findEnclosingComponentOrHook, findParentJsxAttribute, getComponentFlagFromInitPath, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, getPhaseKindOfFunction, hasNoneOrLooseComponentName, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isInitializedFromReact, isInitializedFromReactNative, isInsideComponentOrHook, isInstanceIdEqual, isInversePhase, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookId, isReactHookName, isRender, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectLikeCall, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, 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.6.4",
3
+ "version": "2.6.5-beta.1",
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": {
@@ -35,10 +35,10 @@
35
35
  "@typescript-eslint/utils": "^8.53.0",
36
36
  "birecord": "^0.1.1",
37
37
  "ts-pattern": "^5.9.0",
38
- "@eslint-react/ast": "2.6.4",
39
- "@eslint-react/eff": "2.6.4",
40
- "@eslint-react/shared": "2.6.4",
41
- "@eslint-react/var": "2.6.4"
38
+ "@eslint-react/eff": "2.6.5-beta.1",
39
+ "@eslint-react/ast": "2.6.5-beta.1",
40
+ "@eslint-react/var": "2.6.5-beta.1",
41
+ "@eslint-react/shared": "2.6.5-beta.1"
42
42
  },
43
43
  "devDependencies": {
44
44
  "tsdown": "^0.20.0-beta.3",