@shapeshift-labs/frontier-lang-compiler 0.2.6 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -14,6 +14,8 @@ import type {
14
14
  SemanticIndexRecord,
15
15
  SemanticNode,
16
16
  SemanticPatchBundle,
17
+ SourceMapMappingRecord,
18
+ SourceMapRecord,
17
19
  SourceSpan
18
20
  } from '@shapeshift-labs/frontier-lang-kernel';
19
21
  import type { Diagnostic } from '@shapeshift-labs/frontier-lang-checker';
@@ -104,7 +106,7 @@ export interface ImportNativeSourceOptions {
104
106
  readonly nodes?: Readonly<Record<string, NativeAstNode>>;
105
107
  readonly semanticNodes?: readonly SemanticNode[];
106
108
  readonly frontierNodeIds?: readonly string[];
107
- readonly mappings?: readonly unknown[];
109
+ readonly mappings?: readonly SourceMapMappingRecord[];
108
110
  readonly semanticStatus?: 'native-only' | 'mapped' | 'partial' | string;
109
111
  readonly losses?: readonly NativeAstLossRecord[];
110
112
  readonly evidence?: readonly EvidenceRecord[];
@@ -114,6 +116,8 @@ export interface ImportNativeSourceOptions {
114
116
  readonly author?: string;
115
117
  readonly target?: CompileTarget;
116
118
  readonly semanticIndex?: SemanticIndexRecord;
119
+ readonly sourceMapId?: string;
120
+ readonly sourceMaps?: readonly SourceMapRecord[];
117
121
  readonly universalAstId?: string;
118
122
  readonly universalAstMetadata?: Record<string, unknown>;
119
123
  readonly metadata?: Record<string, unknown>;
@@ -189,6 +193,7 @@ export declare function importNativeSource(input: ImportNativeSourceOptions): Na
189
193
  export declare function createUniversalAstFromDocument(document: FrontierLangDocument, input?: {
190
194
  readonly id?: string;
191
195
  readonly semanticIndex?: SemanticIndexRecord;
196
+ readonly sourceMaps?: readonly SourceMapRecord[];
192
197
  readonly evidence?: readonly EvidenceRecord[];
193
198
  readonly metadata?: Record<string, unknown>;
194
199
  }): FrontierUniversalAstEnvelope;
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  createNativeAstRecord,
5
5
  createPatch,
6
6
  createSemanticIndexRecord,
7
+ createSourceMapRecord,
7
8
  createUniversalAstEnvelope,
8
9
  hashDocumentBase,
9
10
  hashSemanticValue,
@@ -339,11 +340,48 @@ export function importNativeSource(input) {
339
340
  }
340
341
  }];
341
342
  const semanticIndex = input.semanticIndex ?? lightweight?.semanticIndex;
