@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
@@ -3,19 +3,25 @@ import {
3
3
  selectCallOwner,
4
4
  type OwnerCandidate,
5
5
  type OwnerSelection,
6
- } from '../parsers/004-fact-identity.js';
6
+ } from '../parsers/fact-identity.js';
7
7
  import type { Db, Statement } from './connection.js';
8
8
  import {
9
9
  resolveRelativeSymbolCall,
10
- } from './006-relative-symbol-resolution.js';
10
+ } from './relative-symbol-resolution.js';
11
11
  import {
12
12
  parsePackageImportReference,
13
- } from '../parsers/012-package-fact-contract.js';
13
+ } from '../parsers/package-fact-contract.js';
14
14
  import {
15
15
  resolvedBindingReferenceProofValid,
16
16
  type BindingProofCall,
17
17
  type BindingProofTarget,
18
- } from './012-binding-reference-proof.js';
18
+ } from './binding-reference-proof.js';
19
+ import {
20
+ preparedCallSnapshotError,
21
+ } from './index-publication-failure.js';
22
+ import {
23
+ hasSingleHopHelperReturn,
24
+ } from './binding-helper-provenance.js';
19
25
 
20
26
  export function insertSymbolCalls(db: Db, repoId: number, rows: SymbolCallFact[]): void {
21
27
  const insertStmt = db.prepare('INSERT INTO symbol_calls(repo_id,caller_symbol_id,callee_symbol_id,callee_expression,import_source,source_file,source_line,call_site_start_offset,call_site_end_offset,call_role,status,confidence,evidence_json,unresolved_reason) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
@@ -58,8 +64,8 @@ function assertImportProvenance(call: SymbolCallFact): void {
58
64
  const direct = directPackageProvenanceValid(call);
59
65
  const derived = derivedPackageProvenanceValid(call);
60
66
  if (!direct && !derived)
61
- throw new Error(
62
- 'invalid_prepared_repository_snapshot:package_import_provenance_missing',
67
+ throw preparedCallSnapshotError(
68
+ 'package_import_provenance_missing', 'symbol_call', call,
63
69
  );
64
70
  }
65
71
 
@@ -156,7 +162,9 @@ function requiredSymbolCallOwnerId(
156
162
  );
157
163
  if (selected.status !== 'resolved'
158
164
  || selected.owner?.qualifiedName !== call.callerQualifiedName)
159
- throw new Error('invalid_prepared_repository_snapshot:symbol_call_owner_mismatch');
165
+ throw preparedCallSnapshotError(
166
+ 'symbol_call_owner_mismatch', 'symbol_call', call,
167
+ );
160
168
  return selected.owner.id;
161
169
  }
162
170
 
@@ -265,9 +273,11 @@ function exportedSymbolRows(db: Db, repoId: number, r: SymbolCallFact): SymbolTa
265
273
  ));
266
274
  }
267
275
 
268
- function isRelativeImportedSymbolCall(r: SymbolCallFact): boolean {
269
- return Boolean(r.importSource?.startsWith('.'));
270
- }
276
+ const sameFileEligibleRelations = new Set([
277
+ 'indexed_local_symbol',
278
+ 'indexed_local_symbol_unproven',
279
+ 'indexed_this_method',
280
+ ]);
271
281
 
