@shapeshift-labs/frontier-lang-compiler 0.2.103 → 0.2.104
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/README.md +13 -0
- package/dist/declarations/bidirectional-target-change-source-edit.d.ts +30 -0
- package/dist/declarations/bidirectional-target-change.d.ts +10 -0
- package/dist/declarations/js-ts-safe-member-merge.d.ts +58 -0
- package/dist/declarations/js-ts-safe-merge.d.ts +120 -0
- package/dist/declarations/js-ts-semantic-conflict-sidecars.d.ts +235 -0
- package/dist/declarations/js-ts-semantic-merge-contracts.d.ts +287 -0
- package/dist/declarations/js-ts-semantic-merge.d.ts +4 -0
- package/dist/declarations/native-import-losses.d.ts +3 -0
- package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +12 -0
- package/dist/declarations/semantic-edit-script.d.ts +7 -4
- package/dist/declarations/semantic-patch-bundle-index.d.ts +45 -0
- package/dist/declarations/semantic-patch-bundle.d.ts +6 -4
- package/dist/declarations/semantic-sidecar-example.d.ts +18 -0
- package/dist/declarations/semantic-transform-identity.d.ts +3 -0
- package/dist/declarations/source-preservation.d.ts +72 -0
- package/dist/declarations/universal-capability.d.ts +4 -0
- package/dist/declarations/universal-conversion-artifacts.d.ts +61 -1
- package/dist/declarations/universal-conversion-compact-counts.d.ts +51 -0
- package/dist/declarations/universal-conversion-plan.d.ts +6 -1
- package/dist/declarations/universal-representation-coverage.d.ts +90 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/internal/index-impl/bidirectionalExactSourceBackprojection.js +199 -0
- package/dist/internal/index-impl/bidirectionalSameLanguageSourceProjection.js +112 -0
- package/dist/internal/index-impl/bidirectionalSourceEditProjection.js +319 -0
- package/dist/internal/index-impl/bidirectionalSourceEditProjectionArtifacts.js +67 -0
- package/dist/internal/index-impl/bidirectionalTargetChangeRecordInternals.js +17 -5
- package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +58 -20
- package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +60 -7
- package/dist/internal/index-impl/createLightweightNativeImport.js +1 -0
- package/dist/internal/index-impl/createNativeSourcePreservation.js +28 -2
- package/dist/internal/index-impl/diffNativeSymbols.js +3 -3
- package/dist/internal/index-impl/nativeChangeProjectionSourceMapLinks.js +2 -0
- package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +43 -8
- package/dist/internal/index-impl/replaySemanticEditLineEndings.js +34 -0
- package/dist/internal/index-impl/replaySemanticEditProjection.js +39 -19
- package/dist/internal/index-impl/semanticEditBundleAdmission.js +7 -3
- package/dist/internal/index-impl/semanticEditBundleIndex.js +47 -1
- package/dist/internal/index-impl/semanticEditExplicitSourceReplacement.js +40 -0
- package/dist/internal/index-impl/semanticEditOperationCoverage.js +33 -3
- package/dist/internal/index-impl/semanticEditProjectionRecord.js +29 -0
- package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +39 -0
- package/dist/internal/index-impl/semanticEditReplaySourceReplacement.js +85 -0
- package/dist/internal/index-impl/semanticEditScripts.js +4 -0
- package/dist/internal/index-impl/semanticEditSourceRanges.js +27 -0
- package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +1 -0
- package/dist/internal/index-impl/semanticPatchBundleAdmission.js +41 -7
- package/dist/internal/index-impl/semanticPatchBundleRecords.js +16 -0
- package/dist/internal/index-impl/semanticPatchBundleSourceRecords.js +2 -0
- package/dist/internal/index-impl/semanticSidecarQuality.js +111 -0
- package/dist/internal/index-impl/semanticSourceEditDedupe.js +69 -9
- package/dist/internal/index-impl/semanticTransformIdentityRecords.js +85 -9
- package/dist/js-ts-safe-member-merge-result.js +158 -0
- package/dist/js-ts-safe-member-merge.js +202 -0
- package/dist/js-ts-safe-merge-analyze.js +279 -0
- package/dist/js-ts-safe-merge-constants.js +50 -0
- package/dist/js-ts-safe-merge-context.js +118 -0
- package/dist/js-ts-safe-merge-ledger-validation.js +92 -0
- package/dist/js-ts-safe-merge-ledger.js +85 -0
- package/dist/js-ts-safe-merge-parse-declarations.js +210 -0
- package/dist/js-ts-safe-merge-parse-statements.js +155 -0
- package/dist/js-ts-safe-merge-plan.js +190 -0
- package/dist/js-ts-safe-merge.js +175 -0
- package/dist/js-ts-semantic-conflict-sidecar-constants.js +77 -0
- package/dist/js-ts-semantic-conflict-sidecar-detectors.js +195 -0
- package/dist/js-ts-semantic-conflict-sidecar-normalize.js +203 -0
- package/dist/js-ts-semantic-conflict-sidecar-utils.js +190 -0
- package/dist/js-ts-semantic-conflict-sidecars.js +81 -0
- package/dist/js-ts-semantic-merge-contract-helpers.js +128 -0
- package/dist/js-ts-semantic-merge-contracts.js +217 -0
- package/dist/js-ts-semantic-merge-member-containers.js +100 -0
- package/dist/js-ts-semantic-merge-member-keys.js +142 -0
- package/dist/js-ts-semantic-merge-member-segments.js +185 -0
- package/dist/js-ts-semantic-merge-member-source.js +64 -0
- package/dist/js-ts-semantic-merge-member-utils.js +18 -0
- package/dist/js-ts-semantic-merge-parse.js +15 -0
- package/dist/js-ts-semantic-merge.js +21 -0
- package/dist/lightweight-dependency-effects.js +51 -0
- package/dist/lightweight-dependency-language.js +12 -1
- package/dist/lightweight-dependency-relations.js +14 -27
- package/dist/native-region-scanner-core.js +33 -1
- package/dist/native-region-scanner-csharp.js +151 -0
- package/dist/native-region-scanner-dart.js +91 -0
- package/dist/native-region-scanner-dynamic.js +21 -151
- package/dist/native-region-scanner-functional.js +40 -13
- package/dist/native-region-scanner-java.js +97 -0
- package/dist/native-region-scanner-js-class.js +100 -0
- package/dist/native-region-scanner-js-helpers.js +28 -86
- package/dist/native-region-scanner-js-imports.js +121 -1
- package/dist/native-region-scanner-js-nested.js +96 -8
- package/dist/native-region-scanner-js-structure.js +27 -0
- package/dist/native-region-scanner-js-types.js +99 -0
- package/dist/native-region-scanner-js.js +70 -118
- package/dist/native-region-scanner-kotlin.js +94 -0
- package/dist/native-region-scanner-main.js +15 -181
- package/dist/native-region-scanner-php.js +80 -0
- package/dist/native-region-scanner-python.js +62 -0
- package/dist/native-region-scanner-ruby.js +72 -0
- package/dist/native-region-scanner-scala.js +91 -0
- package/dist/native-region-scanner-spans.js +74 -0
- package/dist/native-region-scanner-swift.js +155 -0
- package/dist/native-region-scanner.js +14 -10
- package/dist/native-source-ledger-helpers.js +195 -0
- package/dist/native-source-ledger.js +306 -0
- package/dist/native-source-preservation-scanner.js +4 -0
- package/dist/semantic-import-callsite-regions.js +136 -0
- package/dist/semantic-import-effect-regions.js +283 -0
- package/dist/semantic-import-regions.js +11 -2
- package/dist/semantic-import-sidecar-entry.js +16 -2
- package/dist/semantic-import-sidecar-types.d.ts +2 -0
- package/dist/semantic-sidecar-example.js +68 -0
- package/dist/universal-capability-matrix.js +23 -0
- package/dist/universal-conversion-artifact-query.js +79 -2
- package/dist/universal-conversion-artifact-semantic-edit.js +103 -0
- package/dist/universal-conversion-artifact-summary.js +33 -1
- package/dist/universal-conversion-artifacts.js +13 -48
- package/dist/universal-conversion-plan-scoring.js +21 -1
- package/dist/universal-conversion-plan-summary.js +30 -0
- package/dist/universal-conversion-plan.js +25 -9
- package/dist/universal-conversion-route-metadata.js +96 -0
- package/dist/universal-conversion-route-operations.js +7 -0
- package/dist/universal-representation-coverage.js +193 -0
- package/package.json +1 -1
|
@@ -10,6 +10,8 @@ import { diffNativeSourceImports } from './diffNativeSourceImports.js';
|
|
|
10
10
|
import { normalizeNativeDiffImport } from './normalizeNativeDiffImport.js';
|
|
11
11
|
import { attachBidirectionalMatchPortability, classifyBidirectionalTargetPortability } from './bidirectionalTargetPortability.js';
|
|
12
12
|
import { createRoundtripEvidence, createSemanticMergeAdmissionEvidence, summarizeSourceMapBackprojection } from './bidirectionalTargetRoundtripEvidence.js';
|
|
13
|
+
import { createBidirectionalSourceEditProjection } from './bidirectionalSourceEditProjection.js';
|
|
14
|
+
import { createSameLanguageTargetSourceProjection } from './bidirectionalSameLanguageSourceProjection.js';
|
|
13
15
|
import {
|
|
14
16
|
anchorsFromSourceSidecar,
|
|
15
17
|
classifyBidirectionalReadiness,
|
|
@@ -86,6 +88,20 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
86
88
|
...array(targetPortability.reasonCodes),
|
|
87
89
|
...sourceAnchorMatches.flatMap((match) => match.reasonCodes)
|
|
88
90
|
]);
|
|
91
|
+
const sourceMapEditProjection = createBidirectionalSourceEditProjection({
|
|
92
|
+
id,
|
|
93
|
+
source,
|
|
94
|
+
targetChangeSet,
|
|
95
|
+
sourceAnchorMatches,
|
|
96
|
+
targetPortability,
|
|
97
|
+
reasons
|
|
98
|
+
});
|
|
99
|
+
const sourceEditProjection = sourceMapEditProjection.sourceEditScript ? sourceMapEditProjection : createSameLanguageTargetSourceProjection({
|
|
100
|
+
id,
|
|
101
|
+
source,
|
|
102
|
+
targetChangeSet,
|
|
103
|
+
generatedAt: input.generatedAt
|
|
104
|
+
});
|
|
89
105
|
const evidenceId = input.evidenceId ?? `evidence_${idFragment(id)}_bidirectional_target_change`;
|
|
90
106
|
const sourcePatchBundleId = input.sourcePatchBundleId ?? `semantic_patch_bundle_${idFragment(id)}_source_port`;
|
|
91
107
|
const historyRecordId = input.historyRecordId ?? `semantic_history_${idFragment(id)}_target_change`;
|
|
@@ -101,7 +117,8 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
101
117
|
targetPortability,
|
|
102
118
|
readiness,
|
|
103
119
|
reasons,
|
|
104
|
-
sourceMapBackprojection
|
|
120
|
+
sourceMapBackprojection,
|
|
121
|
+
sourceEditProjection
|
|
105
122
|
});
|
|
106
123
|
const semanticMergeAdmission = createSemanticMergeAdmissionEvidence({
|
|
107
124
|
id,
|
|
@@ -113,7 +130,8 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
113
130
|
targetPortability,
|
|
114
131
|
readiness,
|
|
115
132
|
reasons,
|
|
116
|
-
roundtripEvidence
|
|
133
|
+
roundtripEvidence,
|
|
134
|
+
sourceEditProjection
|
|
117
135
|
});
|
|
118
136
|
const bidirectionalEvidence = createBidirectionalEvidence({
|
|
119
137
|
id,
|
|
@@ -131,9 +149,20 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
131
149
|
...bidirectionalEvidence.metadata,
|
|
132
150
|
roundtripEvidenceId: roundtripEvidence.id,
|
|
133
151
|
roundtripEvidence,
|
|
134
|
-
semanticMergeAdmission
|
|
152
|
+
semanticMergeAdmission,
|
|
153
|
+
sourceEditProjectionId: sourceEditProjection.sourceEditProjection?.id,
|
|
154
|
+
sourceEditReplayId: sourceEditProjection.sourceEditReplay?.id,
|
|
155
|
+
sourceEditScriptId: sourceEditProjection.sourceEditScript?.id,
|
|
156
|
+
sourceProjectionHintId: sourceEditProjection.sourceProjectionHint?.id,
|
|
157
|
+
sourceProjectionHint: sourceEditProjection.sourceProjectionHint
|
|
135
158
|
}
|
|
136
|
-
}];
|
|
159
|
+
}, ...(sourceEditProjection.evidence ?? [])];
|
|
160
|
+
const sourceReplayStatus = sourceEditProjection.sourceEditReplay?.status;
|
|
161
|
+
const sourcePatchAdmission = sourceReplayStatus === 'accepted-clean'
|
|
162
|
+
? { readiness: 'ready', reasonCodes: ['bidirectional-source-edit-replay-accepted-clean'] }
|
|
163
|
+
: sourceReplayStatus === 'already-applied'
|
|
164
|
+
? { status: 'admitted', readiness: 'ready', reasonCodes: ['bidirectional-source-edit-replay-already-applied'] }
|
|
165
|
+
: { status: readiness === 'blocked' ? 'blocked' : 'needs-review', readiness };
|
|
137
166
|
const sourceChangedRegions = sourceAnchorMatches.flatMap((match) => sourceRegionsForMatch(match, readiness));
|
|
138
167
|
const sourcePatchBundle = createSemanticPatchBundleRecord({
|
|
139
168
|
id: `${id}_source_port_projection`,
|
|
@@ -159,7 +188,10 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
159
188
|
id: sourcePatchBundleId,
|
|
160
189
|
patchId: targetChangeSet.patch?.id,
|
|
161
190
|
mergeCandidateId: targetChangeSet.mergeCandidate?.id,
|
|
162
|
-
|
|
191
|
+
semanticEditScripts: [sourceEditProjection.sourceEditScript].filter(Boolean),
|
|
192
|
+
semanticEditProjections: [sourceEditProjection.sourceEditProjection].filter(Boolean),
|
|
193
|
+
semanticEditReplays: [sourceEditProjection.sourceEditReplay].filter(Boolean),
|
|
194
|
+
admission: sourcePatchAdmission,
|
|
163
195
|
metadata: {
|
|
164
196
|
source: 'createBidirectionalTargetChangeRecord',
|
|
165
197
|
targetChangeSetId: targetChangeSet.id,
|
|
@@ -169,6 +201,11 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
169
201
|
sourceMapBackprojection,
|
|
170
202
|
roundtripEvidenceId: roundtripEvidence.id,
|
|
171
203
|
semanticMergeAdmission,
|
|
204
|
+
sourceEditScriptId: sourceEditProjection.sourceEditScript?.id,
|
|
205
|
+
sourceEditProjectionId: sourceEditProjection.sourceEditProjection?.id,
|
|
206
|
+
sourceEditReplayId: sourceEditProjection.sourceEditReplay?.id,
|
|
207
|
+
sourceProjectionHintId: sourceEditProjection.sourceProjectionHint?.id,
|
|
208
|
+
sourceProjectionHint: sourceEditProjection.sourceProjectionHint,
|
|
172
209
|
autoMergeClaim: false,
|
|
173
210
|
semanticEquivalenceClaim: false
|
|
174
211
|
}
|
|
@@ -191,7 +228,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
191
228
|
conflictKeys: targetChangeSet.mergeCandidate?.conflictKeys,
|
|
192
229
|
metadata: { direction: 'target-to-source' }
|
|
193
230
|
}] : [],
|
|
194
|
-
admission: { status: readiness
|
|
231
|
+
admission: { status: semanticMergeAdmission.status, readiness: semanticMergeAdmission.readiness, reasonCodes: semanticMergeAdmission.reasonCodes },
|
|
195
232
|
replayLinks: targetChangeSet.patch ? [{
|
|
196
233
|
id: `replay_${idFragment(targetChangeSet.patch.id)}`,
|
|
197
234
|
kind: 'patch',
|
|
@@ -205,6 +242,11 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
205
242
|
sourceMapBackprojection,
|
|
206
243
|
roundtripEvidenceId: roundtripEvidence.id,
|
|
207
244
|
semanticMergeAdmission,
|
|
245
|
+
sourceEditProjectionId: sourceEditProjection.sourceEditProjection?.id,
|
|
246
|
+
sourceEditReplayId: sourceEditProjection.sourceEditReplay?.id,
|
|
247
|
+
sourceEditScriptId: sourceEditProjection.sourceEditScript?.id,
|
|
248
|
+
sourceProjectionHintId: sourceEditProjection.sourceProjectionHint?.id,
|
|
249
|
+
sourceProjectionHint: sourceEditProjection.sourceProjectionHint,
|
|
208
250
|
autoMergeClaim: false,
|
|
209
251
|
semanticEquivalenceClaim: false
|
|
210
252
|
}
|
|
@@ -222,6 +264,10 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
222
264
|
sourceAnchorMatches,
|
|
223
265
|
targetPortability,
|
|
224
266
|
roundtripEvidence,
|
|
267
|
+
sourceEditScript: sourceEditProjection.sourceEditScript,
|
|
268
|
+
sourceEditProjection: sourceEditProjection.sourceEditProjection,
|
|
269
|
+
sourceEditReplay: sourceEditProjection.sourceEditReplay,
|
|
270
|
+
sourceProjectionHint: sourceEditProjection.sourceProjectionHint,
|
|
225
271
|
sourcePatchBundle,
|
|
226
272
|
historyRecord,
|
|
227
273
|
evidence,
|
|
@@ -237,6 +283,8 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
237
283
|
sourceMapBackedMatches: sourceAnchorMatches.filter((match) => match.sourceMapLinks.length > 0).length,
|
|
238
284
|
sourceMapLinks: sourceMapBackprojection.sourceMapLinks,
|
|
239
285
|
sourceMapMappingIds: sourceMapBackprojection.sourceMapMappingIds.length,
|
|
286
|
+
sourceEditScripts: sourceEditProjection.sourceEditScript ? 1 : 0,
|
|
287
|
+
sourceProjectionHints: sourceEditProjection.sourceProjectionHint ? 1 : 0,
|
|
240
288
|
lineageResolutions: roundtripEvidence.lineageEvidence.lineageResolutionIds.length,
|
|
241
289
|
targetPortabilityStatus: targetPortability.status,
|
|
242
290
|
portableTargetRegions: targetPortability.status === 'portable' ? targetPortability.targetChangedRegions : 0,
|
|
@@ -246,10 +294,15 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
246
294
|
metadata: {
|
|
247
295
|
autoMergeClaim: false,
|
|
248
296
|
semanticEquivalenceClaim: false,
|
|
249
|
-
reviewRequired:
|
|
297
|
+
reviewRequired: sourcePatchBundle.admission.reviewRequired,
|
|
250
298
|
targetPortability,
|
|
251
299
|
roundtripEvidenceId: roundtripEvidence.id,
|
|
252
300
|
semanticMergeAdmission,
|
|
301
|
+
sourceEditScriptId: sourceEditProjection.sourceEditScript?.id,
|
|
302
|
+
sourceEditProjectionId: sourceEditProjection.sourceEditProjection?.id,
|
|
303
|
+
sourceEditReplayId: sourceEditProjection.sourceEditReplay?.id,
|
|
304
|
+
sourceProjectionHintId: sourceEditProjection.sourceProjectionHint?.id,
|
|
305
|
+
sourceProjectionHint: sourceEditProjection.sourceProjectionHint,
|
|
253
306
|
...input.metadata
|
|
254
307
|
}
|
|
255
308
|
};
|
|
@@ -53,6 +53,7 @@ export function createLightweightNativeImport(input) {
|
|
|
53
53
|
signatureHash: hashSemanticValue([input.language, declaration.kind, declaration.name, declaration.fields ?? {}]),
|
|
54
54
|
definitionSpan: declaration.span,
|
|
55
55
|
metadata: {
|
|
56
|
+
...declaration.metadata,
|
|
56
57
|
ownershipRegionId: ownershipRegion.id,
|
|
57
58
|
ownershipRegionKey: ownershipRegion.key,
|
|
58
59
|
ownershipRegionKind: ownershipRegion.regionKind
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
|
|
2
|
+
import { countBy, idFragment, uniqueStrings } from '../../native-import-utils.js';
|
|
3
|
+
import {
|
|
4
|
+
detectNewlineStyle,
|
|
5
|
+
isJavaScriptTypeScriptSource,
|
|
6
|
+
scanJavaScriptTypeScriptSourceLedger,
|
|
7
|
+
scanPreservedSourceDirectives,
|
|
8
|
+
scanPreservedSourceTokens
|
|
9
|
+
} from '../../native-region-scanner.js';
|
|
10
|
+
|
|
2
11
|
export function createNativeSourcePreservation(options) {
|
|
3
12
|
if (!options || typeof options.sourceText !== 'string') {
|
|
4
13
|
throw new Error('createNativeSourcePreservation requires sourceText');
|
|
@@ -26,6 +35,14 @@ export function createNativeSourcePreservation(options) {
|
|
|
26
35
|
maxDirectives: options.maxDirectives
|
|
27
36
|
});
|
|
28
37
|
const directives = directiveScan.directives;
|
|
38
|
+
const ledger = options.includeSourceLedger === false || !isJavaScriptTypeScriptSource(language, options.sourcePath)
|
|
39
|
+
? undefined
|
|
40
|
+
: scanJavaScriptTypeScriptSourceLedger(sourceText, {
|
|
41
|
+
language,
|
|
42
|
+
sourcePath: options.sourcePath,
|
|
43
|
+
sourceHash,
|
|
44
|
+
maxLedgerSpans: options.maxLedgerSpans
|
|
45
|
+
});
|
|
29
46
|
const triviaByKind = countBy(tokensAndTrivia.trivia.map((entry) => entry.kind ?? 'unknown'));
|
|
30
47
|
const directivesByKind = countBy(directives.map((entry) => entry.kind ?? 'directive'));
|
|
31
48
|
const directiveKinds = uniqueStrings(directives.map((entry) => entry.kind ?? 'directive'));
|
|
@@ -52,23 +69,32 @@ export function createNativeSourcePreservation(options) {
|
|
|
52
69
|
tokens: tokensAndTrivia.tokens,
|
|
53
70
|
trivia: tokensAndTrivia.trivia,
|
|
54
71
|
directives,
|
|
72
|
+
...(ledger ? { ledger } : {}),
|
|
55
73
|
summary: {
|
|
56
74
|
tokens: tokensAndTrivia.tokens.length,
|
|
57
75
|
trivia: tokensAndTrivia.trivia.length,
|
|
58
76
|
directives: directives.length,
|
|
59
77
|
comments: tokensAndTrivia.trivia.filter((entry) => entry.kind === 'comment').length,
|
|
60
78
|
whitespace: tokensAndTrivia.trivia.filter((entry) => entry.kind === 'whitespace' || entry.kind === 'newline').length,
|
|
79
|
+
...(ledger ? {
|
|
80
|
+
ledger: ledger.summary,
|
|
81
|
+
sourceMapComments: ledger.summary.sourceMapComments,
|
|
82
|
+
protectedRegions: ledger.summary.protectedRegions,
|
|
83
|
+
importExportSpans: ledger.summary.importExportSpans,
|
|
84
|
+
braces: ledger.summary.braces
|
|
85
|
+
} : {}),
|
|
61
86
|
triviaByKind,
|
|
62
87
|
directivesByKind,
|
|
63
88
|
directiveKinds,
|
|
64
89
|
commentSpanIds,
|
|
65
90
|
directiveSpanIds,
|
|
66
91
|
exactSourceAvailable: options.includeSourceText !== false,
|
|
67
|
-
truncated: tokensAndTrivia.truncated || directiveScan.truncated
|
|
92
|
+
truncated: tokensAndTrivia.truncated || directiveScan.truncated || Boolean(ledger?.summary?.truncated)
|
|
68
93
|
},
|
|
69
94
|
metadata: {
|
|
70
95
|
preservation: 'source-text-token-trivia-directive-evidence',
|
|
71
96
|
tokenization: 'frontier-lightweight-lexical-scan',
|
|
97
|
+
...(ledger ? { sourceLedger: 'frontier-lightweight-js-ts-source-ledger' } : {}),
|
|
72
98
|
...(declaredSourceHash ? {
|
|
73
99
|
declaredSourceHash,
|
|
74
100
|
sourceHashVerified: declaredSourceHash === computedSourceHash
|
|
@@ -59,7 +59,7 @@ function nativeDiffSymbolHasOwnChange(symbol) {
|
|
|
59
59
|
|
|
60
60
|
function nativeDiffSymbolIsMorePreciseNestedChange(candidate, container) {
|
|
61
61
|
if (candidate.changeKind === 'unchanged') return false;
|
|
62
|
-
if (nativeDiffSymbolIsContainer(candidate)) return false;
|
|
62
|
+
if (nativeDiffSymbolIsContainer(candidate) && !nativeDiffSymbolIsMember(candidate)) return false;
|
|
63
63
|
if ((candidate.ownershipKey ?? '') === (container.ownershipKey ?? '')) return false;
|
|
64
64
|
if (!nativeDiffAnySpanContains(container, candidate)) return false;
|
|
65
65
|
return nativeDiffNestedSymbolName(candidate, container) || nativeDiffSymbolIsMember(candidate);
|
|
@@ -118,5 +118,5 @@ function nativeDiffKind(value) {
|
|
|
118
118
|
return String(value ?? '').toLowerCase();
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
const nativeDiffContainerKinds = new Set(['type', 'class', 'interface', 'trait', 'protocol', 'struct', 'enum', 'record']);
|
|
122
|
-
const nativeDiffMemberKinds = new Set(['body', 'method', 'function', 'property', 'declaration']);
|
|
121
|
+
const nativeDiffContainerKinds = new Set(['type', 'class', 'interface', 'trait', 'protocol', 'struct', 'enum', 'record', 'body', 'function', 'method', 'export']);
|
|
122
|
+
const nativeDiffMemberKinds = new Set(['body', 'method', 'function', 'property', 'declaration', 'call', 'effect', 'controlflow', 'mutation']);
|
|
@@ -23,6 +23,8 @@ export function nativeChangeProjectionSourceMapLinks(imported, side, region, sym
|
|
|
23
23
|
precision: mapping.precision,
|
|
24
24
|
sourceSpan: mapping.sourceSpan,
|
|
25
25
|
generatedSpan: mapping.generatedSpan,
|
|
26
|
+
sourceReplacementText: mapping.sourceReplacementText,
|
|
27
|
+
sourceReplacementTextHash: mapping.sourceReplacementTextHash ?? mapping.sourceReplacementHash,
|
|
26
28
|
ownershipRegionId: mapping.ownershipRegionId,
|
|
27
29
|
ownershipRegionKey: mapping.ownershipRegionKey,
|
|
28
30
|
ownershipRegionKind: mapping.ownershipRegionKind
|
|
@@ -4,7 +4,9 @@ import { createSemanticImportSidecar } from './createSemanticImportSidecar.js';
|
|
|
4
4
|
import { mapDiffSymbols } from './mapDiffSymbols.js';
|
|
5
5
|
import { normalizeNativeDiffImport } from './normalizeNativeDiffImport.js';
|
|
6
6
|
import { alreadyAppliedImportEditForOperation } from './semanticEditImportProjection.js';
|
|
7
|
+
import { explicitSourceReplacementEditForOperation } from './semanticEditExplicitSourceReplacement.js';
|
|
7
8
|
import { projectionEditRecord } from './semanticEditProjectionRecord.js';
|
|
9
|
+
import { findCurrentSymbol } from './semanticEditReplayAnchors.js';
|
|
8
10
|
import {
|
|
9
11
|
insertionOffset,
|
|
10
12
|
insertionReplacement,
|
|
@@ -23,7 +25,7 @@ export function projectSemanticEditScriptToSource(input = {}) {
|
|
|
23
25
|
if (typeof workerSourceText !== 'string') reasonCodes.push('missing-worker-source-text');
|
|
24
26
|
if (typeof headSourceText !== 'string') reasonCodes.push('missing-head-source-text');
|
|
25
27
|
const language = normalizeNativeLanguageId(script.language);
|
|
26
|
-
const headSymbols = typeof headSourceText === 'string' &&
|
|
28
|
+
const headSymbols = typeof headSourceText === 'string' && language
|
|
27
29
|
? sourceSymbolIndex({
|
|
28
30
|
sourceText: headSourceText,
|
|
29
31
|
sourcePath: input.headSourcePath ?? script.sourcePath,
|
|
@@ -42,7 +44,7 @@ export function projectSemanticEditScriptToSource(input = {}) {
|
|
|
42
44
|
const edit = sourceEditForOperation(operation, workerSourceText, headSourceText, index, {
|
|
43
45
|
headSourcePath: input.headSourcePath,
|
|
44
46
|
headSymbols,
|
|
45
|
-
symbolIndexAvailable:
|
|
47
|
+
symbolIndexAvailable: headSymbols.length > 0
|
|
46
48
|
});
|
|
47
49
|
if (edit.ok) edits.push(edit.value);
|
|
48
50
|
else reasonCodes.push(...edit.reasonCodes);
|
|
@@ -95,14 +97,16 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText, ord
|
|
|
95
97
|
return { ok: true, value: { ...identity, operationId: operation.id, order, start: 0, end: 0, replacement: '', current: '', alreadyApplied: true } };
|
|
96
98
|
}
|
|
97
99
|
if (operation.status !== 'portable') return { ok: false, reasonCodes: [`operation-not-portable:${operation.id}`] };
|
|
100
|
+
const explicit = explicitSourceReplacementEditForOperation(operation, identity, headSourceText, order);
|
|
101
|
+
if (explicit) return explicit;
|
|
98
102
|
if (operation.changeKind === 'added' || String(operation.kind ?? '').startsWith('add')) {
|
|
99
103
|
return insertionEditForOperation(operation, identity, workerSourceText, headSourceText, order, context);
|
|
100
104
|
}
|
|
101
105
|
if (operation.changeKind === 'removed' || String(operation.kind ?? '').startsWith('remove')) {
|
|
102
|
-
return removalEditForOperation(operation, identity, headSourceText, order);
|
|
106
|
+
return removalEditForOperation(operation, identity, headSourceText, order, context);
|
|
103
107
|
}
|
|
104
108
|
const workerOffsets = spanOffsets(workerSourceText, operation.spans?.worker);
|
|
105
|
-
const headOffsets =
|
|
109
|
+
const headOffsets = headOffsetsForOperation(operation, identity, headSourceText, context);
|
|
106
110
|
const reasons = [];
|
|
107
111
|
if (!workerOffsets) reasons.push(`worker-span-not-resolvable:${operation.id}`);
|
|
108
112
|
if (!headOffsets) reasons.push(`head-span-not-resolvable:${operation.id}`);
|
|
@@ -118,9 +122,12 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText, ord
|
|
|
118
122
|
}
|
|
119
123
|
if (reasons.length) return { ok: false, reasonCodes: reasons };
|
|
120
124
|
const scoped = scopedBodyReplacement(operation, headSourceText, workerSourceText, headOffsets, workerOffsets);
|
|
121
|
-
const
|
|
125
|
+
const rawReplacement = scoped
|
|
122
126
|
? workerSourceText.slice(scoped.worker.start, scoped.worker.end)
|
|
123
127
|
: anchorReplacement;
|
|
128
|
+
const replacement = operation.metadata?.sourceBackprojection?.lineEndingStable
|
|
129
|
+
? normalizeReplacementLineEndings(rawReplacement, anchorCurrent)
|
|
130
|
+
: rawReplacement;
|
|
124
131
|
const current = scoped
|
|
125
132
|
? headSourceText.slice(scoped.head.start, scoped.head.end)
|
|
126
133
|
: anchorCurrent;
|
|
@@ -147,8 +154,8 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText, ord
|
|
|
147
154
|
}
|
|
148
155
|
};
|
|
149
156
|
}
|
|
150
|
-
function removalEditForOperation(operation, identity, headSourceText, order) {
|
|
151
|
-
const headOffsets =
|
|
157
|
+
function removalEditForOperation(operation, identity, headSourceText, order, context) {
|
|
158
|
+
const headOffsets = headOffsetsForOperation(operation, identity, headSourceText, context);
|
|
152
159
|
const reasons = [];
|
|
153
160
|
if (!headOffsets) reasons.push(`head-span-not-resolvable:${operation.id}`);
|
|
154
161
|
if (reasons.length) return { ok: false, reasonCodes: reasons };
|
|
@@ -173,6 +180,35 @@ function removalEditForOperation(operation, identity, headSourceText, order) {
|
|
|
173
180
|
}
|
|
174
181
|
};
|
|
175
182
|
}
|
|
183
|
+
|
|
184
|
+
function headOffsetsForOperation(operation, identity, headSourceText, context) {
|
|
185
|
+
const span = operation.spans?.head ?? operation.spans?.base ?? operation.anchor?.sourceSpan;
|
|
186
|
+
const spanRange = spanOffsets(headSourceText, span);
|
|
187
|
+
const symbol = context.symbolIndexAvailable ? findCurrentSymbol(identity, context.headSymbols) : undefined;
|
|
188
|
+
const symbolRange = spanOffsets(headSourceText, symbol?.sourceSpan);
|
|
189
|
+
if (!symbolRange) return spanRange;
|
|
190
|
+
if (!spanRange || sameRange(spanRange, symbolRange)) return symbolRange;
|
|
191
|
+
const expectedHash = operation.hashes?.headTextHash ?? operation.hashes?.baseTextHash;
|
|
192
|
+
if (expectedHash && rangeHash(headSourceText, symbolRange) === expectedHash) return symbolRange;
|
|
193
|
+
if (expectedHash && rangeHash(headSourceText, spanRange) === expectedHash) return spanRange;
|
|
194
|
+
return spanRange;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function rangeHash(sourceText, range) {
|
|
198
|
+
return range && typeof sourceText === 'string'
|
|
199
|
+
? hashSemanticValue(sourceText.slice(range.start, range.end))
|
|
200
|
+
: undefined;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function sameRange(left, right) {
|
|
204
|
+
return left?.start === right?.start && left?.end === right?.end;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function normalizeReplacementLineEndings(replacement, current) {
|
|
208
|
+
const newline = current.includes('\r\n') ? '\r\n' : current.includes('\r') ? '\r' : '\n';
|
|
209
|
+
return String(replacement ?? '').replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\n/g, newline);
|
|
210
|
+
}
|
|
211
|
+
|
|
176
212
|
function insertionEditForOperation(operation, identity, workerSourceText, headSourceText, order, context) {
|
|
177
213
|
const workerOffsets = spanOffsets(workerSourceText, operation.spans?.worker);
|
|
178
214
|
const reasons = [];
|
|
@@ -263,7 +299,6 @@ function projectedSourcePath(script, edits) {
|
|
|
263
299
|
return edits.map((edit) => edit.sourcePath).find(Boolean) ?? script.sourcePath;
|
|
264
300
|
}
|
|
265
301
|
|
|
266
|
-
function isJavaScriptLike(language) { return language === 'javascript' || language === 'typescript'; }
|
|
267
302
|
function compactRecord(value) {
|
|
268
303
|
return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
|
|
269
304
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
function replayReplacementText(edit, status, range, sourceText) {
|
|
2
|
+
const replacement = edit.replacementText;
|
|
3
|
+
if (status !== 'applied'
|
|
4
|
+
|| typeof replacement !== 'string'
|
|
5
|
+
|| !/[\r\n]/.test(replacement)
|
|
6
|
+
|| typeof sourceText !== 'string') return replacement;
|
|
7
|
+
return replacement.replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\n/g, replayLineEnding(sourceText, range));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function replayLineEnding(sourceText, range) {
|
|
11
|
+
const offset = Math.max(0, Math.min(sourceText.length, range?.start ?? 0));
|
|
12
|
+
return lineEndingInText(range ? sourceText.slice(range.start, range.end) : '')
|
|
13
|
+
?? nearbyLineEnding(sourceText, offset)
|
|
14
|
+
?? lineEndingInText(sourceText)
|
|
15
|
+
?? '\n';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function lineEndingInText(value) { return /\r\n|\r|\n/.exec(value)?.[0]; }
|
|
19
|
+
|
|
20
|
+
function nearbyLineEnding(sourceText, offset) {
|
|
21
|
+
for (let distance = 0; distance <= sourceText.length; distance += 1) {
|
|
22
|
+
const ending = lineEndingAt(sourceText, offset - distance - 1) ?? lineEndingAt(sourceText, offset + distance);
|
|
23
|
+
if (ending) return ending;
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function lineEndingAt(sourceText, index) {
|
|
29
|
+
const char = sourceText[index];
|
|
30
|
+
if (char === '\n') return sourceText[index - 1] === '\r' ? '\r\n' : '\n';
|
|
31
|
+
return char === '\r' ? sourceText[index + 1] === '\n' ? '\r\n' : '\r' : undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { replayReplacementText };
|
|
@@ -3,7 +3,9 @@ import { idFragment, normalizeNativeLanguageId, uniqueStrings } from '../../nati
|
|
|
3
3
|
import { createSemanticImportSidecar } from './createSemanticImportSidecar.js';
|
|
4
4
|
import { mapDiffSymbols } from './mapDiffSymbols.js';
|
|
5
5
|
import { normalizeNativeDiffImport } from './normalizeNativeDiffImport.js';
|
|
6
|
+
import { replayReplacementText } from './replaySemanticEditLineEndings.js';
|
|
6
7
|
import { replayDiagnostics, replayEditDiagnostics, replayEditsWithOverlapDiagnostics } from './semanticEditReplayDiagnostics.js';
|
|
8
|
+
import { explicitSourceReplacementReplayRange } from './semanticEditReplaySourceReplacement.js';
|
|
7
9
|
import {
|
|
8
10
|
findCurrentSymbol,
|
|
9
11
|
findInsertionAnchor,
|
|
@@ -22,14 +24,14 @@ export function replaySemanticEditProjection(input = {}) {
|
|
|
22
24
|
const reasonCodes = baseReasonCodes(projection, currentSourceText);
|
|
23
25
|
const currentHash = typeof currentSourceText === 'string' ? hashSemanticValue(currentSourceText) : undefined;
|
|
24
26
|
if (input.currentSourceHash && currentHash !== input.currentSourceHash) reasonCodes.push('current-source-hash-mismatch');
|
|
25
|
-
const currentSymbols = currentSourceText &&
|
|
27
|
+
const currentSymbols = currentSourceText && language
|
|
26
28
|
? currentSymbolIndex({ currentSourceText, sourcePath, language, parser: input.parser })
|
|
27
29
|
: [];
|
|
28
30
|
const replayedEdits = projection.status === 'projected' && typeof currentSourceText === 'string'
|
|
29
31
|
? (projection.edits ?? []).map((edit, index) => replayProjectionEdit(projectionEditWithOrder(edit, index), {
|
|
30
32
|
currentSourceText,
|
|
31
33
|
currentSymbols,
|
|
32
|
-
symbolIndexAvailable:
|
|
34
|
+
symbolIndexAvailable: currentSymbols.length > 0
|
|
33
35
|
}))
|
|
34
36
|
: [];
|
|
35
37
|
const edits = replayEditsWithOverlapDiagnostics(replayedEdits);
|
|
@@ -80,20 +82,28 @@ function replayProjectionEdit(edit, context) {
|
|
|
80
82
|
const headRange = { start: edit.headStart, end: edit.headEnd };
|
|
81
83
|
const offset = checkRange(edit, headRange, context.currentSourceText, 'head-offset');
|
|
82
84
|
const symbol = findCurrentSymbol(edit, context.currentSymbols);
|
|
83
|
-
const
|
|
85
|
+
const symbolRange = spanOffsets(context.currentSourceText, symbol?.sourceSpan);
|
|
86
|
+
const explicitRange = explicitSourceReplacementReplayRange(edit, symbolRange, context.currentSourceText);
|
|
87
|
+
const spanRange = explicitRange?.range ?? currentSymbolEditRange(edit, symbolRange, context.currentSourceText);
|
|
88
|
+
const reanchorReason = explicitRange?.reasonCode ?? 'offset-reanchored-by-symbol';
|
|
89
|
+
const explicitConflictReasons = explicitRange?.conflictReasonCodes ?? [];
|
|
84
90
|
if (symbol && spanRange && !sameRange(headRange, spanRange)) {
|
|
85
91
|
const moved = checkRange(edit, spanRange, context.currentSourceText, currentSymbolRangeLabel(edit));
|
|
86
|
-
if (moved) return replayEditRecord(edit, moved.status, replayAppliedRange(edit, moved.range, context.currentSourceText), [moved.reason,
|
|
92
|
+
if (moved) return replayEditRecord(edit, moved.status, replayAppliedRange(edit, moved.range, context.currentSourceText), [moved.reason, reanchorReason], context.currentSourceText);
|
|
93
|
+
if (offset && containedRange(headRange, spanRange)) {
|
|
94
|
+
return replayEditRecord(edit, offset.status, offset.range, [offset.reason, 'offset-contained-in-current-symbol'], context.currentSourceText);
|
|
95
|
+
}
|
|
87
96
|
if (edit.editKind === 'delete' && offset && rangesOverlap(headRange, spanRange)) {
|
|
88
97
|
return replayEditRecord(edit, offset.status, offset.range, [offset.reason], context.currentSourceText);
|
|
89
98
|
}
|
|
90
|
-
return replayEditRecord(edit, 'conflict', spanRange, [`${currentSymbolRangeLabel(edit)}-content-mismatch
|
|
99
|
+
return replayEditRecord(edit, 'conflict', spanRange, [`${currentSymbolRangeLabel(edit)}-content-mismatch`, ...explicitConflictReasons], context.currentSourceText);
|
|
91
100
|
}
|
|
92
101
|
if (offset) return replayEditRecord(edit, offset.status, offset.range, [offset.reason], context.currentSourceText);
|
|
93
102
|
const anchored = checkRange(edit, spanRange, context.currentSourceText, currentSymbolRangeLabel(edit));
|
|
94
|
-
if (anchored) return replayEditRecord(edit, anchored.status, replayAppliedRange(edit, anchored.range, context.currentSourceText), [anchored.reason,
|
|
103
|
+
if (anchored) return replayEditRecord(edit, anchored.status, replayAppliedRange(edit, anchored.range, context.currentSourceText), [anchored.reason, reanchorReason], context.currentSourceText);
|
|
95
104
|
return replayEditRecord(edit, symbol ? 'conflict' : 'stale', spanRange, [
|
|
96
|
-
symbol ? `${currentSymbolRangeLabel(edit)}-content-mismatch` : 'current-symbol-anchor-missing'
|
|
105
|
+
symbol ? `${currentSymbolRangeLabel(edit)}-content-mismatch` : 'current-symbol-anchor-missing',
|
|
106
|
+
...explicitConflictReasons
|
|
97
107
|
], context.currentSourceText);
|
|
98
108
|
}
|
|
99
109
|
|
|
@@ -148,6 +158,7 @@ function checkRange(edit, range, sourceText, label) {
|
|
|
148
158
|
|
|
149
159
|
function replayEditRecord(edit, status, range, reasonCodes, sourceText) {
|
|
150
160
|
const normalizedReasonCodes = reasonList(reasonCodes);
|
|
161
|
+
const replacementText = replayReplacementText(edit, status, range, sourceText);
|
|
151
162
|
return compactRecord({
|
|
152
163
|
operationId: edit.operationId,
|
|
153
164
|
semanticKey: edit.semanticKey,
|
|
@@ -163,21 +174,25 @@ function replayEditRecord(edit, status, range, reasonCodes, sourceText) {
|
|
|
163
174
|
status,
|
|
164
175
|
start: range?.start,
|
|
165
176
|
end: range?.end,
|
|
166
|
-
replacementBytes: edit.replacementBytes,
|
|
167
|
-
replacementText
|
|
177
|
+
replacementBytes: typeof replacementText === 'string' ? replacementText.length : edit.replacementBytes,
|
|
178
|
+
replacementText,
|
|
168
179
|
reasonCodes: normalizedReasonCodes,
|
|
169
180
|
diagnostics: replayEditDiagnostics(edit, status, range, normalizedReasonCodes, sourceText)
|
|
170
181
|
});
|
|
171
182
|
}
|
|
172
183
|
|
|
173
184
|
function currentSymbolIndex(input) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
185
|
+
try {
|
|
186
|
+
const imported = normalizeNativeDiffImport({
|
|
187
|
+
language: input.language,
|
|
188
|
+
sourcePath: input.sourcePath,
|
|
189
|
+
sourceText: input.currentSourceText,
|
|
190
|
+
parser: input.parser
|
|
191
|
+
}, input, 'current');
|
|
192
|
+
return [...mapDiffSymbols(imported, createSemanticImportSidecar(imported)).values()];
|
|
193
|
+
} catch {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
181
196
|
}
|
|
182
197
|
|
|
183
198
|
function currentSymbolEditRange(edit, symbolRange, sourceText) {
|
|
@@ -187,6 +202,7 @@ function currentSymbolEditRange(edit, symbolRange, sourceText) {
|
|
|
187
202
|
}
|
|
188
203
|
|
|
189
204
|
function currentSymbolRangeLabel(edit) {
|
|
205
|
+
if (edit.sourceRangeKind === 'cross-language-explicit-source-replacement') return 'current-symbol-explicit-source-replacement';
|
|
190
206
|
return edit.sourceRangeKind === 'body-content' ? 'current-symbol-body' : 'current-symbol-anchor';
|
|
191
207
|
}
|
|
192
208
|
|
|
@@ -202,10 +218,11 @@ function replayStatus(reasonCodes, edits, projection) {
|
|
|
202
218
|
|
|
203
219
|
function replayAdmission(status, reasonCodes, edits) {
|
|
204
220
|
const apply = status === 'accepted-clean';
|
|
221
|
+
const skip = status === 'already-applied';
|
|
205
222
|
return {
|
|
206
223
|
status,
|
|
207
|
-
action: apply ? 'apply' :
|
|
208
|
-
reviewRequired: !apply,
|
|
224
|
+
action: apply ? 'apply' : skip ? 'skip' : status === 'stale' ? 'rerun-semantic-import' : status === 'blocked' ? 'block' : 'human-review',
|
|
225
|
+
reviewRequired: !(apply || skip),
|
|
209
226
|
autoApplyCandidate: apply,
|
|
210
227
|
autoMergeClaim: false,
|
|
211
228
|
semanticEquivalenceClaim: false,
|
|
@@ -269,7 +286,10 @@ function rangesOverlap(left, right) {
|
|
|
269
286
|
return Boolean(left && right && left.start < right.end && right.start < left.end);
|
|
270
287
|
}
|
|
271
288
|
|
|
272
|
-
function
|
|
289
|
+
function containedRange(inner, outer) {
|
|
290
|
+
return Boolean(inner && outer && outer.start <= inner.start && inner.end <= outer.end);
|
|
291
|
+
}
|
|
292
|
+
|
|
273
293
|
function reasonList(values) { return uniqueStrings((values ?? []).filter(Boolean)); }
|
|
274
294
|
function lineEndingStableText(value) {
|
|
275
295
|
if (typeof value !== 'string') return undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { normalizeSemanticMergeReadiness, uniqueStrings } from '../../native-import-utils.js';
|
|
2
|
+
import { summarizeSemanticSidecarQuality } from './semanticSidecarQuality.js';
|
|
2
3
|
|
|
3
4
|
export const SemanticEditBundleAdmissionStatuses = Object.freeze([
|
|
4
5
|
'none',
|
|
@@ -15,7 +16,7 @@ export function createSemanticEditBundleAdmission(input = {}, options = {}) {
|
|
|
15
16
|
const projections = array(input.semanticEditProjections ?? input.projections ?? input.semanticEditProjection);
|
|
16
17
|
const replays = array(input.semanticEditReplays ?? input.replays ?? input.semanticEditReplay);
|
|
17
18
|
const evidence = evidenceRecords(input, options);
|
|
18
|
-
const summary = summarizeSemanticEditBundle(scripts, projections, replays, evidence);
|
|
19
|
+
const summary = summarizeSemanticEditBundle(scripts, projections, replays, evidence, input, options);
|
|
19
20
|
const computedStatus = semanticEditBundleStatus(summary);
|
|
20
21
|
const status = safeStatus(input.status ?? options.status, computedStatus, summary);
|
|
21
22
|
const readiness = normalizeSemanticMergeReadiness(input.readiness ?? options.readiness ?? readinessForStatus(status))
|
|
@@ -45,7 +46,7 @@ export function createSemanticEditBundleAdmission(input = {}, options = {}) {
|
|
|
45
46
|
});
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
function summarizeSemanticEditBundle(scripts, projections, replays, evidence) {
|
|
49
|
+
function summarizeSemanticEditBundle(scripts, projections, replays, evidence, input, options) {
|
|
49
50
|
const scriptStatusEntries = scripts.map((script) => script.admission?.status);
|
|
50
51
|
const projectionStatusEntries = projections.flatMap((projection) => [projection.status, projection.admission?.status]);
|
|
51
52
|
const replayStatusEntries = replays.map((replay) => replay.status);
|
|
@@ -54,6 +55,7 @@ function summarizeSemanticEditBundle(scripts, projections, replays, evidence) {
|
|
|
54
55
|
const replayStatuses = uniqueStrings(strings(replayStatusEntries));
|
|
55
56
|
const replayActions = uniqueStrings(strings(replays.map((replay) => replay.admission?.action)));
|
|
56
57
|
const evidenceSummary = summarizeEvidence(evidence);
|
|
58
|
+
const sidecarQuality = summarizeSemanticSidecarQuality([input, options, ...scripts, ...projections, ...replays]);
|
|
57
59
|
return {
|
|
58
60
|
scripts: scripts.length,
|
|
59
61
|
projections: projections.length,
|
|
@@ -82,11 +84,13 @@ function summarizeSemanticEditBundle(scripts, projections, replays, evidence) {
|
|
|
82
84
|
failedTestEvidence: evidenceSummary.failed,
|
|
83
85
|
conflictEvidence: evidenceSummary.conflict,
|
|
84
86
|
staleEvidence: evidenceSummary.stale,
|
|
87
|
+
semanticSidecarQuality: sidecarQuality,
|
|
85
88
|
reasonCodes: uniqueStrings([
|
|
86
89
|
...scripts.flatMap((script) => strings(script.admission?.reasonCodes)),
|
|
87
90
|
...projections.flatMap((projection) => strings(projection.admission?.reasonCodes)),
|
|
88
91
|
...replays.flatMap((replay) => strings(replay.admission?.reasonCodes)),
|
|
89
|
-
...evidenceSummary.reasonCodes
|
|
92
|
+
...evidenceSummary.reasonCodes,
|
|
93
|
+
...sidecarQuality.warningCodes
|
|
90
94
|
])
|
|
91
95
|
};
|
|
92
96
|
}
|