@angular-modernizer/api 0.1.3 → 0.2.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/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/investigation/call-graph-builder.d.ts +95 -8
- package/dist/investigation/call-graph-builder.d.ts.map +1 -1
- package/dist/investigation/call-graph-builder.js +424 -81
- package/dist/investigation/call-graph-builder.js.map +1 -1
- package/dist/investigation/codebase-searcher.d.ts +68 -0
- package/dist/investigation/codebase-searcher.d.ts.map +1 -1
- package/dist/investigation/codebase-searcher.js +154 -10
- package/dist/investigation/codebase-searcher.js.map +1 -1
- package/dist/investigation/template-usage-finder.d.ts +64 -0
- package/dist/investigation/template-usage-finder.d.ts.map +1 -0
- package/dist/investigation/template-usage-finder.js +279 -0
- package/dist/investigation/template-usage-finder.js.map +1 -0
- package/dist/investigation/template-usage-scanner.d.ts +69 -0
- package/dist/investigation/template-usage-scanner.d.ts.map +1 -0
- package/dist/investigation/template-usage-scanner.js +375 -0
- package/dist/investigation/template-usage-scanner.js.map +1 -0
- package/dist/investigation/usage-finder.d.ts +51 -5
- package/dist/investigation/usage-finder.d.ts.map +1 -1
- package/dist/investigation/usage-finder.js +129 -36
- package/dist/investigation/usage-finder.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +16 -0
- package/src/investigation/call-graph-builder.ts +528 -103
- package/src/investigation/codebase-searcher.ts +240 -11
- package/src/investigation/template-usage-finder.ts +389 -0
- package/src/investigation/template-usage-scanner.ts +529 -0
- package/src/investigation/usage-finder.ts +194 -54
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Template Usage Finder
|
|
3
|
+
*
|
|
4
|
+
* Project-level companion to `scanTemplate`: resolves what a symbol means
|
|
5
|
+
* in Angular templates (component/directive selector, pipe name, class
|
|
6
|
+
* member, input/output binding) and scans every component template
|
|
7
|
+
* (external `templateUrl` files and inline `template:` literals).
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Member hits are `verified` when they read the member from the component
|
|
11
|
+
* context (`foo`, `this.foo`) inside the template of the declaring class or
|
|
12
|
+
* one of its subclasses. Same-name reads elsewhere (other components, or
|
|
13
|
+
* `x.foo`) are reported as `template-unverified`: they may or may not refer
|
|
14
|
+
* to the searched member.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const finder = new TemplateUsageFinder(project);
|
|
19
|
+
* const usages = finder.findTemplateUsages('UserCardComponent', declarations);
|
|
20
|
+
* // [{ file: '/src/app/list.component.html', usageType: 'template', templateKind: 'element', ... }]
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { Node, } from 'ts-morph';
|
|
24
|
+
import { dirname, resolve } from 'node:path';
|
|
25
|
+
import { scanTemplate, } from './template-usage-scanner.js';
|
|
26
|
+
const COMPONENT_DECORATORS = new Set(['Component', 'ExportComponent']);
|
|
27
|
+
const DIRECTIVE_DECORATORS = new Set([
|
|
28
|
+
'Component',
|
|
29
|
+
'ExportComponent',
|
|
30
|
+
'Directive',
|
|
31
|
+
]);
|
|
32
|
+
const SIGNAL_BINDING_FACTORIES = new Set(['input', 'output', 'model']);
|
|
33
|
+
function findDecorator(cls, names) {
|
|
34
|
+
return cls.getDecorators().find((d) => names.has(d.getName()));
|
|
35
|
+
}
|
|
36
|
+
/** Reads a string-valued property (`selector`, `name`, `templateUrl`) from decorator metadata. */
|
|
37
|
+
function readDecoratorString(decorator, property) {
|
|
38
|
+
const arg = decorator.getArguments()[0];
|
|
39
|
+
if (arg === undefined || !Node.isObjectLiteralExpression(arg)) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const prop = arg.getProperty(property);
|
|
43
|
+
if (prop === undefined || !Node.isPropertyAssignment(prop)) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const init = prop.getInitializer();
|
|
47
|
+
if (init !== undefined &&
|
|
48
|
+
(Node.isStringLiteral(init) || Node.isNoSubstitutionTemplateLiteral(init))) {
|
|
49
|
+
return { value: init.getLiteralText(), node: init };
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
function lineInfo(text, offset) {
|
|
54
|
+
const before = text.slice(0, offset);
|
|
55
|
+
const line = before.split('\n').length;
|
|
56
|
+
const lineStart = before.lastIndexOf('\n') + 1;
|
|
57
|
+
const lineEnd = text.indexOf('\n', offset);
|
|
58
|
+
const snippet = text.slice(lineStart, lineEnd === -1 ? undefined : lineEnd);
|
|
59
|
+
return { line, col: offset - lineStart + 1, snippet: snippet.trim() };
|
|
60
|
+
}
|
|
61
|
+
/** Input/output names under which a member can be bound from a parent template. */
|
|
62
|
+
function bindingNamesOf(member) {
|
|
63
|
+
const names = [];
|
|
64
|
+
const name = Node.hasName(member) ? member.getName() : undefined;
|
|
65
|
+
if (Node.isDecoratable(member)) {
|
|
66
|
+
for (const decorator of member.getDecorators()) {
|
|
67
|
+
const decoratorName = decorator.getName();
|
|
68
|
+
if (decoratorName !== 'Input' && decoratorName !== 'Output') {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const alias = decorator.getArguments()[0];
|
|
72
|
+
const aliasText = alias !== undefined && Node.isStringLiteral(alias)
|
|
73
|
+
? alias.getLiteralText()
|
|
74
|
+
: undefined;
|
|
75
|
+
names.push(aliasText ?? name ?? '');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (Node.isPropertyDeclaration(member)) {
|
|
79
|
+
const init = member.getInitializer();
|
|
80
|
+
const callee = init !== undefined && Node.isCallExpression(init)
|
|
81
|
+
? init.getExpression().getText().split('.')[0]
|
|
82
|
+
: undefined;
|
|
83
|
+
if (callee !== undefined && SIGNAL_BINDING_FACTORIES.has(callee)) {
|
|
84
|
+
names.push(name ?? '');
|
|
85
|
+
if (callee === 'model' && name !== undefined) {
|
|
86
|
+
names.push(`${name}Change`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return names.filter((n) => n !== '');
|
|
91
|
+
}
|
|
92
|
+
function inheritsFrom(cls, owners) {
|
|
93
|
+
const seen = new Set();
|
|
94
|
+
let current = cls;
|
|
95
|
+
while (current !== undefined && !seen.has(current)) {
|
|
96
|
+
if (owners.has(current)) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
seen.add(current);
|
|
100
|
+
current = current.getBaseClass();
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Finds usages of a symbol inside Angular component templates.
|
|
106
|
+
*/
|
|
107
|
+
export class TemplateUsageFinder {
|
|
108
|
+
project;
|
|
109
|
+
constructor(project) {
|
|
110
|
+
this.project = project;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* @param symbol - Searched name (class, member, or pipe class name).
|
|
114
|
+
* @param declarations - Declaration nodes named `symbol` (as found by `UsageFinder`).
|
|
115
|
+
* @returns Template usages, unsorted.
|
|
116
|
+
*/
|
|
117
|
+
findTemplateUsages(symbol, declarations) {
|
|
118
|
+
const selectorTargets = [];
|
|
119
|
+
const pipeNames = [];
|
|
120
|
+
const members = [];
|
|
121
|
+
for (const decl of declarations) {
|
|
122
|
+
if (Node.isClassDeclaration(decl)) {
|
|
123
|
+
const directive = findDecorator(decl, DIRECTIVE_DECORATORS);
|
|
124
|
+
const selector = directive === undefined
|
|
125
|
+
? undefined
|
|
126
|
+
: readDecoratorString(directive, 'selector')?.value;
|
|
127
|
+
if (selector !== undefined) {
|
|
128
|
+
selectorTargets.push(selector);
|
|
129
|
+
}
|
|
130
|
+
const pipe = findDecorator(decl, new Set(['Pipe']));
|
|
131
|
+
const pipeName = pipe === undefined ? undefined : readDecoratorString(pipe, 'name')?.value;
|
|
132
|
+
if (pipeName !== undefined) {
|
|
133
|
+
pipeNames.push(pipeName);
|
|
134
|
+
}
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
// Parameter properties live in the constructor; other members directly in the class.
|
|
138
|
+
const ownerClass = Node.isParameterDeclaration(decl)
|
|
139
|
+
? decl.getParent().getParent()
|
|
140
|
+
: decl.getParent();
|
|
141
|
+
const isMember = ownerClass !== undefined &&
|
|
142
|
+
Node.isClassDeclaration(ownerClass) &&
|
|
143
|
+
(Node.isMethodDeclaration(decl) ||
|
|
144
|
+
Node.isPropertyDeclaration(decl) ||
|
|
145
|
+
Node.isGetAccessorDeclaration(decl) ||
|
|
146
|
+
Node.isSetAccessorDeclaration(decl) ||
|
|
147
|
+
(Node.isParameterDeclaration(decl) && decl.isParameterProperty()));
|
|
148
|
+
if (isMember && Node.isClassDeclaration(ownerClass)) {
|
|
149
|
+
members.push({ owner: ownerClass, bindingNames: bindingNamesOf(decl) });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const hasClassTarget = selectorTargets.length > 0 || pipeNames.length > 0;
|
|
153
|
+
const scanMembers = members.length > 0 || declarations.length === 0;
|
|
154
|
+
if (!hasClassTarget && !scanMembers) {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
const queries = this.buildQueries(symbol, selectorTargets, pipeNames, members, scanMembers);
|
|
158
|
+
const memberOwners = new Set(members.map((m) => m.owner));
|
|
159
|
+
const usages = [];
|
|
160
|
+
for (const template of this.collectTemplates()) {
|
|
161
|
+
for (const query of queries) {
|
|
162
|
+
for (const hit of scanTemplate(template.content, query)) {
|
|
163
|
+
usages.push(this.toUsage(template, hit, memberOwners));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return usages;
|
|
168
|
+
}
|
|
169
|
+
buildQueries(symbol, selectors, pipeNames, members, scanMembers) {
|
|
170
|
+
const queries = [];
|
|
171
|
+
for (const selector of selectors) {
|
|
172
|
+
queries.push({ selector });
|
|
173
|
+
}
|
|
174
|
+
for (const pipeName of pipeNames) {
|
|
175
|
+
queries.push({ pipeName });
|
|
176
|
+
}
|
|
177
|
+
if (scanMembers) {
|
|
178
|
+
queries.push({ memberName: symbol });
|
|
179
|
+
}
|
|
180
|
+
for (const member of members) {
|
|
181
|
+
const directive = findDecorator(member.owner, DIRECTIVE_DECORATORS);
|
|
182
|
+
const bindingSelector = directive === undefined
|
|
183
|
+
? undefined
|
|
184
|
+
: readDecoratorString(directive, 'selector')?.value;
|
|
185
|
+
if (bindingSelector === undefined) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
for (const bindingName of member.bindingNames) {
|
|
189
|
+
queries.push({ bindingName, bindingSelector });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return queries;
|
|
193
|
+
}
|
|
194
|
+
toUsage(template, hit, memberOwners) {
|
|
195
|
+
const position = template.locate(hit.offset);
|
|
196
|
+
const isMemberHit = hit.implicitReceiver !== undefined;
|
|
197
|
+
const verified = !isMemberHit ||
|
|
198
|
+
(hit.implicitReceiver === true && inheritsFrom(template.owner, memberOwners));
|
|
199
|
+
const component = template.owner.getName() ?? '<anonymous>';
|
|
200
|
+
return {
|
|
201
|
+
file: template.file,
|
|
202
|
+
line: position.line,
|
|
203
|
+
col: position.col,
|
|
204
|
+
snippet: position.snippet,
|
|
205
|
+
templateKind: hit.kind,
|
|
206
|
+
templateMatch: verified ? 'verified' : 'template-unverified',
|
|
207
|
+
component,
|
|
208
|
+
...(verified
|
|
209
|
+
? {}
|
|
210
|
+
: {
|
|
211
|
+
note: hit.implicitReceiver === true
|
|
212
|
+
? `Same-name member used in the template of ${component}, which does not declare or inherit the searched member.`
|
|
213
|
+
: `Same-name property accessed on another object ('x.${hit.name}') in the template of ${component}; receiver type not checked.`,
|
|
214
|
+
}),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/** All component templates in the project (inline and external). */
|
|
218
|
+
collectTemplates() {
|
|
219
|
+
const templates = [];
|
|
220
|
+
for (const sf of this.project.getSourceFiles()) {
|
|
221
|
+
if (sf.isDeclarationFile() || sf.isInNodeModules()) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
for (const cls of sf.getClasses()) {
|
|
225
|
+
const component = findDecorator(cls, COMPONENT_DECORATORS);
|
|
226
|
+
if (component === undefined) {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const template = this.loadTemplate(sf, cls, component);
|
|
230
|
+
if (template !== undefined) {
|
|
231
|
+
templates.push(template);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return templates;
|
|
236
|
+
}
|
|
237
|
+
loadTemplate(sf, owner, decorator) {
|
|
238
|
+
const inline = readDecoratorString(decorator, 'template');
|
|
239
|
+
if (inline !== undefined) {
|
|
240
|
+
// Raw text between the delimiters keeps offsets aligned with the .ts file.
|
|
241
|
+
const literalStart = inline.node.getStart() + 1;
|
|
242
|
+
const content = inline.node.getText().slice(1, -1);
|
|
243
|
+
return {
|
|
244
|
+
owner,
|
|
245
|
+
file: sf.getFilePath(),
|
|
246
|
+
content,
|
|
247
|
+
locate: (offset) => {
|
|
248
|
+
const pos = literalStart + offset;
|
|
249
|
+
const { line, column } = sf.getLineAndColumnAtPos(pos);
|
|
250
|
+
const snippet = sf.getFullText().split('\n')[line - 1] ?? '';
|
|
251
|
+
return { line, col: column, snippet: snippet.trim() };
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
const templateUrl = readDecoratorString(decorator, 'templateUrl');
|
|
256
|
+
if (templateUrl === undefined) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
const file = resolve(dirname(sf.getFilePath()), templateUrl.value).replaceAll('\\', '/');
|
|
260
|
+
const fs = this.project.getFileSystem();
|
|
261
|
+
let content;
|
|
262
|
+
try {
|
|
263
|
+
if (!fs.fileExistsSync(file)) {
|
|
264
|
+
return undefined;
|
|
265
|
+
}
|
|
266
|
+
content = fs.readFileSync(file);
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
owner,
|
|
273
|
+
file,
|
|
274
|
+
content,
|
|
275
|
+
locate: (offset) => lineInfo(content, offset),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=template-usage-finder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-usage-finder.js","sourceRoot":"","sources":["../../src/investigation/template-usage-finder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @angular-modernizer/api - Template Usage Scanner
|
|
3
|
+
*
|
|
4
|
+
* Parses a single Angular template with `@angular/compiler` and reports
|
|
5
|
+
* where a selector, pipe, class member, or input/output binding is used.
|
|
6
|
+
* Positions are returned as offsets into the template text so callers can
|
|
7
|
+
* map them to external `.html` files or to inline `template:` literals.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Pure function over template text; it knows nothing about ts-morph. The
|
|
11
|
+
* project-level lookup (which templates belong to which class, selector and
|
|
12
|
+
* pipe resolution) lives in `TemplateUsageFinder`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const hits = scanTemplate('<app-user (saved)="onSave()"></app-user>', {
|
|
17
|
+
* selector: 'app-user',
|
|
18
|
+
* memberName: 'onSave',
|
|
19
|
+
* });
|
|
20
|
+
* // [{ kind: 'element', ... }, { kind: 'method-call', implicitReceiver: true, ... }]
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
/** How a template refers to the searched symbol. */
|
|
24
|
+
export type TemplateUsageKind = 'element' | 'attribute' | 'pipe' | 'property-read' | 'property-write' | 'method-call' | 'input-binding' | 'output-binding';
|
|
25
|
+
/** What to look for in a template. All fields are optional and combinable. */
|
|
26
|
+
export interface TemplateQuery {
|
|
27
|
+
/** Component/directive CSS selector (may be a selector list). */
|
|
28
|
+
selector?: string;
|
|
29
|
+
/** Pipe name as used in templates (`{{ x | name }}`). */
|
|
30
|
+
pipeName?: string;
|
|
31
|
+
/** Class member name read, written, or called in expressions. */
|
|
32
|
+
memberName?: string;
|
|
33
|
+
/** Input/output name bound as `[name]`, `name="..."` or `(name)`. */
|
|
34
|
+
bindingName?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Restricts `bindingName` matches to elements matching this selector.
|
|
37
|
+
* When omitted, bindings on any element match.
|
|
38
|
+
*/
|
|
39
|
+
bindingSelector?: string;
|
|
40
|
+
}
|
|
41
|
+
/** A single match inside a template. */
|
|
42
|
+
export interface TemplateHit {
|
|
43
|
+
/** 0-based offset into the template text. */
|
|
44
|
+
offset: number;
|
|
45
|
+
/** Kind of usage. */
|
|
46
|
+
kind: TemplateUsageKind;
|
|
47
|
+
/** Matched name (selector, pipe, member, or binding name). */
|
|
48
|
+
name: string;
|
|
49
|
+
/**
|
|
50
|
+
* For member hits: `true` when the expression reads the member from the
|
|
51
|
+
* component context (`foo`, `this.foo`), `false` for `x.foo`.
|
|
52
|
+
*/
|
|
53
|
+
implicitReceiver?: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Cheap pre-check: can the template possibly contain a hit for `query`?
|
|
57
|
+
* Avoids parsing templates that do not mention any searched token.
|
|
58
|
+
*/
|
|
59
|
+
export declare function templateMayMatch(content: string, query: TemplateQuery): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Scans one template for usages described by `query`.
|
|
62
|
+
*
|
|
63
|
+
* @param content - Raw template text.
|
|
64
|
+
* @param query - What to look for.
|
|
65
|
+
* @returns Hits ordered by offset. Returns `[]` when the template cannot be
|
|
66
|
+
* parsed at all.
|
|
67
|
+
*/
|
|
68
|
+
export declare function scanTemplate(content: string, query: TemplateQuery): TemplateHit[];
|
|
69
|
+
//# sourceMappingURL=template-usage-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-usage-scanner.d.ts","sourceRoot":"","sources":["../../src/investigation/template-usage-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA+BH,oDAAoD;AACpD,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,WAAW,GACX,MAAM,GACN,eAAe,GACf,gBAAgB,GAChB,aAAa,GACb,eAAe,GACf,gBAAgB,CAAC;AAErB,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wCAAwC;AACxC,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IAEf,qBAAqB;IACrB,IAAI,EAAE,iBAAiB,CAAC;IAExB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAmWD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CA8B/E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,WAAW,EAAE,CA6BjF"}
|