@eslint-react/core 2.0.0-next.12 → 2.0.0-next.121

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +125 -31
  2. package/dist/index.js +113 -14
  3. package/package.json +13 -13
package/dist/index.d.ts CHANGED
@@ -2,10 +2,12 @@ import { RuleContext } from '@eslint-react/kit';
2
2
  import { TSESTree } from '@typescript-eslint/types';
3
3
  import { ESLintUtils, TSESTree as TSESTree$1 } from '@typescript-eslint/utils';
4
4
  import * as AST from '@eslint-react/ast';
5
- import { _ } from '@eslint-react/eff';
5
+ import { unit } from '@eslint-react/eff';
6
6
  import * as birecord from 'birecord';
7
7
  import { Scope } from '@typescript-eslint/scope-manager';
8
8
  import * as VAR from '@eslint-react/var';
9
+ import ts from 'typescript';
10
+ export { isFalseLiteralType, isTrueLiteralType } from 'ts-api-utils';
9
11
 
10
12
  /**
11
13
  * Determines whether inside `createElement`'s children.
@@ -80,10 +82,10 @@ interface SemanticEntry {
80
82
  }
81
83
 
82
84
  interface SemanticNode {
83
- id: _ | TSESTree.Identifier | TSESTree.Identifier[];
85
+ id: unit | TSESTree.Identifier | TSESTree.Identifier[];
84
86
  key: string;
85
87
  kind: string;
86
- name: _ | string;
88
+ name: unit | string;
87
89
  node: TSESTree.Node;
88
90
  flag: bigint;
89
91
  hint: bigint;
@@ -100,23 +102,23 @@ declare const ComponentFlag: {
100
102
  };
101
103
 
102
104
  interface FunctionComponent extends SemanticNode {
103
- id: _ | TSESTree.Identifier | TSESTree.Identifier[];
105
+ id: unit | TSESTree.Identifier | TSESTree.Identifier[];
104
106
  kind: "function";
105
107
  node: AST.TSESTreeFunction;
106
108
  flag: ComponentFlag;
107
109
  hint: ComponentDetectionHint;
108
- initPath: _ | AST.FunctionInitPath;
110
+ initPath: unit | AST.FunctionInitPath;
109
111
  hookCalls: TSESTree.CallExpression[];
110
- displayName: _ | TSESTree.Expression;
112
+ displayName: unit | TSESTree.Expression;
111
113
  }
112
114
  interface ClassComponent extends SemanticNode {
113
- id: _ | TSESTree.Identifier;
115
+ id: unit | TSESTree.Identifier;
114
116
  kind: "class";
115
117
  node: AST.TSESTreeClass;
116
118
  flag: ComponentFlag;
117
119
  hint: ComponentDetectionHint;
118
120
  methods: AST.TSESTreeMethodOrProperty[];
119
- displayName: _ | TSESTree.Expression;
121
+ displayName: unit | TSESTree.Expression;
120
122
  }
121
123
  type Component = ClassComponent | FunctionComponent;
122
124
 
@@ -136,7 +138,7 @@ declare namespace useComponentCollector {
136
138
  ctx: {
137
139
  getAllComponents: (node: TSESTree.Program) => Map<string, FunctionComponent>;
138
140
  getCurrentEntries: () => FunctionEntry[];
139
- getCurrentEntry: () => FunctionEntry | _;
141
+ getCurrentEntry: () => FunctionEntry | unit;
140
142
  };
141
143
  listeners: ESLintUtils.RuleListener;
142
144
  };
@@ -178,7 +180,7 @@ declare function useComponentCollectorLegacy(): useComponentCollectorLegacy.Retu
178
180
  declare function isFunctionOfRenderMethod(node: AST.TSESTreeFunction): boolean;
179
181
  declare function isValidComponentDefinition(context: RuleContext, node: AST.TSESTreeFunction, hint: bigint): boolean;
180
182
 
181
- declare function getFunctionComponentId(context: RuleContext, node: AST.TSESTreeFunction): TSESTree.Identifier | TSESTree.Identifier[] | _;
183
+ declare function getFunctionComponentId(context: RuleContext, node: AST.TSESTreeFunction): TSESTree.Identifier | TSESTree.Identifier[] | unit;
182
184
 
183
185
  declare function getComponentFlagFromInitPath(initPath: FunctionComponent["initPath"]): bigint;
184
186
 
@@ -217,7 +219,7 @@ declare function isGetDerivedStateFromError(node: TSESTree.Node): node is AST.TS
217
219
 
218
220
  declare function isComponentName(name: string): boolean;
219
221
  declare function isComponentNameLoose(name: string): boolean;
220
- declare function getComponentNameFromId(id: TSESTree.Identifier | TSESTree.Identifier[] | _): string | undefined;
222
+ declare function getComponentNameFromId(id: TSESTree.Identifier | TSESTree.Identifier[] | unit): string | undefined;
221
223
  declare function hasNoneOrLooseComponentName(context: RuleContext, fn: AST.TSESTreeFunction): boolean;
222
224
 
223
225
  /**
@@ -332,7 +334,7 @@ declare function isComponentWrapperCallLoose(context: RuleContext, node: TSESTre
332
334
  type EffectKind = "useEffect" | "useLayoutEffect" | "useInsertionEffect";
333
335
 
334
336
  interface Hook extends SemanticNode {
335
- id: TSESTree.Identifier | _;
337
+ id: TSESTree.Identifier | unit;
336
338
  node: AST.TSESTreeFunction;
337
339
  name: string;
338
340
  hookCalls: TSESTree.CallExpression[];
@@ -350,17 +352,17 @@ declare function useHookCollector(): useHookCollector.ReturnType;
350
352
 
351
353
  declare function isReactHookId(id: TSESTree.Identifier | TSESTree.MemberExpression): boolean;
352
354
 
353
- declare function isReactHook(node: AST.TSESTreeFunction | _): boolean;
355
+ declare function isReactHook(node: AST.TSESTreeFunction | unit): boolean;
354
356
  /**
355
357
  * Check if the given node is a React Hook call by its name.
356
358
  * @param node The node to check.
357
359
  * @returns `true` if the node is a React Hook call, `false` otherwise.
358
360
  */
