svelte-language-server
Version:
A language server for Svelte
334 lines • 15.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getScriptKindFromFileName = getScriptKindFromFileName;
exports.getExtensionFromScriptKind = getExtensionFromScriptKind;
exports.getScriptKindFromAttributes = getScriptKindFromAttributes;
exports.isSvelteFilePath = isSvelteFilePath;
exports.isVirtualSvelteFilePath = isVirtualSvelteFilePath;
exports.toRealSvelteFilePath = toRealSvelteFilePath;
exports.toVirtualSvelteFilePath = toVirtualSvelteFilePath;
exports.ensureRealSvelteFilePath = ensureRealSvelteFilePath;
exports.convertRange = convertRange;
exports.convertToLocationRange = convertToLocationRange;
exports.convertToLocationForReferenceOrDefinition = convertToLocationForReferenceOrDefinition;
exports.hasNonZeroRange = hasNonZeroRange;
exports.rangeToTextSpan = rangeToTextSpan;
exports.findTsConfigPath = findTsConfigPath;
exports.isSubPath = isSubPath;
exports.getNearestWorkspaceUri = getNearestWorkspaceUri;
exports.symbolKindFromString = symbolKindFromString;
exports.scriptElementKindToCompletionItemKind = scriptElementKindToCompletionItemKind;
exports.mapSeverity = mapSeverity;
exports.getTsCheckComment = getTsCheckComment;
exports.convertToTextSpan = convertToTextSpan;
exports.isInScript = isInScript;
exports.getDiagnosticTag = getDiagnosticTag;
exports.changeSvelteComponentName = changeSvelteComponentName;
exports.isGeneratedSvelteComponentName = isGeneratedSvelteComponentName;
exports.offsetOfGeneratedComponentExport = offsetOfGeneratedComponentExport;
exports.toGeneratedSvelteComponentName = toGeneratedSvelteComponentName;
exports.hasTsExtensions = hasTsExtensions;
exports.isSvelte2tsxShimFile = isSvelte2tsxShimFile;
exports.cloneRange = cloneRange;
const path_1 = require("path");
const typescript_1 = __importDefault(require("typescript"));
const vscode_languageserver_1 = require("vscode-languageserver");
const documents_1 = require("../../lib/documents");
const utils_1 = require("../../utils");
function getScriptKindFromFileName(fileName) {
const ext = fileName.substr(fileName.lastIndexOf('.'));
switch (ext.toLowerCase()) {
case typescript_1.default.Extension.Js:
return typescript_1.default.ScriptKind.JS;
case typescript_1.default.Extension.Jsx:
return typescript_1.default.ScriptKind.JSX;
case typescript_1.default.Extension.Ts:
return typescript_1.default.ScriptKind.TS;
case typescript_1.default.Extension.Tsx:
return typescript_1.default.ScriptKind.TSX;
case typescript_1.default.Extension.Json:
return typescript_1.default.ScriptKind.JSON;
default:
return typescript_1.default.ScriptKind.Unknown;
}
}
function getExtensionFromScriptKind(kind) {
switch (kind) {
case typescript_1.default.ScriptKind.JSX:
return typescript_1.default.Extension.Jsx;
case typescript_1.default.ScriptKind.TS:
return typescript_1.default.Extension.Ts;
case typescript_1.default.ScriptKind.TSX:
return typescript_1.default.Extension.Tsx;
case typescript_1.default.ScriptKind.JSON:
return typescript_1.default.Extension.Json;
case typescript_1.default.ScriptKind.JS:
default:
return typescript_1.default.Extension.Js;
}
}
function getScriptKindFromAttributes(attrs) {
const type = attrs.lang || attrs.type;
switch (type) {
case 'ts':
case 'typescript':
case 'text/ts':
case 'text/typescript':
return typescript_1.default.ScriptKind.TSX;
case 'javascript':
case 'text/javascript':
default:
return typescript_1.default.ScriptKind.JSX;
}
}
function isSvelteFilePath(filePath) {
return filePath.endsWith('.svelte');
}
function isVirtualSvelteFilePath(filePath) {
return filePath.endsWith('.d.svelte.ts');
}
function toRealSvelteFilePath(filePath) {
return filePath.slice(0, -11 /* 'd.svelte.ts'.length */) + 'svelte';
}
function toVirtualSvelteFilePath(svelteFilePath) {
return isVirtualSvelteFilePath(svelteFilePath)
? svelteFilePath
: svelteFilePath.slice(0, -6 /* 'svelte'.length */) + 'd.svelte.ts';
}
function ensureRealSvelteFilePath(filePath) {
return isVirtualSvelteFilePath(filePath) ? toRealSvelteFilePath(filePath) : filePath;
}
function convertRange(document, range) {
return vscode_languageserver_1.Range.create(document.positionAt(range.start || 0), document.positionAt((range.start || 0) + (range.length || 0)));
}
function convertToLocationRange(snapshot, textSpan) {
const range = (0, documents_1.mapRangeToOriginal)(snapshot, convertRange(snapshot, textSpan));
mapUnmappedToTheStartOfFile(range);
return range;
}
function convertToLocationForReferenceOrDefinition(snapshot, textSpan) {
const location = (0, documents_1.mapLocationToOriginal)(snapshot, convertRange(snapshot, textSpan));
mapUnmappedToTheStartOfFile(location.range);
return location;
}
/**Some definition like the svelte component class definition don't exist in the original, so we map to 0,1*/
function mapUnmappedToTheStartOfFile(range) {
if (range.start.line < 0) {
range.start.line = 0;
range.start.character = 1;
}
if (range.end.line < 0) {
range.end = range.start;
}
}
function hasNonZeroRange({ range }) {
return (!!range &&
(range.start.line !== range.end.line || range.start.character !== range.end.character));
}
function rangeToTextSpan(range, document) {
const start = document.offsetAt(range.start);
const end = document.offsetAt(range.end);
return { start, length: end - start };
}
function findTsConfigPath(fileName, rootUris, fileExists, getCanonicalFileName) {
const searchDir = (0, path_1.dirname)(fileName);
const tsconfig = typescript_1.default.findConfigFile(searchDir, fileExists, 'tsconfig.json') || '';
const jsconfig = typescript_1.default.findConfigFile(searchDir, fileExists, 'jsconfig.json') || '';
// Prefer closest config file
const config = tsconfig.length >= jsconfig.length ? tsconfig : jsconfig;
// Don't return config files that exceed the current workspace context or cross a node_modules folder
return !!config &&
rootUris.some((rootUri) => isSubPath(rootUri, config, getCanonicalFileName)) &&
!fileName
.substring(config.length - 13)
.split('/')
.includes('node_modules')
? config
: '';
}
function isSubPath(uri, possibleSubPath, getCanonicalFileName) {
// URL escape codes are in upper-case
// so getCanonicalFileName should be called after converting to file url
return getCanonicalFileName((0, utils_1.pathToUrl)(possibleSubPath)).startsWith(getCanonicalFileName(uri));
}
function getNearestWorkspaceUri(workspaceUris, path, getCanonicalFileName) {
return Array.from(workspaceUris)
.sort((a, b) => b.length - a.length)
.find((workspaceUri) => isSubPath(workspaceUri, path, getCanonicalFileName));
}
function symbolKindFromString(kind) {
switch (kind) {
case 'module':
return vscode_languageserver_1.SymbolKind.Module;
case 'class':
return vscode_languageserver_1.SymbolKind.Class;
case 'local class':
return vscode_languageserver_1.SymbolKind.Class;
case 'interface':
return vscode_languageserver_1.SymbolKind.Interface;
case 'enum':
return vscode_languageserver_1.SymbolKind.Enum;
case 'enum member':
return vscode_languageserver_1.SymbolKind.Constant;
case 'var':
return vscode_languageserver_1.SymbolKind.Variable;
case 'local var':
return vscode_languageserver_1.SymbolKind.Variable;
case 'function':
return vscode_languageserver_1.SymbolKind.Function;
case 'local function':
return vscode_languageserver_1.SymbolKind.Function;
case 'method':
return vscode_languageserver_1.SymbolKind.Method;
case 'getter':
return vscode_languageserver_1.SymbolKind.Method;
case 'setter':
return vscode_languageserver_1.SymbolKind.Method;
case 'property':
return vscode_languageserver_1.SymbolKind.Property;
case 'constructor':
return vscode_languageserver_1.SymbolKind.Constructor;
case 'parameter':
return vscode_languageserver_1.SymbolKind.Variable;
case 'type parameter':
return vscode_languageserver_1.SymbolKind.Variable;
case 'alias':
return vscode_languageserver_1.SymbolKind.Variable;
case 'let':
return vscode_languageserver_1.SymbolKind.Variable;
case 'const':
return vscode_languageserver_1.SymbolKind.Constant;
case 'JSX attribute':
return vscode_languageserver_1.SymbolKind.Property;
default:
return vscode_languageserver_1.SymbolKind.Variable;
}
}
function scriptElementKindToCompletionItemKind(kind) {
switch (kind) {
case typescript_1.default.ScriptElementKind.primitiveType:
case typescript_1.default.ScriptElementKind.keyword:
return vscode_languageserver_1.CompletionItemKind.Keyword;
case typescript_1.default.ScriptElementKind.constElement:
return vscode_languageserver_1.CompletionItemKind.Constant;
case typescript_1.default.ScriptElementKind.letElement:
case typescript_1.default.ScriptElementKind.variableElement:
case typescript_1.default.ScriptElementKind.localVariableElement:
case typescript_1.default.ScriptElementKind.alias:
return vscode_languageserver_1.CompletionItemKind.Variable;
case typescript_1.default.ScriptElementKind.memberVariableElement:
case typescript_1.default.ScriptElementKind.memberGetAccessorElement:
case typescript_1.default.ScriptElementKind.memberSetAccessorElement:
return vscode_languageserver_1.CompletionItemKind.Field;
case typescript_1.default.ScriptElementKind.functionElement:
return vscode_languageserver_1.CompletionItemKind.Function;
case typescript_1.default.ScriptElementKind.memberFunctionElement:
case typescript_1.default.ScriptElementKind.constructSignatureElement:
case typescript_1.default.ScriptElementKind.callSignatureElement:
case typescript_1.default.ScriptElementKind.indexSignatureElement:
return vscode_languageserver_1.CompletionItemKind.Method;
case typescript_1.default.ScriptElementKind.enumElement:
return vscode_languageserver_1.CompletionItemKind.Enum;
case typescript_1.default.ScriptElementKind.moduleElement:
case typescript_1.default.ScriptElementKind.externalModuleName:
return vscode_languageserver_1.CompletionItemKind.Module;
case typescript_1.default.ScriptElementKind.classElement:
case typescript_1.default.ScriptElementKind.typeElement:
return vscode_languageserver_1.CompletionItemKind.Class;
case typescript_1.default.ScriptElementKind.interfaceElement:
return vscode_languageserver_1.CompletionItemKind.Interface;
case typescript_1.default.ScriptElementKind.warning:
case typescript_1.default.ScriptElementKind.scriptElement:
return vscode_languageserver_1.CompletionItemKind.File;
case typescript_1.default.ScriptElementKind.directory:
return vscode_languageserver_1.CompletionItemKind.Folder;
case typescript_1.default.ScriptElementKind.string:
return vscode_languageserver_1.CompletionItemKind.Constant;
}
return vscode_languageserver_1.CompletionItemKind.Property;
}
function mapSeverity(category) {
switch (category) {
case typescript_1.default.DiagnosticCategory.Error:
return vscode_languageserver_1.DiagnosticSeverity.Error;
case typescript_1.default.DiagnosticCategory.Warning:
return vscode_languageserver_1.DiagnosticSeverity.Warning;
case typescript_1.default.DiagnosticCategory.Suggestion:
return vscode_languageserver_1.DiagnosticSeverity.Hint;
case typescript_1.default.DiagnosticCategory.Message:
return vscode_languageserver_1.DiagnosticSeverity.Information;
}
return vscode_languageserver_1.DiagnosticSeverity.Error;
}
// Matches comments that come before any non-comment content
const commentsRegex = /^(\s*\/\/.*\s*)*/;
// The following regex matches @ts-check or @ts-nocheck if:
// - must be @ts-(no)check
// - the comment which has @ts-(no)check can have any type of whitespace before it, but not other characters
// - what's coming after @ts-(no)check is irrelevant as long there is any kind of whitespace or line break, so this would be picked up, too: // @ts-check asdasd
// [ \t\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]
// is just \s (a.k.a any whitespace character) without linebreak and vertical tab
const tsCheckRegex = /\/\/[ \t\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]*(-(no)?check)($|\s)/;
/**
* Returns `// @ts-check` or `// @ts-nocheck` if content starts with comments and has one of these
* in its comments.
*/
function getTsCheckComment(str = '') {
const comments = str.match(commentsRegex)?.[0];
if (comments) {
const tsCheck = comments.match(tsCheckRegex);
if (tsCheck) {
// second-last entry is the capturing group with the exact ts-check wording
return `// ${tsCheck[tsCheck.length - 3]}${typescript_1.default.sys.newLine}`;
}
}
}
function convertToTextSpan(range, snapshot) {
const start = snapshot.offsetAt(snapshot.getGeneratedPosition(range.start));
const end = snapshot.offsetAt(snapshot.getGeneratedPosition(range.end));
return {
start,
length: end - start
};
}
function isInScript(position, snapshot) {
return (0, documents_1.isInTag)(position, snapshot.scriptInfo) || (0, documents_1.isInTag)(position, snapshot.moduleScriptInfo);
}
function getDiagnosticTag(diagnostic) {
const tags = [];
if (diagnostic.reportsUnnecessary) {
tags.push(vscode_languageserver_1.DiagnosticTag.Unnecessary);
}
if (diagnostic.reportsDeprecated) {
tags.push(vscode_languageserver_1.DiagnosticTag.Deprecated);
}
return tags;
}
function changeSvelteComponentName(name) {
return name.replace(/(\w+)__SvelteComponent_/, '$1');
}
const COMPONENT_SUFFIX = '__SvelteComponent_';
function isGeneratedSvelteComponentName(className) {
return className.endsWith(COMPONENT_SUFFIX);
}
function offsetOfGeneratedComponentExport(snapshot) {
return snapshot.getFullText().lastIndexOf(COMPONENT_SUFFIX);
}
function toGeneratedSvelteComponentName(className) {
return className + COMPONENT_SUFFIX;
}
function hasTsExtensions(fileName) {
return (fileName.endsWith(typescript_1.default.Extension.Dts) ||
fileName.endsWith(typescript_1.default.Extension.Tsx) ||
fileName.endsWith(typescript_1.default.Extension.Ts));
}
function isSvelte2tsxShimFile(fileName) {
return fileName?.endsWith('svelte-shims.d.ts') || fileName?.endsWith('svelte-shims-v4.d.ts');
}
function cloneRange(range) {
return vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(range.start.line, range.start.character), vscode_languageserver_1.Position.create(range.end.line, range.end.character));
}
//# sourceMappingURL=utils.js.map