@saptools/service-flow 0.1.68 → 0.1.70

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 (124) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +11 -5
  3. package/TECHNICAL-NOTE.md +13 -0
  4. package/dist/{chunk-AEM4JY22.js → chunk-GSLFY6J2.js} +6986 -5503
  5. package/dist/chunk-GSLFY6J2.js.map +1 -0
  6. package/dist/cli.js +334 -122
  7. package/dist/cli.js.map +1 -1
  8. package/dist/index.d.ts +7 -1
  9. package/dist/index.js +1 -1
  10. package/package.json +1 -1
  11. package/src/cli/{002-doctor-lifecycle.ts → doctor-lifecycle.ts} +1 -1
  12. package/src/cli/{001-doctor-projection.ts → doctor-projection.ts} +1 -1
  13. package/src/cli/doctor.ts +5 -5
  14. package/src/cli/index-summary.ts +22 -0
  15. package/src/cli.ts +155 -91
  16. package/src/db/{009-binding-fact-semantics.ts → binding-fact-semantics.ts} +6 -1
  17. package/src/db/binding-helper-provenance.ts +17 -0
  18. package/src/db/{012-binding-reference-proof.ts → binding-reference-proof.ts} +4 -0
  19. package/src/db/{000-call-fact-repository.ts → call-fact-repository.ts} +49 -23
  20. package/src/db/{003-current-fact-semantics.ts → current-fact-semantics.ts} +5 -4
  21. package/src/db/{001-fact-lifecycle.ts → fact-lifecycle.ts} +3 -3
  22. package/src/db/index-publication-failure.ts +91 -0
  23. package/src/db/{007-package-fact-semantics.ts → package-fact-semantics.ts} +6 -6
  24. package/src/db/{010-package-symbol-surface-semantics.ts → package-symbol-surface-semantics.ts} +2 -2
  25. package/src/db/{004-package-target-invalidation.ts → package-target-invalidation.ts} +11 -1
  26. package/src/db/{008-relative-fact-semantics.ts → relative-fact-semantics.ts} +9 -6
  27. package/src/db/{006-relative-symbol-resolution.ts → relative-symbol-resolution.ts} +28 -7
  28. package/src/db/repositories.ts +24 -7
  29. package/src/db/{011-symbol-call-semantics.ts → symbol-call-semantics.ts} +1 -1
  30. package/src/index.ts +3 -3
  31. package/src/indexer/cds-extension-resolver.ts +27 -3
  32. package/src/indexer/repository-indexer.ts +70 -9
  33. package/src/indexer/workspace-indexer.ts +142 -30
  34. package/src/linker/call-edge-insertion.ts +568 -0
  35. package/src/linker/{002-call-evidence.ts → call-evidence.ts} +2 -2
  36. package/src/linker/cross-repo-linker.ts +6 -169
  37. package/src/linker/dynamic-edge-resolver.ts +1 -1
  38. package/src/linker/{004-event-subscription-handler-linker.ts → event-subscription-handler-linker.ts} +32 -11
  39. package/src/linker/event-template-link.ts +72 -0
  40. package/src/linker/external-http-target.ts +1 -1
  41. package/src/linker/helper-package-linker.ts +1 -1
  42. package/src/linker/{000-implementation-candidates.ts → implementation-candidates.ts} +1 -1
  43. package/src/linker/{001-implementation-evidence-projection.ts → implementation-evidence-projection.ts} +1 -1
  44. package/src/linker/odata-path-normalizer.ts +1 -1
  45. package/src/linker/{005-odata-path-structure.ts → odata-path-structure.ts} +1 -1
  46. package/src/linker/{003-package-import-symbol-resolver.ts → package-import-symbol-resolver.ts} +3 -3
  47. package/src/linker/service-resolver.ts +2 -2
  48. package/src/output/{001-compact-json-output.ts → compact-json-output.ts} +1 -1
  49. package/src/parsers/{006-binding-identity.ts → binding-identity.ts} +9 -4
  50. package/src/parsers/{011-binding-lexical-scope.ts → binding-lexical-scope.ts} +1 -1
  51. package/src/parsers/{021-binding-visibility.ts → binding-visibility.ts} +18 -2
  52. package/src/parsers/{000-direct-query-execution.ts → direct-query-execution.ts} +11 -0
  53. package/src/parsers/{005-event-subscription-facts.ts → event-subscription-facts.ts} +2 -2
  54. package/src/parsers/{016-local-symbol-reference.ts → local-symbol-reference.ts} +2 -2
  55. package/src/parsers/operation-path-analysis.ts +1 -1
  56. package/src/parsers/outbound-call-classifier.ts +692 -0
  57. package/src/parsers/outbound-call-parser.ts +146 -509
  58. package/src/parsers/outbound-expression-analysis.ts +700 -0
  59. package/src/parsers/{018-package-commonjs-syntax.ts → package-commonjs-syntax.ts} +1 -1
  60. package/src/parsers/{012-package-fact-contract.ts → package-fact-contract.ts} +3 -3
  61. package/src/parsers/{010-package-public-surface-analysis.ts → package-public-surface-analysis.ts} +2 -2
  62. package/src/parsers/{003-package-public-surface.ts → package-public-surface.ts} +3 -3
  63. package/src/parsers/{008-package-surface-publication.ts → package-surface-publication.ts} +1 -1
  64. package/src/parsers/{001-query-entity-resolution.ts → query-entity-resolution.ts} +1 -1
  65. package/src/parsers/{015-service-binding-collector.ts → service-binding-collector.ts} +3 -3
  66. package/src/parsers/{014-service-binding-helper-flow.ts → service-binding-helper-flow.ts} +72 -6
  67. package/src/parsers/service-binding-parser-helpers.ts +1 -1
  68. package/src/parsers/service-binding-parser.ts +2 -2
  69. package/src/parsers/{007-source-fact-reconciliation.ts → source-fact-reconciliation.ts} +3 -3
  70. package/src/parsers/{020-stable-local-value.ts → stable-local-value.ts} +2 -2
  71. package/src/parsers/{009-symbol-call-facts.ts → symbol-call-facts.ts} +3 -3
  72. package/src/parsers/{017-symbol-derived-contexts.ts → symbol-derived-contexts.ts} +2 -2
  73. package/src/parsers/symbol-parser.ts +43 -11
  74. package/src/trace/{014-compact-contract.ts → compact-contract.ts} +6 -0
  75. package/src/trace/{021-compact-decision-normalization.ts → compact-decision-normalization.ts} +77 -11
  76. package/src/trace/{020-compact-field-projection.ts → compact-field-projection.ts} +77 -4
  77. package/src/trace/{024-compact-observation-decision.ts → compact-observation-decision.ts} +10 -5
  78. package/src/trace/{016-compact-projector.ts → compact-projector.ts} +6 -7
  79. package/src/trace/{018-compact-trace.ts → compact-trace.ts} +3 -3
  80. package/src/trace/{006-contextual-projection.ts → contextual-projection.ts} +1 -1
  81. package/src/trace/{008-contextual-runtime-state.ts → contextual-runtime-state.ts} +1 -1
  82. package/src/trace/{001-dynamic-identity.ts → dynamic-identity.ts} +2 -2
  83. package/src/trace/{003-dynamic-references.ts → dynamic-references.ts} +2 -2
  84. package/src/trace/dynamic-targets.ts +6 -6
  85. package/src/trace/event-runtime-resolution.ts +151 -0
  86. package/src/trace/{011-event-subscriber-traversal.ts → event-subscriber-traversal.ts} +101 -9
  87. package/src/trace/evidence.ts +2 -2
  88. package/src/trace/implementation-hints.ts +10 -7
  89. package/src/trace/{005-implementation-selection.ts → implementation-selection.ts} +2 -2
  90. package/src/trace/{007-implementation-start-diagnostic.ts → implementation-start-diagnostic.ts} +1 -0
  91. package/src/trace/local-call-expansion.ts +37 -0
  92. package/src/trace/{009-selected-handler-provenance.ts → selected-handler-provenance.ts} +1 -1
  93. package/src/trace/selectors.ts +2 -1
  94. package/src/trace/{017-trace-context.ts → trace-context.ts} +2 -2
  95. package/src/trace/{015-trace-edge-recorder.ts → trace-edge-recorder.ts} +62 -5
  96. package/src/trace/{019-trace-edge-semantics.ts → trace-edge-semantics.ts} +9 -13
  97. package/src/trace/trace-engine.ts +10 -10
  98. package/src/trace/{022-trace-fact-preflight.ts → trace-fact-preflight.ts} +2 -2
  99. package/src/trace/{025-trace-implementation-scope.ts → trace-implementation-scope.ts} +1 -1
  100. package/src/trace/{028-trace-operation-execution.ts → trace-operation-execution.ts} +10 -10
  101. package/src/trace/{013-trace-root-scopes.ts → trace-root-scopes.ts} +5 -6
  102. package/src/trace/{027-trace-scope-execution.ts → trace-scope-execution.ts} +44 -44
  103. package/src/trace/{029-trace-start-implementation.ts → trace-start-implementation.ts} +7 -7
  104. package/src/trace/{026-trace-start-scope.ts → trace-start-scope.ts} +6 -5
  105. package/src/trace/{010-traversal-scope.ts → traversal-scope.ts} +1 -1
  106. package/src/types.ts +2 -1
  107. package/src/version.ts +1 -1
  108. package/dist/chunk-AEM4JY22.js.map +0 -1
  109. /package/src/cli/{000-clean.ts → clean.ts} +0 -0
  110. /package/src/cli/{003-doctor-package-resolution.ts → doctor-package-resolution.ts} +0 -0
  111. /package/src/db/{002-fact-json-inventory.ts → fact-json-inventory.ts} +0 -0
  112. /package/src/db/{005-schema-structure.ts → schema-structure.ts} +0 -0
  113. /package/src/output/{000-stdout-policy.ts → stdout-policy.ts} +0 -0
  114. /package/src/parsers/{019-binding-assignment-targets.ts → binding-assignment-targets.ts} +0 -0
  115. /package/src/parsers/{013-executable-body-eligibility.ts → executable-body-eligibility.ts} +0 -0
  116. /package/src/parsers/{004-fact-identity.ts → fact-identity.ts} +0 -0
  117. /package/src/parsers/{002-symbol-import-bindings.ts → symbol-import-bindings.ts} +0 -0
  118. /package/src/trace/{004-dynamic-candidate-sources.ts → dynamic-candidate-sources.ts} +0 -0
  119. /package/src/trace/{000-dynamic-target-types.ts → dynamic-target-types.ts} +0 -0
  120. /package/src/trace/{023-nested-event-scopes.ts → nested-event-scopes.ts} +0 -0
  121. /package/src/trace/{002-trace-diagnostics.ts → trace-diagnostics.ts} +0 -0
  122. /package/src/trace/{012-trace-graph-lookups.ts → trace-graph-lookups.ts} +0 -0
  123. /package/src/utils/{000-bounded-projection.ts → bounded-projection.ts} +0 -0
  124. /package/src/utils/{001-placeholders.ts → placeholders.ts} +0 -0