343
+ const sourceMapMappings = normalizeSourceMapMappings(
344
+ input.mappings ?? lightweight?.mappings ?? inferSourceMapMappings({
345
+ semanticIndex,
346
+ nativeAst,
347
+ nativeSource,
348
+ evidence
349
+ }),
350
+ {
351
+ semanticIndex,
352
+ nativeAst,
353
+ nativeSource,
354
+ evidence,
355
+ losses,
356
+ target: input.target
357
+ }
358
+ );
359
+ const inferredSourceMaps = sourceMapMappings.length
360
+ ? [createSourceMapRecord({
361
+ id: input.sourceMapId ?? `source_map_${importIdPart}`,
362
+ sourcePath,
363
+ sourceHash,
364
+ target: input.target,
365
+ targetPath: input.target?.emitPath,
366
+ semanticIndexId: semanticIndex?.id,
367
+ nativeAstId: nativeAst.id,
368
+ nativeSourceId: nativeSource.id,
369
+ mappings: sourceMapMappings,
370
+ evidence,
371
+ metadata: {
372
+ sourceLanguage: language,
373
+ parser: nativeAst.parser,
374
+ semanticStatus: input.semanticStatus ?? (semanticNodes.length ? 'mapped' : 'native-only')
375
+ }
376
+ })]
377
+ : [];
378
+ const sourceMaps = input.sourceMaps ?? inferredSourceMaps;
342
379
  const universalAst = createUniversalAstEnvelope({
343
380
  id: input.universalAstId ?? `universal_ast_${importIdPart}`,
344
381
  document,
345
382
  nativeSources: [nativeSource],
346
383
  semanticIndex,
384
+ sourceMaps,
347
385
  losses,
348
386
  evidence,
349
387
  metadata: {
@@ -363,7 +401,13 @@ export function importNativeSource(input) {
363
401
  touches: [{ id: node.id, access: node.kind === 'nativeSource' ? 'evidence' : 'schema' }]
364
402
  })),
365
403
  evidence,
366
- metadata: { sourceLanguage: language, sourcePath, semanticIndexId: semanticIndex?.id, universalAstId: universalAst.id }
404
+ metadata: {
405
+ sourceLanguage: language,
406
+ sourcePath,
407
+ semanticIndexId: semanticIndex?.id,
408
+ universalAstId: universalAst.id,
409
+ sourceMapIds: sourceMaps.map((sourceMap) => sourceMap.id)
410
+ }
367
411
  });
