svelte-language-server
Version:
A language server for Svelte
334 lines • 10.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.not = not;
exports.or = or;
exports.and = and;
exports.unique = unique;
exports.clamp = clamp;
exports.urlToPath = urlToPath;
exports.pathToUrl = pathToUrl;
exports.normalizePath = normalizePath;
exports.normalizeUri = normalizeUri;
exports.getLastPartOfPath = getLastPartOfPath;
exports.flatten = flatten;
exports.passMap = passMap;
exports.isInRange = isInRange;
exports.isZeroLengthRange = isZeroLengthRange;
exports.isRangeStartAfterEnd = isRangeStartAfterEnd;
exports.swapRangeStartEndIfNecessary = swapRangeStartEndIfNecessary;
exports.moveRangeStartToEndIfNecessary = moveRangeStartToEndIfNecessary;
exports.isBeforeOrEqualToPosition = isBeforeOrEqualToPosition;
exports.isPositionEqual = isPositionEqual;
exports.isNotNullOrUndefined = isNotNullOrUndefined;
exports.debounceSameArg = debounceSameArg;
exports.debounceThrottle = debounceThrottle;
exports.regexLastIndexOf = regexLastIndexOf;
exports.regexIndexOf = regexIndexOf;
exports.getRegExpMatches = getRegExpMatches;
exports.modifyLines = modifyLines;
exports.isSamePosition = isSamePosition;
exports.filterAsync = filterAsync;
exports.getIndent = getIndent;
exports.possiblyComponent = possiblyComponent;
exports.returnObjectIfHasKeys = returnObjectIfHasKeys;
exports.toFileNameLowerCase = toFileNameLowerCase;
exports.createGetCanonicalFileName = createGetCanonicalFileName;
exports.memoize = memoize;
exports.removeLineWithString = removeLineWithString;
exports.traverseTypeString = traverseTypeString;
const lodash_1 = require("lodash");
const vscode_uri_1 = require("vscode-uri");
function not(predicate) {
return (x) => !predicate(x);
}
function or(...predicates) {
return (x) => predicates.some((predicate) => predicate(x));
}
function and(...predicates) {
return (x) => predicates.every((predicate) => predicate(x));
}
function unique(array) {
return (0, lodash_1.uniqWith)(array, lodash_1.isEqual);
}
function clamp(num, min, max) {
return Math.max(min, Math.min(max, num));
}
function urlToPath(stringUrl) {
const url = vscode_uri_1.URI.parse(stringUrl);
if (url.scheme !== 'file') {
return null;
}
return url.fsPath.replace(/\\/g, '/');
}
function pathToUrl(path) {
return vscode_uri_1.URI.file(path).toString();
}
/**
* Some paths (on windows) start with a upper case driver letter, some don't.
* This is normalized here.
*/
function normalizePath(path) {
return vscode_uri_1.URI.file(path).fsPath.replace(/\\/g, '/');
}
/**
* URIs coming from the client could be encoded in a different
* way than expected / than the internal services create them.
* This normalizes them to be the same as the internally generated ones.
*/
function normalizeUri(uri) {
return vscode_uri_1.URI.parse(uri).toString();
}
/**
* Given a path like foo/bar or foo/bar.svelte , returns its last path
* (bar or bar.svelte in this example).
*/
function getLastPartOfPath(path) {
return path.replace(/\\/g, '/').split('/').pop() || '';
}
function flatten(arr) {
return arr.reduce((all, item) => (Array.isArray(item) ? [...all, ...item] : [...all, item]), []);
}
/**
* Map or keep original (passthrough) if the mapper returns undefined.
*/
function passMap(array, mapper) {
return array.map((x) => {
const mapped = mapper(x);
return mapped === undefined ? x : mapped;
});
}
function isInRange(range, positionToTest) {
return (isBeforeOrEqualToPosition(range.end, positionToTest) &&
isBeforeOrEqualToPosition(positionToTest, range.start));
}
function isZeroLengthRange(range) {
return isPositionEqual(range.start, range.end);
}
function isRangeStartAfterEnd(range) {
return (range.end.line < range.start.line ||
(range.end.line === range.start.line && range.end.character < range.start.character));
}
function swapRangeStartEndIfNecessary(range) {
if (isRangeStartAfterEnd(range)) {
const start = range.start;
range.start = range.end;
range.end = start;
}
return range;
}
function moveRangeStartToEndIfNecessary(range) {
if (isRangeStartAfterEnd(range)) {
range.start = range.end;
}
return range;
}
function isBeforeOrEqualToPosition(position, positionToTest) {
return (positionToTest.line < position.line ||
(positionToTest.line === position.line && positionToTest.character <= position.character));
}
function isPositionEqual(position1, position2) {
return position1.line === position2.line && position1.character === position2.character;
}
function isNotNullOrUndefined(val) {
return val !== undefined && val !== null;
}
/**
* Debounces a function but cancels previous invocation only if
* a second function determines it should.
*
* @param fn The function with it's argument
* @param determineIfSame The function which determines if the previous invocation should be canceld or not
* @param miliseconds Number of miliseconds to debounce
*/
function debounceSameArg(fn, shouldCancelPrevious, miliseconds) {
let timeout;
let prevArg;
return (arg) => {
if (shouldCancelPrevious(arg, prevArg)) {
clearTimeout(timeout);
}
prevArg = arg;
timeout = setTimeout(() => {
fn(arg);
prevArg = undefined;
}, miliseconds);
};
}
/**
* Debounces a function but also waits at minimum the specified number of miliseconds until
* the next invocation. This avoids needless calls when a synchronous call (like diagnostics)
* took too long and the whole timeout of the next call was eaten up already.
*
* @param fn The function
* @param miliseconds Number of miliseconds to debounce/throttle
*/
function debounceThrottle(fn, miliseconds) {
let timeout;
let lastInvocation = Date.now() - miliseconds;
function maybeCall() {
clearTimeout(timeout);
timeout = setTimeout(() => {
if (Date.now() - lastInvocation < miliseconds) {
maybeCall();
return;
}
fn();
lastInvocation = Date.now();
}, miliseconds);
}
return maybeCall;
}
/**
* Like str.lastIndexOf, but for regular expressions. Note that you need to provide the g-flag to your RegExp!
*/
function regexLastIndexOf(text, regex, endPos) {
if (endPos === undefined) {
endPos = text.length;
}
else if (endPos < 0) {
endPos = 0;
}
const stringToWorkWith = text.substring(0, endPos + 1);
let lastIndexOf = -1;
let result = null;
while ((result = regex.exec(stringToWorkWith)) !== null) {
lastIndexOf = result.index;
}
return lastIndexOf;
}
/**
* Like str.indexOf, but for regular expressions.
*/
function regexIndexOf(text, regex, startPos) {
if (startPos === undefined || startPos < 0) {
startPos = 0;
}
const stringToWorkWith = text.substring(startPos);
const result = regex.exec(stringToWorkWith);
return result?.index ?? -1;
}
/**
* Get all matches of a regexp.
*/
function getRegExpMatches(regex, str) {
const matches = [];
let match;
while ((match = regex.exec(str))) {
matches.push(match);
}
return matches;
}
/**
* Function to modify each line of a text, preserving the line break style (`\n` or `\r\n`)
*/
function modifyLines(text, replacementFn) {
let idx = 0;
return text
.split('\r\n')
.map((l1) => l1
.split('\n')
.map((line) => replacementFn(line, idx++))
.join('\n'))
.join('\r\n');
}
function isSamePosition(position, another) {
return position.line === another.line && position.character === another.character;
}
/**
* Like array.filter, but asynchronous
*/
async function filterAsync(array, predicate) {
const fail = Symbol();
return (await Promise.all(array.map(async (item, idx) => ((await predicate(item, idx)) ? item : fail)))).filter((i) => i !== fail);
}
function getIndent(text) {
return /^[ |\t]+/.exec(text)?.[0] ?? '';
}
function possiblyComponent(nodeOrTagName) {
return !!(typeof nodeOrTagName === 'object' ? nodeOrTagName.tag : nodeOrTagName)?.[0].match(/[A-Z]/);
}
/**
* If the object if it has entries, else undefined
*/
function returnObjectIfHasKeys(obj) {
if (Object.keys(obj || {}).length > 0) {
return obj;
}
}
const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_\. ]+/g;
/**
* adopted from https://github.com/microsoft/TypeScript/blob/8192d550496d884263e292488e325ae96893dc78/src/compiler/core.ts#L1769-L1807
* see the comment there about why we can't just use String.prototype.toLowerCase() here
*/
function toFileNameLowerCase(x) {
return fileNameLowerCaseRegExp.test(x) ? x.replace(fileNameLowerCaseRegExp, toLowerCase) : x;
}
function toLowerCase(x) {
return x.toLowerCase();
}
/**
* adopted from https://github.com/microsoft/TypeScript/blob/8192d550496d884263e292488e325ae96893dc78/src/compiler/core.ts#L2312
*/
function createGetCanonicalFileName(useCaseSensitiveFileNames) {
return useCaseSensitiveFileNames ? identity : toFileNameLowerCase;
}
function identity(x) {
return x;
}
function memoize(callback) {
let value;
let callbackInner = callback;
return () => {
if (callbackInner) {
value = callback();
callbackInner = undefined;
}
return value;
};
}
function removeLineWithString(str, keyword) {
const lines = str.split('\n');
const filteredLines = lines.filter((line) => !line.includes(keyword));
return filteredLines.join('\n');
}
/**
* Traverses a string and returns the index of the end character, taking into account quotes, curlies and generic tags.
*/
function traverseTypeString(str, start, endChar) {
let singleQuoteOpen = false;
let doubleQuoteOpen = false;
let countCurlyBrace = 0;
let countAngleBracket = 0;
for (let i = start; i < str.length; i++) {
const char = str[i];
if (!doubleQuoteOpen && char === "'") {
singleQuoteOpen = !singleQuoteOpen;
}
else if (!singleQuoteOpen && char === '"') {
doubleQuoteOpen = !doubleQuoteOpen;
}
else if (!doubleQuoteOpen && !singleQuoteOpen) {
if (char === '{') {
countCurlyBrace++;
}
else if (char === '}') {
countCurlyBrace--;
}
else if (char === '<') {
countAngleBracket++;
}
else if (char === '>') {
countAngleBracket--;
}
}
if (!singleQuoteOpen &&
!doubleQuoteOpen &&
countCurlyBrace === 0 &&
countAngleBracket === 0 &&
char === endChar) {
return i;
}
}
return -1;
}
//# sourceMappingURL=utils.js.map