@shapeshift-labs/frontier-lang-compiler 0.2.22 → 0.2.23
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 +28 -0
- package/bench/smoke.mjs +40 -1
- package/dist/index.d.ts +59 -0
- package/dist/index.js +1218 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -329,6 +329,14 @@ export const NativeImportLanguageProfiles = Object.freeze([
|
|
|
329
329
|
nativeImportLanguageProfile('r', { aliases: ['R'], extensions: ['.r', '.R'], parserAdapters: ['r-parser', 'tree-sitter'], lossKinds: ['declarationOnlyCoverage', 'opaqueNative', 'dynamicRuntime', 'sourceMapApproximation', 'sourcePreservation'] })
|
|
330
330
|
]);
|
|
331
331
|
|
|
332
|
+
export const ExternalSemanticIndexFormats = Object.freeze([
|
|
333
|
+
'frontier-semantic-index',
|
|
334
|
+
'scip',
|
|
335
|
+
'lsif',
|
|
336
|
+
'lsp',
|
|
337
|
+
'semanticdb'
|
|
338
|
+
]);
|
|
339
|
+
|
|
332
340
|
export function normalizeCompileTarget(target) {
|
|
333
341
|
const normalized = String(target ?? 'typescript').toLowerCase();
|
|
334
342
|
const canonical = canonicalTargets[normalized] ?? normalized;
|
|
@@ -544,6 +552,1216 @@ export function compileNativeSource(input, options = {}) {
|
|
|
544
552
|
};
|
|
545
553
|
}
|
|
546
554
|
|
|
555
|
+
export function importExternalSemanticIndex(input) {
|
|
556
|
+
const payload = input?.payload ?? input?.semanticIndex ?? input;
|
|
557
|
+
if (!payload || typeof payload !== 'object') {
|
|
558
|
+
throw new Error('importExternalSemanticIndex requires a payload object');
|
|
559
|
+
}
|
|
560
|
+
const format = normalizeExternalSemanticIndexFormat(input?.format ?? inferExternalSemanticIndexFormat(payload));
|
|
561
|
+
const idPart = idFragment(input?.id ?? input?.sourcePath ?? input?.projectRoot ?? format);
|
|
562
|
+
const context = {
|
|
563
|
+
format,
|
|
564
|
+
idPart,
|
|
565
|
+
language: normalizeExternalSemanticLanguage(input?.language ?? payload.language ?? payload.languageId),
|
|
566
|
+
sourcePath: input?.sourcePath ?? payload.sourcePath ?? payload.uri ?? payload.path,
|
|
567
|
+
sourceHash: input?.sourceHash ?? payload.sourceHash ?? payload.md5,
|
|
568
|
+
projectRoot: input?.projectRoot ?? payload.projectRoot ?? payload.project_root ?? payload.metadata?.projectRoot ?? payload.metadata?.project_root,
|
|
569
|
+
parser: input?.parser ?? `${format}.external-semantic-index`,
|
|
570
|
+
metadata: input?.metadata ?? {}
|
|
571
|
+
};
|
|
572
|
+
const normalized = normalizeExternalSemanticIndexPayload(payload, context);
|
|
573
|
+
const evidence = attachNativeImportLossSummary(
|
|
574
|
+
uniqueByEvidenceId([...(normalized.evidence ?? []), ...(input?.evidence ?? [])]),
|
|
575
|
+
summarizeNativeImportLosses(normalized.losses ?? [], {
|
|
576
|
+
evidence: [...(normalized.evidence ?? []), ...(input?.evidence ?? [])],
|
|
577
|
+
parser: context.parser,
|
|
578
|
+
scanKind: 'external-semantic-index',
|
|
579
|
+
semanticStatus: normalized.semanticStatus
|
|
580
|
+
})
|
|
581
|
+
);
|
|
582
|
+
const losses = normalizeNativeLossRecords(normalized.losses ?? []);
|
|
583
|
+
const semanticIndex = createSemanticIndexRecord({
|
|
584
|
+
id: input?.semanticIndexId ?? normalized.semanticIndexId ?? `index_${idPart}_${idFragment(format)}`,
|
|
585
|
+
repository: normalized.repository,
|
|
586
|
+
documents: normalized.documents,
|
|
587
|
+
symbols: normalized.symbols,
|
|
588
|
+
occurrences: normalized.occurrences,
|
|
589
|
+
relations: normalized.relations,
|
|
590
|
+
facts: normalized.facts,
|
|
591
|
+
evidence,
|
|
592
|
+
metadata: {
|
|
593
|
+
format,
|
|
594
|
+
parser: context.parser,
|
|
595
|
+
source: 'external-semantic-index',
|
|
596
|
+
projectRoot: context.projectRoot,
|
|
597
|
+
semanticStatus: normalized.semanticStatus,
|
|
598
|
+
...normalized.metadata,
|
|
599
|
+
...context.metadata
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
const sourceMapMappings = externalSemanticSourceMapMappings(semanticIndex, {
|
|
603
|
+
evidence,
|
|
604
|
+
losses,
|
|
605
|
+
sourcePath: context.sourcePath,
|
|
606
|
+
sourceHash: context.sourceHash
|
|
607
|
+
});
|
|
608
|
+
const sourceMaps = sourceMapMappings.length
|
|
609
|
+
? [createSourceMapRecord({
|
|
610
|
+
id: input?.sourceMapId ?? `source_map_${idPart}_${idFragment(format)}`,
|
|
611
|
+
sourcePath: context.sourcePath,
|
|
612
|
+
sourceHash: context.sourceHash,
|
|
613
|
+
semanticIndexId: semanticIndex.id,
|
|
614
|
+
mappings: sourceMapMappings,
|
|
615
|
+
evidence,
|
|
616
|
+
metadata: {
|
|
617
|
+
format,
|
|
618
|
+
source: 'external-semantic-index',
|
|
619
|
+
projectRoot: context.projectRoot
|
|
620
|
+
}
|
|
621
|
+
})]
|
|
622
|
+
: [];
|
|
623
|
+
const document = createDocument({
|
|
624
|
+
id: input?.documentId ?? `document_${idPart}_${idFragment(format)}`,
|
|
625
|
+
name: input?.documentName ?? context.sourcePath ?? `${format} semantic index`,
|
|
626
|
+
nodes: [],
|
|
627
|
+
rootIds: [],
|
|
628
|
+
metadata: {
|
|
629
|
+
sourceLanguage: context.language,
|
|
630
|
+
sourcePath: context.sourcePath,
|
|
631
|
+
sourceHash: context.sourceHash,
|
|
632
|
+
semanticStatus: normalized.semanticStatus,
|
|
633
|
+
externalSemanticIndexFormat: format
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
const universalAst = createUniversalAstEnvelope({
|
|
637
|
+
id: input?.universalAstId ?? `universal_ast_${idPart}_${idFragment(format)}`,
|
|
638
|
+
document,
|
|
639
|
+
nativeSources: [],
|
|
640
|
+
semanticIndex,
|
|
641
|
+
sourceMaps,
|
|
642
|
+
losses,
|
|
643
|
+
evidence,
|
|
644
|
+
metadata: {
|
|
645
|
+
sourceLanguage: context.language,
|
|
646
|
+
sourcePath: context.sourcePath,
|
|
647
|
+
sourceHash: context.sourceHash,
|
|
648
|
+
projectRoot: context.projectRoot,
|
|
649
|
+
externalSemanticIndexFormat: format,
|
|
650
|
+
semanticStatus: normalized.semanticStatus,
|
|
651
|
+
...input?.universalAstMetadata
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
const readiness = classifyNativeImportReadiness(losses, {
|
|
655
|
+
evidence,
|
|
656
|
+
parser: context.parser,
|
|
657
|
+
scanKind: 'external-semantic-index',
|
|
658
|
+
semanticStatus: normalized.semanticStatus
|
|
659
|
+
});
|
|
660
|
+
return {
|
|
661
|
+
kind: 'frontier.lang.externalSemanticIndexImport',
|
|
662
|
+
version: 1,
|
|
663
|
+
id: input?.id ?? `external_semantic_index_${idPart}_${idFragment(format)}`,
|
|
664
|
+
format,
|
|
665
|
+
language: context.language,
|
|
666
|
+
sourcePath: context.sourcePath,
|
|
667
|
+
projectRoot: context.projectRoot,
|
|
668
|
+
semanticIndex,
|
|
669
|
+
universalAst,
|
|
670
|
+
sourceMaps,
|
|
671
|
+
losses,
|
|
672
|
+
evidence,
|
|
673
|
+
readiness,
|
|
674
|
+
summary: {
|
|
675
|
+
documents: semanticIndex.documents.length,
|
|
676
|
+
symbols: semanticIndex.symbols.length,
|
|
677
|
+
occurrences: semanticIndex.occurrences.length,
|
|
678
|
+
relations: semanticIndex.relations.length,
|
|
679
|
+
facts: semanticIndex.facts.length,
|
|
680
|
+
sourceMapMappings: sourceMaps.reduce((sum, sourceMap) => sum + (sourceMap.mappings?.length ?? 0), 0),
|
|
681
|
+
losses: losses.length,
|
|
682
|
+
readiness: readiness.readiness
|
|
683
|
+
},
|
|
684
|
+
metadata: {
|
|
685
|
+
format,
|
|
686
|
+
parser: context.parser,
|
|
687
|
+
semanticStatus: normalized.semanticStatus,
|
|
688
|
+
payloadHash: hashSemanticValue(payload),
|
|
689
|
+
...normalized.metadata,
|
|
690
|
+
...context.metadata
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function normalizeExternalSemanticIndexFormat(format) {
|
|
696
|
+
const normalized = String(format ?? 'frontier-semantic-index').trim().toLowerCase();
|
|
697
|
+
const aliases = {
|
|
698
|
+
frontier: 'frontier-semantic-index',
|
|
699
|
+
'frontier.semantic-index': 'frontier-semantic-index',
|
|
700
|
+
'frontier.lang.semanticindex': 'frontier-semantic-index',
|
|
701
|
+
scipindex: 'scip',
|
|
702
|
+
'sourcegraph-scip': 'scip',
|
|
703
|
+
lsp: 'lsp',
|
|
704
|
+
'language-server-protocol': 'lsp',
|
|
705
|
+
semanticdb: 'semanticdb',
|
|
706
|
+
'scala-semanticdb': 'semanticdb'
|
|
707
|
+
};
|
|
708
|
+
return aliases[normalized] ?? normalized;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function inferExternalSemanticIndexFormat(payload) {
|
|
712
|
+
if (payload.kind === 'frontier.lang.semanticIndex') return 'frontier-semantic-index';
|
|
713
|
+
if (Array.isArray(payload) && payload.some((entry) => entry?.type === 'vertex' || entry?.type === 'edge')) return 'lsif';
|
|
714
|
+
if (Array.isArray(payload.vertices) || Array.isArray(payload.edges)) return 'lsif';
|
|
715
|
+
if (Array.isArray(payload.documents) && payload.documents.some((document) => document?.relative_path ?? document?.relativePath)) return 'scip';
|
|
716
|
+
if (payload.metadata?.project_root || payload.metadata?.projectRoot || payload.external_symbols || payload.externalSymbols) return 'scip';
|
|
717
|
+
if (Array.isArray(payload.documents) && payload.documents.some((document) => document?.symbols && document?.occurrences && (document?.uri || document?.md5 || document?.schema))) return 'semanticdb';
|
|
718
|
+
if (Array.isArray(payload.documentSymbols) || Array.isArray(payload.symbols) || payload.semanticTokens || payload.location || payload.range) return 'lsp';
|
|
719
|
+
return 'frontier-semantic-index';
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function normalizeExternalSemanticIndexPayload(payload, context) {
|
|
723
|
+
if (context.format === 'frontier-semantic-index') return normalizeFrontierSemanticIndexPayload(payload, context);
|
|
724
|
+
if (context.format === 'scip') return normalizeScipPayload(payload, context);
|
|
725
|
+
if (context.format === 'lsif') return normalizeLsifPayload(payload, context);
|
|
726
|
+
if (context.format === 'lsp') return normalizeLspPayload(payload, context);
|
|
727
|
+
if (context.format === 'semanticdb') return normalizeSemanticDbPayload(payload, context);
|
|
728
|
+
return normalizeGenericExternalSemanticIndexPayload(payload, context);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function externalSemanticBase(context, metadata = {}) {
|
|
732
|
+
return {
|
|
733
|
+
repository: context.projectRoot ? { root: context.projectRoot } : undefined,
|
|
734
|
+
documents: [],
|
|
735
|
+
symbols: [],
|
|
736
|
+
occurrences: [],
|
|
737
|
+
relations: [],
|
|
738
|
+
facts: [],
|
|
739
|
+
evidence: [externalSemanticEvidence(context, 'passed', `Imported ${context.format} semantic index payload.`)],
|
|
740
|
+
losses: [externalSemanticCoverageLoss(context)],
|
|
741
|
+
semanticStatus: 'external-semantic-index',
|
|
742
|
+
metadata
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function normalizeFrontierSemanticIndexPayload(payload, context) {
|
|
747
|
+
const result = externalSemanticBase(context, { sourceFormat: payload.kind ?? 'frontier.lang.semanticIndex' });
|
|
748
|
+
result.repository = payload.repository ?? result.repository;
|
|
749
|
+
result.documents = normalizeArray(payload.documents).map((document, index) => externalDocument(document, context, index));
|
|
750
|
+
result.symbols = normalizeArray(payload.symbols).map((symbol, index) => externalSymbol(symbol, context, index));
|
|
751
|
+
result.occurrences = normalizeArray(payload.occurrences).map((occurrence, index) => externalOccurrence(occurrence, context, index));
|
|
752
|
+
result.relations = normalizeArray(payload.relations).map((relation, index) => externalRelation(relation, context, index));
|
|
753
|
+
result.facts = normalizeArray(payload.facts).map((fact, index) => externalFact(fact, context, index));
|
|
754
|
+
result.evidence = uniqueByEvidenceId([...(payload.evidence ?? []), ...result.evidence]);
|
|
755
|
+
if (payload.metadata) result.metadata = { ...result.metadata, ...payload.metadata };
|
|
756
|
+
return withExternalEmptyLoss(result, context);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
function normalizeScipPayload(payload, context) {
|
|
760
|
+
const result = externalSemanticBase(context, { sourceFormat: 'scip' });
|
|
761
|
+
const metadata = payload.metadata ?? {};
|
|
762
|
+
const projectRoot = context.projectRoot ?? metadata.project_root ?? metadata.projectRoot;
|
|
763
|
+
result.repository = projectRoot ? { root: projectRoot } : undefined;
|
|
764
|
+
const documents = normalizeArray(payload.documents);
|
|
765
|
+
for (const [documentIndex, document] of documents.entries()) {
|
|
766
|
+
const path = document.relative_path ?? document.relativePath ?? document.path ?? context.sourcePath ?? `scip-document-${documentIndex + 1}`;
|
|
767
|
+
const language = normalizeExternalSemanticLanguage(document.language ?? context.language);
|
|
768
|
+
const documentId = document.id ?? `doc_${idFragment(path)}`;
|
|
769
|
+
result.documents.push({
|
|
770
|
+
id: documentId,
|
|
771
|
+
path,
|
|
772
|
+
language,
|
|
773
|
+
sourceHash: document.sourceHash ?? document.md5 ?? context.sourceHash,
|
|
774
|
+
metadata: {
|
|
775
|
+
format: 'scip',
|
|
776
|
+
projectRoot,
|
|
777
|
+
textDocumentEncoding: metadata.text_document_encoding ?? metadata.textDocumentEncoding,
|
|
778
|
+
documentIndex
|
|
779
|
+
}
|
|
780
|
+
});
|
|
781
|
+
const documentSymbols = new Map();
|
|
782
|
+
for (const symbolInfo of [...normalizeArray(document.symbols), ...normalizeArray(payload.external_symbols ?? payload.externalSymbols)]) {
|
|
783
|
+
const symbolId = scipSymbolId(symbolInfo.symbol, context, normalizeArray(document.symbols).includes(symbolInfo) ? documentId : undefined);
|
|
784
|
+
if (!symbolId || documentSymbols.has(symbolId)) continue;
|
|
785
|
+
documentSymbols.set(symbolId, true);
|
|
786
|
+
result.symbols.push({
|
|
787
|
+
id: symbolId,
|
|
788
|
+
scheme: 'scip',
|
|
789
|
+
name: symbolInfo.display_name ?? symbolInfo.displayName ?? nameFromExternalSymbol(symbolInfo.symbol),
|
|
790
|
+
kind: normalizeExternalSymbolKind(symbolInfo.kind),
|
|
791
|
+
language,
|
|
792
|
+
signatureHash: hashSemanticValue([symbolInfo.symbol, symbolInfo.signature_documentation ?? symbolInfo.signatureDocumentation]),
|
|
793
|
+
metadata: {
|
|
794
|
+
format: 'scip',
|
|
795
|
+
rawSymbol: symbolInfo.symbol,
|
|
796
|
+
documentation: symbolInfo.documentation,
|
|
797
|
+
enclosingSymbol: symbolInfo.enclosing_symbol ?? symbolInfo.enclosingSymbol,
|
|
798
|
+
external: !normalizeArray(document.symbols).includes(symbolInfo)
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
result.facts.push(...scipSymbolFacts(symbolInfo, symbolId));
|
|
802
|
+
result.relations.push(...scipRelationshipRelations(symbolInfo, symbolId, context));
|
|
803
|
+
}
|
|
804
|
+
for (const [occurrenceIndex, occurrence] of normalizeArray(document.occurrences).entries()) {
|
|
805
|
+
const symbolId = scipSymbolId(occurrence.symbol, context, documentId);
|
|
806
|
+
if (!symbolId) continue;
|
|
807
|
+
const role = scipOccurrenceRole(occurrence.symbol_roles ?? occurrence.symbolRoles);
|
|
808
|
+
if (!documentSymbols.has(symbolId)) {
|
|
809
|
+
documentSymbols.set(symbolId, true);
|
|
810
|
+
result.symbols.push({
|
|
811
|
+
id: symbolId,
|
|
812
|
+
scheme: 'scip',
|
|
813
|
+
name: nameFromExternalSymbol(occurrence.symbol),
|
|
814
|
+
kind: scipSyntaxKind(occurrence.syntax_kind ?? occurrence.syntaxKind),
|
|
815
|
+
language,
|
|
816
|
+
metadata: { format: 'scip', rawSymbol: occurrence.symbol, inferredFromOccurrence: true }
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
result.occurrences.push({
|
|
820
|
+
id: occurrence.id ?? `occ_${idFragment(documentId)}_${occurrenceIndex + 1}`,
|
|
821
|
+
documentId,
|
|
822
|
+
symbolId,
|
|
823
|
+
role,
|
|
824
|
+
span: spanFromScipOccurrence(occurrence, path, context.sourceHash),
|
|
825
|
+
metadata: {
|
|
826
|
+
format: 'scip',
|
|
827
|
+
symbolRoles: occurrence.symbol_roles ?? occurrence.symbolRoles,
|
|
828
|
+
roleSet: scipOccurrenceRoleSet(occurrence.symbol_roles ?? occurrence.symbolRoles),
|
|
829
|
+
syntaxKind: occurrence.syntax_kind ?? occurrence.syntaxKind,
|
|
830
|
+
overrideDocumentation: occurrence.override_documentation ?? occurrence.overrideDocumentation
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
for (const diagnostic of normalizeArray(occurrence.diagnostics)) {
|
|
834
|
+
const scopedDiagnostic = { ...diagnostic, range: diagnostic.range ?? occurrence.range };
|
|
835
|
+
result.facts.push(externalDiagnosticFact(scopedDiagnostic, context, documentId, path, result.facts.length));
|
|
836
|
+
result.losses.push(externalDiagnosticLoss(scopedDiagnostic, context, path));
|
|
837
|
+
}
|
|
838
|
+
if (scipOccurrenceRoleSet(occurrence.symbol_roles ?? occurrence.symbolRoles).includes('generated')) {
|
|
839
|
+
result.losses.push({
|
|
840
|
+
id: `loss_${idFragment(documentId)}_${occurrenceIndex + 1}_generated_scip_occurrence`,
|
|
841
|
+
severity: 'warning',
|
|
842
|
+
phase: 'index',
|
|
843
|
+
sourceFormat: 'scip',
|
|
844
|
+
kind: 'generatedCode',
|
|
845
|
+
message: 'SCIP occurrence is marked generated; merge admission should review generated/source ownership before applying patches.',
|
|
846
|
+
span: spanFromScipOccurrence(occurrence, path, context.sourceHash),
|
|
847
|
+
semanticSymbolId: symbolId,
|
|
848
|
+
metadata: { format: 'scip', symbolRoles: occurrence.symbol_roles ?? occurrence.symbolRoles }
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return withExternalEmptyLoss(result, context);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function normalizeLsifPayload(payload, context) {
|
|
857
|
+
const result = externalSemanticBase(context, { sourceFormat: 'lsif' });
|
|
858
|
+
const records = Array.isArray(payload) ? payload : [...normalizeArray(payload.vertices), ...normalizeArray(payload.edges)];
|
|
859
|
+
const vertices = new Map(records.filter((record) => record?.type === 'vertex').map((record) => [record.id, record]));
|
|
860
|
+
const edges = records.filter((record) => record?.type === 'edge');
|
|
861
|
+
const documentByVertex = new Map();
|
|
862
|
+
const documentIdByRange = new Map();
|
|
863
|
+
const resultSetByRange = new Map();
|
|
864
|
+
const monikerByOut = new Map();
|
|
865
|
+
const definitionRangeIds = new Set();
|
|
866
|
+
for (const vertex of vertices.values()) {
|
|
867
|
+
if (vertex.label === 'document') {
|
|
868
|
+
const path = uriToPath(vertex.uri) ?? vertex.uri ?? context.sourcePath ?? `lsif-document-${result.documents.length + 1}`;
|
|
869
|
+
const documentId = `doc_${idFragment(vertex.id ?? path)}`;
|
|
870
|
+
documentByVertex.set(vertex.id, { id: documentId, path, language: normalizeExternalSemanticLanguage(vertex.languageId ?? context.language) });
|
|
871
|
+
result.documents.push({
|
|
872
|
+
id: documentId,
|
|
873
|
+
path,
|
|
874
|
+
language: normalizeExternalSemanticLanguage(vertex.languageId ?? context.language),
|
|
875
|
+
metadata: { format: 'lsif', vertexId: vertex.id, uri: vertex.uri }
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
if (vertex.label === 'moniker') monikerByOut.set(vertex.id, vertex);
|
|
879
|
+
}
|
|
880
|
+
for (const edge of edges) {
|
|
881
|
+
if (edge.label === 'next') resultSetByRange.set(edge.outV, edge.inV);
|
|
882
|
+
if (edge.label === 'moniker') monikerByOut.set(edge.outV, vertices.get(edge.inV) ?? edge);
|
|
883
|
+
if (edge.label === 'contains') {
|
|
884
|
+
const document = documentByVertex.get(edge.outV);
|
|
885
|
+
if (document) {
|
|
886
|
+
for (const rangeId of normalizeArray(edge.inVs ?? edge.inV)) {
|
|
887
|
+
documentIdByRange.set(rangeId, document.id);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (edge.label === 'item' && (edge.property === 'definitions' || edge.property === 'declarations')) {
|
|
892
|
+
for (const rangeId of normalizeArray(edge.inVs ?? edge.inV)) definitionRangeIds.add(rangeId);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
const documentIds = result.documents.map((document) => document.id);
|
|
896
|
+
const defaultDocument = result.documents[0] ?? {
|
|
897
|
+
id: `doc_${idFragment(context.sourcePath ?? 'lsif')}`,
|
|
898
|
+
path: context.sourcePath ?? 'lsif:memory',
|
|
899
|
+
language: context.language
|
|
900
|
+
};
|
|
901
|
+
if (!result.documents.length) result.documents.push(defaultDocument);
|
|
902
|
+
for (const [vertexId, vertex] of vertices.entries()) {
|
|
903
|
+
if (vertex.label !== 'range') continue;
|
|
904
|
+
const resultSetId = resultSetByRange.get(vertexId);
|
|
905
|
+
const moniker = monikerByOut.get(resultSetId) ?? monikerByOut.get(vertexId);
|
|
906
|
+
const symbolId = moniker?.identifier
|
|
907
|
+
? `symbol:lsif:${idFragment(moniker.scheme ?? moniker.kind ?? 'moniker')}:${idFragment(moniker.identifier)}`
|
|
908
|
+
: `symbol:lsif:${idFragment(resultSetId ?? vertexId)}`;
|
|
909
|
+
const documentId = documentIdByRange.get(vertexId) ?? documentIds[0] ?? defaultDocument.id;
|
|
910
|
+
const owningDocument = result.documents.find((document) => document.id === documentId) ?? defaultDocument;
|
|
911
|
+
const span = spanFromLspRange(vertex, owningDocument.path, context.sourceHash, 0);
|
|
912
|
+
if (!result.symbols.some((symbol) => symbol.id === symbolId)) {
|
|
913
|
+
result.symbols.push({
|
|
914
|
+
id: symbolId,
|
|
915
|
+
scheme: 'lsif',
|
|
916
|
+
name: moniker?.identifier ?? `range:${vertexId}`,
|
|
917
|
+
kind: moniker?.kind ?? 'symbol',
|
|
918
|
+
language: owningDocument.language,
|
|
919
|
+
definitionSpan: definitionRangeIds.has(vertexId) ? span : undefined,
|
|
920
|
+
metadata: { format: 'lsif', resultSetId, moniker }
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
result.occurrences.push({
|
|
924
|
+
id: `occ_${idFragment(vertexId)}`,
|
|
925
|
+
documentId,
|
|
926
|
+
symbolId,
|
|
927
|
+
role: definitionRangeIds.has(vertexId) ? 'definition' : 'reference',
|
|
928
|
+
span,
|
|
929
|
+
metadata: { format: 'lsif', vertexId, resultSetId }
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
for (const edge of edges) {
|
|
933
|
+
if (edge.label === 'textDocument/definition' || edge.label === 'textDocument/references' || edge.label === 'textDocument/declaration') {
|
|
934
|
+
result.relations.push({
|
|
935
|
+
id: `rel_${idFragment(edge.id ?? `${edge.outV}_${edge.inV}_${edge.label}`)}`,
|
|
936
|
+
sourceId: `lsif:${edge.outV}`,
|
|
937
|
+
predicate: edge.label,
|
|
938
|
+
targetId: `lsif:${edge.inV}`,
|
|
939
|
+
metadata: { format: 'lsif', edge }
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return withExternalEmptyLoss(result, context);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function normalizeLspPayload(payload, context) {
|
|
947
|
+
const result = externalSemanticBase(context, { sourceFormat: 'lsp' });
|
|
948
|
+
const documents = normalizeLspDocuments(payload, context);
|
|
949
|
+
for (const [documentIndex, document] of documents.entries()) {
|
|
950
|
+
const sourcePath = uriToPath(document.uri) ?? document.sourcePath ?? document.path ?? context.sourcePath ?? `lsp-document-${documentIndex + 1}`;
|
|
951
|
+
const language = normalizeExternalSemanticLanguage(document.languageId ?? document.language ?? context.language);
|
|
952
|
+
const documentId = document.id ?? `doc_${idFragment(sourcePath)}`;
|
|
953
|
+
result.documents.push({
|
|
954
|
+
id: documentId,
|
|
955
|
+
path: sourcePath,
|
|
956
|
+
language,
|
|
957
|
+
sourceHash: document.sourceHash ?? context.sourceHash,
|
|
958
|
+
metadata: { format: 'lsp', uri: document.uri, documentIndex }
|
|
959
|
+
});
|
|
960
|
+
const symbols = normalizeArray(document.documentSymbols ?? document.symbols ?? payload.documentSymbols ?? payload.symbols);
|
|
961
|
+
for (const symbol of symbols) addLspSymbol(result, symbol, {
|
|
962
|
+
context,
|
|
963
|
+
documentId,
|
|
964
|
+
sourcePath,
|
|
965
|
+
language,
|
|
966
|
+
parentName: symbol.containerName
|
|
967
|
+
});
|
|
968
|
+
const semanticTokens = document.semanticTokens ?? payload.semanticTokens;
|
|
969
|
+
if (semanticTokens) addLspSemanticTokens(result, semanticTokens, { context, documentId, sourcePath, language });
|
|
970
|
+
for (const diagnostic of normalizeArray(document.diagnostics ?? payload.diagnostics)) {
|
|
971
|
+
result.facts.push(externalDiagnosticFact(diagnostic, context, documentId, sourcePath, result.facts.length));
|
|
972
|
+
result.losses.push(externalDiagnosticLoss(diagnostic, context, sourcePath));
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
return withExternalEmptyLoss(result, context);
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
function normalizeSemanticDbPayload(payload, context) {
|
|
979
|
+
const result = externalSemanticBase(context, { sourceFormat: 'semanticdb' });
|
|
980
|
+
const documents = normalizeArray(payload.documents ?? payload.textDocuments ?? payload);
|
|
981
|
+
for (const [documentIndex, document] of documents.entries()) {
|
|
982
|
+
const sourcePath = uriToPath(document.uri) ?? document.uri ?? document.path ?? context.sourcePath ?? `semanticdb-document-${documentIndex + 1}`;
|
|
983
|
+
const language = normalizeExternalSemanticLanguage(document.language ?? context.language ?? 'scala');
|
|
984
|
+
const documentId = document.id ?? `doc_${idFragment(sourcePath)}`;
|
|
985
|
+
result.documents.push({
|
|
986
|
+
id: documentId,
|
|
987
|
+
path: sourcePath,
|
|
988
|
+
language,
|
|
989
|
+
sourceHash: document.md5 ?? document.sourceHash ?? context.sourceHash,
|
|
990
|
+
metadata: { format: 'semanticdb', schema: document.schema, documentIndex }
|
|
991
|
+
});
|
|
992
|
+
for (const [symbolIndex, symbolInfo] of normalizeArray(document.symbols).entries()) {
|
|
993
|
+
const symbolId = semanticDbSymbolId(symbolInfo.symbol, context, documentId);
|
|
994
|
+
result.symbols.push({
|
|
995
|
+
id: symbolId,
|
|
996
|
+
scheme: 'semanticdb',
|
|
997
|
+
name: symbolInfo.display_name ?? symbolInfo.displayName ?? nameFromExternalSymbol(symbolInfo.symbol),
|
|
998
|
+
kind: normalizeExternalSymbolKind(symbolInfo.kind),
|
|
999
|
+
language,
|
|
1000
|
+
signatureHash: hashSemanticValue(symbolInfo.signature ?? symbolInfo.signature_documentation ?? symbolInfo.signatureDocumentation ?? symbolInfo),
|
|
1001
|
+
metadata: { format: 'semanticdb', symbolIndex, rawSymbol: symbolInfo.symbol, properties: symbolInfo.properties }
|
|
1002
|
+
});
|
|
1003
|
+
result.facts.push(...semanticDbSymbolFacts(symbolInfo, symbolId));
|
|
1004
|
+
}
|
|
1005
|
+
for (const [occurrenceIndex, occurrence] of normalizeArray(document.occurrences).entries()) {
|
|
1006
|
+
const symbolId = semanticDbSymbolId(occurrence.symbol, context, documentId);
|
|
1007
|
+
if (!result.symbols.some((symbol) => symbol.id === symbolId)) {
|
|
1008
|
+
result.symbols.push({
|
|
1009
|
+
id: symbolId,
|
|
1010
|
+
scheme: 'semanticdb',
|
|
1011
|
+
name: nameFromExternalSymbol(occurrence.symbol),
|
|
1012
|
+
kind: 'symbol',
|
|
1013
|
+
language,
|
|
1014
|
+
metadata: { format: 'semanticdb', inferredFromOccurrence: true, rawSymbol: occurrence.symbol }
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
result.occurrences.push({
|
|
1018
|
+
id: occurrence.id ?? `occ_${idFragment(documentId)}_${occurrenceIndex + 1}`,
|
|
1019
|
+
documentId,
|
|
1020
|
+
symbolId,
|
|
1021
|
+
role: semanticDbOccurrenceRole(occurrence.role),
|
|
1022
|
+
span: spanFromSemanticDbRange(occurrence.range, sourcePath, document.md5 ?? context.sourceHash),
|
|
1023
|
+
metadata: { format: 'semanticdb', role: occurrence.role }
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
for (const diagnostic of normalizeArray(document.diagnostics)) {
|
|
1027
|
+
result.facts.push(externalDiagnosticFact(diagnostic, context, documentId, sourcePath, result.facts.length));
|
|
1028
|
+
result.losses.push(externalDiagnosticLoss(diagnostic, context, sourcePath));
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return withExternalEmptyLoss(result, context);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
function normalizeGenericExternalSemanticIndexPayload(payload, context) {
|
|
1035
|
+
const result = externalSemanticBase(context, { sourceFormat: context.format, genericPayload: true });
|
|
1036
|
+
result.losses.push({
|
|
1037
|
+
id: `loss_${context.idPart}_${idFragment(context.format)}_unsupported_payload`,
|
|
1038
|
+
severity: 'warning',
|
|
1039
|
+
phase: 'index',
|
|
1040
|
+
sourceFormat: context.format,
|
|
1041
|
+
kind: 'unsupportedSemantic',
|
|
1042
|
+
message: `External semantic index format ${context.format} is not recognized; payload hash is preserved as evidence only.`,
|
|
1043
|
+
metadata: { format: context.format, payloadHash: hashSemanticValue(payload) }
|
|
1044
|
+
});
|
|
1045
|
+
return result;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
function normalizeArray(value) {
|
|
1049
|
+
if (value === undefined || value === null) return [];
|
|
1050
|
+
return Array.isArray(value) ? value : [value];
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
function normalizeExternalSemanticLanguage(value) {
|
|
1054
|
+
if (value === undefined || value === null || value === '') return undefined;
|
|
1055
|
+
const raw = typeof value === 'number' ? externalLanguageNameByNumber[value] : String(value);
|
|
1056
|
+
return normalizeNativeLanguageId(raw);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
function externalDocument(document, context, index) {
|
|
1060
|
+
const path = document.path ?? document.uri ?? document.relative_path ?? document.relativePath ?? context.sourcePath ?? `external-document-${index + 1}`;
|
|
1061
|
+
return {
|
|
1062
|
+
id: document.id ?? `doc_${idFragment(path)}`,
|
|
1063
|
+
path: uriToPath(path) ?? path,
|
|
1064
|
+
language: normalizeExternalSemanticLanguage(document.language ?? document.languageId ?? context.language),
|
|
1065
|
+
sourceHash: document.sourceHash ?? document.md5 ?? context.sourceHash,
|
|
1066
|
+
metadata: { format: context.format, ...document.metadata }
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
function externalSymbol(symbol, context, index) {
|
|
1071
|
+
const id = symbol.id ?? symbol.symbolId ?? symbol.symbol ?? `symbol:${context.format}:${index + 1}`;
|
|
1072
|
+
return {
|
|
1073
|
+
...symbol,
|
|
1074
|
+
id: String(id),
|
|
1075
|
+
scheme: symbol.scheme ?? context.format,
|
|
1076
|
+
name: symbol.name ?? symbol.display_name ?? symbol.displayName ?? nameFromExternalSymbol(id),
|
|
1077
|
+
kind: normalizeExternalSymbolKind(symbol.kind),
|
|
1078
|
+
language: normalizeExternalSemanticLanguage(symbol.language ?? context.language),
|
|
1079
|
+
definitionSpan: normalizeExternalSpan(symbol.definitionSpan ?? symbol.span, context.sourcePath, context.sourceHash),
|
|
1080
|
+
metadata: { format: context.format, rawSymbol: symbol.symbol, ...symbol.metadata }
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
function externalOccurrence(occurrence, context, index) {
|
|
1085
|
+
return {
|
|
1086
|
+
...occurrence,
|
|
1087
|
+
id: occurrence.id ?? `occ_${context.idPart}_${index + 1}`,
|
|
1088
|
+
documentId: occurrence.documentId ?? occurrence.document_id ?? `doc_${idFragment(occurrence.path ?? context.sourcePath ?? context.format)}`,
|
|
1089
|
+
symbolId: occurrence.symbolId ?? occurrence.symbol_id ?? occurrence.symbol ?? `symbol:${context.format}:unknown`,
|
|
1090
|
+
role: normalizeExternalOccurrenceRole(occurrence.role),
|
|
1091
|
+
span: normalizeExternalSpan(occurrence.span ?? occurrence.range, occurrence.path ?? context.sourcePath, context.sourceHash),
|
|
1092
|
+
metadata: { format: context.format, ...occurrence.metadata }
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
function externalRelation(relation, context, index) {
|
|
1097
|
+
return {
|
|
1098
|
+
...relation,
|
|
1099
|
+
id: relation.id ?? `rel_${context.idPart}_${index + 1}`,
|
|
1100
|
+
sourceId: relation.sourceId ?? relation.source_id ?? relation.subjectId ?? relation.subject_id ?? `external:${context.format}`,
|
|
1101
|
+
predicate: relation.predicate ?? relation.label ?? relation.kind ?? 'related',
|
|
1102
|
+
targetId: relation.targetId ?? relation.target_id ?? relation.objectId ?? relation.object_id ?? relation.symbol ?? `external:${context.format}`,
|
|
1103
|
+
metadata: { format: context.format, ...relation.metadata }
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
function externalFact(fact, context, index) {
|
|
1108
|
+
return {
|
|
1109
|
+
...fact,
|
|
1110
|
+
id: fact.id ?? `fact_${context.idPart}_${index + 1}`,
|
|
1111
|
+
predicate: fact.predicate ?? fact.kind ?? 'externalFact',
|
|
1112
|
+
subjectId: fact.subjectId ?? fact.subject_id ?? fact.symbolId ?? fact.symbol_id ?? `external:${context.format}`,
|
|
1113
|
+
value: fact.value ?? fact.data ?? fact,
|
|
1114
|
+
metadata: { format: context.format, ...fact.metadata }
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
function externalSemanticEvidence(context, status, summary, metadata = {}) {
|
|
1119
|
+
return {
|
|
1120
|
+
id: `evidence_${context.idPart}_${idFragment(context.format)}_external_semantic_index`,
|
|
1121
|
+
kind: 'import',
|
|
1122
|
+
status,
|
|
1123
|
+
path: context.sourcePath,
|
|
1124
|
+
summary,
|
|
1125
|
+
metadata: {
|
|
1126
|
+
format: context.format,
|
|
1127
|
+
parser: context.parser,
|
|
1128
|
+
projectRoot: context.projectRoot,
|
|
1129
|
+
...metadata
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
function externalSemanticCoverageLoss(context) {
|
|
1135
|
+
return {
|
|
1136
|
+
id: `loss_${context.idPart}_${idFragment(context.format)}_partial_semantic_index`,
|
|
1137
|
+
severity: 'info',
|
|
1138
|
+
phase: 'index',
|
|
1139
|
+
sourceFormat: context.format,
|
|
1140
|
+
kind: 'partialSemanticIndex',
|
|
1141
|
+
message: `${context.format} payload imported symbols, occurrences, and facts as external semantic evidence; full parser AST, comments, trivia, and executable semantics still require a native parser adapter.`,
|
|
1142
|
+
semanticIndexId: context.semanticIndexId,
|
|
1143
|
+
metadata: {
|
|
1144
|
+
format: context.format,
|
|
1145
|
+
parser: context.parser,
|
|
1146
|
+
source: 'external-semantic-index'
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
function withExternalEmptyLoss(result, context) {
|
|
1152
|
+
if (!result.documents.length) {
|
|
1153
|
+
result.documents.push({
|
|
1154
|
+
id: `doc_${context.idPart}_${idFragment(context.format)}`,
|
|
1155
|
+
path: context.sourcePath ?? `${context.format}:memory`,
|
|
1156
|
+
language: context.language,
|
|
1157
|
+
sourceHash: context.sourceHash,
|
|
1158
|
+
metadata: { format: context.format, inferred: true }
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
if (!result.symbols.length && !result.occurrences.length) {
|
|
1162
|
+
result.losses.push({
|
|
1163
|
+
id: `loss_${context.idPart}_${idFragment(context.format)}_empty_semantic_index`,
|
|
1164
|
+
severity: 'warning',
|
|
1165
|
+
phase: 'index',
|
|
1166
|
+
sourceFormat: context.format,
|
|
1167
|
+
kind: 'partialSemanticIndex',
|
|
1168
|
+
message: `${context.format} payload did not contain symbols or occurrences that Frontier can map.`,
|
|
1169
|
+
metadata: { format: context.format }
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
attachExternalOwnership(result, context);
|
|
1173
|
+
result.symbols = uniqueRecordsById(result.symbols);
|
|
1174
|
+
result.occurrences = uniqueRecordsById(result.occurrences);
|
|
1175
|
+
result.relations = uniqueRecordsById(result.relations);
|
|
1176
|
+
result.facts = uniqueRecordsById(result.facts);
|
|
1177
|
+
result.losses = uniqueByLossId(result.losses);
|
|
1178
|
+
result.evidence = uniqueByEvidenceId(result.evidence);
|
|
1179
|
+
return result;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
function attachExternalOwnership(result, context) {
|
|
1183
|
+
const occurrencesBySymbol = new Map();
|
|
1184
|
+
for (const occurrence of result.occurrences) {
|
|
1185
|
+
if (!occurrencesBySymbol.has(occurrence.symbolId)) occurrencesBySymbol.set(occurrence.symbolId, []);
|
|
1186
|
+
occurrencesBySymbol.get(occurrence.symbolId).push(occurrence);
|
|
1187
|
+
result.relations.push({
|
|
1188
|
+
id: `rel_${idFragment(occurrence.documentId)}_${idFragment(occurrence.id)}_${idFragment(occurrence.role)}`,
|
|
1189
|
+
sourceId: occurrence.documentId,
|
|
1190
|
+
predicate: externalRelationPredicateForOccurrence(occurrence),
|
|
1191
|
+
targetId: occurrence.symbolId,
|
|
1192
|
+
metadata: {
|
|
1193
|
+
format: context.format,
|
|
1194
|
+
source: 'external-semantic-index',
|
|
1195
|
+
occurrenceId: occurrence.id,
|
|
1196
|
+
role: occurrence.role
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
result.symbols = result.symbols.map((symbol) => {
|
|
1201
|
+
const occurrences = occurrencesBySymbol.get(symbol.id) ?? [];
|
|
1202
|
+
const definition = occurrences.find((occurrence) => occurrence.role === 'definition') ?? occurrences[0];
|
|
1203
|
+
const sourceSpan = symbol.definitionSpan ?? definition?.span;
|
|
1204
|
+
const regionKind = semanticRegionKindForSymbol(symbol, undefined, undefined);
|
|
1205
|
+
const key = [
|
|
1206
|
+
'external',
|
|
1207
|
+
symbol.language ?? context.language ?? 'unknown',
|
|
1208
|
+
sourceSpan?.path ?? context.sourcePath ?? 'memory',
|
|
1209
|
+
regionKind,
|
|
1210
|
+
symbol.name ?? symbol.id
|
|
1211
|
+
].join('#');
|
|
1212
|
+
const region = {
|
|
1213
|
+
id: `region_${idFragment(key)}`,
|
|
1214
|
+
key,
|
|
1215
|
+
regionKind,
|
|
1216
|
+
granularity: 'symbol',
|
|
1217
|
+
language: symbol.language ?? context.language,
|
|
1218
|
+
documentId: definition?.documentId,
|
|
1219
|
+
sourcePath: sourceSpan?.path ?? context.sourcePath,
|
|
1220
|
+
sourceHash: context.sourceHash,
|
|
1221
|
+
symbolId: symbol.id,
|
|
1222
|
+
symbolName: symbol.name,
|
|
1223
|
+
symbolKind: symbol.kind,
|
|
1224
|
+
sourceSpan,
|
|
1225
|
+
precision: sourceSpan ? 'declaration' : 'unknown',
|
|
1226
|
+
mergePolicy: semanticRegionMergePolicy(regionKind),
|
|
1227
|
+
metadata: {
|
|
1228
|
+
format: context.format,
|
|
1229
|
+
source: 'external-semantic-index'
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
result.facts.push({
|
|
1233
|
+
id: `fact_${idFragment(symbol.id)}_ownership_region`,
|
|
1234
|
+
predicate: 'semanticOwnershipRegion',
|
|
1235
|
+
subjectId: symbol.id,
|
|
1236
|
+
value: region
|
|
1237
|
+
}, {
|
|
1238
|
+
id: `fact_${idFragment(symbol.id)}_ownership_region_taxonomy`,
|
|
1239
|
+
predicate: 'semanticOwnershipRegionTaxonomy',
|
|
1240
|
+
subjectId: symbol.id,
|
|
1241
|
+
value: {
|
|
1242
|
+
regionKind: region.regionKind,
|
|
1243
|
+
granularity: region.granularity,
|
|
1244
|
+
key: region.key
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
return {
|
|
1248
|
+
...symbol,
|
|
1249
|
+
definitionSpan: symbol.definitionSpan ?? definition?.span,
|
|
1250
|
+
metadata: {
|
|
1251
|
+
...symbol.metadata,
|
|
1252
|
+
ownershipRegionId: symbol.metadata?.ownershipRegionId ?? region.id,
|
|
1253
|
+
ownershipRegionKey: symbol.metadata?.ownershipRegionKey ?? region.key,
|
|
1254
|
+
ownershipRegionKind: symbol.metadata?.ownershipRegionKind ?? region.regionKind
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
function externalRelationPredicateForOccurrence(occurrence) {
|
|
1261
|
+
const role = String(occurrence.role ?? '').toLowerCase();
|
|
1262
|
+
if (role === 'definition' || role === 'declaration') return 'defines';
|
|
1263
|
+
if (role === 'import') return 'imports';
|
|
1264
|
+
if (role === 'write') return 'writes';
|
|
1265
|
+
if (role === 'read') return 'reads';
|
|
1266
|
+
return 'references';
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
function externalSemanticSourceMapMappings(semanticIndex, context) {
|
|
1270
|
+
const symbolsById = new Map((semanticIndex.symbols ?? []).map((symbol) => [symbol.id, symbol]));
|
|
1271
|
+
const evidenceIds = (context.evidence ?? []).map((record) => record.id).filter(Boolean);
|
|
1272
|
+
const lossIds = (context.losses ?? []).map((loss) => loss.id).filter(Boolean);
|
|
1273
|
+
return (semanticIndex.occurrences ?? [])
|
|
1274
|
+
.filter((occurrence) => occurrence.span)
|
|
1275
|
+
.map((occurrence, index) => {
|
|
1276
|
+
const symbol = symbolsById.get(occurrence.symbolId);
|
|
1277
|
+
return {
|
|
1278
|
+
id: `map_${idFragment(occurrence.id ?? `${occurrence.symbolId}_${index + 1}`)}`,
|
|
1279
|
+
semanticSymbolId: occurrence.symbolId,
|
|
1280
|
+
semanticOccurrenceId: occurrence.id,
|
|
1281
|
+
sourceSpan: occurrence.span,
|
|
1282
|
+
evidenceIds,
|
|
1283
|
+
lossIds,
|
|
1284
|
+
ownershipRegionId: symbol?.metadata?.ownershipRegionId,
|
|
1285
|
+
ownershipRegionKey: symbol?.metadata?.ownershipRegionKey,
|
|
1286
|
+
ownershipRegionKind: symbol?.metadata?.ownershipRegionKind,
|
|
1287
|
+
precision: occurrence.span ? 'declaration' : 'unknown',
|
|
1288
|
+
metadata: {
|
|
1289
|
+
source: 'external-semantic-index'
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
function scipSymbolId(symbol, context, documentId) {
|
|
1296
|
+
if (!symbol) return undefined;
|
|
1297
|
+
const raw = String(symbol);
|
|
1298
|
+
if (raw.startsWith('symbol:')) return raw;
|
|
1299
|
+
const scope = /^local\b/i.test(raw) ? `${documentId ?? context.idPart}:` : '';
|
|
1300
|
+
return `symbol:scip:${idFragment(scope + raw)}`;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
function semanticDbSymbolId(symbol, context, documentId) {
|
|
1304
|
+
if (!symbol) return `symbol:semanticdb:${context.idPart}:unknown`;
|
|
1305
|
+
if (String(symbol).startsWith('symbol:')) return String(symbol);
|
|
1306
|
+
const scope = /^local\d+$/i.test(String(symbol)) ? `${documentId}:` : '';
|
|
1307
|
+
return `symbol:semanticdb:${idFragment(scope + symbol)}`;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
function nameFromExternalSymbol(symbol) {
|
|
1311
|
+
const value = String(symbol ?? 'symbol');
|
|
1312
|
+
const cleaned = value
|
|
1313
|
+
.replace(/^symbol:[^:]+:/, '')
|
|
1314
|
+
.replace(/[`'"]/g, '')
|
|
1315
|
+
.split(/[\/#.:() +]+/)
|
|
1316
|
+
.filter(Boolean)
|
|
1317
|
+
.at(-1);
|
|
1318
|
+
return cleaned || value;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
const externalSymbolKindByNumber = Object.freeze({
|
|
1322
|
+
1: 'array',
|
|
1323
|
+
2: 'assertion',
|
|
1324
|
+
3: 'associatedType',
|
|
1325
|
+
4: 'attribute',
|
|
1326
|
+
7: 'class',
|
|
1327
|
+
8: 'constant',
|
|
1328
|
+
9: 'constructor',
|
|
1329
|
+
11: 'enum',
|
|
1330
|
+
12: 'enumMember',
|
|
1331
|
+
13: 'event',
|
|
1332
|
+
15: 'field',
|
|
1333
|
+
16: 'file',
|
|
1334
|
+
17: 'function',
|
|
1335
|
+
21: 'interface',
|
|
1336
|
+
25: 'macro',
|
|
1337
|
+
26: 'method',
|
|
1338
|
+
28: 'message',
|
|
1339
|
+
29: 'module',
|
|
1340
|
+
30: 'namespace',
|
|
1341
|
+
35: 'package',
|
|
1342
|
+
37: 'parameter',
|
|
1343
|
+
41: 'property',
|
|
1344
|
+
42: 'protocol',
|
|
1345
|
+
49: 'struct',
|
|
1346
|
+
53: 'trait',
|
|
1347
|
+
54: 'type',
|
|
1348
|
+
55: 'typeAlias',
|
|
1349
|
+
58: 'typeParameter',
|
|
1350
|
+
61: 'variable',
|
|
1351
|
+
66: 'abstractMethod'
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
const lspSymbolKindByNumber = Object.freeze({
|
|
1355
|
+
1: 'file',
|
|
1356
|
+
2: 'module',
|
|
1357
|
+
3: 'namespace',
|
|
1358
|
+
4: 'package',
|
|
1359
|
+
5: 'class',
|
|
1360
|
+
6: 'method',
|
|
1361
|
+
7: 'property',
|
|
1362
|
+
8: 'field',
|
|
1363
|
+
9: 'constructor',
|
|
1364
|
+
10: 'enum',
|
|
1365
|
+
11: 'interface',
|
|
1366
|
+
12: 'function',
|
|
1367
|
+
13: 'variable',
|
|
1368
|
+
14: 'constant',
|
|
1369
|
+
22: 'enumMember',
|
|
1370
|
+
23: 'struct',
|
|
1371
|
+
26: 'typeParameter'
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
const externalLanguageNameByNumber = Object.freeze({
|
|
1375
|
+
1: 'csharp',
|
|
1376
|
+
2: 'swift',
|
|
1377
|
+
3: 'dart',
|
|
1378
|
+
4: 'kotlin',
|
|
1379
|
+
5: 'scala',
|
|
1380
|
+
6: 'java',
|
|
1381
|
+
15: 'python',
|
|
1382
|
+
16: 'ruby',
|
|
1383
|
+
17: 'elixir',
|
|
1384
|
+
18: 'erlang',
|
|
1385
|
+
19: 'php',
|
|
1386
|
+
22: 'javascript',
|
|
1387
|
+
23: 'typescript',
|
|
1388
|
+
33: 'go',
|
|
1389
|
+
34: 'c',
|
|
1390
|
+
35: 'cpp',
|
|
1391
|
+
38: 'zig',
|
|
1392
|
+
40: 'rust',
|
|
1393
|
+
44: 'haskell',
|
|
1394
|
+
54: 'r',
|
|
1395
|
+
69: 'sql'
|
|
1396
|
+
});
|
|
1397
|
+
|
|
1398
|
+
function normalizeExternalSymbolKind(kind) {
|
|
1399
|
+
if (kind === undefined || kind === null || kind === '') return 'symbol';
|
|
1400
|
+
if (typeof kind === 'number') return externalSymbolKindByNumber[kind] ?? lspSymbolKindByNumber[kind] ?? `kind${kind}`;
|
|
1401
|
+
return String(kind).replace(/^[A-Z_]+_/, '').replace(/^[A-Z]/, (letter) => letter.toLowerCase());
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
function normalizeLspSymbolKind(kind) {
|
|
1405
|
+
if (typeof kind === 'number') return lspSymbolKindByNumber[kind] ?? `kind${kind}`;
|
|
1406
|
+
return normalizeExternalSymbolKind(kind);
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
function scipSyntaxKind(kind) {
|
|
1410
|
+
const normalized = typeof kind === 'number' ? kind : Number(kind);
|
|
1411
|
+
if (normalized === 15 || normalized === 16) return 'function';
|
|
1412
|
+
if (normalized === 19 || normalized === 20) return 'type';
|
|
1413
|
+
if (normalized === 25 || normalized === 26) return 'module';
|
|
1414
|
+
if (normalized === 9 || normalized === 10 || normalized === 12) return 'variable';
|
|
1415
|
+
return 'symbol';
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function normalizeExternalOccurrenceRole(role) {
|
|
1419
|
+
const value = String(role ?? 'reference').toLowerCase();
|
|
1420
|
+
if (value.includes('def')) return 'definition';
|
|
1421
|
+
if (value.includes('decl')) return 'declaration';
|
|
1422
|
+
if (value.includes('import')) return 'import';
|
|
1423
|
+
if (value.includes('write')) return 'write';
|
|
1424
|
+
if (value.includes('read')) return 'read';
|
|
1425
|
+
return value === '2' ? 'definition' : value === '1' ? 'reference' : 'reference';
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
function scipOccurrenceRole(value) {
|
|
1429
|
+
const role = Number(value ?? 0);
|
|
1430
|
+
if ((role & 0x1) > 0) return 'definition';
|
|
1431
|
+
if ((role & 0x2) > 0) return 'import';
|
|
1432
|
+
if ((role & 0x4) > 0) return 'write';
|
|
1433
|
+
if ((role & 0x8) > 0) return 'read';
|
|
1434
|
+
return 'reference';
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
function scipOccurrenceRoleSet(value) {
|
|
1438
|
+
const role = Number(value ?? 0);
|
|
1439
|
+
const roles = [];
|
|
1440
|
+
if ((role & 0x1) > 0) roles.push('definition');
|
|
1441
|
+
if ((role & 0x2) > 0) roles.push('import');
|
|
1442
|
+
if ((role & 0x4) > 0) roles.push('write');
|
|
1443
|
+
if ((role & 0x8) > 0) roles.push('read');
|
|
1444
|
+
if ((role & 0x10) > 0) roles.push('generated');
|
|
1445
|
+
if ((role & 0x20) > 0) roles.push('test');
|
|
1446
|
+
if ((role & 0x40) > 0) roles.push('forwardDefinition');
|
|
1447
|
+
return roles.length ? roles : ['reference'];
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
function semanticDbOccurrenceRole(value) {
|
|
1451
|
+
const role = String(value ?? 'reference').toLowerCase();
|
|
1452
|
+
if (role === '2' || role.includes('definition')) return 'definition';
|
|
1453
|
+
return 'reference';
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
function scipRelationshipRelations(symbolInfo, symbolId, context) {
|
|
1457
|
+
return normalizeArray(symbolInfo.relationships).flatMap((relationship, index) => {
|
|
1458
|
+
const targetId = scipSymbolId(relationship.symbol, context);
|
|
1459
|
+
if (!targetId) return [];
|
|
1460
|
+
const predicates = [];
|
|
1461
|
+
if (relationship.is_reference ?? relationship.isReference) predicates.push('references');
|
|
1462
|
+
if (relationship.is_implementation ?? relationship.isImplementation) predicates.push('implements');
|
|
1463
|
+
if (relationship.is_type_definition ?? relationship.isTypeDefinition) predicates.push('typeDefinition');
|
|
1464
|
+
if (relationship.is_definition ?? relationship.isDefinition) predicates.push('definitionOf');
|
|
1465
|
+
return (predicates.length ? predicates : ['related']).map((predicate) => ({
|
|
1466
|
+
id: `rel_${idFragment(symbolId)}_${idFragment(targetId)}_${idFragment(predicate)}_${index + 1}`,
|
|
1467
|
+
sourceId: symbolId,
|
|
1468
|
+
predicate,
|
|
1469
|
+
targetId,
|
|
1470
|
+
metadata: { format: 'scip', relationship }
|
|
1471
|
+
}));
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
function scipSymbolFacts(symbolInfo, symbolId) {
|
|
1476
|
+
const facts = [];
|
|
1477
|
+
if (symbolInfo.documentation) {
|
|
1478
|
+
facts.push({
|
|
1479
|
+
id: `fact_${idFragment(symbolId)}_documentation`,
|
|
1480
|
+
predicate: 'documentation',
|
|
1481
|
+
subjectId: symbolId,
|
|
1482
|
+
value: normalizeArray(symbolInfo.documentation)
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
const signature = symbolInfo.signature_documentation ?? symbolInfo.signatureDocumentation;
|
|
1486
|
+
if (signature) {
|
|
1487
|
+
facts.push({
|
|
1488
|
+
id: `fact_${idFragment(symbolId)}_signature`,
|
|
1489
|
+
predicate: 'signature',
|
|
1490
|
+
subjectId: symbolId,
|
|
1491
|
+
value: signature
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
for (const [index, relationship] of normalizeArray(symbolInfo.relationships).entries()) {
|
|
1495
|
+
facts.push({
|
|
1496
|
+
id: `fact_${idFragment(symbolId)}_relationship_${index + 1}`,
|
|
1497
|
+
predicate: 'relationship',
|
|
1498
|
+
subjectId: symbolId,
|
|
1499
|
+
value: relationship
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
return facts;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
function semanticDbSymbolFacts(symbolInfo, symbolId) {
|
|
1506
|
+
const facts = [];
|
|
1507
|
+
for (const key of ['signature', 'properties', 'annotations', 'access', 'language']) {
|
|
1508
|
+
if (symbolInfo[key] !== undefined) {
|
|
1509
|
+
facts.push({
|
|
1510
|
+
id: `fact_${idFragment(symbolId)}_${idFragment(key)}`,
|
|
1511
|
+
predicate: key,
|
|
1512
|
+
subjectId: symbolId,
|
|
1513
|
+
value: symbolInfo[key]
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
return facts;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
function normalizeLspDocuments(payload, context) {
|
|
1521
|
+
if (Array.isArray(payload.documents)) return payload.documents;
|
|
1522
|
+
if (payload.textDocument || payload.uri || payload.documentSymbols || payload.symbols || payload.semanticTokens || payload.diagnostics) {
|
|
1523
|
+
return [{
|
|
1524
|
+
...payload,
|
|
1525
|
+
uri: payload.uri ?? payload.textDocument?.uri,
|
|
1526
|
+
languageId: payload.languageId ?? payload.language ?? context.language,
|
|
1527
|
+
documentSymbols: payload.documentSymbols,
|
|
1528
|
+
symbols: payload.symbols,
|
|
1529
|
+
semanticTokens: payload.semanticTokens,
|
|
1530
|
+
diagnostics: payload.diagnostics
|
|
1531
|
+
}];
|
|
1532
|
+
}
|
|
1533
|
+
return [{ uri: context.sourcePath, languageId: context.language }];
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
function addLspSymbol(result, symbol, input) {
|
|
1537
|
+
const location = symbol.location ?? {};
|
|
1538
|
+
const range = symbol.range ?? location.range ?? symbol.selectionRange;
|
|
1539
|
+
const sourcePath = uriToPath(location.uri ?? symbol.uri) ?? input.sourcePath;
|
|
1540
|
+
const symbolName = symbol.name ?? symbol.containerName ?? `symbol_${result.symbols.length + 1}`;
|
|
1541
|
+
const symbolId = symbol.id ?? `symbol:lsp:${idFragment(input.language ?? 'unknown')}:${idFragment([input.parentName, symbolName].filter(Boolean).join('.'))}`;
|
|
1542
|
+
const ownershipSpan = spanFromLspRange(range, sourcePath, input.context.sourceHash, 0);
|
|
1543
|
+
const selectionSpan = spanFromLspRange(symbol.selectionRange ?? range, sourcePath, input.context.sourceHash, 0);
|
|
1544
|
+
if (!result.symbols.some((entry) => entry.id === symbolId)) {
|
|
1545
|
+
result.symbols.push({
|
|
1546
|
+
id: symbolId,
|
|
1547
|
+
scheme: 'lsp',
|
|
1548
|
+
name: symbolName,
|
|
1549
|
+
kind: normalizeLspSymbolKind(symbol.kind),
|
|
1550
|
+
language: input.language,
|
|
1551
|
+
definitionSpan: ownershipSpan,
|
|
1552
|
+
signatureHash: hashSemanticValue([symbolName, symbol.kind, symbol.detail]),
|
|
1553
|
+
metadata: {
|
|
1554
|
+
format: 'lsp',
|
|
1555
|
+
detail: symbol.detail,
|
|
1556
|
+
tags: symbol.tags,
|
|
1557
|
+
deprecated: symbol.deprecated,
|
|
1558
|
+
containerName: symbol.containerName,
|
|
1559
|
+
parentName: input.parentName
|
|
1560
|
+
}
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
result.occurrences.push({
|
|
1564
|
+
id: `occ_${idFragment(symbolId)}_${result.occurrences.length + 1}`,
|
|
1565
|
+
documentId: input.documentId,
|
|
1566
|
+
symbolId,
|
|
1567
|
+
role: 'definition',
|
|
1568
|
+
span: selectionSpan,
|
|
1569
|
+
metadata: { format: 'lsp', range, selectionRange: symbol.selectionRange }
|
|
1570
|
+
});
|
|
1571
|
+
for (const child of normalizeArray(symbol.children)) {
|
|
1572
|
+
addLspSymbol(result, child, {
|
|
1573
|
+
...input,
|
|
1574
|
+
parentName: [input.parentName, symbolName].filter(Boolean).join('.')
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
function addLspSemanticTokens(result, semanticTokens, input) {
|
|
1580
|
+
const data = normalizeArray(semanticTokens.data);
|
|
1581
|
+
const legend = semanticTokens.legend ?? {};
|
|
1582
|
+
let line = 0;
|
|
1583
|
+
let character = 0;
|
|
1584
|
+
for (let index = 0; index + 4 < data.length; index += 5) {
|
|
1585
|
+
line += Number(data[index] ?? 0);
|
|
1586
|
+
character = Number(data[index] ?? 0) === 0 ? character + Number(data[index + 1] ?? 0) : Number(data[index + 1] ?? 0);
|
|
1587
|
+
const length = Number(data[index + 2] ?? 0);
|
|
1588
|
+
const tokenType = legend.tokenTypes?.[Number(data[index + 3] ?? 0)] ?? `tokenType${data[index + 3] ?? 0}`;
|
|
1589
|
+
const span = {
|
|
1590
|
+
path: input.sourcePath,
|
|
1591
|
+
startLine: line + 1,
|
|
1592
|
+
startColumn: character + 1,
|
|
1593
|
+
endLine: line + 1,
|
|
1594
|
+
endColumn: character + length + 1
|
|
1595
|
+
};
|
|
1596
|
+
result.facts.push({
|
|
1597
|
+
id: `fact_${idFragment(input.documentId)}_semantic_token_${index / 5 + 1}`,
|
|
1598
|
+
predicate: 'semanticToken',
|
|
1599
|
+
subjectId: input.documentId,
|
|
1600
|
+
value: {
|
|
1601
|
+
tokenType,
|
|
1602
|
+
tokenModifiers: semanticTokenModifiers(Number(data[index + 4] ?? 0), legend.tokenModifiers),
|
|
1603
|
+
span
|
|
1604
|
+
},
|
|
1605
|
+
metadata: { format: 'lsp' }
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
function semanticTokenModifiers(bitset, modifiers = []) {
|
|
1611
|
+
const result = [];
|
|
1612
|
+
for (let index = 0; index < modifiers.length; index += 1) {
|
|
1613
|
+
if ((bitset & (1 << index)) > 0) result.push(modifiers[index]);
|
|
1614
|
+
}
|
|
1615
|
+
return result;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
function externalDiagnosticFact(diagnostic, context, documentId, sourcePath, index) {
|
|
1619
|
+
return {
|
|
1620
|
+
id: diagnostic.id ? `fact_${idFragment(diagnostic.id)}_diagnostic` : `fact_${context.idPart}_${idFragment(sourcePath)}_diagnostic_${index + 1}`,
|
|
1621
|
+
predicate: `${context.format}.diagnostic`,
|
|
1622
|
+
subjectId: documentId,
|
|
1623
|
+
value: {
|
|
1624
|
+
severity: diagnostic.severity,
|
|
1625
|
+
code: diagnostic.code,
|
|
1626
|
+
message: diagnostic.message,
|
|
1627
|
+
source: diagnostic.source,
|
|
1628
|
+
tags: diagnostic.tags,
|
|
1629
|
+
range: diagnostic.range,
|
|
1630
|
+
span: normalizeExternalSpan(diagnostic.range ?? diagnostic.span, sourcePath, context.sourceHash)
|
|
1631
|
+
},
|
|
1632
|
+
metadata: {
|
|
1633
|
+
format: context.format,
|
|
1634
|
+
source: 'external-semantic-index'
|
|
1635
|
+
}
|
|
1636
|
+
};
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
function externalDiagnosticLoss(diagnostic, context, sourcePath) {
|
|
1640
|
+
const severity = externalDiagnosticSeverity(diagnostic.severity);
|
|
1641
|
+
return {
|
|
1642
|
+
id: diagnostic.id ?? `loss_${context.idPart}_${idFragment(diagnostic.code ?? diagnostic.message ?? severity)}_${idFragment(sourcePath)}`,
|
|
1643
|
+
severity,
|
|
1644
|
+
phase: 'index',
|
|
1645
|
+
sourceFormat: context.format,
|
|
1646
|
+
kind: severity === 'error' ? 'unsupportedSemantic' : 'partialSemanticIndex',
|
|
1647
|
+
message: String(diagnostic.message ?? `${context.format} diagnostic reported ${severity}.`),
|
|
1648
|
+
span: normalizeExternalSpan(diagnostic.range ?? diagnostic.span, sourcePath, context.sourceHash),
|
|
1649
|
+
metadata: {
|
|
1650
|
+
format: context.format,
|
|
1651
|
+
code: diagnostic.code,
|
|
1652
|
+
source: diagnostic.source,
|
|
1653
|
+
tags: diagnostic.tags
|
|
1654
|
+
}
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
function externalDiagnosticSeverity(value) {
|
|
1659
|
+
if (value === undefined || value === null || value === '') return 'error';
|
|
1660
|
+
const raw = String(value).toLowerCase();
|
|
1661
|
+
if (raw === '1' || raw.includes('error')) return 'error';
|
|
1662
|
+
if (raw === '3' || raw.includes('info') || raw.includes('hint')) return 'info';
|
|
1663
|
+
return 'warning';
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
function spanFromScipOccurrence(occurrence, sourcePath, sourceHash) {
|
|
1667
|
+
if (occurrence.single_line_range || occurrence.singleLineRange) {
|
|
1668
|
+
const range = occurrence.single_line_range ?? occurrence.singleLineRange;
|
|
1669
|
+
return {
|
|
1670
|
+
sourceId: sourceHash,
|
|
1671
|
+
path: sourcePath,
|
|
1672
|
+
startLine: Number(range.line ?? 0) + 1,
|
|
1673
|
+
startColumn: Number(range.start_character ?? range.startCharacter ?? 0) + 1,
|
|
1674
|
+
endLine: Number(range.line ?? 0) + 1,
|
|
1675
|
+
endColumn: Number(range.end_character ?? range.endCharacter ?? 0) + 1
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
if (occurrence.multi_line_range || occurrence.multiLineRange) {
|
|
1679
|
+
const range = occurrence.multi_line_range ?? occurrence.multiLineRange;
|
|
1680
|
+
return {
|
|
1681
|
+
sourceId: sourceHash,
|
|
1682
|
+
path: sourcePath,
|
|
1683
|
+
startLine: Number(range.start_line ?? range.startLine ?? 0) + 1,
|
|
1684
|
+
startColumn: Number(range.start_character ?? range.startCharacter ?? 0) + 1,
|
|
1685
|
+
endLine: Number(range.end_line ?? range.endLine ?? 0) + 1,
|
|
1686
|
+
endColumn: Number(range.end_character ?? range.endCharacter ?? 0) + 1
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
const range = occurrence.range;
|
|
1690
|
+
if (Array.isArray(range) && range.length >= 3) {
|
|
1691
|
+
const startLine = Number(range[0] ?? 0);
|
|
1692
|
+
const startColumn = Number(range[1] ?? 0);
|
|
1693
|
+
const endLine = range.length >= 4 ? Number(range[2] ?? startLine) : startLine;
|
|
1694
|
+
const endColumn = range.length >= 4 ? Number(range[3] ?? startColumn) : Number(range[2] ?? startColumn);
|
|
1695
|
+
return {
|
|
1696
|
+
sourceId: sourceHash,
|
|
1697
|
+
path: sourcePath,
|
|
1698
|
+
startLine: startLine + 1,
|
|
1699
|
+
startColumn: startColumn + 1,
|
|
1700
|
+
endLine: endLine + 1,
|
|
1701
|
+
endColumn: endColumn + 1
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
return undefined;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
function spanFromSemanticDbRange(range, sourcePath, sourceHash) {
|
|
1708
|
+
if (!range) return undefined;
|
|
1709
|
+
return {
|
|
1710
|
+
sourceId: sourceHash,
|
|
1711
|
+
path: sourcePath,
|
|
1712
|
+
startLine: Number(range.start_line ?? range.startLine ?? 0) + 1,
|
|
1713
|
+
startColumn: Number(range.start_character ?? range.startCharacter ?? 0) + 1,
|
|
1714
|
+
endLine: Number(range.end_line ?? range.endLine ?? 0) + 1,
|
|
1715
|
+
endColumn: Number(range.end_character ?? range.endCharacter ?? 0) + 1
|
|
1716
|
+
};
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
function spanFromLspRange(range, sourcePath, sourceHash, base = 0) {
|
|
1720
|
+
if (!range) return undefined;
|
|
1721
|
+
const source = range.start && range.end ? range : { start: range, end: range.end ?? range };
|
|
1722
|
+
return {
|
|
1723
|
+
sourceId: sourceHash,
|
|
1724
|
+
path: sourcePath,
|
|
1725
|
+
startLine: Number(source.start?.line ?? source.startLine ?? 0) + (base === 0 ? 1 : 0),
|
|
1726
|
+
startColumn: Number(source.start?.character ?? source.startColumn ?? 0) + (base === 0 ? 1 : 0),
|
|
1727
|
+
endLine: Number(source.end?.line ?? source.endLine ?? source.start?.line ?? 0) + (base === 0 ? 1 : 0),
|
|
1728
|
+
endColumn: Number(source.end?.character ?? source.endColumn ?? source.start?.character ?? 0) + (base === 0 ? 1 : 0)
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
function normalizeExternalSpan(value, sourcePath, sourceHash) {
|
|
1733
|
+
if (!value) return undefined;
|
|
1734
|
+
if (Array.isArray(value)) {
|
|
1735
|
+
return spanFromScipOccurrence({ range: value }, sourcePath, sourceHash);
|
|
1736
|
+
}
|
|
1737
|
+
if (value.start || value.end || value.line !== undefined) return spanFromLspRange(value, sourcePath, sourceHash, 0);
|
|
1738
|
+
if (value.startLine !== undefined || value.start_line !== undefined) {
|
|
1739
|
+
return {
|
|
1740
|
+
sourceId: value.sourceId ?? sourceHash,
|
|
1741
|
+
path: value.path ?? sourcePath,
|
|
1742
|
+
start: value.start,
|
|
1743
|
+
end: value.end,
|
|
1744
|
+
startLine: Number(value.startLine ?? value.start_line),
|
|
1745
|
+
startColumn: value.startColumn ?? value.start_character,
|
|
1746
|
+
endLine: value.endLine ?? value.end_line,
|
|
1747
|
+
endColumn: value.endColumn ?? value.end_character
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
return undefined;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
function uriToPath(uri) {
|
|
1754
|
+
if (typeof uri !== 'string') return undefined;
|
|
1755
|
+
if (uri.startsWith('file://')) {
|
|
1756
|
+
try {
|
|
1757
|
+
return decodeURIComponent(new URL(uri).pathname);
|
|
1758
|
+
} catch {
|
|
1759
|
+
return uri.replace(/^file:\/\//, '');
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
return uri;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
547
1765
|
export function projectFrontierAst(document, target = 'typescript', options = {}) {
|
|
548
1766
|
const normalized = normalizeCompileTarget(target);
|
|
549
1767
|
const projector = projectors[normalized];
|