File: /var/www/design.system/node_modules/@volar/typescript/lib/node/transform.js
"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();
/**
* This file contains a number of facilities for transforming `ts.Diagnostic`s returned
* from the base TypeScript LanguageService, which reference locations in generated
* TS code (e.g. the TypeScript codegen'd from the script portion of a .vue file) into locations
* in the script portion of the .vue file.
*/
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