@@ -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,
@@ -157,12 +157,58 @@ function returnedProperty(
157
157
  return { propertyName, variableName: property.initializer.text };
158
158
  }
159
159
 
160
- function branchDependent(node: ts.Node, fn: ts.FunctionLikeDeclaration): boolean {
160
+ function hazardousTryClause(
161
+ node: ts.Node | undefined,
162
+ fn: ts.FunctionLikeDeclaration,
163
+ anyReturn: boolean,
164
+ ): boolean {
165
+ if (!node) return false;
166
+ let found = false;
167
+ const visit = (current: ts.Node): void => {
168
+ if (found || current !== fn && ts.isFunctionLike(current)) return;
169
+ if (ts.isReturnStatement(current)
170
+ && (anyReturn || current.expression !== undefined)
171
+ || ts.isCallExpression(current) && connectFactFromCall(current)) {
172
+ found = true;
173
+ return;
174
+ }
175
+ ts.forEachChild(current, visit);
176
+ };
177
+ visit(node);
178
+ return found;
179
+ }
180
+
181
+ function hasAncestor(node: ts.Node, ancestor: ts.Node): boolean {
182
+ let current: ts.Node | undefined = node.parent;
183
+ while (current) {
184
+ if (current === ancestor) return true;
185
+ current = current.parent;
186
+ }
187
+ return false;
188
+ }
189
+
190
+ function unsupportedTryAncestor(
191
+ statement: ts.TryStatement,
192
+ returned: ts.Node,
193
+ fn: ts.FunctionLikeDeclaration,
194
+ ): boolean {
195
+ if (!hasAncestor(returned, statement.tryBlock)) return true;
196
+ if (hazardousTryClause(statement.catchClause?.block, fn, false))
197
+ return true;
198
+ return hazardousTryClause(statement.finallyBlock, fn, true);
199
+ }
200
+
201
+ function branchDependent(
202
+ node: ts.Node,
203
+ fn: ts.FunctionLikeDeclaration,
204
+ ): boolean {
161
205
  let current: ts.Node | undefined = node.parent;
162
206
  while (current && current !== fn) {
163
207
  if (ts.isIfStatement(current) || ts.isConditionalExpression(current)
164
- || ts.isSwitchStatement(current) || ts.isIterationStatement(current, false)
165
- || ts.isTryStatement(current)) return true;
208
+ || ts.isSwitchStatement(current)
209
+ || ts.isIterationStatement(current, false)) return true;
210
+ if (ts.isTryStatement(current)
211
+ && unsupportedTryAncestor(current, node, fn)) return true;
166
212
  current = current.parent;
167
213
  }
168
214
  return false;
@@ -231,10 +277,30 @@ function directReturnConnectFact(
231
277
  return directConnectFact(returned);
232
278
  }
233
279
 
280
+ function hasTryAncestor(
281
+ returned: ts.ReturnStatement,
282
+ fn: ts.FunctionLikeDeclaration,
283
+ ): boolean {
284
+ let current: ts.Node | undefined = returned.parent;
285
+ while (current && current !== fn) {
286
+ if (ts.isTryStatement(current)) return true;
287
+ current = current.parent;
288
+ }
289
+ return false;
290
+ }
291
+
234
292
  export function directConnectFactFromFunctionLike(
235
293
  fn: ts.FunctionLikeDeclaration,
236
294
  ): LocalBindingFact | undefined {
237
295
  if (ts.isArrowFunction(fn) && fn.body && !ts.isBlock(fn.body))
238
296
  return directConnectFact(fn.body);
239
- return directReturnConnectFact(fn);
297
+ const returned = singleReturn(fn);
298
+ const fact = directReturnConnectFact(fn);
299
+ if (!fact || !returned || !hasTryAncestor(returned, fn)) return fact;
300
+ return {
301
+ ...fact,
302
+ helperChain: [...(fact.helperChain ?? []), {
303
+ bindingOrigin: 'single_hop_helper_return',
304
+ }],
305
+ };
240
306
  }
@@ -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;
@@ -6,18 +6,18 @@ import type {
6
6
  import {
7
7
  executableSymbolCandidates,
8
8
  selectCallOwner,
9
- } from './004-fact-identity.js';
9
+ } from './fact-identity.js';
10
10
  import {
11
11
  derivedMemberImportReference,
12
12
  identifierMatchesDeclaration,
13
13
  symbolImportReference,
14
14
  type SymbolImportBinding,
15
15
  type SymbolImportReference,
16
- } from './002-symbol-import-bindings.js';
16
+ } from './symbol-import-bindings.js';
17
17
  import {
18
18
  localSymbolTarget,
19
19
  type LocalSymbolTargetIdentity,
20
- } from './016-local-symbol-reference.js';
20
+ } from './local-symbol-reference.js';
21
21
 
