@shapeshift-labs/frontier-lang-compiler 0.2.103 → 0.2.104

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.
Files changed (124) hide show
  1. package/README.md +13 -0
  2. package/dist/declarations/bidirectional-target-change-source-edit.d.ts +30 -0
  3. package/dist/declarations/bidirectional-target-change.d.ts +10 -0
  4. package/dist/declarations/js-ts-safe-member-merge.d.ts +58 -0
  5. package/dist/declarations/js-ts-safe-merge.d.ts +120 -0
  6. package/dist/declarations/js-ts-semantic-conflict-sidecars.d.ts +235 -0
  7. package/dist/declarations/js-ts-semantic-merge-contracts.d.ts +287 -0
  8. package/dist/declarations/js-ts-semantic-merge.d.ts +4 -0
  9. package/dist/declarations/native-import-losses.d.ts +3 -0
  10. package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +12 -0
  11. package/dist/declarations/semantic-edit-script.d.ts +7 -4
  12. package/dist/declarations/semantic-patch-bundle-index.d.ts +45 -0
  13. package/dist/declarations/semantic-patch-bundle.d.ts +6 -4
  14. package/dist/declarations/semantic-sidecar-example.d.ts +18 -0
  15. package/dist/declarations/semantic-transform-identity.d.ts +3 -0
  16. package/dist/declarations/source-preservation.d.ts +72 -0
  17. package/dist/declarations/universal-capability.d.ts +4 -0
  18. package/dist/declarations/universal-conversion-artifacts.d.ts +61 -1
  19. package/dist/declarations/universal-conversion-compact-counts.d.ts +51 -0
  20. package/dist/declarations/universal-conversion-plan.d.ts +6 -1
  21. package/dist/declarations/universal-representation-coverage.d.ts +90 -0
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.js +3 -0
  24. package/dist/internal/index-impl/bidirectionalExactSourceBackprojection.js +199 -0
  25. package/dist/internal/index-impl/bidirectionalSameLanguageSourceProjection.js +112 -0
  26. package/dist/internal/index-impl/bidirectionalSourceEditProjection.js +319 -0
  27. package/dist/internal/index-impl/bidirectionalSourceEditProjectionArtifacts.js +67 -0
  28. package/dist/internal/index-impl/bidirectionalTargetChangeRecordInternals.js +17 -5
  29. package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +58 -20
  30. package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +60 -7
  31. package/dist/internal/index-impl/createLightweightNativeImport.js +1 -0
  32. package/dist/internal/index-impl/createNativeSourcePreservation.js +28 -2
  33. package/dist/internal/index-impl/diffNativeSymbols.js +3 -3
  34. package/dist/internal/index-impl/nativeChangeProjectionSourceMapLinks.js +2 -0
  35. package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +43 -8
  36. package/dist/internal/index-impl/replaySemanticEditLineEndings.js +34 -0
  37. package/dist/internal/index-impl/replaySemanticEditProjection.js +39 -19
  38. package/dist/internal/index-impl/semanticEditBundleAdmission.js +7 -3
  39. package/dist/internal/index-impl/semanticEditBundleIndex.js +47 -1
  40. package/dist/internal/index-impl/semanticEditExplicitSourceReplacement.js +40 -0
  41. package/dist/internal/index-impl/semanticEditOperationCoverage.js +33 -3
  42. package/dist/internal/index-impl/semanticEditProjectionRecord.js +29 -0
  43. package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +39 -0
  44. package/dist/internal/index-impl/semanticEditReplaySourceReplacement.js +85 -0
  45. package/dist/internal/index-impl/semanticEditScripts.js +4 -0
  46. package/dist/internal/index-impl/semanticEditSourceRanges.js +27 -0
  47. package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +1 -0
  48. package/dist/internal/index-impl/semanticPatchBundleAdmission.js +41 -7
  49. package/dist/internal/index-impl/semanticPatchBundleRecords.js +16 -0
  50. package/dist/internal/index-impl/semanticPatchBundleSourceRecords.js +2 -0
  51. package/dist/internal/index-impl/semanticSidecarQuality.js +111 -0
  52. package/dist/internal/index-impl/semanticSourceEditDedupe.js +69 -9
  53. package/dist/internal/index-impl/semanticTransformIdentityRecords.js +85 -9
  54. package/dist/js-ts-safe-member-merge-result.js +158 -0
  55. package/dist/js-ts-safe-member-merge.js +202 -0
  56. package/dist/js-ts-safe-merge-analyze.js +279 -0
  57. package/dist/js-ts-safe-merge-constants.js +50 -0
  58. package/dist/js-ts-safe-merge-context.js +118 -0
  59. package/dist/js-ts-safe-merge-ledger-validation.js +92 -0
  60. package/dist/js-ts-safe-merge-ledger.js +85 -0
  61. package/dist/js-ts-safe-merge-parse-declarations.js +210 -0
  62. package/dist/js-ts-safe-merge-parse-statements.js +155 -0
  63. package/dist/js-ts-safe-merge-plan.js +190 -0
  64. package/dist/js-ts-safe-merge.js +175 -0
  65. package/dist/js-ts-semantic-conflict-sidecar-constants.js +77 -0
  66. package/dist/js-ts-semantic-conflict-sidecar-detectors.js +195 -0
  67. package/dist/js-ts-semantic-conflict-sidecar-normalize.js +203 -0
  68. package/dist/js-ts-semantic-conflict-sidecar-utils.js +190 -0
  69. package/dist/js-ts-semantic-conflict-sidecars.js +81 -0
  70. package/dist/js-ts-semantic-merge-contract-helpers.js +128 -0
  71. package/dist/js-ts-semantic-merge-contracts.js +217 -0
  72. package/dist/js-ts-semantic-merge-member-containers.js +100 -0
  73. package/dist/js-ts-semantic-merge-member-keys.js +142 -0
  74. package/dist/js-ts-semantic-merge-member-segments.js +185 -0
  75. package/dist/js-ts-semantic-merge-member-source.js +64 -0
  76. package/dist/js-ts-semantic-merge-member-utils.js +18 -0
  77. package/dist/js-ts-semantic-merge-parse.js +15 -0
  78. package/dist/js-ts-semantic-merge.js +21 -0
  79. package/dist/lightweight-dependency-effects.js +51 -0
  80. package/dist/lightweight-dependency-language.js +12 -1
  81. package/dist/lightweight-dependency-relations.js +14 -27
  82. package/dist/native-region-scanner-core.js +33 -1
  83. package/dist/native-region-scanner-csharp.js +151 -0
  84. package/dist/native-region-scanner-dart.js +91 -0
  85. package/dist/native-region-scanner-dynamic.js +21 -151
  86. package/dist/native-region-scanner-functional.js +40 -13
  87. package/dist/native-region-scanner-java.js +97 -0
  88. package/dist/native-region-scanner-js-class.js +100 -0
  89. package/dist/native-region-scanner-js-helpers.js +28 -86
  90. package/dist/native-region-scanner-js-imports.js +121 -1
  91. package/dist/native-region-scanner-js-nested.js +96 -8
  92. package/dist/native-region-scanner-js-structure.js +27 -0
  93. package/dist/native-region-scanner-js-types.js +99 -0
  94. package/dist/native-region-scanner-js.js +70 -118
  95. package/dist/native-region-scanner-kotlin.js +94 -0
  96. package/dist/native-region-scanner-main.js +15 -181
  97. package/dist/native-region-scanner-php.js +80 -0
  98. package/dist/native-region-scanner-python.js +62 -0
  99. package/dist/native-region-scanner-ruby.js +72 -0
  100. package/dist/native-region-scanner-scala.js +91 -0
  101. package/dist/native-region-scanner-spans.js +74 -0
  102. package/dist/native-region-scanner-swift.js +155 -0
  103. package/dist/native-region-scanner.js +14 -10
  104. package/dist/native-source-ledger-helpers.js +195 -0
  105. package/dist/native-source-ledger.js +306 -0
  106. package/dist/native-source-preservation-scanner.js +4 -0
  107. package/dist/semantic-import-callsite-regions.js +136 -0
  108. package/dist/semantic-import-effect-regions.js +283 -0
  109. package/dist/semantic-import-regions.js +11 -2
  110. package/dist/semantic-import-sidecar-entry.js +16 -2
  111. package/dist/semantic-import-sidecar-types.d.ts +2 -0
  112. package/dist/semantic-sidecar-example.js +68 -0
  113. package/dist/universal-capability-matrix.js +23 -0
  114. package/dist/universal-conversion-artifact-query.js +79 -2
  115. package/dist/universal-conversion-artifact-semantic-edit.js +103 -0
  116. package/dist/universal-conversion-artifact-summary.js +33 -1
  117. package/dist/universal-conversion-artifacts.js +13 -48
  118. package/dist/universal-conversion-plan-scoring.js +21 -1
  119. package/dist/universal-conversion-plan-summary.js +30 -0
  120. package/dist/universal-conversion-plan.js +25 -9
  121. package/dist/universal-conversion-route-metadata.js +96 -0
  122. package/dist/universal-conversion-route-operations.js +7 -0
  123. package/dist/universal-representation-coverage.js +193 -0
  124. package/package.json +1 -1
