@shapeshift-labs/frontier-lang-compiler 0.2.99 → 0.2.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/declarations/semantic-edit-bundle.d.ts +13 -1
  2. package/dist/declarations/semantic-edit-script.d.ts +34 -37
  3. package/dist/declarations/semantic-lineage.d.ts +63 -34
  4. package/dist/declarations/semantic-patch-bundle.d.ts +13 -0
  5. package/dist/internal/index-impl/declarationRecord.js +2 -2
  6. package/dist/internal/index-impl/inferSemanticLineageEvents.js +8 -0
  7. package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +56 -64
  8. package/dist/internal/index-impl/replaySemanticEditProjection.js +54 -22
  9. package/dist/internal/index-impl/semanticEditBundleAdmission.js +95 -12
  10. package/dist/internal/index-impl/semanticEditBundleIndex.js +16 -10
  11. package/dist/internal/index-impl/semanticEditSourceRanges.js +204 -0
  12. package/dist/internal/index-impl/semanticHistoryLineageResolution.js +35 -1
  13. package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +2 -2
  14. package/dist/internal/index-impl/semanticLineageInferenceMatching.js +150 -13
  15. package/dist/internal/index-impl/semanticLineageResolutionRecords.js +28 -1
  16. package/dist/internal/index-impl/semanticPatchBundleAdmission.js +122 -20
  17. package/dist/internal/index-impl/semanticPatchBundleLineageLinks.js +199 -0
  18. package/dist/internal/index-impl/semanticPatchBundleOverlaps.js +6 -2
  19. package/dist/internal/index-impl/semanticPatchBundleRecords.js +28 -104
  20. package/dist/internal/index-impl/semanticPatchBundleSourceRecords.js +127 -0
  21. package/dist/internal/index-impl/sourceTextForSpan.js +4 -9
  22. package/dist/lightweight-dependency-relations.js +113 -7
  23. package/dist/native-import-utils.js +15 -1
  24. package/dist/native-region-scanner-js-helpers.js +61 -17
  25. package/dist/native-region-scanner-js.js +12 -4
  26. package/dist/semantic-import-regions.js +3 -3
  27. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import type { SemanticMergeReadiness } from '@shapeshift-labs/frontier-lang-kernel';
1
+ import type { EvidenceRecord, SemanticMergeReadiness } from '@shapeshift-labs/frontier-lang-kernel';
2
2
  import type { SemanticEditProjection, SemanticEditReplay, SemanticEditScript } from './semantic-edit-script.js';
3
3
 
4
4
  export type SemanticEditBundleAdmissionStatus =