272
282
  function eligibleSymbolResolution(
273
283
  rows: SymbolTargetRow[],
@@ -292,8 +302,7 @@ function sameFileResolution(
292
302
  r: SymbolCallFact,
293
303
  relation: unknown,
294
304
  ): SymbolCallResolution | undefined {
295
- if (isRelativeImportedSymbolCall(r) || relation === 'package_import')
296
- return undefined;
305
+ if (!sameFileEligibleRelations.has(String(relation))) return undefined;
297
306
  if (relation === 'indexed_local_symbol_unproven')
298
307
  return unresolvedSymbol(
299
308
  'exact_symbol_match', 'no_local_symbol_target', 0,
@@ -452,6 +461,7 @@ interface PersistedBinding {
452
461
  ownerResolution: string;
453
462
  ownerStartOffset: number | null;
454
463
  ownerEndOffset: number | null;
464
+ singleHopHelperReturn: boolean;
455
465
  }
456
466
 
457
467
  function outboundOwnerId(
@@ -471,13 +481,18 @@ function outboundOwnerId(
471
481
  );
472
482
  const resolution = call.evidence?.sourceOwnerResolution;
473
483
  if (resolution === 'ownerless_file_scope')
474
- return ownerlessOutboundOwner(selected.status);
484
+ return ownerlessOutboundOwner(call, selected.status);
475
485
  return ownedOutboundOwner(call, resolution, selected);
476
486
  }
477
487
 
478
- function ownerlessOutboundOwner(status: string): null {
488
+ function ownerlessOutboundOwner(
489
+ call: OutboundCallFact,
490
+ status: string,
491
+ ): null {
479
492
  if (status !== 'none')
480
- throw new Error('invalid_prepared_repository_snapshot:outbound_owner_mismatch');
493
+ throw preparedCallSnapshotError(
494
+ 'outbound_owner_mismatch', 'outbound_call', call,
495
+ );
481
496
  return null;
482
497
  }
483
498
 
@@ -488,10 +503,14 @@ function ownedOutboundOwner(
488
503
  ): number {
489
504
  if (resolution !== 'owned_exact' || selected.status !== 'resolved'
490
505
  || selected.owner?.qualifiedName !== call.sourceSymbolQualifiedName)
491
- throw new Error('invalid_prepared_repository_snapshot:outbound_owner_mismatch');
506
+ throw preparedCallSnapshotError(
507
+ 'outbound_owner_mismatch', 'outbound_call', call,
508
+ );
492
509
  const owner = selected.owner;
493
510
  if (!owner)
494
- throw new Error('invalid_prepared_repository_snapshot:outbound_owner_mismatch');
511
+ throw preparedCallSnapshotError(
512
+ 'outbound_owner_mismatch', 'outbound_call', call,
513
+ );
495
514
  return owner.id;
496
515
  }
497
516
 
@@ -506,14 +525,18 @@ function resolvePersistedBinding(
506
525
  } {
507
526
  const reference = call.serviceBindingReference;
508
527
  if (!reference)
509
- throw new Error('invalid_prepared_repository_snapshot:binding_reference_missing');
528
+ throw preparedCallSnapshotError(
529
+ 'binding_reference_missing', 'outbound_call', call,
530
+ );
510
531
  if (reference.status !== 'resolved_exact')
511
532
  return unresolvedBinding(reference);
512
533
  const candidates = exactBindingRows(db, repoId, reference);
513
534
  const selected = candidates[0];
514
535
  if (candidates.length !== 1 || !selected
515
536
  || selected.variableName !== call.serviceVariableName)
516
- throw new Error('invalid_prepared_repository_snapshot:binding_reference_mismatch');
537
+ throw preparedCallSnapshotError(
538
+ 'binding_reference_mismatch', 'outbound_call', call,
539
+ );
517
540
  assertResolvedBindingProof(repoId, call, selected, reference);
518
541
  return {
519
542
  bindingId: selected.id,
@@ -533,8 +556,8 @@ function bindingProofCall(
533
556
  ): BindingProofCall {
534
557
  if (call.callSiteStartOffset === undefined
535
558
  || call.callSiteEndOffset === undefined)
536
- throw new Error(
537
- 'invalid_prepared_repository_snapshot:binding_lexical_proof_invalid',
559
+ throw preparedCallSnapshotError(
560
+ 'binding_lexical_proof_invalid', 'outbound_call', call,
538
561
  );
539
562
  return {
540
563
  repoId,
@@ -561,6 +584,7 @@ function bindingProofTarget(
561
584
  ownerResolution: binding.ownerResolution,
562
585
  ownerStartOffset: binding.ownerStartOffset,
563
586
  ownerEndOffset: binding.ownerEndOffset,
587
+ singleHopHelperReturn: binding.singleHopHelperReturn,
564
588
  };
565
589
  }
566
590
 
@@ -576,8 +600,8 @@ function assertResolvedBindingProof(
576
600
  bindingProofTarget(repoId, binding),
577
601
  );
578
602
  if (!valid)
579
- throw new Error(
580
- 'invalid_prepared_repository_snapshot:binding_lexical_proof_invalid',
603
+ throw preparedCallSnapshotError(
604
+ 'binding_lexical_proof_invalid', 'outbound_call', call,
581
605
  );
582
606
  }
583
607
 
@@ -608,6 +632,7 @@ function exactBindingRows(
608
632
  binding.binding_site_start_offset siteStart,
609
633
  binding.binding_site_end_offset siteEnd,
610
634
  binding.owner_resolution ownerResolution,
635
+ binding.helper_chain_json helperChainJson,
611
636
  owner.start_offset ownerStartOffset,owner.end_offset ownerEndOffset
612
637
  FROM service_bindings binding
613
638
  LEFT JOIN symbols owner ON owner.id=binding.symbol_id
@@ -642,6 +667,7 @@ function persistedBindingRow(
642
667
  ownerResolution: row.ownerResolution,
643
668
  ownerStartOffset,
644
669
  ownerEndOffset,
670
+ singleHopHelperReturn: hasSingleHopHelperReturn(row.helperChainJson),
645
671
  }];
646
672
  }
647
673
 
@@ -3,16 +3,16 @@ import type { CallType, RepoKind } from '../types.js';
3
3
  import { ANALYZER_VERSION } from '../version.js';
4
4
  import {
5
5
  invalidPackageFactCategories,
6
- } from './007-package-fact-semantics.js';
6
+ } from './package-fact-semantics.js';
7
7
  import {
8
8
  invalidRelativeFactCategories,
9
- } from './008-relative-fact-semantics.js';
9
+ } from './relative-fact-semantics.js';
10
10
  import {
11
11
  invalidBindingFactCategories,
12
- } from './009-binding-fact-semantics.js';
12
+ } from './binding-fact-semantics.js';
13
13
  import {
14
14
  invalidSymbolFactCategories,
15
- } from './011-symbol-call-semantics.js';
15
+ } from './symbol-call-semantics.js';
16
16
 
17
17
  export type PackageFactPhase = 'pre_package' | 'terminal';
18
18
 
@@ -71,6 +71,7 @@ const symbolReasons = [
71
71
  'relative_import_type_only',
72
72
  'relative_import_module_resolution_ambiguous',
73
73
  'relative_import_requested_module_has_no_executable_body',
74
+ 'relative_import_proxy_alias_targets_package_unsupported',
74
75
  'relative_import_requested_module_has_no_target',
75
76
  'multiple_relative_class_targets_in_requested_module',
76
77
  'multiple_namespace_targets_in_requested_module',
@@ -3,16 +3,16 @@ import { CURRENT_SCHEMA_VERSION, schemaVersion } from './migrations.js';
3
3
  import {
4
4
  invalidFactJsonCategories,
5
5
  type FactJsonCategoryCount,
6
- } from './002-fact-json-inventory.js';
6
+ } from './fact-json-inventory.js';
7
7
  import {
8
8
  invalidFactSemanticCategories,
9
9
  type FactSemanticCategoryCount,
10
10
  type PackageFactPhase,
11
- } from './003-current-fact-semantics.js';
11
+ } from './current-fact-semantics.js';
12
12
  import {
13
13
  invalidSchemaStructureCategories,
14
14
  type SchemaStructureCategoryCount,
15
- } from './005-schema-structure.js';
15
+ } from './schema-structure.js';
16
16
  import { ANALYZER_VERSION } from '../version.js';
17
17
 
18
18
  export type FactLifecycleCode =
@@ -0,0 +1,91 @@
1
+ import type { Db } from './connection.js';
2
+
3
+ export type PreparedRepositoryFactKind =
4
+ | 'outbound_call'
5
+ | 'service_binding'
6
+ | 'symbol_call';
7
+
8
+ export type PreparedSnapshotFailureCode =
9
+ | 'binding_lexical_proof_invalid'
10
+ | 'binding_owner_mismatch'
11
+ | 'binding_reference_mismatch'
12
+ | 'binding_reference_missing'
13
+ | 'binding_site_missing'
14
+ | 'duplicate_service_binding_site'
15
+ | 'outbound_owner_mismatch'
16
+ | 'package_import_provenance_missing'
17
+ | 'symbol_call_owner_mismatch';
18
+
19
+ export interface PreparedSnapshotFailureSite {
20
+ factKind: PreparedRepositoryFactKind;
21
+ sourceFile?: string;
22
+ sourceLine?: number;
23
+ callSiteStartOffset?: number;
24
+ callSiteEndOffset?: number;
25
+ }
26
+
27
+ export class PreparedRepositorySnapshotError extends Error {
28
+ readonly failureCode: PreparedSnapshotFailureCode;
29
+ readonly site: PreparedSnapshotFailureSite;
30
+
31
+ constructor(
32
+ failureCode: PreparedSnapshotFailureCode,
33
+ site: PreparedSnapshotFailureSite,
34
+ ) {
35
+ super(`invalid_prepared_repository_snapshot:${failureCode}`);
36
+ this.name = 'PreparedRepositorySnapshotError';
37
+ this.failureCode = failureCode;
38
+ this.site = site;
39
+ }
40
+ }
41
+
42
+ interface PreparedCallSite {
43
+ sourceFile: string;
44
+ sourceLine: number;
45
+ callSiteStartOffset?: number;
46
+ callSiteEndOffset?: number;
47
+ }
48
+
49
+ export function preparedCallSnapshotError(
50
+ failureCode: PreparedSnapshotFailureCode,
51
+ factKind: 'outbound_call' | 'symbol_call',
52
+ call: PreparedCallSite,
53
+ ): PreparedRepositorySnapshotError {
54
+ return new PreparedRepositorySnapshotError(failureCode, {
55
+ factKind,
56
+ sourceFile: call.sourceFile,
57
+ sourceLine: call.sourceLine,
58
+ callSiteStartOffset: call.callSiteStartOffset,
59
+ callSiteEndOffset: call.callSiteEndOffset,
60
+ });
61
+ }
62
+
63
+ export function isPreparedRepositorySnapshotError(
64
+ error: unknown,
65
+ ): error is PreparedRepositorySnapshotError {
66
+ return error instanceof PreparedRepositorySnapshotError;
67
+ }
68
+
69
+ export function recordPreparedSnapshotFailure(
70
+ db: Db,
71
+ repoId: number,
72
+ error: PreparedRepositorySnapshotError,
73
+ ): void {
74
+ db.prepare(`UPDATE repositories SET index_status='failed',
75
+ error_count=1 WHERE id=?`).run(repoId);
76
+ db.prepare(`DELETE FROM diagnostics WHERE repo_id=? AND (
77
+ code IN ('index_failed_snapshot_preserved','source_read_failed')
78
+ OR code GLOB 'invalid_prepared_repository_snapshot:*'
79
+ )`).run(repoId);
80
+ db.prepare(`INSERT INTO diagnostics(
81
+ repo_id,severity,code,message,source_file,source_line
82
+ ) VALUES(?,?,?,?,?,?)`).run(
83
+ repoId,
84
+ 'error',
85
+ error.message,
86
+ 'Index publication failed before commit for this repository; previous facts and fingerprint were preserved. '
87
+ + `factKind=${error.site.factKind}`,
88
+ error.site.sourceFile,
89
+ error.site.sourceLine,
90
+ );
91
+ }
@@ -4,21 +4,21 @@ import type {
4
4
  PackagePublicScope,
5
5
  PackagePublicSurfaceFact,
6
6
  PublicSurfaceTarget,
7
- } from '../parsers/003-package-public-surface.js';
7
+ } from '../parsers/package-public-surface.js';
8
8
  import {
9
9
  parsePackageImportReference,
10
10
  parsePackagePublicSurfaceFact,
11
- } from '../parsers/012-package-fact-contract.js';
11
+ } from '../parsers/package-fact-contract.js';
12
12
  import type { SymbolImportReference } from
