@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.
@@ -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
- ...declaration,
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: `rel_${idFragment(documentId)}_${idFragment(declaration.nativeNode.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
- metadata: {
99
- parser: options.parser,
100
- astFormat: options.astFormat,
101
- language: input.language,
102
- sourceHash: input.sourceHash
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
- const uniqueReasons = uniqueStrings(reasonCodes);
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
+ };