@@ -16,6 +16,8 @@ export interface SemanticEditBundleAdmissionSummary {
16
16
  readonly projections: number;
17
17
  readonly replays: number;
18
18
  readonly files: number;
19
+ readonly portableScripts: number;
20
+ readonly portableProjections: number;
19
21
  readonly acceptedClean: number;
20
22
  readonly alreadyApplied: number;
21
23
  readonly conflicts: number;
@@ -32,6 +34,11 @@ export interface SemanticEditBundleAdmissionSummary {
32
34
  readonly scriptIds: readonly string[];
33
35
  readonly projectionIds: readonly string[];
34
36
  readonly replayIds: readonly string[];
37
+ readonly evidenceIds: readonly string[];
38
+ readonly passedTestEvidence: number;
39
+ readonly failedTestEvidence: number;
40
+ readonly conflictEvidence: number;
41
+ readonly staleEvidence: number;
35
42
  readonly reasonCodes: readonly string[];
36
43
  }
37
44
 
@@ -68,6 +75,11 @@ export interface CreateSemanticEditBundleAdmissionInput {
68
75
  readonly semanticEditReplay?: SemanticEditReplay;
69
76
  readonly semanticEditReplays?: readonly SemanticEditReplay[] | SemanticEditReplay;
70
77
  readonly replays?: readonly SemanticEditReplay[] | SemanticEditReplay;
78
+ readonly evidence?: readonly EvidenceRecord[] | EvidenceRecord;
79
+ readonly testEvidence?: readonly EvidenceRecord[] | EvidenceRecord;
80
+ readonly testResults?: readonly EvidenceRecord[] | EvidenceRecord;
81
+ readonly gateEvidence?: readonly EvidenceRecord[] | EvidenceRecord;
82
+ readonly proofEvidence?: readonly EvidenceRecord[] | EvidenceRecord;
71
83
  readonly metadata?: Record<string, unknown>;
72
84
  }
73
85
 
@@ -1,28 +1,8 @@
1
- import type {
2
- EvidenceRecord,
3
- FrontierSourceLanguage,
4
- SemanticMergeReadiness,
5
- SourceSpan
6
- } from '@shapeshift-labs/frontier-lang-kernel';
1
+ import type { EvidenceRecord, FrontierSourceLanguage, SemanticMergeReadiness, SourceSpan } from '@shapeshift-labs/frontier-lang-kernel';
7
2
  import type { ImportNativeSourceOptions, NativeSourceImportResult } from './import-adapter-core.js';
8
3
 
9
- export type SemanticEditScriptOperationStatus =
10
- | 'candidate'
11
- | 'portable'
12
- | 'already-applied'
13
- | 'covered'
14
- | 'needs-port'
15
- | 'conflict'
16
- | 'stale'
17
- | 'blocked';
18
-
19
- export type SemanticEditScriptAdmissionStatus =
20
- | 'auto-merge-candidate'
21
- | 'needs-port'
22
- | 'conflict'
23
- | 'stale'
24
- | 'blocked'
25
- | 'evidence-only';
4
+ export type SemanticEditScriptOperationStatus = 'candidate' | 'portable' | 'already-applied' | 'covered' | 'needs-port' | 'conflict' | 'stale' | 'blocked';
5
+ export type SemanticEditScriptAdmissionStatus = 'auto-merge-candidate' | 'needs-port' | 'conflict' | 'stale' | 'blocked' | 'evidence-only';
26
6
 
27
7
  export interface SemanticEditScriptOperation {
28
8
  readonly id: string;
@@ -130,7 +110,7 @@ export interface SemanticEditProjectionEdit {
130
110
  readonly operationId?: string;
131
111
  readonly status: 'applied' | 'already-applied';
132
112
  readonly kind?: string;
133
- readonly editKind?: 'replace' | 'insert' | string;
113
+ readonly editKind?: 'replace' | 'insert' | 'delete' | string;
134
114
  readonly changeKind?: string;
135
115
  readonly anchorKey?: string;
136
116
  readonly conflictKey?: string;
@@ -192,14 +172,7 @@ export interface SemanticEditProjection {
192
172
  readonly metadata?: Record<string, unknown>;
193
173
  }
194
174
 
195
- export type SemanticEditReplayStatus =
196
- | 'accepted-clean'
197
- | 'already-applied'
198
- | 'conflict'
199
- | 'stale'
200
- | 'blocked'
201
- | 'needs-port'
202
- | 'evidence-only';
175
+ export type SemanticEditReplayStatus = 'accepted-clean' | 'already-applied' | 'conflict' | 'stale' | 'blocked' | 'needs-port' | 'evidence-only';
203
176
 
204
177
  export interface SemanticEditReplayEdit {
205
178
  readonly operationId?: string;
@@ -207,7 +180,7 @@ export interface SemanticEditReplayEdit {
207
180
  readonly semanticIdentityHash?: string;
208
181
  readonly sourceIdentityHash?: string;
209
182
  readonly editContentHash?: string;
210
- readonly editKind?: 'replace' | 'insert' | string;
183
+ readonly editKind?: 'replace' | 'insert' | 'delete' | string;
211
184
  readonly sourcePath?: string;
212
185
  readonly symbolName?: string;
213
186
  readonly symbolKind?: string;
@@ -269,9 +242,12 @@ export interface ProjectSemanticEditScriptToSourceOptions {
269
242
 
270
243
  export interface ReplaySemanticEditProjectionOptions {
271
244
  readonly id?: string;
272
- readonly projection: SemanticEditProjection;
273
- readonly currentSourceText: string;
245
+ readonly projection?: SemanticEditProjection;
246
+ readonly semanticEditProjection?: SemanticEditProjection;
247
+ readonly currentSourceText?: string;
248
+ readonly headSourceText?: string;
274
249
  readonly currentSourcePath?: string;
250
+ readonly headSourcePath?: string;
275
251
  readonly currentSourceHash?: string;
276
252
  readonly language?: FrontierSourceLanguage | string;
277
253
  readonly parser?: string;
@@ -294,17 +270,38 @@ export interface CreateSemanticEditScriptOptions {
294
270
  readonly workerSourceText?: string;
295
271
  readonly afterSourceText?: string;
296
272
  readonly headSourceText?: string;
273
+ readonly baseSourcePath?: string;
274
+ readonly beforeSourcePath?: string;
275
+ readonly workerSourcePath?: string;
276
+ readonly afterSourcePath?: string;
297
277
  readonly headSourcePath?: string;
298
278
  readonly currentSourceText?: string;
279
+ readonly currentSourcePath?: string;
299
280
  readonly baseSourceHash?: string;
281
+ readonly beforeSourceHash?: string;
300
282
  readonly workerSourceHash?: string;
283
+ readonly afterSourceHash?: string;
301
284
  readonly headSourceHash?: string;
302
- readonly generatedAt?: number;
285
+ readonly currentSourceHash?: string;
286
+ readonly baseMetadata?: Record<string, unknown>;
287
+ readonly beforeMetadata?: Record<string, unknown>;
288
+ readonly workerMetadata?: Record<string, unknown>;
289
+ readonly afterMetadata?: Record<string, unknown>;
290
+ readonly headMetadata?: Record<string, unknown>;
291
+ readonly currentMetadata?: Record<string, unknown>;
292
+ readonly workerChangeSetId?: string;
293
+ readonly headChangeSetId?: string;
294
+ readonly lineageInferenceId?: string;
295
+ readonly generatedAt?: number | string;
303
296
  readonly evidenceId?: string;
304
297
  readonly metadata?: Record<string, unknown>;
305
298
  }
306
299
 
300
+ export interface CreateSemanticEditScriptRuntimeOptions {
301
+ readonly metadata?: Record<string, unknown>;
302
+ }
303
+
307
304
  export declare const SemanticEditScriptAdmissionStatuses: readonly SemanticEditScriptAdmissionStatus[];
308
- export declare function createSemanticEditScript(input?: CreateSemanticEditScriptOptions): SemanticEditScript;
305
+ export declare function createSemanticEditScript(input?: CreateSemanticEditScriptOptions, options?: CreateSemanticEditScriptRuntimeOptions): SemanticEditScript;
309
306
  export declare function projectSemanticEditScriptToSource(input: ProjectSemanticEditScriptToSourceOptions): SemanticEditProjection;
310
307
  export declare function replaySemanticEditProjection(input: ReplaySemanticEditProjectionOptions): SemanticEditReplay;
@@ -1,26 +1,36 @@
1
- import type { FrontierSourceLanguage, SourceSpan } from '@shapeshift-labs/frontier-lang-kernel';
2
- import type { EvidenceRecord, SemanticMergeReadiness } from '@shapeshift-labs/frontier-lang-kernel';
1
+ import type { EvidenceRecord, FrontierSourceLanguage, SemanticMergeReadiness, SourceSpan } from '@shapeshift-labs/frontier-lang-kernel';
3
2
  import type { ImportNativeSourceOptions, NativeSourceImportResult } from './import-adapter-core.js';
4
3
 
5
4
  export type SemanticLineageEventKind = 'unchanged' | 'moved' | 'renamed' | 'split' | 'merged' | 'deleted' | 'recreated' | 'unknown' | string;
6
5
  export type SemanticLineageResolutionStatus = 'unchanged' | 'resolved' | 'ambiguous' | 'deleted' | 'recreated' | 'cycle' | 'max-depth' | 'not-found' | string;
7
6
 
8
7
  export interface SemanticAnchor {
9
- readonly id?: string;
10
- readonly key?: string;
11
- readonly kind?: string;
12
- readonly language?: FrontierSourceLanguage | string;
13
- readonly sourcePath?: string;
14
- readonly sourceHash?: string;
15
- readonly symbolId?: string;
16
- readonly symbolName?: string;
8
+ readonly id?: string; readonly key?: string; readonly kind?: string;
9
+ readonly language?: FrontierSourceLanguage | string; readonly sourcePath?: string; readonly sourceHash?: string;
10
+ readonly symbolId?: string; readonly symbolName?: string;
17
11
  readonly semanticPath?: readonly string[];
18
- readonly signatureHash?: string;
19
- readonly bodyHash?: string;
12
+ readonly signatureHash?: string; readonly bodyHash?: string;
20
13
  readonly sourceSpan?: SourceSpan;
14
+ readonly lineageEventIds?: readonly string[]; readonly terminalLineageEventIds?: readonly string[];
15
+ readonly lineageSourcePaths?: readonly string[]; readonly evidenceIds?: readonly string[];
16
+ readonly proofIds?: readonly string[]; readonly crdtOperationIds?: readonly string[]; readonly crdtHeads?: readonly string[];
17
+ readonly lineageEventKinds?: readonly SemanticLineageEventKind[]; readonly lineageReasonCodes?: readonly string[];
21
18
  readonly metadata?: Record<string, unknown>;
22
19
  }
23
20
 
21
+ export interface CreateSemanticAnchorInput extends SemanticAnchor {
22
+ readonly ownershipKey?: string;
23
+ readonly conflictKey?: string;
24
+ readonly semanticKey?: string;
25
+ readonly anchorKind?: string;
26
+ readonly regionKind?: string;
27
+ readonly symbolKind?: string;
28
+ readonly pathSegments?: readonly string[];
29
+ readonly name?: string;
30
+ readonly hash?: string;
31
+ readonly span?: SourceSpan;
32
+ }
33
+
24
34
  export interface SemanticLineageCrdtClock {
25
35
  readonly operationId?: string;
26
36
  readonly actor?: string;
@@ -31,6 +41,19 @@ export interface SemanticLineageCrdtClock {
31
41
  readonly versionFrame?: Record<string, unknown>;
32
42
  }
33
43
 
44
+ export interface SemanticLineageCrdtClockInput {
45
+ readonly operationId?: string;
46
+ readonly id?: string;
47
+ readonly actor?: string;
48
+ readonly actorId?: string;
49
+ readonly seq?: number;
50
+ readonly deps?: readonly string[] | string;
51
+ readonly heads?: readonly string[] | string;
52
+ readonly stateVector?: Record<string, number>;
53
+ readonly versionFrame?: Record<string, unknown>;
54
+ readonly frame?: Record<string, unknown>;
55
+ }
56
+
34
57
  export interface SemanticLineageEvidence {
35
58
  readonly pathMatch?: boolean;
36
59
  readonly signatureHashMatch?: boolean;
@@ -41,6 +64,10 @@ export interface SemanticLineageEvidence {
41
64
  readonly command?: string;
42
65
  }
43
66
 
67
+ export interface SemanticLineageEvidenceInput extends SemanticLineageEvidence {
68
+ readonly id?: string;
69
+ }
70
+
44
71
  export interface SemanticLineageActor {
45
72
  readonly id?: string;
46
73
  readonly role?: string;
@@ -50,6 +77,10 @@ export interface SemanticLineageActor {
50
77
  readonly metadata?: Record<string, unknown>;
51
78
  }
52
79
 
80
+ export interface SemanticLineageActorInput extends SemanticLineageActor {
81
+ readonly actorId?: string;
82
+ }
83
+
53
84
  export interface SemanticLineageEvent {
54
85
  readonly kind: 'frontier.lang.semanticLineageEvent';
55
86
  readonly version: 1;
@@ -71,32 +102,27 @@ export interface SemanticLineageEvent {
71
102
  }
72
103
 
73
104
  export interface CreateSemanticLineageEventInput {
74
- readonly id?: string;
75
- readonly hash?: string;
76
- readonly createdAt?: number | string;
77
- readonly eventKind?: SemanticLineageEventKind;
78
- readonly event?: SemanticLineageEventKind;
79
- readonly kind?: SemanticLineageEventKind;
80
- readonly from?: SemanticAnchor | string;
81
- readonly fromAnchor?: SemanticAnchor | string;
82
- readonly before?: SemanticAnchor | string;
83
- readonly to?: readonly (SemanticAnchor | string)[] | SemanticAnchor | string;
84
- readonly toAnchors?: readonly (SemanticAnchor | string)[] | SemanticAnchor | string;
85
- readonly after?: readonly (SemanticAnchor | string)[] | SemanticAnchor | string;
86
- readonly confidence?: number;
87
- readonly actor?: SemanticLineageActor | string;
88
- readonly actorId?: string;
89
- readonly actorRole?: string;
90
- readonly crdt?: SemanticLineageCrdtClock;
91
- readonly clock?: SemanticLineageCrdtClock;
92
- readonly operation?: SemanticLineageCrdtClock;
105
+ readonly id?: string; readonly hash?: string; readonly createdAt?: number | string;
106
+ readonly eventKind?: SemanticLineageEventKind; readonly event?: SemanticLineageEventKind; readonly kind?: SemanticLineageEventKind;
107
+ readonly from?: CreateSemanticAnchorInput | string;
108
+ readonly fromAnchor?: CreateSemanticAnchorInput | string;
109
+ readonly before?: CreateSemanticAnchorInput | string;
110
+ readonly to?: readonly (CreateSemanticAnchorInput | string)[] | CreateSemanticAnchorInput | string;
111
+ readonly toAnchors?: readonly (CreateSemanticAnchorInput | string)[] | CreateSemanticAnchorInput | string;
112
+ readonly after?: readonly (CreateSemanticAnchorInput | string)[] | CreateSemanticAnchorInput | string;
113
+ readonly confidence?: number; readonly actor?: SemanticLineageActorInput | string;
114
+ readonly actorId?: string; readonly actorRole?: string;
115
+ readonly crdt?: SemanticLineageCrdtClockInput;
116
+ readonly clock?: SemanticLineageCrdtClockInput;
117
+ readonly operation?: SemanticLineageCrdtClockInput;
93
118
  readonly operationId?: string;
94
119
  readonly seq?: number;
95
120
  readonly deps?: readonly string[] | string;
96
121
  readonly heads?: readonly string[] | string;
97
122
  readonly stateVector?: Record<string, number>;
98
123
  readonly versionFrame?: Record<string, unknown>;
99
- readonly evidence?: SemanticLineageEvidence | readonly { readonly id?: string }[];
124
+ readonly frame?: Record<string, unknown>;
125
+ readonly evidence?: SemanticLineageEvidenceInput | readonly SemanticLineageEvidenceInput[];
100
126
  readonly pathMatch?: boolean;
101
127
  readonly signatureHashMatch?: boolean;
102
128
  readonly bodyHashMatch?: boolean;
@@ -161,6 +187,7 @@ export interface SemanticLineageResolution {
161
187
  readonly currentAnchors: readonly SemanticAnchor[];
162
188
  readonly traversedEventIds: readonly string[];
163
189
  readonly terminalEventIds: readonly string[];
190
+ readonly sourcePaths: readonly string[];
164
191
  readonly status: SemanticLineageResolutionStatus;
165
192
  readonly confidence?: number;
166
193
  readonly conflictKeys: readonly string[];
@@ -236,6 +263,8 @@ export interface SemanticLineageInferenceResult {
236
263
  readonly inferredEvents: number;
237
264
  readonly moved: number;
238
265
  readonly renamed: number;
266
+ readonly split: number;
267
+ readonly recreated: number;
239
268
  readonly deleted: number;
240
269
  readonly ambiguous: number;
241
270
  readonly unmatchedAdded: number;
@@ -280,8 +309,8 @@ export interface InferSemanticLineageEventsOptions {
280
309
 
281
310
  export declare const SemanticLineageEventKinds: readonly SemanticLineageEventKind[];
282
311
  export declare const SemanticLineageResolutionStatuses: readonly SemanticLineageResolutionStatus[];
283
- export declare function createSemanticAnchor(input?: SemanticAnchor | string, defaults?: Partial<SemanticAnchor>): SemanticAnchor | undefined;
284
- export declare function createSemanticLineageEvent(input?: CreateSemanticLineageEventInput, options?: { readonly id?: string; readonly createdAt?: number | string; readonly actor?: SemanticLineageActor | string; readonly actorId?: string; readonly actorRole?: string }): SemanticLineageEvent;
312
+ export declare function createSemanticAnchor(input?: CreateSemanticAnchorInput | string, defaults?: Partial<SemanticAnchor>): SemanticAnchor | undefined;
313
+ export declare function createSemanticLineageEvent(input?: CreateSemanticLineageEventInput, options?: { readonly id?: string; readonly createdAt?: number | string; readonly actor?: SemanticLineageActorInput | string; readonly actorId?: string; readonly actorRole?: string }): SemanticLineageEvent;
285
314
  export declare function createSemanticLineageMap(events?: readonly (SemanticLineageEvent | CreateSemanticLineageEventInput)[], options?: { readonly id?: string; readonly generatedAt?: number | string }): SemanticLineageMap;
286
315
  export declare function inferSemanticLineageEvents(input?: InferSemanticLineageEventsOptions, options?: { readonly metadata?: Record<string, unknown>; readonly deletedConfidence?: number }): SemanticLineageInferenceResult;
287
316
  export declare function querySemanticLineageEvents(events: SemanticLineageEvent | readonly SemanticLineageEvent[], query?: SemanticLineageQuery): readonly SemanticLineageEvent[];
@@ -90,6 +90,7 @@ export interface SemanticPatchBundleAdmission {
90
90
  readonly autoApplyCandidate?: boolean;
91
91
  readonly transformAdmission?: SemanticPatchBundleTransformAdmission;
92
92
  readonly semanticEditAdmission?: SemanticEditBundleAdmission;
93
+ readonly evidenceAdmission?: SemanticPatchBundleEvidenceAdmission;
93
94
  readonly reasonCodes?: readonly string[];
94
95
  readonly conflictKeys?: readonly string[];
95
96
  readonly admittedAt?: number | string;
@@ -98,6 +99,18 @@ export interface SemanticPatchBundleAdmission {
98
99
  readonly metadata?: Record<string, unknown>;
99
100
  }
100
101
 
102
+ export interface SemanticPatchBundleEvidenceAdmission {
103
+ readonly status: 'none' | 'ready' | 'needs-review' | 'stale' | 'blocked' | string;
104
+ readonly action: 'none' | 'admit' | 'review' | 'rerun-semantic-import' | 'block' | string;
105
+ readonly readiness: SemanticMergeReadiness | string;
106
+ readonly reasonCodes?: readonly string[];
107
+ readonly evidenceIds?: readonly string[];
108
+ readonly passed?: number;
109
+ readonly failed?: number;
110
+ readonly conflict?: number;
111
+ readonly stale?: number;
112
+ }
113
+
101
114
  export interface SemanticPatchBundleTransformAdmission {
102
115
  readonly status: 'none' | 'ready' | 'needs-review' | 'blocked' | string;
103
116
  readonly action: 'none' | 'admit' | 'review' | 'block' | string;
@@ -1,11 +1,11 @@
1
- import{idFragment}from'../../native-import-utils.js';
1
+ import{idFragment,caseSensitiveIdFragment}from'../../native-import-utils.js';
2
2
  import{nativeNodeId}from'./nativeNodeId.js';
3
3
  export function declarationRecord(input, nativeNodeId, name, symbolKind, role = 'definition') {
4
4
  return {
5
5
  name: String(name),
6
6
  symbolKind,
7
7
  role,
8
- symbolId: `symbol:${input.language}:${role === 'import' ? 'import:' : ''}${idFragment(name)}`,
8
+ symbolId: `symbol:${input.language}:${role === 'import' ? 'import:' : ''}${caseSensitiveIdFragment(name)}`,
9
9
  nativeNodeId
10
10
  };
11
11
  }
@@ -74,6 +74,8 @@ export function inferSemanticLineageEvents(input = {}, options = {}) {
74
74
  inferredEvents: events.length,
75
75
  moved: events.filter((event) => event.eventKind === 'moved').length,
76
76
  renamed: events.filter((event) => event.eventKind === 'renamed').length,
77
+ split: events.filter((event) => event.eventKind === 'split').length,
78
+ recreated: events.filter((event) => event.eventKind === 'recreated').length,
77
79
  deleted: deleted.length,
78
80
  ambiguous: candidates.ambiguous.length,
79
81
  unmatchedAdded: candidates.unmatchedAfter.length,
@@ -169,6 +171,10 @@ function lineageInferenceEvidence(input) {
169
171
  language: input.language,
170
172
  unchangedAnchors: input.exact.matched.length,
171
173
  inferredEvents: input.events.length,
174
+ moved: input.events.filter((event) => event.eventKind === 'moved').length,
175
+ renamed: input.events.filter((event) => event.eventKind === 'renamed').length,
176
+ split: input.events.filter((event) => event.eventKind === 'split').length,
177
+ recreated: input.events.filter((event) => event.eventKind === 'recreated').length,
172
178
  deleted: input.deleted.length,
173
179
  ambiguous: input.candidates.ambiguous.length,
174
180
  unmatchedAdded: input.candidates.unmatchedAfter.length,
@@ -188,6 +194,8 @@ function inferenceReadiness(input, options) {
188
194
  function inferenceReasons(input) {
189
195
  return uniqueStrings([
190
196
  input.events.length ? 'semantic-lineage-inferred' : undefined,
197
+ input.events.some((event) => event.eventKind === 'split') ? 'split-anchor-lineage-inferred' : undefined,
198
+ input.events.some((event) => event.eventKind === 'recreated') ? 'recreated-anchor-lineage-inferred' : undefined,
191
199
  input.deleted.length ? 'deleted-anchor-lineage-inferred' : undefined,
192
200
  input.added.length ? 'unmatched-added-anchor-review' : undefined,
193
201
  input.ambiguous.length ? 'ambiguous-lineage-candidates' : undefined,
@@ -1,6 +1,14 @@
1
1
  import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
2
2
  import { idFragment, uniqueStrings } from '../../native-import-utils.js';
3
3
  import { semanticEditIdentityFields } from './semanticEditIdentityRecords.js';
4
+ import {
5
+ insertionOffset,
6
+ insertionReplacement,
7
+ projectionCoveredContainerOperationIds,
8
+ removalRange,
9
+ scopedBodyReplacement,
10
+ spanOffsets
11
+ } from './semanticEditSourceRanges.js';
4
12
  import { applySourceEdits, dedupeSourceEdits, validateSourceEdits } from './semanticSourceEditDedupe.js';
5
13
 
6
14
  export function projectSemanticEditScriptToSource(input = {}) {
@@ -9,22 +17,25 @@ export function projectSemanticEditScriptToSource(input = {}) {
9
17
  const headSourceText = input.headSourceText;
10
18
  const reasonCodes = [];
11
19
  if (!script) throw new Error('projectSemanticEditScriptToSource requires a script');
12
- if (script.admission?.status !== 'auto-merge-candidate') reasonCodes.push('script-not-auto-merge-candidate');
13
20
  if (typeof workerSourceText !== 'string') reasonCodes.push('missing-worker-source-text');
14
21
  if (typeof headSourceText !== 'string') reasonCodes.push('missing-head-source-text');
15
22
  const edits = [];
16
23
  const coveredOperationIds = [];
24
+ const projectionCoveredOperationIds = projectionCoveredContainerOperationIds(script.operations ?? [], workerSourceText);
17
25
  for (const [index, operation] of (script.operations ?? []).entries()) {
18
- if (operation.status === 'covered') {
26
+ if (operation.status === 'covered' || projectionCoveredOperationIds.has(operation.id)) {
19
27
  coveredOperationIds.push(operation.id);
20
28
  continue;
21
29
  }
22
- const edit = sourceEditForOperation(operation, workerSourceText, headSourceText, index);
30
+ const edit = sourceEditForOperation(operation, workerSourceText, headSourceText, index, input.headSourcePath);
23
31
  if (edit.ok) edits.push(edit.value);
24
32
  else reasonCodes.push(...edit.reasonCodes);
25
33
  }
26
34
  const deduped = dedupeSourceEdits(edits);
27
35
  reasonCodes.push(...validateSourceEdits(deduped.edits));
36
+ if (script.admission?.status !== 'auto-merge-candidate' && (reasonCodes.length > 0 || (!edits.length && !coveredOperationIds.length))) {
37
+ reasonCodes.push('script-not-auto-merge-candidate');
38
+ }
28
39
  const blocked = reasonCodes.length > 0;
29
40
  const sourceText = blocked ? undefined : applySourceEdits(headSourceText, deduped.edits);
30
41
  const core = {
@@ -62,8 +73,8 @@ export function projectSemanticEditScriptToSource(input = {}) {
62
73
  return { ...core, hash: hashSemanticValue(core) };
63
74
  }
64
75
 
65
- function sourceEditForOperation(operation, workerSourceText, headSourceText, order) {
66
- const identity = projectionIdentity(operation);
76
+ function sourceEditForOperation(operation, workerSourceText, headSourceText, order, headSourcePath) {
77
+ const identity = projectionIdentity(operation, headSourcePath);
67
78
  if (operation.status === 'already-applied') {
68
79
  return { ok: true, value: { ...identity, operationId: operation.id, order, start: 0, end: 0, replacement: '', current: '', alreadyApplied: true } };
69
80
  }
@@ -80,16 +91,23 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText, ord
80
91
  if (!workerOffsets) reasons.push(`worker-span-not-resolvable:${operation.id}`);
81
92
  if (!headOffsets) reasons.push(`head-span-not-resolvable:${operation.id}`);
82
93
  if (reasons.length) return { ok: false, reasonCodes: reasons };
83
- const replacement = workerSourceText.slice(workerOffsets.start, workerOffsets.end);
84
- const current = headSourceText.slice(headOffsets.start, headOffsets.end);
85
- if (operation.hashes?.workerTextHash && hashSemanticValue(replacement) !== operation.hashes.workerTextHash) {
94
+ const anchorReplacement = workerSourceText.slice(workerOffsets.start, workerOffsets.end);
95
+ const anchorCurrent = headSourceText.slice(headOffsets.start, headOffsets.end);
96
+ if (operation.hashes?.workerTextHash && hashSemanticValue(anchorReplacement) !== operation.hashes.workerTextHash) {
86
97
  reasons.push(`worker-span-hash-mismatch:${operation.id}`);
87
98
  }
88
99
  const expectedHeadHash = operation.hashes?.headTextHash ?? operation.hashes?.baseTextHash;
89
- if (expectedHeadHash && hashSemanticValue(current) !== expectedHeadHash) {
100
+ if (expectedHeadHash && hashSemanticValue(anchorCurrent) !== expectedHeadHash) {
90
101
  reasons.push(`head-span-hash-mismatch:${operation.id}`);
91
102
  }
92
103
  if (reasons.length) return { ok: false, reasonCodes: reasons };
104
+ const scoped = scopedBodyReplacement(operation, headSourceText, workerSourceText, headOffsets, workerOffsets);
105
+ const replacement = scoped
106
+ ? workerSourceText.slice(scoped.worker.start, scoped.worker.end)
107
+ : anchorReplacement;
108
+ const current = scoped
109
+ ? headSourceText.slice(scoped.head.start, scoped.head.end)
110
+ : anchorCurrent;
93
111
  return {
94
112
  ok: true,
95
113
  value: {
@@ -97,10 +115,17 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText, ord
97
115
  order,
98
116
  ...identity,
99
117
  editKind: 'replace',
100
- start: headOffsets.start,
101
- end: headOffsets.end,
102
- workerStart: workerOffsets.start,
103
- workerEnd: workerOffsets.end,
118
+ sourceRangeKind: scoped?.sourceRangeKind,
119
+ start: scoped?.head.start ?? headOffsets.start,
120
+ end: scoped?.head.end ?? headOffsets.end,
121
+ workerStart: scoped?.worker.start ?? workerOffsets.start,
122
+ workerEnd: scoped?.worker.end ?? workerOffsets.end,
123
+ headAnchorStart: scoped ? headOffsets.start : undefined,
124
+ headAnchorEnd: scoped ? headOffsets.end : undefined,
125
+ workerAnchorStart: scoped ? workerOffsets.start : undefined,
126
+ workerAnchorEnd: scoped ? workerOffsets.end : undefined,
127
+ anchorDeletedTextHash: scoped ? hashSemanticValue(anchorCurrent) : undefined,
128
+ anchorReplacementTextHash: scoped ? hashSemanticValue(anchorReplacement) : undefined,
104
129
  replacement,
105
130
  current
106
131
  }
@@ -165,9 +190,16 @@ function insertionEditForOperation(operation, identity, workerSourceText, headSo
165
190
  };
166
191
  }
167
192
 
168
- function projectionIdentity(operation) {
193
+ function projectionIdentity(operation, headSourcePath) {
169
194
  const identity = semanticEditIdentity(operation);
170
- return { ...identity, sourcePath: operation.reanchor?.toSourcePath ?? identity.sourcePath };
195
+ const sourcePath = operation.reanchor?.toSourcePath ?? headSourcePath ?? operation.insertion?.sourcePath ?? identity.sourcePath;
196
+ const originalSourcePath = sourcePath && identity.sourcePath && sourcePath !== identity.sourcePath
197
+ ? identity.sourcePath
198
+ : identity.originalSourcePath;
199
+ const targetSourcePath = sourcePath && sourcePath !== identity.sourcePath
200
+ ? sourcePath
201
+ : identity.targetSourcePath;
202
+ return { ...identity, sourcePath, originalSourcePath, targetSourcePath };
171
203
  }
172
204
 
173
205
  function projectionEditRecord(edit) {
@@ -197,18 +229,27 @@ function projectionEditRecord(edit) {
197
229
  operationContentHash: edit.operationContentHash,
198
230
  editContentHash: hashSemanticValue(compactRecord({
199
231
  semanticIdentityHash: identity.semanticIdentityHash,
232
+ sourceRangeKind: edit.sourceRangeKind,
200
233
  deletedTextHash,
201
234
  replacementTextHash,
202
235
  status: edit.alreadyApplied ? 'already-applied' : 'applied'
203
236
  })),
237
+ sourceRangeKind: edit.sourceRangeKind,
204
238
  headStart: edit.start,
205
239
  headEnd: edit.end,
206
240
  workerStart: edit.workerStart,
207
241
  workerEnd: edit.workerEnd,
242
+ editOrder: edit.order,
243
+ headAnchorStart: edit.headAnchorStart,
244
+ headAnchorEnd: edit.headAnchorEnd,
245
+ workerAnchorStart: edit.workerAnchorStart,
246
+ workerAnchorEnd: edit.workerAnchorEnd,
208
247
  deletedBytes: edit.current.length,
209
248
  replacementBytes: edit.replacement.length,
210
249
  deletedTextHash,
211
250
  replacementTextHash,
251
+ anchorDeletedTextHash: edit.anchorDeletedTextHash,
252
+ anchorReplacementTextHash: edit.anchorReplacementTextHash,
212
253
  replacementSpanTextHash: hashSemanticValue(edit.replacementSpanText ?? edit.replacement),
213
254
  insertionMode: edit.insertion?.mode,
214
255
  insertionAnchorKey: edit.insertion?.anchorKey,
@@ -247,55 +288,6 @@ function projectedSourcePath(script, edits) {
247
288
  return edits.map((edit) => edit.sourcePath).find(Boolean) ?? script.sourcePath;
248
289
  }
249
290
 
250
- function spanOffsets(sourceText, span) {
251
- if (typeof sourceText !== 'string' || !span) return undefined;
252
- if (typeof span.start === 'number' && typeof span.end === 'number' && span.end >= span.start) return { start: span.start, end: span.end };
253
- if (typeof span.startLine !== 'number') return undefined;
254
- const lineStarts = [0];
255
- for (let index = 0; index < sourceText.length; index += 1) if (sourceText[index] === '\n') lineStarts.push(index + 1);
256
- const startLine = Math.max(1, span.startLine);
257
- const endLine = Math.max(startLine, typeof span.endLine === 'number' ? span.endLine : startLine);
258
- const start = lineStarts[startLine - 1];
259
- const endLineStart = lineStarts[endLine - 1];
260
- if (start === undefined || endLineStart === undefined) return undefined;
261
- const startColumn = Math.max(1, span.startColumn ?? 1) - 1;
262
- const lineEnd = lineStarts[endLine] === undefined ? sourceText.length : lineStarts[endLine] - 1;
263
- const endColumn = span.endColumn === undefined ? lineEnd - endLineStart : Math.max(1, span.endColumn) - 1;
264
- return { start: start + startColumn, end: endLineStart + endColumn };
265
- }
266
-
267
- function insertionOffset(sourceText, insertion) {
268
- if (typeof sourceText !== 'string') return { ok: false, reasonCodes: ['missing-head-source-text'] };
269
- const mode = insertion?.mode;
270
- if (mode === 'file-start') return { ok: true, offset: 0 };
271
- if (mode === 'file-end') return { ok: true, offset: sourceText.length };
272
- const range = spanOffsets(sourceText, insertion?.headSpan);
273
- if (!range) return { ok: false, reasonCodes: ['insertion-anchor-not-resolvable'] };
274
- if (mode === 'before') return { ok: true, offset: range.start };
275
- if (mode === 'after') return { ok: true, offset: afterLineOffset(sourceText, range.end) };
276
- return { ok: false, reasonCodes: ['insertion-mode-unsupported'] };
277
- }
278
-
279
- function removalRange(sourceText, span) {
280
- const range = { ...span };
281
- if (range.end < sourceText.length && sourceText[range.end] === '\n') range.end += 1;
282
- else if (range.start > 0 && sourceText[range.start - 1] === '\n') range.start -= 1;
283
- return range;
284
- }
285
-
286
- function insertionReplacement(text, sourceText, offset) {
287
- let replacement = String(text ?? '');
288
- if (offset > 0 && sourceText[offset - 1] !== '\n') replacement = `\n${replacement}`;
289
- if (offset < sourceText.length && !replacement.endsWith('\n')) replacement += '\n';
290
- if (offset === sourceText.length && sourceText && !sourceText.endsWith('\n')) replacement = `\n${replacement}`;
291
- if (offset === sourceText.length && !replacement.endsWith('\n')) replacement += '\n';
292
- return replacement;
293
- }
294
-
295
- function afterLineOffset(sourceText, offset) {
296
- return sourceText[offset] === '\n' ? offset + 1 : offset;
297
- }
298
-
299
291
  function compactRecord(value) {
300
292
  return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
301
293
  }