0
# AST Utilities
1
2
Utilities for parsing, analyzing, and modifying TypeScript Abstract Syntax Trees (AST) to programmatically update Angular code. These functions enable precise code modifications for schematics.
3
4
## Capabilities
5
6
### Node Finding
7
8
Functions for locating specific nodes within TypeScript AST structures.
9
10
```typescript { .api }
11
/**
12
* Finds a node of a specific kind with required text content
13
* @param node - Root node to search from
14
* @param kind - TypeScript syntax kind to find
15
* @param text - Text content to match (required)
16
* @returns Found node or null if not found
17
*/
18
function findNode(
19
node: ts.Node,
20
kind: ts.SyntaxKind,
21
text: string
22
): ts.Node | null;
23
24
/**
25
* Gets all nodes from a source file
26
* @param sourceFile - TypeScript source file
27
* @returns Array of all nodes in the file
28
*/
29
function getSourceNodes(sourceFile: ts.SourceFile): ts.Node[];
30
31
/**
32
* Finds all nodes of a specific kind
33
* @param node - Root node to search from
34
* @param kind - TypeScript syntax kind to find
35
* @param max - Maximum number of nodes to find
36
* @returns Array of found nodes
37
*/
38
function findNodes(
39
node: ts.Node,
40
kind: ts.SyntaxKind,
41
max?: number
42
): ts.Node[];
43
```
44
45
**Usage Example:**
46
47
```typescript
48
import { findNode, findNodes } from '@schematics/angular/utility/ast-utils';
49
import * as ts from 'typescript';
50
51
export function findImports(): Rule {
52
return (tree: Tree) => {
53
const source = tree.readText('/src/app/app.module.ts');
54
const sourceFile = ts.createSourceFile('app.module.ts', source, ts.ScriptTarget.Latest);
55
56
// Find import declarations
57
const imports = findNodes(sourceFile, ts.SyntaxKind.ImportDeclaration);
58
59
// Find specific import
60
const angularCoreImport = findNode(sourceFile, ts.SyntaxKind.ImportDeclaration, '@angular/core');
61
62
return tree;
63
};
64
}
65
```
66
67
### Module Modifications
68
69
Functions for adding imports, declarations, and providers to Angular modules.
70
71
```typescript { .api }
72
/**
73
* Adds an import statement to an Angular module
74
* @param source - Source file containing the module
75
* @param modulePath - Path to the module file
76
* @param symbolName - Name of the symbol to import
77
* @param fileName - File to import from
78
* @returns Array of changes to apply
79
*/
80
function addImportToModule(
81
source: ts.SourceFile,
82
modulePath: string,
83
symbolName: string,
84
fileName: string
85
): Change[];
86
87
/**
88
* Adds a declaration to an Angular module's declarations array
89
* @param source - Source file containing the module
90
* @param modulePath - Path to the module file
91
* @param classifiedName - Name of the component/directive/pipe
92
* @param importPath - Path to import the declaration from
93
* @returns Array of changes to apply
94
*/
95
function addDeclarationToModule(
96
source: ts.SourceFile,
97
modulePath: string,
98
classifiedName: string,
99
importPath: string
100
): Change[];
101
102
/**
103
* Adds an export to an Angular module's exports array
104
* @param source - Source file containing the module
105
* @param modulePath - Path to the module file
106
* @param classifiedName - Name of the item to export
107
* @param importPath - Path to import the export from
108
* @returns Array of changes to apply
109
*/
110
function addExportToModule(
111
source: ts.SourceFile,
112
modulePath: string,
113
classifiedName: string,
114
importPath: string
115
): Change[];
116
117
/**
118
* Adds a provider to an Angular module's providers array
119
* @param source - Source file containing the module
120
* @param modulePath - Path to the module file
121
* @param classifiedName - Name of the provider
122
* @param importPath - Path to import the provider from
123
* @returns Array of changes to apply
124
*/
125
function addProviderToModule(
126
source: ts.SourceFile,
127
modulePath: string,
128
classifiedName: string,
129
importPath: string
130
): Change[];
131
132
/**
133
* Adds a component to bootstrap array in Angular module
134
* @param source - Source file containing the module
135
* @param modulePath - Path to the module file
136
* @param classifiedName - Name of the component to bootstrap
137
* @param importPath - Path to import the component from
138
* @returns Array of changes to apply
139
*/
140
function addBootstrapToModule(
141
source: ts.SourceFile,
142
modulePath: string,
143
classifiedName: string,
144
importPath: string
145
): Change[];
146
```
147
148
**Usage Example:**
149
150
```typescript
151
import {
152
addDeclarationToModule,
153
addImportToModule
154
} from '@schematics/angular/utility/ast-utils';
155
import { applyToUpdateRecorder } from '@schematics/angular/utility/change';
156
157
export function addComponentToModule(): Rule {
158
return (tree: Tree) => {
159
const modulePath = '/src/app/app.module.ts';
160
const source = tree.readText(modulePath);
161
const sourceFile = ts.createSourceFile(modulePath, source, ts.ScriptTarget.Latest);
162
163
// Add import and declaration
164
const changes = [
165
...addImportToModule(sourceFile, modulePath, 'MyComponent', './my-component/my-component'),
166
...addDeclarationToModule(sourceFile, modulePath, 'MyComponent', './my-component/my-component')
167
];
168
169
// Apply changes
170
const recorder = tree.beginUpdate(modulePath);
171
applyToUpdateRecorder(recorder, changes);
172
tree.commitUpdate(recorder);
173
174
return tree;
175
};
176
}
177
```
178
179
### Import Management
180
181
Functions for adding and managing import statements.
182
183
```typescript { .api }
184
/**
185
* Inserts an import statement into a source file
186
* @param source - Source file to modify
187
* @param fileToEdit - Path to the file being edited
188
* @param symbolName - Name of the symbol to import
189
* @param fileName - File to import from
190
* @param isDefault - Whether this is a default import
191
* @returns Change object representing the import insertion
192
*/
193
function insertImport(
194
source: ts.SourceFile,
195
fileToEdit: string,
196
symbolName: string,
197
fileName: string,
198
isDefault?: boolean
199
): Change;
200
201
/**
202
* Inserts text after the last occurrence of specified nodes
203
* @param nodes - Array of nodes to search through
204
* @param toInsert - Text to insert
205
* @param file - File path for the change
206
* @param fallbackPos - Position to use if no nodes found
207
* @returns Change object representing the insertion
208
*/
209
function insertAfterLastOccurrence(
210
nodes: ts.Node[],
211
toInsert: string,
212
file: string,
213
fallbackPos?: number
214
): Change;
215
```
216
217
### Decorator Analysis
218
219
Functions for analyzing and working with TypeScript decorators.
220
221
```typescript { .api }
222
/**
223
* Gets decorator metadata from a source file
224
* @param source - Source file to analyze
225
* @param identifier - Decorator name to find (e.g., 'Component')
226
* @param module - Module the decorator is imported from (e.g., '@angular/core')
227
* @returns Array of nodes representing decorator metadata
228
*/
229
function getDecoratorMetadata(
230
source: ts.SourceFile,
231
identifier: string,
232
module: string
233
): ts.Node[];
234
235
/**
236
* Adds a symbol to NgModule metadata (imports, declarations, providers, etc.)
237
* @param source - Source file containing NgModule
238
* @param ngModulePath - Path to the NgModule file
239
* @param metadataField - Field to add to ('imports', 'declarations', 'providers', etc.)
240
* @param symbolName - Name of the symbol to add
241
* @param importPath - Optional import path for the symbol
242
* @returns Array of changes to apply
243
*/
244
function addSymbolToNgModuleMetadata(
245
source: ts.SourceFile,
246
ngModulePath: string,
247
metadataField: string,
248
symbolName: string,
249
importPath?: string
250
): Change[];
251
```
252
253
### Module Discovery
254
255
Functions for finding and working with Angular modules.
256
257
```typescript { .api }
258
/**
259
* Gets the path to the app module from main.ts
260
* @param host - Tree host
261
* @param mainPath - Path to main.ts file
262
* @returns Path to the app module
263
*/
264
function getAppModulePath(host: Tree, mainPath: string): string;
265
266
/**
267
* Finds the module file from options and directory structure
268
* @param host - Tree host
269
* @param generateDir - Directory where files are being generated
270
* @returns Path to the module file
271
*/
272
function findModule(host: Tree, generateDir: string): string;
273
274
/**
275
* Finds module from schematic options
276
* @param host - Tree host
277
* @param options - Options containing module information
278
* @returns Path to module file or undefined
279
*/
280
function findModuleFromOptions(host:Tree, options: ModuleOptions): string | undefined;
281
282
interface ModuleOptions {
283
module?: string;
284
name: string;
285
path?: string;
286
flat?: boolean;
287
}
288
```
289
290
### Routing Utilities
291
292
Functions for working with Angular routing configuration.
293
294
```typescript { .api }
295
/**
296
* Adds a route declaration to a module
297
* @param source - Source file containing routes
298
* @param fileToAdd - File path being modified
299
* @param routeLiteral - Route configuration as string
300
* @returns Array of changes to apply
301
*/
302
function addRouteDeclarationToModule(
303
source: ts.SourceFile,
304
fileToAdd: string,
305
routeLiteral: string
306
): Change[];
307
308
/**
309
* Gets the RouterModule declaration from a source file
310
* @param source - Source file to search
311
* @returns Expression node for RouterModule or undefined
312
*/
313
function getRouterModuleDeclaration(source: ts.SourceFile): ts.Expression | undefined;
314
315
/**
316
* Checks if an import is already present in the source file
317
* @param source - Source file to check
318
* @param className - Class name to look for
319
* @param importPath - Import path to look for
320
* @returns True if import already exists
321
*/
322
function isImported(
323
source: ts.SourceFile,
324
className: string,
325
importPath: string
326
): boolean;
327
328
/**
329
* Gets metadata field from decorator
330
* @param source - Source file containing decorator
331
* @param identifier - Decorator name
332
* @param module - Module the decorator is from
333
* @param field - Metadata field to get
334
* @returns Array of nodes for the field
335
*/
336
function getMetadataField(
337
source: ts.SourceFile,
338
identifier: string,
339
module: string,
340
field: string
341
): ts.Node[];
342
343
/**
344
* Checks if source file has a top-level identifier
345
* @param source - Source file to check
346
* @param name - Identifier name to look for
347
* @returns True if identifier exists at top level
348
*/
349
function hasTopLevelIdentifier(source: ts.SourceFile, name: string): boolean;
350
```
351
352
## Change System
353
354
### Change Types
355
356
```typescript { .api }
357
/**
358
* Abstract base class for representing code changes
359
*/
360
abstract class Change {
361
/** File path this change applies to */
362
readonly path: string | null;
363
/** Order for applying multiple changes */
364
readonly order: number;
365
/** Human-readable description of the change */
366
readonly description: string;
367
368
/**
369
* Applies this change to an UpdateRecorder
370
* @param host - UpdateRecorder to apply changes to
371
* @returns Modified UpdateRecorder
372
*/
373
abstract apply(host: UpdateRecorder): UpdateRecorder;
374
}
375
376
/**
377
* Change that inserts text at a specific position
378
*/
379
class InsertChange extends Change {
380
constructor(path: string, pos: number, toAdd: string);
381
}
382
383
/**
384
* Change that removes text from a specific position and length
385
*/
386
class RemoveChange extends Change {
387
constructor(path: string, pos: number, length: number);
388
}
389
390
/**
391
* Change that replaces text at a specific position
392
*/
393
class ReplaceChange extends Change {
394
constructor(path: string, pos: number, oldText: string, newText: string);
395
}
396
397
/**
398
* Change that does nothing (no-op)
399
*/
400
class NoopChange extends Change {
401
constructor();
402
}
403
```
404
405
### Applying Changes
406
407
```typescript { .api }
408
/**
409
* Applies an array of changes to an UpdateRecorder
410
* @param recorder - UpdateRecorder to apply changes to
411
* @param changes - Array of changes to apply
412
*/
413
function applyToUpdateRecorder(recorder: UpdateRecorder, changes: Change[]): void;
414
```
415
416
**Usage Example:**
417
418
```typescript
419
import { applyToUpdateRecorder, InsertChange } from '@schematics/angular/utility/change';
420
421
export function addImport(): Rule {
422
return (tree: Tree) => {
423
const filePath = '/src/app/app.component.ts';
424
const changes = [
425
new InsertChange(filePath, 0, "import { Component } from '@angular/core';\n")
426
];
427
428
const recorder = tree.beginUpdate(filePath);
429
applyToUpdateRecorder(recorder, changes);
430
tree.commitUpdate(recorder);
431
432
return tree;
433
};
434
}
435
```