@shapeshift-labs/frontier-lang-compiler 0.2.146 → 0.2.148
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/js-ts-safe-merge-independent-deletion-artifacts.js +112 -0
- package/dist/js-ts-safe-merge-independent-deletion-fallback.js +53 -0
- package/dist/js-ts-safe-merge-independent-deletion-plan.js +156 -0
- package/dist/js-ts-safe-merge-independent-deletion-records.js +251 -0
- package/dist/js-ts-safe-merge-semantic-edit-already-applied.js +127 -0
- package/dist/js-ts-safe-merge-semantic-edit-fallback.js +17 -23
- package/dist/js-ts-safe-merge-semantic-edit-gates.js +16 -0
- package/package.json +1 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
|
|
2
|
+
import {
|
|
3
|
+
independentTopLevelDeletionOperation,
|
|
4
|
+
independentTopLevelDeletionProjection,
|
|
5
|
+
independentTopLevelDeletionReplay,
|
|
6
|
+
independentTopLevelDeletionScript
|
|
7
|
+
} from './js-ts-safe-merge-independent-deletion-records.js';
|
|
8
|
+
import { idFragment, uniqueStrings } from './native-import-utils.js';
|
|
9
|
+
|
|
10
|
+
function createIndependentTopLevelDeletionArtifacts(input, topLevelResult, deletionPlan) {
|
|
11
|
+
const id = String(input.id ?? topLevelResult.id ?? 'js_ts_safe_merge');
|
|
12
|
+
const language = input.language ?? topLevelResult.language ?? 'typescript';
|
|
13
|
+
const sourcePath = input.sourcePath ?? topLevelResult.sourcePath ?? 'inline.ts';
|
|
14
|
+
const operationId = `js_ts_independent_top_level_delete_${idFragment([id, deletionPlan.deletedEntry.key].join(':'))}`;
|
|
15
|
+
const operation = independentTopLevelDeletionOperation({ id, operationId, language, sourcePath, deletionPlan, input });
|
|
16
|
+
const script = independentTopLevelDeletionScript({ id, language, sourcePath, operation, input });
|
|
17
|
+
const projection = independentTopLevelDeletionProjection({ id, language, sourcePath, operation, script, deletionPlan, input });
|
|
18
|
+
const replay = independentTopLevelDeletionReplay({
|
|
19
|
+
id: `${id}_semantic_edit_replay`,
|
|
20
|
+
language,
|
|
21
|
+
sourcePath,
|
|
22
|
+
operation,
|
|
23
|
+
projection,
|
|
24
|
+
deletionPlan,
|
|
25
|
+
currentSourceText: input.headSourceText,
|
|
26
|
+
status: 'accepted-clean',
|
|
27
|
+
editStatus: 'applied',
|
|
28
|
+
reasonCodes: ['head-anchor-matches-base', 'independent-top-level-deletion'],
|
|
29
|
+
outputSourceText: deletionPlan.mergedSourceText
|
|
30
|
+
});
|
|
31
|
+
const alreadyAppliedReplay = independentTopLevelDeletionReplay({
|
|
32
|
+
id: `${id}_semantic_edit_already_applied`,
|
|
33
|
+
language,
|
|
34
|
+
sourcePath,
|
|
35
|
+
operation,
|
|
36
|
+
projection,
|
|
37
|
+
deletionPlan,
|
|
38
|
+
currentSourceText: deletionPlan.mergedSourceText,
|
|
39
|
+
status: 'already-applied',
|
|
40
|
+
editStatus: 'already-applied',
|
|
41
|
+
reasonCodes: ['independent-top-level-deletion-already-applied'],
|
|
42
|
+
outputSourceText: deletionPlan.mergedSourceText
|
|
43
|
+
});
|
|
44
|
+
const status = projection.status === 'projected'
|
|
45
|
+
&& replay.status === 'accepted-clean'
|
|
46
|
+
&& replay.outputSourceText === deletionPlan.mergedSourceText
|
|
47
|
+
&& alreadyAppliedReplay.status === 'already-applied'
|
|
48
|
+
? 'verified'
|
|
49
|
+
: 'blocked';
|
|
50
|
+
const reasonCodes = status === 'verified'
|
|
51
|
+
? []
|
|
52
|
+
: uniqueStrings([
|
|
53
|
+
...(projection.admission?.reasonCodes ?? []),
|
|
54
|
+
...(replay.admission?.reasonCodes ?? []),
|
|
55
|
+
...(alreadyAppliedReplay.admission?.reasonCodes ?? [])
|
|
56
|
+
]);
|
|
57
|
+
const core = {
|
|
58
|
+
kind: 'frontier.lang.jsTsSafeMergeSemanticArtifacts',
|
|
59
|
+
version: 1,
|
|
60
|
+
schema: 'frontier.lang.jsTsSafeMergeSemanticArtifacts.v1',
|
|
61
|
+
id: `js_ts_safe_merge_semantic_edit_artifacts_${idFragment(id)}`,
|
|
62
|
+
sourcePath,
|
|
63
|
+
language,
|
|
64
|
+
status,
|
|
65
|
+
script,
|
|
66
|
+
projection,
|
|
67
|
+
replay,
|
|
68
|
+
alreadyAppliedReplay,
|
|
69
|
+
admission: {
|
|
70
|
+
status: status === 'verified' ? 'auto-merge-candidate' : 'blocked',
|
|
71
|
+
action: status === 'verified' ? 'apply' : 'human-review',
|
|
72
|
+
reviewRequired: status !== 'verified',
|
|
73
|
+
autoApplyCandidate: status === 'verified',
|
|
74
|
+
autoMergeClaim: false,
|
|
75
|
+
semanticEquivalenceClaim: false,
|
|
76
|
+
reasonCodes
|
|
77
|
+
},
|
|
78
|
+
summary: {
|
|
79
|
+
operations: script.summary.operations,
|
|
80
|
+
edits: projection.edits.length,
|
|
81
|
+
replayStatus: replay.status,
|
|
82
|
+
alreadyAppliedReplayStatus: alreadyAppliedReplay.status,
|
|
83
|
+
projectedSourceMatchesMerged: projection.sourceText === deletionPlan.mergedSourceText,
|
|
84
|
+
replayOutputMatchesMerged: replay.outputSourceText === deletionPlan.mergedSourceText
|
|
85
|
+
},
|
|
86
|
+
evidence: [{
|
|
87
|
+
id: `evidence_${idFragment(id)}_independent_top_level_deletion`,
|
|
88
|
+
kind: 'js-ts-independent-top-level-deletion-replay',
|
|
89
|
+
status: status === 'verified' ? 'passed' : 'needs-review',
|
|
90
|
+
path: sourcePath,
|
|
91
|
+
summary: status === 'verified'
|
|
92
|
+
? 'JS/TS independent top-level deletion replay verified 1 operation.'
|
|
93
|
+
: `JS/TS independent top-level deletion requires review: ${reasonCodes.join(', ')}.`,
|
|
94
|
+
metadata: {
|
|
95
|
+
autoMergeClaim: false,
|
|
96
|
+
semanticEquivalenceClaim: false,
|
|
97
|
+
deletedKey: deletionPlan.deletedEntry.key,
|
|
98
|
+
originalReasonCodes: topLevelResult.admission?.reasonCodes ?? []
|
|
99
|
+
}
|
|
100
|
+
}],
|
|
101
|
+
metadata: {
|
|
102
|
+
autoMergeClaim: false,
|
|
103
|
+
semanticEquivalenceClaim: false,
|
|
104
|
+
source: 'independent-top-level-deletion-fallback',
|
|
105
|
+
originalReasonCodes: topLevelResult.admission?.reasonCodes ?? [],
|
|
106
|
+
deletion: deletionPlan.summary
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
return { ...core, hash: hashSemanticValue(core) };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { createIndependentTopLevelDeletionArtifacts };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { JsTsSafeMergeStatuses } from './js-ts-safe-merge-constants.js';
|
|
2
|
+
import { createIndependentTopLevelDeletionArtifacts } from './js-ts-safe-merge-independent-deletion-artifacts.js';
|
|
3
|
+
import { createIndependentTopLevelDeletionPlan } from './js-ts-safe-merge-independent-deletion-plan.js';
|
|
4
|
+
import { semanticEditGates } from './js-ts-safe-merge-semantic-edit-gates.js';
|
|
5
|
+
|
|
6
|
+
function independentTopLevelDeletionFallbackResult(input, topLevelResult) {
|
|
7
|
+
const deletionPlan = createIndependentTopLevelDeletionPlan(input, topLevelResult);
|
|
8
|
+
if (!deletionPlan.ok) return undefined;
|
|
9
|
+
const artifacts = createIndependentTopLevelDeletionArtifacts(input, topLevelResult, deletionPlan);
|
|
10
|
+
if (artifacts.status !== 'verified') return undefined;
|
|
11
|
+
const gates = semanticEditGates(artifacts);
|
|
12
|
+
return {
|
|
13
|
+
...topLevelResult,
|
|
14
|
+
id: String(input.id ?? topLevelResult.id ?? 'js_ts_safe_merge'),
|
|
15
|
+
status: JsTsSafeMergeStatuses.merged,
|
|
16
|
+
mergedSourceText: deletionPlan.mergedSourceText,
|
|
17
|
+
outputSourceText: deletionPlan.mergedSourceText,
|
|
18
|
+
conflicts: [],
|
|
19
|
+
gates,
|
|
20
|
+
admission: {
|
|
21
|
+
status: 'auto-merge-candidate',
|
|
22
|
+
action: 'apply',
|
|
23
|
+
reviewRequired: false,
|
|
24
|
+
autoApplyCandidate: true,
|
|
25
|
+
autoMergeClaim: false,
|
|
26
|
+
semanticEquivalenceClaim: false,
|
|
27
|
+
reasonCodes: []
|
|
28
|
+
},
|
|
29
|
+
summary: {
|
|
30
|
+
...topLevelResult.summary,
|
|
31
|
+
changedExistingDeclarations: 0,
|
|
32
|
+
conflicts: 0,
|
|
33
|
+
gatesPassed: gates.filter((gateRecord) => gateRecord.status === 'passed').length,
|
|
34
|
+
topLevelDeclarationDeletions: 1,
|
|
35
|
+
semanticEditOperations: artifacts.script.summary.operations,
|
|
36
|
+
semanticEditAppliedOperations: artifacts.replay.summary.applied,
|
|
37
|
+
semanticEditReplayStatus: artifacts.replay.status,
|
|
38
|
+
composedPhases: 2
|
|
39
|
+
},
|
|
40
|
+
metadata: {
|
|
41
|
+
...topLevelResult.metadata,
|
|
42
|
+
composed: {
|
|
43
|
+
phase: 'independent-top-level-deletion-fallback',
|
|
44
|
+
phases: ['top-level-ledger', 'independent-top-level-deletion'],
|
|
45
|
+
originalReasonCodes: topLevelResult.admission?.reasonCodes ?? [],
|
|
46
|
+
deletion: deletionPlan.summary
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
semanticArtifacts: artifacts
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { independentTopLevelDeletionFallbackResult };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { JsTsSafeMergeConflictCodes } from './js-ts-safe-merge-constants.js';
|
|
2
|
+
import { sameStatementText } from './js-ts-safe-merge-context.js';
|
|
3
|
+
import { scanJsTsTopLevelLedger } from './js-ts-safe-merge-ledger.js';
|
|
4
|
+
import { uniqueStrings } from './native-import-utils.js';
|
|
5
|
+
|
|
6
|
+
function createIndependentTopLevelDeletionPlan(input, topLevelResult) {
|
|
7
|
+
const originalReasonCodes = topLevelResult?.admission?.reasonCodes ?? [];
|
|
8
|
+
if (!originalReasonCodes.includes(JsTsSafeMergeConflictCodes.topLevelOrderChanged)) {
|
|
9
|
+
return { ok: false, reasonCodes: ['top-level-order-not-deletion-shaped'] };
|
|
10
|
+
}
|
|
11
|
+
const allowedOriginalReasonCodes = new Set([
|
|
12
|
+
JsTsSafeMergeConflictCodes.topLevelOrderChanged,
|
|
13
|
+
JsTsSafeMergeConflictCodes.changedExistingDeclaration,
|
|
14
|
+
JsTsSafeMergeConflictCodes.typeAliasConflict
|
|
15
|
+
]);
|
|
16
|
+
if (originalReasonCodes.some((reason) => !allowedOriginalReasonCodes.has(reason))) {
|
|
17
|
+
return { ok: false, reasonCodes: ['top-level-deletion-has-unsafe-original-conflict'] };
|
|
18
|
+
}
|
|
19
|
+
if (typeof input.baseSourceText !== 'string'
|
|
20
|
+
|| typeof input.workerSourceText !== 'string'
|
|
21
|
+
|| typeof input.headSourceText !== 'string') {
|
|
22
|
+
return { ok: false, reasonCodes: ['missing-source-text'] };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const context = quietDeletionLedgerContext(input);
|
|
26
|
+
const base = scanJsTsTopLevelLedger(input.baseSourceText, 'base', context);
|
|
27
|
+
const worker = scanJsTsTopLevelLedger(input.workerSourceText, 'worker', context);
|
|
28
|
+
const head = scanJsTsTopLevelLedger(input.headSourceText, 'head', context);
|
|
29
|
+
if (context.conflicts.length) {
|
|
30
|
+
return { ok: false, reasonCodes: uniqueStrings(context.conflicts.map((conflict) => conflict.code)) };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const duplicateLedgerReason = firstDuplicateLedgerReason(base, worker, head);
|
|
34
|
+
if (duplicateLedgerReason) return { ok: false, reasonCodes: [duplicateLedgerReason] };
|
|
35
|
+
|
|
36
|
+
const baseByKey = entriesByKey(base.entries);
|
|
37
|
+
const workerByKey = entriesByKey(worker.entries);
|
|
38
|
+
const headByKey = entriesByKey(head.entries);
|
|
39
|
+
const baseKeys = base.entries.map((entry) => entry.key);
|
|
40
|
+
const missingWorkerBaseEntries = base.entries.filter((entry) => !workerByKey.has(entry.key));
|
|
41
|
+
const deletedWorkerEntries = missingWorkerBaseEntries.filter((entry) => entry.kind !== 'import');
|
|
42
|
+
const workerAddedEntries = worker.entries.filter((entry) => !baseByKey.has(entry.key));
|
|
43
|
+
if (missingWorkerBaseEntries.length !== 1
|
|
44
|
+
|| deletedWorkerEntries.length !== 1
|
|
45
|
+
|| workerAddedEntries.length !== 0) {
|
|
46
|
+
return { ok: false, reasonCodes: ['worker-top-level-deletion-not-isolated'] };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const deletedEntry = deletedWorkerEntries[0];
|
|
50
|
+
if (deletedEntry.kind !== 'declaration' || deletedEntry.declarationInfo?.exported === true) {
|
|
51
|
+
return { ok: false, reasonCodes: ['exported-or-unsupported-top-level-deletion'] };
|
|
52
|
+
}
|
|
53
|
+
if (isUnsupportedTopLevelDeletion(deletedEntry)) {
|
|
54
|
+
return { ok: false, reasonCodes: ['unsupported-top-level-deletion-declaration'] };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const expectedWorkerKeys = base.entries
|
|
58
|
+
.filter((entry) => entry.key !== deletedEntry.key)
|
|
59
|
+
.map((entry) => entry.key);
|
|
60
|
+
if (!sameStringList(worker.entries.map((entry) => entry.key), expectedWorkerKeys)) {
|
|
61
|
+
return { ok: false, reasonCodes: ['worker-top-level-deletion-order-changed'] };
|
|
62
|
+
}
|
|
63
|
+
for (const baseEntry of base.entries) {
|
|
64
|
+
if (baseEntry.key === deletedEntry.key) continue;
|
|
65
|
+
const workerEntry = workerByKey.get(baseEntry.key);
|
|
66
|
+
if (!workerEntry || !sameStatementText(workerEntry.text, baseEntry.text)) {
|
|
67
|
+
return { ok: false, reasonCodes: [`worker-changed-nondeleted-entry:${baseEntry.key}`] };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const headProjectedBaseKeys = head.entries
|
|
72
|
+
.filter((entry) => baseByKey.has(entry.key))
|
|
73
|
+
.map((entry) => entry.key);
|
|
74
|
+
if (!sameStringList(headProjectedBaseKeys, baseKeys)) {
|
|
75
|
+
return { ok: false, reasonCodes: ['head-base-order-or-presence-changed'] };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const headEntry = headByKey.get(deletedEntry.key);
|
|
79
|
+
if (!headEntry) return { ok: false, reasonCodes: [`head-anchor-missing:${deletedEntry.key}`] };
|
|
80
|
+
if (!sameStatementText(headEntry.text, deletedEntry.text)) {
|
|
81
|
+
return { ok: false, reasonCodes: [`head-anchor-changed-since-base:${deletedEntry.key}`] };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const edit = deleteEntryEdit(input.headSourceText, headEntry);
|
|
85
|
+
const deletedText = input.headSourceText.slice(edit.start, edit.end);
|
|
86
|
+
const mergedSourceText = applySourceEdits(input.headSourceText, [edit]);
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
base,
|
|
90
|
+
worker,
|
|
91
|
+
head,
|
|
92
|
+
deletedEntry,
|
|
93
|
+
headEntry,
|
|
94
|
+
edit,
|
|
95
|
+
deletedText,
|
|
96
|
+
mergedSourceText,
|
|
97
|
+
summary: {
|
|
98
|
+
key: deletedEntry.key,
|
|
99
|
+
name: deletedEntry.names?.[0],
|
|
100
|
+
declarationKind: deletedEntry.declarationInfo?.declarationKind,
|
|
101
|
+
exported: false,
|
|
102
|
+
reasonCodes: ['head-anchor-matches-base', 'independent-top-level-deletion']
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function quietDeletionLedgerContext(input) {
|
|
108
|
+
return {
|
|
109
|
+
id: String(input.id ?? 'js_ts_safe_merge'),
|
|
110
|
+
sourcePath: input.sourcePath,
|
|
111
|
+
language: input.language ?? 'typescript',
|
|
112
|
+
conflicts: [],
|
|
113
|
+
blockedGateIds: new Set(),
|
|
114
|
+
gateReasonCodes: new Map()
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function firstDuplicateLedgerReason(...ledgers) {
|
|
119
|
+
for (const ledger of ledgers) {
|
|
120
|
+
const seen = new Set();
|
|
121
|
+
for (const entry of ledger.entries) {
|
|
122
|
+
if (seen.has(entry.key)) return `duplicate-ledger-key:${ledger.label}:${entry.key}`;
|
|
123
|
+
seen.add(entry.key);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function entriesByKey(entries) {
|
|
130
|
+
return new Map(entries.map((entry) => [entry.key, entry]));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function isUnsupportedTopLevelDeletion(entry) {
|
|
134
|
+
if (entry.declarationInfo?.declarationKind === 'module') return true;
|
|
135
|
+
return /^\s*(?:export\s+)?declare\b/.test(entry.text ?? '');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function sameStringList(left, right) {
|
|
139
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function deleteEntryEdit(sourceText, entry) {
|
|
143
|
+
const lineEnd = sourceText.indexOf('\n', entry.end);
|
|
144
|
+
const end = lineEnd === -1 ? entry.end : lineEnd + 1;
|
|
145
|
+
const lineStart = sourceText.lastIndexOf('\n', Math.max(0, entry.start - 1)) + 1;
|
|
146
|
+
const start = /^[\t ]*$/.test(sourceText.slice(lineStart, entry.start)) ? lineStart : entry.start;
|
|
147
|
+
return { start, end, text: '' };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function applySourceEdits(sourceText, edits) {
|
|
151
|
+
return [...edits]
|
|
152
|
+
.sort((left, right) => right.start - left.start || right.end - left.end)
|
|
153
|
+
.reduce((current, edit) => `${current.slice(0, edit.start)}${edit.text}${current.slice(edit.end)}`, sourceText);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export { createIndependentTopLevelDeletionPlan };
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
|
|
2
|
+
import { idFragment } from './native-import-utils.js';
|
|
3
|
+
|
|
4
|
+
function independentTopLevelDeletionOperation(input) {
|
|
5
|
+
const entry = input.deletionPlan.deletedEntry;
|
|
6
|
+
const name = entry.names?.[0] ?? entry.key;
|
|
7
|
+
const symbolKind = entry.declarationInfo?.declarationKind ?? 'declaration';
|
|
8
|
+
const anchorKey = `source#${input.sourcePath}#declaration#${name}`;
|
|
9
|
+
const operation = {
|
|
10
|
+
id: input.operationId,
|
|
11
|
+
kind: 'jsTsRemoveTopLevelDeclaration',
|
|
12
|
+
changeKind: 'removed',
|
|
13
|
+
anchor: {
|
|
14
|
+
key: anchorKey,
|
|
15
|
+
conflictKey: `declaration:${entry.key}`,
|
|
16
|
+
regionId: anchorKey,
|
|
17
|
+
regionKind: 'declaration',
|
|
18
|
+
granularity: 'js-ts-ledger-entry',
|
|
19
|
+
language: input.language,
|
|
20
|
+
sourcePath: input.sourcePath,
|
|
21
|
+
symbolId: anchorKey,
|
|
22
|
+
symbolName: name,
|
|
23
|
+
symbolKind,
|
|
24
|
+
sourceSpan: { start: input.deletionPlan.headEntry.start, end: input.deletionPlan.headEntry.end }
|
|
25
|
+
},
|
|
26
|
+
spans: {
|
|
27
|
+
base: { start: entry.start, end: entry.end },
|
|
28
|
+
head: { start: input.deletionPlan.headEntry.start, end: input.deletionPlan.headEntry.end }
|
|
29
|
+
},
|
|
30
|
+
hashes: {
|
|
31
|
+
baseSourceHash: input.input.baseHash,
|
|
32
|
+
workerSourceHash: input.input.workerHash,
|
|
33
|
+
headSourceHash: input.input.headHash,
|
|
34
|
+
baseTextHash: hashSemanticValue(entry.text),
|
|
35
|
+
headTextHash: hashSemanticValue(input.deletionPlan.headEntry.text),
|
|
36
|
+
workerTextHash: hashSemanticValue('')
|
|
37
|
+
},
|
|
38
|
+
status: 'portable',
|
|
39
|
+
readiness: 'ready',
|
|
40
|
+
confidence: 1,
|
|
41
|
+
reasonCodes: ['head-anchor-matches-base', 'independent-top-level-deletion'],
|
|
42
|
+
evidenceIds: [`evidence_${idFragment(input.id)}_independent_top_level_deletion`],
|
|
43
|
+
metadata: {
|
|
44
|
+
autoMergeClaim: false,
|
|
45
|
+
semanticEquivalenceClaim: false,
|
|
46
|
+
ledgerKey: entry.key,
|
|
47
|
+
exported: false
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
return { ...operation, operationContentHash: hashSemanticValue(operation) };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function independentTopLevelDeletionScript(input) {
|
|
54
|
+
const core = {
|
|
55
|
+
kind: 'frontier.lang.semanticEditScript',
|
|
56
|
+
version: 1,
|
|
57
|
+
schema: 'frontier.lang.semanticEditScript.v1',
|
|
58
|
+
id: `${input.id}_semantic_edit`,
|
|
59
|
+
stableId: `semantic_edit_script_${idFragment([input.id, input.operation.operationContentHash].join(':'))}`,
|
|
60
|
+
language: input.language,
|
|
61
|
+
sourcePath: input.sourcePath,
|
|
62
|
+
baseHash: input.input.baseHash,
|
|
63
|
+
workerHash: input.input.workerHash,
|
|
64
|
+
headHash: input.input.headHash,
|
|
65
|
+
operations: [input.operation],
|
|
66
|
+
summary: {
|
|
67
|
+
operations: 1,
|
|
68
|
+
byStatus: { portable: 1 },
|
|
69
|
+
byKind: { jsTsRemoveTopLevelDeclaration: 1 },
|
|
70
|
+
portable: 1,
|
|
71
|
+
alreadyApplied: 0,
|
|
72
|
+
needsPort: 0,
|
|
73
|
+
conflicts: 0,
|
|
74
|
+
stale: 0,
|
|
75
|
+
blocked: 0,
|
|
76
|
+
candidates: 0,
|
|
77
|
+
autoMergeCandidates: 1,
|
|
78
|
+
operationContentHashes: [input.operation.operationContentHash]
|
|
79
|
+
},
|
|
80
|
+
admission: {
|
|
81
|
+
status: 'auto-merge-candidate',
|
|
82
|
+
action: 'run-gates-and-apply',
|
|
83
|
+
reviewRequired: false,
|
|
84
|
+
autoApplyCandidate: true,
|
|
85
|
+
autoMergeClaim: false,
|
|
86
|
+
semanticEquivalenceClaim: false,
|
|
87
|
+
reasonCodes: input.operation.reasonCodes,
|
|
88
|
+
conflictKeys: [input.operation.anchor.conflictKey],
|
|
89
|
+
evidenceIds: input.operation.evidenceIds
|
|
90
|
+
},
|
|
91
|
+
evidence: [{
|
|
92
|
+
id: `evidence_${idFragment(input.id)}_independent_top_level_deletion_script`,
|
|
93
|
+
kind: 'semantic-edit-script',
|
|
94
|
+
status: 'passed',
|
|
95
|
+
path: input.sourcePath,
|
|
96
|
+
summary: 'Created independent top-level deletion script with 1 operation.',
|
|
97
|
+
metadata: {
|
|
98
|
+
autoMergeClaim: false,
|
|
99
|
+
semanticEquivalenceClaim: false
|
|
100
|
+
}
|
|
101
|
+
}],
|
|
102
|
+
metadata: {
|
|
103
|
+
autoMergeClaim: false,
|
|
104
|
+
semanticEquivalenceClaim: false,
|
|
105
|
+
source: 'independent-top-level-deletion-fallback'
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
return { ...core, hash: hashSemanticValue(core) };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function independentTopLevelDeletionProjection(input) {
|
|
112
|
+
const editContentHash = hashSemanticValue({
|
|
113
|
+
operationId: input.operation.id,
|
|
114
|
+
deletedText: input.deletionPlan.deletedText,
|
|
115
|
+
replacementText: ''
|
|
116
|
+
});
|
|
117
|
+
const edit = {
|
|
118
|
+
operationId: input.operation.id,
|
|
119
|
+
status: 'applied',
|
|
120
|
+
kind: input.operation.kind,
|
|
121
|
+
editKind: 'delete',
|
|
122
|
+
changeKind: 'removed',
|
|
123
|
+
anchorKey: input.operation.anchor.key,
|
|
124
|
+
conflictKey: input.operation.anchor.conflictKey,
|
|
125
|
+
regionId: input.operation.anchor.regionId,
|
|
126
|
+
regionKind: input.operation.anchor.regionKind,
|
|
127
|
+
sourcePath: input.sourcePath,
|
|
128
|
+
symbolId: input.operation.anchor.symbolId,
|
|
129
|
+
symbolName: input.operation.anchor.symbolName,
|
|
130
|
+
symbolKind: input.operation.anchor.symbolKind,
|
|
131
|
+
operationContentHash: input.operation.operationContentHash,
|
|
132
|
+
editContentHash,
|
|
133
|
+
headStart: input.deletionPlan.edit.start,
|
|
134
|
+
headEnd: input.deletionPlan.edit.end,
|
|
135
|
+
editOrder: 0,
|
|
136
|
+
deletedBytes: input.deletionPlan.deletedText.length,
|
|
137
|
+
replacementBytes: 0,
|
|
138
|
+
deletedTextHash: hashSemanticValue(input.deletionPlan.deletedText),
|
|
139
|
+
replacementTextHash: hashSemanticValue(''),
|
|
140
|
+
deletedTextLineEndingStableHash: lineEndingStableTextHash(input.deletionPlan.deletedText),
|
|
141
|
+
replacementTextLineEndingStableHash: lineEndingStableTextHash(''),
|
|
142
|
+
replacementText: ''
|
|
143
|
+
};
|
|
144
|
+
const core = {
|
|
145
|
+
kind: 'frontier.lang.semanticEditProjection',
|
|
146
|
+
version: 1,
|
|
147
|
+
id: `${input.id}_semantic_edit_projection`,
|
|
148
|
+
scriptId: input.script.id,
|
|
149
|
+
status: 'projected',
|
|
150
|
+
sourcePath: input.sourcePath,
|
|
151
|
+
language: input.language,
|
|
152
|
+
baseHash: input.input.baseHash,
|
|
153
|
+
workerHash: input.input.workerHash,
|
|
154
|
+
headHash: input.input.headHash,
|
|
155
|
+
projectedHash: hashSemanticValue(input.deletionPlan.mergedSourceText),
|
|
156
|
+
appliedOperations: [input.operation.id],
|
|
157
|
+
skippedOperations: [],
|
|
158
|
+
edits: [edit],
|
|
159
|
+
sourceText: input.deletionPlan.mergedSourceText,
|
|
160
|
+
admission: {
|
|
161
|
+
status: 'auto-merge-candidate',
|
|
162
|
+
autoMergeClaim: false,
|
|
163
|
+
semanticEquivalenceClaim: false,
|
|
164
|
+
reasonCodes: []
|
|
165
|
+
},
|
|
166
|
+
metadata: {
|
|
167
|
+
autoMergeClaim: false,
|
|
168
|
+
semanticEquivalenceClaim: false,
|
|
169
|
+
source: 'independent-top-level-deletion-fallback'
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
return { ...core, hash: hashSemanticValue(core) };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function independentTopLevelDeletionReplay(input) {
|
|
176
|
+
const applied = input.editStatus === 'applied';
|
|
177
|
+
const edit = {
|
|
178
|
+
operationId: input.operation.id,
|
|
179
|
+
editKind: 'delete',
|
|
180
|
+
editOrder: 0,
|
|
181
|
+
sourcePath: input.sourcePath,
|
|
182
|
+
symbolName: input.operation.anchor.symbolName,
|
|
183
|
+
symbolKind: input.operation.anchor.symbolKind,
|
|
184
|
+
status: input.editStatus,
|
|
185
|
+
start: applied ? input.deletionPlan.edit.start : undefined,
|
|
186
|
+
end: applied ? input.deletionPlan.edit.end : undefined,
|
|
187
|
+
replacementBytes: 0,
|
|
188
|
+
replacementText: '',
|
|
189
|
+
reasonCodes: input.reasonCodes
|
|
190
|
+
};
|
|
191
|
+
const core = {
|
|
192
|
+
kind: 'frontier.lang.semanticEditReplay',
|
|
193
|
+
version: 1,
|
|
194
|
+
schema: 'frontier.lang.semanticEditReplay.v1',
|
|
195
|
+
id: input.id,
|
|
196
|
+
projectionId: input.projection.id,
|
|
197
|
+
scriptId: input.projection.scriptId,
|
|
198
|
+
sourcePath: input.sourcePath,
|
|
199
|
+
language: input.language,
|
|
200
|
+
currentHash: hashSemanticValue(input.currentSourceText),
|
|
201
|
+
projectedHash: input.projection.projectedHash,
|
|
202
|
+
outputHash: hashSemanticValue(input.outputSourceText),
|
|
203
|
+
status: input.status,
|
|
204
|
+
edits: [edit],
|
|
205
|
+
appliedOperations: applied ? [input.operation.id] : [],
|
|
206
|
+
skippedOperations: applied ? [] : [input.operation.id],
|
|
207
|
+
admission: {
|
|
208
|
+
status: input.status,
|
|
209
|
+
action: applied ? 'apply' : 'skip',
|
|
210
|
+
reviewRequired: false,
|
|
211
|
+
autoApplyCandidate: applied,
|
|
212
|
+
autoMergeClaim: false,
|
|
213
|
+
semanticEquivalenceClaim: false,
|
|
214
|
+
reasonCodes: []
|
|
215
|
+
},
|
|
216
|
+
outputSourceText: input.outputSourceText,
|
|
217
|
+
summary: {
|
|
218
|
+
edits: 1,
|
|
219
|
+
applied: applied ? 1 : 0,
|
|
220
|
+
alreadyApplied: applied ? 0 : 1,
|
|
221
|
+
conflicts: 0,
|
|
222
|
+
stale: 0,
|
|
223
|
+
blocked: 0,
|
|
224
|
+
reasonCodes: []
|
|
225
|
+
},
|
|
226
|
+
metadata: {
|
|
227
|
+
autoMergeClaim: false,
|
|
228
|
+
semanticEquivalenceClaim: false,
|
|
229
|
+
source: 'independent-top-level-deletion-fallback'
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
return { ...core, hash: hashSemanticValue(core) };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function lineEndingStableTextHash(value) {
|
|
236
|
+
const normalized = lineEndingStableText(value);
|
|
237
|
+
return normalized === undefined ? undefined : hashSemanticValue(normalized);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function lineEndingStableText(value) {
|
|
241
|
+
if (typeof value !== 'string') return undefined;
|
|
242
|
+
const normalized = value.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
243
|
+
return normalized.length > 1 && normalized.endsWith('\n') ? normalized.slice(0, -1) : normalized;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export {
|
|
247
|
+
independentTopLevelDeletionOperation,
|
|
248
|
+
independentTopLevelDeletionProjection,
|
|
249
|
+
independentTopLevelDeletionReplay,
|
|
250
|
+
independentTopLevelDeletionScript
|
|
251
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
|
|
2
|
+
import { uniqueStrings } from './native-import-utils.js';
|
|
3
|
+
|
|
4
|
+
function normalizeAlreadyAppliedDeleteReplay(input) {
|
|
5
|
+
if (!isProjectedDeleteAlreadyAppliedReplay(input)) return input.alreadyAppliedReplay;
|
|
6
|
+
const { hash: _hash, ...alreadyAppliedReplay } = input.alreadyAppliedReplay;
|
|
7
|
+
const normalizedEdits = input.alreadyAppliedReplay.edits.map((edit) => alreadyAppliedDeleteEdit(edit));
|
|
8
|
+
const reasonCodes = uniqueStrings(normalizedEdits.flatMap((edit) => edit.reasonCodes ?? []));
|
|
9
|
+
const core = {
|
|
10
|
+
...alreadyAppliedReplay,
|
|
11
|
+
currentHash: input.projection.projectedHash,
|
|
12
|
+
outputHash: input.projection.projectedHash,
|
|
13
|
+
status: 'already-applied',
|
|
14
|
+
edits: normalizedEdits,
|
|
15
|
+
appliedOperations: [],
|
|
16
|
+
skippedOperations: normalizedEdits.map((edit) => edit.operationId).filter(Boolean),
|
|
17
|
+
diagnostics: [],
|
|
18
|
+
admission: {
|
|
19
|
+
status: 'already-applied',
|
|
20
|
+
action: 'skip',
|
|
21
|
+
reviewRequired: false,
|
|
22
|
+
autoApplyCandidate: false,
|
|
23
|
+
autoMergeClaim: false,
|
|
24
|
+
semanticEquivalenceClaim: false,
|
|
25
|
+
reasonCodes
|
|
26
|
+
},
|
|
27
|
+
outputSourceText: input.projection.sourceText,
|
|
28
|
+
summary: {
|
|
29
|
+
edits: normalizedEdits.length,
|
|
30
|
+
applied: 0,
|
|
31
|
+
alreadyApplied: normalizedEdits.length,
|
|
32
|
+
conflicts: 0,
|
|
33
|
+
stale: 0,
|
|
34
|
+
blocked: 0,
|
|
35
|
+
reasonCodes
|
|
36
|
+
},
|
|
37
|
+
metadata: {
|
|
38
|
+
...input.alreadyAppliedReplay.metadata,
|
|
39
|
+
normalizedAlreadyAppliedReplay: 'projected-delete-anchor-absent'
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return { ...core, hash: hashSemanticValue(core) };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isProjectedDeleteAlreadyAppliedReplay(input) {
|
|
46
|
+
if (input.projection?.status !== 'projected') return false;
|
|
47
|
+
if (input.replay?.status !== 'accepted-clean') return false;
|
|
48
|
+
if (input.replay.outputSourceText !== input.projection.sourceText) return false;
|
|
49
|
+
const replay = input.alreadyAppliedReplay;
|
|
50
|
+
if (replay?.status !== 'stale') return false;
|
|
51
|
+
if (replay.currentHash !== input.projection.projectedHash) return false;
|
|
52
|
+
const edits = replay.edits ?? [];
|
|
53
|
+
if (!edits.length) return false;
|
|
54
|
+
const appliedDeleteIds = new Set((input.replay.edits ?? [])
|
|
55
|
+
.filter((edit) => edit.status === 'applied' && edit.editKind === 'delete')
|
|
56
|
+
.map((edit) => edit.operationId));
|
|
57
|
+
const projectionDeleteIds = new Set((input.projection.edits ?? [])
|
|
58
|
+
.filter((edit) => edit.editKind === 'delete')
|
|
59
|
+
.map((edit) => edit.operationId));
|
|
60
|
+
const staleDeletes = edits.filter(isProjectedDeleteMissingAnchor);
|
|
61
|
+
if (hasUnsafeProjectedDeleteCompanions(input, staleDeletes)) return false;
|
|
62
|
+
return staleDeletes.length > 0
|
|
63
|
+
&& edits.every((edit) => edit.status === 'already-applied' || isProjectedDeleteMissingAnchor(edit))
|
|
64
|
+
&& staleDeletes.every((edit) => appliedDeleteIds.has(edit.operationId) && projectionDeleteIds.has(edit.operationId));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isProjectedDeleteMissingAnchor(edit) {
|
|
68
|
+
return edit.editKind === 'delete'
|
|
69
|
+
&& edit.status === 'stale'
|
|
70
|
+
&& (edit.reasonCodes ?? []).includes('current-symbol-anchor-missing');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function alreadyAppliedDeleteEdit(edit) {
|
|
74
|
+
if (!isProjectedDeleteMissingAnchor(edit)) return edit;
|
|
75
|
+
return {
|
|
76
|
+
...edit,
|
|
77
|
+
status: 'already-applied',
|
|
78
|
+
reasonCodes: ['projected-delete-anchor-absent'],
|
|
79
|
+
diagnostics: []
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function hasUnsafeProjectedDeleteCompanions(input, staleDeletes) {
|
|
84
|
+
const projectionEdits = input.projection?.edits ?? [];
|
|
85
|
+
if (!projectionEdits.length || !staleDeletes.length) return false;
|
|
86
|
+
const projectionDeleteById = new Map(projectionEdits
|
|
87
|
+
.filter((edit) => edit.editKind === 'delete')
|
|
88
|
+
.map((edit) => [edit.operationId, edit]));
|
|
89
|
+
for (const staleDelete of staleDeletes) {
|
|
90
|
+
const projectedDelete = projectionDeleteById.get(staleDelete.operationId);
|
|
91
|
+
const scope = memberBodyDeleteScope(projectedDelete ?? staleDelete);
|
|
92
|
+
if (!scope) continue;
|
|
93
|
+
const companions = projectionEdits.filter((edit) => (
|
|
94
|
+
edit.operationId !== staleDelete.operationId
|
|
95
|
+
&& edit.editKind !== 'delete'
|
|
96
|
+
&& symbolContainerName(edit.symbolName) === scope.container
|
|
97
|
+
));
|
|
98
|
+
if (!companions.length) return true;
|
|
99
|
+
const bodyInserts = companions.filter((edit) => (
|
|
100
|
+
edit.editKind === 'insert'
|
|
101
|
+
&& edit.regionKind === scope.regionKind
|
|
102
|
+
&& edit.symbolKind === scope.symbolKind
|
|
103
|
+
));
|
|
104
|
+
if (bodyInserts.length === 0) return true;
|
|
105
|
+
if (companions.some((edit) => !bodyInserts.includes(edit))) return true;
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function memberBodyDeleteScope(edit) {
|
|
111
|
+
if (edit?.editKind !== 'delete' || edit?.regionKind !== 'body') return undefined;
|
|
112
|
+
const container = symbolContainerName(edit.symbolName);
|
|
113
|
+
if (!container) return undefined;
|
|
114
|
+
return {
|
|
115
|
+
container,
|
|
116
|
+
regionKind: edit.regionKind,
|
|
117
|
+
symbolKind: edit.symbolKind
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function symbolContainerName(symbolName) {
|
|
122
|
+
const normalized = String(symbolName ?? '').split(':controlFlow:')[0];
|
|
123
|
+
const separator = normalized.lastIndexOf('.');
|
|
124
|
+
return separator === -1 ? undefined : normalized.slice(0, separator);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export { normalizeAlreadyAppliedDeleteReplay };
|
|
@@ -3,12 +3,15 @@ import { createSemanticEditScript } from './internal/index-impl/semanticEditScri
|
|
|
3
3
|
import { projectSemanticEditScriptToSource } from './internal/index-impl/projectSemanticEditScriptToSource.js';
|
|
4
4
|
import { replaySemanticEditProjection } from './internal/index-impl/replaySemanticEditProjection.js';
|
|
5
5
|
import { JsTsSafeMergeStatuses } from './js-ts-safe-merge-constants.js';
|
|
6
|
+
import { independentTopLevelDeletionFallbackResult } from './js-ts-safe-merge-independent-deletion-fallback.js';
|
|
7
|
+
import { normalizeAlreadyAppliedDeleteReplay } from './js-ts-safe-merge-semantic-edit-already-applied.js';
|
|
6
8
|
import {
|
|
7
9
|
semanticFallbackChangedExistingDeclarations,
|
|
8
10
|
semanticFallbackConflictCode,
|
|
9
11
|
semanticFallbackPhase,
|
|
10
12
|
shouldTrySemanticEditFallback
|
|
11
13
|
} from './js-ts-safe-merge-semantic-edit-fallback-utils.js';
|
|
14
|
+
import { semanticEditGates } from './js-ts-safe-merge-semantic-edit-gates.js';
|
|
12
15
|
import {
|
|
13
16
|
createStagedDeclarationAlreadyAppliedReplay,
|
|
14
17
|
createStagedDeclarationProjection,
|
|
@@ -19,6 +22,8 @@ import { createSourceShapeSemanticFallbackResult } from './js-ts-safe-merge-sour
|
|
|
19
22
|
import { idFragment, uniqueStrings } from './native-import-utils.js';
|
|
20
23
|
|
|
21
24
|
function semanticEditFallbackResult(input, topLevelResult) {
|
|
25
|
+
const independentDeletionResult = independentTopLevelDeletionFallbackResult(input, topLevelResult);
|
|
26
|
+
if (independentDeletionResult) return independentDeletionResult;
|
|
22
27
|
if (!shouldTrySemanticEditFallback(topLevelResult)) return topLevelResult;
|
|
23
28
|
const stagedFallback = createStagedTopLevelSemanticFallback(input, topLevelResult);
|
|
24
29
|
const candidates = semanticFallbackCandidates(stagedFallback);
|
|
@@ -132,14 +137,18 @@ function createSemanticEditFallbackArtifacts(input, topLevelResult, stagedFallba
|
|
|
132
137
|
});
|
|
133
138
|
const alreadyAppliedReplay = stagedDeclarationProjection
|
|
134
139
|
? createStagedDeclarationAlreadyAppliedReplay({ id, projection, sourcePath, language })
|
|
135
|
-
:
|
|
136
|
-
id: `${id}_semantic_edit_already_applied`,
|
|
140
|
+
: normalizeAlreadyAppliedDeleteReplay({
|
|
137
141
|
projection,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
replay,
|
|
143
|
+
alreadyAppliedReplay: replaySemanticEditProjection({
|
|
144
|
+
id: `${id}_semantic_edit_already_applied`,
|
|
145
|
+
projection,
|
|
146
|
+
currentSourceText: projection.sourceText,
|
|
147
|
+
currentSourcePath: sourcePath,
|
|
148
|
+
currentSourceHash: projection.projectedHash,
|
|
149
|
+
language,
|
|
150
|
+
parser: input.parser
|
|
151
|
+
})
|
|
143
152
|
});
|
|
144
153
|
return semanticEditArtifacts({
|
|
145
154
|
id,
|
|
@@ -301,19 +310,4 @@ function semanticEditFallbackBlockedResult(input, topLevelResult, artifacts) {
|
|
|
301
310
|
};
|
|
302
311
|
}
|
|
303
312
|
|
|
304
|
-
|
|
305
|
-
return [
|
|
306
|
-
gate('semantic-edit-script', artifacts.script?.admission?.status === 'auto-merge-candidate', artifacts.script?.admission?.reasonCodes),
|
|
307
|
-
gate('semantic-edit-projection', artifacts.projection?.status === 'projected', artifacts.projection?.admission?.reasonCodes),
|
|
308
|
-
gate('semantic-edit-replay', artifacts.replay?.status === 'accepted-clean', artifacts.replay?.admission?.reasonCodes),
|
|
309
|
-
gate('semantic-edit-already-applied', artifacts.alreadyAppliedReplay?.status === 'already-applied', artifacts.alreadyAppliedReplay?.admission?.reasonCodes)
|
|
310
|
-
];
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function gate(id, passed, reasonCodes = []) {
|
|
314
|
-
return { id, status: passed ? 'passed' : 'blocked', reasonCodes: passed ? [] : uniqueStrings(reasonCodes) };
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export {
|
|
318
|
-
semanticEditFallbackResult
|
|
319
|
-
};
|
|
313
|
+
export { semanticEditFallbackResult };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { uniqueStrings } from './native-import-utils.js';
|
|
2
|
+
|
|
3
|
+
function semanticEditGates(artifacts) {
|
|
4
|
+
return [
|
|
5
|
+
gate('semantic-edit-script', artifacts.script?.admission?.status === 'auto-merge-candidate', artifacts.script?.admission?.reasonCodes),
|
|
6
|
+
gate('semantic-edit-projection', artifacts.projection?.status === 'projected', artifacts.projection?.admission?.reasonCodes),
|
|
7
|
+
gate('semantic-edit-replay', artifacts.replay?.status === 'accepted-clean', artifacts.replay?.admission?.reasonCodes),
|
|
8
|
+
gate('semantic-edit-already-applied', artifacts.alreadyAppliedReplay?.status === 'already-applied', artifacts.alreadyAppliedReplay?.admission?.reasonCodes)
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function gate(id, passed, reasonCodes = []) {
|
|
13
|
+
return { id, status: passed ? 'passed' : 'blocked', reasonCodes: passed ? [] : uniqueStrings(reasonCodes) };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { semanticEditGates };
|
package/package.json
CHANGED