359
- declare function isReactHookCall(node: TSESTree.Node | _): boolean;
360
- declare function isReactHookCallWithName(context: RuleContext, node: TSESTree.Node | _): (name: string) => boolean;
361
- declare function isReactHookCallWithNameLoose(node: TSESTree.Node | _): (name: string) => boolean;
362
- declare function isReactHookCallWithNameAlias(context: RuleContext, name: string, alias?: _ | string[]): (node: TSESTree.CallExpression) => boolean;
363
- declare function isUseEffectCallLoose(node: TSESTree.Node | _): boolean;
361
+ declare function isReactHookCall(node: TSESTree.Node | unit): boolean;
362
+ declare function isReactHookCallWithName(context: RuleContext, node: TSESTree.Node | unit): (name: string) => boolean;
363
+ declare function isReactHookCallWithNameLoose(node: TSESTree.Node | unit): (name: string) => boolean;
364
+ declare function isReactHookCallWithNameAlias(context: RuleContext, name: string, alias?: unit | string[]): (node: TSESTree.CallExpression) => boolean;
365
+ declare function isUseEffectCallLoose(node: TSESTree.Node | unit): boolean;
364
366
  declare const isUseCall: (context: RuleContext, node: TSESTree.Node | undefined) => boolean;
365
367
  declare const isUseActionStateCall: (context: RuleContext, node: TSESTree.Node | undefined) => boolean;
366
368
  declare const isUseCallbackCall: (context: RuleContext, node: TSESTree.Node | undefined) => boolean;
@@ -381,8 +383,7 @@ declare const isUseStateCall: (context: RuleContext, node: TSESTree.Node | undef
381
383
  declare const isUseSyncExternalStoreCall: (context: RuleContext, node: TSESTree.Node | undefined) => boolean;
382
384
  declare const isUseTransitionCall: (context: RuleContext, node: TSESTree.Node | undefined) => boolean;
383
385
 
384
- type HookKind = "custom" | "useActionState" | "useCallback" | "useContext" | "useDebugValue" | "useDeferredValue" | "useEffect" | "useId" | "useImperativeHandle" | "useInsertionEffect" | "useLayoutEffect" | "useMemo" | "useOptimistic" | "useReducer" | "useRef" | "useState" | "useSyncExternalStore" | "useTransition";
385
-
386
+ declare const REACT_BUILTIN_HOOK_NAMES: readonly ["use", "useActionState", "useCallback", "useContext", "useDebugValue", "useDeferredValue", "useEffect", "useFormStatus", "useId", "useImperativeHandle", "useInsertionEffect", "useLayoutEffect", "useMemo", "useOptimistic", "useReducer", "useRef", "useState", "useSyncExternalStore", "useTransition"];
386
387
  /**
387
388
  * Catch all identifiers that begin with "use" followed by an uppercase Latin
388
389
  * character to exclude identifiers like "user".
@@ -399,7 +400,7 @@ declare function isReactHookName(name: string): boolean;
399
400
  * @param initialScope The initial scope to use for variable resolution
400
401
  * @returns The JSX attribute node or undefined
401
402
  */
402
- declare function getAttribute(context: RuleContext, name: string, attributes: (TSESTree$1.JSXAttribute | TSESTree$1.JSXSpreadAttribute)[], initialScope?: Scope): TSESTree$1.JSXAttribute | TSESTree$1.JSXSpreadAttribute | _;
403
+ declare function getAttribute(context: RuleContext, name: string, attributes: (TSESTree$1.JSXAttribute | TSESTree$1.JSXSpreadAttribute)[], initialScope?: Scope): TSESTree$1.JSXAttribute | TSESTree$1.JSXSpreadAttribute | unit;
403
404
 
404
405
  /**
405
406
  * Get the stringified name of a JSX attribute
@@ -442,7 +443,7 @@ declare const DEFAULT_JSX_DETECTION_HINT: bigint;
442
443
  * @param node The AST node to check
443
444
  * @returns `true` if the node is a `JSXText` or a `Literal` node
444
445
  */
445
- declare function isJsxText(node: TSESTree$1.Node | null | _): node is TSESTree$1.JSXText | TSESTree$1.Literal;
446
+ declare function isJsxText(node: TSESTree$1.Node | null | unit): node is TSESTree$1.JSXText | TSESTree$1.Literal;
446
447
  /**
447
448
  * Heuristic decision to determine if a node is a JSX-like node.
448
449
  * @param code The sourceCode object
@@ -453,7 +454,7 @@ declare function isJsxText(node: TSESTree$1.Node | null | _): node is TSESTree$1
453
454
  */
454
455
  declare function isJsxLike(code: {
455
456
  getScope: (node: TSESTree$1.Node) => Scope;
456
- }, node: TSESTree$1.Node | _ | null, hint?: JSXDetectionHint): boolean;
457
+ }, node: TSESTree$1.Node | unit | null, hint?: JSXDetectionHint): boolean;
457
458
 
