@shapeshift-labs/frontier-lang-compiler 0.2.77 → 0.2.78

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 CHANGED
@@ -422,6 +422,22 @@ console.log(targetChange.metadata.semanticEquivalenceClaim); // false
422
422
 
423
423
  Bidirectional target-change records are merge-admission evidence, not transpiler proof. They keep target diffs, source anchor matches, optional lineage resolutions, source patch-bundle records, semantic history records, evidence IDs, readiness, and reason codes. They always keep `autoMergeClaim: false` and `semanticEquivalenceClaim: false`; unmatched or deleted anchors block the source-port route, while matched and ambiguous anchors still require human or verifier review.
424
424
 
425
+ When the target source came from a Frontier/native projection, pass the generated-output `sourceMaps` back into `createBidirectionalTargetChangeRecord`. The record will match target changed regions by generated span or generated name, emit `sourceMapLinks`, include `sourceMapBackedMatches` in the summary/evidence, and carry source-map mapping IDs into the source patch bundle index:
426
+
427
+ ```js
428
+ const sourceMapBacked = createBidirectionalTargetChangeRecord({
429
+ source,
430
+ targetLanguage: 'rust',
431
+ targetPath: 'src/counter.rs',
432
+ baseTarget,
433
+ editedTarget,
434
+ sourceMaps: [projection.sourceMap]
435
+ });
436
+
437
+ console.log(sourceMapBacked.summary.sourceMapBackedMatches);
438
+ console.log(sourceMapBacked.sourcePatchBundle.index.sourceMapMappingIds);
439
+ ```
440
+
425
441
  Store worker outputs as compact semantic history records when a coordinator needs to compare distributed changes without merging whole files:
426
442
 
