@eslint-react/ast 3.0.0-next.9 → 3.0.0-rc.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +90 -68
  2. package/dist/index.js +283 -114
  3. package/package.json +11 -8
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { unit } from "@eslint-react/eff";
2
1
  import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/types";
3
2
  import { TSESTree as TSESTree$1 } from "@typescript-eslint/utils";
4
3
 
@@ -34,7 +33,7 @@ type TSESTreeProperty = TSESTree$1.PropertyDefinition | TSESTree$1.TSIndexSignat
34
33
  /**
35
34
  * Represents all JSX-related nodes in TSESTree
36
35
  */
37
- type TSESTreeJSX = TSESTree$1.JSXAttribute | TSESTree$1.JSXChild | TSESTree$1.JSXClosingElement | TSESTree$1.JSXClosingFragment | TSESTree$1.JSXElement | TSESTree$1.JSXEmptyExpression | TSESTree$1.JSXExpression | TSESTree$1.JSXExpressionContainer | TSESTree$1.JSXFragment | TSESTree$1.JSXIdentifier | TSESTree$1.JSXIdentifierToken | TSESTree$1.JSXMemberExpression | TSESTree$1.JSXNamespacedName | TSESTree$1.JSXOpeningElement | TSESTree$1.JSXOpeningFragment | TSESTree$1.JSXSpreadAttribute | TSESTree$1.JSXSpreadChild | TSESTree$1.JSXTagNameExpression | TSESTree$1.JSXText | TSESTree$1.JSXTextToken;
36
+ type TSESTreeJSX = TSESTree$1.JSXAttribute | TSESTree$1.JSXChild | TSESTree$1.JSXClosingElement | TSESTree$1.JSXClosingFragment | TSESTree$1.JSXEmptyExpression | TSESTree$1.JSXIdentifierToken | TSESTree$1.JSXOpeningElement | TSESTree$1.JSXOpeningFragment | TSESTree$1.JSXSpreadAttribute | TSESTree$1.JSXTagNameExpression | TSESTree$1.JSXTextToken;
38
37
  /**
39
38
  * Represents JSX attribute-like nodes (attributes and spread attributes)
40
39
  */
@@ -56,7 +55,7 @@ type TSESTreeTypeExpression = TSESTree$1.TSAsExpression | TSESTree$1.TSNonNullEx
56
55
  */
57
56
  type TSESTreeTypeAssertionExpression = TSESTree$1.TSAsExpression | TSESTree$1.TSNonNullExpression | TSESTree$1.TSSatisfiesExpression | TSESTree$1.TSTypeAssertion;
58
57
  /**
59
- * Represents a directive expression statement in TSESTree (e.g., "use strict";)
58
+ * Represents a directive expression statement in TSESTree (ex: "use strict";)
60
59
  */
