0
# AST Utilities
1
2
Tools for manipulating and analyzing TypeScript Abstract Syntax Trees, including type guards, predicates, helper functions, and pattern matching utilities.
3
4
## Capabilities
5
6
### Node Type Guards
7
8
Type guards for checking AST node types with full TypeScript type safety.
9
10
```typescript { .api }
11
/**
12
* Creates a type guard function for a specific AST node type
13
* @param nodeType - The AST node type to check for
14
* @returns Type guard function that narrows the node type
15
*/
16
function isNodeOfType<NodeType extends TSESTree.AST_NODE_TYPES>(
17
nodeType: NodeType
18
): (node: TSESTree.Node | null | undefined) => node is Extract<TSESTree.Node, { type: NodeType }>;
19
20
/**
21
* Creates a type guard function for multiple AST node types
22
* @param nodeTypes - Array of AST node types to check for
23
* @returns Type guard function that narrows to one of the specified types
24
*/
25
function isNodeOfTypes<NodeTypes extends readonly TSESTree.AST_NODE_TYPES[]>(
26
nodeTypes: NodeTypes
27
): (node: TSESTree.Node | null | undefined) => node is Extract<TSESTree.Node, { type: NodeTypes[number] }>;
28
29
/**
30
* Creates a conditional type guard with additional constraints
31
* @param nodeType - The AST node type to check for
32
* @param conditions - Additional property conditions to match
33
* @returns Type guard function with type and condition checking
34
*/
35
function isNodeOfTypeWithConditions<
36
NodeType extends TSESTree.AST_NODE_TYPES,
37
Conditions extends Partial<Extract<TSESTree.Node, { type: NodeType }>>
38
>(
39
nodeType: NodeType,
40
conditions: Conditions
41
): (node: TSESTree.Node | null | undefined) => node is Extract<TSESTree.Node, { type: NodeType }> & Conditions;
42
43
/**
44
* Creates a conditional type guard for tokens
45
* @param tokenType - Token type to check for
46
* @param conditions - Additional token conditions
47
* @returns Type guard function for tokens
48
*/
49
function isTokenOfTypeWithConditions<
50
TokenType extends TSESTree.AST_TOKEN_TYPES,
51
Conditions extends Partial<Extract<TSESTree.Token, { type: TokenType }>>
52
>(
53
tokenType: TokenType,
54
conditions: Conditions
55
): (token: TSESTree.Token | null | undefined) => token is Extract<TSESTree.Token, { type: TokenType }> & Conditions;
56
57
/**
58
* Creates a negated conditional type guard for tokens
59
* @param tokenType - Token type to exclude
60
* @param conditions - Additional token conditions to exclude
61
* @returns Negated type guard function
62
*/
63
function isNotTokenOfTypeWithConditions<
64
TokenType extends TSESTree.AST_TOKEN_TYPES,
65
Conditions extends Partial<Extract<TSESTree.Token, { type: TokenType }>>
66
>(
67
tokenType: TokenType,
68
conditions: Conditions
69
): (token: TSESTree.Token | null | undefined) => token is Exclude<TSESTree.Token, Extract<TSESTree.Token, { type: TokenType }> & Conditions>;
70
```
71
72
### Node Predicates
73
74
Predicate functions for identifying specific types of AST nodes.
75
76
```typescript { .api }
77
/**
78
* Checks if a node is an optional call expression (foo?.())
79
*/
80
function isOptionalCallExpression(node: TSESTree.Node | null | undefined): node is TSESTree.CallExpression & { optional: true };
81
82
/**
83
* Checks if a node is a logical OR operator (||)
84
*/
85
function isLogicalOrOperator(node: TSESTree.Node | null | undefined): node is TSESTree.LogicalExpression & { operator: '||' };
86
87
/**
88
* Checks if a node is a type assertion (x as foo or <foo>x)
89
*/
90
function isTypeAssertion(node: TSESTree.Node | null | undefined): node is TSESTree.TSTypeAssertion | TSESTree.TSAsExpression;
91
92
/**
93
* Checks if a node is a variable declarator
94
*/
95
function isVariableDeclarator(node: TSESTree.Node | null | undefined): node is TSESTree.VariableDeclarator;
96
97
/**
98
* Checks if a node is any kind of function (declaration, expression, or arrow)
99
*/
100
function isFunction(node: TSESTree.Node | null | undefined): node is TSESTree.FunctionLike;
101
102
/**
103
* Checks if a node is a function type
104
*/
105
function isFunctionType(node: TSESTree.Node | null | undefined): node is TSESTree.TSFunctionType | TSESTree.TSConstructorType;
106
107
/**
108
* Checks if a node is a function or function type
109
*/
110
function isFunctionOrFunctionType(node: TSESTree.Node | null | undefined): node is TSESTree.FunctionLike | TSESTree.TSFunctionType | TSESTree.TSConstructorType;
111
112
/**
113
* Checks if a node is a TypeScript function type
114
*/
115
function isTSFunctionType(node: TSESTree.Node | null | undefined): node is TSESTree.TSFunctionType;
116
117
/**
118
* Checks if a node is a TypeScript constructor type
119
*/
120
function isTSConstructorType(node: TSESTree.Node | null | undefined): node is TSESTree.TSConstructorType;
121
122
/**
123
* Checks if a node is a class or type element
124
*/
125
function isClassOrTypeElement(node: TSESTree.Node | null | undefined): node is TSESTree.ClassElement | TSESTree.TypeElement;
126
127
/**
128
* Checks if a node is a constructor method
129
*/
130
function isConstructor(node: TSESTree.Node | null | undefined): node is TSESTree.MethodDefinition & { key: TSESTree.Identifier & { name: 'constructor' } };
131
132
/**
133
* Checks if a node is a setter method
134
*/
135
function isSetter(node: TSESTree.Node | null | undefined): node is TSESTree.MethodDefinition & { kind: 'set' } | TSESTree.Property & { kind: 'set' };
136
137
/**
138
* Checks if a node is an identifier
139
*/
140
function isIdentifier(node: TSESTree.Node | null | undefined): node is TSESTree.Identifier;
141
142
/**
143
* Checks if a node is an await expression
144
*/
145
function isAwaitExpression(node: TSESTree.Node | null | undefined): node is TSESTree.AwaitExpression;
146
147
/**
148
* Checks if a node is a loop statement
149
*/
150
function isLoop(node: TSESTree.Node | null | undefined): node is TSESTree.DoWhileStatement | TSESTree.ForStatement | TSESTree.ForInStatement | TSESTree.ForOfStatement | TSESTree.WhileStatement;
151
```
152
153
### Token Predicates
154
155
Predicate functions for identifying specific types of tokens.
156
157
```typescript { .api }
158
/**
159
* Checks if a token is an optional chain punctuator (?.)
160
*/
161
function isOptionalChainPunctuator(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '?.' };
162
163
/**
164
* Checks if a token is NOT an optional chain punctuator
165
*/
166
function isNotOptionalChainPunctuator(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '?.' }>;
167
168
/**
169
* Checks if a token is a non-null assertion punctuator (!)
170
*/
171
function isNonNullAssertionPunctuator(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '!' };
172
173
/**
174
* Checks if a token is NOT a non-null assertion punctuator
175
*/
176
function isNotNonNullAssertionPunctuator(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '!' }>;
177
178
/**
179
* Checks if a token is an await keyword
180
*/
181
function isAwaitKeyword(token: TSESTree.Token | null | undefined): token is TSESTree.KeywordToken & { value: 'await' };
182
183
/**
184
* Checks if a token is a type keyword
185
*/
186
function isTypeKeyword(token: TSESTree.Token | null | undefined): token is TSESTree.KeywordToken & { value: 'type' };
187
188
/**
189
* Checks if a token is an import keyword
190
*/
191
function isImportKeyword(token: TSESTree.Token | null | undefined): token is TSESTree.KeywordToken & { value: 'import' };
192
193
/**
194
* Checks if a token is an arrow function token (=>)
195
*/
196
function isArrowToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '=>' };
197
198
/**
199
* Checks if a token is NOT an arrow function token
200
*/
201
function isNotArrowToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '=>' }>;
202
203
/**
204
* Checks if a token is a closing brace (})
205
*/
206
function isClosingBraceToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '}' };
207
208
/**
209
* Checks if a token is NOT a closing brace
210
*/
211
function isNotClosingBraceToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '}' }>;
212
213
/**
214
* Checks if a token is a closing bracket (])
215
*/
216
function isClosingBracketToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ']' };
217
218
/**
219
* Checks if a token is NOT a closing bracket
220
*/
221
function isNotClosingBracketToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ']' }>;
222
223
/**
224
* Checks if a token is a closing parenthesis ())
225
*/
226
function isClosingParenToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ')' };
227
228
/**
229
* Checks if a token is NOT a closing parenthesis
230
*/
231
function isNotClosingParenToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ')' }>;
232
233
/**
234
* Checks if a token is a colon (:)
235
*/
236
function isColonToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ':' };
237
238
/**
239
* Checks if a token is NOT a colon
240
*/
241
function isNotColonToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ':' }>;
242
243
/**
244
* Checks if a token is a comma (,)
245
*/
246
function isCommaToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ',' };
247
248
/**
249
* Checks if a token is NOT a comma
250
*/
251
function isNotCommaToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ',' }>;
252
253
/**
254
* Checks if a token is a comment token
255
*/
256
function isCommentToken(token: TSESTree.Token | null | undefined): token is TSESTree.Comment;
257
258
/**
259
* Checks if a token is NOT a comment token
260
*/
261
function isNotCommentToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.Comment>;
262
263
/**
264
* Checks if a token is an opening brace ({)
265
*/
266
function isOpeningBraceToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '{' };
267
268
/**
269
* Checks if a token is NOT an opening brace
270
*/
271
function isNotOpeningBraceToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '{' }>;
272
273
/**
274
* Checks if a token is an opening bracket ([)
275
*/
276
function isOpeningBracketToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '[' };
277
278
/**
279
* Checks if a token is NOT an opening bracket
280
*/
281
function isNotOpeningBracketToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '[' }>;
282
283
/**
284
* Checks if a token is an opening parenthesis (()
285
*/
286
function isOpeningParenToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '(' };
287
288
/**
289
* Checks if a token is NOT an opening parenthesis
290
*/
291
function isNotOpeningParenToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '(' }>;
292
293
/**
294
* Checks if a token is a semicolon (;)
295
*/
296
function isSemicolonToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ';' };
297
298
/**
299
* Checks if a token is NOT a semicolon
300
*/
301
function isNotSemicolonToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ';' }>;
302
```
303
304
### Miscellaneous Utilities
305
306
Helper functions for common AST analysis tasks.
307
308
```typescript { .api }
309
/**
310
* Regular expression for matching line breaks
311
*/
312
const LINEBREAK_MATCHER: RegExp; // /\r\n|[\r\n\u2028\u2029]/
313
314
/**
315
* Determines whether two adjacent AST nodes or tokens are on the same line
316
* @param left - Left node or token
317
* @param right - Right node or token
318
* @returns True if both are on the same line
319
*/
320
function isTokenOnSameLine(
321
left: TSESTree.Node | TSESTree.Token,
322
right: TSESTree.Node | TSESTree.Token
323
): boolean;
324
```
325
326
### ESLint-specific AST Utilities
327
328
Advanced utilities for ESLint rule development.
329
330
```typescript { .api }
331
/**
332
* Gets the function head location for reporting purposes
333
* @param node - Function-like node
334
* @param sourceCode - ESLint source code object
335
* @returns Location object suitable for error reporting
336
*/
337
function getFunctionHeadLocation(
338
node: TSESTree.FunctionLike,
339
sourceCode: TSESLint.SourceCode
340
): TSESTree.SourceLocation;
341
342
/**
343
* Gets the function name with its kind (e.g. "function foo", "method bar")
344
* @param node - Function-like node
345
* @param sourceCode - Optional source code object for getting text
346
* @returns Descriptive function name string
347
*/
348
function getFunctionNameWithKind(
349
node: TSESTree.FunctionLike,
350
sourceCode?: TSESLint.SourceCode
351
): string;
352
353
/**
354
* Gets the property name from property-like nodes
355
* @param node - Property-like AST node
356
* @param initialScope - Optional initial scope for evaluation
357
* @returns Property name string or null if not determinable
358
*/
359
function getPropertyName(
360
node: TSESTree.PropertyLike,
361
initialScope?: TSESLintScope.Scope
362
): string | null;
363
364
/**
365
* Gets the static value of an expression if it can be determined
366
* @param node - Expression node to evaluate
367
* @param initialScope - Optional initial scope for evaluation
368
* @returns Object with value and whether it's static, or null
369
*/
370
function getStaticValue(
371
node: TSESTree.Node,
372
initialScope?: TSESLintScope.Scope
373
): { value: unknown; static: boolean } | null;
374
375
/**
376
* Gets string value if the expression evaluates to a constant string
377
* @param node - Expression node to evaluate
378
* @param initialScope - Optional initial scope for evaluation
379
* @returns String value or null if not a constant string
380
*/
381
function getStringIfConstant(
382
node: TSESTree.Node,
383
initialScope?: TSESLintScope.Scope
384
): string | null;
385
386
/**
387
* Checks if a node has side effects when executed
388
* @param node - Node to check for side effects
389
* @param sourceCode - Source code object for analysis
390
* @param options - Optional configuration for side effect analysis
391
* @returns True if the node may have side effects
392
*/
393
function hasSideEffect(
394
node: TSESTree.Node,
395
sourceCode: TSESLint.SourceCode,
396
options?: { considerGetters?: boolean; considerImplicitTypeConversion?: boolean }
397
): boolean;
398
399
/**
400
* Checks if a node is wrapped in parentheses
401
* @param node - Node to check
402
* @param sourceCode - Source code object
403
* @returns True if the node is parenthesized
404
*/
405
function isParenthesized(
406
node: TSESTree.Node,
407
sourceCode: TSESLint.SourceCode
408
): boolean;
409
```
410
411
### Pattern Matching
412
413
Advanced pattern matching utilities for complex AST analysis.
414
415
```typescript { .api }
416
/**
417
* Pattern matcher class for advanced string pattern matching with escape sequences
418
*/
419
class PatternMatcher {
420
/**
421
* Creates a new pattern matcher
422
* @param pattern - Pattern string with escape sequences
423
* @param options - Optional configuration
424
*/
425
constructor(pattern: string, options?: { unicode?: boolean; sticky?: boolean });
426
427
/**
428
* Executes the pattern against input and returns all matches
429
* @param input - Input string to match against
430
* @returns Array of match results
431
*/
432
execAll(input: string): RegExpExecArray[];
433
434
/**
435
* Tests if the pattern matches the input
436
* @param input - Input string to test
437
* @returns True if pattern matches
438
*/
439
test(input: string): boolean;
440
441
/**
442
* Symbol.replace implementation for use with String.replace()
443
*/
444
[Symbol.replace](input: string, replacement: string): string;
445
}
446
```
447
448
### Reference Tracking
449
450
Utilities for tracking variable and import references across scopes.
451
452
```typescript { .api }
453
/**
454
* Reference tracker for following imports and variable usage
455
*/
456
class ReferenceTracker {
457
/**
458
* Creates a new reference tracker
459
* @param globalScope - Global scope to start tracking from
460
*/
461
constructor(globalScope: TSESLintScope.GlobalScope);
462
463
/**
464
* Iterates over global references
465
* @param traceMap - Map of global references to trace
466
* @returns Iterator of found references
467
*/
468
iterateGlobalReferences<T>(
469
traceMap: ReferenceTracker.TraceMap<T>
470
): IterableIterator<ReferenceTracker.FoundReference<T>>;
471
472
/**
473
* Iterates over CommonJS references
474
* @param traceMap - Map of CJS references to trace
475
* @returns Iterator of found references
476
*/
477
iterateCjsReferences<T>(
478
traceMap: ReferenceTracker.TraceMap<T>
479
): IterableIterator<ReferenceTracker.FoundReference<T>>;
480
481
/**
482
* Iterates over ESM references
483
* @param traceMap - Map of ESM references to trace
484
* @returns Iterator of found references
485
*/
486
iterateEsmReferences<T>(
487
traceMap: ReferenceTracker.TraceMap<T>
488
): IterableIterator<ReferenceTracker.FoundReference<T>>;
489
}
490
491
namespace ReferenceTracker {
492
const READ: unique symbol; // Read reference type
493
const CALL: unique symbol; // Call reference type
494
const CONSTRUCT: unique symbol; // Constructor reference type
495
const ESM: unique symbol; // ESM import type
496
497
interface TraceMap<T> {
498
[key: string]: TraceMapElement<T>;
499
}
500
501
type TraceMapElement<T> =
502
| T
503
| { [READ]?: T }
504
| { [CALL]?: T }
505
| { [CONSTRUCT]?: T }
506
| { [ESM]?: true }
507
| TraceMap<T>;
508
509
interface FoundReference<T> {
510
node: TSESTree.Node;
511
path: readonly string[];
512
type: typeof READ | typeof CALL | typeof CONSTRUCT;
513
info: T;
514
}
515
}
516
```
517
518
### Scope Analysis Helpers
519
520
Utilities for working with variable scopes and finding variables.
521
522
```typescript { .api }
523
/**
524
* Finds a variable in the given scope or parent scopes
525
* @param initialScope - Scope to start searching from
526
* @param nameOrNode - Variable name string or identifier node
527
* @returns Variable object if found, null otherwise
528
*/
529
function findVariable(
530
initialScope: TSESLintScope.Scope,
531
nameOrNode: TSESTree.Identifier | string
532
): TSESLintScope.Variable | null;
533
534
/**
535
* Gets the innermost scope that contains the given node
536
* @param initialScope - Scope to start searching from
537
* @param node - AST node to find scope for
538
* @returns Innermost scope containing the node
539
*/
540
function getInnermostScope(
541
initialScope: TSESLintScope.Scope,
542
node: TSESTree.Node
543
): TSESLintScope.Scope;
544
```
545
546
## Usage Examples
547
548
```typescript
549
import { ASTUtils, TSESTree, TSESLint } from "@typescript-eslint/experimental-utils";
550
551
// Using type guards
552
function checkNode(node: TSESTree.Node): void {
553
if (ASTUtils.isFunction(node)) {
554
// node is now typed as TSESTree.FunctionLike
555
console.log('Found function:', node.type);
556
}
557
558
if (ASTUtils.isNodeOfType(TSESTree.AST_NODE_TYPES.CallExpression)(node)) {
559
// node is now typed as TSESTree.CallExpression
560
console.log('Found call expression');
561
}
562
}
563
564
// Using predicates in a rule
565
const rule: TSESLint.RuleModule<'error', []> = {
566
meta: {
567
type: 'problem',
568
messages: { error: 'Message' },
569
schema: []
570
},
571
create(context) {
572
return {
573
CallExpression(node) {
574
if (ASTUtils.isOptionalCallExpression(node)) {
575
context.report({ node, messageId: 'error' });
576
}
577
}
578
};
579
}
580
};
581
582
// Using pattern matching
583
const matcher = new ASTUtils.PatternMatcher('console\\.log\\((.*)\\)');
584
const matches = matcher.execAll(sourceCode);
585
586
// Using reference tracking
587
const tracker = new ASTUtils.ReferenceTracker(context.getScope());
588
const traceMap = {
589
console: {
590
log: { [ASTUtils.ReferenceTracker.CALL]: true }
591
}
592
};
593
594
for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
595
context.report({ node, messageId: 'error' });
596
}
597
```