"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.transformCallHierarchyItem = transformCallHierarchyItem; exports.transformDiagnostic = transformDiagnostic; exports.fillSourceFileText = fillSourceFileText; exports.transformFileTextChanges = transformFileTextChanges; exports.transformDocumentSpan = transformDocumentSpan; exports.transformSpan = transformSpan; exports.transformTextChange = transformTextChange; exports.transformTextSpan = transformTextSpan; exports.toSourceOffset = toSourceOffset; exports.toSourceRanges = toSourceRanges; exports.toSourceOffsets = toSourceOffsets; exports.toGeneratedRanges = toGeneratedRanges; exports.toGeneratedOffset = toGeneratedOffset; exports.toGeneratedOffsets = toGeneratedOffsets; exports.getMappingOffset = getMappingOffset; const language_core_1 = require("@volar/language-core"); const utils_1 = require("./utils"); const transformedDiagnostics = new WeakMap(); const transformedSourceFile = new WeakSet(); function transformCallHierarchyItem(language, item, fallbackToAnyMatch, filter) { const span = transformSpan(language, item.file, item.span, fallbackToAnyMatch, filter); const selectionSpan = transformSpan(language, item.file, item.selectionSpan, fallbackToAnyMatch, filter); return { ...item, file: span?.fileName ?? item.file, span: span?.textSpan ?? { start: 0, length: 0 }, selectionSpan: selectionSpan?.textSpan ?? { start: 0, length: 0 }, }; } function transformDiagnostic(language, diagnostic, program, isTsc) { if (!transformedDiagnostics.has(diagnostic)) { transformedDiagnostics.set(diagnostic, undefined); const { relatedInformation } = diagnostic; if (relatedInformation) { diagnostic.relatedInformation = relatedInformation .map(d => transformDiagnostic(language, d, program, isTsc)) .filter(d => !!d); } if (diagnostic.file !== undefined && diagnostic.start !== undefined && diagnostic.length !== undefined) { const [serviceScript] = (0, utils_1.getServiceScript)(language, diagnostic.file.fileName); if (serviceScript) { const [sourceSpanFileName, sourceSpan] = transformTextSpan(undefined, language, serviceScript, { start: diagnostic.start, length: diagnostic.length }, true, data => (0, language_core_1.shouldReportDiagnostics)(data, String(diagnostic.source), String(diagnostic.code))) ?? []; const actualDiagnosticFile = sourceSpanFileName ? diagnostic.file.fileName === sourceSpanFileName ? diagnostic.file : program?.getSourceFile(sourceSpanFileName) : undefined; if (sourceSpan && actualDiagnosticFile) { if (isTsc) { fillSourceFileText(language, diagnostic.file); } transformedDiagnostics.set(diagnostic, { ...diagnostic, file: actualDiagnosticFile, start: sourceSpan.start, length: sourceSpan.length, }); } } else { transformedDiagnostics.set(diagnostic, diagnostic); } } else { transformedDiagnostics.set(diagnostic, diagnostic); } } return transformedDiagnostics.get(diagnostic); } // fix https://github.com/vuejs/language-tools/issues/4099 without `incremental` function fillSourceFileText(language, sourceFile) { if (transformedSourceFile.has(sourceFile)) { return; } transformedSourceFile.add(sourceFile); const [serviceScript] = (0, utils_1.getServiceScript)(language, sourceFile.fileName); if (serviceScript && !serviceScript.preventLeadingOffset) { const sourceScript = language.scripts.fromVirtualCode(serviceScript.code); sourceFile.text = sourceScript.snapshot.getText(0, sourceScript.snapshot.getLength()) + sourceFile.text.substring(sourceScript.snapshot.getLength()); } } function transformFileTextChanges(language, changes, fallbackToAnyMatch, filter) { const changesPerFile = {}; const newFiles = new Set(); for (const fileChanges of changes) { const [_, source] = (0, utils_1.getServiceScript)(language, fileChanges.fileName); if (source) { fileChanges.textChanges.forEach(c => { const { fileName, textSpan } = transformSpan(language, fileChanges.fileName, c.span, fallbackToAnyMatch, filter) ?? {}; if (fileName && textSpan) { (changesPerFile[fileName] ?? (changesPerFile[fileName] = [])).push({ ...c, span: textSpan }); } }); } else { const list = (changesPerFile[fileChanges.fileName] ?? (changesPerFile[fileChanges.fileName] = [])); fileChanges.textChanges.forEach(c => { list.push(c); }); if (fileChanges.isNewFile) { newFiles.add(fileChanges.fileName); } } } const result = []; for (const fileName in changesPerFile) { result.push({ fileName, isNewFile: newFiles.has(fileName), textChanges: changesPerFile[fileName] }); } return result; } function transformDocumentSpan(language, documentSpan, fallbackToAnyMatch, filter, shouldFallback) { let textSpan = transformSpan(language, documentSpan.fileName, documentSpan.textSpan, fallbackToAnyMatch, filter); if (!textSpan && shouldFallback) { textSpan = { fileName: documentSpan.fileName, textSpan: { start: 0, length: 0 }, }; } if (!textSpan) { return; } const contextSpan = transformSpan(language, documentSpan.fileName, documentSpan.contextSpan, fallbackToAnyMatch, filter); const originalTextSpan = transformSpan(language, documentSpan.originalFileName, documentSpan.originalTextSpan, fallbackToAnyMatch, filter); const originalContextSpan = transformSpan(language, documentSpan.originalFileName, documentSpan.originalContextSpan, fallbackToAnyMatch, filter); return { ...documentSpan, fileName: textSpan.fileName, textSpan: textSpan.textSpan, contextSpan: contextSpan?.textSpan, originalFileName: originalTextSpan?.fileName, originalTextSpan: originalTextSpan?.textSpan, originalContextSpan: originalContextSpan?.textSpan, }; } function transformSpan(language, fileName, textSpan, fallbackToAnyMatch, filter) { if (!fileName || !textSpan) { return; } const [serviceScript] = (0, utils_1.getServiceScript)(language, fileName); if (serviceScript) { const [sourceSpanFileName, sourceSpan] = transformTextSpan(undefined, language, serviceScript, textSpan, fallbackToAnyMatch, filter) ?? []; if (sourceSpan && sourceSpanFileName) { return { fileName: sourceSpanFileName, textSpan: sourceSpan, }; } } else { return { fileName, textSpan, }; } } function transformTextChange(sourceScript, language, serviceScript, textChange, fallbackToAnyMatch, filter) { const [sourceSpanFileName, sourceSpan] = transformTextSpan(sourceScript, language, serviceScript, textChange.span, fallbackToAnyMatch, filter) ?? []; if (sourceSpan && sourceSpanFileName) { return [sourceSpanFileName, { newText: textChange.newText, span: sourceSpan, }]; } return undefined; } function transformTextSpan(sourceScript, language, serviceScript, textSpan, fallbackToAnyMatch, filter) { const start = textSpan.start; const end = textSpan.start + textSpan.length; for (const [fileName, sourceStart, sourceEnd] of toSourceRanges(sourceScript, language, serviceScript, start, end, fallbackToAnyMatch, filter)) { return [fileName, { start: sourceStart, length: sourceEnd - sourceStart, }]; } } function toSourceOffset(sourceScript, language, serviceScript, position, filter) { for (const source of toSourceOffsets(sourceScript, language, serviceScript, position, filter)) { return source; } } function* toSourceRanges(sourceScript, language, serviceScript, start, end, fallbackToAnyMatch, filter) { if (sourceScript) { const map = language.maps.get(serviceScript.code, sourceScript); for (const [sourceStart, sourceEnd] of map.toSourceRange(start - getMappingOffset(language, serviceScript), end - getMappingOffset(language, serviceScript), fallbackToAnyMatch, filter)) { yield [sourceScript.id, sourceStart, sourceEnd]; } } else { for (const [sourceScript, map] of language.maps.forEach(serviceScript.code)) { for (const [sourceStart, sourceEnd] of map.toSourceRange(start - getMappingOffset(language, serviceScript), end - getMappingOffset(language, serviceScript), fallbackToAnyMatch, filter)) { yield [sourceScript.id, sourceStart, sourceEnd]; } } } } function* toSourceOffsets(sourceScript, language, serviceScript, position, filter) { if (sourceScript) { const map = language.maps.get(serviceScript.code, sourceScript); for (const [sourceOffset, mapping] of map.toSourceLocation(position - getMappingOffset(language, serviceScript))) { if (filter(mapping.data)) { yield [sourceScript.id, sourceOffset]; } } } else { for (const [sourceScript, map] of language.maps.forEach(serviceScript.code)) { for (const [sourceOffset, mapping] of map.toSourceLocation(position - getMappingOffset(language, serviceScript))) { if (filter(mapping.data)) { yield [sourceScript.id, sourceOffset]; } } } } } function* toGeneratedRanges(language, serviceScript, sourceScript, start, end, filter) { const map = language.maps.get(serviceScript.code, sourceScript); for (const [generateStart, generateEnd] of map.toGeneratedRange(start, end, true, filter)) { yield [ generateStart + getMappingOffset(language, serviceScript), generateEnd + getMappingOffset(language, serviceScript), ]; } } function toGeneratedOffset(language, serviceScript, sourceScript, position, filter) { for (const [generateOffset] of toGeneratedOffsets(language, serviceScript, sourceScript, position, filter)) { return generateOffset; } } function* toGeneratedOffsets(language, serviceScript, sourceScript, position, filter) { const map = language.maps.get(serviceScript.code, sourceScript); for (const [generateOffset, mapping] of map.toGeneratedLocation(position)) { if (filter(mapping.data)) { yield [generateOffset + getMappingOffset(language, serviceScript), mapping]; } } } function getMappingOffset(language, serviceScript) { if (serviceScript.preventLeadingOffset) { return 0; } const sourceScript = language.scripts.fromVirtualCode(serviceScript.code); return sourceScript.snapshot.getLength(); } //# sourceMappingURL=transform.js.map