22
22
  export interface SymbolCallProxy {
23
23
  importSource: string;
@@ -3,12 +3,12 @@ import {
3
3
  symbolCallName,
4
4
  type SymbolCallProxy,
5
5
  type SymbolClassInstance,
6
- } from './009-symbol-call-facts.js';
6
+ } from './symbol-call-facts.js';
7
7
  import {
8
8
  identifierMatchesDeclaration,
9
9
  symbolImportReference,
10
10
  type SymbolImportBinding,
11
- } from './002-symbol-import-bindings.js';
11
+ } from './symbol-import-bindings.js';
12
12
 
13
13
  interface DerivedContextCollection {
14
14
  source: ts.SourceFile;
@@ -9,24 +9,24 @@ import {
9
9
  } from './outbound-call-parser.js';
10
10
  import type { RepositorySourceContext } from './ts-project.js';
11
11
  import { normalizePath } from '../utils/path-utils.js';
12
- import { reconcileEventSubscriptions } from './005-event-subscription-facts.js';
13
- import { reconcileSymbolCallOwners } from './007-source-fact-reconciliation.js';
12
+ import { reconcileEventSubscriptions } from './event-subscription-facts.js';
13
+ import { reconcileSymbolCallOwners } from './source-fact-reconciliation.js';
14
14
  import {
15
15
  collectSymbolImportBindings,
16
16
  type SymbolImportBinding,
17
- } from './002-symbol-import-bindings.js';
17
+ } from './symbol-import-bindings.js';
18
18
  import {
19
19
  collectSymbolCallFacts,
20
20
  symbolCallName,
21
21
  type SymbolCallProxy,
22
22
  type SymbolClassInstance,
23
- } from './009-symbol-call-facts.js';
23
+ } from './symbol-call-facts.js';
24
24
  import {
25
25
  executableBodyEligibility,
26
- } from './013-executable-body-eligibility.js';
26
+ } from './executable-body-eligibility.js';
27
27
  import {
28
28
  collectDerivedSymbolContexts,
29
- } from './017-symbol-derived-contexts.js';
29
+ } from './symbol-derived-contexts.js';
30
30
 
