@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,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Call Graph Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds a call graph for a named method or function within a ts-morph Project.
|
|
5
|
+
* Supports traversal upward (callers) and downward (callees) with configurable depth.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Used in bug investigation to understand how an error propagates through the
|
|
9
|
+
* codebase. Combine with `find-usages` to trace the full call path from the
|
|
10
|
+
* entry point to the failing code.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const builder = new CallGraphBuilder(project);
|
|
15
|
+
* const graph = builder.buildCallGraph('getUser', '/src/app/user.service.ts', {
|
|
16
|
+
* direction: 'both',
|
|
17
|
+
* depth: 2,
|
|
18
|
+
* });
|
|
19
|
+
* // graph.callers → who calls getUser
|
|
20
|
+
* // graph.callees → what getUser calls
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { SyntaxKind } from 'ts-morph';
|
|
24
|
+
/**
|
|
25
|
+
* Builds caller/callee graphs for methods and functions across a ts-morph Project.
|
|
26
|
+
*/
|
|
27
|
+
export class CallGraphBuilder {
|
|
28
|
+
project;
|
|
29
|
+
/**
|
|
30
|
+
* @param project - A ts-morph `Project` instance with source files already added.
|
|
31
|
+
*/
|
|
32
|
+
constructor(project) {
|
|
33
|
+
this.project = project;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Builds a call graph rooted at the named method or function.
|
|
37
|
+
*
|
|
38
|
+
* @param method - Name of the method or function to analyse.
|
|
39
|
+
* @param file - Absolute path of the source file containing the method.
|
|
40
|
+
* @param options - Traversal direction and depth. Defaults to `both` / depth `2`.
|
|
41
|
+
* @returns A `CallGraphResult` with the target and its caller/callee trees.
|
|
42
|
+
*/
|
|
43
|
+
buildCallGraph(method, file, options = {}) {
|
|
44
|
+
const direction = options.direction ?? 'both';
|
|
45
|
+
const depth = options.depth ?? 2;
|
|
46
|
+
const target = this.resolveTarget(method, file);
|
|
47
|
+
if (!target) {
|
|
48
|
+
return { target: null, callers: [], callees: [] };
|
|
49
|
+
}
|
|
50
|
+
const targetInfo = {
|
|
51
|
+
name: method,
|
|
52
|
+
file,
|
|
53
|
+
line: target.getStartLineNumber(),
|
|
54
|
+
};
|
|
55
|
+
const callers = direction === 'down'
|
|
56
|
+
? []
|
|
57
|
+
: this.buildCallers(target, depth, new Set([`${file}:${method}`]));
|
|
58
|
+
const callees = direction === 'up'
|
|
59
|
+
? []
|
|
60
|
+
: this.buildCallees(target, depth, new Set([`${file}:${method}`]));
|
|
61
|
+
return { target: targetInfo, callers, callees };
|
|
62
|
+
}
|
|
63
|
+
resolveTarget(name, file) {
|
|
64
|
+
const sourceFile = this.project.getSourceFile(file);
|
|
65
|
+
if (!sourceFile) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
// Search class methods
|
|
69
|
+
for (const cls of sourceFile.getClasses()) {
|
|
70
|
+
const method = cls.getMethod(name);
|
|
71
|
+
if (method) {
|
|
72
|
+
return method;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Search top-level functions
|
|
76
|
+
const fn = sourceFile.getFunction(name);
|
|
77
|
+
if (fn) {
|
|
78
|
+
return fn;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
buildCallees(callable, depth, visited) {
|
|
83
|
+
if (depth <= 0) {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
const callees = [];
|
|
87
|
+
const body = callable.getBody();
|
|
88
|
+
if (!body) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
body.forEachDescendant((node) => {
|
|
92
|
+
if (node.getKind() !== SyntaxKind.CallExpression) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const callExpr = node.asKindOrThrow(SyntaxKind.CallExpression);
|
|
96
|
+
const expr = callExpr.getExpression();
|
|
97
|
+
const calleeName = this.extractCallName(expr.getText());
|
|
98
|
+
if (!calleeName) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const targetDecl = this.findDeclarationInProject(calleeName);
|
|
102
|
+
if (!targetDecl) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const targetFile = targetDecl.getSourceFile().getFilePath();
|
|
106
|
+
const key = `${targetFile}:${calleeName}`;
|
|
107
|
+
if (visited.has(key)) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
visited.add(key);
|
|
111
|
+
const children = this.buildCallees(targetDecl, depth - 1, new Set(visited));
|
|
112
|
+
callees.push({
|
|
113
|
+
name: calleeName,
|
|
114
|
+
file: targetFile,
|
|
115
|
+
line: targetDecl.getStartLineNumber(),
|
|
116
|
+
children,
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
return this.deduplicateNodes(callees);
|
|
120
|
+
}
|
|
121
|
+
buildCallers(callable, depth, visited) {
|
|
122
|
+
if (depth <= 0) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
const callers = [];
|
|
126
|
+
const name = callable.getName();
|
|
127
|
+
if (!name) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
const refs = this.project.getLanguageService().findReferences(callable);
|
|
131
|
+
for (const refSymbol of refs) {
|
|
132
|
+
for (const ref of refSymbol.getReferences()) {
|
|
133
|
+
if (ref.isDefinition()) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const refNode = ref.getNode();
|
|
137
|
+
const parentMethod = refNode.getFirstAncestor((n) => n.getKind() === SyntaxKind.MethodDeclaration ||
|
|
138
|
+
n.getKind() === SyntaxKind.FunctionDeclaration);
|
|
139
|
+
if (!parentMethod) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const callerName = parentMethod.getName();
|
|
143
|
+
if (!callerName) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const callerFile = parentMethod.getSourceFile().getFilePath();
|
|
147
|
+
const key = `${callerFile}:${callerName}`;
|
|
148
|
+
if (visited.has(key)) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
visited.add(key);
|
|
152
|
+
const children = this.buildCallers(parentMethod, depth - 1, new Set(visited));
|
|
153
|
+
callers.push({
|
|
154
|
+
name: callerName,
|
|
155
|
+
file: callerFile,
|
|
156
|
+
line: parentMethod.getStartLineNumber(),
|
|
157
|
+
children,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return this.deduplicateNodes(callers);
|
|
162
|
+
}
|
|
163
|
+
findDeclarationInProject(name) {
|
|
164
|
+
for (const sourceFile of this.project.getSourceFiles()) {
|
|
165
|
+
for (const cls of sourceFile.getClasses()) {
|
|
166
|
+
const method = cls.getMethod(name);
|
|
167
|
+
if (method) {
|
|
168
|
+
return method;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const fn = sourceFile.getFunction(name);
|
|
172
|
+
if (fn) {
|
|
173
|
+
return fn;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
extractCallName(exprText) {
|
|
179
|
+
// svc.method() → method, method() → method
|
|
180
|
+
const parts = exprText.split('.');
|
|
181
|
+
const last = parts.at(-1);
|
|
182
|
+
return last && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(last) ? last : null;
|
|
183
|
+
}
|
|
184
|
+
deduplicateNodes(nodes) {
|
|
185
|
+
const seen = new Set();
|
|
186
|
+
return nodes.filter((n) => {
|
|
187
|
+
const key = `${n.file}:${n.name}`;
|
|
188
|
+
if (seen.has(key)) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
seen.add(key);
|
|
192
|
+
return true;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=call-graph-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-graph-builder.js","sourceRoot":"","sources":["../../src/investigation/call-graph-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Codebase Searcher
|
|
3
|
+
*
|
|
4
|
+
* Searches across all source files in a ts-morph Project using three modes:
|
|
5
|
+
* - `text` — literal string search (case-sensitive substring)
|
|
6
|
+
* - `pattern` — regular-expression search
|
|
7
|
+
* - `symbol` — TypeScript declaration search (class, function, interface,
|
|
8
|
+
* enum, type alias, variable)
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* The project must already have the relevant source files added before calling
|
|
12
|
+
* `search`. For `symbol` mode only top-level named declarations are indexed;
|
|
13
|
+
* local variables and anonymous expressions are not returned.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const searcher = new CodebaseSearcher(project);
|
|
18
|
+
*
|
|
19
|
+
* // Text search
|
|
20
|
+
* const hits = searcher.search('TODO:', { mode: 'text' });
|
|
21
|
+
*
|
|
22
|
+
* // Regex search
|
|
23
|
+
* const selectors = searcher.search('selector:\\s*["\']([^"\']+)["\']', { mode: 'pattern' });
|
|
24
|
+
*
|
|
25
|
+
* // Symbol search
|
|
26
|
+
* const classes = searcher.search('UserService', { mode: 'symbol' });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
import type { Project } from 'ts-morph';
|
|
30
|
+
/** The kind of named declaration returned in symbol-mode results. */
|
|
31
|
+
export type SymbolKind = 'class' | 'function' | 'interface' | 'enum' | 'typeAlias' | 'variable';
|
|
32
|
+
/** A single search result. */
|
|
33
|
+
export interface SearchResult {
|
|
34
|
+
/** Absolute file path. */
|
|
35
|
+
file: string;
|
|
36
|
+
/** 1-based line number of the match. */
|
|
37
|
+
line: number;
|
|
38
|
+
/** 1-based column of the match start. */
|
|
39
|
+
col: number;
|
|
40
|
+
/** The source line (trimmed) containing the match. */
|
|
41
|
+
snippet: string;
|
|
42
|
+
/**
|
|
43
|
+
* Set in `symbol` mode to classify the declaration type.
|
|
44
|
+
* Absent in `text` and `pattern` modes.
|
|
45
|
+
*/
|
|
46
|
+
symbolKind?: SymbolKind;
|
|
47
|
+
}
|
|
48
|
+
/** Options for `CodebaseSearcher.search()`. */
|
|
49
|
+
export interface SearchOptions {
|
|
50
|
+
/**
|
|
51
|
+
* - `text` — literal substring match
|
|
52
|
+
* - `pattern` — regular expression match
|
|
53
|
+
* - `symbol` — TypeScript named declaration lookup
|
|
54
|
+
*/
|
|
55
|
+
mode: 'text' | 'pattern' | 'symbol';
|
|
56
|
+
/**
|
|
57
|
+
* Optional glob pattern (minimatch) to restrict which files are searched.
|
|
58
|
+
* E.g. `'**\/*.service.ts'`. When omitted all project source files are
|
|
59
|
+
* searched.
|
|
60
|
+
*/
|
|
61
|
+
include?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Maximum number of results to return. When omitted all matches are
|
|
64
|
+
* returned.
|
|
65
|
+
*/
|
|
66
|
+
maxResults?: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Searches source files in a ts-morph `Project` by text, regex, or symbol
|
|
70
|
+
* name.
|
|
71
|
+
*/
|
|
72
|
+
export declare class CodebaseSearcher {
|
|
73
|
+
private readonly project;
|
|
74
|
+
constructor(project: Project);
|
|
75
|
+
/**
|
|
76
|
+
* Search for `query` across all (filtered) source files.
|
|
77
|
+
*
|
|
78
|
+
* @param query - The text, regex pattern, or symbol name to find.
|
|
79
|
+
* @param options - Search mode and optional file filter / result limit.
|
|
80
|
+
* @returns Array of `SearchResult` objects ordered by file then line.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* searcher.search('UserService', { mode: 'symbol' });
|
|
85
|
+
* searcher.search('TODO', { mode: 'text', include: 'src/**\/*.ts' });
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
search(query: string, options: SearchOptions): SearchResult[];
|
|
89
|
+
/**
|
|
90
|
+
* Text or pattern search: splits each file into lines and tests each line.
|
|
91
|
+
*/
|
|
92
|
+
private searchText;
|
|
93
|
+
/**
|
|
94
|
+
* Symbol search: finds top-level named declarations whose name equals
|
|
95
|
+
* `query`.
|
|
96
|
+
*/
|
|
97
|
+
private searchSymbols;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=codebase-searcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codebase-searcher.d.ts","sourceRoot":"","sources":["../../src/investigation/codebase-searcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,qEAAqE;AACrE,MAAM,MAAM,UAAU,GAClB,OAAO,GACP,UAAU,GACV,WAAW,GACX,MAAM,GACN,WAAW,GACX,UAAU,CAAC;AAEf,8BAA8B;AAC9B,MAAM,WAAW,YAAY;IAC3B,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IAEb,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IAEb,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IAEZ,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IAEpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAeD;;;GAGG;AACH,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,OAAO;IAE7C;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,YAAY,EAAE;IAoB7D;;OAEG;IACH,OAAO,CAAC,UAAU;IAqClB;;;OAGG;IACH,OAAO,CAAC,aAAa;CAwGtB"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Codebase Searcher
|
|
3
|
+
*
|
|
4
|
+
* Searches across all source files in a ts-morph Project using three modes:
|
|
5
|
+
* - `text` — literal string search (case-sensitive substring)
|
|
6
|
+
* - `pattern` — regular-expression search
|
|
7
|
+
* - `symbol` — TypeScript declaration search (class, function, interface,
|
|
8
|
+
* enum, type alias, variable)
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* The project must already have the relevant source files added before calling
|
|
12
|
+
* `search`. For `symbol` mode only top-level named declarations are indexed;
|
|
13
|
+
* local variables and anonymous expressions are not returned.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const searcher = new CodebaseSearcher(project);
|
|
18
|
+
*
|
|
19
|
+
* // Text search
|
|
20
|
+
* const hits = searcher.search('TODO:', { mode: 'text' });
|
|
21
|
+
*
|
|
22
|
+
* // Regex search
|
|
23
|
+
* const selectors = searcher.search('selector:\\s*["\']([^"\']+)["\']', { mode: 'pattern' });
|
|
24
|
+
*
|
|
25
|
+
* // Symbol search
|
|
26
|
+
* const classes = searcher.search('UserService', { mode: 'symbol' });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Converts a glob pattern (`**\/*.service.ts`) to a RegExp and tests `filePath`.
|
|
31
|
+
* Supports `**` (any path segments) and `*` (single segment wildcard).
|
|
32
|
+
*/
|
|
33
|
+
function matchesGlob(filePath, pattern) {
|
|
34
|
+
const escaped = pattern
|
|
35
|
+
.replaceAll(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
36
|
+
.replaceAll('**', '\u0000')
|
|
37
|
+
.replaceAll('*', '[^/]*')
|
|
38
|
+
.replaceAll('\u0000', '.*');
|
|
39
|
+
return new RegExp(`(^|/)${escaped}$`).test(filePath);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Searches source files in a ts-morph `Project` by text, regex, or symbol
|
|
43
|
+
* name.
|
|
44
|
+
*/
|
|
45
|
+
export class CodebaseSearcher {
|
|
46
|
+
project;
|
|
47
|
+
constructor(project) {
|
|
48
|
+
this.project = project;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Search for `query` across all (filtered) source files.
|
|
52
|
+
*
|
|
53
|
+
* @param query - The text, regex pattern, or symbol name to find.
|
|
54
|
+
* @param options - Search mode and optional file filter / result limit.
|
|
55
|
+
* @returns Array of `SearchResult` objects ordered by file then line.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* searcher.search('UserService', { mode: 'symbol' });
|
|
60
|
+
* searcher.search('TODO', { mode: 'text', include: 'src/**\/*.ts' });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
search(query, options) {
|
|
64
|
+
const sourceFiles = this.project
|
|
65
|
+
.getSourceFiles()
|
|
66
|
+
.filter((sf) => options.include === undefined ||
|
|
67
|
+
matchesGlob(sf.getFilePath(), options.include));
|
|
68
|
+
const results = options.mode === 'symbol'
|
|
69
|
+
? this.searchSymbols(query, sourceFiles)
|
|
70
|
+
: this.searchText(query, options.mode, sourceFiles);
|
|
71
|
+
if (options.maxResults !== undefined) {
|
|
72
|
+
return results.slice(0, options.maxResults);
|
|
73
|
+
}
|
|
74
|
+
return results;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Text or pattern search: splits each file into lines and tests each line.
|
|
78
|
+
*/
|
|
79
|
+
searchText(query, mode, sourceFiles) {
|
|
80
|
+
const results = [];
|
|
81
|
+
const regex = mode === 'pattern' ? new RegExp(query) : null;
|
|
82
|
+
for (const sf of sourceFiles) {
|
|
83
|
+
const filePath = sf.getFilePath();
|
|
84
|
+
const lines = sf.getFullText().split('\n');
|
|
85
|
+
lines.forEach((lineText, index) => {
|
|
86
|
+
const matched = regex === null ? lineText.includes(query) : regex.test(lineText);
|
|
87
|
+
if (!matched) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const col = regex === null
|
|
91
|
+
? lineText.indexOf(query) + 1
|
|
92
|
+
: lineText.search(regex) + 1;
|
|
93
|
+
results.push({
|
|
94
|
+
file: filePath,
|
|
95
|
+
line: index + 1,
|
|
96
|
+
col,
|
|
97
|
+
snippet: lineText.trim(),
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return results;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Symbol search: finds top-level named declarations whose name equals
|
|
105
|
+
* `query`.
|
|
106
|
+
*/
|
|
107
|
+
searchSymbols(query, sourceFiles) {
|
|
108
|
+
const results = [];
|
|
109
|
+
for (const sf of sourceFiles) {
|
|
110
|
+
const filePath = sf.getFilePath();
|
|
111
|
+
// Classes
|
|
112
|
+
for (const decl of sf.getClasses()) {
|
|
113
|
+
if (decl.getName() === query) {
|
|
114
|
+
const pos = decl.getNameNode()?.getStart() ?? decl.getStart();
|
|
115
|
+
const { line, column } = sf.getLineAndColumnAtPos(pos);
|
|
116
|
+
results.push({
|
|
117
|
+
file: filePath,
|
|
118
|
+
line,
|
|
119
|
+
col: column,
|
|
120
|
+
snippet: (decl.getText().split('\n')[0] ?? '').trim(),
|
|
121
|
+
symbolKind: 'class',
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Functions
|
|
126
|
+
for (const decl of sf.getFunctions()) {
|
|
127
|
+
if (decl.getName() === query) {
|
|
128
|
+
const pos = decl.getNameNode()?.getStart() ?? decl.getStart();
|
|
129
|
+
const { line, column } = sf.getLineAndColumnAtPos(pos);
|
|
130
|
+
results.push({
|
|
131
|
+
file: filePath,
|
|
132
|
+
line,
|
|
133
|
+
col: column,
|
|
134
|
+
snippet: (decl.getText().split('\n')[0] ?? '').trim(),
|
|
135
|
+
symbolKind: 'function',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Interfaces
|
|
140
|
+
for (const decl of sf.getInterfaces()) {
|
|
141
|
+
if (decl.getName() === query) {
|
|
142
|
+
const pos = decl.getNameNode().getStart();
|
|
143
|
+
const { line, column } = sf.getLineAndColumnAtPos(pos);
|
|
144
|
+
results.push({
|
|
145
|
+
file: filePath,
|
|
146
|
+
line,
|
|
147
|
+
col: column,
|
|
148
|
+
snippet: (decl.getText().split('\n')[0] ?? '').trim(),
|
|
149
|
+
symbolKind: 'interface',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Enums
|
|
154
|
+
for (const decl of sf.getEnums()) {
|
|
155
|
+
if (decl.getName() === query) {
|
|
156
|
+
const pos = decl.getNameNode().getStart();
|
|
157
|
+
const { line, column } = sf.getLineAndColumnAtPos(pos);
|
|
158
|
+
results.push({
|
|
159
|
+
file: filePath,
|
|
160
|
+
line,
|
|
161
|
+
col: column,
|
|
162
|
+
snippet: (decl.getText().split('\n')[0] ?? '').trim(),
|
|
163
|
+
symbolKind: 'enum',
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Type aliases
|
|
168
|
+
for (const decl of sf.getTypeAliases()) {
|
|
169
|
+
if (decl.getName() === query) {
|
|
170
|
+
const pos = decl.getNameNode().getStart();
|
|
171
|
+
const { line, column } = sf.getLineAndColumnAtPos(pos);
|
|
172
|
+
results.push({
|
|
173
|
+
file: filePath,
|
|
174
|
+
line,
|
|
175
|
+
col: column,
|
|
176
|
+
snippet: (decl.getText().split('\n')[0] ?? '').trim(),
|
|
177
|
+
symbolKind: 'typeAlias',
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Variables (top-level const/let/var declarations)
|
|
182
|
+
for (const varStmt of sf.getVariableStatements()) {
|
|
183
|
+
for (const decl of varStmt.getDeclarations()) {
|
|
184
|
+
if (decl.getName() === query) {
|
|
185
|
+
const pos = decl.getNameNode().getStart();
|
|
186
|
+
const { line, column } = sf.getLineAndColumnAtPos(pos);
|
|
187
|
+
results.push({
|
|
188
|
+
file: filePath,
|
|
189
|
+
line,
|
|
190
|
+
col: column,
|
|
191
|
+
snippet: (varStmt.getText().split('\n')[0] ?? '').trim(),
|
|
192
|
+
symbolKind: 'variable',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return results;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=codebase-searcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codebase-searcher.js","sourceRoot":"","sources":["../../src/investigation/codebase-searcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Stack Trace Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses Node.js/Angular/Zone.js/browser stack traces and maps frames to project source files.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* Frames are classified as project files when their resolved path starts with `projectRoot`
|
|
8
|
+
* and does not pass through `node_modules`. Browser URL frames (http/https) are always
|
|
9
|
+
* classified as non-project files regardless of origin.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const parser = new StackTraceParser('/my/project/src');
|
|
14
|
+
* const frames = parser.parse(error.stack ?? '');
|
|
15
|
+
* // frames[0].file → '/my/project/src/app/user.service.ts'
|
|
16
|
+
* // frames[0].isProjectFile → true
|
|
17
|
+
*
|
|
18
|
+
* const projectOnly = parser.parseProjectFrames(error.stack ?? '');
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
/** A single resolved stack frame. */
|
|
22
|
+
export interface StackFrame {
|
|
23
|
+
/** Absolute file path. For browser URL frames, the raw URL string. */
|
|
24
|
+
file: string;
|
|
25
|
+
/** 1-based line number. */
|
|
26
|
+
line: number;
|
|
27
|
+
/** 1-based column number. */
|
|
28
|
+
col: number;
|
|
29
|
+
/** Function or method name. `'<anonymous>'` when not present. */
|
|
30
|
+
functionName: string;
|
|
31
|
+
/**
|
|
32
|
+
* `true` when the frame's path starts with `projectRoot`
|
|
33
|
+
* and does not pass through `node_modules`.
|
|
34
|
+
*/
|
|
35
|
+
isProjectFile: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parses Node.js/Angular/Zone.js/browser stack traces into structured frames.
|
|
39
|
+
*/
|
|
40
|
+
export declare class StackTraceParser {
|
|
41
|
+
private readonly projectRoot;
|
|
42
|
+
/**
|
|
43
|
+
* @param projectRoot - Absolute path to the project root used to classify
|
|
44
|
+
* frames as project files vs. external dependencies.
|
|
45
|
+
*/
|
|
46
|
+
constructor(projectRoot: string);
|
|
47
|
+
/**
|
|
48
|
+
* Parses a raw stack trace string into an array of structured frames.
|
|
49
|
+
*
|
|
50
|
+
* @param stackTrace - Raw `Error.stack` string or console-captured stack trace.
|
|
51
|
+
* @returns All frames found, including non-project frames.
|
|
52
|
+
*/
|
|
53
|
+
parse(stackTrace: string): StackFrame[];
|
|
54
|
+
/**
|
|
55
|
+
* Parses a stack trace and returns only frames that belong to the project.
|
|
56
|
+
*
|
|
57
|
+
* @param stackTrace - Raw `Error.stack` string or console-captured stack trace.
|
|
58
|
+
* @returns Frames where `isProjectFile` is `true`.
|
|
59
|
+
*/
|
|
60
|
+
parseProjectFrames(stackTrace: string): StackFrame[];
|
|
61
|
+
private parseLine;
|
|
62
|
+
private buildFrame;
|
|
63
|
+
private isProjectFile;
|
|
64
|
+
/**
|
|
65
|
+
* Strips the `async ` prefix that ts-jest/V8 sometimes leaves in function names
|
|
66
|
+
* when the regex group captures it as part of the name rather than the keyword.
|
|
67
|
+
*/
|
|
68
|
+
private sanitizeFunctionName;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=stack-trace-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack-trace-parser.d.ts","sourceRoot":"","sources":["../../src/investigation/stack-trace-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,qCAAqC;AACrC,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IAEb,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IAEZ,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;CACxB;AAqBD;;GAEG;AACH,qBAAa,gBAAgB;IAKf,OAAO,CAAC,QAAQ,CAAC,WAAW;IAJxC;;;OAGG;gBAC0B,WAAW,EAAE,MAAM;IAEhD;;;;;OAKG;IACH,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE;IAiBvC;;;;;OAKG;IACH,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE;IAIpD,OAAO,CAAC,SAAS;IA0BjB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,aAAa;IAUrB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;CAM7B"}
|