svelte-language-server
Version:
A language server for Svelte
258 lines • 10.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SourceMapDocumentMapper = exports.FragmentMapper = exports.IdentityMapper = void 0;
exports.mapRangeToOriginal = mapRangeToOriginal;
exports.mapLocationToOriginal = mapLocationToOriginal;
exports.mapRangeToGenerated = mapRangeToGenerated;
exports.mapCompletionItemToOriginal = mapCompletionItemToOriginal;
exports.mapHoverToParent = mapHoverToParent;
exports.mapObjWithRangeToOriginal = mapObjWithRangeToOriginal;
exports.mapInsertReplaceEditToOriginal = mapInsertReplaceEditToOriginal;
exports.mapEditToOriginal = mapEditToOriginal;
exports.mapDiagnosticToGenerated = mapDiagnosticToGenerated;
exports.mapColorPresentationToOriginal = mapColorPresentationToOriginal;
exports.mapSymbolInformationToOriginal = mapSymbolInformationToOriginal;
exports.mapLocationLinkToOriginal = mapLocationLinkToOriginal;
exports.mapTextDocumentEditToOriginal = mapTextDocumentEditToOriginal;
exports.mapCodeActionToOriginal = mapCodeActionToOriginal;
exports.mapSelectionRangeToParent = mapSelectionRangeToParent;
const vscode_languageserver_1 = require("vscode-languageserver");
const utils_1 = require("./utils");
const logger_1 = require("../../logger");
const trace_mapping_1 = require("@jridgewell/trace-mapping");
/**
* Does not map, returns positions as is.
*/
class IdentityMapper {
constructor(url, parent) {
this.url = url;
this.parent = parent;
}
getOriginalPosition(generatedPosition) {
if (this.parent) {
generatedPosition = this.getOriginalPosition(generatedPosition);
}
return generatedPosition;
}
getGeneratedPosition(originalPosition) {
if (this.parent) {
originalPosition = this.getGeneratedPosition(originalPosition);
}
return originalPosition;
}
isInGenerated(position) {
if (this.parent && !this.parent.isInGenerated(position)) {
return false;
}
return true;
}
getURL() {
return this.url;
}
}
exports.IdentityMapper = IdentityMapper;
/**
* Maps positions in a fragment relative to a parent.
*/
class FragmentMapper {
constructor(originalText, tagInfo, url) {
this.originalText = originalText;
this.tagInfo = tagInfo;
this.url = url;
this.lineOffsetsOriginal = (0, utils_1.getLineOffsets)(this.originalText);
this.lineOffsetsGenerated = (0, utils_1.getLineOffsets)(this.tagInfo.content);
}
getOriginalPosition(generatedPosition) {
const parentOffset = this.offsetInParent((0, utils_1.offsetAt)(generatedPosition, this.tagInfo.content, this.lineOffsetsGenerated));
return (0, utils_1.positionAt)(parentOffset, this.originalText, this.lineOffsetsOriginal);
}
offsetInParent(offset) {
return this.tagInfo.start + offset;
}
getGeneratedPosition(originalPosition) {
const fragmentOffset = (0, utils_1.offsetAt)(originalPosition, this.originalText, this.lineOffsetsOriginal) -
this.tagInfo.start;
return (0, utils_1.positionAt)(fragmentOffset, this.tagInfo.content, this.lineOffsetsGenerated);
}
isInGenerated(pos) {
const offset = (0, utils_1.offsetAt)(pos, this.originalText, this.lineOffsetsOriginal);
return offset >= this.tagInfo.start && offset <= this.tagInfo.end;
}
getURL() {
return this.url;
}
}
exports.FragmentMapper = FragmentMapper;
class SourceMapDocumentMapper {
constructor(traceMap, sourceUri, parent) {
this.traceMap = traceMap;
this.sourceUri = sourceUri;
this.parent = parent;
}
getOriginalPosition(generatedPosition) {
if (this.parent) {
generatedPosition = this.parent.getOriginalPosition(generatedPosition);
}
if (generatedPosition.line < 0) {
return { line: -1, character: -1 };
}
const mapped = (0, trace_mapping_1.originalPositionFor)(this.traceMap, {
line: generatedPosition.line + 1,
column: generatedPosition.character
});
if (!mapped) {
return { line: -1, character: -1 };
}
if (mapped.line === 0) {
logger_1.Logger.debug('Got 0 mapped line from', generatedPosition, 'col was', mapped.column);
}
return {
line: (mapped.line || 0) - 1,
character: mapped.column || 0
};
}
getGeneratedPosition(originalPosition) {
if (this.parent) {
originalPosition = this.parent.getGeneratedPosition(originalPosition);
}
const mapped = (0, trace_mapping_1.generatedPositionFor)(this.traceMap, {
line: originalPosition.line + 1,
column: originalPosition.character,
source: this.sourceUri
});
if (!mapped) {
return { line: -1, character: -1 };
}
const result = {
line: (mapped.line || 0) - 1,
character: mapped.column || 0
};
if (result.line < 0) {
return result;
}
return result;
}
isInGenerated(position) {
if (this.parent && !this.isInGenerated(position)) {
return false;
}
const generated = this.getGeneratedPosition(position);
return generated.line >= 0;
}
getURL() {
return this.sourceUri;
}
}
exports.SourceMapDocumentMapper = SourceMapDocumentMapper;
function mapRangeToOriginal(fragment, range) {
// DON'T use Range.create here! Positions might not be mapped
// and therefore return negative numbers, which makes Range.create throw.
// These invalid position need to be handled
// on a case-by-case basis in the calling functions.
const originalRange = {
start: fragment.getOriginalPosition(range.start),
end: fragment.getOriginalPosition(range.end)
};
checkRangeLength(originalRange, range);
return originalRange;
}
/** Range may be mapped one character short - reverse that for "in the same line" cases*/
function checkRangeLength(originalRange, range) {
if (originalRange.start.line === originalRange.end.line &&
range.start.line === range.end.line &&
originalRange.end.character - originalRange.start.character ===
range.end.character - range.start.character - 1) {
originalRange.end.character += 1;
}
}
function mapLocationToOriginal(fragment, range) {
const map = (fragment.getOriginalFilePosition ??
fragment.getOriginalPosition).bind(fragment);
const start = map(range.start);
const end = map(range.end);
const originalRange = {
start: { line: start.line, character: start.character },
end: { line: end.line, character: end.character }
};
checkRangeLength(originalRange, range);
return {
range: originalRange,
uri: start.uri ? start.uri : fragment.getURL()
};
}
function mapRangeToGenerated(fragment, range) {
return vscode_languageserver_1.Range.create(fragment.getGeneratedPosition(range.start), fragment.getGeneratedPosition(range.end));
}
function mapCompletionItemToOriginal(fragment, item) {
if (!item.textEdit) {
return item;
}
return {
...item,
textEdit: mapEditToOriginal(fragment, item.textEdit)
};
}
function mapHoverToParent(fragment, hover) {
if (!hover.range) {
return hover;
}
return { ...hover, range: mapRangeToOriginal(fragment, hover.range) };
}
function mapObjWithRangeToOriginal(fragment, objWithRange) {
return { ...objWithRange, range: mapRangeToOriginal(fragment, objWithRange.range) };
}
function mapInsertReplaceEditToOriginal(fragment, edit) {
return {
...edit,
insert: mapRangeToOriginal(fragment, edit.insert),
replace: mapRangeToOriginal(fragment, edit.replace)
};
}
function mapEditToOriginal(fragment, edit) {
return vscode_languageserver_1.TextEdit.is(edit)
? mapObjWithRangeToOriginal(fragment, edit)
: mapInsertReplaceEditToOriginal(fragment, edit);
}
function mapDiagnosticToGenerated(fragment, diagnostic) {
return { ...diagnostic, range: mapRangeToGenerated(fragment, diagnostic.range) };
}
function mapColorPresentationToOriginal(fragment, presentation) {
const item = {
...presentation
};
if (item.textEdit) {
item.textEdit = mapObjWithRangeToOriginal(fragment, item.textEdit);
}
if (item.additionalTextEdits) {
item.additionalTextEdits = item.additionalTextEdits.map((edit) => mapObjWithRangeToOriginal(fragment, edit));
}
return item;
}
function mapSymbolInformationToOriginal(fragment, info) {
return { ...info, location: mapObjWithRangeToOriginal(fragment, info.location) };
}
function mapLocationLinkToOriginal(fragment, def) {
return vscode_languageserver_1.LocationLink.create(def.targetUri, fragment.getURL() === def.targetUri
? mapRangeToOriginal(fragment, def.targetRange)
: def.targetRange, fragment.getURL() === def.targetUri
? mapRangeToOriginal(fragment, def.targetSelectionRange)
: def.targetSelectionRange, def.originSelectionRange
? mapRangeToOriginal(fragment, def.originSelectionRange)
: undefined);
}
function mapTextDocumentEditToOriginal(fragment, edit) {
if (edit.textDocument.uri !== fragment.getURL()) {
return edit;
}
return vscode_languageserver_1.TextDocumentEdit.create(edit.textDocument, edit.edits.map((textEdit) => mapObjWithRangeToOriginal(fragment, textEdit)));
}
function mapCodeActionToOriginal(fragment, codeAction) {
return vscode_languageserver_1.CodeAction.create(codeAction.title, {
documentChanges: codeAction.edit.documentChanges.map((edit) => mapTextDocumentEditToOriginal(fragment, edit))
}, codeAction.kind);
}
function mapSelectionRangeToParent(fragment, selectionRange) {
const { range, parent } = selectionRange;
return vscode_languageserver_1.SelectionRange.create(mapRangeToOriginal(fragment, range), parent && mapSelectionRangeToParent(fragment, parent));
}
//# sourceMappingURL=DocumentMapper.js.map