@shapeshift-labs/frontier-lang-compiler 0.2.100 → 0.2.101
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/dist/declarations/bidirectional-target-change-evidence.d.ts +299 -0
- package/dist/declarations/bidirectional-target-change.d.ts +19 -120
- package/dist/declarations/native-project-admission.d.ts +43 -22
- package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +24 -0
- package/dist/declarations/semantic-edit-script.d.ts +20 -15
- package/dist/declarations/semantic-lineage.d.ts +3 -21
- package/dist/declarations/semantic-merge-candidates.d.ts +39 -0
- package/dist/declarations/semantic-sidecar-admission.d.ts +14 -0
- package/dist/declarations/semantic-sidecar.d.ts +12 -14
- package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +200 -0
- package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +62 -17
- package/dist/internal/index-impl/createNativeSourcePreservation.js +16 -1
- package/dist/internal/index-impl/createProjectImportAdmissionRecord.js +151 -1
- package/dist/internal/index-impl/createSemanticImportSidecar.js +5 -0
- package/dist/internal/index-impl/createSemanticImportSidecarAdmission.js +29 -11
- package/dist/internal/index-impl/nativeChangeProjectionEndpoint.js +56 -16
- package/dist/internal/index-impl/projectImportAdmissionMergeScore.js +26 -74
- package/dist/internal/index-impl/projectImportAdmissionProjectionCoverage.js +74 -0
- package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +39 -13
- package/dist/internal/index-impl/replaySemanticEditProjection.js +65 -23
- package/dist/internal/index-impl/semanticEditInsertionAnchors.js +8 -5
- package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +167 -0
- package/dist/internal/index-impl/semanticEditSourceRanges.js +94 -15
- package/dist/internal/index-impl/semanticHistoryLineageResolution.js +21 -2
- package/dist/internal/index-impl/semanticLineageHashEvidence.js +97 -0
- package/dist/internal/index-impl/semanticLineageInferenceMatching.js +8 -0
- package/dist/internal/index-impl/semanticLineageResolutionRecords.js +18 -1
- package/dist/internal/index-impl/semanticMergeCandidateRecords.js +22 -2
- package/dist/internal/index-impl/semanticMergeCandidateScoreFacets.js +221 -0
- package/dist/internal/index-impl/semanticPatchBundleOverlaps.js +23 -1
- package/dist/internal/index-impl/sourcePreservationFromProjectionContext.js +9 -2
- package/dist/native-import-language-profiles.js +10 -2
- package/dist/native-region-scanner-js-helpers.js +8 -2
- package/dist/native-region-scanner-js-imports.js +7 -0
- package/dist/native-region-scanner-js.js +4 -4
- package/dist/native-region-scanner.js +2 -1
- package/dist/semantic-import-regions.js +6 -4
- package/dist/semantic-import-sidecar-admission-types.d.ts +14 -0
- package/dist/semantic-import-sidecar-entry.js +151 -7
- package/dist/semantic-import-sidecar-types.d.ts +18 -13
- package/dist/semantic-import-source-preservation-utils.js +55 -0
- package/dist/semantic-import-source-preservation.js +98 -3
- package/package.json +1 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { idFragment, uniqueRecordsById, uniqueStrings } from '../../native-import-utils.js';
|
|
2
|
+
import { sourceHash } from './bidirectionalTargetChangeRecordInternals.js';
|
|
3
|
+
|
|
4
|
+
export function summarizeSourceMapBackprojection(matches) {
|
|
5
|
+
const links = matches.flatMap((match) => match.sourceMapLinks ?? []);
|
|
6
|
+
return {
|
|
7
|
+
sourceMapBackedMatches: matches.filter((match) => (match.sourceMapLinks ?? []).length > 0).length,
|
|
8
|
+
sourceMapLinks: links.length,
|
|
9
|
+
sourceMapIds: uniqueStrings(links.map((link) => link.sourceMapId)),
|
|
10
|
+
sourceMapMappingIds: uniqueStrings(links.map((link) => link.sourceMapMappingId))
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createRoundtripEvidence(context) {
|
|
15
|
+
const sourceMapLinks = uniqueRecordsById(context.sourceAnchorMatches.flatMap((match) => match.sourceMapLinks ?? []));
|
|
16
|
+
const targetProjectionLinks = uniqueRecordsById((context.targetChangeSet.changedRegions ?? [])
|
|
17
|
+
.flatMap((region) => array(region.metadata?.changedRegionProjection?.sourceMapLinks)));
|
|
18
|
+
const sourceAnchors = uniqueRecordsByKey(context.sourceAnchorMatches.flatMap((match) => match.sourceAnchors ?? []));
|
|
19
|
+
const lineageResolutions = uniqueRecordsById(context.sourceAnchorMatches.flatMap((match) => match.lineageResolutions ?? []));
|
|
20
|
+
return {
|
|
21
|
+
schema: 'frontier.lang.bidirectionalTargetChangeRoundtripEvidence.v1',
|
|
22
|
+
version: 1,
|
|
23
|
+
id: `roundtrip_evidence_${idFragment(context.id)}`,
|
|
24
|
+
evidenceId: context.evidenceId,
|
|
25
|
+
sourcePatchBundleId: context.sourcePatchBundleId,
|
|
26
|
+
historyRecordId: context.historyRecordId,
|
|
27
|
+
source: sourceIdentity(context.source),
|
|
28
|
+
target: targetChangeIdentity(context.targetChangeSet),
|
|
29
|
+
targetRegions: (context.targetChangeSet.changedRegions ?? []).map(targetRegionIdentity),
|
|
30
|
+
sourceAnchorMatches: context.sourceAnchorMatches.map(matchIdentity),
|
|
31
|
+
sourceAnchors,
|
|
32
|
+
sourceMapEvidence: {
|
|
33
|
+
...context.sourceMapBackprojection,
|
|
34
|
+
sourceMapLinkIds: uniqueStrings(sourceMapLinks.map((link) => link.id)),
|
|
35
|
+
staleSourceMapLinkIds: uniqueStrings(context.targetPortability.staleSourceMapLinkIds),
|
|
36
|
+
targetProjectionSourceMapLinks: targetProjectionLinks.length,
|
|
37
|
+
targetProjectionSourceMapLinkIds: uniqueStrings(targetProjectionLinks.map((link) => link.id)),
|
|
38
|
+
targetProjectionSourceMapIds: uniqueStrings(targetProjectionLinks.map((link) => link.sourceMapId)),
|
|
39
|
+
targetProjectionSourceMapMappingIds: uniqueStrings(targetProjectionLinks.map((link) => link.sourceMapMappingId))
|
|
40
|
+
},
|
|
41
|
+
lineageEvidence: {
|
|
42
|
+
lineageResolutionIds: uniqueStrings(lineageResolutions.map((resolution) => resolution.id)),
|
|
43
|
+
lineageEventIds: uniqueStrings(lineageResolutions.flatMap((resolution) => resolution.traversedEventIds ?? [])),
|
|
44
|
+
lineageEvidenceIds: uniqueStrings(lineageResolutions.flatMap((resolution) => resolution.evidenceIds ?? [])),
|
|
45
|
+
lineageProofIds: uniqueStrings(lineageResolutions.flatMap((resolution) => resolution.proofIds ?? [])),
|
|
46
|
+
lineageReasonCodes: uniqueStrings(lineageResolutions.flatMap((resolution) => resolution.reasonCodes ?? []))
|
|
47
|
+
},
|
|
48
|
+
targetPortability: {
|
|
49
|
+
status: context.targetPortability.status,
|
|
50
|
+
action: context.targetPortability.action,
|
|
51
|
+
readiness: context.targetPortability.readiness,
|
|
52
|
+
reasonCodes: context.targetPortability.reasonCodes,
|
|
53
|
+
conflictKeys: context.targetPortability.conflictKeys
|
|
54
|
+
},
|
|
55
|
+
admission: {
|
|
56
|
+
status: context.readiness === 'blocked' ? 'blocked' : 'needs-review',
|
|
57
|
+
readiness: context.readiness,
|
|
58
|
+
action: context.targetPortability.action,
|
|
59
|
+
reasonCodes: context.reasons,
|
|
60
|
+
conflictKeys: uniqueStrings([
|
|
61
|
+
...array(context.targetPortability.conflictKeys),
|
|
62
|
+
...context.sourceAnchorMatches.flatMap((match) => match.conflictKeys ?? [])
|
|
63
|
+
]),
|
|
64
|
+
evidenceIds: [context.evidenceId],
|
|
65
|
+
reviewRequired: true,
|
|
66
|
+
autoMergeClaim: false,
|
|
67
|
+
semanticEquivalenceClaim: false
|
|
68
|
+
},
|
|
69
|
+
reviewRequired: true,
|
|
70
|
+
autoMergeClaim: false,
|
|
71
|
+
semanticEquivalenceClaim: false
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function createSemanticMergeAdmissionEvidence(context) {
|
|
76
|
+
return {
|
|
77
|
+
schema: 'frontier.lang.bidirectionalTargetChangeSemanticMergeAdmission.v1',
|
|
78
|
+
version: 1,
|
|
79
|
+
id: `semantic_merge_admission_${idFragment(context.id)}_target_change`,
|
|
80
|
+
evidenceIds: [context.evidenceId],
|
|
81
|
+
sourcePatchBundleId: context.sourcePatchBundleId,
|
|
82
|
+
historyRecordId: context.historyRecordId,
|
|
83
|
+
targetChangeSetId: context.targetChangeSet.id,
|
|
84
|
+
targetPatchId: context.targetChangeSet.patch?.id,
|
|
85
|
+
targetMergeCandidateId: context.targetChangeSet.mergeCandidate?.id,
|
|
86
|
+
readiness: context.readiness,
|
|
87
|
+
status: context.readiness === 'blocked' ? 'blocked' : 'needs-review',
|
|
88
|
+
action: context.targetPortability.action,
|
|
89
|
+
reasonCodes: context.reasons,
|
|
90
|
+
conflictKeys: context.roundtripEvidence.admission.conflictKeys,
|
|
91
|
+
sourceAnchorMatchIds: uniqueStrings(context.sourceAnchorMatches.map((match) => match.id)),
|
|
92
|
+
sourceAnchorKeys: uniqueStrings(context.roundtripEvidence.sourceAnchors.map((anchor) => anchor.key)),
|
|
93
|
+
targetRegionKeys: uniqueStrings(context.roundtripEvidence.targetRegions.map((region) => region.key)),
|
|
94
|
+
sourceMapLinkIds: context.roundtripEvidence.sourceMapEvidence.sourceMapLinkIds,
|
|
95
|
+
sourceMapIds: context.roundtripEvidence.sourceMapEvidence.sourceMapIds,
|
|
96
|
+
sourceMapMappingIds: context.roundtripEvidence.sourceMapEvidence.sourceMapMappingIds,
|
|
97
|
+
staleSourceMapLinkIds: context.roundtripEvidence.sourceMapEvidence.staleSourceMapLinkIds,
|
|
98
|
+
targetProjectionSourceMapLinkIds: context.roundtripEvidence.sourceMapEvidence.targetProjectionSourceMapLinkIds,
|
|
99
|
+
targetProjectionSourceMapMappingIds: context.roundtripEvidence.sourceMapEvidence.targetProjectionSourceMapMappingIds,
|
|
100
|
+
lineageResolutionIds: context.roundtripEvidence.lineageEvidence.lineageResolutionIds,
|
|
101
|
+
reviewRequired: true,
|
|
102
|
+
autoMergeClaim: false,
|
|
103
|
+
semanticEquivalenceClaim: false
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function sourceIdentity(source) {
|
|
108
|
+
return compactRecord({
|
|
109
|
+
importId: source?.id,
|
|
110
|
+
language: source?.language,
|
|
111
|
+
sourcePath: source?.sourcePath,
|
|
112
|
+
sourceHash: sourceHash(source),
|
|
113
|
+
nativeSourceId: source?.nativeSource?.id,
|
|
114
|
+
nativeAstId: source?.nativeAst?.id,
|
|
115
|
+
semanticIndexId: source?.semanticIndex?.id,
|
|
116
|
+
universalAstId: source?.universalAst?.id,
|
|
117
|
+
sourceMapIds: uniqueStrings((source?.sourceMaps ?? []).map((sourceMap) => sourceMap?.id))
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function targetChangeIdentity(targetChangeSet) {
|
|
122
|
+
return compactRecord({
|
|
123
|
+
changeSetId: targetChangeSet.id,
|
|
124
|
+
language: targetChangeSet.language,
|
|
125
|
+
sourcePath: targetChangeSet.sourcePath,
|
|
126
|
+
beforeHash: targetChangeSet.beforeHash,
|
|
127
|
+
afterHash: targetChangeSet.afterHash,
|
|
128
|
+
beforeImportId: targetChangeSet.before?.id,
|
|
129
|
+
afterImportId: targetChangeSet.after?.id,
|
|
130
|
+
beforeNativeSourceId: targetChangeSet.before?.nativeSource?.id,
|
|
131
|
+
afterNativeSourceId: targetChangeSet.after?.nativeSource?.id,
|
|
132
|
+
beforeNativeAstId: targetChangeSet.before?.nativeAst?.id,
|
|
133
|
+
afterNativeAstId: targetChangeSet.after?.nativeAst?.id,
|
|
134
|
+
beforeSemanticIndexId: targetChangeSet.before?.semanticIndex?.id,
|
|
135
|
+
afterSemanticIndexId: targetChangeSet.after?.semanticIndex?.id,
|
|
136
|
+
patchId: targetChangeSet.patch?.id,
|
|
137
|
+
mergeCandidateId: targetChangeSet.mergeCandidate?.id,
|
|
138
|
+
sourceMapIds: uniqueStrings((targetChangeSet.sourceMaps ?? []).map((sourceMap) => sourceMap?.id))
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function targetRegionIdentity(region) {
|
|
143
|
+
const projection = region.metadata?.changedRegionProjection;
|
|
144
|
+
return compactRecord({
|
|
145
|
+
id: region.id,
|
|
146
|
+
key: region.key,
|
|
147
|
+
conflictKey: region.conflictKey,
|
|
148
|
+
changeKind: region.changeKind,
|
|
149
|
+
regionKind: region.regionKind,
|
|
150
|
+
language: region.language,
|
|
151
|
+
sourcePath: region.sourcePath,
|
|
152
|
+
sourceHash: region.sourceHash,
|
|
153
|
+
symbolId: region.symbolId,
|
|
154
|
+
symbolName: region.symbolName ?? region.name,
|
|
155
|
+
sourceSpan: region.sourceSpan,
|
|
156
|
+
changedRegionProjectionId: projection?.id,
|
|
157
|
+
beforeIdentity: projection?.before?.identity,
|
|
158
|
+
afterIdentity: projection?.after?.identity,
|
|
159
|
+
sourceMapLinkIds: uniqueStrings(array(projection?.sourceMapLinks).map((link) => link.id)),
|
|
160
|
+
sourceMapIds: uniqueStrings(array(projection?.sourceMapLinks).map((link) => link.sourceMapId)),
|
|
161
|
+
sourceMapMappingIds: uniqueStrings(array(projection?.sourceMapLinks).map((link) => link.sourceMapMappingId))
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function matchIdentity(match) {
|
|
166
|
+
return compactRecord({
|
|
167
|
+
id: match.id,
|
|
168
|
+
status: match.status,
|
|
169
|
+
targetRegionKey: match.targetRegion?.key,
|
|
170
|
+
targetRegionConflictKey: match.targetRegion?.conflictKey,
|
|
171
|
+
sourceAnchorKeys: uniqueStrings((match.sourceAnchors ?? []).map((anchor) => anchor.key)),
|
|
172
|
+
sourceMapLinkIds: uniqueStrings((match.sourceMapLinks ?? []).map((link) => link.id)),
|
|
173
|
+
sourceMapMappingIds: uniqueStrings((match.sourceMapLinks ?? []).map((link) => link.sourceMapMappingId)),
|
|
174
|
+
lineageResolutionIds: uniqueStrings((match.lineageResolutions ?? []).map((resolution) => resolution.id)),
|
|
175
|
+
portabilityStatus: match.portability?.status,
|
|
176
|
+
portabilityAction: match.portability?.action,
|
|
177
|
+
reasonCodes: match.reasonCodes,
|
|
178
|
+
conflictKeys: match.conflictKeys
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function uniqueRecordsByKey(records) {
|
|
183
|
+
const seen = new Set();
|
|
184
|
+
const result = [];
|
|
185
|
+
for (const record of records ?? []) {
|
|
186
|
+
const key = record?.key ?? record?.id;
|
|
187
|
+
if (!key || seen.has(key)) continue;
|
|
188
|
+
seen.add(key);
|
|
189
|
+
result.push(record);
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function array(value) {
|
|
195
|
+
return value === undefined || value === null ? [] : Array.isArray(value) ? value : [value];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function compactRecord(value) {
|
|
199
|
+
return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
|
|
200
|
+
}
|
|
@@ -9,6 +9,7 @@ import { createSemanticHistoryRecord } from './semanticHistoryRecords.js';
|
|
|
9
9
|
import { diffNativeSourceImports } from './diffNativeSourceImports.js';
|
|
10
10
|
import { normalizeNativeDiffImport } from './normalizeNativeDiffImport.js';
|
|
11
11
|
import { attachBidirectionalMatchPortability, classifyBidirectionalTargetPortability } from './bidirectionalTargetPortability.js';
|
|
12
|
+
import { createRoundtripEvidence, createSemanticMergeAdmissionEvidence, summarizeSourceMapBackprojection } from './bidirectionalTargetRoundtripEvidence.js';
|
|
12
13
|
import {
|
|
13
14
|
anchorsFromSourceSidecar,
|
|
14
15
|
classifyBidirectionalReadiness,
|
|
@@ -85,16 +86,54 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
85
86
|
...array(targetPortability.reasonCodes),
|
|
86
87
|
...sourceAnchorMatches.flatMap((match) => match.reasonCodes)
|
|
87
88
|
]);
|
|
88
|
-
const
|
|
89
|
+
const evidenceId = input.evidenceId ?? `evidence_${idFragment(id)}_bidirectional_target_change`;
|
|
90
|
+
const sourcePatchBundleId = input.sourcePatchBundleId ?? `semantic_patch_bundle_${idFragment(id)}_source_port`;
|
|
91
|
+
const historyRecordId = input.historyRecordId ?? `semantic_history_${idFragment(id)}_target_change`;
|
|
92
|
+
const sourceMapBackprojection = summarizeSourceMapBackprojection(sourceAnchorMatches);
|
|
93
|
+
const roundtripEvidence = createRoundtripEvidence({
|
|
89
94
|
id,
|
|
90
|
-
|
|
95
|
+
evidenceId,
|
|
96
|
+
sourcePatchBundleId,
|
|
97
|
+
historyRecordId,
|
|
98
|
+
source,
|
|
99
|
+
targetChangeSet,
|
|
100
|
+
sourceAnchorMatches,
|
|
101
|
+
targetPortability,
|
|
102
|
+
readiness,
|
|
103
|
+
reasons,
|
|
104
|
+
sourceMapBackprojection
|
|
105
|
+
});
|
|
106
|
+
const semanticMergeAdmission = createSemanticMergeAdmissionEvidence({
|
|
107
|
+
id,
|
|
108
|
+
evidenceId,
|
|
109
|
+
sourcePatchBundleId,
|
|
110
|
+
historyRecordId,
|
|
111
|
+
targetChangeSet,
|
|
112
|
+
sourceAnchorMatches,
|
|
113
|
+
targetPortability,
|
|
114
|
+
readiness,
|
|
115
|
+
reasons,
|
|
116
|
+
roundtripEvidence
|
|
117
|
+
});
|
|
118
|
+
const bidirectionalEvidence = createBidirectionalEvidence({
|
|
119
|
+
id,
|
|
120
|
+
input: { ...input, evidenceId },
|
|
91
121
|
source,
|
|
92
122
|
targetChangeSet,
|
|
93
123
|
sourceAnchorMatches,
|
|
94
124
|
targetPortability,
|
|
95
125
|
readiness,
|
|
96
126
|
reasons
|
|
97
|
-
})
|
|
127
|
+
});
|
|
128
|
+
const evidence = [{
|
|
129
|
+
...bidirectionalEvidence,
|
|
130
|
+
metadata: {
|
|
131
|
+
...bidirectionalEvidence.metadata,
|
|
132
|
+
roundtripEvidenceId: roundtripEvidence.id,
|
|
133
|
+
roundtripEvidence,
|
|
134
|
+
semanticMergeAdmission
|
|
135
|
+
}
|
|
136
|
+
}];
|
|
98
137
|
const sourceChangedRegions = sourceAnchorMatches.flatMap((match) => sourceRegionsForMatch(match, readiness));
|
|
99
138
|
const sourcePatchBundle = createSemanticPatchBundleRecord({
|
|
100
139
|
id: `${id}_source_port_projection`,
|
|
@@ -112,22 +151,30 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
112
151
|
targetPatchId: targetChangeSet.patch?.id,
|
|
113
152
|
targetMergeCandidateId: targetChangeSet.mergeCandidate?.id,
|
|
114
153
|
targetPortability,
|
|
115
|
-
sourceMapBackprojection
|
|
154
|
+
sourceMapBackprojection,
|
|
155
|
+
roundtripEvidenceId: roundtripEvidence.id,
|
|
156
|
+
semanticMergeAdmission
|
|
116
157
|
}
|
|
117
158
|
}, {
|
|
118
|
-
id:
|
|
159
|
+
id: sourcePatchBundleId,
|
|
119
160
|
patchId: targetChangeSet.patch?.id,
|
|
120
161
|
mergeCandidateId: targetChangeSet.mergeCandidate?.id,
|
|
121
162
|
admission: { status: readiness === 'blocked' ? 'blocked' : 'needs-review', readiness },
|
|
122
163
|
metadata: {
|
|
123
164
|
source: 'createBidirectionalTargetChangeRecord',
|
|
165
|
+
targetChangeSetId: targetChangeSet.id,
|
|
166
|
+
targetPatchId: targetChangeSet.patch?.id,
|
|
167
|
+
targetMergeCandidateId: targetChangeSet.mergeCandidate?.id,
|
|
124
168
|
targetPortability,
|
|
169
|
+
sourceMapBackprojection,
|
|
170
|
+
roundtripEvidenceId: roundtripEvidence.id,
|
|
171
|
+
semanticMergeAdmission,
|
|
125
172
|
autoMergeClaim: false,
|
|
126
173
|
semanticEquivalenceClaim: false
|
|
127
174
|
}
|
|
128
175
|
});
|
|
129
176
|
const historyRecord = createSemanticHistoryRecord({
|
|
130
|
-
id:
|
|
177
|
+
id: historyRecordId,
|
|
131
178
|
importResult: source,
|
|
132
179
|
language: source?.language,
|
|
133
180
|
sourcePath: source?.sourcePath,
|
|
@@ -155,7 +202,9 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
155
202
|
sourcePatchBundleId: sourcePatchBundle.id,
|
|
156
203
|
targetChangeSetId: targetChangeSet.id,
|
|
157
204
|
targetPortability,
|
|
158
|
-
sourceMapBackprojection
|
|
205
|
+
sourceMapBackprojection,
|
|
206
|
+
roundtripEvidenceId: roundtripEvidence.id,
|
|
207
|
+
semanticMergeAdmission,
|
|
159
208
|
autoMergeClaim: false,
|
|
160
209
|
semanticEquivalenceClaim: false
|
|
161
210
|
}
|
|
@@ -172,6 +221,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
172
221
|
targetChangeSet,
|
|
173
222
|
sourceAnchorMatches,
|
|
174
223
|
targetPortability,
|
|
224
|
+
roundtripEvidence,
|
|
175
225
|
sourcePatchBundle,
|
|
176
226
|
historyRecord,
|
|
177
227
|
evidence,
|
|
@@ -185,6 +235,9 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
185
235
|
deletedSourceAnchors: sourceAnchorMatches.filter((match) => match.status === 'deleted').length,
|
|
186
236
|
sourceChangedRegions: sourceChangedRegions.length,
|
|
187
237
|
sourceMapBackedMatches: sourceAnchorMatches.filter((match) => match.sourceMapLinks.length > 0).length,
|
|
238
|
+
sourceMapLinks: sourceMapBackprojection.sourceMapLinks,
|
|
239
|
+
sourceMapMappingIds: sourceMapBackprojection.sourceMapMappingIds.length,
|
|
240
|
+
lineageResolutions: roundtripEvidence.lineageEvidence.lineageResolutionIds.length,
|
|
188
241
|
targetPortabilityStatus: targetPortability.status,
|
|
189
242
|
portableTargetRegions: targetPortability.status === 'portable' ? targetPortability.targetChangedRegions : 0,
|
|
190
243
|
staleTargetRegions: targetPortability.status === 'stale' ? targetPortability.targetChangedRegions : 0,
|
|
@@ -195,21 +248,13 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
195
248
|
semanticEquivalenceClaim: false,
|
|
196
249
|
reviewRequired: true,
|
|
197
250
|
targetPortability,
|
|
251
|
+
roundtripEvidenceId: roundtripEvidence.id,
|
|
252
|
+
semanticMergeAdmission,
|
|
198
253
|
...input.metadata
|
|
199
254
|
}
|
|
200
255
|
};
|
|
201
256
|
}
|
|
202
257
|
|
|
203
|
-
function summarizeSourceMapBackprojection(matches) {
|
|
204
|
-
const links = matches.flatMap((match) => match.sourceMapLinks ?? []);
|
|
205
|
-
return {
|
|
206
|
-
sourceMapBackedMatches: matches.filter((match) => (match.sourceMapLinks ?? []).length > 0).length,
|
|
207
|
-
sourceMapLinks: links.length,
|
|
208
|
-
sourceMapIds: uniqueStrings(links.map((link) => link.sourceMapId)),
|
|
209
|
-
sourceMapMappingIds: uniqueStrings(links.map((link) => link.sourceMapMappingId))
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
258
|
function array(value) {
|
|
214
259
|
return value === undefined || value === null ? [] : Array.isArray(value) ? value : [value];
|
|
215
260
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{idFragment}from'../../native-import-utils.js';import{detectNewlineStyle,scanPreservedSourceDirectives,scanPreservedSourceTokens}from'../../native-region-scanner.js';import{hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';
|
|
1
|
+
import{countBy,idFragment,uniqueStrings}from'../../native-import-utils.js';import{detectNewlineStyle,scanPreservedSourceDirectives,scanPreservedSourceTokens}from'../../native-region-scanner.js';import{hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';
|
|
2
2
|
export function createNativeSourcePreservation(options) {
|
|
3
3
|
if (!options || typeof options.sourceText !== 'string') {
|
|
4
4
|
throw new Error('createNativeSourcePreservation requires sourceText');
|
|
@@ -26,6 +26,16 @@ export function createNativeSourcePreservation(options) {
|
|
|
26
26
|
maxDirectives: options.maxDirectives
|
|
27
27
|
});
|
|
28
28
|
const directives = directiveScan.directives;
|
|
29
|
+
const triviaByKind = countBy(tokensAndTrivia.trivia.map((entry) => entry.kind ?? 'unknown'));
|
|
30
|
+
const directivesByKind = countBy(directives.map((entry) => entry.kind ?? 'directive'));
|
|
31
|
+
const directiveKinds = uniqueStrings(directives.map((entry) => entry.kind ?? 'directive'));
|
|
32
|
+
const commentSpanIds = tokensAndTrivia.trivia
|
|
33
|
+
.filter((entry) => entry.kind === 'comment')
|
|
34
|
+
.map((entry) => entry.id)
|
|
35
|
+
.filter(Boolean);
|
|
36
|
+
const directiveSpanIds = directives
|
|
37
|
+
.map((entry) => entry.id)
|
|
38
|
+
.filter(Boolean);
|
|
29
39
|
const newline = detectNewlineStyle(sourceText);
|
|
30
40
|
return {
|
|
31
41
|
kind: 'frontier.lang.nativeSourcePreservation',
|
|
@@ -48,6 +58,11 @@ export function createNativeSourcePreservation(options) {
|
|
|
48
58
|
directives: directives.length,
|
|
49
59
|
comments: tokensAndTrivia.trivia.filter((entry) => entry.kind === 'comment').length,
|
|
50
60
|
whitespace: tokensAndTrivia.trivia.filter((entry) => entry.kind === 'whitespace' || entry.kind === 'newline').length,
|
|
61
|
+
triviaByKind,
|
|
62
|
+
directivesByKind,
|
|
63
|
+
directiveKinds,
|
|
64
|
+
commentSpanIds,
|
|
65
|
+
directiveSpanIds,
|
|
51
66
|
exactSourceAvailable: options.includeSourceText !== false,
|
|
52
67
|
truncated: tokensAndTrivia.truncated || directiveScan.truncated
|
|
53
68
|
},
|
|
@@ -22,7 +22,8 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
|
|
|
22
22
|
const importSummaries=projectAdmissionImports(imports,contract?.sources??[],mergeCandidates);
|
|
23
23
|
const languages=admissionLanguages(importSummaries);
|
|
24
24
|
const semanticEvidence=admissionSemanticEvidence(projectResult,imports,importSummaries);
|
|
25
|
-
const
|
|
25
|
+
const sourceStaleness=admissionSourceStaleness(imports,importSummaries,contract);
|
|
26
|
+
const sourcePreservation=admissionSourcePreservationWithStaleness(admissionSourcePreservation(importSummaries,contract),sourceStaleness);
|
|
26
27
|
const ownership=admissionOwnership(contract,mergeCandidates);
|
|
27
28
|
const mergeCandidateRisk=admissionMergeCandidates(projectResult,imports,mergeCandidates,lossSummary);
|
|
28
29
|
const readiness=maxSemanticMergeReadiness(
|
|
@@ -54,6 +55,7 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
|
|
|
54
55
|
readiness,
|
|
55
56
|
sourceCount:imports.length,
|
|
56
57
|
semanticEvidence,
|
|
58
|
+
sourceStaleness,
|
|
57
59
|
sourcePreservation,
|
|
58
60
|
ownership,
|
|
59
61
|
mergeCandidateRisk,
|
|
@@ -71,6 +73,7 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
|
|
|
71
73
|
sourceCount:imports.length,
|
|
72
74
|
languages,
|
|
73
75
|
semanticEvidence,
|
|
76
|
+
sourceStaleness,
|
|
74
77
|
sourcePreservation,
|
|
75
78
|
ownership,
|
|
76
79
|
mergeCandidates:mergeCandidateRisk,
|
|
@@ -89,3 +92,150 @@ export function createProjectImportAdmissionRecord(projectResult,options={}){
|
|
|
89
92
|
}
|
|
90
93
|
};
|
|
91
94
|
}
|
|
95
|
+
|
|
96
|
+
function admissionSourceStaleness(imports,importSummaries,contract){
|
|
97
|
+
const total=Math.max(imports.length,importSummaries.length,contract?.sources?.length??0);
|
|
98
|
+
const records=[];
|
|
99
|
+
for(let index=0;index<total;index+=1){
|
|
100
|
+
const record=sourceStalenessRecord(imports[index],importSummaries[index],contract?.sources?.[index]);
|
|
101
|
+
if(record.reasonCodes.length) records.push(record);
|
|
102
|
+
}
|
|
103
|
+
const staleRecords=records.filter((record)=>record.staleByContentHash||record.staleByBaseHash);
|
|
104
|
+
const contentHashRecords=records.filter((record)=>record.staleByContentHash);
|
|
105
|
+
const baseHashRecords=records.filter((record)=>record.staleByBaseHash);
|
|
106
|
+
const dirtyWorkspaceRecords=records.filter((record)=>record.dirtyWorkspace);
|
|
107
|
+
const unverifiedRecords=records.filter((record)=>record.unverifiedSourceHash);
|
|
108
|
+
return {
|
|
109
|
+
total,
|
|
110
|
+
stale:staleRecords.length,
|
|
111
|
+
contentHashStale:contentHashRecords.length,
|
|
112
|
+
baseHashStale:baseHashRecords.length,
|
|
113
|
+
dirtyWorkspace:dirtyWorkspaceRecords.length,
|
|
114
|
+
unverified:unverifiedRecords.length,
|
|
115
|
+
staleSourcePaths:sourcePaths(staleRecords),
|
|
116
|
+
contentHashStaleSourcePaths:sourcePaths(contentHashRecords),
|
|
117
|
+
baseHashStaleSourcePaths:sourcePaths(baseHashRecords),
|
|
118
|
+
dirtyWorkspaceSourcePaths:sourcePaths(dirtyWorkspaceRecords),
|
|
119
|
+
unverifiedSourcePaths:sourcePaths(unverifiedRecords),
|
|
120
|
+
records
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function sourceStalenessRecord(imported,summary,source){
|
|
125
|
+
const nativeSource=imported?.nativeSource;
|
|
126
|
+
const nativeAst=imported?.nativeAst??nativeSource?.ast;
|
|
127
|
+
const preservation=imported?.metadata?.sourcePreservation
|
|
128
|
+
??nativeSource?.metadata?.sourcePreservation
|
|
129
|
+
??nativeAst?.metadata?.sourcePreservation
|
|
130
|
+
??imported?.universalAst?.metadata?.sourcePreservation;
|
|
131
|
+
const metadata=[
|
|
132
|
+
imported?.metadata,
|
|
133
|
+
nativeSource?.metadata,
|
|
134
|
+
nativeAst?.metadata,
|
|
135
|
+
preservation?.metadata,
|
|
136
|
+
imported?.universalAst?.metadata,
|
|
137
|
+
imported?.patch?.metadata
|
|
138
|
+
].filter((entry)=>entry&&typeof entry==='object');
|
|
139
|
+
const lossReasons=(imported?.losses??nativeAst?.losses??[]).flatMap((loss)=>[
|
|
140
|
+
loss?.reason,
|
|
141
|
+
loss?.metadata?.reason,
|
|
142
|
+
...(Array.isArray(loss?.reasonCodes)?loss.reasonCodes:[]),
|
|
143
|
+
...(Array.isArray(loss?.metadata?.reasonCodes)?loss.metadata.reasonCodes:[])
|
|
144
|
+
]);
|
|
145
|
+
const observedReasonCodes=uniqueStrings([
|
|
146
|
+
...metadata.flatMap((entry)=>[
|
|
147
|
+
entry.reason,
|
|
148
|
+
...(Array.isArray(entry.reasonCodes)?entry.reasonCodes:[]),
|
|
149
|
+
...(Array.isArray(entry.reasons)?entry.reasons:[])
|
|
150
|
+
]),
|
|
151
|
+
...lossReasons
|
|
152
|
+
]);
|
|
153
|
+
const sourcePath=firstString(summary?.sourcePath,source?.sourcePath,imported?.sourcePath,nativeSource?.sourcePath,nativeAst?.sourcePath,preservation?.sourcePath);
|
|
154
|
+
const sourceHash=firstString(summary?.sourceHash,source?.sourceHash,imported?.sourceHash,nativeSource?.sourceHash,nativeAst?.sourceHash,preservation?.sourceHash);
|
|
155
|
+
const declaredSourceHash=firstMetadataString(metadata,'declaredSourceHash');
|
|
156
|
+
const contentHash=firstMetadataString(metadata,'currentContentHash','actualContentHash','contentHash')??sourceHash;
|
|
157
|
+
const declaredContentHash=firstMetadataString(metadata,'declaredContentHash','expectedContentHash','expectedSourceHash')??declaredSourceHash;
|
|
158
|
+
const sourceHashMismatch=Boolean(declaredSourceHash&&sourceHash&&declaredSourceHash!==sourceHash);
|
|
159
|
+
const contentHashMismatch=Boolean(declaredContentHash&&contentHash&&declaredContentHash!==contentHash);
|
|
160
|
+
const preservationHashMismatch=Boolean(preservation?.sourceHash&&sourceHash&&preservation.sourceHash!==sourceHash);
|
|
161
|
+
const sourceHashVerifiedFalse=metadata.some((entry)=>entry.sourceHashVerified===false);
|
|
162
|
+
const staleByContentHash=sourceHashMismatch
|
|
163
|
+
||contentHashMismatch
|
|
164
|
+
||preservationHashMismatch
|
|
165
|
+
||(sourceHashVerifiedFalse&&Boolean(declaredSourceHash||declaredContentHash));
|
|
166
|
+
const baseHash=firstString(imported?.baseHash,imported?.patch?.baseHash,firstMetadataString(metadata,'baseHash'));
|
|
167
|
+
const expectedBaseHash=firstMetadataString(metadata,'expectedBaseHash','declaredBaseHash','sourceBaseHash');
|
|
168
|
+
const currentBaseHash=firstMetadataString(metadata,'currentBaseHash','actualBaseHash','headBaseHash','workspaceBaseHash');
|
|
169
|
+
const staleByBaseHash=Boolean(
|
|
170
|
+
expectedBaseHash&¤tBaseHash&&expectedBaseHash!==currentBaseHash
|
|
171
|
+
)||metadata.some((entry)=>entry.baseHashVerified===false)||observedReasonCodes.includes('base-hash-mismatch');
|
|
172
|
+
const dirtyWorkspace=metadata.some((entry)=>
|
|
173
|
+
entry.dirtyWorkspace===true
|
|
174
|
+
||entry.workspaceDirty===true
|
|
175
|
+
||entry.worktreeDirty===true
|
|
176
|
+
||entry.dirtyWorktree===true
|
|
177
|
+
)||observedReasonCodes.some((reason)=>reason==='dirty-workspace'||reason==='workspace-dirty'||reason==='dirty-worktree');
|
|
178
|
+
const unverifiedSourceHash=sourceHashVerifiedFalse&&!staleByContentHash;
|
|
179
|
+
const reasonCodes=uniqueStrings([
|
|
180
|
+
...(sourceHashMismatch?['source-hash-mismatch']:[]),
|
|
181
|
+
...(contentHashMismatch?['content-hash-mismatch']:[]),
|
|
182
|
+
...(preservationHashMismatch?['source-preservation-hash-mismatch']:[]),
|
|
183
|
+
...(staleByContentHash&&sourceHashVerifiedFalse?['source-hash-unverified']:[]),
|
|
184
|
+
...(staleByBaseHash?['base-hash-mismatch']:[]),
|
|
185
|
+
...(dirtyWorkspace?['dirty-workspace']:[]),
|
|
186
|
+
...(unverifiedSourceHash?['source-hash-unverified']:[])
|
|
187
|
+
]);
|
|
188
|
+
return {
|
|
189
|
+
...(sourcePath?{sourcePath}:{}),
|
|
190
|
+
...(sourceHash?{sourceHash}:{}),
|
|
191
|
+
...(declaredSourceHash?{declaredSourceHash}:{}),
|
|
192
|
+
...(contentHash?{contentHash}:{}),
|
|
193
|
+
...(declaredContentHash?{declaredContentHash}:{}),
|
|
194
|
+
...(baseHash?{baseHash}:{}),
|
|
195
|
+
...(expectedBaseHash?{expectedBaseHash}:{}),
|
|
196
|
+
...(currentBaseHash?{currentBaseHash}:{}),
|
|
197
|
+
staleByContentHash,
|
|
198
|
+
staleByBaseHash,
|
|
199
|
+
dirtyWorkspace,
|
|
200
|
+
unverifiedSourceHash,
|
|
201
|
+
reasonCodes
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function admissionSourcePreservationWithStaleness(sourcePreservation,sourceStaleness){
|
|
206
|
+
const stale=sourceStaleness.stale;
|
|
207
|
+
const quality=stale>0?'stale':sourcePreservation.quality==='stale'
|
|
208
|
+
? sourcePreservation.missing>0?'missing':sourcePreservation.lossy>0||sourcePreservation.truncated?'lossy':sourcePreservation.total===0?'empty':'exact'
|
|
209
|
+
: sourcePreservation.quality;
|
|
210
|
+
return {
|
|
211
|
+
...sourcePreservation,
|
|
212
|
+
quality,
|
|
213
|
+
stale,
|
|
214
|
+
staleSourcePaths:sourceStaleness.staleSourcePaths,
|
|
215
|
+
contentHashStale:sourceStaleness.contentHashStale,
|
|
216
|
+
baseHashStale:sourceStaleness.baseHashStale,
|
|
217
|
+
dirtyWorkspace:sourceStaleness.dirtyWorkspace,
|
|
218
|
+
contentHashStaleSourcePaths:sourceStaleness.contentHashStaleSourcePaths,
|
|
219
|
+
baseHashStaleSourcePaths:sourceStaleness.baseHashStaleSourcePaths,
|
|
220
|
+
dirtyWorkspaceSourcePaths:sourceStaleness.dirtyWorkspaceSourcePaths
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function sourcePaths(records){
|
|
225
|
+
return uniqueStrings(records.map((record)=>record.sourcePath).filter(Boolean));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function firstMetadataString(metadata,...keys){
|
|
229
|
+
for(const key of keys){
|
|
230
|
+
const value=firstString(...metadata.map((entry)=>entry?.[key]));
|
|
231
|
+
if(value) return value;
|
|
232
|
+
}
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function firstString(...values){
|
|
237
|
+
for(const value of values){
|
|
238
|
+
if(value!==undefined&&value!==null&&String(value)) return String(value);
|
|
239
|
+
}
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
@@ -29,6 +29,7 @@ export function createSemanticImportSidecar(importResult, options = {}) {
|
|
|
29
29
|
const patchHints = ownershipRegions.map((region) => semanticPatchHintForRegion(region, readiness, options));
|
|
30
30
|
const quality = createSemanticImportSidecarQuality({
|
|
31
31
|
expected: options.expected === true || options.semanticImportExpected === true,
|
|
32
|
+
expectedEmpty: options.expectedEmpty === true || options.semanticImportExpectedEmpty === true,
|
|
32
33
|
importEntries,
|
|
33
34
|
symbols,
|
|
34
35
|
ownershipRegions,
|
|
@@ -130,8 +131,12 @@ export function createSemanticImportSidecar(importResult, options = {}) {
|
|
|
130
131
|
patchHints: patchHints.length,
|
|
131
132
|
evidenceWarnings: quality.emptyEvidenceWarnings.length,
|
|
132
133
|
semanticImportExpected: quality.expected,
|
|
134
|
+
semanticImportExpectedEmpty: quality.expectedEmpty,
|
|
133
135
|
semanticImportExpectedSatisfied: quality.expectedSatisfied,
|
|
134
136
|
semanticImportExpectedMissingReasonCodes: quality.expectedMissingReasonCodes,
|
|
137
|
+
semanticImportRecordClassification: quality.record.classification,
|
|
138
|
+
semanticImportRecordReasonCode: quality.record.reasonCode,
|
|
139
|
+
semanticImportRecordAction: quality.record.action,
|
|
135
140
|
readiness,
|
|
136
141
|
emptySemanticIndex: symbols.length === 0
|
|
137
142
|
},
|