@saptools/service-flow 0.1.69 → 0.1.72

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 (144) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +9 -5
  3. package/TECHNICAL-NOTE.md +17 -0
  4. package/dist/{chunk-3N3B5KHV.js → chunk-Z6D433R5.js} +8766 -6546
  5. package/dist/chunk-Z6D433R5.js.map +1 -0
  6. package/dist/cli.js +703 -160
  7. package/dist/cli.js.map +1 -1
  8. package/dist/index.d.ts +53 -14
  9. package/dist/index.js +2 -23
  10. package/dist/index.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/cli/doctor-event-quality.ts +371 -0
  13. package/src/cli/{002-doctor-lifecycle.ts → doctor-lifecycle.ts} +1 -1
  14. package/src/cli/{001-doctor-projection.ts → doctor-projection.ts} +1 -1
  15. package/src/cli/doctor.ts +9 -11
  16. package/src/cli.ts +6 -6
  17. package/src/db/{009-binding-fact-semantics.ts → binding-fact-semantics.ts} +2 -2
  18. package/src/db/{000-call-fact-repository.ts → call-fact-repository.ts} +12 -9
  19. package/src/db/{003-current-fact-semantics.ts → current-fact-semantics.ts} +8 -8
  20. package/src/db/event-fact-semantics.ts +347 -0
  21. package/src/db/event-surface-invalidation.ts +38 -0
  22. package/src/db/{002-fact-json-inventory.ts → fact-json-inventory.ts} +16 -0
  23. package/src/db/{001-fact-lifecycle.ts → fact-lifecycle.ts} +3 -3
  24. package/src/db/migrations.ts +12 -1
  25. package/src/db/{007-package-fact-semantics.ts → package-fact-semantics.ts} +6 -6
  26. package/src/db/{010-package-symbol-surface-semantics.ts → package-symbol-surface-semantics.ts} +2 -2
  27. package/src/db/{004-package-target-invalidation.ts → package-target-invalidation.ts} +80 -1
  28. package/src/db/{008-relative-fact-semantics.ts → relative-fact-semantics.ts} +3 -3
  29. package/src/db/{006-relative-symbol-resolution.ts → relative-symbol-resolution.ts} +1 -1
  30. package/src/db/repositories.ts +31 -5
  31. package/src/db/{005-schema-structure.ts → schema-structure.ts} +41 -1
  32. package/src/db/schema.ts +6 -2
  33. package/src/db/{011-symbol-call-semantics.ts → symbol-call-semantics.ts} +1 -1
  34. package/src/index.ts +3 -3
  35. package/src/indexer/repository-indexer.ts +50 -11
  36. package/src/indexer/workspace-indexer.ts +3 -3
  37. package/src/linker/{007-call-edge-insertion.ts → call-edge-insertion.ts} +2 -2
  38. package/src/linker/{002-call-evidence.ts → call-evidence.ts} +2 -2
  39. package/src/linker/cross-repo-linker.ts +30 -8
  40. package/src/linker/dynamic-edge-resolver.ts +1 -1
  41. package/src/linker/event-environment-link.ts +211 -0
  42. package/src/linker/event-shape-candidate-linker.ts +161 -0
  43. package/src/linker/{004-event-subscription-handler-linker.ts → event-subscription-handler-linker.ts} +124 -20
  44. package/src/linker/{006-event-template-link.ts → event-template-link.ts} +40 -6
  45. package/src/linker/external-http-target.ts +1 -1
  46. package/src/linker/helper-package-linker.ts +1 -1
  47. package/src/linker/{000-implementation-candidates.ts → implementation-candidates.ts} +1 -1
  48. package/src/linker/{001-implementation-evidence-projection.ts → implementation-evidence-projection.ts} +1 -1
  49. package/src/linker/odata-path-normalizer.ts +1 -1
  50. package/src/linker/{005-odata-path-structure.ts → odata-path-structure.ts} +1 -1
  51. package/src/linker/package-event-constant-resolver.ts +298 -0
  52. package/src/linker/{003-package-import-symbol-resolver.ts → package-import-symbol-resolver.ts} +3 -3
  53. package/src/linker/service-resolver.ts +2 -2
  54. package/src/output/{001-compact-json-output.ts → compact-json-output.ts} +1 -1
  55. package/src/output/table-output.ts +13 -1
  56. package/src/parsers/{006-binding-identity.ts → binding-identity.ts} +3 -3
  57. package/src/parsers/{011-binding-lexical-scope.ts → binding-lexical-scope.ts} +1 -1
  58. package/src/parsers/{021-binding-visibility.ts → binding-visibility.ts} +1 -1
  59. package/src/parsers/decorator-parser.ts +9 -53
  60. package/src/parsers/environment-declarations.ts +327 -0
  61. package/src/parsers/event-call-analysis.ts +242 -0
  62. package/src/parsers/event-environment-reference.ts +231 -0
  63. package/src/parsers/event-loop-registration.ts +132 -0
  64. package/src/parsers/event-name-import-resolution.ts +243 -0
  65. package/src/parsers/event-receiver-analysis.ts +404 -0
  66. package/src/parsers/{005-event-subscription-facts.ts → event-subscription-facts.ts} +6 -2
  67. package/src/parsers/generated-constants-parser.ts +80 -14
  68. package/src/parsers/{016-local-symbol-reference.ts → local-symbol-reference.ts} +2 -2
  69. package/src/parsers/operation-path-analysis.ts +1 -1
  70. package/src/parsers/{023-outbound-call-classifier.ts → outbound-call-classifier.ts} +30 -127
  71. package/src/parsers/outbound-call-parser.ts +15 -3
  72. package/src/parsers/{022-outbound-expression-analysis.ts → outbound-expression-analysis.ts} +4 -4
  73. package/src/parsers/{018-package-commonjs-syntax.ts → package-commonjs-syntax.ts} +1 -1
  74. package/src/parsers/{012-package-fact-contract.ts → package-fact-contract.ts} +3 -3
  75. package/src/parsers/{010-package-public-surface-analysis.ts → package-public-surface-analysis.ts} +2 -2
  76. package/src/parsers/{003-package-public-surface.ts → package-public-surface.ts} +3 -3
  77. package/src/parsers/{008-package-surface-publication.ts → package-surface-publication.ts} +1 -1
  78. package/src/parsers/{001-query-entity-resolution.ts → query-entity-resolution.ts} +1 -1
  79. package/src/parsers/{015-service-binding-collector.ts → service-binding-collector.ts} +3 -3
  80. package/src/parsers/{014-service-binding-helper-flow.ts → service-binding-helper-flow.ts} +2 -2
  81. package/src/parsers/service-binding-parser-helpers.ts +1 -1
  82. package/src/parsers/service-binding-parser.ts +2 -2
  83. package/src/parsers/{007-source-fact-reconciliation.ts → source-fact-reconciliation.ts} +3 -3
  84. package/src/parsers/{020-stable-local-value.ts → stable-local-value.ts} +32 -11
  85. package/src/parsers/string-constant-lookups.ts +358 -0
  86. package/src/parsers/{009-symbol-call-facts.ts → symbol-call-facts.ts} +3 -3
  87. package/src/parsers/{017-symbol-derived-contexts.ts → symbol-derived-contexts.ts} +2 -2
  88. package/src/parsers/symbol-parser.ts +6 -6
  89. package/src/trace/{021-compact-decision-normalization.ts → compact-decision-normalization.ts} +2 -2
  90. package/src/trace/{020-compact-field-projection.ts → compact-field-projection.ts} +3 -3
  91. package/src/trace/{024-compact-observation-decision.ts → compact-observation-decision.ts} +3 -3
  92. package/src/trace/{016-compact-projector.ts → compact-projector.ts} +4 -4
  93. package/src/trace/{018-compact-trace.ts → compact-trace.ts} +3 -3
  94. package/src/trace/{006-contextual-projection.ts → contextual-projection.ts} +1 -1
  95. package/src/trace/{008-contextual-runtime-state.ts → contextual-runtime-state.ts} +1 -1
  96. package/src/trace/{001-dynamic-identity.ts → dynamic-identity.ts} +2 -2
  97. package/src/trace/{003-dynamic-references.ts → dynamic-references.ts} +2 -2
  98. package/src/trace/dynamic-targets.ts +6 -6
  99. package/src/trace/{030-event-runtime-resolution.ts → event-runtime-resolution.ts} +26 -5
  100. package/src/trace/event-shape-candidate-trace.ts +172 -0
  101. package/src/trace/{011-event-subscriber-traversal.ts → event-subscriber-traversal.ts} +20 -8
  102. package/src/trace/evidence.ts +9 -2
  103. package/src/trace/implementation-hints.ts +2 -2
  104. package/src/trace/{005-implementation-selection.ts → implementation-selection.ts} +2 -2
  105. package/src/trace/{031-local-call-expansion.ts → local-call-expansion.ts} +3 -3
  106. package/src/trace/{009-selected-handler-provenance.ts → selected-handler-provenance.ts} +1 -1
  107. package/src/trace/selectors.ts +1 -1
  108. package/src/trace/{017-trace-context.ts → trace-context.ts} +2 -2
  109. package/src/trace/{015-trace-edge-recorder.ts → trace-edge-recorder.ts} +2 -2
  110. package/src/trace/{019-trace-edge-semantics.ts → trace-edge-semantics.ts} +3 -3
  111. package/src/trace/trace-engine.ts +10 -10
  112. package/src/trace/{022-trace-fact-preflight.ts → trace-fact-preflight.ts} +2 -2
  113. package/src/trace/{025-trace-implementation-scope.ts → trace-implementation-scope.ts} +1 -1
  114. package/src/trace/{028-trace-operation-execution.ts → trace-operation-execution.ts} +10 -10
  115. package/src/trace/{013-trace-root-scopes.ts → trace-root-scopes.ts} +3 -3
  116. package/src/trace/{027-trace-scope-execution.ts → trace-scope-execution.ts} +35 -43
  117. package/src/trace/{029-trace-start-implementation.ts → trace-start-implementation.ts} +7 -7
  118. package/src/trace/{026-trace-start-scope.ts → trace-start-scope.ts} +5 -5
  119. package/src/trace/{010-traversal-scope.ts → traversal-scope.ts} +1 -1
  120. package/src/types.ts +17 -1
  121. package/src/utils/event-skeleton.ts +207 -0
  122. package/src/version.ts +1 -1
  123. package/dist/chunk-3N3B5KHV.js.map +0 -1
  124. /package/src/cli/{000-clean.ts → clean.ts} +0 -0
  125. /package/src/cli/{003-doctor-package-resolution.ts → doctor-package-resolution.ts} +0 -0
  126. /package/src/cli/{001-index-summary.ts → index-summary.ts} +0 -0
  127. /package/src/db/{014-binding-helper-provenance.ts → binding-helper-provenance.ts} +0 -0
  128. /package/src/db/{012-binding-reference-proof.ts → binding-reference-proof.ts} +0 -0
  129. /package/src/db/{013-index-publication-failure.ts → index-publication-failure.ts} +0 -0
  130. /package/src/output/{000-stdout-policy.ts → stdout-policy.ts} +0 -0
  131. /package/src/parsers/{019-binding-assignment-targets.ts → binding-assignment-targets.ts} +0 -0
  132. /package/src/parsers/{000-direct-query-execution.ts → direct-query-execution.ts} +0 -0
  133. /package/src/parsers/{013-executable-body-eligibility.ts → executable-body-eligibility.ts} +0 -0
  134. /package/src/parsers/{004-fact-identity.ts → fact-identity.ts} +0 -0
  135. /package/src/parsers/{002-symbol-import-bindings.ts → symbol-import-bindings.ts} +0 -0
  136. /package/src/trace/{014-compact-contract.ts → compact-contract.ts} +0 -0
  137. /package/src/trace/{004-dynamic-candidate-sources.ts → dynamic-candidate-sources.ts} +0 -0
  138. /package/src/trace/{000-dynamic-target-types.ts → dynamic-target-types.ts} +0 -0
  139. /package/src/trace/{007-implementation-start-diagnostic.ts → implementation-start-diagnostic.ts} +0 -0
  140. /package/src/trace/{023-nested-event-scopes.ts → nested-event-scopes.ts} +0 -0
  141. /package/src/trace/{002-trace-diagnostics.ts → trace-diagnostics.ts} +0 -0
  142. /package/src/trace/{012-trace-graph-lookups.ts → trace-graph-lookups.ts} +0 -0
  143. /package/src/utils/{000-bounded-projection.ts → bounded-projection.ts} +0 -0
  144. /package/src/utils/{001-placeholders.ts → placeholders.ts} +0 -0