427
443
  ```js
package/bench/smoke.mjs CHANGED
@@ -116,6 +116,7 @@ console.log(JSON.stringify({
116
116
  semanticLineageInferenceDurationMs: Number(sourceChangeMetrics.semanticLineageInferenceDurationMs.toFixed(2)),
117
117
  bidirectionalTargetChanges: sourceChangeMetrics.bidirectionalTargetChanges,
118
118
  bidirectionalTargetChangeMatches: sourceChangeMetrics.bidirectionalTargetChangeMatches,
119
+ bidirectionalTargetChangeSourceMapBacked: sourceChangeMetrics.bidirectionalTargetChangeSourceMapBacked,
119
120
  bidirectionalTargetChangeBlocked: sourceChangeMetrics.bidirectionalTargetChangeBlocked,
120
121
  bidirectionalTargetChangeDurationMs: Number(sourceChangeMetrics.bidirectionalTargetChangeDurationMs.toFixed(2)),
121
122
  externalSemanticImports: sourceChangeMetrics.externalSemanticImports,
@@ -112,6 +112,8 @@ function measureBidirectionalTargetChanges() {
112
112
  sourcePath: 'src/bidirectional-source.ts',
113
113
  sourceText: 'export function advance(frame: number): number { return frame + 1; }\n'
114
114
  });
115
+ const sourceSymbol = source.semanticIndex.symbols.find((symbol) => symbol.name === 'advance');
116
+ const sourceMapping = source.sourceMaps[0].mappings.find((mapping) => mapping.semanticSymbolId === sourceSymbol.id);
115
117
  const lineage = [createSemanticLineageEvent({
116
118
  eventKind: 'moved',
117
119
  from: { key: 'source#src/bidirectional-source.ts#body#advance', symbolName: 'advance' },
@@ -134,18 +136,45 @@ function measureBidirectionalTargetChanges() {
134
136
  sourcePath: `src/bidirectional-${index}.rs`,
135
137
  sourceText: `pub fn advance(frame: i32, delta: i32) -> i32 { frame + delta + ${index} }\n`
136
138
  },
137
- sourceAnchorMappings: [{ targetSymbolName: 'advance', sourceSymbolName: 'advance' }],
139
+ ...(index % 2 === 0
140
+ ? { sourceMaps: [rustSourceMap(source, sourceSymbol, sourceMapping, index)] }
141
+ : { sourceAnchorMappings: [{ targetSymbolName: 'advance', sourceSymbolName: 'advance' }] }),
138
142
  lineage: index % 4 === 0 ? lineage : []
139
143
  }));
140
144
  }
141
145
  return {
142
146
  bidirectionalTargetChanges: records.length,
143
147
  bidirectionalTargetChangeMatches: records.reduce((sum, record) => sum + record.summary.sourceAnchorMatches, 0),
148
+ bidirectionalTargetChangeSourceMapBacked: records.reduce((sum, record) => sum + record.summary.sourceMapBackedMatches, 0),
144
149
  bidirectionalTargetChangeBlocked: records.filter((record) => record.readiness === 'blocked').length,
145
150
  bidirectionalTargetChangeDurationMs: performance.now() - start
146
151
  };
147
152
  }
148
153
 
154
+ function rustSourceMap(source, sourceSymbol, sourceMapping, index) {
155
+ const targetPath = `src/bidirectional-${index}.rs`;
156
+ return {
157
+ kind: 'frontier.lang.sourceMap',
158
+ version: 1,
159
+ id: `bench_source_map_bidirectional_${index}`,
160
+ sourcePath: source.sourcePath,
161
+ sourceHash: source.nativeSource.sourceHash,
162
+ target: 'rust',
163
+ targetPath,
164
+ mappings: [{
165
+ id: `bench_map_advance_${index}`,
166
+ semanticSymbolId: sourceSymbol.id,
167
+ nativeAstNodeId: sourceSymbol.nativeAstNodeId,
168
+ sourceSpan: sourceMapping.sourceSpan,
169
+ generatedSpan: { path: targetPath, target: 'rust', targetPath, startLine: 1, startColumn: 1, endLine: 1, endColumn: 80, generatedName: 'advance' },
170
+ target: 'rust',
171
+ generatedName: 'advance',
172
+ precision: 'declaration',
173
+ preservation: 'declaration'
174
+ }]
175
+ };
176
+ }
177
+
149
178
  function measureExternalSemanticImports() {
150
179
  const externalSemanticStart = performance.now();
151
180
  const externalSemanticImports = [];
@@ -2,6 +2,8 @@ import type {
2
2
  EvidenceRecord,
3
3
  FrontierSourceLanguage,
4
4
  SemanticMergeReadiness,
5
+ SourceMapMappingRecord,
6
+ SourceMapRecord,
5
7
  SourceSpan
6
8
  } from '@shapeshift-labs/frontier-lang-kernel';
7
9
  import type { ImportNativeSourceOptions, NativeSourceImportResult } from './import-adapter-core.js';
@@ -27,6 +29,26 @@ export interface BidirectionalTargetChangeSourceAnchorMapping {
27
29
  readonly sourceSymbolId?: string;
28
30
  }
29
31
 
32
+ export interface BidirectionalTargetChangeSourceMapLink {
33
+ readonly id: string;
34
+ readonly sourceMapId?: string;
35
+ readonly sourceMapMappingId?: string;
36
+ readonly sourcePath?: string;
37
+ readonly sourceHash?: string;
38
+ readonly targetPath?: string;
39
+ readonly targetHash?: string;
40
+ readonly semanticSymbolId?: string;
41
+ readonly semanticOccurrenceId?: string;
42
+ readonly semanticNodeId?: string;
43
+ readonly nativeSourceId?: string;
44
+ readonly nativeAstNodeId?: string;
45
+ readonly precision?: string;
46
+ readonly sourceSpan?: SourceSpan;
47
+ readonly generatedSpan?: SourceMapMappingRecord['generatedSpan'];
48
+ readonly regionKey?: string;
49
+ readonly regionKind?: string;
50
+ }
51
+
30
52
  export interface BidirectionalTargetChangeAnchor {
31
53
  readonly id?: string;
32
54
  readonly key?: string;
@@ -47,6 +69,7 @@ export interface BidirectionalTargetChangeSourceAnchorMatch {
47
69
  readonly targetRegion: Partial<NativeSourceChangeRegion>;
48
70
  readonly sourceAnchors: readonly BidirectionalTargetChangeAnchor[];
49
71
  readonly lineageResolutions: readonly SemanticLineageResolution[];
72
+ readonly sourceMapLinks: readonly BidirectionalTargetChangeSourceMapLink[];
50
73
  readonly status: BidirectionalTargetChangeAnchorStatus;
51
74
  readonly confidence?: number;
52
75
  readonly reasonCodes: readonly string[];
@@ -77,6 +100,11 @@ export interface CreateBidirectionalTargetChangeRecordOptions {
77
100
  readonly after?: NativeSourceImportResult | ImportNativeSourceOptions;
78
101
  readonly sourceAnchorMappings?: readonly BidirectionalTargetChangeSourceAnchorMapping[];
79
102
  readonly anchorMappings?: readonly BidirectionalTargetChangeSourceAnchorMapping[];
103
+ readonly sourceMaps?: readonly SourceMapRecord[];
104
+ readonly projectionSourceMaps?: readonly SourceMapRecord[];
105
+ readonly targetSourceMaps?: readonly SourceMapRecord[];
106
+ readonly targetProjectionSourceMaps?: readonly SourceMapRecord[];
107
+ readonly targetCompileResult?: { readonly sourceMaps?: readonly SourceMapRecord[]; readonly sourceMap?: SourceMapRecord };
80
108
  readonly lineage?: readonly SemanticLineageEvent[];
81
109
  readonly lineageEvents?: readonly SemanticLineageEvent[];
82
110
  readonly lineageMap?: unknown;
@@ -114,6 +142,7 @@ export interface BidirectionalTargetChangeRecord {
114
142
  readonly unmatchedTargetRegions: number;
115
143
  readonly deletedSourceAnchors: number;
116
144
  readonly sourceChangedRegions: number;
145
+ readonly sourceMapBackedMatches: number;
117
146
  };
118
147
  readonly metadata: {
119
148
  readonly autoMergeClaim: false;
@@ -8,13 +8,14 @@ import { resolveSemanticLineage } from './semanticLineageResolutionRecords.js';
8
8
 
9
9
  export function matchTargetRegion(context) {
10
10
  const explicit = explicitMappingForRegion(context.region, context.mappings);
11
- const candidateAnchors = explicit
12
- ? sourceAnchorsForMapping(explicit, context.sourceAnchors)
13
- : sourceAnchorsByName(context.region, context.sourceAnchors);
11
+ const mapped = explicit ? { anchors: sourceAnchorsForMapping(explicit, context.sourceAnchors), links: [] }
12
+ : sourceMapAnchorsForRegion(context.region, context.sourceMaps, context.sourceAnchors);
13
+ const candidateAnchors = mapped.anchors.length ? mapped.anchors : sourceAnchorsByName(context.region, context.sourceAnchors);
14
14
  const resolvedAnchors = candidateAnchors.flatMap((anchor) => resolveAnchor(anchor, context.lineage));
15
15
  const status = matchStatus(candidateAnchors, resolvedAnchors);
16
16
  const reasonCodes = uniqueStrings([
17
- explicit ? 'explicit-anchor-mapping' : 'inferred-by-symbol-name',
17
+ explicit ? 'explicit-anchor-mapping' : mapped.links.length ? 'source-map-generated-anchor' : 'inferred-by-symbol-name',
18
+ mapped.links.length ? 'mapped-by-generated-source-map' : undefined,
18
19
  status === 'unmatched' ? 'source-anchor-not-found' : undefined,
19
20
  status === 'ambiguous' ? 'source-anchor-ambiguous' : undefined,
20
21
  status === 'deleted' ? 'source-anchor-deleted' : undefined,
@@ -27,8 +28,9 @@ export function matchTargetRegion(context) {
27
28
  targetRegion: compactRegion(context.region),
28
29
  sourceAnchors: resolvedAnchors.map((entry) => entry.anchor),
29
30
  lineageResolutions: uniqueRecordsById(resolvedAnchors.map((entry) => entry.resolution).filter(Boolean)),
31
+ sourceMapLinks: mapped.links,
30
32
  status,
31
- confidence: status === 'matched' && explicit ? 0.8 : status === 'matched' ? 0.58 : undefined,
33
+ confidence: status === 'matched' && explicit ? 0.8 : status === 'matched' && mapped.links.length ? 0.72 : status === 'matched' ? 0.58 : undefined,
32
34
  reasonCodes,
33
35
  reviewRequired: true,
34
36
  autoMergeClaim: false,
@@ -37,6 +39,7 @@ export function matchTargetRegion(context) {
37
39
  context.region.conflictKey,
38
40
  context.region.key,
39
41
  ...resolvedAnchors.map((entry) => entry.anchor?.key),
42
+ ...mapped.links.map((link) => link.sourceMapMappingId && `source-map:${link.sourceMapMappingId}`),
40
43
  status === 'unmatched' ? `target:${context.region.sourcePath ?? context.region.language ?? 'unknown'}` : undefined
41
44
  ])
42
45
  };
@@ -65,6 +68,7 @@ export function sourceRegionsForMatch(match, readiness) {
65
68
  symbolId: anchor?.symbolId,
66
69
  symbolName: anchor?.symbolName,
67
70
  sourceSpan: anchor?.sourceSpan,
71
+ sourceMapLinks: match.sourceMapLinks,
68
72
  admission: {
69
73
  readiness,
70
74
  action: 'review-port-from-target-change',
@@ -75,6 +79,7 @@ export function sourceRegionsForMatch(match, readiness) {
75
79
  bidirectionalTargetChange: {
76
80
  matchId: match.id,
77
81
  targetRegion: match.targetRegion,
82
+ sourceMapLinkIds: match.sourceMapLinks.map((link) => link.id),
78
83
  lineageResolutionIds: match.lineageResolutions.map((resolution) => resolution.id),
79
84
  reviewRequired: true,
80
85
  autoMergeClaim: false,
@@ -97,6 +102,8 @@ export function createBidirectionalEvidence(context) {
97
102
  targetChangeSetId: context.targetChangeSet.id,
98
103
  targetPatchId: context.targetChangeSet.patch?.id,
99
104
  sourceAnchorMatchIds: context.sourceAnchorMatches.map((match) => match.id),
105
+ sourceMapBackedMatches: context.sourceAnchorMatches.filter((match) => match.sourceMapLinks.length > 0).length,
106
+ sourceMapLinkIds: context.sourceAnchorMatches.flatMap((match) => match.sourceMapLinks.map((link) => link.id)),
100
107
  readiness: context.readiness,
101
108
  reasons: context.reasons,
102
109
  autoMergeClaim: false,
@@ -105,6 +112,77 @@ export function createBidirectionalEvidence(context) {
105
112
  };
106
113
  }
107
114
 
115
+ function sourceMapAnchorsForRegion(region, sourceMaps, sourceAnchors) {
116
+ const links = [];
117
+ const anchors = [];
118
+ for (const sourceMap of sourceMaps ?? []) {
119
+ for (const mapping of sourceMap?.mappings ?? []) {
120
+ if (!mappingMatchesTargetRegion(mapping, sourceMap, region)) continue;
121
+ const link = sourceMapLinkForMapping(sourceMap, mapping);
122
+ links.push(link);
123
+ anchors.push(...anchorsForSourceMapMapping(mapping, link, sourceAnchors));
124
+ }
125
+ }
126
+ return { anchors: uniqueRecordsById(anchors), links: uniqueRecordsById(links) };
127
+ }
128
+
129
+ function anchorsForSourceMapMapping(mapping, link, sourceAnchors) {
130
+ const matches = sourceAnchors.filter((anchor) =>
131
+ (mapping.semanticSymbolId && anchor.symbolId === mapping.semanticSymbolId)
132
+ || (mapping.semanticNodeId && anchor.id === mapping.semanticNodeId)
133
+ || (mapping.nativeAstNodeId && anchor.metadata?.nativeAstNodeId === mapping.nativeAstNodeId)
134
+ || (mapping.ownershipRegionKey && anchor.key === mapping.ownershipRegionKey)
135
+ );
136
+ if (matches.length) return matches;
137
+ return [compactRecord({
138
+ id: mapping.semanticSymbolId ?? mapping.semanticNodeId ?? mapping.nativeAstNodeId ?? link.id,
139
+ key: mapping.ownershipRegionKey ?? mapping.semanticSymbolId ?? mapping.semanticNodeId ?? link.id,
140
+ kind: mapping.ownershipRegionKind ?? 'source-map',
141
+ language: link.sourceSpan?.language,
142
+ sourcePath: link.sourcePath,
143
+ sourceHash: link.sourceHash,
144
+ symbolId: mapping.semanticSymbolId,
145
+ symbolName: mapping.generatedName ?? mapping.generatedSpan?.generatedName,
146
+ sourceSpan: mapping.sourceSpan,
147
+ metadata: { sourceMapId: link.sourceMapId, sourceMapMappingId: link.sourceMapMappingId }
148
+ })];
149
+ }
150
+
151
+ function mappingMatchesTargetRegion(mapping, sourceMap, region) {
152
+ if (!targetPathMatches(mapping, sourceMap, region)) return false;
153
+ if (mapping.generatedName && namesForRegion(region).includes(mapping.generatedName)) return true;
154
+ if (mapping.generatedSpan?.generatedName && namesForRegion(region).includes(mapping.generatedSpan.generatedName)) return true;
155
+ return spansOverlap(mapping.generatedSpan, region.sourceSpan);
156
+ }
157
+
158
+ function targetPathMatches(mapping, sourceMap, region) {
159
+ const targetPaths = uniqueStrings([mapping.generatedSpan?.targetPath, mapping.generatedSpan?.path, sourceMap?.targetPath]);
160
+ const regionPath = region.sourcePath ?? region.sourceSpan?.path;
161
+ return !regionPath || targetPaths.length === 0 || targetPaths.includes(regionPath);
162
+ }
163
+
164
+ function sourceMapLinkForMapping(sourceMap, mapping) {
165
+ return compactRecord({
166
+ id: `source_map_link_${idFragment(sourceMap?.id ?? 'map')}_${idFragment(mapping.id ?? mapping.semanticSymbolId ?? 'mapping')}`,
167
+ sourceMapId: sourceMap?.id,
168
+ sourceMapMappingId: mapping.id,
169
+ sourcePath: mapping.sourceSpan?.path ?? sourceMap?.sourcePath,
170
+ sourceHash: mapping.sourceSpan?.sourceId ?? sourceMap?.sourceHash,
171
+ targetPath: mapping.generatedSpan?.targetPath ?? sourceMap?.targetPath,
172
+ targetHash: mapping.generatedSpan?.targetHash ?? sourceMap?.targetHash,
173
+ semanticSymbolId: mapping.semanticSymbolId,
174
+ semanticOccurrenceId: mapping.semanticOccurrenceId,
175
+ semanticNodeId: mapping.semanticNodeId,
176
+ nativeSourceId: mapping.nativeSourceId,
177
+ nativeAstNodeId: mapping.nativeAstNodeId,
178
+ precision: mapping.precision,
179
+ sourceSpan: mapping.sourceSpan,
180
+ generatedSpan: mapping.generatedSpan,
181
+ regionKey: mapping.ownershipRegionKey,
182
+ regionKind: mapping.ownershipRegionKind
183
+ });
184
+ }
185
+
108
186
  export function anchorsFromSourceSidecar(sidecar, source) {
109
187
  return uniqueRecordsById((sidecar.ownershipRegions ?? []).map((region) => compactRecord({
110
188
  id: region.id,
@@ -148,11 +226,15 @@ function sourceAnchorsForMapping(mapping, sourceAnchors) {
148
226
  }
149
227
 
150
228
  function sourceAnchorsByName(region, sourceAnchors) {
151
- const names = uniqueStrings([region.symbolName, region.name, region.metadata?.changedRegionProjection?.region?.symbolName]);
229
+ const names = namesForRegion(region);
152
230
  if (names.length === 0) return [];
153
231
  return sourceAnchors.filter((anchor) => names.includes(anchor.symbolName));
154
232
  }
155
233
 
234
+ function namesForRegion(region) {
235
+ return uniqueStrings([region.symbolName, region.name, region.metadata?.changedRegionProjection?.region?.symbolName]);
236
+ }
237
+
156
238
  function resolveAnchor(anchor, lineage) {
157
239
  if (!anchor) return [];
158
240
  const resolution = array(lineage).length ? resolveSemanticLineage(lineage, { anchorKey: anchor.key }) : undefined;
@@ -189,6 +271,23 @@ function compactRegion(region) {
189
271
  });
190
272
  }
191
273
 
274
+ function spansOverlap(left, right) {
275
+ if (!left || !right) return false;
276
+ if (!sourcePathsCompatible(left, right)) return false;
277
+ const leftStart = Number(left.startLine ?? 0);
278
+ const leftEnd = Number(left.endLine ?? left.startLine ?? 0);
279
+ const rightStart = Number(right.startLine ?? 0);
280
+ const rightEnd = Number(right.endLine ?? right.startLine ?? 0);
281
+ if (!leftStart || !rightStart) return false;
282
+ return leftStart <= rightEnd && rightStart <= leftEnd;
283
+ }
284
+
285
+ function sourcePathsCompatible(left, right) {
286
+ const leftPath = left.targetPath ?? left.path;
287
+ const rightPath = right.targetPath ?? right.path;
288
+ return !leftPath || !rightPath || leftPath === rightPath;
289
+ }
290
+
192
291
  function array(value) {
193
292
  return value === undefined || value === null ? [] : Array.isArray(value) ? value : [value];
194
293
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  idFragment,
3
+ uniqueRecordsById,
3
4
  uniqueStrings
4
5
  } from '../../native-import-utils.js';
5
6
  import { createSemanticImportSidecar } from './createSemanticImportSidecar.js';
@@ -45,6 +46,14 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
45
46
  }) : undefined;
46
47
  const sourceAnchors = sourceSidecar ? anchorsFromSourceSidecar(sourceSidecar, source) : [];
47
48
  const mappings = array(input.sourceAnchorMappings ?? input.anchorMappings);
49
+ const sourceMaps = uniqueRecordsById([
50
+ ...array(input.sourceMaps),
51
+ ...array(input.projectionSourceMaps),
52
+ ...array(input.targetSourceMaps),
53
+ ...array(input.targetProjectionSourceMaps),
54
+ ...array(input.targetCompileResult?.sourceMaps),
55
+ input.targetCompileResult?.sourceMap
56
+ ]);
48
57
  const lineage = input.lineage ?? input.lineageEvents ?? input.lineageMap ?? [];
49
58
  const sourceAnchorMatches = targetChangeSet.changedRegions.map((region, index) => matchTargetRegion({
50
59
  id,
@@ -53,6 +62,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
53
62
  source,
54
63
  sourceAnchors,
55
64
  mappings,
65
+ sourceMaps,
56
66
  lineage
57
67
  }));
58
68
  const readiness = classifyBidirectionalReadiness(targetChangeSet, source, sourceAnchorMatches);
@@ -86,7 +96,8 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
86
96
  projectionOnly: true,
87
97
  targetChangeSetId: targetChangeSet.id,
88
98
  targetPatchId: targetChangeSet.patch?.id,
89
- targetMergeCandidateId: targetChangeSet.mergeCandidate?.id
99
+ targetMergeCandidateId: targetChangeSet.mergeCandidate?.id,
100
+ sourceMapBackprojection: summarizeSourceMapBackprojection(sourceAnchorMatches)
90
101
  }
91
102
  }, {
92
103
  id: input.sourcePatchBundleId ?? `semantic_patch_bundle_${idFragment(id)}_source_port`,
@@ -127,6 +138,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
127
138
  bidirectionalTargetChangeId: id,
128
139
  sourcePatchBundleId: sourcePatchBundle.id,
129
140
  targetChangeSetId: targetChangeSet.id,
141
+ sourceMapBackprojection: summarizeSourceMapBackprojection(sourceAnchorMatches),
130
142
  autoMergeClaim: false,
131
143
  semanticEquivalenceClaim: false
132
144
  }
@@ -153,7 +165,8 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
153
165
  ambiguousMatches: sourceAnchorMatches.filter((match) => match.status === 'ambiguous').length,
154
166
  unmatchedTargetRegions: sourceAnchorMatches.filter((match) => match.status === 'unmatched').length,
155
167
  deletedSourceAnchors: sourceAnchorMatches.filter((match) => match.status === 'deleted').length,
156
- sourceChangedRegions: sourceChangedRegions.length
168
+ sourceChangedRegions: sourceChangedRegions.length,
169
+ sourceMapBackedMatches: sourceAnchorMatches.filter((match) => match.sourceMapLinks.length > 0).length
157
170
  },
158
171
  metadata: {
159
172
  autoMergeClaim: false,
@@ -164,6 +177,16 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
164
177
  };
165
178
  }
166
179
 
180
+ function summarizeSourceMapBackprojection(matches) {
181
+ const links = matches.flatMap((match) => match.sourceMapLinks ?? []);
182
+ return {
183
+ sourceMapBackedMatches: matches.filter((match) => (match.sourceMapLinks ?? []).length > 0).length,
184
+ sourceMapLinks: links.length,
185
+ sourceMapIds: uniqueStrings(links.map((link) => link.sourceMapId)),
186
+ sourceMapMappingIds: uniqueStrings(links.map((link) => link.sourceMapMappingId))
187
+ };
188
+ }
189
+
167
190
  function array(value) {
168
191
  return value === undefined || value === null ? [] : Array.isArray(value) ? value : [value];
169
192
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.77",
3
+ "version": "0.2.78",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",