13
- '../parsers/002-symbol-import-bindings.js';
14
- import type { PackageFactPhase } from './003-current-fact-semantics.js';
13
+ '../parsers/symbol-import-bindings.js';
14
+ import type { PackageFactPhase } from './current-fact-semantics.js';
15
15
  import {
16
16
  expectedPackageImportResolutions,
17
17
  type PackageCallResolution,
18
- } from '../linker/003-package-import-symbol-resolver.js';
18
+ } from '../linker/package-import-symbol-resolver.js';
19
19
  import {
20
20
  invalidPackageSymbolSurfaceCount,
21
- } from './010-package-symbol-surface-semantics.js';
21
+ } from './package-symbol-surface-semantics.js';
22
22
 
23
23
  export interface PackageFactCategoryCount {
24
24
  category: string;
@@ -6,10 +6,10 @@ import {
6
6
  type PackagePublicScope,
7
7
  type PackagePublicSurfaceFact,
8
8
  type PublicSurfaceTarget,
9
- } from '../parsers/003-package-public-surface.js';
9
+ } from '../parsers/package-public-surface.js';
10
10
  import {
11
11
  parsePackagePublicSurfaceFact,
12
- } from '../parsers/012-package-fact-contract.js';
12
+ } from '../parsers/package-fact-contract.js';
13
13
  import type { Db } from './connection.js';