458
459
  /**
459
460
  * Get the stringified type of a JSX element
@@ -473,12 +474,12 @@ declare function hasEveryAttribute(context: RuleContext, names: string[], attrib
473
474
  * @param test The test to apply to the parent attribute
474
475
  * @returns The parent attribute node or undefined
475
476
  */
476
- declare function findParentAttribute(node: TSESTree.Node, test?: (node: TSESTree.JSXAttribute) => boolean): TSESTree.JSXAttribute | _;
477
+ declare function findParentAttribute(node: TSESTree.Node, test?: (node: TSESTree.JSXAttribute) => boolean): TSESTree.JSXAttribute | unit;
477
478
 
478
479
  declare function isHostElement(context: RuleContext, node: TSESTree.Node): boolean;
479
480
  declare function isKeyedElement(context: RuleContext, node: TSESTree.Node, initialScope?: Scope): boolean;
480
- declare function isFragmentElement(context: RuleContext, node: TSESTree.Node | null | _, allowJSXFragment?: false): node is TSESTree.JSXElement;
481
- declare function isFragmentElement(context: RuleContext, node: TSESTree.Node | null | _, allowJSXFragment?: true): node is TSESTree.JSXElement | TSESTree.JSXFragment;
481
+ declare function isFragmentElement(context: RuleContext, node: TSESTree.Node | null | unit, allowJSXFragment?: false): node is TSESTree.JSXElement;
482
+ declare function isFragmentElement(context: RuleContext, node: TSESTree.Node | null | unit, allowJSXFragment?: true): node is TSESTree.JSXElement | TSESTree.JSXFragment;
482
483
 
483
484
  /**
484
485
  * Get the stringified representation of a JSX node
@@ -487,6 +488,99 @@ declare function isFragmentElement(context: RuleContext, node: TSESTree.Node | n
487
488
  */
488
489
  declare function stringifyJsx(node: TSESTree$1.JSXIdentifier | TSESTree$1.JSXMemberExpression | TSESTree$1.JSXNamespacedName | TSESTree$1.JSXOpeningElement | TSESTree$1.JSXClosingElement | TSESTree$1.JSXOpeningFragment | TSESTree$1.JSXClosingFragment | TSESTree$1.JSXText): string;
489
490
 
