@saptools/service-flow 0.1.67 → 0.1.69
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/CHANGELOG.md +20 -0
- package/README.md +27 -9
- package/TECHNICAL-NOTE.md +36 -0
- package/dist/chunk-3N3B5KHV.js +19596 -0
- package/dist/chunk-3N3B5KHV.js.map +1 -0
- package/dist/cli.js +2645 -521
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +67 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/cli/001-index-summary.ts +22 -0
- package/src/cli/003-doctor-package-resolution.ts +68 -0
- package/src/cli/doctor.ts +25 -14
- package/src/cli.ts +151 -87
- package/src/db/000-call-fact-repository.ts +499 -340
- package/src/db/001-fact-lifecycle.ts +60 -30
- package/src/db/002-fact-json-inventory.ts +169 -0
- package/src/db/003-current-fact-semantics.ts +699 -0
- package/src/db/004-package-target-invalidation.ts +183 -0
- package/src/db/005-schema-structure.ts +201 -0
- package/src/db/006-relative-symbol-resolution.ts +464 -0
- package/src/db/007-package-fact-semantics.ts +573 -0
- package/src/db/008-relative-fact-semantics.ts +210 -0
- package/src/db/009-binding-fact-semantics.ts +352 -0
- package/src/db/010-package-symbol-surface-semantics.ts +320 -0
- package/src/db/011-symbol-call-semantics.ts +144 -0
- package/src/db/012-binding-reference-proof.ts +268 -0
- package/src/db/013-index-publication-failure.ts +91 -0
- package/src/db/014-binding-helper-provenance.ts +17 -0
- package/src/db/migrations.ts +16 -3
- package/src/db/repositories.ts +130 -6
- package/src/db/schema.ts +4 -2
- package/src/index.ts +12 -0
- package/src/indexer/cds-extension-resolver.ts +27 -3
- package/src/indexer/repository-indexer.ts +135 -13
- package/src/indexer/workspace-indexer.ts +237 -34
- package/src/linker/003-package-import-symbol-resolver.ts +363 -131
- package/src/linker/004-event-subscription-handler-linker.ts +34 -11
- package/src/linker/005-odata-path-structure.ts +371 -0
- package/src/linker/006-event-template-link.ts +72 -0
- package/src/linker/007-call-edge-insertion.ts +568 -0
- package/src/linker/cross-repo-linker.ts +4 -166
- package/src/linker/odata-path-normalizer.ts +273 -180
- package/src/linker/service-resolver.ts +197 -77
- package/src/parsers/000-direct-query-execution.ts +11 -0
- package/src/parsers/002-symbol-import-bindings.ts +516 -0
- package/src/parsers/003-package-public-surface.ts +661 -0
- package/src/parsers/004-fact-identity.ts +108 -0
- package/src/parsers/005-event-subscription-facts.ts +281 -0
- package/src/parsers/006-binding-identity.ts +348 -0
- package/src/parsers/007-source-fact-reconciliation.ts +105 -0
- package/src/parsers/008-package-surface-publication.ts +82 -0
- package/src/parsers/009-symbol-call-facts.ts +528 -0
- package/src/parsers/010-package-public-surface-analysis.ts +352 -0
- package/src/parsers/011-binding-lexical-scope.ts +583 -0
- package/src/parsers/012-package-fact-contract.ts +306 -0
- package/src/parsers/013-executable-body-eligibility.ts +35 -0
- package/src/parsers/014-service-binding-helper-flow.ts +306 -0
- package/src/parsers/015-service-binding-collector.ts +693 -0
- package/src/parsers/016-local-symbol-reference.ts +261 -0
- package/src/parsers/017-symbol-derived-contexts.ts +268 -0
- package/src/parsers/018-package-commonjs-syntax.ts +142 -0
- package/src/parsers/019-binding-assignment-targets.ts +76 -0
- package/src/parsers/020-stable-local-value.ts +217 -0
- package/src/parsers/021-binding-visibility.ts +168 -0
- package/src/parsers/022-outbound-expression-analysis.ts +700 -0
- package/src/parsers/023-outbound-call-classifier.ts +692 -0
- package/src/parsers/operation-path-analysis.ts +6 -1
- package/src/parsers/outbound-call-parser.ts +162 -512
- package/src/parsers/package-json-parser.ts +45 -3
- package/src/parsers/service-binding-parser-helpers.ts +86 -15
- package/src/parsers/service-binding-parser.ts +147 -597
- package/src/parsers/symbol-parser.ts +513 -352
- package/src/trace/002-trace-diagnostics.ts +36 -1
- package/src/trace/007-implementation-start-diagnostic.ts +1 -0
- package/src/trace/011-event-subscriber-traversal.ts +100 -8
- package/src/trace/013-trace-root-scopes.ts +2 -3
- package/src/trace/014-compact-contract.ts +6 -0
- package/src/trace/015-trace-edge-recorder.ts +61 -4
- package/src/trace/016-compact-projector.ts +15 -17
- package/src/trace/019-trace-edge-semantics.ts +6 -10
- package/src/trace/020-compact-field-projection.ts +122 -38
- package/src/trace/021-compact-decision-normalization.ts +171 -0
- package/src/trace/022-trace-fact-preflight.ts +21 -0
- package/src/trace/023-nested-event-scopes.ts +23 -0
- package/src/trace/024-compact-observation-decision.ts +81 -0
- package/src/trace/025-trace-implementation-scope.ts +123 -0
- package/src/trace/026-trace-start-scope.ts +336 -0
- package/src/trace/027-trace-scope-execution.ts +566 -0
- package/src/trace/028-trace-operation-execution.ts +336 -0
- package/src/trace/029-trace-start-implementation.ts +172 -0
- package/src/trace/030-event-runtime-resolution.ts +151 -0
- package/src/trace/031-local-call-expansion.ts +37 -0
- package/src/trace/implementation-hints.ts +9 -6
- package/src/trace/selectors.ts +1 -0
- package/src/trace/trace-engine.ts +122 -624
- package/src/types.ts +57 -0
- package/src/utils/001-placeholders.ts +188 -10
- package/src/version.ts +1 -1
- package/dist/chunk-ZQABU7MR.js +0 -12151
- package/dist/chunk-ZQABU7MR.js.map +0 -1
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
export type SymbolImportModuleKind = 'relative' | 'package';
|
|
4
|
+
export type SymbolImportBindingKind =
|
|
5
|
+
| 'esm_named'
|
|
6
|
+
| 'esm_default'
|
|
7
|
+
| 'esm_namespace'
|
|
8
|
+
| 'cjs_destructured'
|
|
9
|
+
| 'cjs_namespace';
|
|
10
|
+
export type SymbolImportReferenceShape =
|
|
11
|
+
| 'identifier'
|
|
12
|
+
| 'namespace_member'
|
|
13
|
+
| 'static_member'
|
|
14
|
+
| 'default_member';
|
|
15
|
+
|
|
16
|
+
export interface PackageModuleRequest {
|
|
17
|
+
packageName: string;
|
|
18
|
+
moduleSubpath: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface SymbolImportBinding {
|
|
22
|
+
version: 1;
|
|
23
|
+
moduleKind: SymbolImportModuleKind;
|
|
24
|
+
bindingKind: SymbolImportBindingKind;
|
|
25
|
+
localName: string;
|
|
26
|
+
importedName: string | null;
|
|
27
|
+
requestedPackageName: string | null;
|
|
28
|
+
requestedModuleSubpath: string | null;
|
|
29
|
+
rawModuleSpecifier: string;
|
|
30
|
+
typeOnly: boolean;
|
|
31
|
+
bindingSiteStartOffset: number;
|
|
32
|
+
bindingSiteEndOffset: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SymbolImportReference extends SymbolImportBinding {
|
|
36
|
+
referenceShape: SymbolImportReferenceShape;
|
|
37
|
+
referencedMemberName: string | null;
|
|
38
|
+
requestedPublicName: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const packagePart = /^[A-Za-z0-9][A-Za-z0-9._~-]*$/;
|
|
42
|
+
const invalidPackageSpecifierCharacter = /[\\:?#]/;
|
|
43
|
+
|
|
44
|
+
function hasInvalidSubpath(parts: string[]): boolean {
|
|
45
|
+
return parts.some((part) =>
|
|
46
|
+
!part || part === '.' || part === '..' || !packagePart.test(part));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function invalidPackageSpecifier(specifier: string): boolean {
|
|
50
|
+
return !specifier || specifier.startsWith('.')
|
|
51
|
+
|| invalidPackageSpecifierCharacter.test(specifier);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function validPackageParts(parts: string[], scoped: boolean): boolean {
|
|
55
|
+
if (parts.some((part) => !part)) return false;
|
|
56
|
+
if (scoped && (parts.length !== 2 || !parts[0]?.startsWith('@')))
|
|
57
|
+
return false;
|
|
58
|
+
return !hasInvalidSubpath(parts.map((part) => part.replace(/^@/, '')));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function packageModuleRequest(
|
|
62
|
+
specifier: string,
|
|
63
|
+
): PackageModuleRequest | undefined {
|
|
64
|
+
if (invalidPackageSpecifier(specifier)) return undefined;
|
|
65
|
+
const parts = specifier.split('/');
|
|
66
|
+
const scoped = specifier.startsWith('@');
|
|
67
|
+
const packageParts = scoped ? parts.slice(0, 2) : parts.slice(0, 1);
|
|
68
|
+
const subpathParts = scoped ? parts.slice(2) : parts.slice(1);
|
|
69
|
+
if (!validPackageParts(packageParts, scoped)
|
|
70
|
+
|| hasInvalidSubpath(subpathParts)) return undefined;
|
|
71
|
+
return {
|
|
72
|
+
packageName: packageParts.join('/'),
|
|
73
|
+
moduleSubpath: subpathParts.length > 0
|
|
74
|
+
? `./${subpathParts.join('/')}`
|
|
75
|
+
: '.',
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function moduleFields(specifier: string): Pick<
|
|
80
|
+
SymbolImportBinding,
|
|
81
|
+
'moduleKind' | 'requestedPackageName' | 'requestedModuleSubpath'
|
|
82
|
+
> | undefined {
|
|
83
|
+
if (specifier.startsWith('.')) return {
|
|
84
|
+
moduleKind: 'relative',
|
|
85
|
+
requestedPackageName: null,
|
|
86
|
+
requestedModuleSubpath: null,
|
|
87
|
+
};
|
|
88
|
+
const request = packageModuleRequest(specifier);
|
|
89
|
+
return request ? {
|
|
90
|
+
moduleKind: 'package',
|
|
91
|
+
requestedPackageName: request.packageName,
|
|
92
|
+
requestedModuleSubpath: request.moduleSubpath,
|
|
93
|
+
} : undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function binding(
|
|
97
|
+
specifier: string,
|
|
98
|
+
bindingKind: SymbolImportBindingKind,
|
|
99
|
+
localName: string,
|
|
100
|
+
importedName: string | null,
|
|
101
|
+
typeOnly: boolean,
|
|
102
|
+
site: ts.Identifier,
|
|
103
|
+
): SymbolImportBinding | undefined {
|
|
104
|
+
const module = moduleFields(specifier);
|
|
105
|
+
return module ? {
|
|
106
|
+
version: 1,
|
|
107
|
+
...module,
|
|
108
|
+
bindingKind,
|
|
109
|
+
localName,
|
|
110
|
+
importedName,
|
|
111
|
+
rawModuleSpecifier: specifier,
|
|
112
|
+
typeOnly,
|
|
113
|
+
bindingSiteStartOffset: site.getStart(site.getSourceFile()),
|
|
114
|
+
bindingSiteEndOffset: site.getEnd(),
|
|
115
|
+
} : undefined;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function esmBindings(node: ts.ImportDeclaration): SymbolImportBinding[] {
|
|
119
|
+
if (!ts.isStringLiteralLike(node.moduleSpecifier)) return [];
|
|
120
|
+
const specifier = node.moduleSpecifier.text;
|
|
121
|
+
const clause = node.importClause;
|
|
122
|
+
if (!clause) return [];
|
|
123
|
+
const bindings: SymbolImportBinding[] = [];
|
|
124
|
+
if (clause.name) {
|
|
125
|
+
const value = binding(
|
|
126
|
+
specifier, 'esm_default', clause.name.text, 'default', clause.isTypeOnly,
|
|
127
|
+
clause.name,
|
|
128
|
+
);
|
|
129
|
+
if (value) bindings.push(value);
|
|
130
|
+
}
|
|
131
|
+
const named = clause.namedBindings;
|
|
132
|
+
if (named && ts.isNamespaceImport(named)) {
|
|
133
|
+
const value = binding(
|
|
134
|
+
specifier, 'esm_namespace', named.name.text, null, clause.isTypeOnly,
|
|
135
|
+
named.name,
|
|
136
|
+
);
|
|
137
|
+
if (value) bindings.push(value);
|
|
138
|
+
}
|
|
139
|
+
if (named && ts.isNamedImports(named))
|
|
140
|
+
bindings.push(...esmNamedBindings(specifier, clause.isTypeOnly, named));
|
|
141
|
+
return bindings;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function esmNamedBindings(
|
|
145
|
+
specifier: string,
|
|
146
|
+
clauseTypeOnly: boolean,
|
|
147
|
+
named: ts.NamedImports,
|
|
148
|
+
): SymbolImportBinding[] {
|
|
149
|
+
return named.elements.flatMap((element) => {
|
|
150
|
+
const value = binding(
|
|
151
|
+
specifier,
|
|
152
|
+
'esm_named',
|
|
153
|
+
element.name.text,
|
|
154
|
+
element.propertyName?.text ?? element.name.text,
|
|
155
|
+
clauseTypeOnly || element.isTypeOnly,
|
|
156
|
+
element.name,
|
|
157
|
+
);
|
|
158
|
+
return value ? [value] : [];
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function requireSpecifier(
|
|
163
|
+
expression: ts.Expression | undefined,
|
|
164
|
+
): string | undefined {
|
|
165
|
+
if (!expression || !ts.isCallExpression(expression)
|
|
166
|
+
|| !ts.isIdentifier(expression.expression)
|
|
167
|
+
|| expression.expression.text !== 'require'
|
|
168
|
+
|| lexicalIdentifierDeclaration(expression.expression)
|
|
169
|
+
|| expression.arguments.length !== 1) return undefined;
|
|
170
|
+
const [argument] = expression.arguments;
|
|
171
|
+
return argument && ts.isStringLiteralLike(argument)
|
|
172
|
+
? argument.text
|
|
173
|
+
: undefined;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function cjsBindingElement(
|
|
177
|
+
specifier: string,
|
|
178
|
+
element: ts.BindingElement,
|
|
179
|
+
): SymbolImportBinding[] {
|
|
180
|
+
if (element.dotDotDotToken || !ts.isIdentifier(element.name)
|
|
181
|
+
|| (element.propertyName
|
|
182
|
+
&& !ts.isIdentifier(element.propertyName)
|
|
183
|
+
&& !ts.isStringLiteralLike(element.propertyName))) return [];
|
|
184
|
+
const importedName = element.propertyName
|
|
185
|
+
? element.propertyName.text
|
|
186
|
+
: element.name.text;
|
|
187
|
+
const value = binding(
|
|
188
|
+
specifier, 'cjs_destructured', element.name.text, importedName, false,
|
|
189
|
+
element.name,
|
|
190
|
+
);
|
|
191
|
+
return value ? [value] : [];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function cjsBindings(
|
|
195
|
+
declaration: ts.VariableDeclaration,
|
|
196
|
+
): SymbolImportBinding[] {
|
|
197
|
+
const specifier = requireSpecifier(declaration.initializer);
|
|
198
|
+
if (!specifier) return [];
|
|
199
|
+
if (ts.isIdentifier(declaration.name)) {
|
|
200
|
+
const value = binding(
|
|
201
|
+
specifier, 'cjs_namespace', declaration.name.text, null, false,
|
|
202
|
+
declaration.name,
|
|
203
|
+
);
|
|
204
|
+
return value ? [value] : [];
|
|
205
|
+
}
|
|
206
|
+
if (!ts.isObjectBindingPattern(declaration.name)) return [];
|
|
207
|
+
return declaration.name.elements.flatMap((element) =>
|
|
208
|
+
cjsBindingElement(specifier, element));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function importEqualsBinding(
|
|
212
|
+
statement: ts.ImportEqualsDeclaration,
|
|
213
|
+
): SymbolImportBinding[] {
|
|
214
|
+
const reference = statement.moduleReference;
|
|
215
|
+
if (!ts.isExternalModuleReference(reference)
|
|
216
|
+
|| !reference.expression
|
|
217
|
+
|| !ts.isStringLiteralLike(reference.expression)) return [];
|
|
218
|
+
const value = binding(
|
|
219
|
+
reference.expression.text,
|
|
220
|
+
'cjs_namespace',
|
|
221
|
+
statement.name.text,
|
|
222
|
+
null,
|
|
223
|
+
statement.isTypeOnly,
|
|
224
|
+
statement.name,
|
|
225
|
+
);
|
|
226
|
+
return value ? [value] : [];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function compareBinary(left: string, right: string): number {
|
|
230
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function bindingKey(value: SymbolImportBinding): string {
|
|
234
|
+
return [
|
|
235
|
+
value.localName,
|
|
236
|
+
value.rawModuleSpecifier,
|
|
237
|
+
value.bindingKind,
|
|
238
|
+
value.importedName ?? '',
|
|
239
|
+
String(value.bindingSiteStartOffset).padStart(12, '0'),
|
|
240
|
+
String(value.bindingSiteEndOffset).padStart(12, '0'),
|
|
241
|
+
].join('\0');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function collectNestedCjsBindings(
|
|
245
|
+
source: ts.SourceFile,
|
|
246
|
+
): SymbolImportBinding[] {
|
|
247
|
+
const bindings: SymbolImportBinding[] = [];
|
|
248
|
+
const visit = (node: ts.Node): void => {
|
|
249
|
+
if (ts.isVariableStatement(node)
|
|
250
|
+
&& (node.declarationList.flags & ts.NodeFlags.Const) !== 0)
|
|
251
|
+
for (const declaration of node.declarationList.declarations)
|
|
252
|
+
bindings.push(...cjsBindings(declaration));
|
|
253
|
+
ts.forEachChild(node, visit);
|
|
254
|
+
};
|
|
255
|
+
visit(source);
|
|
256
|
+
return bindings;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function collectSymbolImportBindings(
|
|
260
|
+
source: ts.SourceFile,
|
|
261
|
+
): SymbolImportBinding[] {
|
|
262
|
+
const bindings = collectNestedCjsBindings(source);
|
|
263
|
+
for (const statement of source.statements) {
|
|
264
|
+
if (ts.isImportDeclaration(statement))
|
|
265
|
+
bindings.push(...esmBindings(statement));
|
|
266
|
+
if (ts.isImportEqualsDeclaration(statement))
|
|
267
|
+
bindings.push(...importEqualsBinding(statement));
|
|
268
|
+
}
|
|
269
|
+
return bindings.sort((left, right) =>
|
|
270
|
+
compareBinary(bindingKey(left), bindingKey(right)));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function matchingBinding(
|
|
274
|
+
bindings: readonly SymbolImportBinding[],
|
|
275
|
+
identifier: ts.Identifier,
|
|
276
|
+
): SymbolImportBinding | undefined {
|
|
277
|
+
const matches = bindings.filter((value) =>
|
|
278
|
+
value.localName === identifier.text
|
|
279
|
+
&& identifierMatchesBinding(identifier, value));
|
|
280
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const scopeDeclarationCache = new WeakMap<ts.Node, ts.Identifier[]>();
|
|
284
|
+
|
|
285
|
+
function bindingIdentifiers(name: ts.BindingName): ts.Identifier[] {
|
|
286
|
+
if (ts.isIdentifier(name)) return [name];
|
|
287
|
+
return name.elements.flatMap((element) =>
|
|
288
|
+
ts.isBindingElement(element) ? bindingIdentifiers(element.name) : []);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function importIdentifiers(statement: ts.Statement): ts.Identifier[] {
|
|
292
|
+
if (ts.isImportEqualsDeclaration(statement)) return [statement.name];
|
|
293
|
+
if (!ts.isImportDeclaration(statement)) return [];
|
|
294
|
+
const clause = statement.importClause;
|
|
295
|
+
const values = clause?.name ? [clause.name] : [];
|
|
296
|
+
const named = clause?.namedBindings;
|
|
297
|
+
if (named && ts.isNamespaceImport(named)) values.push(named.name);
|
|
298
|
+
if (named && ts.isNamedImports(named))
|
|
299
|
+
values.push(...named.elements.map((element) => element.name));
|
|
300
|
+
return values;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function statementIdentifiers(
|
|
304
|
+
statement: ts.Statement,
|
|
305
|
+
includeVar: boolean,
|
|
306
|
+
): ts.Identifier[] {
|
|
307
|
+
if (ts.isVariableStatement(statement)) {
|
|
308
|
+
const blockScoped = (statement.declarationList.flags
|
|
309
|
+
& ts.NodeFlags.BlockScoped) !== 0;
|
|
310
|
+
return includeVar || blockScoped
|
|
311
|
+
? statement.declarationList.declarations.flatMap((declaration) =>
|
|
312
|
+
bindingIdentifiers(declaration.name))
|
|
313
|
+
: [];
|
|
314
|
+
}
|
|
315
|
+
if ((ts.isFunctionDeclaration(statement)
|
|
316
|
+
|| ts.isClassDeclaration(statement)
|
|
317
|
+
|| ts.isEnumDeclaration(statement)) && statement.name)
|
|
318
|
+
return [statement.name];
|
|
319
|
+
return includeVar ? importIdentifiers(statement) : [];
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function varIdentifiers(scope: ts.FunctionLikeDeclaration): ts.Identifier[] {
|
|
323
|
+
const values: ts.Identifier[] = [];
|
|
324
|
+
const visit = (node: ts.Node): void => {
|
|
325
|
+
if (node !== scope.body && ts.isFunctionLike(node)) return;
|
|
326
|
+
if (ts.isVariableDeclaration(node)
|
|
327
|
+
&& ts.isVariableDeclarationList(node.parent)
|
|
328
|
+
&& (node.parent.flags & ts.NodeFlags.BlockScoped) === 0)
|
|
329
|
+
values.push(...bindingIdentifiers(node.name));
|
|
330
|
+
ts.forEachChild(node, visit);
|
|
331
|
+
};
|
|
332
|
+
if (scope.body) visit(scope.body);
|
|
333
|
+
return values;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function functionIdentifiers(scope: ts.FunctionLikeDeclaration): ts.Identifier[] {
|
|
337
|
+
const values = scope.parameters.flatMap((parameter) =>
|
|
338
|
+
bindingIdentifiers(parameter.name));
|
|
339
|
+
if ((ts.isFunctionDeclaration(scope)
|
|
340
|
+
|| ts.isFunctionExpression(scope)) && scope.name)
|
|
341
|
+
values.push(scope.name);
|
|
342
|
+
return [...values, ...varIdentifiers(scope)];
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function loopIdentifiers(node: ts.Node): ts.Identifier[] {
|
|
346
|
+
const initializer = ts.isForStatement(node)
|
|
347
|
+
? node.initializer
|
|
348
|
+
: ts.isForInStatement(node) || ts.isForOfStatement(node)
|
|
349
|
+
? node.initializer
|
|
350
|
+
: undefined;
|
|
351
|
+
return initializer && ts.isVariableDeclarationList(initializer)
|
|
352
|
+
&& (initializer.flags & ts.NodeFlags.BlockScoped) !== 0
|
|
353
|
+
? initializer.declarations.flatMap((declaration) =>
|
|
354
|
+
bindingIdentifiers(declaration.name))
|
|
355
|
+
: [];
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function lexicalFunctionScope(
|
|
359
|
+
node: ts.Node,
|
|
360
|
+
): node is ts.FunctionLikeDeclaration {
|
|
361
|
+
return ts.isFunctionDeclaration(node)
|
|
362
|
+
|| ts.isFunctionExpression(node)
|
|
363
|
+
|| ts.isArrowFunction(node)
|
|
364
|
+
|| ts.isMethodDeclaration(node)
|
|
365
|
+
|| ts.isGetAccessorDeclaration(node)
|
|
366
|
+
|| ts.isSetAccessorDeclaration(node)
|
|
367
|
+
|| ts.isConstructorDeclaration(node);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function uncachedScopeIdentifiers(node: ts.Node): ts.Identifier[] {
|
|
371
|
+
if (ts.isSourceFile(node))
|
|
372
|
+
return node.statements.flatMap((statement) =>
|
|
373
|
+
statementIdentifiers(statement, true));
|
|
374
|
+
if (ts.isClassExpression(node) && node.name) return [node.name];
|
|
375
|
+
if (ts.isBlock(node) || ts.isModuleBlock(node))
|
|
376
|
+
return node.statements.flatMap((statement) =>
|
|
377
|
+
statementIdentifiers(statement, false));
|
|
378
|
+
if (ts.isCaseBlock(node))
|
|
379
|
+
return node.clauses.flatMap((clause) =>
|
|
380
|
+
clause.statements.flatMap((statement) =>
|
|
381
|
+
statementIdentifiers(statement, false)));
|
|
382
|
+
if (lexicalFunctionScope(node)) return functionIdentifiers(node);
|
|
383
|
+
if (ts.isCatchClause(node) && node.variableDeclaration)
|
|
384
|
+
return bindingIdentifiers(node.variableDeclaration.name);
|
|
385
|
+
return loopIdentifiers(node);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function scopeIdentifiers(node: ts.Node): ts.Identifier[] {
|
|
389
|
+
const cached = scopeDeclarationCache.get(node);
|
|
390
|
+
if (cached) return cached;
|
|
391
|
+
const values = uncachedScopeIdentifiers(node);
|
|
392
|
+
scopeDeclarationCache.set(node, values);
|
|
393
|
+
return values;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export function lexicalIdentifierDeclarations(
|
|
397
|
+
identifier: ts.Identifier,
|
|
398
|
+
): ts.Identifier[] {
|
|
399
|
+
let current: ts.Node | undefined = identifier.parent;
|
|
400
|
+
while (current) {
|
|
401
|
+
const matches = scopeIdentifiers(current).filter((candidate) =>
|
|
402
|
+
candidate.text === identifier.text);
|
|
403
|
+
if (matches.length > 0) return matches;
|
|
404
|
+
current = current.parent;
|
|
405
|
+
}
|
|
406
|
+
return [];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export function lexicalIdentifierDeclaration(
|
|
410
|
+
identifier: ts.Identifier,
|
|
411
|
+
): ts.Identifier | undefined {
|
|
412
|
+
const matches = lexicalIdentifierDeclarations(identifier);
|
|
413
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export function identifierMatchesDeclaration(
|
|
417
|
+
identifier: ts.Identifier,
|
|
418
|
+
startOffset: number,
|
|
419
|
+
endOffset: number,
|
|
420
|
+
): boolean {
|
|
421
|
+
const declaration = lexicalIdentifierDeclaration(identifier);
|
|
422
|
+
return declaration?.getStart(identifier.getSourceFile()) === startOffset
|
|
423
|
+
&& declaration.getEnd() === endOffset;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function identifierMatchesBinding(
|
|
427
|
+
identifier: ts.Identifier,
|
|
428
|
+
value: SymbolImportBinding,
|
|
429
|
+
): boolean {
|
|
430
|
+
return identifierMatchesDeclaration(
|
|
431
|
+
identifier,
|
|
432
|
+
value.bindingSiteStartOffset,
|
|
433
|
+
value.bindingSiteEndOffset,
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export function derivedMemberImportReference(
|
|
438
|
+
value: SymbolImportBinding,
|
|
439
|
+
member: string,
|
|
440
|
+
): SymbolImportReference | undefined {
|
|
441
|
+
const namespace = value.bindingKind === 'esm_namespace'
|
|
442
|
+
|| value.bindingKind === 'cjs_namespace';
|
|
443
|
+
if (!member || (!namespace && value.importedName === null)) return undefined;
|
|
444
|
+
const defaultBinding = value.bindingKind === 'esm_default';
|
|
445
|
+
return {
|
|
446
|
+
...value,
|
|
447
|
+
referenceShape: namespace
|
|
448
|
+
? 'namespace_member'
|
|
449
|
+
: defaultBinding ? 'default_member' : 'static_member',
|
|
450
|
+
referencedMemberName: member,
|
|
451
|
+
requestedPublicName: namespace
|
|
452
|
+
? member
|
|
453
|
+
: `${value.importedName}.${member}`,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function identifierReference(
|
|
458
|
+
expression: ts.Identifier,
|
|
459
|
+
bindings: readonly SymbolImportBinding[],
|
|
460
|
+
): SymbolImportReference | undefined {
|
|
461
|
+
const value = matchingBinding(bindings, expression);
|
|
462
|
+
if (!value || value.importedName === null) return undefined;
|
|
463
|
+
return {
|
|
464
|
+
...value,
|
|
465
|
+
referenceShape: 'identifier',
|
|
466
|
+
referencedMemberName: null,
|
|
467
|
+
requestedPublicName: value.importedName,
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function memberReference(
|
|
472
|
+
expression: ts.PropertyAccessExpression,
|
|
473
|
+
bindings: readonly SymbolImportBinding[],
|
|
474
|
+
): SymbolImportReference | undefined {
|
|
475
|
+
if (expression.questionDotToken || !ts.isIdentifier(expression.expression)
|
|
476
|
+
|| !ts.isIdentifier(expression.name)) return undefined;
|
|
477
|
+
const value = matchingBinding(bindings, expression.expression);
|
|
478
|
+
if (!value) return undefined;
|
|
479
|
+
const member = expression.name.text;
|
|
480
|
+
return derivedMemberImportReference(value, member);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function accessorMemberReference(
|
|
484
|
+
expression: ts.PropertyAccessExpression,
|
|
485
|
+
bindings: readonly SymbolImportBinding[],
|
|
486
|
+
): SymbolImportReference | undefined {
|
|
487
|
+
const receiver = expression.expression;
|
|
488
|
+
if (!ts.isCallExpression(receiver)
|
|
489
|
+
|| receiver.arguments.length !== 0
|
|
490
|
+
|| !ts.isPropertyAccessExpression(receiver.expression)
|
|
491
|
+
|| !ts.isIdentifier(receiver.expression.expression)
|
|
492
|
+
|| receiver.expression.questionDotToken
|
|
493
|
+
|| expression.questionDotToken) return undefined;
|
|
494
|
+
const value = matchingBinding(
|
|
495
|
+
bindings, receiver.expression.expression,
|
|
496
|
+
);
|
|
497
|
+
if (!value || value.importedName === null)
|
|
498
|
+
return undefined;
|
|
499
|
+
return {
|
|
500
|
+
...value,
|
|
501
|
+
referenceShape: 'static_member',
|
|
502
|
+
referencedMemberName: expression.name.text,
|
|
503
|
+
requestedPublicName: `${value.importedName}.${expression.name.text}`,
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
export function symbolImportReference(
|
|
508
|
+
expression: ts.Expression,
|
|
509
|
+
bindings: readonly SymbolImportBinding[],
|
|
510
|
+
): SymbolImportReference | undefined {
|
|
511
|
+
if (ts.isIdentifier(expression))
|
|
512
|
+
return identifierReference(expression, bindings);
|
|
513
|
+
if (!ts.isPropertyAccessExpression(expression)) return undefined;
|
|
514
|
+
return memberReference(expression, bindings)
|
|
515
|
+
?? accessorMemberReference(expression, bindings);
|
|
516
|
+
}
|