61
60
  type TSESTreeDirective = TSESTree$1.ExpressionStatement & {
62
61
  directive: string;
@@ -73,37 +72,9 @@ type TSESTreeDirectiveLike = TSESTree$1.ExpressionStatement & {
73
72
  /**
74
73
  * Get the class identifier of a class node
75
74
  * @param node The class node to get the identifier from
76
- * @returns The class identifier or unit if not found
75
+ * @returns The class identifier or null if not found
77
76
  */
78
- declare function getClassId(node: TSESTreeClass): TSESTree.BindingName | unit;
79
- //#endregion
80
- //#region src/directive-helper.d.ts
81
- /**
82
- * Get all directive expression statements from the top of a program AST node
83
- * @param node The program AST node
84
- * @returns The array of directive string literals (e.g., "use strict")
85
- */
86
- declare function getFileDirectives(node: TSESTree.Program): TSESTreeDirective[];
87
- /**
88
- * Get all directive expression statements from the top of a function AST node
89
- * @param node The function AST node
90
- * @returns The array of directive string literals (e.g., "use memo", "use no memo")
91
- */
92
- declare function getFunctionDirectives(node: TSESTreeFunction): TSESTreeDirective[];
93
- /**
94
- * Check if a directive with the given name exists in the file or function directives
95
- * @param node The program or function AST node
96
- * @param name The directive name to check (e.g., "use strict", "use memo", "use no memo")
97
- * @returns True if the directive exists, false otherwise
98
- */
99
- declare function isDirectiveInFile(node: TSESTree.Program, name: string): boolean;
100
- /**
101
- * Check if a directive with the given name exists in the function directives
102
- * @param node The function AST node
103
- * @param name The directive name to check (e.g., "use memo", "use no memo")
104
- * @returns True if the directive exists, false otherwise
105
- */
106
- declare function isDirectiveInFunction(node: TSESTreeFunction, name: string): boolean;
77
+ declare function getClassId(node: TSESTreeClass): TSESTree.BindingName | null;
107
78
  //#endregion
108
79
  //#region src/directive-is.d.ts
109
80
  /**
@@ -120,6 +91,9 @@ declare function isDirective(node: TSESTree.Node): node is TSESTreeDirective;
120
91
  declare function isDirectiveLike(node: TSESTree.Node): node is TSESTreeDirectiveLike;
121
92
  //#endregion
122
93
  //#region src/directive-kind.d.ts
94
+ /**
95
+ * Known directive kinds in React
96
+ */
123
97
  type DirectiveKind = "use client" | "use server" | "use memo" | "use no memo";
124
98
  /**
125
99
  * Check if a node is a directive kind
@@ -136,15 +110,6 @@ declare function isDirectiveKind(kind: string): kind is DirectiveKind;
136
110
  */
137
111
  declare function isDirectiveName(name: string): boolean;
138
112
  //#endregion
139
- //#region src/expression-base.d.ts
140
- /**
141
- * Unwraps any type expressions to get the underlying JavaScript expression node.
142
- * Recursively processes nodes until a non-type expression is found.
143
- * @param node The AST node to unwrap
144
- * @returns The underlying JavaScript expression node
145
- */
146
- declare function getUnderlyingExpression(node: TSESTree.Node): Exclude<TSESTree.Node, TSESTreeTypeExpression>;
147
- //#endregion
148
113
  //#region src/expression-is.d.ts
149
114
  /**
150
115
  * Check if the given expression is a 'this' expression
@@ -190,6 +155,36 @@ declare const getNestedNewExpressions: (node: TSESTree.Node) => TSESTree.NewExpr
190
155
  */
191
156
  declare const getNestedCallExpressions: (node: TSESTree.Node) => TSESTree.CallExpression[];
192
157
  //#endregion
158
+ //#region src/file-directive.d.ts
159
+ /**
160
+ * Get all directive expression statements from the top of a program AST node
161
+ * @param node The program AST node
162
+ * @returns The array of directive string literals (ex: "use strict")
163
+ */
164
+ declare function getFileDirectives(node: TSESTree.Program): TSESTreeDirective[];
165
+ /**
166
+ * Check if a directive with the given name exists in the file or function directives
167
+ * @param node The program or function AST node
168
+ * @param name The directive name to check (ex: "use strict", "use memo", "use no memo")
169
+ * @returns True if the directive exists, false otherwise
170
+ */
171
+ declare function isDirectiveInFile(node: TSESTree.Program, name: string): boolean;
172
+ //#endregion
173
+ //#region src/function-directive.d.ts
174
+ /**
175
+ * Get all directive expression statements from the top of a function AST node
176
+ * @param node The function AST node
177
+ * @returns The array of directive string literals (ex: "use memo", "use no memo")
178
+ */
179
+ declare function getFunctionDirectives(node: TSESTreeFunction): TSESTreeDirective[];
180
+ /**
181
+ * Check if a directive with the given name exists in the function directives
182
+ * @param node The function AST node
183
+ * @param name The directive name to check (ex: "use memo", "use no memo")
184
+ * @returns True if the directive exists, false otherwise
185
+ */
186
+ declare function isDirectiveInFunction(node: TSESTreeFunction, name: string): boolean;
187
+ //#endregion
193
188
  //#region src/function-id.d.ts
194
189
  /**
195
190
  * Gets the static name of a function AST node. For function declarations it is
@@ -198,7 +193,7 @@ declare const getNestedCallExpressions: (node: TSESTree.Node) => TSESTree.CallEx
198
193
  * where JS gives anonymous function expressions names. We roughly detect the
199
194
  * same AST nodes with some exceptions to better fit our use case.
200
195
  */
201
- declare function getFunctionId(node: TSESTree.Expression | TSESTreeFunction): 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;
196
+ declare function getFunctionId(node: TSESTree.Expression | TSESTreeFunction): 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 | null;
202
197
  /**
203
198
  * Type representing the return type of getFunctionId
204
199
  */
@@ -215,14 +210,14 @@ type FunctionInitPath = readonly [TSESTree.FunctionDeclaration] | readonly [TSES
215
210
  * Determine what kind of component declaration pattern the function belongs to.
216
211
  *
217
212
  * @param node The function node to analyze
218
- * @returns The function initialization path or unit if not identifiable
213
+ * @returns The function initialization path or null if not identifiable
219
214
  */
220
- declare function getFunctionInitPath(node: TSESTreeFunction): unit | FunctionInitPath;
215
+ declare function getFunctionInitPath(node: TSESTreeFunction): null | FunctionInitPath;
221
216
  /**
222
217
  * Check if a specific function call exists in the function initialization path.
223
218
  * Useful for detecting HOCs like React.memo, React.forwardRef, etc.
224
219
  *
225
- * @param callName The name of the call to check for (e.g., "memo", "forwardRef")
220
+ * @param callName The name of the call to check for (ex: "memo", "forwardRef")
226
221
  * @param initPath The function initialization path to search in
227
222
  * @returns True if the call exists in the path, false otherwise
228
223
  */
@@ -249,7 +244,7 @@ declare function isFunctionImmediatelyInvoked(node: TSESTreeFunction): boolean;
249
244
  * @param name The name to check
250
245
  * @returns True if the node is an identifier, false otherwise
251
246
  */
252
- declare function isIdentifier(node: TSESTree.Node | null | unit, name?: string): node is TSESTree.Identifier;
247
+ declare function isIdentifier(node: TSESTree.Node | null, name?: string): node is TSESTree.Identifier;
253
248
  //#endregion
254
249
  //#region src/identifier-name.d.ts
255
250
  /**
@@ -259,6 +254,15 @@ declare function isIdentifier(node: TSESTree.Node | null | unit, name?: string):
259
254
  */
260
255
  declare function isIdentifierName(name: string): boolean;
261
256
  //#endregion
257
+ //#region src/identifier-traverse.d.ts
258
+ /**
259
+ * Get the root identifier of a (possibly nested) member expression.
260
+ * For `a.b.c`, returns the `a` Identifier node.
261
+ * @param node The expression to analyze
262
+ * @returns The root Identifier node, or null if it cannot be determined (ex: non-identifier root)
263
+ */
264
+ declare function getRootIdentifier(node: TSESTree.Expression | TSESTree.PrivateIdentifier): TSESTree.Identifier | null;
265
+ //#endregion
262
266
  //#region src/literal-is.d.ts
263
267
  /**
264
268
  * Check if a node is a literal value
@@ -272,7 +276,7 @@ declare function isLiteral(node: TSESTree.Node, type: "number"): node is TSESTre
272
276
  declare function isLiteral(node: TSESTree.Node, type: "regexp"): node is TSESTree.RegExpLiteral;
273
277
  declare function isLiteral(node: TSESTree.Node, type: "string"): node is TSESTree.StringLiteral;
274
278
  //#endregion
275
- //#region src/node-equal.d.ts
279
+ //#region src/node-equality.d.ts
276
280
  /**
277
281
  * Check if two nodes are equal
278
282
  * @param a node to compare
@@ -442,24 +446,33 @@ declare const SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION: string;
442
446
  * Find the parent node that satisfies the test function
443
447
  * @param node The AST node
444
448
  * @param test The test function
445
- * @returns The parent node that satisfies the test function or `_` if not found
449
+ * @returns The parent node that satisfies the test function or `null` if not found
446
450
  */
447
- declare function findParentNode<A extends TSESTree.Node>(node: TSESTree.Node | unit, test: (n: TSESTree.Node) => n is A): A | unit;
451
+ declare function findParentNode<A extends TSESTree.Node>(node: TSESTree.Node | null, test: (n: TSESTree.Node) => n is A): A | null;
448
452
  /**
449
- * Find the parent node that satisfies the test function or `_` if not found
453
+ * Find the parent node that satisfies the test function or `null` if not found
450
454
  * @param node The AST node
451
455
  * @param test The test function
452
456
  * @returns The parent node that satisfies the test function
453
457
  */
454
- declare function findParentNode(node: TSESTree.Node | unit, test: (node: TSESTree.Node) => boolean): TSESTree.Node | unit;
458
+ declare function findParentNode(node: TSESTree.Node | null, test: (node: TSESTree.Node) => boolean): TSESTree.Node | null;
459
+ //#endregion
460
+ //#region src/node-unwrap.d.ts
461
+ /**
462
+ * Unwraps any type expressions to get the underlying JavaScript expression node.
463
+ * Recursively processes nodes until a non-type expression is found.
464
+ * @param node The AST node to unwrap
465
+ * @returns The underlying JavaScript expression node
466
+ */
467
+ declare function getUnderlyingExpression(node: TSESTree.Node): Exclude<TSESTree.Node, TSESTreeTypeExpression>;
455
468
  //#endregion
456
- //#region src/process-env-node-env.d.ts
469
+ //#region src/pattern-process-env-node-env.d.ts
457
470
  /**
458
471
  * Check if the given node is a member expression that accesses `process.env.NODE_ENV`
459
472
  * @param node The AST node
460
473
  * @returns True if the node is a member expression that accesses `process.env.NODE_ENV`, false otherwise
461
474
  */
462
- declare function isProcessEnvNodeEnv(node: TSESTree.Node | null | unit): node is TSESTree.MemberExpression;
475
+ declare function isProcessEnvNodeEnv(node: TSESTree.Node | null): node is TSESTree.MemberExpression;
463
476
  /**
464
477
  * Check if the given node is a binary expression that compares `process.env.NODE_ENV` with a string literal.
465
478
  * @param node The AST node
@@ -467,31 +480,40 @@ declare function isProcessEnvNodeEnv(node: TSESTree.Node | null | unit): node is
467
480
  * @param value The string literal value to compare against
468
481
  * @returns True if the node is a binary expression that compares `process.env.NODE_ENV` with the specified value, false otherwise
469
482
  */
470
- declare function isProcessEnvNodeEnvCompare(node: TSESTree.Node | null | unit, operator: "===" | "!==", value: "development" | "production"): node is TSESTree.BinaryExpression;
471
- //#endregion
472
- //#region src/property-name.d.ts
473
- /**
474
- * Get the name of a property from a node
475
- * Handles identifiers, private identifiers, literals, and template literals
476
- * @param node The node to get the property name from
477
- * @returns The property name or unit if not determinable
478
- */
479
- declare function getPropertyName(node: TSESTree.Node): string | unit;
483
+ declare function isProcessEnvNodeEnvCompare(node: TSESTree.Node | null, operator: "===" | "!==", value: "development" | "production"): node is TSESTree.BinaryExpression;
480
484
  //#endregion
481
- //#region src/vitest-mock.d.ts
485
+ //#region src/pattern-vitest-mock.d.ts
482
486
  /**
483
487
  * Check if the given node is a `vi.mock`.
484
488
  * @param node The node to check
485
489
  * @returns `true` if the node is a `vi.mock`, otherwise `false`.
486
490
  * @internal
487
491
  */
488
- declare function isViMock(node: TSESTree.Node | null | unit): node is TSESTree.MemberExpression;
492
+ declare function isViMock(node: TSESTree.Node | null): node is TSESTree.MemberExpression;
489
493
  /**
490
494
  * Check if the given node is a `vi.mock` callback.
491
495
  * @param node The node to check
492
496
  * @returns `true` if the node is a `vi.mock` callback, otherwise `false`.
493
497
  * @internal
494
498
  */
495
- declare function isViMockCallback(node: TSESTree.Node | null | unit): boolean;
499
+ declare function isViMockCallback(node: TSESTree.Node | null): boolean;
500
+ //#endregion
501
+ //#region src/property-name.d.ts
502
+ /**
503
+ * Get the name of a property from a node
504
+ * Handles identifiers, private identifiers, literals, and template literals
505
+ * @param node The node to get the property name from
506
+ * @returns The property name or null if not determinable
507
+ */
508
+ declare function getPropertyName(node: TSESTree.Node): string | null;
509
+ //#endregion
510
+ //#region src/property-traverse.d.ts
511
+ /**
512
+ * Recursively traverses an object expression's properties to find a property with the specified name
513
+ * @param properties The properties of the object expression to traverse
514
+ * @param name The name of the property to find
515
+ * @returns The matching property node, or null if not found
516
+ */
517
+ declare function findProperty(properties: TSESTree.ObjectLiteralElement[], name: string): TSESTree.Property | null;
496
518
  //#endregion
497
- export { DirectiveKind, DisplayNameAssignmentExpression, FunctionID, FunctionInitPath, ImplicitReturnArrowFunctionExpression, ObjectDestructuringVariableDeclarator, SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION, SEL_IMPLICIT_RETURN_ARROW_FUNCTION_EXPRESSION, SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR, TSESTreeArrayTupleType, TSESTreeClass, TSESTreeDestructuringPattern, TSESTreeDirective, TSESTreeDirectiveLike, TSESTreeFunction, TSESTreeFunctionType, TSESTreeJSX, TSESTreeJSXAttributeLike, TSESTreeLoop, TSESTreeMethodOrProperty, TSESTreeProperty, TSESTreeTypeAssertionExpression, TSESTreeTypeDeclaration, TSESTreeTypeExpression, findParentNode, getClassId, getFileDirectives, getFullyQualifiedName, getFunctionDirectives, getFunctionId, getFunctionInitPath, getHumanReadableKind, getNestedCallExpressions, getNestedExpressionsOfType, getNestedIdentifiers, getNestedNewExpressions, getNestedReturnStatements, getPropertyName, getUnderlyingExpression, hasCallInFunctionInitPath, is, isClass, isConditional, isControlFlow, isDirective, isDirectiveInFile, isDirectiveInFunction, isDirectiveKind, isDirectiveLike, isDirectiveName, isFunction, isFunctionEmpty, isFunctionImmediatelyInvoked, isFunctionType, isIdentifier, isIdentifierName, isJSX, isJSXElement, isJSXFragment, isJSXTagNameExpression, isLineBreak, isLiteral, isLoop, isMethodOrProperty, isMultiLine, isNodeEqual, isOneOf, isProcessEnvNodeEnv, isProcessEnvNodeEnvCompare, isProperty, isThisExpressionLoose, isTypeAssertionExpression, isTypeExpression, isViMock, isViMockCallback };
519
+ export { DirectiveKind, DisplayNameAssignmentExpression, FunctionID, FunctionInitPath, ImplicitReturnArrowFunctionExpression, ObjectDestructuringVariableDeclarator, SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION, SEL_IMPLICIT_RETURN_ARROW_FUNCTION_EXPRESSION, SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR, TSESTreeArrayTupleType, TSESTreeClass, TSESTreeDestructuringPattern, TSESTreeDirective, TSESTreeDirectiveLike, TSESTreeFunction, TSESTreeFunctionType, TSESTreeJSX, TSESTreeJSXAttributeLike, TSESTreeLoop, TSESTreeMethodOrProperty, TSESTreeProperty, TSESTreeTypeAssertionExpression, TSESTreeTypeDeclaration, TSESTreeTypeExpression, findParentNode, findProperty, getClassId, getFileDirectives, getFullyQualifiedName, getFunctionDirectives, getFunctionId, getFunctionInitPath, getHumanReadableKind, getNestedCallExpressions, getNestedExpressionsOfType, getNestedIdentifiers, getNestedNewExpressions, getNestedReturnStatements, getPropertyName, getRootIdentifier, getUnderlyingExpression, hasCallInFunctionInitPath, is, isClass, isConditional, isControlFlow, isDirective, isDirectiveInFile, isDirectiveInFunction, isDirectiveKind, isDirectiveLike, isDirectiveName, isFunction, isFunctionEmpty, isFunctionImmediatelyInvoked, isFunctionType, isIdentifier, isIdentifierName, isJSX, isJSXElement, isJSXFragment, isJSXTagNameExpression, isLineBreak, isLiteral, isLoop, isMethodOrProperty, isMultiLine, isNodeEqual, isOneOf, isProcessEnvNodeEnv, isProcessEnvNodeEnvCompare, isProperty, isThisExpressionLoose, isTypeAssertionExpression, isTypeExpression, isViMock, isViMockCallback };
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
- import { dual, or, unit } from "@eslint-react/eff";
2
- import { AST_NODE_TYPES } from "@typescript-eslint/types";
1
+ import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/types";
3
2
  import { ASTUtils } from "@typescript-eslint/utils";
4
3
  import { simpleTraverse } from "@typescript-eslint/typescript-estree";
5
4
  import { delimiterCase, replace, toLowerCase } from "string-ts";
@@ -8,12 +7,12 @@ import { delimiterCase, replace, toLowerCase } from "string-ts";
8
7
  /**
9
8
  * Get the class identifier of a class node
10
9
  * @param node The class node to get the identifier from
11
- * @returns The class identifier or unit if not found
10
+ * @returns The class identifier or null if not found
12
11
  */
13
12
  function getClassId(node) {
14
13
  if (node.id != null) return node.id;
15
14
  if (node.parent.type === AST_NODE_TYPES.VariableDeclarator) return node.parent.id;
16
- return unit;
15
+ return null;
17
16
  }
18
17
 
19
18
  //#endregion
@@ -60,54 +59,6 @@ function isDirectiveLike(node) {
60
59
  return node.type === AST_NODE_TYPES.ExpressionStatement && isLiteral(node.expression, "string") && isDirectiveName(node.expression.value);
61
60
  }
62
61
 
63
- //#endregion
64
- //#region src/directive-helper.ts
65
- /**
66
- * Get all directive expression statements from the top of a program AST node
67
- * @param node The program AST node
68
- * @returns The array of directive string literals (e.g., "use strict")
69
- */
70
- function getFileDirectives(node) {
71
- const directives = [];
72
- for (const stmt of node.body) {
73
- if (!isDirective(stmt)) continue;
74
- directives.push(stmt);
75
- }
76
- return directives;
77
- }
78
- /**
79
- * Get all directive expression statements from the top of a function AST node
80
- * @param node The function AST node
81
- * @returns The array of directive string literals (e.g., "use memo", "use no memo")
82
- */
83
- function getFunctionDirectives(node) {
84
- const directives = [];
85
- if (node.body.type !== AST_NODE_TYPES.BlockStatement) return directives;
86
- for (const stmt of node.body.body) {
87
- if (!isDirective(stmt)) continue;
88
- directives.push(stmt);
89
- }
90
- return directives;
91
- }
92
- /**
93
- * Check if a directive with the given name exists in the file or function directives
94
- * @param node The program or function AST node
95
- * @param name The directive name to check (e.g., "use strict", "use memo", "use no memo")
96
- * @returns True if the directive exists, false otherwise
97
- */
98
- function isDirectiveInFile(node, name) {
99
- return getFileDirectives(node).some((d) => d.directive === name);
100
- }
101
- /**
102
- * Check if a directive with the given name exists in the function directives
103
- * @param node The function AST node
104
- * @param name The directive name to check (e.g., "use memo", "use no memo")
105
- * @returns True if the directive exists, false otherwise
106
- */
107
- function isDirectiveInFunction(node, name) {
108
- return getFunctionDirectives(node).some((d) => d.directive === name);
109
- }
110
-
111
62
  //#endregion
112
63
  //#region src/directive-kind.ts
113
64
  /**
@@ -119,6 +70,127 @@ function isDirectiveKind(kind) {
119
70
  return kind === "use client" || kind === "use server" || kind === "use memo" || kind === "use no memo";
120
71
  }
121
72
 
73
+ //#endregion
74
+ //#region ../../../.pkgs/eff/dist/index.js
75
+ function or(a, b) {
76
+ return (data) => a(data) || b(data);
77
+ }
78
+ /**
79
+ * Creates a function that can be used in a data-last (aka `pipe`able) or
80
+ * data-first style.
81
+ *
82
+ * The first parameter to `dual` is either the arity of the uncurried function
83
+ * or a predicate that determines if the function is being used in a data-first
84
+ * or data-last style.
85
+ *
86
+ * Using the arity is the most common use case, but there are some cases where
87
+ * you may want to use a predicate. For example, if you have a function that
88
+ * takes an optional argument, you can use a predicate to determine if the
89
+ * function is being used in a data-first or data-last style.
90
+ *
91
+ * You can pass either the arity of the uncurried function or a predicate
92
+ * which determines if the function is being used in a data-first or
93
+ * data-last style.
94
+ *
95
+ * **Example** (Using arity to determine data-first or data-last style)
96
+ *
97
+ * ```ts
98
+ * import { dual, pipe } from "effect/Function"
99
+ *
100
+ * const sum = dual<
101
+ * (that: number) => (self: number) => number,
102
+ * (self: number, that: number) => number
103
+ * >(2, (self, that) => self + that)
104
+ *
105
+ * console.log(sum(2, 3)) // 5
106
+ * console.log(pipe(2, sum(3))) // 5
107
+ * ```
108
+ *
109
+ * **Example** (Using call signatures to define the overloads)
110
+ *
111
+ * ```ts
112
+ * import { dual, pipe } from "effect/Function"
113
+ *
114
+ * const sum: {
115
+ * (that: number): (self: number) => number
116
+ * (self: number, that: number): number
117
+ * } = dual(2, (self: number, that: number): number => self + that)
118
+ *
119
+ * console.log(sum(2, 3)) // 5
120
+ * console.log(pipe(2, sum(3))) // 5
121
+ * ```
122
+ *
123
+ * **Example** (Using a predicate to determine data-first or data-last style)
124
+ *
125
+ * ```ts
126
+ * import { dual, pipe } from "effect/Function"
127
+ *
128
+ * const sum = dual<
129
+ * (that: number) => (self: number) => number,
130
+ * (self: number, that: number) => number
131
+ * >(
132
+ * (args) => args.length === 2,
133
+ * (self, that) => self + that
134
+ * )
135
+ *
136
+ * console.log(sum(2, 3)) // 5
137
+ * console.log(pipe(2, sum(3))) // 5
138
+ * ```
139
+ *
140
+ * @param arity - The arity of the uncurried function or a predicate that determines if the function is being used in a data-first or data-last style.
141
+ * @param body - The function to be curried.
142
+ * @since 1.0.0
143
+ */
144
+ const dual = function(arity, body) {
145
+ if (typeof arity === "function") return function() {
146
+ return arity(arguments) ? body.apply(this, arguments) : ((self) => body(self, ...arguments));
147
+ };
148
+ switch (arity) {
149
+ case 0:
150
+ case 1: throw new RangeError(`Invalid arity ${arity}`);
151
+ case 2: return function(a, b) {
152
+ if (arguments.length >= 2) return body(a, b);
153
+ return function(self) {
154
+ return body(self, a);
155
+ };
156
+ };
157
+ case 3: return function(a, b, c) {
158
+ if (arguments.length >= 3) return body(a, b, c);
159
+ return function(self) {
160
+ return body(self, a, b);
161
+ };
162
+ };
163
+ default: return function() {
164
+ if (arguments.length >= arity) return body.apply(this, arguments);
165
+ const args = arguments;
166
+ return function(self) {
167
+ return body(self, ...args);
168
+ };
169
+ };
170
+ }
171
+ };
172
+ /**
173
+ * Composes two functions, `ab` and `bc` into a single function that takes in an argument `a` of type `A` and returns a result of type `C`.
174
+ * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`.
175
+ *
176
+ * @param self - The first function to apply (or the composed function in data-last style).
177
+ * @param bc - The second function to apply.
178
+ * @returns A composed function that applies both functions in sequence.
179
+ * @example
180
+ * ```ts
181
+ * import * as assert from "node:assert"
182
+ * import { compose } from "effect/Function"
183
+ *
184
+ * const increment = (n: number) => n + 1;
185
+ * const square = (n: number) => n * n;
186
+ *
187
+ * assert.strictEqual(compose(increment, square)(2), 9);
188
+ * ```
189
+ *
190
+ * @since 1.0.0
191
+ */
192
+ const compose = dual(2, (ab, bc) => (a) => bc(ab(a)));
193
+
122
194
  //#endregion
123
195
  //#region src/node-is.ts
124
196
  /**
@@ -275,7 +347,7 @@ const isTypeAssertionExpression = isOneOf([
275
347
  ]);
276
348
 
277
349
  //#endregion
278
- //#region src/expression-base.ts
350
+ //#region src/node-unwrap.ts
279
351
  /**
280
352
  * Unwraps any type expressions to get the underlying JavaScript expression node.
281
353
  * Recursively processes nodes until a non-type expression is found.
@@ -303,13 +375,13 @@ function isThisExpressionLoose(node) {
303
375
  //#endregion
304
376
  //#region src/node-traverse.ts
305
377
  function findParentNode(node, test) {
306
- if (node == null) return unit;
378
+ if (node == null) return null;
307
379
  let parent = node.parent;
308
380
  while (parent != null && parent.type !== AST_NODE_TYPES.Program) {
309
381
  if (test(parent)) return parent;
310
382
  parent = parent.parent;
311
383
  }
312
- return unit;
384
+ return null;
313
385
  }
314
386
 
315
387
  //#endregion
@@ -355,8 +427,8 @@ function getNestedIdentifiers(node) {
355
427
  identifiers.push(...chunk);
356
428
  }
357
429
  if (node.type === AST_NODE_TYPES.MemberExpression) {
358
- const chunk = getNestedIdentifiers(node.object);
359
- identifiers.push(...chunk);
430
+ identifiers.push(...getNestedIdentifiers(node.object));
431
+ if (node.computed) identifiers.push(...getNestedIdentifiers(node.property));
360
432
  }
361
433
  if (node.type === AST_NODE_TYPES.UnaryExpression) {
362
434
  const chunk = getNestedIdentifiers(node.argument);
@@ -378,6 +450,22 @@ function getNestedIdentifiers(node) {
378
450
  const chunk = getNestedIdentifiers(node.expression);
379
451
  identifiers.push(...chunk);
380
452
  }
453
+ if (node.type === AST_NODE_TYPES.ConditionalExpression) {
454
+ identifiers.push(...getNestedIdentifiers(node.test));
455
+ identifiers.push(...getNestedIdentifiers(node.consequent));
456
+ identifiers.push(...getNestedIdentifiers(node.alternate));
457
+ }
458
+ if (node.type === AST_NODE_TYPES.AwaitExpression) identifiers.push(...getNestedIdentifiers(node.argument));
459
+ if (node.type === AST_NODE_TYPES.YieldExpression && node.argument != null) identifiers.push(...getNestedIdentifiers(node.argument));
460
+ if (node.type === AST_NODE_TYPES.UpdateExpression) identifiers.push(...getNestedIdentifiers(node.argument));
461
+ if (node.type === AST_NODE_TYPES.CallExpression || node.type === AST_NODE_TYPES.NewExpression) identifiers.push(...getNestedIdentifiers(node.callee));
462
+ if (node.type === AST_NODE_TYPES.TaggedTemplateExpression) {
463
+ identifiers.push(...getNestedIdentifiers(node.tag));
464
+ identifiers.push(...getNestedIdentifiers(node.quasi));
465
+ }
466
+ if (node.type === AST_NODE_TYPES.ImportExpression) identifiers.push(...getNestedIdentifiers(node.source));
467
+ if (node.type === AST_NODE_TYPES.TSTypeAssertion) identifiers.push(...getNestedIdentifiers(node.expression));
468
+ if (node.type === AST_NODE_TYPES.TSInstantiationExpression) identifiers.push(...getNestedIdentifiers(node.expression));
381
469
  return identifiers;
382
470
  }
383
471
  /**
@@ -403,84 +491,77 @@ function getNestedReturnStatements(node) {
403
491
  */
404
492
  function getNestedExpressionsOfType(type) {
405
493
  const isNodeOfType = is(type);
406
- return (node) => {
407
- const boundGetNestedExpressionsOfType = getNestedExpressionsOfType(type);
494
+ const recurse = (node) => {
408
495
  const expressions = [];
409
496
  if (isNodeOfType(node)) expressions.push(node);
410
497
  if ("arguments" in node) {
411
- const chunk = node.arguments.flatMap(getNestedExpressionsOfType(type));
498
+ const chunk = node.arguments.flatMap(recurse);
412
499
  expressions.push(...chunk);
413
500
  }
414
501
  if ("expression" in node && node.expression !== true && node.expression !== false) {
415
- const chunk = boundGetNestedExpressionsOfType(node.expression);
502
+ const chunk = recurse(node.expression);
416
503
  expressions.push(...chunk);
417
504
  }
418
505
  if ("left" in node) {
419
- const chunk = boundGetNestedExpressionsOfType(node.left);
506
+ const chunk = recurse(node.left);
420
507
  expressions.push(...chunk);
421
508
  }
422
509
  if ("right" in node) {
423
- const chunk = boundGetNestedExpressionsOfType(node.right);
510
+ const chunk = recurse(node.right);
424
511
  expressions.push(...chunk);
425
512
  }
426
513
  if ("test" in node && node.test != null) {
427
- const chunk = boundGetNestedExpressionsOfType(node.test);
514
+ const chunk = recurse(node.test);
428
515
  expressions.push(...chunk);
429
516
  }
430
517
  if ("consequent" in node) {
431
- const chunk = Array.isArray(node.consequent) ? node.consequent.flatMap(boundGetNestedExpressionsOfType) : boundGetNestedExpressionsOfType(node.consequent);
518
+ const chunk = Array.isArray(node.consequent) ? node.consequent.flatMap(recurse) : recurse(node.consequent);
432
519
  expressions.push(...chunk);
433
520
  }
434
521
  if ("alternate" in node && node.alternate != null) {
435
- const chunk = Array.isArray(node.alternate) ? node.alternate.flatMap(boundGetNestedExpressionsOfType) : boundGetNestedExpressionsOfType(node.alternate);
522
+ const chunk = Array.isArray(node.alternate) ? node.alternate.flatMap(recurse) : recurse(node.alternate);
436
523
  expressions.push(...chunk);
437
524
  }
438
525
  if ("elements" in node) {
439
- const chunk = node.elements.filter((x) => x != null).flatMap(getNestedExpressionsOfType(type));
526
+ const chunk = node.elements.filter((x) => x != null).flatMap(recurse);
440
527
  expressions.push(...chunk);
441
528
  }
442
529
  if ("properties" in node) {
443
- const chunk = node.properties.flatMap(boundGetNestedExpressionsOfType);
530
+ const chunk = node.properties.flatMap(recurse);
444
531
  expressions.push(...chunk);
445
532
  }
446
533
  if ("expressions" in node) {
447
- const chunk = node.expressions.flatMap(boundGetNestedExpressionsOfType);
534
+ const chunk = node.expressions.flatMap(recurse);
448
535
  expressions.push(...chunk);
449
536
  }
450
537
  if (node.type === AST_NODE_TYPES.Property) {
451
- const chunk = boundGetNestedExpressionsOfType(node.value);
538
+ const chunk = recurse(node.value);
452
539
  expressions.push(...chunk);
453
540
  }
454
541
  if (node.type === AST_NODE_TYPES.SpreadElement) {
455
- const chunk = boundGetNestedExpressionsOfType(node.argument);
542
+ const chunk = recurse(node.argument);
456
543
  expressions.push(...chunk);
457
544
  }
458
545
  if (node.type === AST_NODE_TYPES.MemberExpression) {
459
- const chunk = boundGetNestedExpressionsOfType(node.object);
460
- expressions.push(...chunk);
546
+ expressions.push(...recurse(node.object));
547
+ if (node.computed) expressions.push(...recurse(node.property));
461
548
  }
462
549
  if (node.type === AST_NODE_TYPES.UnaryExpression) {
463
- const chunk = boundGetNestedExpressionsOfType(node.argument);
464
- expressions.push(...chunk);
465
- }
466
- if (node.type === AST_NODE_TYPES.ChainExpression) {
467
- const chunk = boundGetNestedExpressionsOfType(node.expression);
468
- expressions.push(...chunk);
469
- }
470
- if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
471
- const chunk = boundGetNestedExpressionsOfType(node.expression);
472
- expressions.push(...chunk);
473
- }
474
- if (node.type === AST_NODE_TYPES.TSAsExpression) {
475
- const chunk = boundGetNestedExpressionsOfType(node.expression);
550
+ const chunk = recurse(node.argument);
476
551
  expressions.push(...chunk);
477
552
  }
478
- if (node.type === AST_NODE_TYPES.TSSatisfiesExpression) {
479
- const chunk = boundGetNestedExpressionsOfType(node.expression);
480
- expressions.push(...chunk);
553
+ if (node.type === AST_NODE_TYPES.AwaitExpression) expressions.push(...recurse(node.argument));
554
+ if (node.type === AST_NODE_TYPES.YieldExpression && node.argument != null) expressions.push(...recurse(node.argument));
555
+ if (node.type === AST_NODE_TYPES.UpdateExpression) expressions.push(...recurse(node.argument));
556
+ if (node.type === AST_NODE_TYPES.CallExpression || node.type === AST_NODE_TYPES.NewExpression) expressions.push(...recurse(node.callee));
557
+ if (node.type === AST_NODE_TYPES.TaggedTemplateExpression) {
558
+ expressions.push(...recurse(node.tag));
559
+ expressions.push(...recurse(node.quasi));
481
560
  }
561
+ if (node.type === AST_NODE_TYPES.ImportExpression) expressions.push(...recurse(node.source));
482
562
  return expressions;
483
563
  };
564
+ return recurse;
484
565
  }
485
566
  /**
486
567
  * Get all nested new expressions in an expression like node
@@ -495,6 +576,57 @@ const getNestedNewExpressions = getNestedExpressionsOfType(AST_NODE_TYPES.NewExp
495
576
  */
496
577
  const getNestedCallExpressions = getNestedExpressionsOfType(AST_NODE_TYPES.CallExpression);
497
578
 
579
+ //#endregion
580
+ //#region src/file-directive.ts
581
+ /**
582
+ * Get all directive expression statements from the top of a program AST node
583
+ * @param node The program AST node
584
+ * @returns The array of directive string literals (ex: "use strict")
585
+ */
586
+ function getFileDirectives(node) {
587
+ const directives = [];
588
+ for (const stmt of node.body) {
589
+ if (!isDirective(stmt)) continue;
590
+ directives.push(stmt);
591
+ }
592
+ return directives;
593
+ }
594
+ /**
595
+ * Check if a directive with the given name exists in the file or function directives
596
+ * @param node The program or function AST node
597
+ * @param name The directive name to check (ex: "use strict", "use memo", "use no memo")
598
+ * @returns True if the directive exists, false otherwise
599
+ */
600
+ function isDirectiveInFile(node, name) {
601
+ return getFileDirectives(node).some((d) => d.directive === name);
602
+ }
603
+
604
+ //#endregion
605
+ //#region src/function-directive.ts
606
+ /**
607
+ * Get all directive expression statements from the top of a function AST node
608
+ * @param node The function AST node
609
+ * @returns The array of directive string literals (ex: "use memo", "use no memo")
610
+ */
611
+ function getFunctionDirectives(node) {
612
+ const directives = [];
613
+ if (node.body.type !== AST_NODE_TYPES.BlockStatement) return directives;
614
+ for (const stmt of node.body.body) {
615
+ if (!isDirective(stmt)) continue;
616
+ directives.push(stmt);
617
+ }
618
+ return directives;
619
+ }
620
+ /**
621
+ * Check if a directive with the given name exists in the function directives
622
+ * @param node The function AST node
623
+ * @param name The directive name to check (ex: "use memo", "use no memo")
624
+ * @returns True if the directive exists, false otherwise
625
+ */
626
+ function isDirectiveInFunction(node, name) {
627
+ return getFunctionDirectives(node).some((d) => d.directive === name);
628
+ }
629
+
498
630
  //#endregion
499
631
  //#region src/function-id.ts
500
632
  /**
@@ -515,7 +647,7 @@ function getFunctionId(node) {
515
647
  case node.parent.type === AST_NODE_TYPES.ConditionalExpression: return getFunctionId(node.parent);
516
648
  case isTypeAssertionExpression(node.parent): return getFunctionId(node.parent);
517
649
  }
518
- return unit;
650
+ return null;
519
651
  }
520
652
 
521
653
  //#endregion
@@ -525,11 +657,12 @@ function getFunctionId(node) {
525
657
  * Determine what kind of component declaration pattern the function belongs to.
526
658
  *
527
659
  * @param node The function node to analyze
528
- * @returns The function initialization path or unit if not identifiable
660
+ * @returns The function initialization path or null if not identifiable
529
661
  */
530
662
  function getFunctionInitPath(node) {
531
663
  if (node.type === AST_NODE_TYPES.FunctionDeclaration) return [node];
532
- const { parent } = node;
664
+ let parent = node.parent;
665
+ while (isTypeExpression(parent)) parent = parent.parent;
533
666
  switch (true) {
534
667
  case parent.type === AST_NODE_TYPES.VariableDeclarator: return [
535
668
  parent.parent,
@@ -569,13 +702,13 @@ function getFunctionInitPath(node) {
569
702
  node
570
703
  ];
571
704
  }
572
- return unit;
705
+ return null;
573
706
  }
574
707
  /**
575
708
  * Check if a specific function call exists in the function initialization path.
576
709
  * Useful for detecting HOCs like React.memo, React.forwardRef, etc.
577
710
  *
578
- * @param callName The name of the call to check for (e.g., "memo", "forwardRef")
711
+ * @param callName The name of the call to check for (ex: "memo", "forwardRef")
579
712
  * @param initPath The function initialization path to search in
580
713
  * @returns True if the call exists in the path, false otherwise
581
714
  */
@@ -632,7 +765,24 @@ function isIdentifierName(name) {
632
765
  }
633
766
 
634
767
  //#endregion
635
- //#region src/node-equal.ts
768
+ //#region src/identifier-traverse.ts
769
+ /**
770
+ * Get the root identifier of a (possibly nested) member expression.
771
+ * For `a.b.c`, returns the `a` Identifier node.
772
+ * @param node The expression to analyze
773
+ * @returns The root Identifier node, or null if it cannot be determined (ex: non-identifier root)
774
+ */
775
+ function getRootIdentifier(node) {
776
+ const expr = getUnderlyingExpression(node);
777
+ switch (expr.type) {
778
+ case AST_NODE_TYPES.Identifier: return expr;
779
+ case AST_NODE_TYPES.MemberExpression: return getRootIdentifier(expr.object);
780
+ default: return null;
781
+ }
782
+ }
783
+
784
+ //#endregion
785
+ //#region src/node-equality.ts
636
786
  /**
637
787
  * Check if two nodes are equal
638
788
  * @param a node to compare
@@ -734,7 +884,7 @@ const SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION = [
734
884
  ].join("");
735
885
 
736
886
  //#endregion
737
- //#region src/process-env-node-env.ts
887
+ //#region src/pattern-process-env-node-env.ts
738
888
  /**
739
889
  * Check if the given node is a member expression that accesses `process.env.NODE_ENV`
740
890
  * @param node The AST node
@@ -760,23 +910,7 @@ function isProcessEnvNodeEnvCompare(node, operator, value) {
760
910
  }
761
911
 
762
912
  //#endregion
763
- //#region src/property-name.ts
764
- /**
765
- * Get the name of a property from a node
766
- * Handles identifiers, private identifiers, literals, and template literals
767
- * @param node The node to get the property name from
768
- * @returns The property name or unit if not determinable
769
- */
770
- function getPropertyName(node) {
771
- if (isTypeExpression(node)) return getPropertyName(getUnderlyingExpression(node));
772
- if (node.type === AST_NODE_TYPES.Identifier || node.type === AST_NODE_TYPES.PrivateIdentifier) return node.name;
773
- if (node.type === AST_NODE_TYPES.Literal) return String(node.value);
774
- if (node.type === AST_NODE_TYPES.TemplateLiteral && node.expressions.length === 0) return node.quasis[0]?.value.raw;
775
- return unit;
776
- }
777
-
778
- //#endregion
779
- //#region src/vitest-mock.ts
913
+ //#region src/pattern-vitest-mock.ts
780
914
  /**
781
915
  * Check if the given node is a `vi.mock`.
782
916
  * @param node The node to check
@@ -797,4 +931,39 @@ function isViMockCallback(node) {
797
931
  }
798
932
 
799
933
  //#endregion
800
- export { SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION, SEL_IMPLICIT_RETURN_ARROW_FUNCTION_EXPRESSION, SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR, findParentNode, getClassId, getFileDirectives, getFullyQualifiedName, getFunctionDirectives, getFunctionId, getFunctionInitPath, getHumanReadableKind, getNestedCallExpressions, getNestedExpressionsOfType, getNestedIdentifiers, getNestedNewExpressions, getNestedReturnStatements, getPropertyName, getUnderlyingExpression, hasCallInFunctionInitPath, is, isClass, isConditional, isControlFlow, isDirective, isDirectiveInFile, isDirectiveInFunction, isDirectiveKind, isDirectiveLike, isDirectiveName, isFunction, isFunctionEmpty, isFunctionImmediatelyInvoked, isFunctionType, isIdentifier, isIdentifierName, isJSX, isJSXElement, isJSXFragment, isJSXTagNameExpression, isLineBreak, isLiteral, isLoop, isMethodOrProperty, isMultiLine, isNodeEqual, isOneOf, isProcessEnvNodeEnv, isProcessEnvNodeEnvCompare, isProperty, isThisExpressionLoose, isTypeAssertionExpression, isTypeExpression, isViMock, isViMockCallback };
934
+ //#region src/property-name.ts
935
+ /**
936
+ * Get the name of a property from a node
937
+ * Handles identifiers, private identifiers, literals, and template literals
938
+ * @param node The node to get the property name from
939
+ * @returns The property name or null if not determinable
940
+ */
941
+ function getPropertyName(node) {
942
+ if (isTypeExpression(node)) return getPropertyName(getUnderlyingExpression(node));
943
+ if (node.type === AST_NODE_TYPES.Identifier || node.type === AST_NODE_TYPES.PrivateIdentifier) return node.name;
944
+ if (node.type === AST_NODE_TYPES.Literal) return String(node.value);
945
+ if (node.type === AST_NODE_TYPES.TemplateLiteral && node.expressions.length === 0) return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw ?? null;
946
+ return null;
947
+ }
948
+
949
+ //#endregion
950
+ //#region src/property-traverse.ts
951
+ /**
952
+ * Recursively traverses an object expression's properties to find a property with the specified name
953
+ * @param properties The properties of the object expression to traverse
954
+ * @param name The name of the property to find
955
+ * @returns The matching property node, or null if not found
956
+ */
957
+ function findProperty(properties, name) {
958
+ for (const prop of properties) {
959
+ if (prop.type === AST_NODE_TYPES.Property && getPropertyName(prop.key) === name) return prop;
960
+ if (prop.type === AST_NODE_TYPES.SpreadElement && prop.argument.type === AST_NODE_TYPES.ObjectExpression) {
961
+ const found = findProperty(prop.argument.properties, name);
962
+ if (found != null) return found;
963
+ }
964
+ }
965
+ return null;
966
+ }
967
+
968
+ //#endregion
969
+ export { SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION, SEL_IMPLICIT_RETURN_ARROW_FUNCTION_EXPRESSION, SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR, findParentNode, findProperty, getClassId, getFileDirectives, getFullyQualifiedName, getFunctionDirectives, getFunctionId, getFunctionInitPath, getHumanReadableKind, getNestedCallExpressions, getNestedExpressionsOfType, getNestedIdentifiers, getNestedNewExpressions, getNestedReturnStatements, getPropertyName, getRootIdentifier, getUnderlyingExpression, hasCallInFunctionInitPath, is, isClass, isConditional, isControlFlow, isDirective, isDirectiveInFile, isDirectiveInFunction, isDirectiveKind, isDirectiveLike, isDirectiveName, isFunction, isFunctionEmpty, isFunctionImmediatelyInvoked, isFunctionType, isIdentifier, isIdentifierName, isJSX, isJSXElement, isJSXFragment, isJSXTagNameExpression, isLineBreak, isLiteral, isLoop, isMethodOrProperty, isMultiLine, isNodeEqual, isOneOf, isProcessEnvNodeEnv, isProcessEnvNodeEnvCompare, isProperty, isThisExpressionLoose, isTypeAssertionExpression, isTypeExpression, isViMock, isViMockCallback };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-react/ast",
3
- "version": "3.0.0-next.9",
3
+ "version": "3.0.0-rc.1",
4
4
  "description": "ESLint React's TSESTree AST utility module.",
5
5
  "homepage": "https://github.com/Rel1cx/eslint-react",
6
6
  "bugs": {
@@ -33,23 +33,26 @@
33
33
  "@typescript-eslint/types": "canary",
34
34
  "@typescript-eslint/typescript-estree": "canary",
35
35
  "@typescript-eslint/utils": "canary",
36
- "string-ts": "^2.3.1",
37
- "@eslint-react/eff": "3.0.0-next.9"
36
+ "string-ts": "^2.3.1"
38
37
  },
39
38
  "devDependencies": {
40
- "tsdown": "^0.20.3",
41
- "@local/configs": "0.0.0"
39
+ "tsdown": "^0.21.2",
40
+ "@local/configs": "0.0.0",
41
+ "@local/eff": "3.0.0-beta.72"
42
42
  },
43
43
  "peerDependencies": {
44
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
45
- "typescript": ">=4.8.4 <6.0.0"
44
+ "eslint": "^10.0.0",
45
+ "typescript": "*"
46
46
  },
47
47
  "engines": {
48
48
  "node": ">=22.0.0"
49
49
  },
50
+ "inlinedDependencies": {
51
+ "@local/eff": "workspace:*"
52
+ },
50
53
  "scripts": {
51
54
  "build": "tsdown --dts-resolve",
52
55
  "lint:publish": "publint",
53
- "lint:ts": "tsc --noEmit"
56
+ "lint:ts": "tsl"
54
57
  }
55
58
  }