@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.
Files changed (101) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +27 -9
  3. package/TECHNICAL-NOTE.md +36 -0
  4. package/dist/chunk-3N3B5KHV.js +19596 -0
  5. package/dist/chunk-3N3B5KHV.js.map +1 -0
  6. package/dist/cli.js +2645 -521
  7. package/dist/cli.js.map +1 -1
  8. package/dist/index.d.ts +67 -2
  9. package/dist/index.js +1 -1
  10. package/package.json +1 -1
  11. package/src/cli/001-index-summary.ts +22 -0
  12. package/src/cli/003-doctor-package-resolution.ts +68 -0
  13. package/src/cli/doctor.ts +25 -14
  14. package/src/cli.ts +151 -87
  15. package/src/db/000-call-fact-repository.ts +499 -340
  16. package/src/db/001-fact-lifecycle.ts +60 -30
  17. package/src/db/002-fact-json-inventory.ts +169 -0
  18. package/src/db/003-current-fact-semantics.ts +699 -0
  19. package/src/db/004-package-target-invalidation.ts +183 -0
  20. package/src/db/005-schema-structure.ts +201 -0
  21. package/src/db/006-relative-symbol-resolution.ts +464 -0
  22. package/src/db/007-package-fact-semantics.ts +573 -0
  23. package/src/db/008-relative-fact-semantics.ts +210 -0
  24. package/src/db/009-binding-fact-semantics.ts +352 -0
  25. package/src/db/010-package-symbol-surface-semantics.ts +320 -0
  26. package/src/db/011-symbol-call-semantics.ts +144 -0
  27. package/src/db/012-binding-reference-proof.ts +268 -0
  28. package/src/db/013-index-publication-failure.ts +91 -0
  29. package/src/db/014-binding-helper-provenance.ts +17 -0
  30. package/src/db/migrations.ts +16 -3
  31. package/src/db/repositories.ts +130 -6
  32. package/src/db/schema.ts +4 -2
  33. package/src/index.ts +12 -0
  34. package/src/indexer/cds-extension-resolver.ts +27 -3
  35. package/src/indexer/repository-indexer.ts +135 -13
  36. package/src/indexer/workspace-indexer.ts +237 -34
  37. package/src/linker/003-package-import-symbol-resolver.ts +363 -131
  38. package/src/linker/004-event-subscription-handler-linker.ts +34 -11
  39. package/src/linker/005-odata-path-structure.ts +371 -0
  40. package/src/linker/006-event-template-link.ts +72 -0
  41. package/src/linker/007-call-edge-insertion.ts +568 -0
  42. package/src/linker/cross-repo-linker.ts +4 -166
  43. package/src/linker/odata-path-normalizer.ts +273 -180
  44. package/src/linker/service-resolver.ts +197 -77
  45. package/src/parsers/000-direct-query-execution.ts +11 -0
  46. package/src/parsers/002-symbol-import-bindings.ts +516 -0
  47. package/src/parsers/003-package-public-surface.ts +661 -0
  48. package/src/parsers/004-fact-identity.ts +108 -0
  49. package/src/parsers/005-event-subscription-facts.ts +281 -0
  50. package/src/parsers/006-binding-identity.ts +348 -0
  51. package/src/parsers/007-source-fact-reconciliation.ts +105 -0
  52. package/src/parsers/008-package-surface-publication.ts +82 -0
  53. package/src/parsers/009-symbol-call-facts.ts +528 -0
  54. package/src/parsers/010-package-public-surface-analysis.ts +352 -0
  55. package/src/parsers/011-binding-lexical-scope.ts +583 -0
  56. package/src/parsers/012-package-fact-contract.ts +306 -0
  57. package/src/parsers/013-executable-body-eligibility.ts +35 -0
  58. package/src/parsers/014-service-binding-helper-flow.ts +306 -0
  59. package/src/parsers/015-service-binding-collector.ts +693 -0
  60. package/src/parsers/016-local-symbol-reference.ts +261 -0
  61. package/src/parsers/017-symbol-derived-contexts.ts +268 -0
  62. package/src/parsers/018-package-commonjs-syntax.ts +142 -0
  63. package/src/parsers/019-binding-assignment-targets.ts +76 -0
  64. package/src/parsers/020-stable-local-value.ts +217 -0
  65. package/src/parsers/021-binding-visibility.ts +168 -0
  66. package/src/parsers/022-outbound-expression-analysis.ts +700 -0
  67. package/src/parsers/023-outbound-call-classifier.ts +692 -0
  68. package/src/parsers/operation-path-analysis.ts +6 -1
  69. package/src/parsers/outbound-call-parser.ts +162 -512
  70. package/src/parsers/package-json-parser.ts +45 -3
  71. package/src/parsers/service-binding-parser-helpers.ts +86 -15
  72. package/src/parsers/service-binding-parser.ts +147 -597
  73. package/src/parsers/symbol-parser.ts +513 -352
  74. package/src/trace/002-trace-diagnostics.ts +36 -1
  75. package/src/trace/007-implementation-start-diagnostic.ts +1 -0
  76. package/src/trace/011-event-subscriber-traversal.ts +100 -8
  77. package/src/trace/013-trace-root-scopes.ts +2 -3
  78. package/src/trace/014-compact-contract.ts +6 -0
  79. package/src/trace/015-trace-edge-recorder.ts +61 -4
  80. package/src/trace/016-compact-projector.ts +15 -17
  81. package/src/trace/019-trace-edge-semantics.ts +6 -10
  82. package/src/trace/020-compact-field-projection.ts +122 -38
  83. package/src/trace/021-compact-decision-normalization.ts +171 -0
  84. package/src/trace/022-trace-fact-preflight.ts +21 -0
  85. package/src/trace/023-nested-event-scopes.ts +23 -0
  86. package/src/trace/024-compact-observation-decision.ts +81 -0
  87. package/src/trace/025-trace-implementation-scope.ts +123 -0
  88. package/src/trace/026-trace-start-scope.ts +336 -0
  89. package/src/trace/027-trace-scope-execution.ts +566 -0
  90. package/src/trace/028-trace-operation-execution.ts +336 -0
  91. package/src/trace/029-trace-start-implementation.ts +172 -0
  92. package/src/trace/030-event-runtime-resolution.ts +151 -0
  93. package/src/trace/031-local-call-expansion.ts +37 -0
  94. package/src/trace/implementation-hints.ts +9 -6
  95. package/src/trace/selectors.ts +1 -0
  96. package/src/trace/trace-engine.ts +122 -624
  97. package/src/types.ts +57 -0
  98. package/src/utils/001-placeholders.ts +188 -10
  99. package/src/version.ts +1 -1
  100. package/dist/chunk-ZQABU7MR.js +0 -12151
  101. 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
+ }