@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,117 @@
|
|
|
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
|
+
/**
|
|
22
|
+
* Regex matching a V8-style "at" frame in the following forms:
|
|
23
|
+
*
|
|
24
|
+
* ```
|
|
25
|
+
* at FunctionName (file:line:col)
|
|
26
|
+
* at async FunctionName (file:line:col)
|
|
27
|
+
* at new FunctionName (file:line:col)
|
|
28
|
+
* at file:line:col
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
const AT_FRAME_WITH_LOCATION = /^\s*at\s+(?:async\s+)?(.+?)\s+\((.+):(\d+):(\d+)\)\s*$/;
|
|
32
|
+
const AT_FRAME_WITHOUT_FUNCTION = /^\s*at\s+((?!async\s|new\s)[^(]+):(\d+):(\d+)\s*$/;
|
|
33
|
+
const HTTP_SCHEME = /^https?:\/\//;
|
|
34
|
+
const NODE_MODULES_SEGMENT = /[/\\]node_modules[/\\]/;
|
|
35
|
+
/**
|
|
36
|
+
* Parses Node.js/Angular/Zone.js/browser stack traces into structured frames.
|
|
37
|
+
*/
|
|
38
|
+
export class StackTraceParser {
|
|
39
|
+
projectRoot;
|
|
40
|
+
/**
|
|
41
|
+
* @param projectRoot - Absolute path to the project root used to classify
|
|
42
|
+
* frames as project files vs. external dependencies.
|
|
43
|
+
*/
|
|
44
|
+
constructor(projectRoot) {
|
|
45
|
+
this.projectRoot = projectRoot;
|
|
46
|
+
}
|
|
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) {
|
|
54
|
+
if (!stackTrace) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const frames = [];
|
|
58
|
+
for (const line of stackTrace.split('\n')) {
|
|
59
|
+
const frame = this.parseLine(line);
|
|
60
|
+
if (frame !== null) {
|
|
61
|
+
frames.push(frame);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return frames;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Parses a stack trace and returns only frames that belong to the project.
|
|
68
|
+
*
|
|
69
|
+
* @param stackTrace - Raw `Error.stack` string or console-captured stack trace.
|
|
70
|
+
* @returns Frames where `isProjectFile` is `true`.
|
|
71
|
+
*/
|
|
72
|
+
parseProjectFrames(stackTrace) {
|
|
73
|
+
return this.parse(stackTrace).filter((f) => f.isProjectFile);
|
|
74
|
+
}
|
|
75
|
+
parseLine(line) {
|
|
76
|
+
const withFunc = AT_FRAME_WITH_LOCATION.exec(line);
|
|
77
|
+
if (withFunc !== null) {
|
|
78
|
+
const [, functionName, file, lineStr, colStr] = withFunc;
|
|
79
|
+
return this.buildFrame(this.sanitizeFunctionName(functionName ?? ''), file ?? '', Number(lineStr), Number(colStr));
|
|
80
|
+
}
|
|
81
|
+
const withoutFunc = AT_FRAME_WITHOUT_FUNCTION.exec(line);
|
|
82
|
+
if (withoutFunc !== null) {
|
|
83
|
+
const [, file, lineStr, colStr] = withoutFunc;
|
|
84
|
+
return this.buildFrame('<anonymous>', file ?? '', Number(lineStr), Number(colStr));
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
buildFrame(functionName, file, line, col) {
|
|
89
|
+
return {
|
|
90
|
+
file,
|
|
91
|
+
line,
|
|
92
|
+
col,
|
|
93
|
+
functionName,
|
|
94
|
+
isProjectFile: this.isProjectFile(file),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
isProjectFile(file) {
|
|
98
|
+
if (HTTP_SCHEME.test(file)) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (NODE_MODULES_SEGMENT.test(file)) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
return file.startsWith(this.projectRoot);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Strips the `async ` prefix that ts-jest/V8 sometimes leaves in function names
|
|
108
|
+
* when the regex group captures it as part of the name rather than the keyword.
|
|
109
|
+
*/
|
|
110
|
+
sanitizeFunctionName(name) {
|
|
111
|
+
return name
|
|
112
|
+
.replace(/^async\s+/, '')
|
|
113
|
+
.replace(/^new\s+/, 'new ')
|
|
114
|
+
.trim();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=stack-trace-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack-trace-parser.js","sourceRoot":"","sources":["../../src/investigation/stack-trace-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Type Resolver
|
|
3
|
+
*
|
|
4
|
+
* Resolves the TypeScript type at a given position (file, line, column)
|
|
5
|
+
* using the ts-morph language service and type checker.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Useful in bug investigation to understand what type a variable holds
|
|
9
|
+
* at a specific location — including whether it is nullable, async,
|
|
10
|
+
* or wraps a generic parameter.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const resolver = new TypeResolver(project);
|
|
15
|
+
* const info = resolver.resolveType('/src/app/user.service.ts', 42, 15);
|
|
16
|
+
* // info.typeString → 'UserService'
|
|
17
|
+
* // info.isNullable → false
|
|
18
|
+
* // info.isAsync → false
|
|
19
|
+
* // info.declaredIn → '/src/app/user.service.ts'
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import type { Project } from 'ts-morph';
|
|
23
|
+
/** Resolved type information for a source position. */
|
|
24
|
+
export interface ResolvedTypeInfo {
|
|
25
|
+
/** Human-readable resolved type string. */
|
|
26
|
+
typeString: string;
|
|
27
|
+
/** Generic type parameters extracted from the type string (e.g. `['string']` for `Array<string>`). */
|
|
28
|
+
genericParams: string[];
|
|
29
|
+
/** Absolute path of the file where this type is declared. Empty string when not determinable. */
|
|
30
|
+
declaredIn: string;
|
|
31
|
+
/** `true` when the type includes `null` or `undefined` in a union. */
|
|
32
|
+
isNullable: boolean;
|
|
33
|
+
/** `true` when the type is `Promise<T>` or `Observable<T>`. */
|
|
34
|
+
isAsync: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resolves TypeScript types at source positions via ts-morph.
|
|
38
|
+
*/
|
|
39
|
+
export declare class TypeResolver {
|
|
40
|
+
private readonly project;
|
|
41
|
+
/**
|
|
42
|
+
* @param project - A ts-morph `Project` instance with source files already added.
|
|
43
|
+
*/
|
|
44
|
+
constructor(project: Project);
|
|
45
|
+
/**
|
|
46
|
+
* Resolves the TypeScript type at the given 1-based position.
|
|
47
|
+
*
|
|
48
|
+
* @param file - Absolute path of the source file.
|
|
49
|
+
* @param line - 1-based line number.
|
|
50
|
+
* @param column - 1-based column number.
|
|
51
|
+
* @returns Resolved type information, or a fallback with `typeString: 'unknown'`.
|
|
52
|
+
*/
|
|
53
|
+
resolveType(file: string, line: number, column: number): ResolvedTypeInfo;
|
|
54
|
+
private extractGenericParams;
|
|
55
|
+
private resolveDeclaredIn;
|
|
56
|
+
private checkNullable;
|
|
57
|
+
private checkAsync;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=type-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-resolver.d.ts","sourceRoot":"","sources":["../../src/investigation/type-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IAEnB,sGAAsG;IACtG,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB,iGAAiG;IACjG,UAAU,EAAE,MAAM,CAAC;IAEnB,sEAAsE;IACtE,UAAU,EAAE,OAAO,CAAC;IAEpB,+DAA+D;IAC/D,OAAO,EAAE,OAAO,CAAC;CAClB;AAgBD;;GAEG;AACH,qBAAa,YAAY;IAIX,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC;;OAEG;gBAC0B,OAAO,EAAE,OAAO;IAE7C;;;;;;;OAOG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB;IA+BzE,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,UAAU;CAInB"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Type Resolver
|
|
3
|
+
*
|
|
4
|
+
* Resolves the TypeScript type at a given position (file, line, column)
|
|
5
|
+
* using the ts-morph language service and type checker.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Useful in bug investigation to understand what type a variable holds
|
|
9
|
+
* at a specific location — including whether it is nullable, async,
|
|
10
|
+
* or wraps a generic parameter.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const resolver = new TypeResolver(project);
|
|
15
|
+
* const info = resolver.resolveType('/src/app/user.service.ts', 42, 15);
|
|
16
|
+
* // info.typeString → 'UserService'
|
|
17
|
+
* // info.isNullable → false
|
|
18
|
+
* // info.isAsync → false
|
|
19
|
+
* // info.declaredIn → '/src/app/user.service.ts'
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
const ASYNC_TYPE_NAMES = new Set([
|
|
23
|
+
'Promise',
|
|
24
|
+
'Observable',
|
|
25
|
+
'Subject',
|
|
26
|
+
'BehaviorSubject',
|
|
27
|
+
]);
|
|
28
|
+
const FALLBACK = {
|
|
29
|
+
typeString: 'unknown',
|
|
30
|
+
genericParams: [],
|
|
31
|
+
declaredIn: '',
|
|
32
|
+
isNullable: false,
|
|
33
|
+
isAsync: false,
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Resolves TypeScript types at source positions via ts-morph.
|
|
37
|
+
*/
|
|
38
|
+
export class TypeResolver {
|
|
39
|
+
project;
|
|
40
|
+
/**
|
|
41
|
+
* @param project - A ts-morph `Project` instance with source files already added.
|
|
42
|
+
*/
|
|
43
|
+
constructor(project) {
|
|
44
|
+
this.project = project;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Resolves the TypeScript type at the given 1-based position.
|
|
48
|
+
*
|
|
49
|
+
* @param file - Absolute path of the source file.
|
|
50
|
+
* @param line - 1-based line number.
|
|
51
|
+
* @param column - 1-based column number.
|
|
52
|
+
* @returns Resolved type information, or a fallback with `typeString: 'unknown'`.
|
|
53
|
+
*/
|
|
54
|
+
resolveType(file, line, column) {
|
|
55
|
+
const sourceFile = this.project.getSourceFile(file);
|
|
56
|
+
if (!sourceFile) {
|
|
57
|
+
return FALLBACK;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const pos = sourceFile.compilerNode.getPositionOfLineAndCharacter(line - 1, column - 1);
|
|
61
|
+
const node = sourceFile.getDescendantAtPos(pos);
|
|
62
|
+
if (!node) {
|
|
63
|
+
return FALLBACK;
|
|
64
|
+
}
|
|
65
|
+
const type = this.project.getTypeChecker().getTypeAtLocation(node);
|
|
66
|
+
const typeString = type.getText(node);
|
|
67
|
+
const genericParams = this.extractGenericParams(typeString);
|
|
68
|
+
const declaredIn = this.resolveDeclaredIn(type);
|
|
69
|
+
const isNullable = this.checkNullable(typeString);
|
|
70
|
+
const isAsync = this.checkAsync(typeString);
|
|
71
|
+
return { typeString, genericParams, declaredIn, isNullable, isAsync };
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return FALLBACK;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
extractGenericParams(typeString) {
|
|
78
|
+
const match = /<([^>]+)>/.exec(typeString);
|
|
79
|
+
if (!match?.[1]) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
return match[1]
|
|
83
|
+
.split(',')
|
|
84
|
+
.map((s) => s.trim())
|
|
85
|
+
.filter(Boolean);
|
|
86
|
+
}
|
|
87
|
+
resolveDeclaredIn(type) {
|
|
88
|
+
try {
|
|
89
|
+
const symbol = type.getSymbol();
|
|
90
|
+
if (!symbol) {
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
const declarations = symbol.getDeclarations();
|
|
94
|
+
if (declarations.length === 0) {
|
|
95
|
+
return '';
|
|
96
|
+
}
|
|
97
|
+
return declarations[0]?.getSourceFile().getFilePath() ?? '';
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return '';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
checkNullable(typeString) {
|
|
104
|
+
return typeString.includes('null') || typeString.includes('undefined');
|
|
105
|
+
}
|
|
106
|
+
checkAsync(typeString) {
|
|
107
|
+
const baseName = typeString.split('<')[0]?.trim() ?? '';
|
|
108
|
+
return ASYNC_TYPE_NAMES.has(baseName);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=type-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-resolver.js","sourceRoot":"","sources":["../../src/investigation/type-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Usage Finder
|
|
3
|
+
*
|
|
4
|
+
* Finds all references to a symbol (class, method, function, variable, constant)
|
|
5
|
+
* across a ts-morph Project. Used in bug investigation to determine call paths
|
|
6
|
+
* and blast radius before proposing a fix.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Uses ts-morph `findReferences()` under the hood. The project must already have
|
|
10
|
+
* the relevant source files added before calling `findUsages`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const finder = new UsageFinder(project);
|
|
15
|
+
* const usages = finder.findUsages('UserService', { file: '/src/app/user.component.ts' });
|
|
16
|
+
* // usages[0] → { file, line, col, snippet, usageType: 'read' }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import type { Project } from 'ts-morph';
|
|
20
|
+
/** Classification of how a symbol is used at a given location. */
|
|
21
|
+
export type UsageType = 'read' | 'write' | 'call';
|
|
22
|
+
/** A single resolved symbol usage. */
|
|
23
|
+
export interface SymbolUsage {
|
|
24
|
+
/** Absolute file path containing the usage. */
|
|
25
|
+
file: string;
|
|
26
|
+
/** 1-based line number. */
|
|
27
|
+
line: number;
|
|
28
|
+
/** 1-based column number. */
|
|
29
|
+
col: number;
|
|
30
|
+
/** The source line containing the usage. */
|
|
31
|
+
snippet: string;
|
|
32
|
+
/** How the symbol is used at this location. */
|
|
33
|
+
usageType: UsageType;
|
|
34
|
+
}
|
|
35
|
+
/** Options for narrowing `findUsages` results. */
|
|
36
|
+
export interface FindUsagesOptions {
|
|
37
|
+
/**
|
|
38
|
+
* Restrict results to a single source file (absolute path).
|
|
39
|
+
* When omitted, all files in the project are searched.
|
|
40
|
+
*/
|
|
41
|
+
file?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Restrict results to a specific usage type.
|
|
44
|
+
* When omitted, all usage types are returned.
|
|
45
|
+
*/
|
|
46
|
+
usageType?: UsageType;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Finds all references to named symbols across a ts-morph Project.
|
|
50
|
+
*/
|
|
51
|
+
export declare class UsageFinder {
|
|
52
|
+
private readonly project;
|
|
53
|
+
/**
|
|
54
|
+
* @param project - A ts-morph `Project` instance with source files already added.
|
|
55
|
+
*/
|
|
56
|
+
constructor(project: Project);
|
|
57
|
+
/**
|
|
58
|
+
* Finds all usages of the named symbol across the project.
|
|
59
|
+
*
|
|
60
|
+
* @param symbol - The symbol name to search for (class, method, function, variable, constant).
|
|
61
|
+
* @param options - Optional filters for file scope and usage type.
|
|
62
|
+
* @returns Array of resolved usages, sorted by file path then line number.
|
|
63
|
+
*/
|
|
64
|
+
findUsages(symbol: string, options?: FindUsagesOptions): SymbolUsage[];
|
|
65
|
+
private findSymbolNodes;
|
|
66
|
+
private classifyUsage;
|
|
67
|
+
private deduplicate;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=usage-finder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-finder.d.ts","sourceRoot":"","sources":["../../src/investigation/usage-finder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAQ,MAAM,UAAU,CAAC;AAE9C,kEAAkE;AAClE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAElD,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IAEb,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IAEZ,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAEhB,+CAA+C;IAC/C,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;GAEG;AACH,qBAAa,WAAW;IAIV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC;;OAEG;gBAC0B,OAAO,EAAE,OAAO;IAE7C;;;;;;OAMG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,WAAW,EAAE;IAqD1E,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,WAAW;CAWpB"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Usage Finder
|
|
3
|
+
*
|
|
4
|
+
* Finds all references to a symbol (class, method, function, variable, constant)
|
|
5
|
+
* across a ts-morph Project. Used in bug investigation to determine call paths
|
|
6
|
+
* and blast radius before proposing a fix.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Uses ts-morph `findReferences()` under the hood. The project must already have
|
|
10
|
+
* the relevant source files added before calling `findUsages`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const finder = new UsageFinder(project);
|
|
15
|
+
* const usages = finder.findUsages('UserService', { file: '/src/app/user.component.ts' });
|
|
16
|
+
* // usages[0] → { file, line, col, snippet, usageType: 'read' }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Finds all references to named symbols across a ts-morph Project.
|
|
21
|
+
*/
|
|
22
|
+
export class UsageFinder {
|
|
23
|
+
project;
|
|
24
|
+
/**
|
|
25
|
+
* @param project - A ts-morph `Project` instance with source files already added.
|
|
26
|
+
*/
|
|
27
|
+
constructor(project) {
|
|
28
|
+
this.project = project;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Finds all usages of the named symbol across the project.
|
|
32
|
+
*
|
|
33
|
+
* @param symbol - The symbol name to search for (class, method, function, variable, constant).
|
|
34
|
+
* @param options - Optional filters for file scope and usage type.
|
|
35
|
+
* @returns Array of resolved usages, sorted by file path then line number.
|
|
36
|
+
*/
|
|
37
|
+
findUsages(symbol, options = {}) {
|
|
38
|
+
const usages = [];
|
|
39
|
+
const sourceFiles = options.file
|
|
40
|
+
? [this.project.getSourceFile(options.file)].filter(Boolean)
|
|
41
|
+
: this.project.getSourceFiles();
|
|
42
|
+
for (const sourceFile of sourceFiles) {
|
|
43
|
+
if (!sourceFile) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const nodes = this.findSymbolNodes(sourceFile, symbol);
|
|
47
|
+
for (const node of nodes) {
|
|
48
|
+
const refs = this.project.getLanguageService().findReferences(node);
|
|
49
|
+
for (const refSymbol of refs) {
|
|
50
|
+
for (const ref of refSymbol.getReferences()) {
|
|
51
|
+
const refFile = ref.getSourceFile();
|
|
52
|
+
const refFilePath = refFile.getFilePath();
|
|
53
|
+
if (options.file && refFilePath !== options.file) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const pos = ref.getNode().getStart();
|
|
57
|
+
const lineAndCol = refFile.getLineAndColumnAtPos(pos);
|
|
58
|
+
const lineText = refFile.getFullText().split('\n')[lineAndCol.line - 1] ?? '';
|
|
59
|
+
const usageType = this.classifyUsage(ref.getNode());
|
|
60
|
+
if (options.usageType && usageType !== options.usageType) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
usages.push({
|
|
64
|
+
file: refFilePath,
|
|
65
|
+
line: lineAndCol.line,
|
|
66
|
+
col: lineAndCol.column,
|
|
67
|
+
snippet: lineText.trim(),
|
|
68
|
+
usageType,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return this.deduplicate(usages).sort((a, b) => a.file !== b.file ? a.file.localeCompare(b.file) : a.line - b.line);
|
|
75
|
+
}
|
|
76
|
+
findSymbolNodes(sourceFile, symbol) {
|
|
77
|
+
if (!sourceFile) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
const nodes = [];
|
|
81
|
+
sourceFile.forEachDescendant((node) => {
|
|
82
|
+
if ('getName' in node &&
|
|
83
|
+
typeof node.getName === 'function') {
|
|
84
|
+
if (node.getName() === symbol) {
|
|
85
|
+
nodes.push(node);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return nodes;
|
|
90
|
+
}
|
|
91
|
+
classifyUsage(node) {
|
|
92
|
+
const parent = node.getParent();
|
|
93
|
+
if (!parent) {
|
|
94
|
+
return 'read';
|
|
95
|
+
}
|
|
96
|
+
const parentKindName = parent.getKindName();
|
|
97
|
+
// Call expression: svc.method() or method()
|
|
98
|
+
if (parentKindName === 'CallExpression') {
|
|
99
|
+
return 'call';
|
|
100
|
+
}
|
|
101
|
+
if (parentKindName === 'PropertyAccessExpression') {
|
|
102
|
+
const grandParent = parent.getParent();
|
|
103
|
+
if (grandParent?.getKindName() === 'CallExpression') {
|
|
104
|
+
return 'call';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Assignment: x = value or x += value
|
|
108
|
+
if (parentKindName === 'BinaryExpression' ||
|
|
109
|
+
parentKindName === 'VariableDeclaration' ||
|
|
110
|
+
parentKindName === 'PropertyAssignment') {
|
|
111
|
+
const parentText = parent.getText();
|
|
112
|
+
const nodeText = node.getText();
|
|
113
|
+
const nodePos = parentText.indexOf(nodeText);
|
|
114
|
+
if (nodePos === 0) {
|
|
115
|
+
return 'write';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return 'read';
|
|
119
|
+
}
|
|
120
|
+
deduplicate(usages) {
|
|
121
|
+
const seen = new Set();
|
|
122
|
+
return usages.filter((u) => {
|
|
123
|
+
const key = `${u.file}:${u.line}:${u.col}`;
|
|
124
|
+
if (seen.has(key)) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
seen.add(key);
|
|
128
|
+
return true;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=usage-finder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-finder.js","sourceRoot":"","sources":["../../src/investigation/usage-finder.ts"],"names":[],"mappings":"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"}
|