UNPKG

vscode-helpers

Version:

Helper functions and classes for own VS Code (extensions)

1,056 lines 31.9 kB
"use strict"; /** * This file is part of the vscode-helpers distribution. * Copyright (c) Marcel Joachim Kloubert. * * vscode-helpers is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, version 3. * * vscode-helpers is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.toEOL = exports.toBooleanSafe = exports.toArray = exports.setExtensionRoot = exports.readAll = exports.randomBytes = exports.openAndShowTextDocument = exports.now = exports.normalizeString = exports.loadModule = exports.isEmptyString = exports.isBinaryContentSync = exports.isBinaryContent = exports.guid = exports.getPackageFileSync = exports.getPackageFile = exports.getExtensionRoot = exports.formatArray = exports.format = exports.forEachAsync = exports.execFile = exports.doesMatch = exports.createQueue = exports.createGitClientSync = exports.createGitClient = exports.createDevToolsClient = exports.createCompletedAction = exports.createChromeClient = exports.compareValuesBy = exports.compareValues = exports.cloneObjectFlat = exports.cloneObject = exports.asUTC = exports.asLocalTime = exports.asBuffer = exports.asArray = exports.applyFuncFor = exports.SESSION_DISPOSER = exports.SESSION = exports.QUEUE = exports.IS_WINDOWS = exports.IS_SUNOS = exports.IS_OPEN_BSD = exports.IS_MAC = exports.IS_LINUX = exports.IS_FREE_BSD = exports.IS_AIX = exports.repeat = exports.range = exports.from = void 0; exports.uuid = exports.utcNow = exports.tryCreateGitClientSync = exports.tryCreateGitClient = exports.toStringSafe = void 0; const _ = require("lodash"); const ChildProcess = require("child_process"); const Crypto = require("crypto"); const Enumerable = require("node-enumerable"); const FS = require("fs"); const IsBinaryFile = require("isbinaryfile"); const IsStream = require("is-stream"); const MergeDeep = require('merge-deep'); const Minimatch = require("minimatch"); const Moment = require("moment"); const OS = require("os"); const Path = require("path"); const p_queue_1 = require("p-queue"); const vscode = require("vscode"); const vscode_helpers_devtools = require("./devtools"); const vscode_helpers_events = require("./events"); const vscode_helpers_scm_git = require("./scm/git"); // sub modules __exportStar(require("./cache"), exports); __exportStar(require("./devtools"), exports); __exportStar(require("./disposable"), exports); __exportStar(require("./events"), exports); __exportStar(require("./fs"), exports); __exportStar(require("./html"), exports); __exportStar(require("./http"), exports); __exportStar(require("./logging"), exports); var node_enumerable_1 = require("node-enumerable"); Object.defineProperty(exports, "from", { enumerable: true, get: function () { return node_enumerable_1.from; } }); Object.defineProperty(exports, "range", { enumerable: true, get: function () { return node_enumerable_1.range; } }); Object.defineProperty(exports, "repeat", { enumerable: true, get: function () { return node_enumerable_1.repeat; } }); __exportStar(require("./notifications"), exports); __exportStar(require("./progress"), exports); __exportStar(require("./timers"), exports); __exportStar(require("./workflows"), exports); __exportStar(require("./workspaces"), exports); const readFile = FS.promises.readFile; let extensionRoot; /** * Is AIX or not. */ exports.IS_AIX = process.platform === 'aix'; /** * Is Free BSD or not. */ exports.IS_FREE_BSD = process.platform === 'freebsd'; /** * Is Linux or not. */ exports.IS_LINUX = process.platform === 'linux'; /** * Is Sun OS or not. */ exports.IS_MAC = process.platform === 'darwin'; /** * Is Open BSD or not. */ exports.IS_OPEN_BSD = process.platform === 'openbsd'; /** * Is Sun OS or not. */ exports.IS_SUNOS = process.platform === 'sunos'; /** * Is Windows or not. */ exports.IS_WINDOWS = process.platform === 'win32'; /** * Global execution queue, which only allows one execution at the same time. */ exports.QUEUE = new p_queue_1.default({ autoStart: true, concurrency: 1, }); /** * Stores global data for the current extension session. */ exports.SESSION = {}; /** * Disposes 'SESSION', by removing its data. */ exports.SESSION_DISPOSER = { /** @inheritdoc */ dispose: () => { for (const P of Object.keys(exports.SESSION)) { delete exports.SESSION[P]; } } }; /** * Applies a function for a specific object / value. * * @param {TFunc} func The function. * @param {any} [thisArgs] The object to apply to the function. * * @return {TFunc} The wrapped function. */ function applyFuncFor(func, thisArgs) { return function () { return func.apply(thisArgs, arguments); }; } exports.applyFuncFor = applyFuncFor; /** * Returns a value as array. * * @param {T|T[]|ReadonlyArray<T>} val The value. * @param {boolean} [removeEmpty] Remove items that are (null) / (undefined) or not. * * @return {T[]} The value as (new) array. */ function asArray(val, removeEmpty = true) { removeEmpty = toBooleanSafe(removeEmpty, true); return (_.isArrayLike(val) ? val : [val]).filter(i => { if (removeEmpty) { return !_.isNil(i); } return true; }); } exports.asArray = asArray; /** * Returns a value as buffer. * * @param {any} val The value to convert / cast. * @param {string} enc The custom encoding for the string parsers. * @param {number} [maxDepth] The custom value for the max depth of wrapped functions. Default: 63 * * @return {Promise<Buffer>} The promise with the buffer. */ async function asBuffer(val, enc, maxDepth) { return await asBufferInner(val, enc, null, maxDepth); } exports.asBuffer = asBuffer; async function asBufferInner(val, enc, funcDepth, maxDepth) { enc = normalizeString(enc); if ('' === enc) { enc = undefined; } if (isNaN(funcDepth)) { funcDepth = 0; } if (isNaN(maxDepth)) { maxDepth = 63; } if (funcDepth > maxDepth) { throw new Error(`Maximum depth of ${maxDepth} reached!`); } if (Buffer.isBuffer(val) || _.isNil(val)) { return val; } if (_.isFunction(val)) { // wrapped return asBufferInner(await Promise.resolve(val(enc, funcDepth, maxDepth)), enc, funcDepth + 1, maxDepth); } if (IsStream.isReadableStream(val)) { // stream return await readAll(val); } if (_.isObject(val)) { // JSON object return Buffer.from(JSON.stringify(val), enc); } // handle as string return Buffer.from(toStringSafe(val), enc); } /** * Returns a value as local Moment instance. * * @param {any} val The input value. * * @return {Moment.Moment} The output value. */ function asLocalTime(val) { let localTime; if (!_.isNil(val)) { if (Moment.isMoment(val)) { localTime = val; } else if (Moment.isDate(val)) { localTime = Moment(val); } else { localTime = Moment(toStringSafe(val)); } } if (localTime) { if (!localTime.isLocal()) { localTime = localTime.local(); } } return localTime; } exports.asLocalTime = asLocalTime; /** * Returns a value as UTC Moment instance. * * @param {any} val The input value. * * @return {Moment.Moment} The output value. */ function asUTC(val) { let utcTime; if (!_.isNil(val)) { if (Moment.isMoment(val)) { utcTime = val; } else if (Moment.isDate(val)) { utcTime = Moment(val); } else { utcTime = Moment(toStringSafe(val)); } } if (utcTime) { if (!utcTime.isUTC()) { utcTime = utcTime.utc(); } } return utcTime; } exports.asUTC = asUTC; /** * Clones an object / value deep. * * @param {T} val The value / object to clone. * * @return {T} The cloned value / object. */ function cloneObject(val) { if (!val) { return val; } return JSON.parse(JSON.stringify(val)); } exports.cloneObject = cloneObject; /** * Clones an value flat. * * @param {T} val The object to clone. * @param {boolean} [useNewObjectForFunctions] Use new object as 'thisArg' for functions (true) or * the original 'val' (false). * * @return {T} The cloned object. */ function cloneObjectFlat(val, useNewObjectForFunctions = true) { useNewObjectForFunctions = toBooleanSafe(useNewObjectForFunctions, true); if (_.isNil(val)) { return val; } const CLONED_OBJ = {}; const THIS_ARG = useNewObjectForFunctions ? CLONED_OBJ : val; const ADD_PROPERTY = (prop, value) => { Object.defineProperty(CLONED_OBJ, prop, { configurable: true, enumerable: true, get: () => { return value; }, set: (newValue) => { value = newValue; }, }); }; _.forIn(val, (value, prop) => { let valueToSet = value; if (_.isFunction(valueToSet)) { const FUNC = valueToSet; valueToSet = function () { return FUNC.apply(THIS_ARG, arguments); }; } ADD_PROPERTY(prop, valueToSet); }); return CLONED_OBJ; } exports.cloneObjectFlat = cloneObjectFlat; /** * Compares two values for a sort operation. * * @param {T} x The left value. * @param {T} y The right value. * * @return {number} The "sort value". */ function compareValues(x, y) { if (x !== y) { if (x > y) { return 1; } else if (x < y) { return -1; } } return 0; } exports.compareValues = compareValues; /** * Compares values by using a selector. * * @param {T} x The left value. * @param {T} y The right value. * @param {Function} selector The selector. * * @return {number} The "sort value". */ function compareValuesBy(x, y, selector) { return compareValues(selector(x), selector(y)); } exports.compareValuesBy = compareValuesBy; /** * Alias for 'createDevToolsClient'. */ function createChromeClient(opts) { return createDevToolsClient.apply(null, arguments); } exports.createChromeClient = createChromeClient; /** * Creates a simple 'completed' callback for a promise. * * @param {Function} resolve The 'succeeded' callback. * @param {Function} reject The 'error' callback. * * @return {SimpleCompletedAction<TResult>} The created action. */ function createCompletedAction(resolve, reject) { let completedInvoked = false; return (err, result) => { if (completedInvoked) { return; } completedInvoked = true; if (err) { if (reject) { reject(err); } } else { if (resolve) { resolve(result); } } }; } exports.createCompletedAction = createCompletedAction; /** * Creates a new instance of a client, which can connect to a DevTools compatible * browser like Google Chrome. * * @param {vscode_helpers_devtools.DevToolsClientOptions} [opts] Custom options. * * @return {vscode_helpers_devtools.DevToolsClient} The new client instance. */ function createDevToolsClient(opts) { return new vscode_helpers_devtools.DevToolsClient(opts); } exports.createDevToolsClient = createDevToolsClient; /** * Creates a Git client. * * @param {string} [cwd] The custom working directory. * @param {string} [path] The optional specific path where to search first. * * @return {Promise<vscode_helpers_scm_git.GitClient|false>} The promise with the client or (false) if no client found. */ function createGitClient(cwd, path) { return Promise.resolve(createGitClientSync(cwd, path)); } exports.createGitClient = createGitClient; /** * Creates a Git client (sync). * * @param {string} [cwd] The custom working directory. * @param {string} [path] The optional specific path where to search first. * * @return {vscode_helpers_scm_git.GitClient|false} The client or (false) if no client found. */ function createGitClientSync(cwd, path) { const CLIENT = tryCreateGitClientSync(cwd, path); if (false === CLIENT) { throw new Error('No git client found!'); } return CLIENT; } exports.createGitClientSync = createGitClientSync; /** * Creates a new queue. * * @param {TOpts} [opts] The custom options. * * @return {PQueue} The new queue. */ function createQueue(opts) { const DEFAULT_OPTS = { autoStart: true, concurrency: 1, }; return new p_queue_1.default(MergeDeep(DEFAULT_OPTS, opts)); } exports.createQueue = createQueue; /** * Handles a value as string and checks if it does match at least one (minimatch) pattern. * * @param {any} val The value to check. * @param {string|string[]} patterns One or more patterns. * @param {Minimatch.IOptions} [options] Additional options. * * @return {boolean} Does match or not. */ function doesMatch(val, patterns, options) { val = toStringSafe(val); patterns = asArray(patterns).map(p => { return toStringSafe(p); }); for (const P of patterns) { if (Minimatch(val, P, options)) { return true; } } return false; } exports.doesMatch = doesMatch; /** * Executes a file. * * @param {string} command The thing / command to execute. * @param {any[]} [args] One or more argument for the execution. * @param {ChildProcess.ExecFileOptions} [opts] Custom options. * * @return {Promise<ExecFileResult>} The promise with the result. */ async function execFile(command, args, opts) { command = toStringSafe(command); args = asArray(args, false).map(a => { return toStringSafe(a); }); if (!opts) { opts = {}; } if (_.isNil(opts.env)) { opts.env = process.env; } return new Promise((resolve, reject) => { const RESULT = { stdErr: undefined, stdOut: undefined, process: undefined, }; let completedInvoked = false; const COMPLETED = (err) => { if (completedInvoked) { return; } completedInvoked = true; if (err) { reject(err); } else { resolve(RESULT); } }; try { const P = ChildProcess.execFile(command, args, opts, (err, stdout, stderr) => { if (err) { COMPLETED(err); } else { try { RESULT.process = P; (async () => { RESULT.stdErr = await asBuffer(stderr, 'utf8'); RESULT.stdOut = await asBuffer(stdout, 'utf8'); })().then(() => { COMPLETED(null); }, (err) => { COMPLETED(err); }); } catch (e) { COMPLETED(e); } } }); } catch (e) { COMPLETED(e); } }); } exports.execFile = execFile; /** * Async 'forEach'. * * @param {Enumerable.Sequence<T>} items The items to iterate. * @param {Function} action The item action. * @param {any} [thisArg] The underlying object / value for the item action. * * @return {TResult} The result of the last action call. */ async function forEachAsync(items, action, thisArg) { if (!_.isArrayLike(items)) { items = Enumerable.from(items) .toArray(); } let lastResult; for (let i = 0; i < items.length; i++) { lastResult = await Promise.resolve(action.apply(thisArg, [items[i], i, items])); } return lastResult; } exports.forEachAsync = forEachAsync; /** * Formats a string. * * @param {any} formatStr The value that represents the format string. * @param {any[]} [args] The arguments for 'formatStr'. * * @return {string} The formated string. */ function format(formatStr, ...args) { return formatArray(formatStr, args); } exports.format = format; /** * Formats a string. * * @param {any} formatStr The value that represents the format string. * @param {Enumerable.Sequence<any>} [args] The arguments for 'formatStr'. * * @return {string} The formated string. */ function formatArray(formatStr, args) { formatStr = toStringSafe(formatStr); if (!_.isArrayLike(args)) { args = Enumerable.from(args) .toArray(); } // apply arguments in // placeholders return formatStr.replace(/{(\d+)(\:)?([^}]*)}/g, (match, index, formatSeparator, formatExpr) => { index = parseInt(toStringSafe(index)); let resultValue = args[index]; if (':' === formatSeparator) { // collect "format providers" const FORMAT_PROVIDERS = toStringSafe(formatExpr).split(',') .map(x => x.toLowerCase().trim()) .filter(x => x); // transform argument by // format providers FORMAT_PROVIDERS.forEach(fp => { switch (fp) { case 'ending_space': resultValue = toStringSafe(resultValue); if ('' !== resultValue) { resultValue = resultValue + ' '; } break; case 'leading_space': resultValue = toStringSafe(resultValue); if ('' !== resultValue) { resultValue = ' ' + resultValue; } break; case 'lower': resultValue = toStringSafe(resultValue).toLowerCase(); break; case 'trim': resultValue = toStringSafe(resultValue).trim(); break; case 'upper': resultValue = toStringSafe(resultValue).toUpperCase(); break; case 'surround': resultValue = toStringSafe(resultValue); if ('' !== resultValue) { resultValue = "'" + toStringSafe(resultValue) + "'"; } break; } }); } if (_.isUndefined(resultValue)) { return match; } return toStringSafe(resultValue); }); } exports.formatArray = formatArray; /** * Gets the root directory of the extension. * * @return {string} The root directory of the extension. */ function getExtensionRoot() { return extensionRoot; } exports.getExtensionRoot = getExtensionRoot; /** * Loads the package file (package.json) of the extension. * * @param {string} [packageJson] The custom path to the file. * * @return {Promise<PackageFile>} The promise with the meta data of the file. */ async function getPackageFile(packageJson = '../package.json') { return JSON.parse((await readFile(getPackageFilePath(packageJson))).toString('utf8')); } exports.getPackageFile = getPackageFile; function getPackageFilePath(packageJson) { packageJson = toStringSafe(packageJson); if ('' === packageJson.trim()) { packageJson = '../package.json'; } if (!Path.isAbsolute(packageJson)) { packageJson = Path.join(getExtensionRoot(), packageJson); } return Path.resolve(packageJson); } /** * Loads the package file (package.json) of the extension sync. * * @param {string} [packageJson] The custom path to the file. * * @return {PackageFile} The meta data of the file. */ function getPackageFileSync(packageJson = '../package.json') { return JSON.parse((FS.readFileSync(getPackageFilePath(packageJson))).toString('utf8')); } exports.getPackageFileSync = getPackageFileSync; /** * Alias for 'uuid'. */ function guid(ver, ...args) { return uuid.apply(this, arguments); } exports.guid = guid; /** * Checks if data is binary or text content. * * @param {Buffer} data The data to check. * * @returns {Promise<boolean>} The promise that indicates if content is binary or not. */ function isBinaryContent(data) { return new Promise((resolve, reject) => { const COMPLETED = createCompletedAction(resolve, reject); try { IsBinaryFile(data, data.length, (err, result) => { COMPLETED(err, result); }); } catch (e) { COMPLETED(e); } }); } exports.isBinaryContent = isBinaryContent; /** * Checks if data is binary or text content (sync). * * @param {Buffer} data The data to check. * * @returns {boolean} Content is binary or not. */ function isBinaryContentSync(data) { return IsBinaryFile.sync(data, data.length); } exports.isBinaryContentSync = isBinaryContentSync; /** * Checks if the string representation of a value is empty * or contains whitespaces only. * * @param {any} val The value to check. * * @return {boolean} Is empty or not. */ function isEmptyString(val) { return '' === toStringSafe(val).trim(); } exports.isEmptyString = isEmptyString; /** * Loads a module from a script. * * @param {string} file The path to the script. * @param {boolean} [fromCache] Cache module or not. * * @return {TModule} The loaded module. */ function loadModule(file, fromCache = false) { file = toStringSafe(file); if (isEmptyString(file)) { file = './module.js'; } if (!Path.isAbsolute(file)) { file = Path.join(process.cwd(), file); } file = Path.resolve(file); fromCache = toBooleanSafe(fromCache); if (!fromCache) { delete require.cache[file]; } return require(file); } exports.loadModule = loadModule; /** * Normalizes a value as string so that is comparable. * * @param {any} val The value to convert. * @param {StringNormalizer} [normalizer] The custom normalizer. * * @return {string} The normalized value. */ function normalizeString(val, normalizer) { if (!normalizer) { normalizer = (str) => str.toLowerCase().trim(); } return normalizer(toStringSafe(val)); } exports.normalizeString = normalizeString; /** * Returns the current time. * * @param {string} [timezone] The custom timezone to use. * * @return {Moment.Moment} The current time. */ function now(timezone) { timezone = toStringSafe(timezone).trim(); const NOW = Moment(); return '' === timezone ? NOW : NOW.tz(timezone); } exports.now = now; /** * Opens and shows a new text document / editor. * * @param {OpenAndShowTextDocumentOptions} [filenameOrOpts] The custom options or the path to the file to open. * * @return {vscode.TextEditor} The promise with the new, opened text editor. */ async function openAndShowTextDocument(filenameOrOpts) { if (_.isNil(filenameOrOpts)) { filenameOrOpts = { content: '', language: 'plaintext', }; } return await vscode.window.showTextDocument(await vscode.workspace.openTextDocument(filenameOrOpts)); } exports.openAndShowTextDocument = openAndShowTextDocument; /** * Promise version of 'crypto.randomBytes()' function. * * @param {number} size The size of the result. * * @return {Promise<Buffer>} The buffer with the random bytes. */ function randomBytes(size) { size = parseInt(toStringSafe(size).trim()); return new Promise((resolve, reject) => { const COMPLETED = createCompletedAction(resolve, reject); Crypto.randomBytes(size, (err, buf) => { COMPLETED(err, buf); }); }); } exports.randomBytes = randomBytes; /** * Reads the content of a stream. * * @param {Stream.Readable} stream The stream. * @param {string} [enc] The custom (string) encoding to use. * * @returns {Promise<Buffer>} The promise with the content. */ function readAll(stream, enc) { enc = normalizeString(enc); if ('' === enc) { enc = undefined; } return new Promise((resolve, reject) => { let buff; let dataListener; let endListener; let errorListener; let completedInvoked = false; const COMPLETED = (err) => { if (completedInvoked) { return; } completedInvoked = true; vscode_helpers_events.tryRemoveListener(stream, 'data', dataListener); vscode_helpers_events.tryRemoveListener(stream, 'end', endListener); vscode_helpers_events.tryRemoveListener(stream, 'error', errorListener); if (err) { reject(err); } else { resolve(buff); } }; if (_.isNil(stream)) { buff = stream; COMPLETED(null); return; } errorListener = (err) => { if (err) { COMPLETED(err); } }; dataListener = (chunk) => { try { if (!chunk || chunk.length < 1) { return; } if (_.isString(chunk)) { chunk = Buffer.from(chunk, enc); } buff = Buffer.concat([buff, chunk]); } catch (e) { COMPLETED(e); } }; endListener = () => { COMPLETED(null); }; try { stream.on('error', errorListener); buff = Buffer.alloc(0); stream.once('end', endListener); stream.on('data', dataListener); } catch (e) { COMPLETED(e); } }); } exports.readAll = readAll; /** * Sets the root directory of the extension. * * @param {string} path The path of the extension. * * @return {string} The new value. */ function setExtensionRoot(path) { path = toStringSafe(path); if ('' === path.trim()) { path = undefined; } else { if (!Path.isAbsolute(path)) { path = Path.join(process.cwd(), path); } path = Path.resolve(path); } extensionRoot = path; return path; } exports.setExtensionRoot = setExtensionRoot; /** * Returns a sequence object as new array. * * @param {Enumerable.Sequence<T>} seq The input object. * @param {boolean} [normalize] Returns an empty array, if input object is (null) / (undefined). * * @return {T[]} The input object as array. */ function toArray(seq, normalize = true) { if (_.isNil(seq)) { if (toBooleanSafe(normalize, true)) { return []; } return seq; } if (_.isArrayLike(seq)) { const NEW_ARRAY = []; for (let i = 0; i < seq.length; i++) { NEW_ARRAY.push(seq[i]); } return NEW_ARRAY; } return Enumerable.from(seq) .toArray(); } exports.toArray = toArray; /** * Returns a value as boolean, which is not (null) and (undefined). * * @param {any} val The value to convert. * @param {boolean} [defaultVal] The custom default value if 'val' is (null) or (undefined). * * @return {boolean} 'val' as boolean. */ function toBooleanSafe(val, defaultVal = false) { if (_.isBoolean(val)) { return val; } if (_.isNil(val)) { return !!defaultVal; } return !!val; } exports.toBooleanSafe = toBooleanSafe; /** * Converts an EOL enum value to a string. * * @param {vscode.EndOfLine} [eol] The (optional) enum value. * * @return string The EOL string. */ function toEOL(eol) { switch (eol) { case vscode.EndOfLine.CRLF: return "\r\n"; case vscode.EndOfLine.LF: return "\n"; } return OS.EOL; } exports.toEOL = toEOL; /** * Returns a value as string, which is not (null) and (undefined). * * @param {any} val The value to convert. * @param {string} [defaultVal] The custom default value if 'val' is (null) or (undefined). * * @return {string} 'val' as string. */ function toStringSafe(val, defaultVal = '') { if (_.isString(val)) { return val; } if (_.isNil(val)) { return '' + defaultVal; } try { if (val instanceof Error) { return '' + val.message; } if (_.isFunction(val['toString'])) { return '' + val.toString(); } if (_.isObject(val)) { return JSON.stringify(val); } } catch { } return '' + val; } exports.toStringSafe = toStringSafe; /** * Tries to create a Git client. * * @param {string} [cwd] The custom working directory. * @param {string} [path] The optional specific path where to search first. * * @return {Promise<vscode_helpers_scm_git.GitClient|false>} The promise with the client or (false) if no client found. */ function tryCreateGitClient(cwd, path) { return Promise.resolve(tryCreateGitClientSync(cwd, path)); } exports.tryCreateGitClient = tryCreateGitClient; /** * Tries to create a Git client (sync). * * @param {string} [cwd] The custom working directory. * @param {string} [path] The optional specific path where to search first. * * @return {vscode_helpers_scm_git.GitClient|false} The client or (false) if no client found. */ function tryCreateGitClientSync(cwd, path) { const GIT_EXEC = vscode_helpers_scm_git.tryFindGitPathSync(path); if (false !== GIT_EXEC) { return new vscode_helpers_scm_git.GitClient(GIT_EXEC, cwd); } return false; } exports.tryCreateGitClientSync = tryCreateGitClientSync; /** * Returns the current UTC time. * * @return {Moment.Moment} The current UTC time. */ function utcNow() { return Moment.utc(); } exports.utcNow = utcNow; /** * Generates a new unique ID. * * @param {string} [ver] The custom version to use. Default: '4'. * @param {any[]} [args] Additional arguments for the function. * * @return {string} The generated ID. */ function uuid(ver, ...args) { const UUID = require('uuid'); ver = normalizeString(ver); let func = false; switch (ver) { case '': case '4': case 'v4': func = UUID.v4; break; case '1': case 'v1': func = UUID.v1; break; case '5': case 'v5': func = UUID.v5; break; } if (false === func) { throw new Error(`Version '${ver}' is not supported!`); } return func.apply(null, args); } exports.uuid = uuid; //# sourceMappingURL=index.js.map