491
+ declare const isAnyType: (type: ts.Type) => boolean;
492
+ declare const isBigIntType: (type: ts.Type) => boolean;
493
+ declare const isBooleanType: (type: ts.Type) => boolean;
494
+ declare const isEnumType: (type: ts.Type) => boolean;
495
+ declare const isFalsyBigIntType: (type: ts.Type) => type is ts.LiteralType & {
496
+ freshType: ts.FreshableType;
497
+ regularType: ts.FreshableType;
498
+ flags: ts.TypeFlags;
499
+ symbol: ts.Symbol;
500
+ pattern?: ts.DestructuringPattern;
501
+ aliasSymbol?: ts.Symbol;
502
+ aliasTypeArguments?: readonly ts.Type[];
503
+ getFlags: () => ts.TypeFlags;
504
+ getSymbol: () => ts.Symbol | undefined;
505
+ getProperties: () => ts.Symbol[];
506
+ getProperty: (propertyName: string) => ts.Symbol | undefined;
507
+ getApparentProperties: () => ts.Symbol[];
508
+ getCallSignatures: () => readonly ts.Signature[];
509
+ getConstructSignatures: () => readonly ts.Signature[];
510
+ getStringIndexType: () => ts.Type | undefined;
511
+ getNumberIndexType: () => ts.Type | undefined;
512
+ getBaseTypes: () => ts.BaseType[] | undefined;
513
+ getNonNullableType: () => ts.Type;
514
+ getConstraint: () => ts.Type | undefined;
515
+ getDefault: () => ts.Type | undefined;
516
+ isUnion: () => this is ts.UnionType;
517
+ isIntersection: () => this is ts.IntersectionType;
518
+ isUnionOrIntersection: () => this is ts.UnionOrIntersectionType;
519
+ isLiteral: () => this is ts.LiteralType;
520
+ isStringLiteral: () => this is ts.StringLiteralType;
521
+ isNumberLiteral: () => this is ts.NumberLiteralType;
522
+ isTypeParameter: () => this is ts.TypeParameter;
523
+ isClassOrInterface: () => this is ts.InterfaceType;
524
+ isClass: () => this is ts.InterfaceType;
525
+ isIndexType: () => this is ts.IndexType;
526
+ value: {
527
+ negative: boolean;
528
+ base10Value: "0";
529
+ };
530
+ };
531
+ declare const isFalsyNumberType: (type: ts.Type) => boolean;
532
+ declare const isFalsyStringType: (type: ts.Type) => boolean;
533
+ declare const isNeverType: (type: ts.Type) => boolean;
534
+ declare const isNullishType: (type: ts.Type) => boolean;
535
+ declare const isNumberType: (type: ts.Type) => boolean;
536
+ declare const isObjectType: (type: ts.Type) => boolean;
537
+ declare const isStringType: (type: ts.Type) => boolean;
538
+ declare const isTruthyBigIntType: (type: ts.Type) => type is ts.LiteralType & {
539
+ freshType: ts.FreshableType;
540
+ regularType: ts.FreshableType;
541
+ flags: ts.TypeFlags;
542
+ symbol: ts.Symbol;
543
+ pattern?: ts.DestructuringPattern;
544
+ aliasSymbol?: ts.Symbol;
545
+ aliasTypeArguments?: readonly ts.Type[];
546
+ getFlags: () => ts.TypeFlags;
547
+ getSymbol: () => ts.Symbol | undefined;
548
+ getProperties: () => ts.Symbol[];
549
+ getProperty: (propertyName: string) => ts.Symbol | undefined;
550
+ getApparentProperties: () => ts.Symbol[];
551
+ getCallSignatures: () => readonly ts.Signature[];
552
+ getConstructSignatures: () => readonly ts.Signature[];
553
+ getStringIndexType: () => ts.Type | undefined;
554
+ getNumberIndexType: () => ts.Type | undefined;
555
+ getBaseTypes: () => ts.BaseType[] | undefined;
556
+ getNonNullableType: () => ts.Type;
557
+ getConstraint: () => ts.Type | undefined;
558
+ getDefault: () => ts.Type | undefined;
559
+ isUnion: () => this is ts.UnionType;
560
+ isIntersection: () => this is ts.IntersectionType;
561
+ isUnionOrIntersection: () => this is ts.UnionOrIntersectionType;
562
+ isLiteral: () => this is ts.LiteralType;
563
+ isStringLiteral: () => this is ts.StringLiteralType;
564
+ isNumberLiteral: () => this is ts.NumberLiteralType;
565
+ isTypeParameter: () => this is ts.TypeParameter;
566
+ isClassOrInterface: () => this is ts.InterfaceType;
567
+ isClass: () => this is ts.InterfaceType;
568
+ isIndexType: () => this is ts.IndexType;
569
+ value: ts.PseudoBigInt;
570
+ };
571
+ declare const isTruthyNumberType: (type: ts.Type) => boolean;
572
+ declare const isTruthyStringType: (type: ts.Type) => boolean;
573
+ declare const isUnknownType: (type: ts.Type) => boolean;
574
+
575
+ type TypeVariant = "any" | "bigint" | "boolean" | "enum" | "never" | "nullish" | "number" | "object" | "string" | "unknown" | "falsy bigint" | "falsy boolean" | "falsy number" | "falsy string" | "truthy bigint" | "truthy boolean" | "truthy number" | "truthy string";
576
+ /**
577
+ * Ported from https://github.com/typescript-eslint/typescript-eslint/blob/eb736bbfc22554694400e6a4f97051d845d32e0b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts#L826 with some enhancements
578
+ * Get the variants of an array of types.
579
+ * @param types The types to get the variants of
580
+ * @returns The variants of the types
581
+ */
582
+ declare function getTypeVariants(types: ts.Type[]): Set<TypeVariant>;
583
+
490
584
  /** @internal */
491
585
  declare function getInstanceId(node: TSESTree.Node, prev?: TSESTree.Node): TSESTree.ArrayExpression | TSESTree.ArrayPattern | TSESTree.ArrowFunctionExpression | TSESTree.AssignmentExpression | TSESTree.AwaitExpression | TSESTree.BinaryExpression | 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.UnaryExpression | TSESTree.UpdateExpression | TSESTree.YieldExpression | undefined;
492
586
 
