@shapeshift-labs/frontier-lang-compiler 0.2.104 → 0.2.106
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/dist/declarations/js-ts-safe-member-merge.d.ts +29 -1
- package/dist/declarations/js-ts-safe-merge.d.ts +47 -0
- package/dist/declarations/native-project.d.ts +110 -0
- package/dist/internal/index-impl/createNativeProjectImportResult.js +177 -3
- package/dist/internal/index-impl/replaySemanticEditProjection.js +1 -1
- package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +200 -15
- package/dist/js-ts-safe-member-merge.js +69 -6
- package/dist/js-ts-safe-merge-composed.js +175 -0
- package/dist/js-ts-safe-merge-semantic-artifact-ledger.js +197 -0
- package/dist/js-ts-safe-merge-semantic-artifacts.js +266 -0
- package/dist/js-ts-safe-merge.js +6 -1
- package/dist/js-ts-semantic-merge-member-source.js +22 -4
- package/dist/js-ts-semantic-merge-parse.js +1 -0
- package/dist/js-ts-semantic-merge.js +3 -0
- package/package.json +1 -1
|
@@ -6,24 +6,39 @@ export function semanticIndexFromNativeDeclarations(declarations, input, options
|
|
|
6
6
|
const symbols = [];
|
|
7
7
|
const occurrences = [];
|
|
8
8
|
const relations = [];
|
|
9
|
-
const facts = [];
|
|
9
|
+
const facts = input.sourceHash ? [fileHashFact(documentId, input, evidenceId)] : [];
|
|
10
10
|
const mappings = [];
|
|
11
11
|
for (const declaration of declarations) {
|
|
12
12
|
const symbolId = declaration.symbolId ?? `symbol:${input.language}:${declaration.role === 'import' ? 'import:' : ''}${caseSensitiveIdFragment(declaration.name)}`;
|
|
13
|
+
const normalizedDeclaration = {
|
|
14
|
+
...declaration,
|
|
15
|
+
symbolId,
|
|
16
|
+
regionKind: declarationRegionKind(declaration)
|
|
17
|
+
};
|
|
13
18
|
const occurrenceId = `occ_${idFragment(declaration.nativeNode.id)}_${declaration.role ?? 'definition'}`;
|
|
14
19
|
const ownershipRegion = semanticOwnershipRegionForDeclaration(input, {
|
|
15
|
-
...
|
|
20
|
+
...normalizedDeclaration,
|
|
16
21
|
nodeId: declaration.nativeNode.id,
|
|
17
22
|
kind: declaration.nativeNode.kind,
|
|
18
23
|
languageKind: declaration.nativeNode.languageKind,
|
|
19
24
|
span: declaration.nativeNode.span,
|
|
20
25
|
symbolId
|
|
21
26
|
}, documentId);
|
|
27
|
+
const relationId = `rel_${idFragment(documentId)}_${idFragment(declaration.nativeNode.id)}`;
|
|
28
|
+
const moduleEdge = moduleEdgeForDeclaration(normalizedDeclaration, input, documentId, relationId, ownershipRegion);
|
|
29
|
+
const publicContractRegion = publicContractRegionForDeclaration(normalizedDeclaration, ownershipRegion, moduleEdge);
|
|
30
|
+
const reExportIdentity = reExportIdentityForDeclaration(normalizedDeclaration, input, documentId, relationId, ownershipRegion, moduleEdge);
|
|
31
|
+
const graphMetadata = {
|
|
32
|
+
...(moduleEdge ? { moduleEdge } : {}),
|
|
33
|
+
...(publicContractRegion ? { publicContract: true, publicContractRegionId: publicContractRegion.id } : {}),
|
|
34
|
+
...(reExportIdentity ? { reExportIdentity } : {})
|
|
35
|
+
};
|
|
22
36
|
declaration.nativeNode.metadata = {
|
|
23
37
|
...declaration.nativeNode.metadata,
|
|
24
38
|
ownershipRegionId: ownershipRegion.id,
|
|
25
39
|
ownershipRegionKey: ownershipRegion.key,
|
|
26
|
-
ownershipRegionKind: ownershipRegion.regionKind
|
|
40
|
+
ownershipRegionKind: ownershipRegion.regionKind,
|
|
41
|
+
...graphMetadata
|
|
27
42
|
};
|
|
28
43
|
symbols.push({
|
|
29
44
|
id: symbolId,
|
|
@@ -38,7 +53,8 @@ export function semanticIndexFromNativeDeclarations(declarations, input, options
|
|
|
38
53
|
...declaration.nativeNode.metadata,
|
|
39
54
|
ownershipRegionId: ownershipRegion.id,
|
|
40
55
|
ownershipRegionKey: ownershipRegion.key,
|
|
41
|
-
ownershipRegionKind: ownershipRegion.regionKind
|
|
56
|
+
ownershipRegionKind: ownershipRegion.regionKind,
|
|
57
|
+
...graphMetadata
|
|
42
58
|
}
|
|
43
59
|
});
|
|
44
60
|
occurrences.push({
|
|
@@ -47,13 +63,16 @@ export function semanticIndexFromNativeDeclarations(declarations, input, options
|
|
|
47
63
|
symbolId,
|
|
48
64
|
role: declaration.role ?? 'definition',
|
|
49
65
|
span: declaration.nativeNode.span,
|
|
50
|
-
nativeAstNodeId: declaration.nativeNode.id
|
|
66
|
+
nativeAstNodeId: declaration.nativeNode.id,
|
|
67
|
+
...(Object.keys(graphMetadata).length ? { metadata: graphMetadata } : {})
|
|
51
68
|
});
|
|
52
69
|
relations.push({
|
|
53
|
-
id:
|
|
70
|
+
id: relationId,
|
|
54
71
|
sourceId: documentId,
|
|
55
72
|
predicate: relationPredicateForDeclaration(declaration),
|
|
56
|
-
targetId: symbolId
|
|
73
|
+
targetId: symbolId,
|
|
74
|
+
evidenceIds: [evidenceId],
|
|
75
|
+
...(Object.keys(graphMetadata).length ? { metadata: graphMetadata } : {})
|
|
57
76
|
});
|
|
58
77
|
facts.push({
|
|
59
78
|
id: `fact_${idFragment(declaration.nativeNode.id)}_kind`,
|
|
@@ -74,7 +93,7 @@ export function semanticIndexFromNativeDeclarations(declarations, input, options
|
|
|
74
93
|
granularity: ownershipRegion.granularity,
|
|
75
94
|
key: ownershipRegion.key
|
|
76
95
|
}
|
|
77
|
-
});
|
|
96
|
+
}, ...projectSymbolGraphFacts({ moduleEdge, publicContractRegion, reExportIdentity, relationId, symbolId, evidenceId }));
|
|
78
97
|
mappings.push({
|
|
79
98
|
id: `map_${idFragment(declaration.nativeNode.id)}`,
|
|
80
99
|
nativeAstNodeId: declaration.nativeNode.id,
|
|
@@ -95,12 +114,18 @@ export function semanticIndexFromNativeDeclarations(declarations, input, options
|
|
|
95
114
|
status: 'passed',
|
|
96
115
|
path: input.sourcePath,
|
|
97
116
|
summary: `Normalized ${options.astFormat ?? options.parser} native AST with ${declarations.length} declaration(s).`,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
117
|
+
metadata: {
|
|
118
|
+
parser: options.parser,
|
|
119
|
+
astFormat: options.astFormat,
|
|
120
|
+
language: input.language,
|
|
121
|
+
sourceHash: input.sourceHash,
|
|
122
|
+
graphRecords: {
|
|
123
|
+
fileHashes: input.sourceHash ? 1 : 0,
|
|
124
|
+
moduleEdges: facts.filter((fact) => fact.predicate === 'moduleEdge').length,
|
|
125
|
+
reExportIdentities: facts.filter((fact) => fact.predicate === 'reExportIdentity').length,
|
|
126
|
+
publicContractRegions: facts.filter((fact) => fact.predicate === 'publicContractRegion').length
|
|
127
|
+
}
|
|
128
|
+
}
|
|
104
129
|
}];
|
|
105
130
|
return {
|
|
106
131
|
semanticIndex: createSemanticIndexRecord({
|
|
@@ -119,10 +144,170 @@ export function semanticIndexFromNativeDeclarations(declarations, input, options
|
|
|
119
144
|
metadata: {
|
|
120
145
|
parser: options.parser,
|
|
121
146
|
astFormat: options.astFormat,
|
|
122
|
-
coverage: 'native-ast-declarations'
|
|
147
|
+
coverage: 'native-ast-declarations',
|
|
148
|
+
graphCoverage: 'module-edge-declarations'
|
|
123
149
|
}
|
|
124
150
|
}),
|
|
125
151
|
mappings,
|
|
126
152
|
evidence
|
|
127
153
|
};
|
|
128
154
|
}
|
|
155
|
+
|
|
156
|
+
function fileHashFact(documentId, input, evidenceId) {
|
|
157
|
+
return {
|
|
158
|
+
id: `fact_${idFragment(documentId)}_file_hash`,
|
|
159
|
+
predicate: 'fileHash',
|
|
160
|
+
subjectId: documentId,
|
|
161
|
+
value: { ...hashParts(input.sourceHash), sourcePath: input.sourcePath, language: input.language },
|
|
162
|
+
evidenceIds: [evidenceId]
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function declarationRegionKind(declaration) {
|
|
167
|
+
if (declaration.regionKind) return declaration.regionKind;
|
|
168
|
+
if (declaration.role === 'import' || declaration.importPath) return 'import';
|
|
169
|
+
if (declaration.role === 'export' || declaration.exported || declaration.reExport) return 'export';
|
|
170
|
+
if (declaration.publicContract || declaration.metadata?.publicContract) return 'export';
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function moduleEdgeForDeclaration(declaration, input, documentId, relationId, ownershipRegion) {
|
|
175
|
+
const role = declaration.role;
|
|
176
|
+
if (role !== 'import' && role !== 'export') return undefined;
|
|
177
|
+
const moduleSpecifier = moduleSpecifierForDeclaration(declaration);
|
|
178
|
+
const edgeKind = role === 'import' ? 'import' : moduleSpecifier || declaration.reExport ? 're-export' : 'export';
|
|
179
|
+
return compactRecord({
|
|
180
|
+
kind: 'frontier.lang.moduleEdge',
|
|
181
|
+
version: 1,
|
|
182
|
+
id: relationId,
|
|
183
|
+
edgeKind,
|
|
184
|
+
role,
|
|
185
|
+
sourceDocumentId: documentId,
|
|
186
|
+
sourcePath: input.sourcePath,
|
|
187
|
+
sourceHash: input.sourceHash,
|
|
188
|
+
moduleSpecifier,
|
|
189
|
+
symbolId: declaration.symbolId,
|
|
190
|
+
relationId,
|
|
191
|
+
ownershipRegionId: ownershipRegion.id,
|
|
192
|
+
ownershipRegionKey: ownershipRegion.key,
|
|
193
|
+
importKind: declaration.importKind ?? declaration.metadata?.importKind,
|
|
194
|
+
exportKind: declaration.exportKind ?? declaration.metadata?.exportKind,
|
|
195
|
+
importedName: declaration.importedName ?? declaration.metadata?.importedName,
|
|
196
|
+
exportedName: declaration.exportedName ?? declaration.metadata?.exportedName,
|
|
197
|
+
localName: declaration.localName ?? declaration.metadata?.localName,
|
|
198
|
+
namespace: declaration.namespace ?? declaration.metadata?.namespace,
|
|
199
|
+
isTypeOnly: declaration.isTypeOnly ?? declaration.metadata?.isTypeOnly,
|
|
200
|
+
isReExport: edgeKind === 're-export',
|
|
201
|
+
publicContract: publicContractForDeclaration(declaration, edgeKind)
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function moduleSpecifierForDeclaration(declaration) {
|
|
206
|
+
return firstString(
|
|
207
|
+
declaration.moduleSpecifier,
|
|
208
|
+
declaration.importPath,
|
|
209
|
+
declaration.exportPath,
|
|
210
|
+
declaration.source,
|
|
211
|
+
declaration.metadata?.moduleSpecifier,
|
|
212
|
+
declaration.metadata?.importPath,
|
|
213
|
+
declaration.metadata?.exportPath,
|
|
214
|
+
declaration.metadata?.source,
|
|
215
|
+
declaration.symbolKind === 'module' ? declaration.name : undefined
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function publicContractForDeclaration(declaration, edgeKind) {
|
|
220
|
+
return Boolean(
|
|
221
|
+
declaration.publicContract
|
|
222
|
+
|| declaration.exported
|
|
223
|
+
|| declaration.metadata?.publicContract
|
|
224
|
+
|| declaration.metadata?.publicContractRegion
|
|
225
|
+
|| declaration.role === 'export'
|
|
226
|
+
|| edgeKind === 'export'
|
|
227
|
+
|| edgeKind === 're-export'
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function publicContractRegionForDeclaration(declaration, ownershipRegion, moduleEdge) {
|
|
232
|
+
if (!publicContractForDeclaration(declaration, moduleEdge?.edgeKind)) return undefined;
|
|
233
|
+
return {
|
|
234
|
+
...ownershipRegion,
|
|
235
|
+
regionKind: declaration.publicContractRegionKind ?? declaration.metadata?.publicContractRegionKind ?? ownershipRegion.regionKind,
|
|
236
|
+
publicContract: true,
|
|
237
|
+
exportedName: declaration.exportedName ?? declaration.metadata?.exportedName,
|
|
238
|
+
moduleSpecifier: moduleEdge?.moduleSpecifier,
|
|
239
|
+
edgeKind: moduleEdge?.edgeKind
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function reExportIdentityForDeclaration(declaration, input, documentId, relationId, ownershipRegion, moduleEdge) {
|
|
244
|
+
if (!moduleEdge?.isReExport && !declaration.reExport) return undefined;
|
|
245
|
+
return compactRecord({
|
|
246
|
+
kind: 'frontier.lang.reExportIdentity',
|
|
247
|
+
version: 1,
|
|
248
|
+
id: `reexport_${idFragment(relationId)}`,
|
|
249
|
+
sourceDocumentId: documentId,
|
|
250
|
+
sourcePath: input.sourcePath,
|
|
251
|
+
sourceHash: input.sourceHash,
|
|
252
|
+
moduleSpecifier: moduleEdge?.moduleSpecifier,
|
|
253
|
+
exportedName: declaration.exportedName ?? declaration.metadata?.exportedName,
|
|
254
|
+
importedName: declaration.importedName ?? declaration.metadata?.importedName,
|
|
255
|
+
localName: declaration.localName ?? declaration.metadata?.localName,
|
|
256
|
+
namespace: declaration.namespace ?? declaration.metadata?.namespace,
|
|
257
|
+
isTypeOnly: declaration.isTypeOnly ?? declaration.metadata?.isTypeOnly,
|
|
258
|
+
symbolId: declaration.symbolId,
|
|
259
|
+
relationId,
|
|
260
|
+
ownershipRegionId: ownershipRegion.id,
|
|
261
|
+
ownershipRegionKey: ownershipRegion.key,
|
|
262
|
+
publicContract: true
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function projectSymbolGraphFacts({ moduleEdge, publicContractRegion, reExportIdentity, relationId, symbolId, evidenceId }) {
|
|
267
|
+
return [
|
|
268
|
+
moduleEdge ? {
|
|
269
|
+
id: `fact_${idFragment(relationId)}_module_edge`,
|
|
270
|
+
predicate: 'moduleEdge',
|
|
271
|
+
subjectId: relationId,
|
|
272
|
+
objectId: symbolId,
|
|
273
|
+
value: moduleEdge,
|
|
274
|
+
evidenceIds: [evidenceId]
|
|
275
|
+
} : undefined,
|
|
276
|
+
reExportIdentity ? {
|
|
277
|
+
id: `fact_${idFragment(relationId)}_re_export_identity`,
|
|
278
|
+
predicate: 'reExportIdentity',
|
|
279
|
+
subjectId: symbolId,
|
|
280
|
+
objectId: relationId,
|
|
281
|
+
value: reExportIdentity,
|
|
282
|
+
evidenceIds: [evidenceId]
|
|
283
|
+
} : undefined,
|
|
284
|
+
publicContractRegion ? {
|
|
285
|
+
id: `fact_${idFragment(symbolId)}_public_contract_region`,
|
|
286
|
+
predicate: 'publicContractRegion',
|
|
287
|
+
subjectId: symbolId,
|
|
288
|
+
objectId: publicContractRegion.id,
|
|
289
|
+
value: publicContractRegion,
|
|
290
|
+
evidenceIds: [evidenceId]
|
|
291
|
+
} : undefined
|
|
292
|
+
].filter(Boolean);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function hashParts(sourceHash) {
|
|
296
|
+
const text = String(sourceHash);
|
|
297
|
+
const separator = text.indexOf(':');
|
|
298
|
+
return {
|
|
299
|
+
sourceHash: text,
|
|
300
|
+
...(separator > 0 ? { algorithm: text.slice(0, separator), value: text.slice(separator + 1) } : { value: text })
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function compactRecord(record) {
|
|
305
|
+
return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function firstString(...values) {
|
|
309
|
+
for (const value of values) {
|
|
310
|
+
if (value !== undefined && value !== null && String(value)) return String(value);
|
|
311
|
+
}
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyMemberAdditions,
|
|
3
|
+
applyPreparedMemberAdditions,
|
|
3
4
|
canonicalizeSourceBodies,
|
|
4
5
|
findContainer,
|
|
5
6
|
normalizeKind,
|
|
@@ -17,6 +18,54 @@ function safeMergeJsTsMembers(input = {}) {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
function mergeJsTsSafeMemberAdditions(input = {}) {
|
|
21
|
+
const analysis = analyzeJsTsSafeMemberAdditions(input);
|
|
22
|
+
const uniqueReasons = uniqueStrings(analysis.reasonCodes);
|
|
23
|
+
if (uniqueReasons.length) {
|
|
24
|
+
return mergeResult('rejected', undefined, uniqueReasons, analysis.preparedRegions, input, analysis.explicitPolicy);
|
|
25
|
+
}
|
|
26
|
+
const sourceText = applyMemberAdditions(analysis.headSourceText, analysis.preparedRegions);
|
|
27
|
+
return mergeResult('merged', sourceText, [], analysis.preparedRegions, input, analysis.explicitPolicy);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function analyzeJsTsSafeMemberAdditions(input = {}) {
|
|
31
|
+
const analysis = prepareJsTsSafeMemberAdditions(input);
|
|
32
|
+
const reasonCodes = [...analysis.reasonCodes];
|
|
33
|
+
if (!input.allowNonPolicySourceChanges) {
|
|
34
|
+
reasonCodes.push(...nonPolicySourceChangeReasons(analysis));
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
...analysis,
|
|
38
|
+
reasonCodes: uniqueStrings(reasonCodes),
|
|
39
|
+
ok: reasonCodes.length === 0
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function neutralizeJsTsSafeMemberMergeSources(input = {}) {
|
|
44
|
+
const analysis = analyzeJsTsSafeMemberAdditions({
|
|
45
|
+
...input,
|
|
46
|
+
allowNonPolicySourceChanges: true
|
|
47
|
+
});
|
|
48
|
+
if (analysis.reasonCodes.length) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
analysis,
|
|
52
|
+
result: mergeResult('rejected', undefined, analysis.reasonCodes, analysis.preparedRegions, input, analysis.explicitPolicy)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
ok: true,
|
|
57
|
+
analysis,
|
|
58
|
+
baseSourceText: analysis.baseSourceText,
|
|
59
|
+
workerSourceText: canonicalizeSourceBodies(analysis.workerSourceText, analysis.preparedRegions, 'worker'),
|
|
60
|
+
headSourceText: canonicalizeSourceBodies(analysis.headSourceText, analysis.preparedRegions, 'head')
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function applyJsTsPreparedMemberAdditions(sourceText, preparedRegions, sides) {
|
|
65
|
+
return applyPreparedMemberAdditions(sourceText, preparedRegions, sides);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function prepareJsTsSafeMemberAdditions(input = {}) {
|
|
20
69
|
const baseSourceText = input.baseSourceText;
|
|
21
70
|
const workerSourceText = input.workerSourceText;
|
|
22
71
|
const headSourceText = input.headSourceText;
|
|
@@ -36,6 +85,20 @@ function mergeJsTsSafeMemberAdditions(input = {}) {
|
|
|
36
85
|
reasonCodes.push(...prepared.reasonCodes);
|
|
37
86
|
if (prepared.ok) preparedRegions.push(prepared.value);
|
|
38
87
|
}
|
|
88
|
+
const explicitPolicy = policyRegions.length > 0;
|
|
89
|
+
return {
|
|
90
|
+
baseSourceText,
|
|
91
|
+
workerSourceText,
|
|
92
|
+
headSourceText,
|
|
93
|
+
reasonCodes: uniqueStrings(reasonCodes),
|
|
94
|
+
preparedRegions,
|
|
95
|
+
explicitPolicy
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function nonPolicySourceChangeReasons(analysis) {
|
|
100
|
+
const reasonCodes = [];
|
|
101
|
+
const { baseSourceText, workerSourceText, headSourceText, preparedRegions } = analysis;
|
|
39
102
|
if (typeof baseSourceText === 'string' && typeof workerSourceText === 'string' && preparedRegions.length) {
|
|
40
103
|
const canonicalWorker = canonicalizeSourceBodies(workerSourceText, preparedRegions, 'worker');
|
|
41
104
|
if (canonicalWorker !== baseSourceText) reasonCodes.push('non-policy-source-change:worker');
|
|
@@ -44,11 +107,7 @@ function mergeJsTsSafeMemberAdditions(input = {}) {
|
|
|
44
107
|
const canonicalHead = canonicalizeSourceBodies(headSourceText, preparedRegions, 'head');
|
|
45
108
|
if (canonicalHead !== baseSourceText) reasonCodes.push('non-policy-source-change:head');
|
|
46
109
|
}
|
|
47
|
-
|
|
48
|
-
const explicitPolicy = policyRegions.length > 0;
|
|
49
|
-
if (uniqueReasons.length) return mergeResult('rejected', undefined, uniqueReasons, preparedRegions, input, explicitPolicy);
|
|
50
|
-
const sourceText = applyMemberAdditions(headSourceText, preparedRegions);
|
|
51
|
-
return mergeResult('merged', sourceText, [], preparedRegions, input, explicitPolicy);
|
|
110
|
+
return reasonCodes;
|
|
52
111
|
}
|
|
53
112
|
|
|
54
113
|
function normalizePolicyRegions(policy) {
|
|
@@ -125,7 +184,8 @@ function prepareRegion(input) {
|
|
|
125
184
|
headMembers: headMembers.members,
|
|
126
185
|
workerAddedKeys,
|
|
127
186
|
headAddedKeys,
|
|
128
|
-
workerAddedMembers: workerMembers.members.filter((member) => workerAddedKeys.includes(member.key))
|
|
187
|
+
workerAddedMembers: workerMembers.members.filter((member) => workerAddedKeys.includes(member.key)),
|
|
188
|
+
headAddedMembers: headMembers.members.filter((member) => headAddedKeys.includes(member.key))
|
|
129
189
|
}
|
|
130
190
|
};
|
|
131
191
|
}
|
|
@@ -197,6 +257,9 @@ function regionReason(region, reason) {
|
|
|
197
257
|
}
|
|
198
258
|
|
|
199
259
|
export {
|
|
260
|
+
analyzeJsTsSafeMemberAdditions,
|
|
261
|
+
applyJsTsPreparedMemberAdditions,
|
|
200
262
|
mergeJsTsSafeMemberAdditions,
|
|
263
|
+
neutralizeJsTsSafeMemberMergeSources,
|
|
201
264
|
safeMergeJsTsMembers
|
|
202
265
|
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JsTsSafeMergeConflictCodes,
|
|
3
|
+
JsTsSafeMergeGateIds,
|
|
4
|
+
JsTsSafeMergeStatuses,
|
|
5
|
+
jsTsSafeMergeGateOrder
|
|
6
|
+
} from './js-ts-safe-merge-constants.js';
|
|
7
|
+
import { safeMergeJsTsImportsAndDeclarations } from './js-ts-safe-merge.js';
|
|
8
|
+
import { createJsTsSafeMergeSemanticArtifacts } from './js-ts-safe-merge-semantic-artifacts.js';
|
|
9
|
+
import {
|
|
10
|
+
applyJsTsPreparedMemberAdditions,
|
|
11
|
+
neutralizeJsTsSafeMemberMergeSources
|
|
12
|
+
} from './js-ts-safe-member-merge.js';
|
|
13
|
+
|
|
14
|
+
function safeMergeJsTsSource(input = {}) {
|
|
15
|
+
if (!hasMemberMergePolicy(input)) return safeMergeJsTsImportsAndDeclarations(input);
|
|
16
|
+
|
|
17
|
+
const memberNeutralization = neutralizeJsTsSafeMemberMergeSources(input);
|
|
18
|
+
if (!memberNeutralization.ok) {
|
|
19
|
+
return composedBlockedResult(input, 'member-analysis', memberNeutralization.result, memberNeutralization.analysis);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const topLevelResult = safeMergeJsTsImportsAndDeclarations({
|
|
23
|
+
...input,
|
|
24
|
+
baseSourceText: memberNeutralization.baseSourceText,
|
|
25
|
+
workerSourceText: memberNeutralization.workerSourceText,
|
|
26
|
+
headSourceText: memberNeutralization.headSourceText
|
|
27
|
+
});
|
|
28
|
+
if (topLevelResult.status !== JsTsSafeMergeStatuses.merged) {
|
|
29
|
+
return composedBlockedResult(input, 'top-level', topLevelResult, memberNeutralization.analysis);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const memberApplication = applyJsTsPreparedMemberAdditions(
|
|
33
|
+
topLevelResult.mergedSourceText,
|
|
34
|
+
memberNeutralization.analysis.preparedRegions,
|
|
35
|
+
['head', 'worker']
|
|
36
|
+
);
|
|
37
|
+
if (memberApplication.reasonCodes.length) {
|
|
38
|
+
return composedMemberApplicationBlockedResult(input, topLevelResult, memberNeutralization.analysis, memberApplication.reasonCodes);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const memberAdditions = memberNeutralization.analysis.preparedRegions.reduce((total, region) => (
|
|
42
|
+
total + region.workerAddedKeys.length + region.headAddedKeys.length
|
|
43
|
+
), 0);
|
|
44
|
+
const result = {
|
|
45
|
+
...topLevelResult,
|
|
46
|
+
id: String(input.id ?? topLevelResult.id),
|
|
47
|
+
mergedSourceText: memberApplication.sourceText,
|
|
48
|
+
outputSourceText: memberApplication.sourceText,
|
|
49
|
+
summary: {
|
|
50
|
+
...topLevelResult.summary,
|
|
51
|
+
memberRegions: memberNeutralization.analysis.preparedRegions.length,
|
|
52
|
+
memberAdditions,
|
|
53
|
+
composedPhases: 2
|
|
54
|
+
},
|
|
55
|
+
metadata: {
|
|
56
|
+
...topLevelResult.metadata,
|
|
57
|
+
composed: {
|
|
58
|
+
phases: ['top-level', 'member'],
|
|
59
|
+
memberRegions: memberNeutralization.analysis.preparedRegions.map((region) => ({
|
|
60
|
+
kind: region.kind,
|
|
61
|
+
name: region.name,
|
|
62
|
+
regionKind: region.policy.regionKind,
|
|
63
|
+
workerAddedKeys: region.workerAddedKeys,
|
|
64
|
+
headAddedKeys: region.headAddedKeys
|
|
65
|
+
}))
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
...result,
|
|
71
|
+
semanticArtifacts: createJsTsSafeMergeSemanticArtifacts(input, result)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function hasMemberMergePolicy(input) {
|
|
76
|
+
const policy = input.policy ?? input.mergePolicy ?? input;
|
|
77
|
+
const regions = Array.isArray(policy)
|
|
78
|
+
? policy
|
|
79
|
+
: policy?.unorderedRegions
|
|
80
|
+
?? policy?.unorderedMemberRegions
|
|
81
|
+
?? policy?.safeList
|
|
82
|
+
?? policy?.safeMembers
|
|
83
|
+
?? [];
|
|
84
|
+
return Array.isArray(regions) && regions.length > 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function composedBlockedResult(input, phase, result, memberAnalysis) {
|
|
88
|
+
return {
|
|
89
|
+
kind: 'frontier.lang.jsTsSafeMerge',
|
|
90
|
+
version: 1,
|
|
91
|
+
schema: 'frontier.lang.jsTsSafeMerge.v1',
|
|
92
|
+
id: String(input.id ?? result.id ?? 'js_ts_safe_merge'),
|
|
93
|
+
status: JsTsSafeMergeStatuses.blocked,
|
|
94
|
+
sourcePath: input.sourcePath,
|
|
95
|
+
language: input.language ?? 'typescript',
|
|
96
|
+
conflicts: result.conflicts ?? [],
|
|
97
|
+
gates: result.gates ?? [],
|
|
98
|
+
admission: {
|
|
99
|
+
status: 'blocked',
|
|
100
|
+
action: 'human-review',
|
|
101
|
+
reviewRequired: true,
|
|
102
|
+
autoApplyCandidate: false,
|
|
103
|
+
autoMergeClaim: false,
|
|
104
|
+
semanticEquivalenceClaim: false,
|
|
105
|
+
reasonCodes: result.admission?.reasonCodes ?? result.reasonCodes ?? []
|
|
106
|
+
},
|
|
107
|
+
summary: {
|
|
108
|
+
importSpecifierAdditions: 0,
|
|
109
|
+
topLevelDeclarationAdditions: 0,
|
|
110
|
+
changedExistingDeclarations: result.summary?.changedExistingDeclarations ?? 0,
|
|
111
|
+
conflicts: result.conflicts?.length ?? result.summary?.conflicts ?? 0,
|
|
112
|
+
gatesPassed: result.gates?.filter((gate) => gate.status === 'passed').length ?? 0,
|
|
113
|
+
memberRegions: memberAnalysis?.preparedRegions?.length ?? 0,
|
|
114
|
+
memberAdditions: 0,
|
|
115
|
+
composedPhases: phase === 'top-level' ? 2 : 1
|
|
116
|
+
},
|
|
117
|
+
metadata: {
|
|
118
|
+
composed: {
|
|
119
|
+
phase,
|
|
120
|
+
sourceKind: result.kind
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function composedMemberApplicationBlockedResult(input, topLevelResult, memberAnalysis, reasonCodes) {
|
|
127
|
+
const conflicts = reasonCodes.map((reason) => ({
|
|
128
|
+
code: JsTsSafeMergeConflictCodes.parserLedgerLoss,
|
|
129
|
+
gateId: JsTsSafeMergeGateIds.parseLedger,
|
|
130
|
+
message: 'Composed member application could not find a stable target container.',
|
|
131
|
+
side: 'merged',
|
|
132
|
+
sourcePath: input.sourcePath,
|
|
133
|
+
details: { reason }
|
|
134
|
+
}));
|
|
135
|
+
return {
|
|
136
|
+
...topLevelResult,
|
|
137
|
+
status: JsTsSafeMergeStatuses.blocked,
|
|
138
|
+
mergedSourceText: undefined,
|
|
139
|
+
outputSourceText: undefined,
|
|
140
|
+
conflicts,
|
|
141
|
+
gates: jsTsSafeMergeGateOrder.map((id, index) => ({
|
|
142
|
+
id,
|
|
143
|
+
status: index === 0 ? 'blocked' : 'skipped',
|
|
144
|
+
reasonCodes: index === 0 ? [JsTsSafeMergeConflictCodes.parserLedgerLoss] : []
|
|
145
|
+
})),
|
|
146
|
+
admission: {
|
|
147
|
+
status: 'blocked',
|
|
148
|
+
action: 'human-review',
|
|
149
|
+
reviewRequired: true,
|
|
150
|
+
autoApplyCandidate: false,
|
|
151
|
+
autoMergeClaim: false,
|
|
152
|
+
semanticEquivalenceClaim: false,
|
|
153
|
+
reasonCodes: [JsTsSafeMergeConflictCodes.parserLedgerLoss]
|
|
154
|
+
},
|
|
155
|
+
summary: {
|
|
156
|
+
...topLevelResult.summary,
|
|
157
|
+
conflicts: conflicts.length,
|
|
158
|
+
gatesPassed: 0,
|
|
159
|
+
memberRegions: memberAnalysis.preparedRegions.length,
|
|
160
|
+
memberAdditions: 0,
|
|
161
|
+
composedPhases: 2
|
|
162
|
+
},
|
|
163
|
+
metadata: {
|
|
164
|
+
...topLevelResult.metadata,
|
|
165
|
+
composed: {
|
|
166
|
+
phase: 'member-application',
|
|
167
|
+
reasonCodes
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export {
|
|
174
|
+
safeMergeJsTsSource
|
|
175
|
+
};
|