14
14
 
15
15
  interface Exposure {
@@ -2,7 +2,7 @@ import type { Db } from './connection.js';
2
2
  import { ANALYZER_VERSION } from '../version.js';
3
3
  import {
4
4
  parsePackageImportReference,
5
- } from '../parsers/012-package-fact-contract.js';
5
+ } from '../parsers/package-fact-contract.js';
6
6
 
7
7
  interface PackageCallRow {
8
8
  id: number;
@@ -157,6 +157,16 @@ export function createPackageInvalidationBatch(
157
157
  };
158
158
  }
159
159
 
160
+ export function mergePackageInvalidationEffects(
161
+ target: PackageInvalidationBatch,
162
+ source: PackageInvalidationBatch,
163
+ ): void {
164
+ for (const repoId of source.affectedCallerRepoIds)
165
+ target.affectedCallerRepoIds.add(repoId);
166
+ for (const workspaceId of source.affectedWorkspaceIds)
167
+ target.affectedWorkspaceIds.add(workspaceId);
168
+ }
169
+
160
170
  export function finalizePackageTargetInvalidations(
161
171
  db: Db,
162
172
  batch: PackageInvalidationBatch,
@@ -2,12 +2,12 @@ import type { Db } from './connection.js';
2
2
  import { ANALYZER_VERSION } from '../version.js';
3
3
  import {
4
4
  resolveRelativeSymbolCall,
5
- } from './006-relative-symbol-resolution.js';
5
+ } from './relative-symbol-resolution.js';
6
6
  import type { SymbolCallFact } from '../types.js';
