0
# Code Analysis and Utilities
1
2
Advanced analysis utilities for scope boundaries, variable declarations, control flow, import/export analysis, modifier checking, and compiler option validation. These functions provide deep insights into TypeScript code structure and behavior.
3
4
## Capabilities
5
6
### Modifier Analysis
7
8
Utilities for analyzing TypeScript modifiers on declarations and class members.
9
10
```typescript { .api }
11
/**
12
* Get specific modifier from a node
13
* @param node - Node to check for modifier
14
* @param kind - Type of modifier to find
15
* @returns Modifier node if found, undefined otherwise
16
*/
17
function getModifier(node: ts.Node, kind: ts.Modifier['kind']): ts.Modifier | undefined;
18
19
/**
20
* Check if node has any of the specified modifiers
21
* @param modifiers - Modifiers array to check
22
* @param kinds - Modifier kinds to look for
23
* @returns true if any of the specified modifiers are present
24
*/
25
function hasModifier(modifiers: ts.ModifiersArray | undefined, ...kinds: Array<ts.Modifier['kind']>): boolean;
26
27
/**
28
* Check if parameter declaration is a parameter property
29
* @param node - Parameter declaration to check
30
* @returns true if parameter has access modifier making it a property
31
*/
32
function isParameterProperty(node: ts.ParameterDeclaration): boolean;
33
34
/**
35
* Check if node has access modifier (public, private, protected)
36
* @param node - Class element or parameter to check
37
* @returns true if node has access modifier
38
*/
39
function hasAccessModifier(node: ts.ClassElement | ts.ParameterDeclaration): boolean;
40
41
/**
42
* Check if parameter is the 'this' parameter
43
* @param parameter - Parameter declaration to check
44
* @returns true if parameter represents 'this'
45
*/
46
function isThisParameter(parameter: ts.ParameterDeclaration): boolean;
47
```
48
49
### Flag Checking Utilities
50
51
Utilities for checking various TypeScript compiler flags on nodes, types, and symbols.
52
53
```typescript { .api }
54
/**
55
* Check if node has specific node flags set
56
* @param node - Node to check
57
* @param flag - Node flags to test
58
* @returns true if flags are set
59
*/
60
const isNodeFlagSet: (node: ts.Node, flag: ts.NodeFlags) => boolean;
61
62
/**
63
* Check if type has specific type flags set
64
* @param type - Type to check
65
* @param flag - Type flags to test
66
* @returns true if flags are set
67
*/
68
const isTypeFlagSet: (type: ts.Type, flag: ts.TypeFlags) => boolean;
69
70
/**
71
* Check if symbol has specific symbol flags set
72
* @param symbol - Symbol to check
73
* @param flag - Symbol flags to test
74
* @returns true if flags are set
75
*/
76
const isSymbolFlagSet: (symbol: ts.Symbol, flag: ts.SymbolFlags) => boolean;
77
78
/**
79
* Check if object type has specific object flags set
80
* @param objectType - Object type to check
81
* @param flag - Object flags to test
82
* @returns true if flags are set
83
*/
84
function isObjectFlagSet(objectType: ts.ObjectType, flag: ts.ObjectFlags): boolean;
85
86
/**
87
* Check if node has specific modifier flags set
88
* @param node - Node to check
89
* @param flag - Modifier flags to test
90
* @returns true if flags are set
91
*/
92
function isModifierFlagSet(node: ts.Node, flag: ts.ModifierFlags): boolean;
93
```
94
95
### Variable Declaration Analysis
96
97
Utilities for analyzing variable declarations and their scoping behavior.
98
99
```typescript { .api }
100
/**
101
* Get the declaration kind (var, let, const) for a variable declaration list
102
* @param declarationList - Variable declaration list to analyze
103
* @returns Declaration kind enum value
104
*/
105
function getVariableDeclarationKind(declarationList: ts.VariableDeclarationList): VariableDeclarationKind;
106
107
/**
108
* Check if variable declaration list is block-scoped (let/const)
109
* @param declarationList - Declaration list to check
110
* @returns true if declarations are block-scoped
111
*/
112
function isBlockScopedVariableDeclarationList(declarationList: ts.VariableDeclarationList): boolean;
113
114
/**
115
* Check if variable declaration is block-scoped
116
* @param declaration - Variable declaration to check
117
* @returns true if declaration is block-scoped
118
*/
119
function isBlockScopedVariableDeclaration(declaration: ts.VariableDeclaration): boolean;
120
121
/**
122
* Check if statement is a block-scoped declaration statement
123
* @param statement - Statement to check
124
* @returns true if statement declares block-scoped variables
125
*/
126
function isBlockScopedDeclarationStatement(statement: ts.Statement): statement is ts.DeclarationStatement;
127
128
/**
129
* Variable declaration kind enumeration
130
*/
131
enum VariableDeclarationKind {
132
Var,
133
Let,
134
Const
135
}
136
```
137
138
### Destructuring Analysis
139
140
Utilities for analyzing destructuring patterns and extracting identifiers.
141
142
```typescript { .api }
143
/**
144
* Iterate through all identifiers in a destructuring pattern
145
* @param pattern - Binding pattern to analyze
146
* @param fn - Callback function for each identifier
147
* @returns Result from callback if any
148
*/
149
function forEachDestructuringIdentifier<T>(
150
pattern: ts.BindingPattern,
151
fn: (element: ts.BindingElement & { name: ts.Identifier }) => T
152
): T | undefined;
153
154
/**
155
* Iterate through all declared variables in a declaration list
156
* @param declarationList - Variable declaration list to analyze
157
* @param cb - Callback function for each declared variable
158
* @returns Result from callback if any
159
*/
160
function forEachDeclaredVariable<T>(
161
declarationList: ts.VariableDeclarationList,
162
cb: (element: (ts.VariableDeclaration | ts.BindingElement) & { name: ts.Identifier }) => T
163
): T | undefined;
164
165
/**
166
* Get the declaration that contains a binding element
167
* @param node - Binding element to find declaration for
168
* @returns Parent variable or parameter declaration
169
*/
170
function getDeclarationOfBindingElement(node: ts.BindingElement): ts.VariableDeclaration | ts.ParameterDeclaration;
171
```
172
173
### Scope Analysis
174
175
Utilities for analyzing scope boundaries and context in TypeScript code.
176
177
```typescript { .api }
178
/**
179
* Determine the type of scope boundary a node represents
180
* @param node - Node to check
181
* @returns Scope boundary flags
182
*/
183
function isScopeBoundary(node: ts.Node): ScopeBoundary;
184
185
/**
186
* Check if node is a type scope boundary
187
* @param node - Node to check
188
* @returns Type scope boundary flags
189
*/
190
function isTypeScopeBoundary(node: ts.Node): ScopeBoundary;
191
192
/**
193
* Check if node is a function scope boundary
194
* @param node - Node to check
195
* @returns Function scope boundary flags
196
*/
197
function isFunctionScopeBoundary(node: ts.Node): ScopeBoundary;
198
199
/**
200
* Check if node is a block scope boundary
201
* @param node - Node to check
202
* @returns Block scope boundary flags
203
*/
204
function isBlockScopeBoundary(node: ts.Node): ScopeBoundary;
205
206
/**
207
* Check if statement is in single statement context (if/else/while body)
208
* @param statement - Statement to check
209
* @returns true if statement is not in block context
210
*/
211
function isInSingleStatementContext(statement: ts.Statement): boolean;
212
213
/**
214
* Scope boundary enumeration
215
*/
216
enum ScopeBoundary {
217
None = 0,
218
Function = 1,
219
Block = 2,
220
Type = 4,
221
ConditionalType = 8
222
}
223
224
/**
225
* Scope boundary selector for hierarchical selection
226
*/
227
enum ScopeBoundarySelector {
228
Function = ScopeBoundary.Function,
229
Block = ScopeBoundarySelector.Function | ScopeBoundary.Block,
230
Type = ScopeBoundarySelector.Block | ScopeBoundary.Type,
231
InferType = ScopeBoundary.ConditionalType
232
}
233
```
234
235
### Import/Export Analysis
236
237
Utilities for analyzing module import and export patterns.
238
239
```typescript { .api }
240
/**
241
* Find all import string literals in a source file
242
* @param sourceFile - Source file to analyze
243
* @param kinds - Types of imports to find
244
* @param ignoreFileName - Whether to ignore filename-based imports
245
* @returns Array of import string literals
246
*/
247
function findImports(
248
sourceFile: ts.SourceFile,
249
kinds: ImportKind,
250
ignoreFileName?: boolean
251
): Array<ts.StringLiteral | ts.NoSubstitutionTemplateLiteral>;
252
253
/**
254
* Find all import-like nodes in a source file
255
* @param sourceFile - Source file to analyze
256
* @param kinds - Types of imports to find
257
* @param ignoreFileName - Whether to ignore filename-based imports
258
* @returns Array of import-like nodes
259
*/
260
function findImportLikeNodes(
261
sourceFile: ts.SourceFile,
262
kinds: ImportKind,
263
ignoreFileName?: boolean
264
): ImportLike[];
265
266
/**
267
* Union type for import-like constructs
268
*/
269
type ImportLike = ts.ImportDeclaration
270
| ts.ImportEqualsDeclaration & {moduleReference: ts.ExternalModuleReference}
271
| ts.ExportDeclaration & {moduleSpecifier: {}}
272
| ts.CallExpression & {expression: ts.Token<ts.SyntaxKind.ImportKeyword> | ts.Identifier & {text: 'require'}, arguments: [ts.Expression, ...ts.Expression[]]}
273
| ts.ImportTypeNode;
274
275
/**
276
* Import kind enumeration for filtering import types
277
*/
278
enum ImportKind {
279
ImportDeclaration = 1,
280
ImportEquals = 2,
281
ExportFrom = 4,
282
DynamicImport = 8,
283
Require = 16,
284
ImportType = 32,
285
All = ImportDeclaration | ImportEquals | ExportFrom | DynamicImport | Require | ImportType
286
}
287
```
288
289
### Function and Context Analysis
290
291
Utilities for analyzing function contexts and this references.
292
293
```typescript { .api }
294
/**
295
* Check if node has its own 'this' reference
296
* @param node - Node to check
297
* @returns true if node establishes its own 'this' context
298
*/
299
function hasOwnThisReference(node: ts.Node): boolean;
300
301
/**
302
* Check if node is a function with a body
303
* @param node - Node to check
304
* @returns true if node is function-like with body property
305
*/
306
function isFunctionWithBody(node: ts.Node): node is ts.FunctionLikeDeclaration & {body: {}};
307
308
/**
309
* Get IIFE (Immediately Invoked Function Expression) call expression
310
* @param func - Function expression or arrow function
311
* @returns Call expression if function is immediately invoked
312
*/
313
function getIIFE(func: ts.FunctionExpression | ts.ArrowFunction): ts.CallExpression | undefined;
314
```
315
316
### Compiler Options Analysis
317
318
Utilities for checking compiler options and their effects.
319
320
```typescript { .api }
321
/**
322
* Check if strict compiler option is enabled
323
* @param options - Compiler options to check
324
* @param option - Specific strict option to check
325
* @returns true if strict option is enabled
326
*/
327
function isStrictCompilerOptionEnabled(options: ts.CompilerOptions, option: StrictCompilerOption): boolean;
328
329
/**
330
* Check if boolean compiler option is enabled
331
* @param options - Compiler options to check
332
* @param option - Boolean option to check
333
* @returns true if option is enabled
334
*/
335
function isCompilerOptionEnabled(options: ts.CompilerOptions, option: BooleanCompilerOptions | 'stripInternal'): boolean;
336
337
/**
338
* Type for strict compiler options
339
*/
340
type StrictCompilerOption = 'noImplicitAny' | 'noImplicitThis' | 'strictNullChecks' | 'strictFunctionTypes' | 'strictPropertyInitialization' | 'alwaysStrict' | 'strictBindCallApply';
341
342
/**
343
* Type for boolean compiler options
344
*/
345
type BooleanCompilerOptions = {[K in keyof ts.CompilerOptions]: NonNullable<ts.CompilerOptions[K]> extends boolean ? K : never} extends {[_ in keyof ts.CompilerOptions]: infer U} ? U : never;
346
```
347
348
### Ambient Context Analysis
349
350
Utilities for analyzing ambient (declare) contexts and module blocks.
351
352
```typescript { .api }
353
/**
354
* Check if statement is in ambient context
355
* @param node - Statement to check
356
* @returns true if statement is in ambient (declare) context
357
*/
358
function isStatementInAmbientContext(node: ts.Statement): boolean;
359
360
/**
361
* Check if node is an ambient module block
362
* @param node - Node to check
363
* @returns true if node is ambient module block
364
*/
365
function isAmbientModuleBlock(node: ts.Node): node is ts.ModuleBlock;
366
367
/**
368
* Check if module declaration is ambient
369
* @param node - Module declaration to check
370
* @returns true if module is ambient
371
*/
372
function isAmbientModule(node: ts.ModuleDeclaration): boolean;
373
```
374
375
**Usage Examples:**
376
377
```typescript
378
import * as ts from "typescript";
379
import {
380
hasModifier,
381
isParameterProperty,
382
getVariableDeclarationKind,
383
isScopeBoundary,
384
findImports,
385
isStrictCompilerOptionEnabled,
386
VariableDeclarationKind,
387
ScopeBoundary,
388
ImportKind
389
} from "tsutils/util";
390
391
// Modifier analysis example
392
function analyzeClassMember(member: ts.ClassElement) {
393
if (hasModifier(member.modifiers, ts.SyntaxKind.PrivateKeyword)) {
394
console.log("Member is private");
395
}
396
397
if (hasModifier(member.modifiers, ts.SyntaxKind.StaticKeyword, ts.SyntaxKind.ReadonlyKeyword)) {
398
console.log("Member is static or readonly");
399
}
400
}
401
402
// Parameter property detection
403
function analyzeConstructorParameters(constructor: ts.ConstructorDeclaration) {
404
constructor.parameters.forEach(param => {
405
if (isParameterProperty(param)) {
406
console.log(`Parameter ${param.name?.getText()} is also a property`);
407
}
408
});
409
}
410
411
// Variable declaration analysis
412
function analyzeVariableDeclarations(statement: ts.VariableStatement) {
413
const kind = getVariableDeclarationKind(statement.declarationList);
414
415
switch (kind) {
416
case VariableDeclarationKind.Var:
417
console.log("Function-scoped variables");
418
break;
419
case VariableDeclarationKind.Let:
420
console.log("Block-scoped mutable variables");
421
break;
422
case VariableDeclarationKind.Const:
423
console.log("Block-scoped immutable variables");
424
break;
425
}
426
}
427
428
// Scope boundary analysis
429
function analyzeScopeBoundaries(node: ts.Node) {
430
const boundary = isScopeBoundary(node);
431
432
if (boundary & ScopeBoundary.Function) {
433
console.log("Node creates function scope");
434
}
435
436
if (boundary & ScopeBoundary.Block) {
437
console.log("Node creates block scope");
438
}
439
440
if (boundary & ScopeBoundary.Type) {
441
console.log("Node creates type scope");
442
}
443
}
444
445
// Import analysis
446
function analyzeImports(sourceFile: ts.SourceFile) {
447
const allImports = findImports(sourceFile, ImportKind.All);
448
const dynamicImports = findImports(sourceFile, ImportKind.DynamicImport);
449
450
console.log(`Total imports: ${allImports.length}`);
451
console.log(`Dynamic imports: ${dynamicImports.length}`);
452
453
allImports.forEach(importLiteral => {
454
console.log(`Import: ${importLiteral.text}`);
455
});
456
}
457
458
// Compiler options checking
459
function checkStrictMode(options: ts.CompilerOptions) {
460
if (isStrictCompilerOptionEnabled(options, 'strictNullChecks')) {
461
console.log("Strict null checks enabled");
462
}
463
464
if (isStrictCompilerOptionEnabled(options, 'noImplicitAny')) {
465
console.log("No implicit any enabled");
466
}
467
}
468
```