kjelsrud.dev/node_modules/@astrojs/language-server/dist/utils.js
2023-07-19 21:31:30 +02:00

270 lines
9.2 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getWorkspacePnpPath = exports.getAstroInstall = exports.isAstroWorkspace = exports.debounceThrottle = exports.debounceSameArg = exports.getRegExpMatches = exports.regexLastIndexOf = exports.isBeforeOrEqualToPosition = exports.isInRange = exports.isNotNullOrUndefined = exports.clamp = exports.modifyLines = exports.toPascalCase = exports.mergeDeep = exports.get = exports.getLastPartOfPath = exports.pathToUrl = exports.urlToPath = exports.normalizePath = exports.normalizeUri = void 0;
const path_1 = require("path");
const vscode_uri_1 = require("vscode-uri");
const importPackage_1 = require("./importPackage");
/** Normalizes a document URI */
function normalizeUri(uri) {
return vscode_uri_1.URI.parse(uri).toString();
}
exports.normalizeUri = normalizeUri;
/**
* 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, '/');
}
exports.normalizePath = normalizePath;
/** Turns a URL into a normalized FS Path */
function urlToPath(stringUrl) {
const url = vscode_uri_1.URI.parse(stringUrl);
if (url.scheme !== 'file') {
return null;
}
return url.fsPath.replace(/\\/g, '/');
}
exports.urlToPath = urlToPath;
/** Converts a path to a URL */
function pathToUrl(path) {
return vscode_uri_1.URI.file(path).toString();
}
exports.pathToUrl = pathToUrl;
/**
* Given a path like foo/bar or foo/bar.astro , returns its last path
* (bar or bar.astro in this example).
*/
function getLastPartOfPath(path) {
return path.replace(/\\/g, '/').split('/').pop() || '';
}
exports.getLastPartOfPath = getLastPartOfPath;
/**
* Return an element in an object using a path as a string (ex: `astro.typescript.format` will return astro['typescript']['format']).
* From: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_get
*/
function get(obj, path) {
const travel = (regexp) => String.prototype.split
.call(path, regexp)
.filter(Boolean)
.reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj);
const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/);
return result === undefined ? undefined : result;
}
exports.get = get;
/**
* Performs a deep merge of objects and returns new object. Does not modify
* objects (immutable) and merges arrays via concatenation.
* From: https://stackoverflow.com/a/48218209
*/
function mergeDeep(...objects) {
const isObject = (obj) => obj && typeof obj === 'object';
return objects.reduce((prev, obj) => {
Object.keys(obj).forEach((key) => {
const pVal = prev[key];
const oVal = obj[key];
if (Array.isArray(pVal) && Array.isArray(oVal)) {
prev[key] = pVal.concat(...oVal);
}
else if (isObject(pVal) && isObject(oVal)) {
prev[key] = mergeDeep(pVal, oVal);
}
else {
prev[key] = oVal;
}
});
return prev;
}, {});
}
exports.mergeDeep = mergeDeep;
/**
* Transform a string into PascalCase
*/
function toPascalCase(string) {
return `${string}`
.replace(new RegExp(/[-_]+/, 'g'), ' ')
.replace(new RegExp(/[^\w\s]/, 'g'), '')
.replace(new RegExp(/\s+(.)(\w*)/, 'g'), ($1, $2, $3) => `${$2.toUpperCase() + $3.toLowerCase()}`)
.replace(new RegExp(/\w/), (s) => s.toUpperCase());
}
exports.toPascalCase = toPascalCase;
/**
* 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');
}
exports.modifyLines = modifyLines;
/** Clamps a number between min and max */
function clamp(num, min, max) {
return Math.max(min, Math.min(max, num));
}
exports.clamp = clamp;
function isNotNullOrUndefined(val) {
return val !== undefined && val !== null;
}
exports.isNotNullOrUndefined = isNotNullOrUndefined;
function isInRange(range, positionToTest) {
return isBeforeOrEqualToPosition(range.end, positionToTest) && isBeforeOrEqualToPosition(positionToTest, range.start);
}
exports.isInRange = isInRange;
function isBeforeOrEqualToPosition(position, positionToTest) {
return (positionToTest.line < position.line ||
(positionToTest.line === position.line && positionToTest.character <= position.character));
}
exports.isBeforeOrEqualToPosition = isBeforeOrEqualToPosition;
/**
* 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;
}
exports.regexLastIndexOf = regexLastIndexOf;
/**
* Get all matches of a regexp.
*/
function getRegExpMatches(regex, str) {
const matches = [];
let match;
while ((match = regex.exec(str))) {
matches.push(match);
}
return matches;
}
exports.getRegExpMatches = getRegExpMatches;
/**
* 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 milliseconds Number of miliseconds to debounce
*/
function debounceSameArg(fn, shouldCancelPrevious, milliseconds) {
let timeout;
let prevArg;
return (arg) => {
if (shouldCancelPrevious(arg, prevArg)) {
clearTimeout(timeout);
}
prevArg = arg;
timeout = setTimeout(() => {
fn(arg);
prevArg = undefined;
}, milliseconds);
};
}
exports.debounceSameArg = debounceSameArg;
/**
* Debounces a function but also waits at minimum the specified number of milliseconds 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 with it's argument
* @param milliseconds Number of milliseconds to debounce/throttle
*/
function debounceThrottle(fn, milliseconds) {
let timeout;
let lastInvocation = Date.now() - milliseconds;
function maybeCall(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => {
if (Date.now() - lastInvocation < milliseconds) {
maybeCall(...args);
return;
}
fn(...args);
lastInvocation = Date.now();
}, milliseconds);
}
return maybeCall;
}
exports.debounceThrottle = debounceThrottle;
/**
* Try to determine if a workspace could be an Astro project based on the content of `package.json`
*/
function isAstroWorkspace(workspacePath) {
try {
const astroPackageJson = require.resolve('./package.json', { paths: [workspacePath] });
const deps = Object.assign(require(astroPackageJson).dependencies ?? {}, require(astroPackageJson).devDependencies ?? {});
if (Object.keys(deps).includes('astro')) {
return true;
}
}
catch (e) {
return false;
}
return false;
}
exports.isAstroWorkspace = isAstroWorkspace;
function getAstroInstall(basePaths) {
let path;
let version;
try {
path = (0, importPackage_1.getPackagePath)('astro', basePaths);
if (!path) {
throw Error;
}
version = require((0, path_1.resolve)(path, 'package.json')).version;
}
catch {
// If we couldn't find it inside the workspace's node_modules, it might means we're in the monorepo
try {
path = (0, importPackage_1.getPackagePath)('./packages/astro', basePaths);
if (!path) {
throw Error;
}
version = require((0, path_1.resolve)(path, 'package.json')).version;
}
catch (e) {
// If we still couldn't find it, it probably just doesn't exist
console.error(`${basePaths[0]} seems to be an Astro project, but we couldn't find Astro or Astro is not installed`);
return undefined;
}
}
let [major, minor, patch] = version.split('.');
if (patch.includes('-')) {
const patchParts = patch.split('-');
patch = patchParts[0];
}
return {
path,
version: {
full: version,
major: Number(major),
minor: Number(minor),
patch: Number(patch),
},
};
}
exports.getAstroInstall = getAstroInstall;
function getWorkspacePnpPath(workspacePath) {
try {
const possiblePath = (0, path_1.resolve)(workspacePath, '.pnp.cjs');
require.resolve(possiblePath);
return possiblePath;
}
catch {
return null;
}
}
exports.getWorkspacePnpPath = getWorkspacePnpPath;