368
412
  return {
369
413
  ...createImportResult({
@@ -375,14 +419,16 @@ export function importNativeSource(input) {
375
419
  nativeAst,
376
420
  semanticIndex,
377
421
  universalAst,
422
+ sourceMaps,
378
423
  losses,
379
424
  evidence,
380
425
  metadata: {
381
426
  nativeSourceId: nativeSource.id,
382
427
  semanticIndexId: semanticIndex?.id,
383
428
  universalAstId: universalAst.id,
429
+ sourceMapIds: sourceMaps.map((sourceMap) => sourceMap.id),
384
430
  semanticStatus: input.semanticStatus ?? (semanticNodes.length ? 'mapped' : 'native-only'),
385
- mappings: input.mappings ?? [],
431
+ mappings: sourceMapMappings,
386
432
  ...input.metadata
387
433
  }
388
434
  }),
@@ -409,6 +455,8 @@ function createLightweightNativeImport(input) {
409
455
  const occurrences = [];
410
456
  const relations = [];
411
457
  const facts = [];
458
+ const mappings = [];
459
+ const evidenceId = `evidence_${idFragment(input.sourcePath ?? input.language)}_lightweight_scan`;
412
460
 
413
461
  for (const declaration of declarations) {
414
462
  nodes[rootId].children.push(declaration.nodeId);
@@ -422,6 +470,7 @@ function createLightweightNativeImport(input) {
422
470
  metadata: declaration.metadata
423
471
  };
424
472
  if (declaration.symbolId) {
473
+ const occurrenceId = `occ_${idFragment(declaration.nodeId)}_def`;
425
474
  symbols.push({
426
475
  id: declaration.symbolId,
427
476
  scheme: 'frontier',
@@ -433,7 +482,7 @@ function createLightweightNativeImport(input) {
433
482
  definitionSpan: declaration.span
434
483
  });
435
484
  occurrences.push({
436
- id: `occ_${idFragment(declaration.nodeId)}_def`,
485
+ id: occurrenceId,
437
486
  documentId,
438
487
  symbolId: declaration.symbolId,
439
488
  role: declaration.role ?? 'definition',
@@ -452,9 +501,20 @@ function createLightweightNativeImport(input) {
452
501
  subjectId: declaration.symbolId,
453
502
  value: declaration.languageKind
454
503
  });
504
+ mappings.push({
505
+ id: `map_${idFragment(declaration.nodeId)}`,
506
+ nativeAstNodeId: declaration.nodeId,
507
+ semanticSymbolId: declaration.symbolId,
508
+ semanticOccurrenceId: occurrenceId,
509
+ sourceSpan: declaration.span,
510
+ evidenceIds: [evidenceId],
511
+ lossIds: declaration.loss ? [declaration.loss.id] : [],
512
+ precision: 'declaration'
513
+ });
455
514
  }
456
515
  if (declaration.loss) losses.push(declaration.loss);
457
516
  }
517
+ losses.push(...lightweightCoverageLosses(input, declarations));
458
518
 
459
519
  const semanticIndex = createSemanticIndexRecord({
460
520
  id: `index_${idFragment(input.sourcePath ?? input.language)}`,
@@ -469,7 +529,7 @@ function createLightweightNativeImport(input) {
469
529
  relations,
470
530
  facts,
471
531
  evidence: [{
472
- id: `evidence_${idFragment(input.sourcePath ?? input.language)}_lightweight_scan`,
532
+ id: evidenceId,
473
533
  kind: 'import',
474
534
  status: 'passed',
475
535
  path: input.sourcePath,
@@ -489,6 +549,7 @@ function createLightweightNativeImport(input) {
489
549
  nodes,
490
550
  losses,
491
551
  semanticIndex,
552
+ mappings,
492
553
  metadata: { parser, scanKind: 'lightweight-declaration-scan', declarationCount: declarations.length }
493
554
  };
494
555
  }
@@ -499,6 +560,12 @@ function scanNativeDeclarations(input) {
499
560
  if (language === 'python') return scanPython(input);
500
561
  if (language === 'rust') return scanRust(input);
501
562
  if (language === 'c' || language === 'cpp' || language === 'c++') return scanCLike(input);
563
+ if (language === 'java') return scanJava(input);
564
+ if (language === 'go') return scanGo(input);
565
+ if (language === 'swift') return scanSwift(input);
566
+ if (language === 'csharp' || language === 'c#') return scanCSharp(input);
567
+ if (language === 'php') return scanPhp(input);
568
+ if (language === 'ruby' || language === 'rb') return scanRuby(input);
502
569
  return scanGenericDeclarations(input);
503
570
  }
504
571
 
@@ -588,12 +655,155 @@ function scanCLike(input) {
588
655
  return declarations;
589
656
  }
590
657
 
658
+ function scanJava(input) {
659
+ const declarations = [];
660
+ for (const { line, number } of sourceLines(input.sourceText)) {
661
+ const trimmed = line.trim();
662
+ let match;
663
+ if ((match = trimmed.match(/^package\s+([A-Za-z_][\w.]*);/))) {
664
+ declarations.push(nativeDeclaration(input, number, 'PackageDeclaration', 'package', match[1], {}, false));
665
+ } else if ((match = trimmed.match(/^import\s+(?:static\s+)?([A-Za-z_][\w.*]*);/))) {
666
+ declarations.push(nativeImportDeclaration(input, number, match[1], 'ImportDeclaration', 'package'));
667
+ } else if ((match = trimmed.match(/^(?:(?:public|protected|private|abstract|final|static|sealed|non-sealed)\s+)*(class|interface|enum|record|@interface)\s+([A-Za-z_$][\w$]*)/))) {
668
+ const kind = match[1] === '@interface' ? 'AnnotationDeclaration' : `${upperFirst(match[1])}Declaration`;
669
+ declarations.push(nativeDeclaration(input, number, kind, javaSymbolKind(match[1]), match[2], {}, trimmed.includes('{')));
670
+ } else if ((match = trimmed.match(/^(?:(?:public|protected|private|abstract|final|static|synchronized|native)\s+)*(?:<[^>]+>\s+)?[A-Za-z_$][\w$<>\[\].?,\s]*\s+([A-Za-z_$][\w$]*)\s*\(([^)]*)\)\s*(?:throws\s+[^{]+)?(?:\{|;)?$/))) {
671
+ declarations.push(nativeDeclaration(input, number, 'MethodDeclaration', 'method', match[1], { parameters: splitParameters(match[2]) }, trimmed.includes('{')));
672
+ }
673
+ }
674
+ return declarations;
675
+ }
676
+
677
+ function scanGo(input) {
678
+ const declarations = [];
679
+ for (const { line, number } of sourceLines(input.sourceText)) {
680
+ const trimmed = line.trim();
681
+ let match;
682
+ if ((match = trimmed.match(/^package\s+([A-Za-z_]\w*)/))) {
683
+ declarations.push(nativeDeclaration(input, number, 'PackageClause', 'package', match[1], {}, false));
684
+ } else if ((match = trimmed.match(/^import\s+(?:[A-Za-z_]\w*\s+)?["']([^"']+)["']/))) {
685
+ declarations.push(nativeImportDeclaration(input, number, match[1], 'ImportSpec', 'package'));
686
+ } else if ((match = trimmed.match(/^type\s+([A-Za-z_]\w*)\s+(struct|interface)\b/))) {
687
+ declarations.push(nativeDeclaration(input, number, match[2] === 'struct' ? 'TypeSpecStruct' : 'TypeSpecInterface', 'type', match[1], {}, trimmed.includes('{')));
688
+ } else if ((match = trimmed.match(/^func\s+(?:\([^)]*\)\s*)?([A-Za-z_]\w*)\s*\(([^)]*)\)/))) {
689
+ declarations.push(nativeDeclaration(input, number, 'FuncDecl', 'function', match[1], { parameters: splitParameters(match[2]) }, trimmed.includes('{')));
690
+ } else if ((match = trimmed.match(/^var\s+([A-Za-z_]\w*)\b/))) {
691
+ declarations.push(nativeDeclaration(input, number, 'VarDecl', 'variable', match[1], {}, false));
692
+ } else if ((match = trimmed.match(/^const\s+([A-Za-z_]\w*)\b/))) {
693
+ declarations.push(nativeDeclaration(input, number, 'ConstDecl', 'constant', match[1], {}, false));
694
+ }
695
+ }
696
+ return declarations;
697
+ }
698
+
699
+ function scanSwift(input) {
700
+ const declarations = [];
701
+ for (const { line, number } of sourceLines(input.sourceText)) {
702
+ const trimmed = line.trim();
703
+ let match;
704
+ if ((match = trimmed.match(/^import\s+([A-Za-z_]\w*)/))) {
705
+ declarations.push(nativeImportDeclaration(input, number, match[1], 'ImportDecl', 'module'));
706
+ } else if ((match = trimmed.match(/^(?:(?:public|private|fileprivate|internal|open|final)\s+)*(struct|class|enum|protocol|actor|extension)\s+([A-Za-z_]\w*)/))) {
707
+ declarations.push(nativeDeclaration(input, number, `${upperFirst(match[1])}Decl`, swiftSymbolKind(match[1]), match[2], {}, trimmed.includes('{')));
708
+ } else if ((match = trimmed.match(/^(?:(?:public|private|fileprivate|internal|open|static|class|mutating)\s+)*func\s+([A-Za-z_]\w*)\s*\(([^)]*)\)/))) {
709
+ declarations.push(nativeDeclaration(input, number, 'FunctionDecl', 'function', match[1], { parameters: splitParameters(match[2]) }, trimmed.includes('{')));
710
+ } else if ((match = trimmed.match(/^(?:let|var)\s+([A-Za-z_]\w*)\b/))) {
711
+ declarations.push(nativeDeclaration(input, number, 'ValueBindingDecl', 'variable', match[1], {}, false));
712
+ }
713
+ }
714
+ return declarations;
715
+ }
716
+
717
+ function scanCSharp(input) {
718
+ const declarations = [];
719
+ for (const { line, number } of sourceLines(input.sourceText)) {
720
+ const trimmed = line.trim();
721
+ let match;
722
+ if ((match = trimmed.match(/^using\s+(?:static\s+)?([A-Za-z_][\w.]*)\s*;/))) {
723
+ declarations.push(nativeImportDeclaration(input, number, match[1], 'UsingDirective', 'namespace'));
724
+ } else if ((match = trimmed.match(/^namespace\s+([A-Za-z_][\w.]*)/))) {
725
+ declarations.push(nativeDeclaration(input, number, 'NamespaceDeclaration', 'namespace', match[1], {}, trimmed.includes('{')));
726
+ } else if ((match = trimmed.match(/^(?:(?:public|protected|private|internal|abstract|sealed|static|partial|readonly)\s+)*(class|interface|struct|enum|record)\s+([A-Za-z_]\w*)/))) {
727
+ declarations.push(nativeDeclaration(input, number, `${upperFirst(match[1])}Declaration`, csharpSymbolKind(match[1]), match[2], {}, trimmed.includes('{')));
728
+ } else if ((match = trimmed.match(/^(?:(?:public|protected|private|internal|static|virtual|override|async|partial|sealed|abstract|extern)\s+)*[A-Za-z_][\w<>\[\].?,\s]*\s+([A-Za-z_]\w*)\s*\(([^)]*)\)\s*(?:\{|;)?$/))) {
729
+ declarations.push(nativeDeclaration(input, number, 'MethodDeclaration', 'method', match[1], { parameters: splitParameters(match[2]) }, trimmed.includes('{')));
730
+ }
731
+ }
732
+ return declarations;
733
+ }
734
+
735
+ function scanPhp(input) {
736
+ const declarations = [];
737
+ for (const { line, number } of sourceLines(input.sourceText)) {
738
+ const trimmed = line.trim().replace(/^<\?php\s*/, '');
739
+ let match;
740
+ if ((match = trimmed.match(/^namespace\s+([A-Za-z_][\w\\]*)\s*;/))) {
741
+ declarations.push(nativeDeclaration(input, number, 'NamespaceDefinition', 'namespace', match[1], {}, false));
742
+ } else if ((match = trimmed.match(/^use\s+([A-Za-z_][\w\\]*)(?:\s+as\s+([A-Za-z_]\w*))?\s*;/))) {
743
+ declarations.push(nativeImportDeclaration(input, number, match[1], 'UseDeclaration', 'namespace'));
744
+ } else if ((match = trimmed.match(/^(?:(?:abstract|final|readonly)\s+)*(class|interface|trait|enum)\s+([A-Za-z_]\w*)/))) {
745
+ declarations.push(nativeDeclaration(input, number, `${upperFirst(match[1])}Declaration`, phpSymbolKind(match[1]), match[2], {}, trimmed.includes('{')));
746
+ } else if ((match = trimmed.match(/^(?:(?:public|protected|private|static|final|abstract)\s+)*function\s+&?\s*([A-Za-z_]\w*)\s*\(([^)]*)\)/))) {
747
+ declarations.push(nativeDeclaration(input, number, 'FunctionDeclaration', 'function', match[1], { parameters: splitParameters(match[2]) }, trimmed.includes('{')));
748
+ }
749
+ }
750
+ return declarations;
751
+ }
752
+
753
+ function scanRuby(input) {
754
+ const declarations = [];
755
+ for (const { line, number } of sourceLines(input.sourceText)) {
756
+ const trimmed = line.trim();
757
+ let match;
758
+ if ((match = trimmed.match(/^(?:require|load)\s+['"]([^'"]+)['"]/))) {
759
+ declarations.push(nativeImportDeclaration(input, number, match[1], 'Require', 'module'));
760
+ } else if ((match = trimmed.match(/^module\s+([A-Za-z_]\w*(?:::[A-Za-z_]\w*)*)/))) {
761
+ declarations.push(nativeDeclaration(input, number, 'Module', 'module', match[1], {}, true));
762
+ } else if ((match = trimmed.match(/^class\s+([A-Za-z_]\w*(?:::[A-Za-z_]\w*)*)/))) {
763
+ declarations.push(nativeDeclaration(input, number, 'Class', 'class', match[1], {}, true));
764
+ } else if ((match = trimmed.match(/^def\s+(?:self\.)?([A-Za-z_]\w*[!?=]?)\s*(?:\(([^)]*)\)|([^#=]*))?/))) {
765
+ declarations.push(nativeDeclaration(input, number, 'Def', 'method', match[1], { parameters: splitParameters(match[2] ?? match[3]) }, true));
766
+ }
767
+ }
768
+ return declarations;
769
+ }
770
+
591
771
  function scanGenericDeclarations(input) {
592
772
  return sourceLines(input.sourceText)
593
773
  .filter(({ line }) => /\b(function|class|struct|enum|trait|interface|def)\b/.test(line))
594
774
  .map(({ line, number }) => nativeDeclaration(input, number, 'NativeDeclaration', 'variable', idFragment(line.trim()).slice(0, 40), { source: line.trim() }, true));
595
775
  }
596
776
 
777
+ function upperFirst(value) {
778
+ return String(value).charAt(0).toUpperCase() + String(value).slice(1);
779
+ }
780
+
781
+ function javaSymbolKind(kind) {
782
+ if (kind === 'interface' || kind === '@interface') return 'interface';
783
+ if (kind === 'enum' || kind === 'record') return 'type';
784
+ return 'class';
785
+ }
786
+
787
+ function swiftSymbolKind(kind) {
788
+ if (kind === 'protocol') return 'protocol';
789
+ if (kind === 'extension') return 'implementation';
790
+ if (kind === 'struct' || kind === 'enum' || kind === 'actor') return 'type';
791
+ return 'class';
792
+ }
793
+
794
+ function csharpSymbolKind(kind) {
795
+ if (kind === 'interface') return 'interface';
796
+ if (kind === 'struct' || kind === 'enum' || kind === 'record') return 'type';
797
+ return 'class';
798
+ }
799
+
800
+ function phpSymbolKind(kind) {
801
+ if (kind === 'interface') return 'interface';
802
+ if (kind === 'trait') return 'trait';
803
+ if (kind === 'enum') return 'type';
804
+ return 'class';
805
+ }
806
+
597
807
  function nativeDeclaration(input, lineNumber, languageKind, symbolKind, name, fields = {}, hasBody = false) {
598
808
  const nodeId = `native_${idFragment(languageKind)}_${lineNumber}_${idFragment(name)}`;
599
809
  return {
@@ -666,6 +876,54 @@ function opaqueBodyLoss(input, lineNumber, nodeId, name) {
666
876
  };
667
877
  }
668
878
 
879
+ function lightweightCoverageLosses(input, declarations) {
880
+ const id = idFragment(input.sourcePath ?? input.language);
881
+ const span = declarations[0]?.span ?? {
882
+ sourceId: input.sourceHash,
883
+ path: input.sourcePath,
884
+ startLine: 1,
885
+ startColumn: 1
886
+ };
887
+ return [
888
+ {
889
+ id: `loss_${id}_declaration_only_coverage`,
890
+ severity: 'info',
891
+ phase: 'read',
892
+ sourceFormat: input.language,
893
+ kind: 'declarationOnlyCoverage',
894
+ message: 'Lightweight importer scanned declarations and imports only; expressions, control flow, and full type checking were not evaluated.',
895
+ span
896
+ },
897
+ {
898
+ id: `loss_${id}_partial_semantic_index`,
899
+ severity: 'info',
900
+ phase: 'index',
901
+ sourceFormat: input.language,
902
+ kind: 'partialSemanticIndex',
903
+ message: 'Semantic index contains lightweight declaration/import facts only; references, calls, resolved types, and cross-file links may be missing.',
904
+ span
905
+ },
906
+ {
907
+ id: `loss_${id}_source_map_approximation`,
908
+ severity: 'info',
909
+ phase: 'map',
910
+ sourceFormat: input.language,
911
+ kind: 'sourceMapApproximation',
912
+ message: 'Source-map spans are declaration or line estimates; exact token ranges require a parser adapter.',
913
+ span
914
+ },
915
+ {
916
+ id: `loss_${id}_source_preservation`,
917
+ severity: 'warning',
918
+ phase: 'read',
919
+ sourceFormat: input.language,
920
+ kind: 'sourcePreservation',
921
+ message: 'Comments, whitespace, token order, directives, and formatting are not preserved by the lightweight importer.',
922
+ span
923
+ }
924
+ ];
925
+ }
926
+
669
927
  function sourceLines(sourceText) {
670
928
  return String(sourceText ?? '').split(/\r?\n/).map((line, index) => ({ line, number: index + 1 }));
671
929
  }
@@ -687,11 +945,95 @@ function splitParameters(raw) {
687
945
  .filter(Boolean);
688
946
  }
689
947
 
948
+ function inferSourceMapMappings(input) {
949
+ const semanticIndex = input.semanticIndex;
950
+ const nativeAst = input.nativeAst;
951
+ const nativeSource = input.nativeSource;
952
+ const evidenceIds = [
953
+ ...(semanticIndex?.evidence ?? []).map((record) => record.id),
954
+ ...(input.evidence ?? []).map((record) => record.id)
955
+ ];
956
+ const symbolsById = new Map((semanticIndex?.symbols ?? []).map((symbol) => [symbol.id, symbol]));
957
+
958
+ if (semanticIndex?.occurrences?.length) {
959
+ return semanticIndex.occurrences
960
+ .filter((occurrence) => occurrence.nativeAstNodeId || occurrence.span)
961
+ .map((occurrence) => {
962
+ const symbol = symbolsById.get(occurrence.symbolId);
963
+ const nativeNode = occurrence.nativeAstNodeId ? nativeAst?.nodes?.[occurrence.nativeAstNodeId] : undefined;
964
+ return {
965
+ id: `map_${idFragment(occurrence.id)}`,
966
+ nativeSourceId: nativeSource?.id,
967
+ nativeAstNodeId: occurrence.nativeAstNodeId,
968
+ semanticSymbolId: occurrence.symbolId,
969
+ semanticOccurrenceId: occurrence.id,
970
+ semanticNodeId: occurrence.semanticNodeId ?? symbol?.semanticNodeId,
971
+ sourceSpan: occurrence.span ?? nativeNode?.span,
972
+ evidenceIds,
973
+ lossIds: lossIdsForNativeNode(input.losses ?? nativeAst?.losses ?? [], occurrence.nativeAstNodeId),
974
+ precision: occurrence.span || nativeNode?.span ? 'declaration' : 'unknown'
975
+ };
976
+ });
977
+ }
978
+
979
+ return Object.values(nativeAst?.nodes ?? {})
980
+ .filter((node) => node.span)
981
+ .map((node) => ({
982
+ id: `map_${idFragment(node.id)}`,
983
+ nativeSourceId: nativeSource?.id,
984
+ nativeAstNodeId: node.id,
985
+ sourceSpan: node.span,
986
+ evidenceIds,
987
+ lossIds: lossIdsForNativeNode(input.losses ?? nativeAst?.losses ?? [], node.id),
988
+ precision: 'line'
989
+ }));
990
+ }
991
+
992
+ function normalizeSourceMapMappings(mappings, context) {
993
+ const semanticIndex = context.semanticIndex;
994
+ const nativeAst = context.nativeAst;
995
+ const nativeSource = context.nativeSource;
996
+ const symbolsById = new Map((semanticIndex?.symbols ?? []).map((symbol) => [symbol.id, symbol]));
997
+ const occurrencesById = new Map((semanticIndex?.occurrences ?? []).map((occurrence) => [occurrence.id, occurrence]));
998
+ const evidenceIds = (context.evidence ?? []).map((record) => record.id);
999
+ return (mappings ?? [])
1000
+ .filter((mapping) => mapping && typeof mapping === 'object')
1001
+ .map((mapping, index) => {
1002
+ const occurrence = mapping.semanticOccurrenceId ? occurrencesById.get(mapping.semanticOccurrenceId) : undefined;
1003
+ const symbol = mapping.semanticSymbolId ? symbolsById.get(mapping.semanticSymbolId) : occurrence ? symbolsById.get(occurrence.symbolId) : undefined;
1004
+ const nativeAstNodeId = mapping.nativeAstNodeId ?? occurrence?.nativeAstNodeId;
1005
+ const nativeNode = nativeAstNodeId ? nativeAst?.nodes?.[nativeAstNodeId] : undefined;
1006
+ const sourceSpan = mapping.sourceSpan ?? occurrence?.span ?? nativeNode?.span;
1007
+ return {
1008
+ ...mapping,
1009
+ id: mapping.id ?? `map_${idFragment(nativeAstNodeId ?? mapping.semanticSymbolId ?? mapping.semanticNodeId ?? index + 1)}`,
1010
+ nativeSourceId: mapping.nativeSourceId ?? nativeSource?.id,
1011
+ nativeAstNodeId,
1012
+ semanticSymbolId: mapping.semanticSymbolId ?? occurrence?.symbolId,
1013
+ semanticOccurrenceId: mapping.semanticOccurrenceId ?? occurrence?.id,
1014
+ semanticNodeId: mapping.semanticNodeId ?? occurrence?.semanticNodeId ?? symbol?.semanticNodeId,
1015
+ sourceSpan,
1016
+ target: mapping.target ?? context.target,
1017
+ evidenceIds: mapping.evidenceIds ?? evidenceIds,
1018
+ lossIds: mapping.lossIds ?? lossIdsForNativeNode(context.losses ?? nativeAst?.losses ?? [], nativeAstNodeId),
1019
+ precision: mapping.precision ?? (sourceSpan ? 'declaration' : 'unknown')
1020
+ };
1021
+ });
1022
+ }
1023
+
1024
+ function lossIdsForNativeNode(losses, nativeAstNodeId) {
1025
+ if (!nativeAstNodeId) return [];
1026
+ return (losses ?? [])
1027
+ .filter((loss) => loss.nodeId === nativeAstNodeId)
1028
+ .map((loss) => loss.id);
1029
+ }
1030
+
690
1031
  export function createUniversalAstFromDocument(document, input = {}) {
691
1032
  return createUniversalAstEnvelope({
692
1033
  id: input.id ?? `universal_ast_${idFragment(document.id)}`,
693
1034
  document,
694
1035
  semanticIndex: input.semanticIndex,
1036
+ sourceMaps: input.sourceMaps ?? [],
695
1037
  evidence: input.evidence ?? [],
696
1038
  metadata: input.metadata
697
1039
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -56,14 +56,14 @@
56
56
  "access": "public"
57
57
  },
58
58
  "dependencies": {
59
- "@shapeshift-labs/frontier-lang-c": "0.2.2",
60
- "@shapeshift-labs/frontier-lang-checker": "0.3.2",
61
- "@shapeshift-labs/frontier-lang-javascript": "0.2.2",
62
- "@shapeshift-labs/frontier-lang-kernel": "0.3.2",
63
- "@shapeshift-labs/frontier-lang-parser": "0.3.2",
64
- "@shapeshift-labs/frontier-lang-python": "0.2.2",
65
- "@shapeshift-labs/frontier-lang-rust": "0.2.2",
66
- "@shapeshift-labs/frontier-lang-typescript": "0.3.2"
59
+ "@shapeshift-labs/frontier-lang-c": "0.2.3",
60
+ "@shapeshift-labs/frontier-lang-checker": "0.3.3",
61
+ "@shapeshift-labs/frontier-lang-javascript": "0.2.3",
62
+ "@shapeshift-labs/frontier-lang-kernel": "0.3.3",
63
+ "@shapeshift-labs/frontier-lang-parser": "0.3.3",
64
+ "@shapeshift-labs/frontier-lang-python": "0.2.3",
65
+ "@shapeshift-labs/frontier-lang-rust": "0.2.3",
66
+ "@shapeshift-labs/frontier-lang-typescript": "0.3.3"
67
67
  },
68
68
  "devDependencies": {
69
69
  "typescript": "^5.9.3"