@@ -0,0 +1,203 @@
1
+ import { uniqueStrings } from './native-import-utils.js';
2
+ import { array, compactRecord, firstString, keysForAffected, keysForChange, normalizeChangeKind, numberOrUndefined, numberValue, strings } from './js-ts-semantic-conflict-sidecar-utils.js';
3
+
4
+ export function normalizedChanges(input, context) {
5
+ return [
6
+ ...array(input.changes),
7
+ ...array(input.operations),
8
+ ...array(input.edits),
9
+ ...array(input.left?.changes).map((change) => ({ ...change, side: change.side ?? 'left' })),
10
+ ...array(input.left?.operations).map((change) => ({ ...change, side: change.side ?? 'left' })),
11
+ ...array(input.right?.changes).map((change) => ({ ...change, side: change.side ?? 'right' })),
12
+ ...array(input.right?.operations).map((change) => ({ ...change, side: change.side ?? 'right' }))
13
+ ].map((change, index) => normalizeChange(change, context, `change_${index + 1}`));
14
+ }
15
+
16
+ export function normalizeChange(change, context, fallbackId) {
17
+ const anchor = change.anchor ?? {};
18
+ const insertion = change.insertion ?? {};
19
+ const spans = change.spans ?? {};
20
+ const sourcePath = firstString(
21
+ change.sourcePath,
22
+ change.originalSourcePath,
23
+ change.targetSourcePath,
24
+ anchor.sourcePath,
25
+ insertion.sourcePath,
26
+ insertion.insertedSourcePath,
27
+ context.sourcePath
28
+ );
29
+ const span = normalizeSpan(
30
+ change.sourceSpan
31
+ ?? change.span
32
+ ?? change.range
33
+ ?? spans.head
34
+ ?? spans.worker
35
+ ?? spans.base
36
+ ?? anchor.sourceSpan
37
+ ?? insertion.insertedSourceSpan
38
+ ?? insertion.baseSpan
39
+ ?? insertion.headSpan,
40
+ sourcePath
41
+ );
42
+ const key = firstString(
43
+ change.conflictKey,
44
+ change.regionKey,
45
+ change.key,
46
+ change.semanticKey,
47
+ change.anchorKey,
48
+ anchor.conflictKey,
49
+ anchor.key,
50
+ anchor.regionId,
51
+ insertion.anchorKey
52
+ );
53
+ const listKey = firstString(change.listKey, change.orderedListKey, change.containerKey, change.parentKey, change.orderingKey);
54
+ return {
55
+ raw: change,
56
+ id: firstString(change.id, change.operationId, fallbackId),
57
+ side: firstString(change.side, change.author, change.branch, change.source, fallbackId),
58
+ changeKind: normalizeChangeKind(change.changeKind ?? change.kind ?? change.editKind ?? change.op),
59
+ sourcePath,
60
+ span,
61
+ key,
62
+ regionKey: firstString(change.regionKey, anchor.regionId, key),
63
+ conflictKey: firstString(change.conflictKey, anchor.conflictKey, key),
64
+ symbolId: firstString(change.symbolId, anchor.symbolId, insertion.insertedSymbolId),
65
+ symbolName: firstString(change.symbolName, anchor.symbolName, insertion.insertedSymbolName),
66
+ symbolKind: firstString(change.symbolKind, anchor.symbolKind, insertion.insertedSymbolKind),
67
+ memberName: firstString(change.memberName, change.name, change.symbolName, insertion.insertedSymbolName),
68
+ exportName: firstString(change.exportName, change.exportedName),
69
+ containerKey: firstString(change.containerKey, change.parentKey, anchor.regionId),
70
+ listKey,
71
+ orderedListKey: firstString(change.orderedListKey, listKey),
72
+ index: firstString(change.index, change.position, change.orderIndex),
73
+ position: firstString(change.position, change.index),
74
+ orderKey: firstString(change.orderKey, change.order, change.sortKey),
75
+ beforeKey: firstString(change.beforeKey, change.before, change.previousKey),
76
+ afterKey: firstString(change.afterKey, change.after, change.nextKey),
77
+ anchorKey: firstString(change.anchorKey, insertion.anchorKey, anchor.key),
78
+ sourceHash: firstString(change.sourceHash, change.currentSourceHash, change.targetHash),
79
+ reasonCodes: uniqueStrings([...strings(change.reasonCode), ...strings(change.reasonCodes)])
80
+ };
81
+ }
82
+
83
+ export function normalizeDeclaration(entry, index, context) {
84
+ const change = normalizeChange(entry, context, `declaration_${index + 1}`);
85
+ const name = firstString(entry.name, entry.memberName, entry.exportName, entry.symbolName, change.memberName, change.exportName, change.symbolName);
86
+ const exported = entry.exported === true || entry.isExport === true || Boolean(entry.exportName) || /export/i.test(String(entry.kind ?? entry.symbolKind ?? ''));
87
+ const member = entry.member === true || entry.isMember === true || Boolean(entry.memberName || entry.containerKey || entry.parentKey) || /member|method|field|property/i.test(String(entry.kind ?? entry.symbolKind ?? ''));
88
+ return {
89
+ ...change,
90
+ name,
91
+ exported,
92
+ member,
93
+ containerKey: firstString(entry.containerKey, entry.parentKey, entry.classKey, entry.ownerKey, change.containerKey),
94
+ key: firstString(entry.key, entry.semanticKey, change.key, name)
95
+ };
96
+ }
97
+
98
+ export function sameChangeRegion(left, right) {
99
+ if (left.id === right.id) return false;
100
+ if (left.side && right.side && left.side === right.side) return false;
101
+ const leftKeys = keysForChange(left);
102
+ const rightKeys = keysForChange(right);
103
+ if (leftKeys.some((key) => rightKeys.includes(key))) return true;
104
+ return spansOverlap(left.span, right.span);
105
+ }
106
+
107
+ export function spansOverlap(left, right) {
108
+ if (!left || !right) return false;
109
+ if (left.sourcePath && right.sourcePath && left.sourcePath !== right.sourcePath) return false;
110
+ const leftStart = numberValue(left.startOffset, left.start);
111
+ const leftEnd = numberValue(left.endOffset, left.end);
112
+ const rightStart = numberValue(right.startOffset, right.start);
113
+ const rightEnd = numberValue(right.endOffset, right.end);
114
+ if (Number.isFinite(leftStart) && Number.isFinite(leftEnd) && Number.isFinite(rightStart) && Number.isFinite(rightEnd)) {
115
+ return leftStart < rightEnd && rightStart < leftEnd;
116
+ }
117
+ const leftStartLine = numberValue(left.startLine, left.line);
118
+ const leftEndLine = numberValue(left.endLine, leftStartLine);
119
+ const rightStartLine = numberValue(right.startLine, right.line);
120
+ const rightEndLine = numberValue(right.endLine, rightStartLine);
121
+ if (Number.isFinite(leftStartLine) && Number.isFinite(leftEndLine) && Number.isFinite(rightStartLine) && Number.isFinite(rightEndLine)) {
122
+ return leftStartLine <= rightEndLine && rightStartLine <= leftEndLine;
123
+ }
124
+ return false;
125
+ }
126
+
127
+ export function affectedFromEntries(entries, context) {
128
+ return normalizeAffected({
129
+ sourcePath: uniqueStrings(entries.map((entry) => entry.sourcePath)),
130
+ sourceSpan: entries.map((entry) => entry.span ?? entry.sourceSpan).filter(Boolean),
131
+ key: entries.flatMap((entry) => keysForAffected(entry)),
132
+ symbolId: entries.map((entry) => entry.symbolId),
133
+ symbolName: entries.map((entry) => entry.symbolName ?? entry.name),
134
+ memberKey: entries.map((entry) => entry.memberName ? `${entry.containerKey ?? entry.sourcePath ?? context.sourcePath ?? 'member'}#${entry.memberName}` : undefined),
135
+ exportName: entries.map((entry) => entry.exportName ?? (entry.exported ? entry.name : undefined)),
136
+ orderedListKey: entries.map((entry) => entry.listKey ?? entry.orderedListKey),
137
+ sourceHash: entries.map((entry) => entry.sourceHash)
138
+ }, context);
139
+ }
140
+
141
+ export function normalizeAffected(value, context) {
142
+ const sourcePaths = uniqueStrings([
143
+ context.sourcePath,
144
+ ...strings(value.sourcePath),
145
+ ...strings(value.sourcePaths),
146
+ ...array(value.spans).map((span) => span?.sourcePath),
147
+ ...array(value.sourceSpan).map((span) => span?.sourcePath)
148
+ ]);
149
+ const spans = uniqueSpans([
150
+ ...array(value.sourceSpan),
151
+ ...array(value.span),
152
+ ...array(value.spans)
153
+ ].map((span) => normalizeSpan(span, sourcePaths[0])).filter(Boolean));
154
+ const keys = uniqueStrings([
155
+ ...strings(value.key),
156
+ ...strings(value.keys),
157
+ ...strings(value.conflictKey),
158
+ ...strings(value.conflictKeys),
159
+ ...strings(value.regionKey),
160
+ ...strings(value.regionKeys),
161
+ ...strings(value.semanticKey),
162
+ ...strings(value.anchorKey)
163
+ ]);
164
+ return {
165
+ sourcePaths,
166
+ spans,
167
+ keys,
168
+ regionKeys: uniqueStrings([...strings(value.regionKey), ...strings(value.regionKeys)]),
169
+ symbolIds: uniqueStrings([...strings(value.symbolId), ...strings(value.symbolIds)]),
170
+ symbolNames: uniqueStrings([...strings(value.symbolName), ...strings(value.symbolNames)]),
171
+ memberKeys: uniqueStrings([...strings(value.memberKey), ...strings(value.memberKeys)]),
172
+ exportNames: uniqueStrings([...strings(value.exportName), ...strings(value.exportNames)]),
173
+ orderedListKeys: uniqueStrings([...strings(value.orderedListKey), ...strings(value.orderedListKeys), ...strings(value.listKey)]),
174
+ sourceHashes: uniqueStrings([...strings(value.sourceHash), ...strings(value.sourceHashes)])
175
+ };
176
+ }
177
+
178
+ export function normalizeSpan(span, sourcePath) {
179
+ if (!span || typeof span !== 'object') return undefined;
180
+ return compactRecord({
181
+ sourcePath: span.sourcePath ?? span.path ?? sourcePath,
182
+ start: numberOrUndefined(span.start),
183
+ end: numberOrUndefined(span.end),
184
+ startOffset: numberOrUndefined(span.startOffset ?? span.offset),
185
+ endOffset: numberOrUndefined(span.endOffset),
186
+ startLine: numberOrUndefined(span.startLine ?? span.line),
187
+ startColumn: numberOrUndefined(span.startColumn ?? span.column),
188
+ endLine: numberOrUndefined(span.endLine ?? span.line),
189
+ endColumn: numberOrUndefined(span.endColumn)
190
+ });
191
+ }
192
+
193
+ export function uniqueSpans(spans) {
194
+ const seen = new Set();
195
+ const result = [];
196
+ for (const span of spans) {
197
+ const key = JSON.stringify(span);
198
+ if (seen.has(key)) continue;
199
+ seen.add(key);
200
+ result.push(span);
201
+ }
202
+ return result;
203
+ }
@@ -0,0 +1,190 @@
1
+ import { uniqueStrings } from './native-import-utils.js';
2
+ import { deleteChangeKinds, modifyChangeKinds, riskRank, severityRank } from './js-ts-semantic-conflict-sidecar-constants.js';
3
+
4
+ export function changePairs(changes) {
5
+ const pairs = [];
6
+ for (let leftIndex = 0; leftIndex < changes.length; leftIndex += 1) {
7
+ for (let rightIndex = leftIndex + 1; rightIndex < changes.length; rightIndex += 1) {
8
+ pairs.push([changes[leftIndex], changes[rightIndex]]);
9
+ }
10
+ }
11
+ return pairs;
12
+ }
13
+
14
+ export function duplicateGroups(entries, keyFn) {
15
+ const groups = new Map();
16
+ for (const entry of entries) {
17
+ const key = keyFn(entry);
18
+ if (!key || /^(\|)+$/.test(key)) continue;
19
+ groups.set(key, [...(groups.get(key) ?? []), entry]);
20
+ }
21
+ return [...groups.values()].filter((group) => group.length > 1);
22
+ }
23
+
24
+ export function dedupeSidecars(records) {
25
+ const seen = new Set();
26
+ const result = [];
27
+ for (const record of records) {
28
+ const key = `${record.class}:${record.id}:${record.reasonCodes.join('|')}`;
29
+ if (seen.has(key)) continue;
30
+ seen.add(key);
31
+ result.push(record);
32
+ }
33
+ return result.sort(compareSidecars);
34
+ }
35
+
36
+ function compareSidecars(left, right) {
37
+ return (riskRank[right.risk] ?? 2) - (riskRank[left.risk] ?? 2)
38
+ || (severityRank[right.severity] ?? 2) - (severityRank[left.severity] ?? 2)
39
+ || String(left.class).localeCompare(String(right.class))
40
+ || String(left.id).localeCompare(String(right.id));
41
+ }
42
+
43
+ export function mergeContext(input, options) {
44
+ return {
45
+ language: options.language ?? input.language ?? input.sourceLanguage ?? 'typescript',
46
+ sourcePath: options.sourcePath ?? input.sourcePath ?? input.path,
47
+ readiness: options.readiness ?? input.readiness,
48
+ expectedSourceHash: firstString(
49
+ options.expectedSourceHash,
50
+ input.expectedSourceHash,
51
+ input.expectedHash,
52
+ input.sourceHashAssertions?.expectedSourceHash,
53
+ input.sourceHashes?.expectedSourceHash
54
+ ),
55
+ currentSourceHash: firstString(
56
+ options.currentSourceHash,
57
+ input.currentSourceHash,
58
+ input.actualSourceHash,
59
+ input.sourceHashAssertions?.currentSourceHash,
60
+ input.sourceHashes?.currentSourceHash
61
+ )
62
+ };
63
+ }
64
+
65
+ export function keysForChange(change) {
66
+ return uniqueStrings([
67
+ change.key,
68
+ change.conflictKey,
69
+ change.regionKey,
70
+ change.semanticKey,
71
+ change.anchorKey
72
+ ]);
73
+ }
74
+
75
+ export function keysForAffected(entry) {
76
+ return uniqueStrings([
77
+ entry.key,
78
+ entry.conflictKey,
79
+ entry.regionKey,
80
+ entry.semanticKey,
81
+ entry.anchorKey,
82
+ entry.containerKey,
83
+ entry.id
84
+ ]);
85
+ }
86
+
87
+ export function lossText(entry) {
88
+ return [
89
+ entry?.kind,
90
+ entry?.code,
91
+ entry?.reasonCode,
92
+ ...(entry?.reasonCodes ?? []),
93
+ entry?.message,
94
+ entry?.summary,
95
+ entry?.category,
96
+ entry?.lossClass
97
+ ].filter(Boolean).join(' ');
98
+ }
99
+
100
+ export function lossReasonCodes(entry) {
101
+ return uniqueStrings([
102
+ ...strings(entry?.reasonCode),
103
+ ...strings(entry?.reasonCodes),
104
+ entry?.code,
105
+ entry?.kind
106
+ ]);
107
+ }
108
+
109
+ export function classesFromRecords(records) {
110
+ return records.map((record) => record.class);
111
+ }
112
+
113
+ export function summarySuggestedOutcome(records, readiness) {
114
+ if (!records.length) return 'auto-merge-safe';
115
+ const outcomes = uniqueStrings(records.map((record) => record.suggestedOutcome));
116
+ if (readiness === 'blocked') return outcomes.includes('rerun-parser-and-ledger-before-merge')
117
+ ? 'rerun-parser-and-ledger-before-merge'
118
+ : 'manual-merge-required';
119
+ return outcomes[0] ?? 'human-review';
120
+ }
121
+
122
+ export function highestSeverity(records) {
123
+ const value = Math.max(0, ...records.map((record) => severityRank[record.severity] ?? 2));
124
+ return Object.keys(severityRank).find((severity) => severityRank[severity] === value) ?? 'info';
125
+ }
126
+
127
+ export function highestRisk(records) {
128
+ const value = Math.max(0, ...records.map((record) => riskRank[record.risk] ?? 2));
129
+ return Object.keys(riskRank).find((risk) => riskRank[risk] === value) ?? 'low';
130
+ }
131
+
132
+ export function normalizeSeverity(value) {
133
+ const severity = String(value ?? '').toLowerCase();
134
+ return Object.prototype.hasOwnProperty.call(severityRank, severity) ? severity : undefined;
135
+ }
136
+
137
+ export function normalizeRisk(value) {
138
+ const risk = String(value ?? '').toLowerCase();
139
+ return Object.prototype.hasOwnProperty.call(riskRank, risk) ? risk : undefined;
140
+ }
141
+
142
+ export function normalizeChangeKind(value) {
143
+ const text = String(value ?? 'modify').toLowerCase();
144
+ if (text === 'removed') return 'delete';
145
+ if (text === 'added') return 'insert';
146
+ if (text === 'updated') return 'modify';
147
+ return text;
148
+ }
149
+
150
+ export function isDeleteChange(change) {
151
+ return deleteChangeKinds.test(change.changeKind);
152
+ }
153
+
154
+ export function isModifyChange(change) {
155
+ return modifyChangeKinds.test(change.changeKind);
156
+ }
157
+
158
+ export function isInsertChange(change) {
159
+ return /^(?:insert|add|create)$/i.test(change.changeKind);
160
+ }
161
+
162
+ export function numberValue(...values) {
163
+ for (const value of values) {
164
+ const number = Number(value);
165
+ if (Number.isFinite(number)) return number;
166
+ }
167
+ return undefined;
168
+ }
169
+
170
+ export function numberOrUndefined(value) {
171
+ const number = Number(value);
172
+ return Number.isFinite(number) ? number : undefined;
173
+ }
174
+
175
+ export function array(value) {
176
+ if (value === undefined || value === null) return [];
177
+ return Array.isArray(value) ? value : [value];
178
+ }
179
+
180
+ export function strings(value) {
181
+ return array(value).flatMap((entry) => Array.isArray(entry) ? strings(entry) : [String(entry ?? '')]).filter(Boolean);
182
+ }
183
+
184
+ export function firstString(...values) {
185
+ return values.map((value) => value === undefined || value === null ? '' : String(value)).find(Boolean);
186
+ }
187
+
188
+ export function compactRecord(value) {
189
+ return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && entry !== ''));
190
+ }
@@ -0,0 +1,81 @@
1
+ import { countBy, idFragment, maxSemanticMergeReadiness, normalizeSemanticMergeReadiness, uniqueStrings } from './native-import-utils.js';
2
+ import { JsTsSemanticConflictSidecarClasses } from './js-ts-semantic-conflict-sidecar-constants.js';
3
+ import { deleteModifySidecars, duplicateDeclarationSidecars, explicitSidecars, orderedListSidecars, parserLedgerLossSidecars, sameRegionSidecars, staleSourceHashSidecars, unsupportedSyntaxSidecars } from './js-ts-semantic-conflict-sidecar-detectors.js';
4
+ import { normalizedChanges } from './js-ts-semantic-conflict-sidecar-normalize.js';
5
+ import { array, classesFromRecords, compactRecord, dedupeSidecars, highestRisk, highestSeverity, mergeContext, summarySuggestedOutcome } from './js-ts-semantic-conflict-sidecar-utils.js';
6
+
7
+ export { JsTsSemanticConflictSidecarClasses } from './js-ts-semantic-conflict-sidecar-constants.js';
8
+
9
+ export function createJsTsSemanticConflictSidecars(input = {}, options = {}) {
10
+ const context = mergeContext(input, options);
11
+ const changes = normalizedChanges(input, context);
12
+ const records = dedupeSidecars([
13
+ ...explicitSidecars(input, context),
14
+ ...sameRegionSidecars(changes, context),
15
+ ...deleteModifySidecars(changes, context),
16
+ ...duplicateDeclarationSidecars(input, changes, context),
17
+ ...orderedListSidecars(input, changes, context),
18
+ ...parserLedgerLossSidecars(input, context),
19
+ ...staleSourceHashSidecars(input, context),
20
+ ...unsupportedSyntaxSidecars(input, context)
21
+ ]);
22
+ const summary = summarizeJsTsSemanticConflictSidecars(records, context);
23
+ const id = options.id
24
+ ?? input.id
25
+ ?? `js_ts_semantic_conflict_sidecars_${idFragment(context.sourcePath ?? context.language ?? 'source')}`;
26
+ return {
27
+ kind: 'frontier.lang.jsTsSemanticMergeConflictSidecars',
28
+ version: 1,
29
+ schema: 'frontier.lang.jsTsSemanticMergeConflictSidecars.v1',
30
+ id,
31
+ language: context.language,
32
+ sourcePath: context.sourcePath,
33
+ expectedSourceHash: context.expectedSourceHash,
34
+ currentSourceHash: context.currentSourceHash,
35
+ conflicts: records,
36
+ sidecars: records,
37
+ summary,
38
+ admission: {
39
+ status: records.length ? summary.readiness : 'ready',
40
+ reviewRequired: records.length > 0,
41
+ autoMergeSafe: records.length === 0,
42
+ suggestedOutcome: summary.suggestedOutcome,
43
+ reasonCodes: summary.reasonCodes
44
+ },
45
+ metadata: compactRecord({
46
+ conflictSidecarSource: 'js-ts-semantic-merge',
47
+ ...options.metadata,
48
+ ...input.metadata
49
+ })
50
+ };
51
+ }
52
+
53
+ export function summarizeJsTsSemanticConflictSidecars(records = [], context = {}) {
54
+ const list = array(records).filter(Boolean);
55
+ const classes = uniqueStrings(list.map((record) => record.class));
56
+ const reasonCodes = uniqueStrings(list.flatMap((record) => record.reasonCodes ?? []));
57
+ const affectedSourcePaths = uniqueStrings([
58
+ context.sourcePath,
59
+ ...list.flatMap((record) => record.affected?.sourcePaths ?? [])
60
+ ]);
61
+ const affectedKeys = uniqueStrings(list.flatMap((record) => record.affected?.keys ?? []));
62
+ const readiness = list.reduce(
63
+ (current, record) => maxSemanticMergeReadiness(current, record.readiness ?? 'needs-review'),
64
+ normalizeSemanticMergeReadiness(context.readiness) ?? 'ready'
65
+ );
66
+ return {
67
+ schema: 'frontier.lang.jsTsSemanticConflictSidecarSummary.v1',
68
+ total: list.length,
69
+ classes,
70
+ byClass: countBy(classesFromRecords(list)),
71
+ bySeverity: countBy(list.map((record) => record.severity ?? 'warning')),
72
+ byRisk: countBy(list.map((record) => record.risk ?? 'medium')),
73
+ highestSeverity: highestSeverity(list),
74
+ highestRisk: highestRisk(list),
75
+ readiness,
76
+ affectedSourcePaths,
77
+ affectedKeys,
78
+ reasonCodes,
79
+ suggestedOutcome: summarySuggestedOutcome(list, readiness)
80
+ };
81
+ }
@@ -0,0 +1,128 @@
1
+ import { idFragment, normalizeSemanticMergeReadiness, uniqueStrings } from './native-import-utils.js';
2
+ import { JsTsSemanticMergeGateStatuses } from './js-ts-semantic-merge-contracts.js';
3
+ import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
4
+
5
+ export function normalizeConflictSides(sides = {}) {
6
+ return compactRecord({
7
+ base: normalizeConflictSide('base', sides.base),
8
+ left: normalizeConflictSide('left', sides.left),
9
+ right: normalizeConflictSide('right', sides.right)
10
+ });
11
+ }
12
+
13
+ function normalizeConflictSide(side, value) {
14
+ if (!value) return undefined;
15
+ return compactRecord({
16
+ side: firstString(value.side, side),
17
+ sourcePath: firstString(value.sourcePath),
18
+ sourceHash: firstString(value.sourceHash),
19
+ editIds: uniqueStrings(value.editIds),
20
+ regionIds: uniqueStrings(value.regionIds),
21
+ tokenIds: uniqueStrings(value.tokenIds),
22
+ summary: firstString(value.summary),
23
+ metadata: value.metadata
24
+ });
25
+ }
26
+
27
+ export function normalizeGateChecks(checks, fallbackStatus) {
28
+ return array(checks).filter(Boolean).map((check, index) => {
29
+ const status = normalizeGateStatus(check.status) ?? fallbackStatus;
30
+ const name = firstString(check.name, check.id, `check-${index + 1}`);
31
+ const reasonCodes = uniqueStrings([
32
+ ...strings(check.reasonCodes),
33
+ ...strings(check.reasons),
34
+ ...(status === 'passed' ? [] : [`js-ts-merge-check:${status}`])
35
+ ]);
36
+ const stablePayload = compactRecord({
37
+ name,
38
+ status,
39
+ readiness: normalizeSemanticMergeReadiness(check.readiness) ?? check.readiness,
40
+ reasonCodes,
41
+ evidenceIds: uniqueStrings(check.evidenceIds)
42
+ });
43
+ const hash = firstString(check.hash) || hashSemanticValue(stablePayload);
44
+ return compactRecord({
45
+ id: firstString(check.id) || `js_ts_merge_check_${idFragment(name)}_${idFragment(hash)}`,
46
+ name,
47
+ status,
48
+ readiness: stablePayload.readiness,
49
+ reasonCodes,
50
+ evidenceIds: stablePayload.evidenceIds,
51
+ hash,
52
+ metadata: check.metadata
53
+ });
54
+ });
55
+ }
56
+
57
+ export function readinessForRisk(risk) {
58
+ if (risk === 'high') return 'blocked';
59
+ if (risk === 'low') return 'ready-with-losses';
60
+ return 'needs-review';
61
+ }
62
+
63
+ export function readinessForGateStatus(status, checks, conflictExplanationIds) {
64
+ if (status === 'blocked' || status === 'failed') return 'blocked';
65
+ if (conflictExplanationIds.length > 0) return 'needs-review';
66
+ if (checks.some((check) => check.status === 'failed' || check.status === 'blocked')) return 'blocked';
67
+ if (status === 'warning' || checks.some((check) => check.status === 'warning')) return 'ready-with-losses';
68
+ if (status === 'passed') return 'ready';
69
+ return 'needs-review';
70
+ }
71
+
72
+ export function actionForConflict({ risk, readiness }) {
73
+ if (readiness === 'blocked' || risk === 'high') return 'block';
74
+ if (readiness === 'ready') return 'merge';
75
+ return 'manual-review';
76
+ }
77
+
78
+ export function actionForGate({ status, readiness, mergeable }) {
79
+ if (mergeable) return 'merge';
80
+ if (status === 'blocked' || status === 'failed' || readiness === 'blocked') return 'block';
81
+ if (status === 'skipped') return 'skip';
82
+ return 'review';
83
+ }
84
+
85
+ export function titleForConflictClass(conflictClass) {
86
+ return String(conflictClass).split(/[-_]+/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
87
+ }
88
+
89
+ export function normalizeRisk(value) {
90
+ const risk = String(value ?? '').toLowerCase();
91
+ return risk === 'low' || risk === 'medium' || risk === 'high' ? risk : undefined;
92
+ }
93
+
94
+ export function normalizeGateStatus(value) {
95
+ const status = String(value ?? '').toLowerCase();
96
+ return JsTsSemanticMergeGateStatuses.includes(status) ? status : undefined;
97
+ }
98
+
99
+ export function booleanValue(...values) {
100
+ for (const value of values) {
101
+ if (typeof value === 'boolean') return value;
102
+ }
103
+ return undefined;
104
+ }
105
+
106
+ export function numberValue(...values) {
107
+ for (const value of values) {
108
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
109
+ }
110
+ return undefined;
111
+ }
112
+
113
+ export function array(value) {
114
+ if (value === undefined || value === null) return [];
115
+ return Array.isArray(value) ? value : [value];
116
+ }
117
+
118
+ export function strings(value) {
119
+ return array(value).map((entry) => entry === undefined || entry === null ? '' : String(entry)).filter(Boolean);
120
+ }
121
+
122
+ export function firstString(...values) {
123
+ return values.map((value) => value === undefined || value === null ? '' : String(value)).find(Boolean);
124
+ }
125
+
126
+ export function compactRecord(value) {
127
+ return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined));
128
+ }