@@ -4,18 +4,16 @@ import { classifyODataPathIntent } from '../linker/odata-path-normalizer.js';
4
4
  import type { OutboundCallFact } from '../types.js';
5
5
  import { normalizePath, stripQuotes } from '../utils/path-utils.js';
6
6
  import { summarizeExpression } from '../utils/redaction.js';
7
- import { directQueryBuilderStatement } from './000-direct-query-execution.js';
7
+ import { directQueryBuilderStatement } from './direct-query-execution.js';
8
8
  import {
9
9
  expressionName,
10
10
  queryEntityFromAst,
11
11
  variableInitializers,
12
- } from './001-query-entity-resolution.js';
12
+ } from './query-entity-resolution.js';
13
13
  import {
14
- CDS_LIFECYCLE_EVENTS,
15
14
  calledWrapperNames,
16
15
  collectServiceVariables,
17
16
  externalHttpEvidence,
18
- isSupportedEventReceiver,
19
17
  legacyPathCandidates,
20
18
  lineOf,
21
19
  literalPathSource,
@@ -34,7 +32,18 @@ import {
34
32
  wrapperSpec,
35
33
  type ExpressionResolution,
36
34
  type WrapperSpec,
37
- } from './022-outbound-expression-analysis.js';
35
+ } from './outbound-expression-analysis.js';
36
+ import {
37
+ analyzeEventCall,
38
+ createEventCallAnalysisContext,
39
+ type EventCallAnalysisContext,
40
+ } from './event-call-analysis.js';
41
+ import type {
42
+ ImportedEventNameResolver,
43
+ } from './event-name-import-resolution.js';
44
+ import type {
45
+ EventEnvironmentReferenceResolver,
46
+ } from './event-environment-reference.js';
38
47
  import {
39
48
  analyzeOperationPath,
40
49
  operationPathExpression,
@@ -47,6 +56,11 @@ export interface ClassifiedOutboundCall {
47
56
  node: ts.CallExpression;
48
57
  }
49
58
 
59
+ export interface OutboundClassificationOptions {
60
+ importedEventNameResolver?: ImportedEventNameResolver;
61
+ eventEnvironmentReferenceResolver?: EventEnvironmentReferenceResolver;
62
+ }
63
+
50
64
  function namedFunctionLike(
51
65
  node: ts.Node,
52
66
  ): { name: string; fn: ts.FunctionLikeDeclaration } | undefined {
@@ -79,122 +93,6 @@ function collectWrapperSpecs(
79
93
  return specs;
80
94
  }
81
95
 
82
- interface EventCallClassification {
83
- fact: Pick<OutboundCallFact,
84
- 'callType' | 'serviceVariableName' | 'eventNameExpr'
85
- | 'confidence' | 'unresolvedReason'>;
86
- evidence: Record<string, unknown>;
87
- }
88
-
89
- interface EventReceiver {
90
- effectiveReceiver: string;
91
- receiver?: string;
92
- rootReceiver?: string;
93
- }
94
-
95
- function eventReceiver(
96
- expression: ts.PropertyAccessExpression,
97
- serviceVariables: Set<string>,
98
- ): EventReceiver | undefined {
99
- const receiver = receiverName(expression.expression);
100
- const rootReceiver = rootReceiverName(expression.expression);
101
- if (!isSupportedEventReceiver(receiver, rootReceiver, serviceVariables))
102
- return undefined;
103
- const effectiveReceiver = rootReceiver ?? receiver;
104
- return effectiveReceiver
105
- ? { receiver, rootReceiver, effectiveReceiver } : undefined;
106
- }
107
-
108
- function eventUnresolvedReason(
109
- resolved: ExpressionResolution,
110
- ): string | undefined {
111
- if (resolved.status === 'static') return undefined;
112
- return resolved.value !== undefined && resolved.placeholderKeys.length > 0
113
- ? 'dynamic_event_name_identifier'
114
- : 'dynamic_event_name_unsupported_expression';
115
- }
116
-
117
- function eventConfidence(reason: string | undefined): number {
118
- if (!reason) return 0.8;
119
- return reason === 'dynamic_event_name_identifier' ? 0.6 : 0.3;
120
- }
121
-
122
- function eventClassificationEvidence(
123
- expression: ts.PropertyAccessExpression,
124
- receiver: EventReceiver,
125
- resolved: ExpressionResolution,
126
- ): Record<string, unknown> {
127
- return {
128
- receiver: receiver.receiver,
129
- rootReceiver: receiver.rootReceiver,
130
- classifier: expression.name.text === 'on'
131
- ? 'cap_service_event_subscription' : 'cap_service_event_emit',
132
- receiverClassification: 'cap_evidence',
133
- ...(resolved.status === 'static' ? {} : {
134
- eventNameStatus: resolved.status,
135
- eventNameSourceKind: resolved.sourceKind,
136
- eventNamePlaceholderKeys: resolved.placeholderKeys,
137
- }),
138
- };
139
- }
140
-
141
- interface EventNameState {
142
- eventName: string;
143
- resolved: ExpressionResolution;
144
- unresolvedReason?: string;
145
- }
146
-
147
- function eventNameState(node: ts.CallExpression): EventNameState | undefined {
148
- const expression = node.arguments[0];
149
- const resolved = resolveExpression(expression, node, 'operation_path');
150
- let eventName = resolved.value;
151
- if (eventName === undefined) eventName = resolved.rawExpression;
152
- if (eventName === undefined && expression)
153
- eventName = expression.getText(node.getSourceFile());
154
- if (!eventName) return undefined;
155
- return {
156
- eventName,
157
- resolved,
158
- unresolvedReason: eventUnresolvedReason(resolved),
159
- };
160
- }
161
-
162
- function excludedEventName(
163
- expression: ts.PropertyAccessExpression,
164
- receiver: EventReceiver,
165
- state: EventNameState,
166
- ): boolean {
167
- if (state.resolved.status !== 'static') return false;
168
- if (receiver.effectiveReceiver === 'cds'
169
- && CDS_LIFECYCLE_EVENTS.has(state.eventName)) return true;
170
- return expression.name.text === 'on' && state.eventName === 'error';
171
- }
172
-
173
- function eventCallClassification(
174
- node: ts.CallExpression,
175
- expression: ts.PropertyAccessExpression,
176
- serviceVariables: Set<string>,
177
- ): EventCallClassification | undefined {
178
- const receiver = eventReceiver(expression, serviceVariables);
179
- if (!receiver) return undefined;
180
- const state = eventNameState(node);
181
- if (!state || excludedEventName(expression, receiver, state))
182
- return undefined;
183
- return {
184
- fact: {
185
- callType: expression.name.text === 'on'
186
- ? 'async_subscribe' : 'async_emit',
187
- serviceVariableName: receiver.effectiveReceiver,
188
- eventNameExpr: state.eventName,
189
- confidence: eventConfidence(state.unresolvedReason),
190
- unresolvedReason: state.unresolvedReason,
191
- },
192
- evidence: eventClassificationEvidence(
193
- expression, receiver, state.resolved,
194
- ),
195
- };
196
- }
197
-
198
96
  type OutboundFactInput = Omit<
199
97
  OutboundCallFact, 'sourceFile' | 'sourceLine' | 'confidence'
200
98
  > & { confidence?: number };
@@ -208,6 +106,7 @@ interface OutboundCallContext {
208
106
  source: ts.SourceFile;
209
107
  initializers: Map<string, ts.Expression>;
210
108
  serviceVariables: Set<string>;
109
+ eventAnalysis: EventCallAnalysisContext;
211
110
  wrapperSpecs: Map<string, WrapperSpec>;
212
111
  add: AddOutboundCall;
213
112
  }
@@ -589,11 +488,10 @@ function classifyEventCall(
589
488
  const expression = node.expression;
590
489
  if (!ts.isPropertyAccessExpression(expression)
591
490
  || !['emit', 'publish', 'on'].includes(expression.name.text)) return false;
592
- const event = eventCallClassification(
593
- node, expression, context.serviceVariables,
594
- );
595
- if (event) context.add(node, event.fact, event.evidence);
596
- return true;
491
+ const event = analyzeEventCall(node, expression, context.eventAnalysis);
492
+ if (event.status === 'classified')
493
+ context.add(node, event.fact, event.evidence);
494
+ return event.status !== 'unclassified';
597
495
  }
598
496
 
599
497
  function classifyExternalCall(
@@ -661,11 +559,16 @@ function visitOutboundCalls(
661
559
  export function classifyOutboundCallsInSource(
662
560
  source: ts.SourceFile,
663
561
  filePath: string,
562
+ options: OutboundClassificationOptions = {},
664
563
  ): ClassifiedOutboundCall[] {
665
564
  const calls: ClassifiedOutboundCall[] = [];
666
565
  const sourceFile = normalizePath(filePath);
667
566
  const initializers = variableInitializers(source);
668
567
  const serviceVariables = collectServiceVariables(source);
568
+ const eventAnalysis = createEventCallAnalysisContext(
569
+ source, serviceVariables, options.importedEventNameResolver,
570
+ options.eventEnvironmentReferenceResolver,
571
+ );
669
572
  const wrapperSpecs = collectWrapperSpecs(source);
670
573
  const internalRanges = [...wrapperSpecs.values()].map((spec) => ({
671
574
  start: spec.internalStart, end: spec.internalEnd,
@@ -682,7 +585,7 @@ export function classifyOutboundCallsInSource(
682
585
  } });
683
586
  };
684
587
  const context = {
685
- source, initializers, serviceVariables, wrapperSpecs, add,
588
+ source, initializers, serviceVariables, eventAnalysis, wrapperSpecs, add,
686
589
  };
687
590
  visitOutboundCalls(
688
591
  source, internalRanges,
@@ -6,15 +6,21 @@ import { normalizePath } from '../utils/path-utils.js';
6
6
  import {
7
7
  classifyOutboundCallsInSource,
8
8
  type ClassifiedOutboundCall,
9
- } from './023-outbound-call-classifier.js';
9
+ } from './outbound-call-classifier.js';
10
10
  import {
11
11
  lineOf,
12
12
  literalText,
13
13
  parserEvidence,
14
- } from './022-outbound-expression-analysis.js';
14
+ } from './outbound-expression-analysis.js';
15
15
  import { parseImportedWrapperCalls } from './imported-wrapper-parser.js';
16
16
  import { parseServiceBindings } from './service-binding-parser.js';
17
17
  import type { RepositorySourceContext } from './ts-project.js';
18
+ import {
19
+ createImportedEventNameResolver,
20
+ } from './event-name-import-resolution.js';
21
+ import {
22
+ createEventEnvironmentReferenceResolver,
23
+ } from './event-environment-reference.js';
18
24
 
19
25
  export {
20
26
  classifyOutboundCallsInSource,
@@ -77,7 +83,13 @@ export async function parseOutboundCalls(
77
83
  repoPath, filePath, source, bindingNames, context,
78
84
  );
79
85
  const nativeCalls = classified
80
- ?? classifyOutboundCallsInSource(source, filePath);
86
+ ?? classifyOutboundCallsInSource(source, filePath, context ? {
87
+ importedEventNameResolver: createImportedEventNameResolver(
88
+ context, source, filePath,
89
+ ),
90
+ eventEnvironmentReferenceResolver:
91
+ createEventEnvironmentReferenceResolver(context, source, filePath),
92
+ } : undefined);
81
93
  return [
82
94
  ...nativeCalls.map((call) => call.fact),
83
95
  ...importedWrappers,
@@ -3,12 +3,12 @@ import {
3
3
  chainIncludesForUpdate,
4
4
  queryBuilderRoot,
5
5
  type DirectQueryBuilderStatement,
6
- } from './000-direct-query-execution.js';
6
+ } from './direct-query-execution.js';
7
7
  import {
8
8
  expressionName,
9
9
  maxAliasDepth,
10
10
  resolveBinding,
11
- } from './001-query-entity-resolution.js';
11
+ } from './query-entity-resolution.js';
12
12
  import type { OperationPathAnalysis } from './operation-path-analysis.js';
13
13
  import { stripQuotes } from '../utils/path-utils.js';
14
14
  export function lineOf(text: string, index: number): number {
@@ -55,7 +55,6 @@ export function queryWarning(expression: string): string {
55
55
  return 'query_variable_without_static_initializer';
56
56
  return 'dynamic_entity_expression';
57
57
  }
58
-
59
58
  export function parserEvidence(
60
59
  source: ts.SourceFile,
61
60
  node: ts.CallExpression,
@@ -109,7 +108,8 @@ type ExpressionSourceKind =
109
108
  | 'string_literal'
110
109
  | 'no_substitution_template'
111
110
  | 'template_with_substitutions'
112
- | 'const_alias'
111
+ | 'const_alias' | 'const_identifier'
112
+ | 'enum_member' | 'const_object_property'
113
113
  | 'conditional_candidates'
114
114
  | 'dynamic_expression';
115
115
 
@@ -1,7 +1,7 @@
1
1
  import ts from 'typescript';
2
2
  import {
3
3
  lexicalIdentifierDeclarations,
4
- } from './002-symbol-import-bindings.js';
4
+ } from './symbol-import-bindings.js';
5
5
 
6
6
  interface AccessPath {
7
7
  root: ts.Identifier;
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  PACKAGE_PUBLIC_SURFACE_RECORD_CAP,
3
3
  PACKAGE_PUBLIC_SURFACE_SCHEMA,
4
- } from './003-package-public-surface.js';
4
+ } from './package-public-surface.js';
5
5
  import type {
6
6
  ExecutableBodyEligibility,
7
7
  PackagePublicEntry,
8
8
  PackagePublicScope,
9
9
  PackagePublicSurfaceFact,
10
10
  PublicSurfaceTarget,
11
- } from './003-package-public-surface.js';
11
+ } from './package-public-surface.js';
12
12
  import {
13
13
  packageModuleRequest,
14
14
  type SymbolImportBindingKind,
15
15
  type SymbolImportReference,
16
16
  type SymbolImportReferenceShape,
17
- } from './002-symbol-import-bindings.js';
17
+ } from './symbol-import-bindings.js';
18
18
 
19
19
  const bindingKinds = new Set<SymbolImportBindingKind>([
20
20
  'esm_named', 'esm_default', 'esm_namespace',
@@ -4,7 +4,7 @@ import {
4
4
  PACKAGE_PUBLIC_SURFACE_RECORD_CAP,
5
5
  PACKAGE_PUBLIC_SURFACE_SCHEMA,
6
6
  resolveModule,
7
- } from './003-package-public-surface.js';
7
+ } from './package-public-surface.js';
8
8
  import type {
9
9
  ModuleInfo,
10
10
  ModuleResolution,
@@ -16,7 +16,7 @@ import type {
16
16
  PackageSourceModule,
17
17
  ResolvedExport,
18
18
  SymbolPublicSurfaceEvidence,
19
- } from './003-package-public-surface.js';
19
+ } from './package-public-surface.js';
20
20
  import type { PackageEntrypointManifest } from './package-json-parser.js';
21
21
 
22
22
  interface EntryResolution {
@@ -4,8 +4,8 @@ import {
4
4
  hasNestedCommonJsMutation,
5
5
  isUnshadowedCommonJsExportExpression,
6
6
  unsupportedCommonJsMutation,
7
- } from './018-package-commonjs-syntax.js';
8
- import { stableLocalValueReference } from './020-stable-local-value.js';
7
+ } from './package-commonjs-syntax.js';
8
+ import { stableLocalValueReference } from './stable-local-value.js';
9
9
 
10
10
  export const PACKAGE_PUBLIC_SURFACE_SCHEMA =
11
11
  'service-flow/package-public-surface@1';
@@ -658,4 +658,4 @@ export function moduleInfoMap(
658
658
  }
659
659
 
660
660
  export { analyzePackagePublicSurface } from
661
- './010-package-public-surface-analysis.js';
661
+ './package-public-surface-analysis.js';
@@ -8,7 +8,7 @@ import {
8
8
  analyzePackagePublicSurface,
9
9
  type PackagePublicSurfaceAnalysis,
10
10
  type SymbolPublicSurfaceEvidence,
11
- } from './003-package-public-surface.js';
11
+ } from './package-public-surface.js';
12
12
  import type { RepositorySourceContext } from './ts-project.js';
13
13
 
14
14
  function symbolIdentity(
@@ -1,5 +1,5 @@
1
1
  import ts from 'typescript';
2
- import { isCapQueryBuilderRootName } from './000-direct-query-execution.js';
2
+ import { isCapQueryBuilderRootName } from './direct-query-execution.js';
3
3
 
4
4
  export interface BindingResolution {
5
5
  declaration?: ts.VariableDeclaration | ts.ParameterDeclaration;
@@ -15,8 +15,8 @@ import {
15
15
  createBindingLexicalIndex,
16
16
  type BindingLexicalIndex,
17
17
  type BindingSiteCandidate,
18
- } from './011-binding-lexical-scope.js';
19
- import { selectVisibleBinding } from './021-binding-visibility.js';
18
+ } from './binding-lexical-scope.js';
19
+ import { selectVisibleBinding } from './binding-visibility.js';
20
20
  import {
21
21
  arrayAssignmentName,
22
22
  arrayBindingName,
@@ -24,7 +24,7 @@ import {
24
24
  collectReturnedObjectBindings,
25
25
  directConnectFactFromFunctionLike,
26
26
  functionLikeInitializer,
27
- } from './014-service-binding-helper-flow.js';
27
+ } from './service-binding-helper-flow.js';
28
28
 
29
29
  type ResolvedHelper = { helper: HelperBinding; imp?: ImportBinding };
30
30
  type BindingEvent = {
@@ -11,8 +11,8 @@ import {
11
11
  type BindingLexicalIndex,
12
12
  type BindingSiteCandidate,
13
13
  type VisibleBinding,
14
- } from './011-binding-lexical-scope.js';
15
- import { selectVisibleBinding } from './021-binding-visibility.js';
14
+ } from './binding-lexical-scope.js';
15
+ import { selectVisibleBinding } from './binding-visibility.js';
16
16
 
17
17
  export type LocalBindingFact = Omit<
18
18
  HelperBinding,
@@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import ts from 'typescript';
4
4
  import { normalizePath } from '../utils/path-utils.js';
5
- import { extractPlaceholderKeys } from '../utils/001-placeholders.js';
5
+ import { extractPlaceholderKeys } from '../utils/placeholders.js';
6
6
  import type { RepositorySourceContext } from './ts-project.js';
7
7
 
8
8
  export interface HelperBinding {
@@ -15,8 +15,8 @@ import {
15
15
  directConnectFactFromFunctionLike,
16
16
  functionLikeInitializer,
17
17
  type LocalBindingFact,
18
- } from './014-service-binding-helper-flow.js';
19
- import { collectServiceBindings } from './015-service-binding-collector.js';
18
+ } from './service-binding-helper-flow.js';
19
+ import { collectServiceBindings } from './service-binding-collector.js';
20
20
  import type { RepositorySourceContext } from './ts-project.js';
21
21
 
22
22
  interface LocalHelperFact extends LocalBindingFact {
@@ -8,9 +8,9 @@ import type {
8
8
  import {
9
9
  executableSymbolCandidates,
10
10
  selectCallOwner,
11
- } from './004-fact-identity.js';
12
- import { reconcileEventSubscriptions } from './005-event-subscription-facts.js';
13
- import { reconcileBindingAndCallIdentity } from './006-binding-identity.js';
11
+ } from './fact-identity.js';
12
+ import { reconcileEventSubscriptions } from './event-subscription-facts.js';
13
+ import { reconcileBindingAndCallIdentity } from './binding-identity.js';
14
14
  import type { ClassifiedOutboundCall } from './outbound-call-parser.js';
15
15
 
16
16
  export interface ReconciledSourceFacts {
@@ -1,10 +1,10 @@
1
1
  import ts from 'typescript';
2
2
  import {
3
3
  identifierMatchesDeclaration,
4
- } from './002-symbol-import-bindings.js';
4
+ } from './symbol-import-bindings.js';
5
5
  import {
6
6
  isUnshadowedCommonJsExportExpression,
7
- } from './018-package-commonjs-syntax.js';
7
+ } from './package-commonjs-syntax.js';
8
8
 
9
9
  function transparentUse(node: ts.Node): ts.Node {
10
10
  const parent = node.parent;
@@ -37,19 +37,38 @@ function directWriteTarget(node: ts.Node): boolean {
37
37
  && parent.initializer === use;
38
38
  }
39
39
 
40
- type MemberContainer = ts.ObjectLiteralExpression | ts.ClassLikeDeclaration;
41
- type StableMember = ts.ObjectLiteralElementLike | ts.ClassElement;
40
+ type MemberContainer =
41
+ | ts.ObjectLiteralExpression
42
+ | ts.ClassLikeDeclaration
43
+ | ts.EnumDeclaration;
44
+ type StableMember =
45
+ | ts.ObjectLiteralElementLike
46
+ | ts.ClassElement
47
+ | ts.EnumMember;
48
+
49
+ function memberInitializer(
50
+ expression: ts.Expression,
51
+ ): ts.Expression {
52
+ if (ts.isParenthesizedExpression(expression)
53
+ || ts.isAsExpression(expression)
54
+ || ts.isSatisfiesExpression(expression)
55
+ || ts.isTypeAssertionExpression(expression))
56
+ return memberInitializer(expression.expression);
57
+ return expression;
58
+ }
42
59
 
43
60
  function memberContainer(
44
61
  declaration: ts.Identifier,
45
62
  ): MemberContainer | undefined {
46
63
  const parent = declaration.parent;
47
64
  if (ts.isClassDeclaration(parent)) return parent;
65
+ if (ts.isEnumDeclaration(parent)) return parent;
48
66
  if (!ts.isVariableDeclaration(parent) || parent.name !== declaration
49
67
  || !parent.initializer) return undefined;
50
- return ts.isObjectLiteralExpression(parent.initializer)
51
- || ts.isClassExpression(parent.initializer)
52
- ? parent.initializer
68
+ const initializer = memberInitializer(parent.initializer);
69
+ return ts.isObjectLiteralExpression(initializer)
70
+ || ts.isClassExpression(initializer)
71
+ ? initializer
53
72
  : undefined;
54
73
  }
55
74
 
@@ -81,10 +100,12 @@ function matchingMember(
81
100
  ): StableMember | undefined {
82
101
  const members = ts.isObjectLiteralExpression(value)
83
102
  ? value.properties
84
- : value.members.filter((member) =>
85
- ts.canHaveModifiers(member)
86
- && ts.getModifiers(member)?.some((modifier) =>
87
- modifier.kind === ts.SyntaxKind.StaticKeyword));
103
+ : ts.isEnumDeclaration(value)
104
+ ? value.members
105
+ : value.members.filter((member) =>
106
+ ts.canHaveModifiers(member)
107
+ && ts.getModifiers(member)?.some((modifier) =>
108
+ modifier.kind === ts.SyntaxKind.StaticKeyword));
88
109
  const matches = members.filter((member) =>
89
110
  'name' in member && member.name && memberName(member.name) === name);
90
111
  if (matches.length === 1) return matches[0];