@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.
- package/CHANGELOG.md +14 -0
- package/README.md +11 -5
- package/TECHNICAL-NOTE.md +13 -0
- package/dist/{chunk-AEM4JY22.js → chunk-GSLFY6J2.js} +6986 -5503
- package/dist/chunk-GSLFY6J2.js.map +1 -0
- package/dist/cli.js +334 -122
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/cli/{002-doctor-lifecycle.ts → doctor-lifecycle.ts} +1 -1
- package/src/cli/{001-doctor-projection.ts → doctor-projection.ts} +1 -1
- package/src/cli/doctor.ts +5 -5
- package/src/cli/index-summary.ts +22 -0
- package/src/cli.ts +155 -91
- package/src/db/{009-binding-fact-semantics.ts → binding-fact-semantics.ts} +6 -1
- package/src/db/binding-helper-provenance.ts +17 -0
- package/src/db/{012-binding-reference-proof.ts → binding-reference-proof.ts} +4 -0
- package/src/db/{000-call-fact-repository.ts → call-fact-repository.ts} +49 -23
- package/src/db/{003-current-fact-semantics.ts → current-fact-semantics.ts} +5 -4
- package/src/db/{001-fact-lifecycle.ts → fact-lifecycle.ts} +3 -3
- package/src/db/index-publication-failure.ts +91 -0
- package/src/db/{007-package-fact-semantics.ts → package-fact-semantics.ts} +6 -6
- package/src/db/{010-package-symbol-surface-semantics.ts → package-symbol-surface-semantics.ts} +2 -2
- package/src/db/{004-package-target-invalidation.ts → package-target-invalidation.ts} +11 -1
- package/src/db/{008-relative-fact-semantics.ts → relative-fact-semantics.ts} +9 -6
- package/src/db/{006-relative-symbol-resolution.ts → relative-symbol-resolution.ts} +28 -7
- package/src/db/repositories.ts +24 -7
- package/src/db/{011-symbol-call-semantics.ts → symbol-call-semantics.ts} +1 -1
- package/src/index.ts +3 -3
- package/src/indexer/cds-extension-resolver.ts +27 -3
- package/src/indexer/repository-indexer.ts +70 -9
- package/src/indexer/workspace-indexer.ts +142 -30
- package/src/linker/call-edge-insertion.ts +568 -0
- package/src/linker/{002-call-evidence.ts → call-evidence.ts} +2 -2
- package/src/linker/cross-repo-linker.ts +6 -169
- package/src/linker/dynamic-edge-resolver.ts +1 -1
- package/src/linker/{004-event-subscription-handler-linker.ts → event-subscription-handler-linker.ts} +32 -11
- package/src/linker/event-template-link.ts +72 -0
- package/src/linker/external-http-target.ts +1 -1
- package/src/linker/helper-package-linker.ts +1 -1
- package/src/linker/{000-implementation-candidates.ts → implementation-candidates.ts} +1 -1
- package/src/linker/{001-implementation-evidence-projection.ts → implementation-evidence-projection.ts} +1 -1
- package/src/linker/odata-path-normalizer.ts +1 -1
- package/src/linker/{005-odata-path-structure.ts → odata-path-structure.ts} +1 -1
- package/src/linker/{003-package-import-symbol-resolver.ts → package-import-symbol-resolver.ts} +3 -3
- package/src/linker/service-resolver.ts +2 -2
- package/src/output/{001-compact-json-output.ts → compact-json-output.ts} +1 -1
- package/src/parsers/{006-binding-identity.ts → binding-identity.ts} +9 -4
- package/src/parsers/{011-binding-lexical-scope.ts → binding-lexical-scope.ts} +1 -1
- package/src/parsers/{021-binding-visibility.ts → binding-visibility.ts} +18 -2
- package/src/parsers/{000-direct-query-execution.ts → direct-query-execution.ts} +11 -0
- package/src/parsers/{005-event-subscription-facts.ts → event-subscription-facts.ts} +2 -2
- package/src/parsers/{016-local-symbol-reference.ts → local-symbol-reference.ts} +2 -2
- package/src/parsers/operation-path-analysis.ts +1 -1
- package/src/parsers/outbound-call-classifier.ts +692 -0
- package/src/parsers/outbound-call-parser.ts +146 -509
- package/src/parsers/outbound-expression-analysis.ts +700 -0
- package/src/parsers/{018-package-commonjs-syntax.ts → package-commonjs-syntax.ts} +1 -1
- package/src/parsers/{012-package-fact-contract.ts → package-fact-contract.ts} +3 -3
- package/src/parsers/{010-package-public-surface-analysis.ts → package-public-surface-analysis.ts} +2 -2
- package/src/parsers/{003-package-public-surface.ts → package-public-surface.ts} +3 -3
- package/src/parsers/{008-package-surface-publication.ts → package-surface-publication.ts} +1 -1
- package/src/parsers/{001-query-entity-resolution.ts → query-entity-resolution.ts} +1 -1
- package/src/parsers/{015-service-binding-collector.ts → service-binding-collector.ts} +3 -3
- package/src/parsers/{014-service-binding-helper-flow.ts → service-binding-helper-flow.ts} +72 -6
- package/src/parsers/service-binding-parser-helpers.ts +1 -1
- package/src/parsers/service-binding-parser.ts +2 -2
- package/src/parsers/{007-source-fact-reconciliation.ts → source-fact-reconciliation.ts} +3 -3
- package/src/parsers/{020-stable-local-value.ts → stable-local-value.ts} +2 -2
- package/src/parsers/{009-symbol-call-facts.ts → symbol-call-facts.ts} +3 -3
- package/src/parsers/{017-symbol-derived-contexts.ts → symbol-derived-contexts.ts} +2 -2
- package/src/parsers/symbol-parser.ts +43 -11
- package/src/trace/{014-compact-contract.ts → compact-contract.ts} +6 -0
- package/src/trace/{021-compact-decision-normalization.ts → compact-decision-normalization.ts} +77 -11
- package/src/trace/{020-compact-field-projection.ts → compact-field-projection.ts} +77 -4
- package/src/trace/{024-compact-observation-decision.ts → compact-observation-decision.ts} +10 -5
- package/src/trace/{016-compact-projector.ts → compact-projector.ts} +6 -7
- package/src/trace/{018-compact-trace.ts → compact-trace.ts} +3 -3
- package/src/trace/{006-contextual-projection.ts → contextual-projection.ts} +1 -1
- package/src/trace/{008-contextual-runtime-state.ts → contextual-runtime-state.ts} +1 -1
- package/src/trace/{001-dynamic-identity.ts → dynamic-identity.ts} +2 -2
- package/src/trace/{003-dynamic-references.ts → dynamic-references.ts} +2 -2
- package/src/trace/dynamic-targets.ts +6 -6
- package/src/trace/event-runtime-resolution.ts +151 -0
- package/src/trace/{011-event-subscriber-traversal.ts → event-subscriber-traversal.ts} +101 -9
- package/src/trace/evidence.ts +2 -2
- package/src/trace/implementation-hints.ts +10 -7
- package/src/trace/{005-implementation-selection.ts → implementation-selection.ts} +2 -2
- package/src/trace/{007-implementation-start-diagnostic.ts → implementation-start-diagnostic.ts} +1 -0
- package/src/trace/local-call-expansion.ts +37 -0
- package/src/trace/{009-selected-handler-provenance.ts → selected-handler-provenance.ts} +1 -1
- package/src/trace/selectors.ts +2 -1
- package/src/trace/{017-trace-context.ts → trace-context.ts} +2 -2
- package/src/trace/{015-trace-edge-recorder.ts → trace-edge-recorder.ts} +62 -5
- package/src/trace/{019-trace-edge-semantics.ts → trace-edge-semantics.ts} +9 -13
- package/src/trace/trace-engine.ts +10 -10
- package/src/trace/{022-trace-fact-preflight.ts → trace-fact-preflight.ts} +2 -2
- package/src/trace/{025-trace-implementation-scope.ts → trace-implementation-scope.ts} +1 -1
- package/src/trace/{028-trace-operation-execution.ts → trace-operation-execution.ts} +10 -10
- package/src/trace/{013-trace-root-scopes.ts → trace-root-scopes.ts} +5 -6
- package/src/trace/{027-trace-scope-execution.ts → trace-scope-execution.ts} +44 -44
- package/src/trace/{029-trace-start-implementation.ts → trace-start-implementation.ts} +7 -7
- package/src/trace/{026-trace-start-scope.ts → trace-start-scope.ts} +6 -5
- package/src/trace/{010-traversal-scope.ts → traversal-scope.ts} +1 -1
- package/src/types.ts +2 -1
- package/src/version.ts +1 -1
- package/dist/chunk-AEM4JY22.js.map +0 -1
- /package/src/cli/{000-clean.ts → clean.ts} +0 -0
- /package/src/cli/{003-doctor-package-resolution.ts → doctor-package-resolution.ts} +0 -0
- /package/src/db/{002-fact-json-inventory.ts → fact-json-inventory.ts} +0 -0
- /package/src/db/{005-schema-structure.ts → schema-structure.ts} +0 -0
- /package/src/output/{000-stdout-policy.ts → stdout-policy.ts} +0 -0
- /package/src/parsers/{019-binding-assignment-targets.ts → binding-assignment-targets.ts} +0 -0
- /package/src/parsers/{013-executable-body-eligibility.ts → executable-body-eligibility.ts} +0 -0
- /package/src/parsers/{004-fact-identity.ts → fact-identity.ts} +0 -0
- /package/src/parsers/{002-symbol-import-bindings.ts → symbol-import-bindings.ts} +0 -0
- /package/src/trace/{004-dynamic-candidate-sources.ts → dynamic-candidate-sources.ts} +0 -0
- /package/src/trace/{000-dynamic-target-types.ts → dynamic-target-types.ts} +0 -0
- /package/src/trace/{023-nested-event-scopes.ts → nested-event-scopes.ts} +0 -0
- /package/src/trace/{002-trace-diagnostics.ts → trace-diagnostics.ts} +0 -0
- /package/src/trace/{012-trace-graph-lookups.ts → trace-graph-lookups.ts} +0 -0
- /package/src/utils/{000-bounded-projection.ts → bounded-projection.ts} +0 -0
- /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/
|
|
6
|
+
} from '../parsers/fact-identity.js';
|
|
7
7
|
import type { Db, Statement } from './connection.js';
|
|
8
8
|
import {
|
|
9
9
|
resolveRelativeSymbolCall,
|
|
10
|
-
} from './
|
|
10
|
+
} from './relative-symbol-resolution.js';
|
|
11
11
|
import {
|
|
12
12
|
parsePackageImportReference,
|
|
13
|
-
} from '../parsers/
|
|
13
|
+
} from '../parsers/package-fact-contract.js';
|
|
14
14
|
import {
|
|
15
15
|
resolvedBindingReferenceProofValid,
|
|
16
16
|
type BindingProofCall,
|
|
17
17
|
type BindingProofTarget,
|
|
18
|
-
} from './
|
|
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
|
|
62
|
-
'
|
|
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
|
|
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
|
-
|
|
269
|
-
|
|
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 (
|
|
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(
|
|
488
|
+
function ownerlessOutboundOwner(
|
|
489
|
+
call: OutboundCallFact,
|
|
490
|
+
status: string,
|
|
491
|
+
): null {
|
|
479
492
|
if (status !== 'none')
|
|
480
|
-
throw
|
|
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
|
|
506
|
+
throw preparedCallSnapshotError(
|
|
507
|
+
'outbound_owner_mismatch', 'outbound_call', call,
|
|
508
|
+
);
|
|
492
509
|
const owner = selected.owner;
|
|
493
510
|
if (!owner)
|
|
494
|
-
throw
|
|
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
|
|
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
|
|
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
|
|
537
|
-
'
|
|
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
|
|
580
|
-
'
|
|
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 './
|
|
6
|
+
} from './package-fact-semantics.js';
|
|
7
7
|
import {
|
|
8
8
|
invalidRelativeFactCategories,
|
|
9
|
-
} from './
|
|
9
|
+
} from './relative-fact-semantics.js';
|
|
10
10
|
import {
|
|
11
11
|
invalidBindingFactCategories,
|
|
12
|
-
} from './
|
|
12
|
+
} from './binding-fact-semantics.js';
|
|
13
13
|
import {
|
|
14
14
|
invalidSymbolFactCategories,
|
|
15
|
-
} from './
|
|
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 './
|
|
6
|
+
} from './fact-json-inventory.js';
|
|
7
7
|
import {
|
|
8
8
|
invalidFactSemanticCategories,
|
|
9
9
|
type FactSemanticCategoryCount,
|
|
10
10
|
type PackageFactPhase,
|
|
11
|
-
} from './
|
|
11
|
+
} from './current-fact-semantics.js';
|
|
12
12
|
import {
|
|
13
13
|
invalidSchemaStructureCategories,
|
|
14
14
|
type SchemaStructureCategoryCount,
|
|
15
|
-
} from './
|
|
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/
|
|
7
|
+
} from '../parsers/package-public-surface.js';
|
|
8
8
|
import {
|
|
9
9
|
parsePackageImportReference,
|
|
10
10
|
parsePackagePublicSurfaceFact,
|
|
11
|
-
} from '../parsers/
|
|
11
|
+
} from '../parsers/package-fact-contract.js';
|
|
12
12
|
import type { SymbolImportReference } from
|
|
13
|
-
'../parsers/
|
|
14
|
-
import type { PackageFactPhase } from './
|
|
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/
|
|
18
|
+
} from '../linker/package-import-symbol-resolver.js';
|
|
19
19
|
import {
|
|
20
20
|
invalidPackageSymbolSurfaceCount,
|
|
21
|
-
} from './
|
|
21
|
+
} from './package-symbol-surface-semantics.js';
|
|
22
22
|
|
|
23
23
|
export interface PackageFactCategoryCount {
|
|
24
24
|
category: string;
|
package/src/db/{010-package-symbol-surface-semantics.ts → package-symbol-surface-semantics.ts}
RENAMED
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
type PackagePublicScope,
|
|
7
7
|
type PackagePublicSurfaceFact,
|
|
8
8
|
type PublicSurfaceTarget,
|
|
9
|
-
} from '../parsers/
|
|
9
|
+
} from '../parsers/package-public-surface.js';
|
|
10
10
|
import {
|
|
11
11
|
parsePackagePublicSurfaceFact,
|
|
12
|
-
} from '../parsers/
|
|
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/
|
|
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 './
|
|
5
|
+
} from './relative-symbol-resolution.js';
|
|
6
6
|
import type { SymbolCallFact } from '../types.js';
|
|
7
7
|
import { parseRelativeImportReference } from
|
|
8
|
-
'../parsers/
|
|
8
|
+
'../parsers/package-fact-contract.js';
|
|
9
9
|
import type { SymbolImportReference } from
|
|
10
|
-
'../parsers/
|
|
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
|
-
|
|
86
|
-
|
|
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
|
-
|
|
142
|
-
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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 {
|
|
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([
|
package/src/db/repositories.ts
CHANGED
|
@@ -11,7 +11,11 @@ import type {
|
|
|
11
11
|
import {
|
|
12
12
|
selectCallOwner,
|
|
13
13
|
type OwnerCandidate,
|
|
14
|
-
} from '../parsers/
|
|
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
|
|
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
|
|
480
|
+
throw bindingSnapshotError('binding_owner_mismatch', fact);
|
|
464
481
|
const owner = selected.owner;
|
|
465
482
|
if (!owner)
|
|
466
|
-
throw
|
|
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
|
|
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
|
|
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 './
|
|
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 './
|
|
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/
|
|
17
|
-
export type { CompactTraceExecution } from './trace/
|
|
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/
|
|
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(
|
|
19
|
-
|
|
20
|
-
|
|
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';
|