7
7
  import { parseRelativeImportReference } from
8
- '../parsers/012-package-fact-contract.js';
8
+ '../parsers/package-fact-contract.js';
9
9
  import type { SymbolImportReference } from
10
- '../parsers/002-symbol-import-bindings.js';
10
+ '../parsers/symbol-import-bindings.js';
11
11
 
12
12
  export interface RelativeFactCategoryCount {
13
13
  category: string;
@@ -81,9 +81,12 @@ function derivedRelativeProvenance(
81
81
  targetName: string,
82
82
  ): boolean {
83
83
  if (!memberReference(binding)) return false;
84
- if (evidence.relation === 'class_instance_method')
85
- return targetName === binding.requestedPublicName
86
- && evidence.methodName === binding.referencedMemberName;
84
+ if (evidence.relation === 'class_instance_method') {
85
+ if (evidence.methodName !== binding.referencedMemberName) return false;
86
+ return binding.bindingKind === 'esm_default'
87
+ ? targetName === `${binding.localName}.${binding.referencedMemberName}`
88
+ : targetName === binding.requestedPublicName;
89
+ }
87
90
  if (evidence.relation !== 'relative_import_proxy_member') return false;
88
91
  return targetName === binding.referencedMemberName
89
92
  && typeof evidence.proxyVariableName === 'string';
@@ -1,5 +1,7 @@
1
1
  import { posix } from 'node:path';
2
2
  import type { SymbolCallFact } from '../types.js';
3
+ import { packageModuleRequest } from
4
+ '../parsers/symbol-import-bindings.js';
3
5
  import type { Db } from './connection.js';
4
6
 
5
7
  export interface RelativeSymbolCallResolution {
@@ -33,6 +35,7 @@ interface MappingTarget {
33
35
  interface MappedExecutableRows {
34
36
  rows: TargetRow[];
35
37
  ambiguous: boolean;
38
+ packageTargetUnsupported: boolean;
36
39
  }
37
40
 
38
41
  const stripExtension = (value: string): string =>
@@ -138,8 +141,12 @@ function handlerMemberPubliclyCarried(
138
141
  ): boolean {
139
142
  if (row.exported) return true;
140
143
  const evidence = parsedRecord(row.evidenceJson);
141
- return evidence?.source === 'exported_class_instance_member'
142
- && evidence.exportedClass === binding.importedName;
144
+ if (evidence?.source !== 'exported_class_instance_member') return false;
145
+ const exportKind = evidence.exportedClassExportKind;
146
+ if (exportKind !== 'default' && exportKind !== 'named') return false;
147
+ return binding.bindingKind === 'esm_default'
148
+ ? exportKind === 'default'
149
+ : evidence.exportedClass === binding.importedName;
143
150
  }
144
151
 
145
152
  function requiresPublicClassMember(
@@ -287,9 +294,12 @@ function mappingTargetScope(
287
294
  ): RelativeModuleScope | undefined {
288
295
  const target = mappingTarget(row);
289
296
  if (!target) return undefined;
290
- return target.specifier
291
- ? relativeModuleScope(db, repoId, row.sourceFile, target.specifier)
292
- : { paths: new Set([stripExtension(row.sourceFile)]), ambiguous: false };
297
+ if (!target.specifier)
298
+ return {
299
+ paths: new Set([stripExtension(row.sourceFile)]), ambiguous: false,
300
+ };
301
+ if (packageModuleRequest(target.specifier)) return undefined;
302
+ return relativeModuleScope(db, repoId, row.sourceFile, target.specifier);
293
303
  }
294
304
 
295
305
  function mappedExecutableRows(
@@ -298,18 +308,24 @@ function mappedExecutableRows(
298
308
  rows: readonly TargetRow[],
299
309
  aliases: readonly TargetRow[],
300
310
  ): MappedExecutableRows {
311
+ const packageTargetUnsupported = aliases.some((alias) => {
312
+ const target = mappingTarget(alias);
313
+ return Boolean(target?.specifier && packageModuleRequest(target.specifier));
314
+ });
301
315
  const scopes = aliases.flatMap((alias) => {
302
316
  const scope = mappingTargetScope(db, repoId, alias);
303
317
  return scope ? [scope] : [];
304
318
  });
305
319
  if (scopes.some((scope) => scope.ambiguous))
306
- return { rows: [], ambiguous: true };
320
+ return { rows: [], ambiguous: true, packageTargetUnsupported };
307
321
  const mapped = scopes.flatMap((scope) => {
308
322
  return rows.filter((row) =>
309
323
  row.kind !== 'object_alias' && bodyEligible(row)
310
324
  && scope.paths.has(stripExtension(row.sourceFile)));
311
325
  });
312
- return { rows: uniqueRows(mapped), ambiguous: false };
326
+ return {
327
+ rows: uniqueRows(mapped), ambiguous: false, packageTargetUnsupported,
328
+ };
313
329
  }
314
330
 
315
331
  function proxyResolution(
@@ -326,6 +342,11 @@ function proxyResolution(
326
342
  'relative_import_module_resolution_ambiguous',
327
343
  rows.length, 0, false,
328
344
  );
345
+ if (mapped.packageTargetUnsupported) return unresolved(
346
+ 'proxy_member_exported_object_map',
347
+ 'relative_import_proxy_alias_targets_package_unsupported',
348
+ rows.length,
349
+ );
329
350
  const direct = scoped.filter((row) =>
330
351
  row.kind !== 'object_alias' && row.exported && bodyEligible(row));
331
352
  const eligible = uniqueRows([
@@ -11,7 +11,11 @@ import type {
11
11
  import {
12
12
  selectCallOwner,
13
13
  type OwnerCandidate,
14
- } from '../parsers/004-fact-identity.js';
14
+ } from '../parsers/fact-identity.js';
15
+ import {
16
+ PreparedRepositorySnapshotError,
17
+ type PreparedSnapshotFailureCode,
18
+ } from './index-publication-failure.js';
15
19
  export interface RepoRow {
16
20
  id: number;
17
21
  name: string;
@@ -414,6 +418,19 @@ interface PersistedOwnerCandidate extends OwnerCandidate {
414
418
  id: number;
415
419
  }
416
420
 
421
+ function bindingSnapshotError(
422
+ failureCode: PreparedSnapshotFailureCode,
423
+ fact: ServiceBindingFact,
424
+ ): PreparedRepositorySnapshotError {
425
+ return new PreparedRepositorySnapshotError(failureCode, {
426
+ factKind: 'service_binding',
427
+ sourceFile: fact.sourceFile,
428
+ sourceLine: fact.sourceLine,
429
+ callSiteStartOffset: fact.bindingSiteStartOffset,
430
+ callSiteEndOffset: fact.bindingSiteEndOffset,
431
+ });
432
+ }
433
+
417
434
  function persistedOwnerCandidates(
418
435
  db: Db,
419
436
  repoId: number,
@@ -454,16 +471,16 @@ function bindingOwnerId(
454
471
  );
455
472
  if (fact.ownerResolution === 'ownerless_file_scope') {
456
473
  if (selected.status !== 'none')
457
- throw new Error('invalid_prepared_repository_snapshot:binding_owner_mismatch');
474
+ throw bindingSnapshotError('binding_owner_mismatch', fact);
458
475
  return null;
459
476
  }
460
477
  if (fact.ownerResolution !== 'owned_exact'
461
478
  || selected.status !== 'resolved'
462
479
  || selected.owner?.qualifiedName !== fact.sourceSymbolQualifiedName)
463
- throw new Error('invalid_prepared_repository_snapshot:binding_owner_mismatch');
480
+ throw bindingSnapshotError('binding_owner_mismatch', fact);
464
481
  const owner = selected.owner;
465
482
  if (!owner)
466
- throw new Error('invalid_prepared_repository_snapshot:binding_owner_mismatch');
483
+ throw bindingSnapshotError('binding_owner_mismatch', fact);
467
484
  return owner.id;
468
485
  }
469
486
 
@@ -474,13 +491,13 @@ function assertUniquePreparedBindingSites(
474
491
  for (const row of rows) {
475
492
  if (row.bindingSiteStartOffset === undefined
476
493
  || row.bindingSiteEndOffset === undefined)
477
- throw new Error('invalid_prepared_repository_snapshot:binding_site_missing');
494
+ throw bindingSnapshotError('binding_site_missing', row);
478
495
  const key = [
479
496
  row.sourceFile, row.variableName,
480
497
  row.bindingSiteStartOffset, row.bindingSiteEndOffset,
481
498
  ].join('\u0000');
482
499
  if (seen.has(key))
483
- throw new Error('invalid_prepared_repository_snapshot:duplicate_service_binding_site');
500
+ throw bindingSnapshotError('duplicate_service_binding_site', row);
484
501
  seen.add(key);
485
502
  }
486
503
  }
@@ -488,4 +505,4 @@ export function insertExecutableSymbols(db: Db, repoId: number, rows: Executable
488
505
  const stmt = db.prepare('INSERT INTO symbols(repo_id,file_id,kind,name,qualified_name,exported,start_line,end_line,start_offset,end_offset,source_file,exported_name,evidence_json) VALUES(?,(SELECT id FROM files WHERE repo_id=? AND relative_path=?),?,?,?,?,?,?,?,?,?,?,?)');
489
506
  for (const r of rows) stmt.run(repoId, repoId, r.sourceFile, r.kind, r.localName, r.qualifiedName, r.exported ? 1 : 0, r.startLine, r.endLine, r.startOffset, r.endOffset, r.sourceFile, r.exportedName, r.importExportEvidence ? JSON.stringify(r.importExportEvidence) : null);
490
507
  }
491
- export { insertCalls, insertSymbolCalls } from './000-call-fact-repository.js';
508
+ export { insertCalls, insertSymbolCalls } from './call-fact-repository.js';
@@ -1,6 +1,6 @@
1
1
  import type { SymbolCallFact } from '../types.js';
2
2
  import { ANALYZER_VERSION } from '../version.js';
3
- import { resolveSymbolCallTarget } from './000-call-fact-repository.js';
3
+ import { resolveSymbolCallTarget } from './call-fact-repository.js';
4
4
  import type { Db } from './connection.js';
5
5
 
6
6
  export interface SymbolFactCategoryCount {
package/src/index.ts CHANGED
@@ -13,8 +13,8 @@ export { trace } from './trace/trace-engine.js';
13
13
  export {
14
14
  compactTrace,
15
15
  traceAndCompact,
16
- } from './trace/018-compact-trace.js';
17
- export type { CompactTraceExecution } from './trace/018-compact-trace.js';
16
+ } from './trace/compact-trace.js';
17
+ export type { CompactTraceExecution } from './trace/compact-trace.js';
18
18
  export type {
19
19
  CompactDecisionV1,
20
20
  CompactDiagnosticDetailsV1,
@@ -31,7 +31,7 @@ export type {
31
31
  CompactStartV1,
32
32
  CompactStatus,
33
33
  CompactStatusCountsV1,
34
- } from './trace/014-compact-contract.js';
34
+ } from './trace/compact-contract.js';
35
35
  export { parseImplementationHint } from './trace/implementation-hints.js';
36
36
  export type { DynamicMode, ImplementationHint, TraceOptions } from './types.js';
37
37
  export { redactValue, redactText } from './utils/redaction.js';
@@ -15,9 +15,12 @@ interface BaseRow { id: number; repoId: number }
15
15
  interface DesiredOperation { id: number; operationType: string; operationName: string; operationPath: string; paramsJson: string; returnType: string | null; sourceFile: string; sourceLine: number }
16
16
  interface ExistingOperation extends DesiredOperation { baseOperationId: number | null }
17
17
 
18
- export function materializeCdsExtensionOperations(db: Db, workspaceId: number): void {
19
- const extensions = db.prepare(`SELECT s.id,r.id repoId,s.service_name serviceName,s.qualified_name qualifiedName,s.source_file sourceFile,s.extension_module_specifier moduleSpecifier,s.extension_imported_symbol importedSymbol,s.extension_import_kind importKind
20
- FROM cds_services s JOIN repositories r ON r.id=s.repo_id WHERE r.workspace_id=? AND s.is_extend=1`).all(workspaceId) as unknown as ExtensionRow[];
18
+ export function materializeCdsExtensionOperations(
19
+ db: Db,
20
+ workspaceId: number,
21
+ excludedRepoIds: ReadonlySet<number> = new Set(),
22
+ ): void {
23
+ const extensions = extensionRows(db, workspaceId, excludedRepoIds);
21
24
  db.transaction(() => {
22
25
  const changedRepos = new Set<number>();
23
26
  for (const extension of extensions) {
@@ -27,6 +30,27 @@ export function materializeCdsExtensionOperations(db: Db, workspaceId: number):
27
30
  });
28
31
  }
29
32
 
33
+ function extensionRows(
34
+ db: Db,
35
+ workspaceId: number,
36
+ excludedRepoIds: ReadonlySet<number>,
37
+ ): ExtensionRow[] {
38
+ const excluded = [...excludedRepoIds].sort((left, right) => left - right);
39
+ const exclusion = excluded.length > 0
40
+ ? ` AND r.id NOT IN (${excluded.map(() => '?').join(',')})`
41
+ : '';
42
+ return db.prepare(`SELECT s.id,r.id repoId,s.service_name serviceName,
43
+ s.qualified_name qualifiedName,s.source_file sourceFile,
44
+ s.extension_module_specifier moduleSpecifier,
45
+ s.extension_imported_symbol importedSymbol,
46
+ s.extension_import_kind importKind
47
+ FROM cds_services s JOIN repositories r ON r.id=s.repo_id
48
+ WHERE r.workspace_id=? AND s.is_extend=1${exclusion}
49
+ ORDER BY r.id,s.id`).all(
50
+ workspaceId, ...excluded,
51
+ ) as unknown as ExtensionRow[];
52
+ }
53
+
30
54
  function reconcileExtension(db: Db, workspaceId: number, extension: ExtensionRow): boolean {
31
55
  const bases = resolveBase(db, workspaceId, extension);
32
56
  const status = bases.length === 1 ? 'resolved' : bases.length > 1 ? 'ambiguous' : 'unresolved';