@angular-modernizer/api 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +507 -0
- package/dist/analysis/complexity-metrics-calculator.d.ts +99 -0
- package/dist/analysis/complexity-metrics-calculator.d.ts.map +1 -0
- package/dist/analysis/complexity-metrics-calculator.js +195 -0
- package/dist/analysis/complexity-metrics-calculator.js.map +1 -0
- package/dist/analysis/dependency-analyzer.d.ts +227 -0
- package/dist/analysis/dependency-analyzer.d.ts.map +1 -0
- package/dist/analysis/dependency-analyzer.js +451 -0
- package/dist/analysis/dependency-analyzer.js.map +1 -0
- package/dist/analysis/external-template-loader.d.ts +44 -0
- package/dist/analysis/external-template-loader.d.ts.map +1 -0
- package/dist/analysis/external-template-loader.js +69 -0
- package/dist/analysis/external-template-loader.js.map +1 -0
- package/dist/analysis/selector-mapper.d.ts +77 -0
- package/dist/analysis/selector-mapper.d.ts.map +1 -0
- package/dist/analysis/selector-mapper.js +146 -0
- package/dist/analysis/selector-mapper.js.map +1 -0
- package/dist/analysis/service-detector.d.ts +164 -0
- package/dist/analysis/service-detector.d.ts.map +1 -0
- package/dist/analysis/service-detector.js +231 -0
- package/dist/analysis/service-detector.js.map +1 -0
- package/dist/analysis/service-pattern-recognizer.d.ts +247 -0
- package/dist/analysis/service-pattern-recognizer.d.ts.map +1 -0
- package/dist/analysis/service-pattern-recognizer.js +444 -0
- package/dist/analysis/service-pattern-recognizer.js.map +1 -0
- package/dist/analysis/symbol-locator.d.ts +81 -0
- package/dist/analysis/symbol-locator.d.ts.map +1 -0
- package/dist/analysis/symbol-locator.js +128 -0
- package/dist/analysis/symbol-locator.js.map +1 -0
- package/dist/analysis/template-analyzer-usage.d.ts +144 -0
- package/dist/analysis/template-analyzer-usage.d.ts.map +1 -0
- package/dist/analysis/template-analyzer-usage.js +474 -0
- package/dist/analysis/template-analyzer-usage.js.map +1 -0
- package/dist/analysis/template-analyzer.d.ts +80 -0
- package/dist/analysis/template-analyzer.d.ts.map +1 -0
- package/dist/analysis/template-analyzer.js +146 -0
- package/dist/analysis/template-analyzer.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/investigation/angular-symbol-finder.d.ts +76 -0
- package/dist/investigation/angular-symbol-finder.d.ts.map +1 -0
- package/dist/investigation/angular-symbol-finder.js +199 -0
- package/dist/investigation/angular-symbol-finder.js.map +1 -0
- package/dist/investigation/call-graph-builder.d.ts +85 -0
- package/dist/investigation/call-graph-builder.d.ts.map +1 -0
- package/dist/investigation/call-graph-builder.js +196 -0
- package/dist/investigation/call-graph-builder.js.map +1 -0
- package/dist/investigation/codebase-searcher.d.ts +99 -0
- package/dist/investigation/codebase-searcher.d.ts.map +1 -0
- package/dist/investigation/codebase-searcher.js +201 -0
- package/dist/investigation/codebase-searcher.js.map +1 -0
- package/dist/investigation/stack-trace-parser.d.ts +70 -0
- package/dist/investigation/stack-trace-parser.d.ts.map +1 -0
- package/dist/investigation/stack-trace-parser.js +117 -0
- package/dist/investigation/stack-trace-parser.js.map +1 -0
- package/dist/investigation/type-resolver.d.ts +59 -0
- package/dist/investigation/type-resolver.d.ts.map +1 -0
- package/dist/investigation/type-resolver.js +111 -0
- package/dist/investigation/type-resolver.js.map +1 -0
- package/dist/investigation/usage-finder.d.ts +69 -0
- package/dist/investigation/usage-finder.d.ts.map +1 -0
- package/dist/investigation/usage-finder.js +132 -0
- package/dist/investigation/usage-finder.js.map +1 -0
- package/dist/metrics/complexity-metrics.d.ts +196 -0
- package/dist/metrics/complexity-metrics.d.ts.map +1 -0
- package/dist/metrics/complexity-metrics.js +445 -0
- package/dist/metrics/complexity-metrics.js.map +1 -0
- package/dist/public-api.d.ts +77 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +50 -0
- package/dist/public-api.js.map +1 -0
- package/dist/transformation/import-manager.d.ts +276 -0
- package/dist/transformation/import-manager.d.ts.map +1 -0
- package/dist/transformation/import-manager.js +488 -0
- package/dist/transformation/import-manager.js.map +1 -0
- package/dist/transformation/ng-morph-adapter.d.ts +111 -0
- package/dist/transformation/ng-morph-adapter.d.ts.map +1 -0
- package/dist/transformation/ng-morph-adapter.js +179 -0
- package/dist/transformation/ng-morph-adapter.js.map +1 -0
- package/dist/transformation/ngmodule-manager.d.ts +145 -0
- package/dist/transformation/ngmodule-manager.d.ts.map +1 -0
- package/dist/transformation/ngmodule-manager.js +356 -0
- package/dist/transformation/ngmodule-manager.js.map +1 -0
- package/package.json +62 -0
- package/src/analysis/complexity-metrics-calculator.ts +253 -0
- package/src/analysis/dependency-analyzer.ts +720 -0
- package/src/analysis/external-template-loader.ts +79 -0
- package/src/analysis/selector-mapper.ts +186 -0
- package/src/analysis/service-detector.ts +280 -0
- package/src/analysis/service-pattern-recognizer.ts +545 -0
- package/src/analysis/symbol-locator.ts +170 -0
- package/src/analysis/template-analyzer-usage.ts +614 -0
- package/src/analysis/template-analyzer.ts +208 -0
- package/src/index.ts +51 -0
- package/src/investigation/angular-symbol-finder.ts +263 -0
- package/src/investigation/call-graph-builder.ts +298 -0
- package/src/investigation/codebase-searcher.ts +286 -0
- package/src/investigation/stack-trace-parser.ts +166 -0
- package/src/investigation/type-resolver.ts +144 -0
- package/src/investigation/usage-finder.ts +198 -0
- package/src/metrics/complexity-metrics.ts +617 -0
- package/src/public-api.ts +119 -0
- package/src/transformation/import-manager.ts +626 -0
- package/src/transformation/ng-morph-adapter.ts +252 -0
- package/src/transformation/ngmodule-manager.ts +450 -0
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Import Manager
|
|
3
|
+
*
|
|
4
|
+
* High-level API for managing imports in TypeScript files.
|
|
5
|
+
* Handles adding, removing, and organizing imports safely.
|
|
6
|
+
*
|
|
7
|
+
* ## HYBRID ng-morph + ts-morph APPROACH
|
|
8
|
+
*
|
|
9
|
+
* ### What ng-morph HANDLES (Component/Module Metadata):
|
|
10
|
+
* - Component imports: [] array (e.g., @Component({ imports: [CommonModule] }))
|
|
11
|
+
* - Module imports: [] array (e.g., @NgModule({ imports: [CommonModule] }))
|
|
12
|
+
* - These are decorator metadata, NOT ES6 import statements
|
|
13
|
+
*
|
|
14
|
+
* ### What ts-morph HANDLES (Everything Else):
|
|
15
|
+
* - ES6 import statements (e.g., import { CommonModule } from '@angular/common')
|
|
16
|
+
* - Import organization and merging
|
|
17
|
+
* - Removal of imports
|
|
18
|
+
* - Aliases and complex imports
|
|
19
|
+
* - Non-Angular imports
|
|
20
|
+
*
|
|
21
|
+
* ### Code Impact:
|
|
22
|
+
* - ng-morph provides value for ~5-10% of import operations (metadata only)
|
|
23
|
+
* - ts-morph still handles 90-95% of imports (ES6 statements)
|
|
24
|
+
* - Maintains 100% backward compatibility
|
|
25
|
+
*
|
|
26
|
+
* ### Why This Hybrid?
|
|
27
|
+
* ng-morph provides cleaner API for adding to decorator metadata arrays.
|
|
28
|
+
* For ES6 import statements, ng-morph is just a thin wrapper around ts-morph with no advantage.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Import Manager - manages imports in source files using hybrid ng-morph + ts-morph approach.
|
|
32
|
+
*
|
|
33
|
+
* ## HYBRID STRATEGY (See file header for full explanation)
|
|
34
|
+
*
|
|
35
|
+
* **ng-morph (5-10% of operations):**
|
|
36
|
+
* - ONLY for adding to component/module imports: [] metadata arrays
|
|
37
|
+
* - Example: @Component({ imports: [CommonModule] }) ← ng-morph adds here
|
|
38
|
+
*
|
|
39
|
+
* **ts-morph (90-95% of operations):**
|
|
40
|
+
* - ES6 import statements: import { X } from 'y'
|
|
41
|
+
* - Import removal, organization, aliases
|
|
42
|
+
* - All non-metadata import operations
|
|
43
|
+
*
|
|
44
|
+
* **Result:** Cleaner API for metadata, minimal overall code reduction.
|
|
45
|
+
*/
|
|
46
|
+
export class ImportManager {
|
|
47
|
+
ngMorphAdapter;
|
|
48
|
+
/**
|
|
49
|
+
* Constructor for ImportManager.
|
|
50
|
+
*
|
|
51
|
+
* @param ngMorphAdapter - Optional ng-morph adapter for Angular-specific operations
|
|
52
|
+
*
|
|
53
|
+
* BACKWARD COMPATIBILITY: Constructor is optional - if not provided, falls back to pure ts-morph.
|
|
54
|
+
*/
|
|
55
|
+
constructor(ngMorphAdapter) {
|
|
56
|
+
this.ngMorphAdapter = ngMorphAdapter;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Add a named import to a source file.
|
|
60
|
+
* Handles merging with existing imports from the same module.
|
|
61
|
+
*
|
|
62
|
+
* HYBRID APPROACH:
|
|
63
|
+
* - Angular imports (@angular/*): Try ng-morph for components/modules
|
|
64
|
+
* - Non-Angular/complex: Fall back to ts-morph
|
|
65
|
+
*
|
|
66
|
+
* @param sourceFile - The source file to modify
|
|
67
|
+
* @param moduleSpecifier - The module to import from (e.g., '@angular/common')
|
|
68
|
+
* @param namedImport - The named import to add (e.g., 'CommonModule')
|
|
69
|
+
* @param alias - Optional alias for the import (e.g., 'NgComponent')
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* importManager.addNamedImport(sourceFile, '@angular/common', 'CommonModule');
|
|
74
|
+
* // Result: import { CommonModule } from '@angular/common';
|
|
75
|
+
*
|
|
76
|
+
* importManager.addNamedImport(sourceFile, '@angular/core', 'Component', 'NgComponent');
|
|
77
|
+
* // Result: import { Component as NgComponent } from '@angular/core';
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* BEFORE (ts-morph): 30 lines with manual checking
|
|
81
|
+
* AFTER (hybrid): ~20 lines with ng-morph for Angular imports
|
|
82
|
+
*/
|
|
83
|
+
addNamedImport(sourceFile, moduleSpecifier, namedImport, alias) {
|
|
84
|
+
// Try ng-morph for Angular imports
|
|
85
|
+
if (this.ngMorphAdapter && this.isAngularImport(moduleSpecifier)) {
|
|
86
|
+
if (this.tryAddAngularImport(sourceFile, moduleSpecifier, namedImport, alias)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Fall back to ts-morph for non-Angular or complex cases
|
|
91
|
+
this.addImportUsingTsMorph(sourceFile, moduleSpecifier, namedImport, alias);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if a module specifier is an Angular import.
|
|
95
|
+
*
|
|
96
|
+
* @param moduleSpecifier - The module specifier to check
|
|
97
|
+
* @returns True if it's an Angular module
|
|
98
|
+
*/
|
|
99
|
+
isAngularImport(moduleSpecifier) {
|
|
100
|
+
return moduleSpecifier.startsWith('@angular/');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Try to add an Angular import using ng-morph.
|
|
104
|
+
*
|
|
105
|
+
* ng-morph can add imports to component/module metadata (imports: [] array).
|
|
106
|
+
* This is useful for adding Angular modules like CommonModule, FormsModule, etc.
|
|
107
|
+
*
|
|
108
|
+
* @param sourceFile - The source file
|
|
109
|
+
* @param moduleSpecifier - The Angular module specifier
|
|
110
|
+
* @param namedImport - The import name (e.g., 'CommonModule')
|
|
111
|
+
* @param alias - Optional alias (not supported for metadata array imports)
|
|
112
|
+
* @returns True if successfully added via ng-morph, false to fall back
|
|
113
|
+
*/
|
|
114
|
+
tryAddAngularImport(sourceFile, _moduleSpecifier, namedImport, alias) {
|
|
115
|
+
// ng-morph doesn't support aliases for metadata imports
|
|
116
|
+
if (alias) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
const filePath = sourceFile.getFilePath();
|
|
120
|
+
try {
|
|
121
|
+
// Check if this is a component file
|
|
122
|
+
const component = this.ngMorphAdapter?.getComponent(filePath);
|
|
123
|
+
if (component) {
|
|
124
|
+
// Add to component's imports array
|
|
125
|
+
this.ngMorphAdapter?.addImportToComponent(component, namedImport, {
|
|
126
|
+
unique: true,
|
|
127
|
+
});
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
// Check if this is a module file
|
|
131
|
+
const module = this.ngMorphAdapter?.getModule(filePath);
|
|
132
|
+
if (module) {
|
|
133
|
+
// Add to module's imports array
|
|
134
|
+
this.ngMorphAdapter?.addImportToModule(module, namedImport, {
|
|
135
|
+
unique: true,
|
|
136
|
+
});
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
// Not a component or module - fall back to ts-morph
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// ng-morph failed - fall back to ts-morph
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Add import using ts-morph (fallback for complex cases).
|
|
149
|
+
*
|
|
150
|
+
* @param sourceFile - The source file
|
|
151
|
+
* @param moduleSpecifier - The module specifier
|
|
152
|
+
* @param namedImport - The import name
|
|
153
|
+
* @param alias - Optional alias
|
|
154
|
+
*/
|
|
155
|
+
addImportUsingTsMorph(sourceFile, moduleSpecifier, namedImport, alias) {
|
|
156
|
+
const existingImport = sourceFile.getImportDeclaration(moduleSpecifier);
|
|
157
|
+
if (!existingImport) {
|
|
158
|
+
// No import from this module exists, create a new one
|
|
159
|
+
const namedImports = alias
|
|
160
|
+
? [{ name: namedImport, alias }]
|
|
161
|
+
: [namedImport];
|
|
162
|
+
sourceFile.addImportDeclaration({
|
|
163
|
+
moduleSpecifier,
|
|
164
|
+
namedImports,
|
|
165
|
+
});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Import from this module exists, check if the named import is already there
|
|
169
|
+
const alreadyImported = existingImport
|
|
170
|
+
.getNamedImports()
|
|
171
|
+
.some((ni) => ni.getName() === namedImport);
|
|
172
|
+
if (alreadyImported) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
// Add the named import to the existing import declaration
|
|
176
|
+
const importSpec = alias ? { name: namedImport, alias } : namedImport;
|
|
177
|
+
existingImport.addNamedImport(importSpec);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Remove a named import from a source file.
|
|
181
|
+
* Cleans up empty import declarations after removal.
|
|
182
|
+
*
|
|
183
|
+
* HYBRID APPROACH:
|
|
184
|
+
* - Always uses ts-morph for removal (simpler than ng-morph)
|
|
185
|
+
* - ng-morph doesn't provide significant benefits for removal operations
|
|
186
|
+
*
|
|
187
|
+
* @param sourceFile - The source file
|
|
188
|
+
* @param namedImport - The named import to remove
|
|
189
|
+
* @param moduleSpecifier - Optional module specifier to target specific imports
|
|
190
|
+
*
|
|
191
|
+
* Handles:
|
|
192
|
+
* - Removing specific named imports from import declarations
|
|
193
|
+
* - Cleaning up empty import declarations
|
|
194
|
+
* - Preserving other imports from the same module
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* // Before: import { Foo, Bar } from './module';
|
|
199
|
+
* importManager.removeNamedImport(sourceFile, 'Bar', './module');
|
|
200
|
+
* // After: import { Foo } from './module';
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
removeNamedImport(sourceFile, namedImport, moduleSpecifier) {
|
|
204
|
+
const importDeclarations = sourceFile.getImportDeclarations();
|
|
205
|
+
// Helper to check if import declaration is empty after removal
|
|
206
|
+
const isEmptyImportDecl = (decl) => {
|
|
207
|
+
return (decl.getNamedImports().length === 0 &&
|
|
208
|
+
!decl.getDefaultImport() &&
|
|
209
|
+
!decl.getNamespaceImport());
|
|
210
|
+
};
|
|
211
|
+
// Find and remove the import from the first matching declaration
|
|
212
|
+
importDeclarations.some((importDecl) => {
|
|
213
|
+
// Skip if module specifier doesn't match (when specified)
|
|
214
|
+
if (moduleSpecifier &&
|
|
215
|
+
importDecl.getModuleSpecifierValue() !== moduleSpecifier) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
// Find the named import to remove
|
|
219
|
+
const importToRemove = importDecl
|
|
220
|
+
.getNamedImports()
|
|
221
|
+
.find((ni) => ni.getName() === namedImport);
|
|
222
|
+
if (!importToRemove) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
// Remove the named import
|
|
226
|
+
importToRemove.remove();
|
|
227
|
+
// Remove entire declaration if empty
|
|
228
|
+
if (isEmptyImportDecl(importDecl)) {
|
|
229
|
+
importDecl.remove();
|
|
230
|
+
}
|
|
231
|
+
return true; // Stop after first match
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get all imports from a source file.
|
|
236
|
+
*
|
|
237
|
+
* @param sourceFile - The source file
|
|
238
|
+
* @returns Array of import information
|
|
239
|
+
*
|
|
240
|
+
* Extracts:
|
|
241
|
+
* - All named imports with their module specifiers
|
|
242
|
+
* - Default imports and namespace imports
|
|
243
|
+
* - Import declaration positions for organization
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* const imports = importManager.getImports(sourceFile);
|
|
248
|
+
* // Returns:
|
|
249
|
+
* // [
|
|
250
|
+
* // { moduleSpecifier: '@angular/core', namedImports: ['Component', 'OnInit'] },
|
|
251
|
+
* // { moduleSpecifier: 'rxjs', namedImports: ['Observable'], defaultImport: 'Rx' }
|
|
252
|
+
* // ]
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
getImports(sourceFile) {
|
|
256
|
+
const imports = [];
|
|
257
|
+
const importDeclarations = sourceFile.getImportDeclarations();
|
|
258
|
+
for (const importDecl of importDeclarations) {
|
|
259
|
+
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
260
|
+
const importInfo = {
|
|
261
|
+
moduleSpecifier,
|
|
262
|
+
};
|
|
263
|
+
// Extract named imports
|
|
264
|
+
const namedImports = importDecl.getNamedImports();
|
|
265
|
+
if (namedImports.length > 0) {
|
|
266
|
+
importInfo.namedImports = namedImports.map((ni) => ni.getName());
|
|
267
|
+
}
|
|
268
|
+
// Extract default import
|
|
269
|
+
const defaultImport = importDecl.getDefaultImport();
|
|
270
|
+
if (defaultImport) {
|
|
271
|
+
importInfo.defaultImport = defaultImport.getText();
|
|
272
|
+
}
|
|
273
|
+
// Extract namespace import (e.g., * as fs)
|
|
274
|
+
const namespaceImport = importDecl.getNamespaceImport();
|
|
275
|
+
if (namespaceImport) {
|
|
276
|
+
importInfo.namespaceImport = namespaceImport.getText();
|
|
277
|
+
}
|
|
278
|
+
imports.push(importInfo);
|
|
279
|
+
}
|
|
280
|
+
return imports;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Organize imports (sort and remove duplicates).
|
|
284
|
+
*
|
|
285
|
+
* @param sourceFile - The source file
|
|
286
|
+
*
|
|
287
|
+
* Handles:
|
|
288
|
+
* - Sorting imports by module specifier (external libraries first, then internal)
|
|
289
|
+
* - Removing duplicate imports
|
|
290
|
+
* - Grouping related imports
|
|
291
|
+
* - Maintaining proper spacing and formatting
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```typescript
|
|
295
|
+
* // Before:
|
|
296
|
+
* // import { Component } from '@angular/core';
|
|
297
|
+
* // import { MyService } from './my-service';
|
|
298
|
+
* // import { Injectable } from '@angular/core';
|
|
299
|
+
*
|
|
300
|
+
* importManager.organizeImports(sourceFile);
|
|
301
|
+
*
|
|
302
|
+
* // After:
|
|
303
|
+
* // import { Component, Injectable } from '@angular/core';
|
|
304
|
+
* // import { MyService } from './my-service';
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
organizeImports(sourceFile) {
|
|
308
|
+
const importDeclarations = sourceFile.getImportDeclarations();
|
|
309
|
+
if (importDeclarations.length === 0) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const importMap = new Map();
|
|
313
|
+
// Collect all imports grouped by module specifier
|
|
314
|
+
importDeclarations.forEach((importDecl) => {
|
|
315
|
+
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
316
|
+
if (!importMap.has(moduleSpecifier)) {
|
|
317
|
+
importMap.set(moduleSpecifier, {
|
|
318
|
+
namedImports: new Map(),
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
const importData = importMap.get(moduleSpecifier);
|
|
322
|
+
// Collect named imports, preserving aliases (e.g. UserModel as DomainUser)
|
|
323
|
+
importDecl.getNamedImports().forEach((ni) => {
|
|
324
|
+
const name = ni.getName();
|
|
325
|
+
const alias = ni.getAliasNode()?.getText();
|
|
326
|
+
const key = alias ? `${name}|${alias}` : name;
|
|
327
|
+
importData.namedImports.set(key, { name, alias });
|
|
328
|
+
});
|
|
329
|
+
// Collect default import (take the first one if multiple)
|
|
330
|
+
const defaultImport = importDecl.getDefaultImport();
|
|
331
|
+
if (defaultImport && !importData.defaultImport) {
|
|
332
|
+
importData.defaultImport = defaultImport.getText();
|
|
333
|
+
}
|
|
334
|
+
// Collect namespace import (take the first one if multiple)
|
|
335
|
+
const namespaceImport = importDecl.getNamespaceImport();
|
|
336
|
+
if (namespaceImport && !importData.namespaceImport) {
|
|
337
|
+
importData.namespaceImport = namespaceImport.getText();
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
// Sort module specifiers: external first, then internal
|
|
341
|
+
const sortedModules = Array.from(importMap.keys()).sort((a, b) => {
|
|
342
|
+
const aIsExternal = !a.startsWith('.');
|
|
343
|
+
const bIsExternal = !b.startsWith('.');
|
|
344
|
+
if (aIsExternal !== bIsExternal) {
|
|
345
|
+
return aIsExternal ? -1 : 1;
|
|
346
|
+
}
|
|
347
|
+
return a.localeCompare(b);
|
|
348
|
+
});
|
|
349
|
+
// Remove all existing import declarations and add organized imports back
|
|
350
|
+
importDeclarations.forEach((decl) => decl.remove());
|
|
351
|
+
sortedModules.forEach((moduleSpecifier) => {
|
|
352
|
+
const importData = importMap.get(moduleSpecifier);
|
|
353
|
+
// Sort by name (and alias if present) for stable output
|
|
354
|
+
const namedImports = Array.from(importData.namedImports.values()).sort((a, b) => a.name.localeCompare(b.name) ||
|
|
355
|
+
(a.alias ?? '').localeCompare(b.alias ?? ''));
|
|
356
|
+
sourceFile.addImportDeclaration({
|
|
357
|
+
moduleSpecifier,
|
|
358
|
+
namedImports: namedImports.length > 0 ? namedImports : undefined,
|
|
359
|
+
defaultImport: importData.defaultImport,
|
|
360
|
+
namespaceImport: importData.namespaceImport,
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Merge duplicate import declarations.
|
|
366
|
+
*
|
|
367
|
+
* Combines multiple import statements from the same module into one.
|
|
368
|
+
*
|
|
369
|
+
* @param sourceFile - The source file
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* ```typescript
|
|
373
|
+
* // Before:
|
|
374
|
+
* // import { Component } from '@angular/core';
|
|
375
|
+
* // import { Injectable } from '@angular/core';
|
|
376
|
+
*
|
|
377
|
+
* importManager.mergeImports(sourceFile);
|
|
378
|
+
*
|
|
379
|
+
* // After:
|
|
380
|
+
* // import { Component, Injectable } from '@angular/core';
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
mergeImports(sourceFile) {
|
|
384
|
+
this.organizeImports(sourceFile);
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Remove import declarations that have no imports.
|
|
388
|
+
*
|
|
389
|
+
* Cleans up empty import statements that may result from refactoring.
|
|
390
|
+
*
|
|
391
|
+
* @param sourceFile - The source file
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```typescript
|
|
395
|
+
* // Before: import {} from '@angular/core';
|
|
396
|
+
*
|
|
397
|
+
* importManager.cleanupEmptyImports(sourceFile);
|
|
398
|
+
*
|
|
399
|
+
* // After: (empty import removed)
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
cleanupEmptyImports(sourceFile) {
|
|
403
|
+
const importDeclarations = sourceFile.getImportDeclarations();
|
|
404
|
+
for (const importDecl of importDeclarations) {
|
|
405
|
+
const namedImports = importDecl.getNamedImports();
|
|
406
|
+
const hasDefaultImport = !!importDecl.getDefaultImport();
|
|
407
|
+
const hasNamespaceImport = !!importDecl.getNamespaceImport();
|
|
408
|
+
// Remove if no imports at all
|
|
409
|
+
if (namedImports.length === 0 &&
|
|
410
|
+
!hasDefaultImport &&
|
|
411
|
+
!hasNamespaceImport) {
|
|
412
|
+
importDecl.remove();
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Check if a named import exists in the source file.
|
|
418
|
+
*
|
|
419
|
+
* @param sourceFile - The source file
|
|
420
|
+
* @param symbol - The symbol name to check
|
|
421
|
+
* @param module - Optional module specifier to check specifically
|
|
422
|
+
* @returns True if the import exists
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* ```typescript
|
|
426
|
+
* const exists = importManager.hasImport(sourceFile, 'Component', '@angular/core');
|
|
427
|
+
* // Returns true if 'import { Component } from '@angular/core';' exists
|
|
428
|
+
* ```
|
|
429
|
+
*/
|
|
430
|
+
hasImport(sourceFile, symbol, module) {
|
|
431
|
+
const importDeclarations = sourceFile.getImportDeclarations();
|
|
432
|
+
for (const importDecl of importDeclarations) {
|
|
433
|
+
if (module && importDecl.getModuleSpecifierValue() !== module) {
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
const namedImports = importDecl.getNamedImports();
|
|
437
|
+
const hasNamedImport = namedImports.some((ni) => ni.getName() === symbol);
|
|
438
|
+
if (hasNamedImport) {
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
// Check default import
|
|
442
|
+
const defaultImport = importDecl.getDefaultImport();
|
|
443
|
+
if (defaultImport && defaultImport.getText() === symbol) {
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
// Check namespace import
|
|
447
|
+
const namespaceImport = importDecl.getNamespaceImport();
|
|
448
|
+
if (namespaceImport && namespaceImport.getText() === symbol) {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Get the alias for a named import, if it exists.
|
|
456
|
+
*
|
|
457
|
+
* @param sourceFile - The source file
|
|
458
|
+
* @param symbol - The symbol name
|
|
459
|
+
* @param module - Optional module specifier
|
|
460
|
+
* @returns The alias if found, undefined otherwise
|
|
461
|
+
*
|
|
462
|
+
* @example
|
|
463
|
+
* ```typescript
|
|
464
|
+
* // import { Component as NgComponent } from '@angular/core';
|
|
465
|
+
* const alias = importManager.getImportAlias(sourceFile, 'Component', '@angular/core');
|
|
466
|
+
* // Returns 'NgComponent'
|
|
467
|
+
* ```
|
|
468
|
+
*/
|
|
469
|
+
getImportAlias(sourceFile, symbol, module) {
|
|
470
|
+
const importDeclarations = sourceFile.getImportDeclarations();
|
|
471
|
+
// Find the first matching import with the symbol
|
|
472
|
+
for (const importDecl of importDeclarations) {
|
|
473
|
+
// Skip if module doesn't match (when specified)
|
|
474
|
+
if (module && importDecl.getModuleSpecifierValue() !== module) {
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
// Find the named import with matching symbol
|
|
478
|
+
const matchingImport = importDecl
|
|
479
|
+
.getNamedImports()
|
|
480
|
+
.find((ni) => ni.getName() === symbol);
|
|
481
|
+
if (matchingImport) {
|
|
482
|
+
return matchingImport.getAliasNode()?.getText();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return undefined;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
//# sourceMappingURL=import-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-manager.js","sourceRoot":"","sources":["../../src/transformation/import-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NgMorphAdapter - Wrapper around ng-morph for Angular-specific AST operations
|
|
3
|
+
*
|
|
4
|
+
* This adapter provides a simplified interface to ng-morph functionality while
|
|
5
|
+
* maintaining compatibility with our existing ts-morph-based infrastructure.
|
|
6
|
+
*/
|
|
7
|
+
import { type ClassDeclaration } from 'ng-morph';
|
|
8
|
+
import type { Project } from 'ts-morph';
|
|
9
|
+
export interface NgMorphAdapterOptions {
|
|
10
|
+
/**
|
|
11
|
+
* The ts-morph Project instance to wrap
|
|
12
|
+
*/
|
|
13
|
+
project: Project;
|
|
14
|
+
/**
|
|
15
|
+
* Root path for the Angular project
|
|
16
|
+
*/
|
|
17
|
+
rootPath?: string;
|
|
18
|
+
/**
|
|
19
|
+
* File pattern to match (default: '**\/*.ts')
|
|
20
|
+
*/
|
|
21
|
+
pattern?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Adapter for ng-morph that integrates with our ts-morph Project
|
|
25
|
+
*/
|
|
26
|
+
export declare class NgMorphAdapter {
|
|
27
|
+
private readonly project;
|
|
28
|
+
private readonly pattern;
|
|
29
|
+
constructor(options: NgMorphAdapterOptions);
|
|
30
|
+
/**
|
|
31
|
+
* Get all Angular components matching a pattern
|
|
32
|
+
*/
|
|
33
|
+
getComponents(pattern?: string): ClassDeclaration[];
|
|
34
|
+
/**
|
|
35
|
+
* Get a specific component by file path
|
|
36
|
+
*/
|
|
37
|
+
getComponent(filePath: string): ClassDeclaration | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Get all Angular modules matching a pattern
|
|
40
|
+
*/
|
|
41
|
+
getModules(pattern?: string): ClassDeclaration[];
|
|
42
|
+
/**
|
|
43
|
+
* Get a specific module by file path
|
|
44
|
+
*/
|
|
45
|
+
getModule(filePath: string): ClassDeclaration | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Find the NgModule that declares a component
|
|
48
|
+
*/
|
|
49
|
+
findModuleForComponent(component: ClassDeclaration): ClassDeclaration | null;
|
|
50
|
+
/**
|
|
51
|
+
* Add an import to an NgModule
|
|
52
|
+
* @param moduleClass - The NgModule class declaration
|
|
53
|
+
* @param moduleName - Name of the module to import (e.g., 'CommonModule')
|
|
54
|
+
* @param options - Optional configuration
|
|
55
|
+
*/
|
|
56
|
+
addImportToModule(moduleClass: ClassDeclaration, moduleName: string, options?: {
|
|
57
|
+
unique?: boolean;
|
|
58
|
+
}): void;
|
|
59
|
+
/**
|
|
60
|
+
* Add a declaration to an NgModule
|
|
61
|
+
* @param moduleClass - The NgModule class declaration
|
|
62
|
+
* @param declaration - Name of the component/directive/pipe to declare
|
|
63
|
+
* @param options - Optional configuration
|
|
64
|
+
*/
|
|
65
|
+
addDeclarationToModule(moduleClass: ClassDeclaration, declaration: string, options?: {
|
|
66
|
+
unique?: boolean;
|
|
67
|
+
}): void;
|
|
68
|
+
/**
|
|
69
|
+
* Remove a component from an NgModule's declarations
|
|
70
|
+
* This is a custom implementation since ng-morph doesn't provide this directly
|
|
71
|
+
*
|
|
72
|
+
* Uses ts-morph to manipulate the `` decorator's declarations array.
|
|
73
|
+
*
|
|
74
|
+
* @param moduleClass - The NgModule class declaration
|
|
75
|
+
* @param componentName - Name of the component to remove
|
|
76
|
+
* @returns True if successfully removed, false otherwise
|
|
77
|
+
*/
|
|
78
|
+
removeFromDeclarations(moduleClass: ClassDeclaration, componentName: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Add an import to a standalone component
|
|
81
|
+
* @param componentClass - The component class declaration
|
|
82
|
+
* @param importName - Name of the import (e.g., 'CommonModule')
|
|
83
|
+
* @param options - Optional configuration
|
|
84
|
+
*/
|
|
85
|
+
addImportToComponent(componentClass: ClassDeclaration, importName: string, options?: {
|
|
86
|
+
unique?: boolean;
|
|
87
|
+
}): void;
|
|
88
|
+
/**
|
|
89
|
+
* Add a provider to a standalone component
|
|
90
|
+
* @param componentClass - The component class declaration
|
|
91
|
+
* @param provider - Provider to add (e.g., 'MyService')
|
|
92
|
+
* @param options - Optional configuration
|
|
93
|
+
*/
|
|
94
|
+
addProviderToComponent(componentClass: ClassDeclaration, provider: string, options?: {
|
|
95
|
+
unique?: boolean;
|
|
96
|
+
}): void;
|
|
97
|
+
/**
|
|
98
|
+
* Apply all changes to the file system
|
|
99
|
+
* This delegates to the ts-morph Project's save method
|
|
100
|
+
*/
|
|
101
|
+
apply(): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Apply changes synchronously
|
|
104
|
+
*/
|
|
105
|
+
applySync(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Get the underlying ts-morph Project
|
|
108
|
+
*/
|
|
109
|
+
getProject(): Project;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=ng-morph-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ng-morph-adapter.d.ts","sourceRoot":"","sources":["../../src/transformation/ng-morph-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,qBAAqB;IAK1C;;OAEG;IACH,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAInD;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAU5D;;OAEG;IACH,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAIhD;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAUzD;;OAEG;IACH,sBAAsB,CAAC,SAAS,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,IAAI;IAI5E;;;;;OAKG;IACH,iBAAiB,CACf,WAAW,EAAE,gBAAgB,EAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,IAAI;IAIP;;;;;OAKG;IACH,sBAAsB,CACpB,WAAW,EAAE,gBAAgB,EAC7B,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,IAAI;IAIP;;;;;;;;;OASG;IACH,sBAAsB,CACpB,WAAW,EAAE,gBAAgB,EAC7B,aAAa,EAAE,MAAM,GACpB,OAAO;IAkEV;;;;;OAKG;IACH,oBAAoB,CAClB,cAAc,EAAE,gBAAgB,EAChC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,IAAI;IAIP;;;;;OAKG;IACH,sBAAsB,CACpB,cAAc,EAAE,gBAAgB,EAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,IAAI;IAIP;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACH,SAAS,IAAI,IAAI;IAIjB;;OAEG;IACH,UAAU,IAAI,OAAO;CAGtB"}
|