@shapeshift-labs/frontier-lang-compiler 0.2.85 → 0.2.86

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.
@@ -66,6 +66,9 @@ export interface SemanticEditScriptOperation {
66
66
  readonly reanchor?: {
67
67
  readonly fromAnchorKey?: string;
68
68
  readonly toAnchorKey?: string;
69
+ readonly toSourcePath?: string;
70
+ readonly toSymbolName?: string;
71
+ readonly toSymbolKind?: string;
69
72
  readonly lineageStatus?: string;
70
73
  readonly traversedEventIds?: readonly string[];
71
74
  };
@@ -138,6 +141,11 @@ export interface SemanticEditProjectionEdit {
138
141
  readonly regionId?: string;
139
142
  readonly regionKind?: string;
140
143
  readonly sourcePath?: string;
144
+ readonly originalSourcePath?: string;
145
+ readonly targetAnchorKey?: string;
146
+ readonly targetSourcePath?: string;
147
+ readonly targetSymbolName?: string;
148
+ readonly targetSymbolKind?: string;
141
149
  readonly symbolId?: string;
142
150
  readonly symbolName?: string;
143
151
  readonly symbolKind?: string;
@@ -188,6 +196,7 @@ export interface ProjectSemanticEditScriptToSourceOptions {
188
196
  readonly script: SemanticEditScript;
189
197
  readonly workerSourceText: string;
190
198
  readonly headSourceText: string;
199
+ readonly headSourcePath?: string;
191
200
  readonly metadata?: Record<string, unknown>;
192
201
  }
193
202
 
@@ -207,6 +216,7 @@ export interface CreateSemanticEditScriptOptions {
207
216
  readonly workerSourceText?: string;
208
217
  readonly afterSourceText?: string;
209
218
  readonly headSourceText?: string;
219
+ readonly headSourcePath?: string;
210
220
  readonly currentSourceText?: string;
211
221
  readonly baseSourceHash?: string;
212
222
  readonly workerSourceHash?: string;
@@ -25,7 +25,7 @@ export function projectSemanticEditScriptToSource(input = {}) {
25
25
  id: input.id ?? `semantic_edit_projection_${idFragment(script.id ?? script.hash ?? 'script')}`,
26
26
  scriptId: script.id,
27
27
  status: blocked ? 'blocked' : 'projected',
28
- sourcePath: script.sourcePath,
28
+ sourcePath: input.headSourcePath ?? projectedSourcePath(script, edits),
29
29
  language: script.language,
30
30
  baseHash: script.baseHash,
31
31
  workerHash: script.workerHash,
@@ -54,8 +54,9 @@ export function projectSemanticEditScriptToSource(input = {}) {
54
54
  }
55
55
 
56
56
  function sourceEditForOperation(operation, workerSourceText, headSourceText) {
57
+ const identity = projectionIdentity(operation);
57
58
  if (operation.status === 'already-applied') {
58
- return { ok: true, value: { ...semanticEditIdentity(operation), operationId: operation.id, start: 0, end: 0, replacement: '', current: '', alreadyApplied: true } };
59
+ return { ok: true, value: { ...identity, operationId: operation.id, start: 0, end: 0, replacement: '', current: '', alreadyApplied: true } };
59
60
  }
60
61
  if (operation.status !== 'portable') return { ok: false, reasonCodes: [`operation-not-portable:${operation.id}`] };
61
62
  const workerOffsets = spanOffsets(workerSourceText, operation.spans?.worker);
@@ -78,7 +79,7 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText) {
78
79
  ok: true,
79
80
  value: {
80
81
  operationId: operation.id,
81
- ...semanticEditIdentity(operation),
82
+ ...identity,
82
83
  start: headOffsets.start,
83
84
  end: headOffsets.end,
84
85
  workerStart: workerOffsets.start,
@@ -89,6 +90,11 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText) {
89
90
  };
90
91
  }
91
92
 
93
+ function projectionIdentity(operation) {
94
+ const identity = semanticEditIdentity(operation);
95
+ return { ...identity, sourcePath: operation.reanchor?.toSourcePath ?? identity.sourcePath };
96
+ }
97
+
92
98
  function projectionEditRecord(edit) {
93
99
  const deletedTextHash = hashSemanticValue(edit.current);
94
100
  const replacementTextHash = hashSemanticValue(edit.replacement);
@@ -103,6 +109,11 @@ function projectionEditRecord(edit) {
103
109
  regionId: edit.regionId,
104
110
  regionKind: edit.regionKind,
105
111
  sourcePath: edit.sourcePath,
112
+ originalSourcePath: edit.originalSourcePath,
113
+ targetAnchorKey: edit.targetAnchorKey,
114
+ targetSourcePath: edit.targetSourcePath,
115
+ targetSymbolName: edit.targetSymbolName,
116
+ targetSymbolKind: edit.targetSymbolKind,
106
117
  symbolId: edit.symbolId,
107
118
  symbolName: edit.symbolName,
108
119
  symbolKind: edit.symbolKind,
@@ -136,6 +147,11 @@ function semanticEditIdentity(operation) {
136
147
  regionId: anchor.regionId,
137
148
  regionKind: anchor.regionKind,
138
149
  sourcePath: anchor.sourcePath,
150
+ originalSourcePath: operation.reanchor?.toSourcePath ? anchor.sourcePath : undefined,
151
+ targetAnchorKey: operation.reanchor?.toAnchorKey,
152
+ targetSourcePath: operation.reanchor?.toSourcePath,
153
+ targetSymbolName: operation.reanchor?.toSymbolName,
154
+ targetSymbolKind: operation.reanchor?.toSymbolKind,
139
155
  symbolId: anchor.symbolId,
140
156
  symbolName: anchor.symbolName,
141
157
  symbolKind: anchor.symbolKind,
@@ -152,6 +168,10 @@ function applySourceEdits(sourceText, edits) {
152
168
  .reduce((text, edit) => text.slice(0, edit.start) + edit.replacement + text.slice(edit.end), sourceText);
153
169
  }
154
170
 
171
+ function projectedSourcePath(script, edits) {
172
+ return edits.map((edit) => edit.sourcePath).find(Boolean) ?? script.sourcePath;
173
+ }
174
+
155
175
  function spanOffsets(sourceText, span) {
156
176
  if (typeof sourceText !== 'string' || !span) return undefined;
157
177
  if (typeof span.start === 'number' && typeof span.end === 'number' && span.end >= span.start) return { start: span.start, end: span.end };
@@ -92,12 +92,15 @@ function classifyMissingHeadAnchor(input) {
92
92
  ? resolveSemanticLineage(input.context.headLineage.lineageMap, { anchorKey: input.anchorKey })
93
93
  : undefined;
94
94
  if (resolved?.status === 'resolved' && resolved.currentAnchors.length === 1) {
95
- return editStatus('needs-port', 'needs-review', 0.72, ['anchor-moved-or-renamed'], {
96
- fromAnchorKey: input.anchorKey,
97
- toAnchorKey: resolved.currentAnchors[0].key,
98
- lineageStatus: resolved.status,
99
- traversedEventIds: resolved.traversedEventIds
100
- }, resolved.evidenceIds);
95
+ const target = resolved.currentAnchors[0];
96
+ const reanchor = reanchorRecord(input.anchorKey, target, resolved);
97
+ if (target.bodyHash && input.baseSymbol?.spanHash && target.bodyHash === input.baseSymbol.spanHash) {
98
+ return editStatus('portable', 'ready', 0.86, ['anchor-reanchored-head-matches-base'], reanchor, resolved.evidenceIds);
99
+ }
100
+ if (target.bodyHash && input.workerSymbol?.spanHash && target.bodyHash === input.workerSymbol.spanHash) {
101
+ return editStatus('already-applied', 'ready', 0.87, ['anchor-reanchored-head-matches-worker'], reanchor, resolved.evidenceIds);
102
+ }
103
+ return editStatus('needs-port', 'needs-review', 0.72, ['anchor-moved-or-renamed'], reanchor, resolved.evidenceIds);
101
104
  }
102
105
  if (resolved?.status === 'ambiguous') {
103
106
  return editStatus('blocked', 'blocked', 0.1, ['anchor-lineage-ambiguous'], { fromAnchorKey: input.anchorKey, lineageStatus: resolved.status }, resolved.evidenceIds);
@@ -112,6 +115,18 @@ function editStatus(status, readiness, confidence, reasonCodes, reanchor, eviden
112
115
  return { status, readiness, confidence, reasonCodes, reanchor, evidenceIds };
113
116
  }
114
117
 
118
+ function reanchorRecord(fromAnchorKey, target, resolved) {
119
+ return {
120
+ fromAnchorKey,
121
+ toAnchorKey: target.key,
122
+ toSourcePath: target.sourcePath,
123
+ toSymbolName: target.symbolName,
124
+ toSymbolKind: target.kind,
125
+ lineageStatus: resolved.status,
126
+ traversedEventIds: resolved.traversedEventIds
127
+ };
128
+ }
129
+
115
130
  function admissionStatus(summary) {
116
131
  if (summary.operations === 0) return 'evidence-only';
117
132
  if (summary.blocked > 0) return 'blocked';
@@ -132,8 +132,9 @@ function semanticEditOperation(region, index, context, input) {
132
132
  const anchorKey = region.key ?? region.conflictKey ?? region.id;
133
133
  const baseSymbol = context.baseSymbols.get(anchorKey);
134
134
  const workerSymbol = context.workerSymbols.get(anchorKey);
135
- const headSymbol = context.headSymbols.get(anchorKey);
136
- const classification = classifySemanticEdit({ region, anchorKey, baseSymbol, workerSymbol, headSymbol, context });
135
+ const directHeadSymbol = context.headSymbols.get(anchorKey);
136
+ const classification = classifySemanticEdit({ region, anchorKey, baseSymbol, workerSymbol, headSymbol: directHeadSymbol, context });
137
+ const headSymbol = directHeadSymbol ?? reanchoredHeadSymbol(context, classification);
137
138
  const kind = semanticEditOperationKind(region);
138
139
  const baseText = spanText(context.base, baseSymbol?.sourceSpan ?? region.metadata?.changedRegionProjection?.before?.sourceSpan ?? region.sourceSpan);
139
140
  const workerText = spanText(context.worker, workerSymbol?.sourceSpan ?? region.metadata?.changedRegionProjection?.after?.sourceSpan ?? region.sourceSpan);
@@ -192,6 +193,11 @@ function semanticEditOperation(region, index, context, input) {
192
193
  });
193
194
  }
194
195
 
196
+ function reanchoredHeadSymbol(context, classification) {
197
+ const targetKey = classification.reanchor?.toAnchorKey;
198
+ return targetKey ? context.headSymbols.get(targetKey) : undefined;
199
+ }
200
+
195
201
  function semanticEditIdentityRecord(input) {
196
202
  return {
197
203
  kind: input.kind,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.85",
3
+ "version": "0.2.86",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",