@shapeshift-labs/frontier-lang-compiler 0.2.84 → 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.
- package/README.md +0 -2
- package/dist/declarations/semantic-edit-script.d.ts +19 -0
- package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +33 -40
- package/dist/internal/index-impl/semanticEditIdentityRecords.js +54 -0
- package/dist/internal/index-impl/semanticEditScriptClassification.js +26 -7
- package/dist/internal/index-impl/semanticEditScripts.js +56 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -933,7 +933,6 @@ The published Frontier package family is generated from one shared package catal
|
|
|
933
933
|
- [`@shapeshift-labs/frontier-realtime-server`](https://www.npmjs.com/package/@shapeshift-labs/frontier-realtime-server): Authoritative realtime room, tick, command validation, rate-limit, session, and snapshot-history runtime.
|
|
934
934
|
- [`@shapeshift-labs/frontier-realtime-websocket`](https://www.npmjs.com/package/@shapeshift-labs/frontier-realtime-websocket): WebSocket client, wire, and Node room-server transport for Frontier realtime.
|
|
935
935
|
- [`@shapeshift-labs/frontier-game`](https://www.npmjs.com/package/@shapeshift-labs/frontier-game): Game-facing entity, component, player, room, ownership, spatial interest, rollback, physics, and replication helpers above realtime.
|
|
936
|
-
- [`@shapeshift-labs/loom`](https://www.npmjs.com/package/@shapeshift-labs/loom): Repo-level semantic collaboration CLI for .loom workspaces, including init, scan, status, graph snapshots, projection plans, Frontier Lang delegation, Frontier Swarm delegation, and Frontier Framework delegation.
|
|
937
936
|
|
|
938
937
|
Package source repositories:
|
|
939
938
|
|
|
@@ -1027,4 +1026,3 @@ Package source repositories:
|
|
|
1027
1026
|
- [`siliconjungle/-shapeshift-labs-frontier-realtime-server`](https://github.com/siliconjungle/-shapeshift-labs-frontier-realtime-server)
|
|
1028
1027
|
- [`siliconjungle/-shapeshift-labs-frontier-realtime-websocket`](https://github.com/siliconjungle/-shapeshift-labs-frontier-realtime-websocket)
|
|
1029
1028
|
- [`siliconjungle/-shapeshift-labs-frontier-game`](https://github.com/siliconjungle/-shapeshift-labs-frontier-game)
|
|
1030
|
-
- [`siliconjungle/-shapeshift-labs-loom`](https://github.com/siliconjungle/-shapeshift-labs-loom)
|
|
@@ -40,6 +40,10 @@ export interface SemanticEditScriptOperation {
|
|
|
40
40
|
readonly symbolKind?: string;
|
|
41
41
|
readonly sourceSpan?: SourceSpan;
|
|
42
42
|
};
|
|
43
|
+
readonly semanticKey?: string;
|
|
44
|
+
readonly semanticIdentityHash?: string;
|
|
45
|
+
readonly sourceIdentityHash?: string;
|
|
46
|
+
readonly operationContentHash?: string;
|
|
43
47
|
readonly spans?: {
|
|
44
48
|
readonly base?: SourceSpan;
|
|
45
49
|
readonly worker?: SourceSpan;
|
|
@@ -62,6 +66,9 @@ export interface SemanticEditScriptOperation {
|
|
|
62
66
|
readonly reanchor?: {
|
|
63
67
|
readonly fromAnchorKey?: string;
|
|
64
68
|
readonly toAnchorKey?: string;
|
|
69
|
+
readonly toSourcePath?: string;
|
|
70
|
+
readonly toSymbolName?: string;
|
|
71
|
+
readonly toSymbolKind?: string;
|
|
65
72
|
readonly lineageStatus?: string;
|
|
66
73
|
readonly traversedEventIds?: readonly string[];
|
|
67
74
|
};
|
|
@@ -84,6 +91,10 @@ export interface SemanticEditScriptSummary {
|
|
|
84
91
|
readonly blocked: number;
|
|
85
92
|
readonly candidates: number;
|
|
86
93
|
readonly autoMergeCandidates: number;
|
|
94
|
+
readonly semanticKeys?: readonly string[];
|
|
95
|
+
readonly semanticIdentityHashes?: readonly string[];
|
|
96
|
+
readonly sourceIdentityHashes?: readonly string[];
|
|
97
|
+
readonly operationContentHashes?: readonly string[];
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
export interface SemanticEditScriptAdmission {
|
|
@@ -130,12 +141,18 @@ export interface SemanticEditProjectionEdit {
|
|
|
130
141
|
readonly regionId?: string;
|
|
131
142
|
readonly regionKind?: string;
|
|
132
143
|
readonly sourcePath?: string;
|
|
144
|
+
readonly originalSourcePath?: string;
|
|
145
|
+
readonly targetAnchorKey?: string;
|
|
146
|
+
readonly targetSourcePath?: string;
|
|
147
|
+
readonly targetSymbolName?: string;
|
|
148
|
+
readonly targetSymbolKind?: string;
|
|
133
149
|
readonly symbolId?: string;
|
|
134
150
|
readonly symbolName?: string;
|
|
135
151
|
readonly symbolKind?: string;
|
|
136
152
|
readonly semanticKey?: string;
|
|
137
153
|
readonly semanticIdentityHash?: string;
|
|
138
154
|
readonly sourceIdentityHash?: string;
|
|
155
|
+
readonly operationContentHash?: string;
|
|
139
156
|
readonly editContentHash?: string;
|
|
140
157
|
readonly headStart: number;
|
|
141
158
|
readonly headEnd: number;
|
|
@@ -179,6 +196,7 @@ export interface ProjectSemanticEditScriptToSourceOptions {
|
|
|
179
196
|
readonly script: SemanticEditScript;
|
|
180
197
|
readonly workerSourceText: string;
|
|
181
198
|
readonly headSourceText: string;
|
|
199
|
+
readonly headSourcePath?: string;
|
|
182
200
|
readonly metadata?: Record<string, unknown>;
|
|
183
201
|
}
|
|
184
202
|
|
|
@@ -198,6 +216,7 @@ export interface CreateSemanticEditScriptOptions {
|
|
|
198
216
|
readonly workerSourceText?: string;
|
|
199
217
|
readonly afterSourceText?: string;
|
|
200
218
|
readonly headSourceText?: string;
|
|
219
|
+
readonly headSourcePath?: string;
|
|
201
220
|
readonly currentSourceText?: string;
|
|
202
221
|
readonly baseSourceHash?: string;
|
|
203
222
|
readonly workerSourceHash?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
|
|
2
2
|
import { idFragment, uniqueStrings } from '../../native-import-utils.js';
|
|
3
|
+
import { semanticEditIdentityFields } from './semanticEditIdentityRecords.js';
|
|
3
4
|
|
|
4
5
|
export function projectSemanticEditScriptToSource(input = {}) {
|
|
5
6
|
const script = input.script;
|
|
@@ -24,7 +25,7 @@ export function projectSemanticEditScriptToSource(input = {}) {
|
|
|
24
25
|
id: input.id ?? `semantic_edit_projection_${idFragment(script.id ?? script.hash ?? 'script')}`,
|
|
25
26
|
scriptId: script.id,
|
|
26
27
|
status: blocked ? 'blocked' : 'projected',
|
|
27
|
-
sourcePath: script
|
|
28
|
+
sourcePath: input.headSourcePath ?? projectedSourcePath(script, edits),
|
|
28
29
|
language: script.language,
|
|
29
30
|
baseHash: script.baseHash,
|
|
30
31
|
workerHash: script.workerHash,
|
|
@@ -53,8 +54,9 @@ export function projectSemanticEditScriptToSource(input = {}) {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
function sourceEditForOperation(operation, workerSourceText, headSourceText) {
|
|
57
|
+
const identity = projectionIdentity(operation);
|
|
56
58
|
if (operation.status === 'already-applied') {
|
|
57
|
-
return { ok: true, value: { ...
|
|
59
|
+
return { ok: true, value: { ...identity, operationId: operation.id, start: 0, end: 0, replacement: '', current: '', alreadyApplied: true } };
|
|
58
60
|
}
|
|
59
61
|
if (operation.status !== 'portable') return { ok: false, reasonCodes: [`operation-not-portable:${operation.id}`] };
|
|
60
62
|
const workerOffsets = spanOffsets(workerSourceText, operation.spans?.worker);
|
|
@@ -77,7 +79,7 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText) {
|
|
|
77
79
|
ok: true,
|
|
78
80
|
value: {
|
|
79
81
|
operationId: operation.id,
|
|
80
|
-
...
|
|
82
|
+
...identity,
|
|
81
83
|
start: headOffsets.start,
|
|
82
84
|
end: headOffsets.end,
|
|
83
85
|
workerStart: workerOffsets.start,
|
|
@@ -88,12 +90,15 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText) {
|
|
|
88
90
|
};
|
|
89
91
|
}
|
|
90
92
|
|
|
93
|
+
function projectionIdentity(operation) {
|
|
94
|
+
const identity = semanticEditIdentity(operation);
|
|
95
|
+
return { ...identity, sourcePath: operation.reanchor?.toSourcePath ?? identity.sourcePath };
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
function projectionEditRecord(edit) {
|
|
92
99
|
const deletedTextHash = hashSemanticValue(edit.current);
|
|
93
100
|
const replacementTextHash = hashSemanticValue(edit.replacement);
|
|
94
|
-
const
|
|
95
|
-
const semanticIdentityHash = hashSemanticValue(semanticIdentityRecord(edit, semanticKey));
|
|
96
|
-
const sourceIdentityHash = hashSemanticValue(sourceIdentityRecord(edit));
|
|
101
|
+
const identity = semanticEditIdentityFields(edit);
|
|
97
102
|
return compactRecord({
|
|
98
103
|
operationId: edit.operationId,
|
|
99
104
|
status: edit.alreadyApplied ? 'already-applied' : 'applied',
|
|
@@ -104,14 +109,18 @@ function projectionEditRecord(edit) {
|
|
|
104
109
|
regionId: edit.regionId,
|
|
105
110
|
regionKind: edit.regionKind,
|
|
106
111
|
sourcePath: edit.sourcePath,
|
|
112
|
+
originalSourcePath: edit.originalSourcePath,
|
|
113
|
+
targetAnchorKey: edit.targetAnchorKey,
|
|
114
|
+
targetSourcePath: edit.targetSourcePath,
|
|
115
|
+
targetSymbolName: edit.targetSymbolName,
|
|
116
|
+
targetSymbolKind: edit.targetSymbolKind,
|
|
107
117
|
symbolId: edit.symbolId,
|
|
108
118
|
symbolName: edit.symbolName,
|
|
109
119
|
symbolKind: edit.symbolKind,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
sourceIdentityHash,
|
|
120
|
+
...identity,
|
|
121
|
+
operationContentHash: edit.operationContentHash,
|
|
113
122
|
editContentHash: hashSemanticValue(compactRecord({
|
|
114
|
-
semanticIdentityHash,
|
|
123
|
+
semanticIdentityHash: identity.semanticIdentityHash,
|
|
115
124
|
deletedTextHash,
|
|
116
125
|
replacementTextHash,
|
|
117
126
|
status: edit.alreadyApplied ? 'already-applied' : 'applied'
|
|
@@ -128,35 +137,6 @@ function projectionEditRecord(edit) {
|
|
|
128
137
|
});
|
|
129
138
|
}
|
|
130
139
|
|
|
131
|
-
function semanticEditKey(edit) {
|
|
132
|
-
const scope = edit.symbolName
|
|
133
|
-
? `${edit.symbolKind ?? 'symbol'}:${edit.symbolName}`
|
|
134
|
-
: edit.anchorKey ?? edit.regionId ?? edit.operationId;
|
|
135
|
-
return ['semantic-edit', edit.kind ?? 'region', edit.changeKind ?? 'change', scope].filter(Boolean).join(':');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function semanticIdentityRecord(edit, semanticKey) {
|
|
139
|
-
return compactRecord({
|
|
140
|
-
semanticKey,
|
|
141
|
-
kind: edit.kind,
|
|
142
|
-
changeKind: edit.changeKind,
|
|
143
|
-
regionKind: edit.regionKind,
|
|
144
|
-
symbolName: edit.symbolName,
|
|
145
|
-
symbolKind: edit.symbolKind
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function sourceIdentityRecord(edit) {
|
|
150
|
-
return compactRecord({
|
|
151
|
-
anchorKey: edit.anchorKey,
|
|
152
|
-
conflictKey: edit.conflictKey,
|
|
153
|
-
regionId: edit.regionId,
|
|
154
|
-
sourcePath: edit.sourcePath,
|
|
155
|
-
symbolId: edit.symbolId,
|
|
156
|
-
semanticKey: semanticEditKey(edit)
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
|
|
160
140
|
function semanticEditIdentity(operation) {
|
|
161
141
|
const anchor = operation.anchor ?? {};
|
|
162
142
|
return compactRecord({
|
|
@@ -167,9 +147,18 @@ function semanticEditIdentity(operation) {
|
|
|
167
147
|
regionId: anchor.regionId,
|
|
168
148
|
regionKind: anchor.regionKind,
|
|
169
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,
|
|
170
155
|
symbolId: anchor.symbolId,
|
|
171
156
|
symbolName: anchor.symbolName,
|
|
172
|
-
symbolKind: anchor.symbolKind
|
|
157
|
+
symbolKind: anchor.symbolKind,
|
|
158
|
+
semanticKey: operation.semanticKey,
|
|
159
|
+
semanticIdentityHash: operation.semanticIdentityHash,
|
|
160
|
+
sourceIdentityHash: operation.sourceIdentityHash,
|
|
161
|
+
operationContentHash: operation.operationContentHash
|
|
173
162
|
});
|
|
174
163
|
}
|
|
175
164
|
|
|
@@ -179,6 +168,10 @@ function applySourceEdits(sourceText, edits) {
|
|
|
179
168
|
.reduce((text, edit) => text.slice(0, edit.start) + edit.replacement + text.slice(edit.end), sourceText);
|
|
180
169
|
}
|
|
181
170
|
|
|
171
|
+
function projectedSourcePath(script, edits) {
|
|
172
|
+
return edits.map((edit) => edit.sourcePath).find(Boolean) ?? script.sourcePath;
|
|
173
|
+
}
|
|
174
|
+
|
|
182
175
|
function spanOffsets(sourceText, span) {
|
|
183
176
|
if (typeof sourceText !== 'string' || !span) return undefined;
|
|
184
177
|
if (typeof span.start === 'number' && typeof span.end === 'number' && span.end >= span.start) return { start: span.start, end: span.end };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
|
|
2
|
+
|
|
3
|
+
export function semanticEditIdentityFields(record) {
|
|
4
|
+
const semanticKey = record.semanticKey ?? semanticEditKey(record);
|
|
5
|
+
return compactRecord({
|
|
6
|
+
semanticKey,
|
|
7
|
+
semanticIdentityHash: record.semanticIdentityHash ?? hashSemanticValue(semanticIdentityRecord(record, semanticKey)),
|
|
8
|
+
sourceIdentityHash: record.sourceIdentityHash ?? hashSemanticValue(sourceIdentityRecord(record, semanticKey))
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function semanticEditOperationContentHash(record) {
|
|
13
|
+
const semanticIdentityHash = record.semanticIdentityHash ?? semanticEditIdentityFields(record).semanticIdentityHash;
|
|
14
|
+
return hashSemanticValue(compactRecord({
|
|
15
|
+
semanticIdentityHash,
|
|
16
|
+
baseTextHash: record.baseTextHash,
|
|
17
|
+
workerTextHash: record.workerTextHash,
|
|
18
|
+
headTextHash: record.headTextHash,
|
|
19
|
+
status: record.status
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function semanticEditKey(record) {
|
|
24
|
+
const scope = record.symbolName
|
|
25
|
+
? `${record.symbolKind ?? 'symbol'}:${record.symbolName}`
|
|
26
|
+
: record.anchorKey ?? record.regionId ?? record.operationId ?? record.id;
|
|
27
|
+
return ['semantic-edit', record.kind ?? 'region', record.changeKind ?? 'change', scope].filter(Boolean).join(':');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function semanticIdentityRecord(record, semanticKey) {
|
|
31
|
+
return compactRecord({
|
|
32
|
+
semanticKey,
|
|
33
|
+
kind: record.kind,
|
|
34
|
+
changeKind: record.changeKind,
|
|
35
|
+
regionKind: record.regionKind,
|
|
36
|
+
symbolName: record.symbolName,
|
|
37
|
+
symbolKind: record.symbolKind
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function sourceIdentityRecord(record, semanticKey) {
|
|
42
|
+
return compactRecord({
|
|
43
|
+
anchorKey: record.anchorKey,
|
|
44
|
+
conflictKey: record.conflictKey,
|
|
45
|
+
regionId: record.regionId,
|
|
46
|
+
sourcePath: record.sourcePath,
|
|
47
|
+
symbolId: record.symbolId,
|
|
48
|
+
semanticKey
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function compactRecord(value) {
|
|
53
|
+
return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
|
|
54
|
+
}
|
|
@@ -44,7 +44,11 @@ export function summarizeSemanticEditOperations(operations) {
|
|
|
44
44
|
stale: byStatus.stale ?? 0,
|
|
45
45
|
blocked: byStatus.blocked ?? 0,
|
|
46
46
|
candidates: byStatus.candidate ?? 0,
|
|
47
|
-
autoMergeCandidates: (byStatus.portable ?? 0) + (byStatus['already-applied'] ?? 0)
|
|
47
|
+
autoMergeCandidates: (byStatus.portable ?? 0) + (byStatus['already-applied'] ?? 0),
|
|
48
|
+
semanticKeys: uniqueStrings(operations.map((operation) => operation.semanticKey).filter(Boolean)),
|
|
49
|
+
semanticIdentityHashes: uniqueStrings(operations.map((operation) => operation.semanticIdentityHash).filter(Boolean)),
|
|
50
|
+
sourceIdentityHashes: uniqueStrings(operations.map((operation) => operation.sourceIdentityHash).filter(Boolean)),
|
|
51
|
+
operationContentHashes: uniqueStrings(operations.map((operation) => operation.operationContentHash).filter(Boolean))
|
|
48
52
|
};
|
|
49
53
|
}
|
|
50
54
|
|
|
@@ -88,12 +92,15 @@ function classifyMissingHeadAnchor(input) {
|
|
|
88
92
|
? resolveSemanticLineage(input.context.headLineage.lineageMap, { anchorKey: input.anchorKey })
|
|
89
93
|
: undefined;
|
|
90
94
|
if (resolved?.status === 'resolved' && resolved.currentAnchors.length === 1) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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);
|
|
97
104
|
}
|
|
98
105
|
if (resolved?.status === 'ambiguous') {
|
|
99
106
|
return editStatus('blocked', 'blocked', 0.1, ['anchor-lineage-ambiguous'], { fromAnchorKey: input.anchorKey, lineageStatus: resolved.status }, resolved.evidenceIds);
|
|
@@ -108,6 +115,18 @@ function editStatus(status, readiness, confidence, reasonCodes, reanchor, eviden
|
|
|
108
115
|
return { status, readiness, confidence, reasonCodes, reanchor, evidenceIds };
|
|
109
116
|
}
|
|
110
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
|
+
|
|
111
130
|
function admissionStatus(summary) {
|
|
112
131
|
if (summary.operations === 0) return 'evidence-only';
|
|
113
132
|
if (summary.blocked > 0) return 'blocked';
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
summarizeSemanticEditOperations
|
|
14
14
|
} from './semanticEditScriptClassification.js';
|
|
15
15
|
import { sourceTextForSpan } from './sourceTextForSpan.js';
|
|
16
|
+
import { semanticEditIdentityFields, semanticEditOperationContentHash } from './semanticEditIdentityRecords.js';
|
|
16
17
|
|
|
17
18
|
export { SemanticEditScriptAdmissionStatuses };
|
|
18
19
|
|
|
@@ -131,48 +132,55 @@ function semanticEditOperation(region, index, context, input) {
|
|
|
131
132
|
const anchorKey = region.key ?? region.conflictKey ?? region.id;
|
|
132
133
|
const baseSymbol = context.baseSymbols.get(anchorKey);
|
|
133
134
|
const workerSymbol = context.workerSymbols.get(anchorKey);
|
|
134
|
-
const
|
|
135
|
-
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);
|
|
136
138
|
const kind = semanticEditOperationKind(region);
|
|
137
139
|
const baseText = spanText(context.base, baseSymbol?.sourceSpan ?? region.metadata?.changedRegionProjection?.before?.sourceSpan ?? region.sourceSpan);
|
|
138
140
|
const workerText = spanText(context.worker, workerSymbol?.sourceSpan ?? region.metadata?.changedRegionProjection?.after?.sourceSpan ?? region.sourceSpan);
|
|
139
141
|
const headText = spanText(context.head, headSymbol?.sourceSpan ?? region.metadata?.changedRegionProjection?.head?.sourceSpan ?? baseSymbol?.sourceSpan);
|
|
142
|
+
const anchor = compactRecord({
|
|
143
|
+
key: anchorKey,
|
|
144
|
+
conflictKey: region.conflictKey ?? `region:${anchorKey}`,
|
|
145
|
+
regionId: region.id,
|
|
146
|
+
regionKind: region.regionKind,
|
|
147
|
+
granularity: region.granularity,
|
|
148
|
+
language: region.language ?? context.workerChangeSet.language,
|
|
149
|
+
sourcePath: region.sourcePath ?? context.workerChangeSet.sourcePath,
|
|
150
|
+
symbolId: region.symbolId ?? workerSymbol?.id ?? baseSymbol?.id,
|
|
151
|
+
symbolName: region.symbolName ?? workerSymbol?.name ?? baseSymbol?.name,
|
|
152
|
+
symbolKind: region.symbolKind ?? workerSymbol?.kind ?? baseSymbol?.kind,
|
|
153
|
+
sourceSpan: workerSymbol?.sourceSpan ?? region.sourceSpan
|
|
154
|
+
});
|
|
155
|
+
const hashes = compactRecord({
|
|
156
|
+
baseSourceHash: context.workerChangeSet.beforeHash,
|
|
157
|
+
workerSourceHash: context.workerChangeSet.afterHash,
|
|
158
|
+
headSourceHash: context.headChangeSet?.afterHash,
|
|
159
|
+
baseSpanHash: baseSymbol?.spanHash,
|
|
160
|
+
workerSpanHash: workerSymbol?.spanHash,
|
|
161
|
+
headSpanHash: headSymbol?.spanHash,
|
|
162
|
+
baseTextHash: baseText === undefined ? undefined : hashSemanticValue(baseText),
|
|
163
|
+
workerTextHash: workerText === undefined ? undefined : hashSemanticValue(workerText),
|
|
164
|
+
headTextHash: headText === undefined ? undefined : hashSemanticValue(headText),
|
|
165
|
+
beforeSignatureHash: workerSymbol?.beforeSignatureHash ?? baseSymbol?.signatureHash,
|
|
166
|
+
afterSignatureHash: workerSymbol?.afterSignatureHash ?? workerSymbol?.signatureHash
|
|
167
|
+
});
|
|
168
|
+
const identityRecord = semanticEditIdentityRecord({ kind, region, anchor });
|
|
169
|
+
const identity = semanticEditIdentityFields(identityRecord);
|
|
140
170
|
return compactRecord({
|
|
141
171
|
id: `semantic_edit_op_${idFragment(firstString(input.id, anchorKey, index))}`,
|
|
142
172
|
kind,
|
|
143
173
|
changeKind: region.changeKind,
|
|
144
|
-
anchor
|
|
145
|
-
|
|
146
|
-
conflictKey: region.conflictKey ?? `region:${anchorKey}`,
|
|
147
|
-
regionId: region.id,
|
|
148
|
-
regionKind: region.regionKind,
|
|
149
|
-
granularity: region.granularity,
|
|
150
|
-
language: region.language ?? context.workerChangeSet.language,
|
|
151
|
-
sourcePath: region.sourcePath ?? context.workerChangeSet.sourcePath,
|
|
152
|
-
symbolId: region.symbolId ?? workerSymbol?.id ?? baseSymbol?.id,
|
|
153
|
-
symbolName: region.symbolName ?? workerSymbol?.name ?? baseSymbol?.name,
|
|
154
|
-
symbolKind: region.symbolKind ?? workerSymbol?.kind ?? baseSymbol?.kind,
|
|
155
|
-
sourceSpan: workerSymbol?.sourceSpan ?? region.sourceSpan
|
|
156
|
-
}),
|
|
174
|
+
anchor,
|
|
175
|
+
...identity,
|
|
157
176
|
spans: compactRecord({
|
|
158
177
|
base: baseSymbol?.sourceSpan ?? region.metadata?.changedRegionProjection?.before?.sourceSpan,
|
|
159
178
|
worker: workerSymbol?.sourceSpan ?? region.metadata?.changedRegionProjection?.after?.sourceSpan ?? region.sourceSpan,
|
|
160
179
|
head: headSymbol?.sourceSpan
|
|
161
180
|
}),
|
|
162
|
-
hashes
|
|
163
|
-
baseSourceHash: context.workerChangeSet.beforeHash,
|
|
164
|
-
workerSourceHash: context.workerChangeSet.afterHash,
|
|
165
|
-
headSourceHash: context.headChangeSet?.afterHash,
|
|
166
|
-
baseSpanHash: baseSymbol?.spanHash,
|
|
167
|
-
workerSpanHash: workerSymbol?.spanHash,
|
|
168
|
-
headSpanHash: headSymbol?.spanHash,
|
|
169
|
-
baseTextHash: baseText === undefined ? undefined : hashSemanticValue(baseText),
|
|
170
|
-
workerTextHash: workerText === undefined ? undefined : hashSemanticValue(workerText),
|
|
171
|
-
headTextHash: headText === undefined ? undefined : hashSemanticValue(headText),
|
|
172
|
-
beforeSignatureHash: workerSymbol?.beforeSignatureHash ?? baseSymbol?.signatureHash,
|
|
173
|
-
afterSignatureHash: workerSymbol?.afterSignatureHash ?? workerSymbol?.signatureHash
|
|
174
|
-
}),
|
|
181
|
+
hashes,
|
|
175
182
|
status: classification.status,
|
|
183
|
+
operationContentHash: semanticEditOperationContentHash({ ...identityRecord, ...identity, ...hashes, status: classification.status }),
|
|
176
184
|
reanchor: classification.reanchor,
|
|
177
185
|
readiness: classification.readiness,
|
|
178
186
|
confidence: classification.confidence,
|
|
@@ -185,6 +193,26 @@ function semanticEditOperation(region, index, context, input) {
|
|
|
185
193
|
});
|
|
186
194
|
}
|
|
187
195
|
|
|
196
|
+
function reanchoredHeadSymbol(context, classification) {
|
|
197
|
+
const targetKey = classification.reanchor?.toAnchorKey;
|
|
198
|
+
return targetKey ? context.headSymbols.get(targetKey) : undefined;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function semanticEditIdentityRecord(input) {
|
|
202
|
+
return {
|
|
203
|
+
kind: input.kind,
|
|
204
|
+
changeKind: input.region.changeKind,
|
|
205
|
+
anchorKey: input.anchor.key,
|
|
206
|
+
conflictKey: input.anchor.conflictKey,
|
|
207
|
+
regionId: input.anchor.regionId,
|
|
208
|
+
regionKind: input.anchor.regionKind,
|
|
209
|
+
sourcePath: input.anchor.sourcePath,
|
|
210
|
+
symbolId: input.anchor.symbolId,
|
|
211
|
+
symbolName: input.anchor.symbolName,
|
|
212
|
+
symbolKind: input.anchor.symbolKind
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
188
216
|
function semanticEditOperationKind(region) {
|
|
189
217
|
const prefix = region.changeKind === 'added' ? 'add' : region.changeKind === 'removed' ? 'remove' : 'replace';
|
|
190
218
|
const kind = String(region.regionKind ?? region.granularity ?? 'region');
|
package/package.json
CHANGED