31
31
  function lineOf(source: ts.SourceFile, pos: number): number {
32
32
  return source.getLineAndCharacterOfPosition(pos).line + 1;
@@ -42,6 +42,12 @@ function isFunctionLike(node: ts.Node): node is ts.FunctionLikeDeclaration {
42
42
  function exported(node: ts.Node): boolean {
43
43
  return Boolean(ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export);
44
44
  }
45
+ function defaultExported(node: ts.Node): boolean {
46
+ return Boolean(
47
+ ts.getCombinedModifierFlags(node as ts.Declaration)
48
+ & ts.ModifierFlags.Default,
49
+ );
50
+ }
45
51
  function isPublicClassMethod(node: ts.MethodDeclaration): boolean {
46
52
  const flags = ts.getCombinedModifierFlags(node);
47
53
  return (flags & ts.ModifierFlags.Private) === 0 && (flags & ts.ModifierFlags.Protected) === 0;
@@ -141,6 +147,7 @@ interface SymbolCollection {
141
147
  exportNames: Map<string, string>;
142
148
  objectExports: Set<string>;
143
149
  exportedClasses: Set<string>;
150
+ defaultExportedClasses: Set<string>;
144
151
  declaredClasses: Set<string>;
145
152
  proxies: Map<string, SymbolCallProxy[]>;
146
153
  instances: Map<string, SymbolClassInstance[]>;
@@ -153,7 +160,8 @@ function symbolSourceEvidence(
153
160
  parentRoot: string;
154
161
  qualifiedName: string;
155
162
  declaredExportName?: string;
156
- classContainerExported: boolean; classMemberExported: boolean;
163
+ classContainerExported: boolean; classContainerDefaultExported: boolean;
164
+ classMemberExported: boolean;
157
165
  objectExported: boolean;
158
166
  evidence?: Record<string, unknown>;
159
167
  },
@@ -168,6 +176,8 @@ function symbolSourceEvidence(
168
176
  if (options.classContainerExported && ts.isMethodDeclaration(node)
169
177
  && isPublicClassMethod(node)) return {
170
178
  source: 'exported_class_instance_member', exportedClass: options.parentRoot,
179
+ exportedClassExportKind: options.classContainerDefaultExported
180
+ ? 'default' : 'named',
171
181
  memberKind: 'class_method',
172
182
  };
173
183
  if (options.declaredExportName) return {
@@ -201,6 +211,7 @@ interface SymbolNames {
201
211
  declaredExportName?: string;
202
212
  objectExported: boolean;
203
213
  classContainerExported: boolean;
214
+ classContainerDefaultExported: boolean;
204
215
  classMemberExported: boolean;
205
216
  effectiveName?: string;
206
217
  }
@@ -219,6 +230,24 @@ function exportedClassMember(
219
230
  && isPublicClassMethod(node);
220
231
  }
221
232
 
233
+ function classExportState(
234
+ collection: SymbolCollection,
235
+ parentName: string | undefined,
236
+ parentRoot: string,
237
+ ): {
238
+ classContainerExported: boolean;
239
+ classContainerDefaultExported: boolean;
240
+ } {
241
+ return {
242
+ classContainerExported: Boolean(
243
+ parentName && collection.exportedClasses.has(parentRoot),
244
+ ),
245
+ classContainerDefaultExported: Boolean(
246
+ parentName && collection.defaultExportedClasses.has(parentRoot),
247
+ ),
248
+ };
249
+ }
250
+
222
251
  function symbolNames(
223
252
  collection: SymbolCollection,
224
253
  kind: string,
@@ -238,12 +267,11 @@ function symbolNames(
238
267
  const classMemberExported = exportedClassMember(
239
268
  collection, kind, parentName, parentRoot, node,
240
269
  );
241
- const classContainerExported = Boolean(
242
- parentName && collection.exportedClasses.has(parentRoot),
243
- );
270
+ const classState = classExportState(collection, parentName, parentRoot);
244
271
  return {
245
272
  parentRoot, declaredExportName, qualifiedName,
246
- objectExported, classContainerExported, classMemberExported,
273
+ objectExported, ...classState,
274
+ classMemberExported,
247
275
  effectiveName: classMemberExported || objectExported
248
276
  ? qualifiedName : declaredExportName,
249
277
  };
@@ -266,6 +294,7 @@ function addExecutableSymbol(
266
294
  qualifiedName: names.qualifiedName,
267
295
  declaredExportName: names.declaredExportName,
268
296
  classContainerExported: names.classContainerExported,
297
+ classContainerDefaultExported: names.classContainerDefaultExported,
269
298
  classMemberExported: names.classMemberExported,
270
299
  objectExported: names.objectExported,
271
300
  evidence,
@@ -457,6 +486,8 @@ function collectClassDeclaration(
457
486
  collection.declaredClasses.add(node.name.text);
458
487
  if (exported(node) || collection.exportNames.has(node.name.text))
459
488
  collection.exportedClasses.add(node.name.text);
489
+ if (defaultExported(node))
490
+ collection.defaultExportedClasses.add(node.name.text);
460
491
  for (const member of node.members)
461
492
  visitDeclaredSymbol(collection, member, node.name.text);
462
493
  return true;
@@ -553,6 +584,7 @@ function createCollection(
553
584
  importBindings: collectSymbolImportBindings(source),
554
585
  exportNames: exportDeclarations(source),
555
586
  objectExports: new Set(), exportedClasses: new Set(),
587
+ defaultExportedClasses: new Set(),
556
588
  declaredClasses: new Set(), proxies: new Map(), instances: new Map(),
557
589
  };
558
590
  }
@@ -82,6 +82,7 @@ export interface CompactDecisionInput {
82
82
  implementationStrategy?: string;
83
83
  implementationGuided?: boolean;
84
84
  implementationContextual?: boolean;
85
+ tiedCandidateRepos?: CompactReferenceGroupV1;
85
86
  reasonCode?: string;
86
87
  eventMatchStrategy?: string;
87
88
  dispatchCertainty?: string;
@@ -225,6 +226,7 @@ export interface CompactDecisionV1 {
225
226
  implementationStrategy?: string;
226
227
  implementationGuided?: boolean;
227
228
  implementationContextual?: boolean;
229
+ tiedCandidateRepos?: CompactReferenceGroupV1;
228
230
  eventMatchStrategy?: string;
229
231
  dispatchCertainty?: string;
230
232
  eventSubscriptionCount?: number;
@@ -247,6 +249,10 @@ export interface CompactEdgeDetailsV1 {
247
249
 
248
250
  export interface CompactDiagnosticDetailsV1 {
249
251
  reasonCode?: string;
252
+ tiedCandidateRepos?: CompactReferenceGroupV1;
253
+ selectorKind?: string;
254
+ selectorSuggestions?: CompactReferenceGroupV1;
255
+ invalidFactCategories?: CompactReferenceGroupV1;
250
256
  missingVariableNames?: string[];
251
257
  missingVariableCount?: number;
252
258
  shownMissingVariableCount?: number;
@@ -1,11 +1,14 @@
1
- import { compareBinary } from './010-traversal-scope.js';
1
+ import { compareBinary } from './traversal-scope.js';
2
2
  import type {
3
3
  CompactDecisionV1,
4
+ CompactReferenceGroupV1,
4
5
  CompactStatus,
5
- } from './014-compact-contract.js';
6
+ } from './compact-contract.js';
6
7
 
7
8
  export const COMPACT_MISSING_NAME_LIMIT = 8;
8
9
  export const COMPACT_MISSING_NAME_MAX_LENGTH = 160;
10
+ export const COMPACT_REFERENCE_VALUE_LIMIT = 5;
11
+ const COMPACT_REFERENCE_VALUE_MAX_LENGTH = 240;
9
12
 
10
13
  export interface CompactMissingNameProjection {
11
14
  readonly names: string[];
@@ -23,11 +26,17 @@ export function projectCompactMissingNames(
23
26
  values: readonly string[] | undefined,
24
27
  authoritativeCount: unknown,
25
28
  ): CompactMissingNameProjection {
26
- const raw = [...new Set((values ?? [])
27
- .map((value) => value.trim())
28
- .filter(Boolean))]
29
- .sort(compareBinary);
30
- const safe = raw.filter(isSafeCompactMissingName);
29
+ const candidates = new Map<string, boolean>();
30
+ for (const value of values ?? []) {
31
+ const normalized = value.trim();
32
+ if (!normalized) continue;
33
+ candidates.set(
34
+ normalized,
35
+ (candidates.get(normalized) ?? true) && isSafeCompactMissingName(value),
36
+ );
37
+ }
38
+ const raw = [...candidates.keys()].sort(compareBinary);
39
+ const safe = raw.filter((name) => candidates.get(name) === true);
31
40
  const names = safe.slice(0, COMPACT_MISSING_NAME_LIMIT);
32
41
  const total = Math.max(compactCount(authoritativeCount), raw.length);
33
42
  return {
@@ -37,25 +46,58 @@ export function projectCompactMissingNames(
37
46
  }
38
47
 
39
48
  export function isSafeCompactMissingName(value: string): boolean {
49
+ if (hasControlCharacter(value)) return false;
40
50
  const normalized = value.trim();
41
51
  return normalized.length > 0
42
52
  && normalized.length <= COMPACT_MISSING_NAME_MAX_LENGTH
43
- && !hasControlCharacter(normalized)
44
53
  && safeMissingName.test(normalized);
45
54
  }
46
55
 
56
+ export function projectCompactReferenceGroup(
57
+ values: readonly string[] | undefined,
58
+ authoritativeCount: unknown,
59
+ isSafe: (value: string) => boolean,
60
+ ): CompactReferenceGroupV1 | undefined {
61
+ const candidates = normalizedReferenceValues(values, isSafe);
62
+ const unique = [...candidates.keys()].sort(compareBinary);
63
+ const safe = unique.filter((value) => candidates.get(value) === true);
64
+ const shown = safe.slice(0, COMPACT_REFERENCE_VALUE_LIMIT);
65
+ const total = Math.max(compactCount(authoritativeCount), unique.length);
66
+ if (total === 0) return undefined;
67
+ return {
68
+ values: shown,
69
+ total,
70
+ shown: shown.length,
71
+ omitted: Math.max(0, total - shown.length),
72
+ };
73
+ }
74
+
75
+ export function isSafeCompactReferenceName(value: string): boolean {
76
+ if (!safeReferenceText(value, 160)) return false;
77
+ return /^[@A-Za-z0-9_$][@A-Za-z0-9_$./:-]*$/.test(value.trim());
78
+ }
79
+
80
+ export function isSafeCompactSelectorSuggestion(value: string): boolean {
81
+ if (!safeReferenceText(value, COMPACT_REFERENCE_VALUE_MAX_LENGTH))
82
+ return false;
83
+ return /^(?:--(?:repo|service|operation|path|handler) [@A-Za-z0-9_$./:-]+)(?: --(?:repo|service|operation|path|handler) [@A-Za-z0-9_$./:-]+)*$/
84
+ .test(value.trim());
85
+ }
86
+
47
87
  export function normalizeCompactDecisionEquivalence(
48
88
  decision: CompactDecisionV1,
49
89
  status: CompactStatus,
50
90
  canonicalTarget: string | undefined,
51
91
  targetIdentityEqual = false,
52
92
  persistedIdentityEqual = false,
93
+ rawPersistedStatus?: string,
53
94
  ): void {
95
+ if (decision.effectiveResolutionStatus === status)
96
+ delete decision.effectiveResolutionStatus;
54
97
  removeEquivalentPersistedDecision(
55
98
  decision, status, canonicalTarget, persistedIdentityEqual,
99
+ rawPersistedStatus,
56
100
  );
57
- if (decision.effectiveResolutionStatus === status)
58
- delete decision.effectiveResolutionStatus;
59
101
  if (targetIdentityEqual && canonicalTarget !== undefined
60
102
  && decision.effectiveTarget === canonicalTarget)
61
103
  delete decision.effectiveTarget;
@@ -77,9 +119,10 @@ function removeEquivalentPersistedDecision(
77
119
  status: CompactStatus,
78
120
  canonicalTarget: string | undefined,
79
121
  identityEqual: boolean,
122
+ rawPersistedStatus: string | undefined,
80
123
  ): void {
81
124
  if (!identityEqual
82
- || decision.persistedResolutionStatus !== status
125
+ || rawPersistedStatus !== status
83
126
  || (decision.effectiveResolutionStatus !== undefined
84
127
  && decision.persistedResolutionStatus
85
128
  !== decision.effectiveResolutionStatus))
@@ -96,6 +139,29 @@ function compactCount(value: unknown): number {
96
139
  ? Math.max(0, Math.floor(value)) : 0;
97
140
  }
98
141
 
142
+ function normalizedReferenceValues(
143
+ values: readonly string[] | undefined,
144
+ isSafe: (value: string) => boolean,
145
+ ): Map<string, boolean> {
146
+ const unique = new Map<string, boolean>();
147
+ for (const raw of values ?? []) {
148
+ const value = raw.trim();
149
+ if (!value) continue;
150
+ unique.set(value, (unique.get(value) ?? true) && isSafe(raw));
151
+ }
152
+ return unique;
153
+ }
154
+
155
+ function safeReferenceText(value: string, maxLength: number): boolean {
156
+ if (hasControlCharacter(value)) return false;
157
+ const normalized = value.trim();
158
+ return normalized.length > 0
159
+ && normalized.length <= maxLength
160
+ && !/^[a-z]+:\/\//i.test(normalized)
161
+ && !/(?:^|[^A-Za-z0-9])(?:authorization|bearer|credential|destination|password|secret|token)(?:$|[^A-Za-z0-9])/i
162
+ .test(normalized);
163
+ }
164
+
99
165
  function hasControlCharacter(value: string): boolean {
100
166
  for (let index = 0; index < value.length; index += 1) {
101
167
  const code = value.charCodeAt(index);