@@ -504,15 +598,15 @@ declare function isInstanceIdEqual(context: RuleContext, a: TSESTree.Node, b: TS
504
598
 
505
599
  declare namespace isReactAPI {
506
600
  type ReturnType = {
507
- (context: RuleContext, node: _ | null | TSESTree.Node): node is TSESTree.Identifier | TSESTree.MemberExpression;
508
- (context: RuleContext): (node: _ | null | TSESTree.Node) => node is TSESTree.MemberExpression | TSESTree.Identifier;
601
+ (context: RuleContext, node: unit | null | TSESTree.Node): node is TSESTree.Identifier | TSESTree.MemberExpression;
602
+ (context: RuleContext): (node: unit | null | TSESTree.Node) => node is TSESTree.MemberExpression | TSESTree.Identifier;
509
603
  };
510
604
  }
511
605
  declare function isReactAPI(api: string): isReactAPI.ReturnType;
512
606
  declare namespace isReactAPICall {
513
607
  type ReturnType = {
514
- (context: RuleContext, node: _ | null | TSESTree.Node): node is TSESTree.CallExpression;
515
- (context: RuleContext): (node: _ | null | TSESTree.Node) => node is TSESTree.CallExpression;
608
+ (context: RuleContext, node: unit | null | TSESTree.Node): node is TSESTree.CallExpression;
609
+ (context: RuleContext): (node: unit | null | TSESTree.Node) => node is TSESTree.CallExpression;
516
610
  };
517
611
  }
518
612
  declare function isReactAPICall(api: string): isReactAPICall.ReturnType;
@@ -543,4 +637,4 @@ declare const isForwardRefCall: isReactAPICall.ReturnType;
543
637
  declare const isMemoCall: isReactAPICall.ReturnType;
544
638
  declare const isLazyCall: isReactAPICall.ReturnType;
545
639
 
546
- export { type ClassComponent, type Component, ComponentDetectionHint, type ComponentEffectPhaseKind, ComponentFlag, type ComponentKind, type ComponentLifecyclePhaseKind, type ComponentPhaseKind, ComponentPhaseRelevance, type ComponentStateKind, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, type EffectKind, type FunctionComponent, type Hook, type HookKind, JSXDetectionHint, type SemanticEntry, type SemanticNode, findParentAttribute, getAttribute, getAttributeName, getAttributeValue, getComponentFlagFromInitPath, getComponentNameFromId, getElementType, getFunctionComponentId, getInstanceId, hasAnyAttribute, hasAttribute, hasEveryAttribute, hasNoneOrLooseComponentName, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFragmentElement, isFunctionOfRender, isFunctionOfRenderMethod, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHostElement, isInitializedFromReact, isInstanceIdEqual, isInversePhase, isJsxLike, isJsxText, isKeyedElement, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookId, isReactHookName, isRenderFunctionLoose, isRenderLike, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, isValidComponentDefinition, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
640
+ export { type ClassComponent, type Component, ComponentDetectionHint, type ComponentEffectPhaseKind, ComponentFlag, type ComponentKind, type ComponentLifecyclePhaseKind, type ComponentPhaseKind, ComponentPhaseRelevance, type ComponentStateKind, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, type EffectKind, type FunctionComponent, type Hook, JSXDetectionHint, REACT_BUILTIN_HOOK_NAMES, type SemanticEntry, type SemanticNode, type TypeVariant, findParentAttribute, getAttribute, getAttributeName, getAttributeValue, getComponentFlagFromInitPath, getComponentNameFromId, getElementType, getFunctionComponentId, getInstanceId, getTypeVariants, hasAnyAttribute, hasAttribute, hasEveryAttribute, hasNoneOrLooseComponentName, isAnyType, isAssignmentToThisState, isBigIntType, isBooleanType, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isEnumType, isFalsyBigIntType, isFalsyNumberType, isFalsyStringType, isForwardRef, isForwardRefCall, isFragmentElement, isFunctionOfRender, isFunctionOfRenderMethod, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHostElement, isInitializedFromReact, isInstanceIdEqual, isInversePhase, isJsxLike, isJsxText, isKeyedElement, isLazy, isLazyCall, isMemo, isMemoCall, isNeverType, isNullishType, isNumberType, isObjectType, isPureComponent, isReactAPI, isReactAPICall, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookId, isReactHookName, isRenderFunctionLoose, isRenderLike, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isStringType, isThisSetState, isTruthyBigIntType, isTruthyNumberType, isTruthyStringType, isUnknownType, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, isValidComponentDefinition, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
package/dist/index.js CHANGED
@@ -1,11 +1,14 @@
1
1
  import { AST_NODE_TYPES } from '@typescript-eslint/types';
2
2
  import * as AST14 from '@eslint-react/ast';
3
- import { flip, dual, constFalse, identity, constTrue, _ } from '@eslint-react/eff';
3
+ import { flip, dual, constFalse, identity, constTrue, unit } from '@eslint-react/eff';
4
4
  import { RegExp, Selector } from '@eslint-react/kit';
5
5
  import { coerceSettings, DEFAULT_ESLINT_REACT_SETTINGS, getId } from '@eslint-react/shared';
6
6
  import * as VAR3 from '@eslint-react/var';
7
7
  import { isMatching, P, match } from 'ts-pattern';
8
8
  import birecord from 'birecord';
9
+ import { isTypeFlagSet, isFalseLiteralType, isTrueLiteralType } from 'ts-api-utils';
10
+ export { isFalseLiteralType, isTrueLiteralType } from 'ts-api-utils';
11
+ import ts from 'typescript';
9
12
 
10
13
  // src/component/component-children.ts
11
14
  function isReactAPI(api) {
@@ -70,7 +73,7 @@ function getInstanceId(node, prev) {
70
73
  case (node.type === AST_NODE_TYPES.PropertyDefinition && node.value === prev):
71
74
  return node.key;
72
75
  case (node.type === AST_NODE_TYPES.BlockStatement || node.type === AST_NODE_TYPES.Program || node.parent === node):
73
- return _;
76
+ return unit;
74
77
  default:
75
78
  return getInstanceId(node.parent, node);
76
79
  }
@@ -108,6 +111,27 @@ function isInstanceIdEqual(context, a, b) {
108
111
  }
109
112
 
110
113
  // src/hook/hook-name.ts
114
+ var REACT_BUILTIN_HOOK_NAMES = [
115
+ "use",
116
+ "useActionState",
117
+ "useCallback",
118
+ "useContext",
119
+ "useDebugValue",
120
+ "useDeferredValue",
121
+ "useEffect",
122
+ "useFormStatus",
123
+ "useId",
124
+ "useImperativeHandle",
125
+ "useInsertionEffect",
126
+ "useLayoutEffect",
127
+ "useMemo",
128
+ "useOptimistic",
129
+ "useReducer",
130
+ "useRef",
131
+ "useState",
132
+ "useSyncExternalStore",
133
+ "useTransition"
134
+ ];
111
135
  function isReactHookName(name) {
112
136
  return name === "use" || /^use[A-Z0-9]/.test(name);
113
137
  }
@@ -411,6 +435,9 @@ function isJsxLike(code, node, hint = DEFAULT_JSX_DETECTION_HINT) {
411
435
  return !(hint & JSXDetectionHint.SkipStringLiteral);
412
436
  }
413
437
  case AST_NODE_TYPES.ArrayExpression: {
438
+ if (node.elements.length === 0) {
439
+ return !(hint & JSXDetectionHint.SkipEmptyArray);
440
+ }
414
441
  if (hint & JSXDetectionHint.StrictArray) {
415
442
  return node.elements.every((n) => isJsxLike(code, n, hint));
416
443
  }
@@ -643,7 +670,7 @@ function getFunctionComponentId(context, node) {
643
670
  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) {
644
671
  return parent.parent.parent.id;
645
672
  }
646
- return _;
673
+ return unit;
647
674
  }
648
675
 
649
676
  // src/component/component-flag.ts
@@ -674,7 +701,7 @@ function isComponentNameLoose(name) {
674
701
  return RegExp.COMPONENT_NAME_LOOSE.test(name);
675
702
  }
676
703
  function getComponentNameFromId(id) {
677
- if (id == null) return _;
704
+ if (id == null) return unit;
678
705
  return Array.isArray(id) ? id.map((n) => n.name).join(".") : id.name;
679
706
  }
680
707
  function hasNoneOrLooseComponentName(context, fn) {
@@ -702,11 +729,15 @@ function useComponentCollector(context, options = {}) {
702
729
  const entry = functionEntries.at(-1);
703
730
  if (entry == null) return;
704
731
  if (!entry.isComponent) return functionEntries.pop();
705
- const shouldDrop = AST14.getNestedReturnStatements(entry.node.body).slice().reverse().some((r) => {
706
- return context.sourceCode.getScope(r).block === entry.node && r.argument != null && !isJsxLike(context.sourceCode, r.argument, hint);
707
- });
708
- if (shouldDrop) {
709
- components.delete(entry.key);
732
+ const rets = AST14.getNestedReturnStatements(entry.node.body);
733
+ for (let i = rets.length - 1; i >= 0; i--) {
734
+ const ret = rets[i];
735
+ if (ret == null) continue;
736
+ const shouldDrop = context.sourceCode.getScope(ret).block === entry.node && ret.argument != null && !isJsxLike(context.sourceCode, ret.argument, hint);
737
+ if (shouldDrop) {
738
+ components.delete(entry.key);
739
+ break;
740
+ }
710
741
  }
711
742
  return functionEntries.pop();
712
743
  };
@@ -739,7 +770,7 @@ function useComponentCollector(context, options = {}) {
739
770
  kind: "function",
740
771
  name,
741
772
  node: entry.node,
742
- displayName: _,
773
+ displayName: unit,
743
774
  flag: getComponentFlagFromInitPath(initPath),
744
775
  hint,
745
776
  hookCalls: entry.hookCalls,
@@ -750,7 +781,7 @@ function useComponentCollector(context, options = {}) {
750
781
  [Selector.DISPLAY_NAME_ASSIGNMENT_EXPRESSION](node) {
751
782
  const { left, right } = node;
752
783
  if (left.type !== AST_NODE_TYPES.MemberExpression) return;
753
- const componentName = left.object.type === AST_NODE_TYPES.Identifier ? left.object.name : _;
784
+ const componentName = left.object.type === AST_NODE_TYPES.Identifier ? left.object.name : unit;
754
785
  const component = [...components.values()].findLast(({ name }) => name != null && name === componentName);
755
786
  if (component == null) return;
756
787
  component.displayName = right;
@@ -779,7 +810,7 @@ function useComponentCollector(context, options = {}) {
779
810
  kind: "function",
780
811
  name,
781
812
  node: entry.node,
782
- displayName: _,
813
+ displayName: unit,
783
814
  flag: getComponentFlagFromInitPath(initPath),
784
815
  hint,
785
816
  hookCalls: entry.hookCalls,
@@ -813,7 +844,7 @@ function useComponentCollectorLegacy() {
813
844
  name: id?.name,
814
845
  node,
815
846
  // TODO: Get displayName of class component
816
- displayName: _,
847
+ displayName: unit,
817
848
  flag,
818
849
  hint: 0n,
819
850
  // TODO: Get methods of class component
@@ -933,5 +964,73 @@ function isAssignmentToThisState(node) {
933
964
  const { left } = node;
934
965
  return left.type === AST_NODE_TYPES.MemberExpression && AST14.isThisExpression(left.object) && AST14.getPropertyName(left.property) === "state";
935
966
  }
967
+ var isAnyType = (type) => isTypeFlagSet(type, ts.TypeFlags.TypeParameter | ts.TypeFlags.Any);
968
+ var isBigIntType = (type) => isTypeFlagSet(type, ts.TypeFlags.BigIntLike);
969
+ var isBooleanType = (type) => isTypeFlagSet(type, ts.TypeFlags.BooleanLike);
970
+ var isEnumType = (type) => isTypeFlagSet(type, ts.TypeFlags.EnumLike);
971
+ var isFalsyBigIntType = (type) => type.isLiteral() && isMatching({ value: { base10Value: "0" } }, type);
972
+ var isFalsyNumberType = (type) => type.isNumberLiteral() && type.value === 0;
973
+ var isFalsyStringType = (type) => type.isStringLiteral() && type.value === "";
974
+ var isNeverType = (type) => isTypeFlagSet(type, ts.TypeFlags.Never);
975
+ var isNullishType = (type) => isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.VoidLike);
976
+ var isNumberType = (type) => isTypeFlagSet(type, ts.TypeFlags.NumberLike);
977
+ var isObjectType = (type) => !isTypeFlagSet(
978
+ type,
979
+ ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.VoidLike | ts.TypeFlags.BooleanLike | ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike | ts.TypeFlags.TypeParameter | ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never
980
+ );
981
+ var isStringType = (type) => isTypeFlagSet(type, ts.TypeFlags.StringLike);
982
+ var isTruthyBigIntType = (type) => type.isLiteral() && isMatching({ value: { base10Value: P.not("0") } }, type);
983
+ var isTruthyNumberType = (type) => type.isNumberLiteral() && type.value !== 0;
984
+ var isTruthyStringType = (type) => type.isStringLiteral() && type.value !== "";
985
+ var isUnknownType = (type) => isTypeFlagSet(type, ts.TypeFlags.Unknown);
986
+ function getTypeVariants(types) {
987
+ const variants = /* @__PURE__ */ new Set();
988
+ if (types.some(isUnknownType)) {
989
+ variants.add("unknown");
990
+ return variants;
991
+ }
992
+ if (types.some(isNullishType)) {
993
+ variants.add("nullish");
994
+ }
995
+ const booleans = types.filter(isBooleanType);
996
+ const boolean0 = booleans[0];
997
+ if (booleans.length === 1 && boolean0 != null) {
998
+ if (isFalseLiteralType(boolean0)) {
999
+ variants.add("falsy boolean");
1000
+ } else if (isTrueLiteralType(boolean0)) {
1001
+ variants.add("truthy boolean");
1002
+ }
1003
+ } else if (booleans.length === 2) {
1004
+ variants.add("boolean");
1005
+ }
1006
+ const strings = types.filter(isStringType);
1007
+ if (strings.length > 0) {
1008
+ const evaluated = match(strings).when((types2) => types2.every(isTruthyStringType), () => "truthy string").when((types2) => types2.every(isFalsyStringType), () => "falsy string").otherwise(() => "string");
1009
+ variants.add(evaluated);
1010
+ }
1011
+ const bigints = types.filter(isBigIntType);
1012
+ if (bigints.length > 0) {
1013
+ const evaluated = match(bigints).when((types2) => types2.every(isTruthyBigIntType), () => "truthy bigint").when((types2) => types2.every(isFalsyBigIntType), () => "falsy bigint").otherwise(() => "bigint");
1014
+ variants.add(evaluated);
1015
+ }
1016
+ const numbers = types.filter(isNumberType);
1017
+ if (numbers.length > 0) {
1018
+ const evaluated = match(numbers).when((types2) => types2.every(isTruthyNumberType), () => "truthy number").when((types2) => types2.every(isFalsyNumberType), () => "falsy number").otherwise(() => "number");
1019
+ variants.add(evaluated);
1020
+ }
1021
+ if (types.some(isEnumType)) {
1022
+ variants.add("enum");
1023
+ }
1024
+ if (types.some(isObjectType)) {
1025
+ variants.add("object");
1026
+ }
1027
+ if (types.some(isAnyType)) {
1028
+ variants.add("any");
1029
+ }
1030
+ if (types.some(isNeverType)) {
1031
+ variants.add("never");
1032
+ }
1033
+ return variants;
1034
+ }
936
1035
 
937
- export { ComponentDetectionHint, ComponentFlag, ComponentPhaseRelevance, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, JSXDetectionHint, findParentAttribute, getAttribute, getAttributeName, getAttributeValue, getComponentFlagFromInitPath, getComponentNameFromId, getElementType, getFunctionComponentId, getInstanceId, hasAnyAttribute, hasAttribute, hasEveryAttribute, hasNoneOrLooseComponentName, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFragmentElement, isFunctionOfRender, isFunctionOfRenderMethod, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHostElement, isInitializedFromReact, isInstanceIdEqual, isInversePhase, isJsxLike, isJsxText, isKeyedElement, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookId, isReactHookName, isRenderFunctionLoose, isRenderLike, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, isValidComponentDefinition, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
1036
+ export { ComponentDetectionHint, ComponentFlag, ComponentPhaseRelevance, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, JSXDetectionHint, REACT_BUILTIN_HOOK_NAMES, findParentAttribute, getAttribute, getAttributeName, getAttributeValue, getComponentFlagFromInitPath, getComponentNameFromId, getElementType, getFunctionComponentId, getInstanceId, getTypeVariants, hasAnyAttribute, hasAttribute, hasEveryAttribute, hasNoneOrLooseComponentName, isAnyType, isAssignmentToThisState, isBigIntType, isBooleanType, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isEnumType, isFalsyBigIntType, isFalsyNumberType, isFalsyStringType, isForwardRef, isForwardRefCall, isFragmentElement, isFunctionOfRender, isFunctionOfRenderMethod, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHostElement, isInitializedFromReact, isInstanceIdEqual, isInversePhase, isJsxLike, isJsxText, isKeyedElement, isLazy, isLazyCall, isMemo, isMemoCall, isNeverType, isNullishType, isNumberType, isObjectType, isPureComponent, isReactAPI, isReactAPICall, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookId, isReactHookName, isRenderFunctionLoose, isRenderLike, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isStringType, isThisSetState, isTruthyBigIntType, isTruthyNumberType, isTruthyStringType, isUnknownType, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, isValidComponentDefinition, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-react/core",
3
- "version": "2.0.0-next.12",
3
+ "version": "2.0.0-next.121",
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": {
@@ -27,24 +27,24 @@
27
27
  "./package.json"
28
28
  ],
29
29
  "dependencies": {
30
- "@typescript-eslint/scope-manager": "^8.31.1",
31
- "@typescript-eslint/type-utils": "^8.31.1",
32
- "@typescript-eslint/types": "^8.31.1",
33
- "@typescript-eslint/utils": "^8.31.1",
30
+ "@typescript-eslint/scope-manager": "^8.38.0",
31
+ "@typescript-eslint/type-utils": "^8.38.0",
32
+ "@typescript-eslint/types": "^8.38.0",
33
+ "@typescript-eslint/utils": "^8.38.0",
34
34
  "birecord": "^0.1.1",
35
- "ts-pattern": "^5.7.0",
36
- "@eslint-react/eff": "2.0.0-next.12",
37
- "@eslint-react/shared": "2.0.0-next.12",
38
- "@eslint-react/ast": "2.0.0-next.12",
39
- "@eslint-react/var": "2.0.0-next.12",
40
- "@eslint-react/kit": "2.0.0-next.12"
35
+ "ts-api-utils": "^2.1.0",
36
+ "ts-pattern": "^5.8.0",
37
+ "@eslint-react/ast": "2.0.0-next.121",
38
+ "@eslint-react/kit": "2.0.0-next.121",
39
+ "@eslint-react/shared": "2.0.0-next.121",
40
+ "@eslint-react/eff": "2.0.0-next.121",
41
+ "@eslint-react/var": "2.0.0-next.121"
41
42
  },
42
43
  "devDependencies": {
43
- "tsup": "^8.4.0",
44
+ "tsup": "^8.5.0",
44
45
  "@local/configs": "0.0.0"
45
46
  },
46
47
  "engines": {
47
- "bun": ">=1.0.15",
48
48
  "node": ">=20.19.0"
49
49
  },
50
50
  "scripts": {