UNPKG

vscode-helpers

Version:

Helper functions and classes for own VS Code (extensions)

503 lines 17 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/>. */ Object.defineProperty(exports, "__esModule", { value: true }); const FastGlob = require("fast-glob"); const FS = require("fs"); const FSExtra = require("fs-extra"); const Glob = require("glob"); const MergeDeep = require('merge-deep'); const Path = require("path"); const TMP = require("tmp"); const vscode_helpers = require("../index"); const vscode_workflows = require("../workflows"); /** * Creates a directory (if needed). * * @param {string} dir The path of the directory to create. * * @return {Promise<boolean>} The promise that indicates if directory has been created or not. */ async function createDirectoryIfNeeded(dir) { dir = vscode_helpers.toStringSafe(dir); if (!(await exists(dir))) { await FSExtra.mkdirs(dir); return true; } return false; } exports.createDirectoryIfNeeded = createDirectoryIfNeeded; /** * Promise version of 'FS.exists()' function. * * @param {string|Buffer} path The path. * * @return {Promise<boolean>} The promise that indicates if path exists or not. */ function exists(path) { return new Promise((resolve, reject) => { const COMPLETED = vscode_helpers.createCompletedAction(resolve, reject); try { FS.exists(path, (doesExist) => { COMPLETED(null, doesExist); }); } catch (e) { COMPLETED(e); } }); } exports.exists = exists; /** * Fast version of 'node-glob'. * * @param {string|string[]} patterns One or more patterns to search for. * @param {FastGlob.Options} [opts] Custom options. * * @return {Promise<FastGlobEntryItem[]>} Promise with the found files / directories. */ function fastGlob(patterns, opts) { return FastGlob(patterns, opts); } exports.fastGlob = fastGlob; /** * Fast version of 'node-glob' (sync). * * @param {string|string[]} patterns One or more patterns to search for. * @param {FastGlob.Options} [opts] Custom options. * * @return {FastGlobEntryItem[]} The found files / directories. */ function fastGlobSync(patterns, opts) { return FastGlob.sync(patterns, opts); } exports.fastGlobSync = fastGlobSync; /** * Promise version of 'Glob()' function. * * @param {string|string[]} patterns One or more patterns. * @param {Glob.IOptions} [opts] Custom options. * * @return {Promise<string[]>} The promise with the matches. */ async function glob(patterns, opts) { opts = normalizeGlobOptions(opts, { sync: false, }); const WF = vscode_workflows.buildWorkflow(); WF.next(() => { return []; }); vscode_helpers.asArray(patterns).forEach(p => { WF.next((allMatches) => { return new Promise((res, rej) => { const COMPLETED = vscode_helpers.createCompletedAction(res, rej); try { Glob(p, opts, (err, matches) => { if (err) { COMPLETED(err); } else { allMatches.push .apply(allMatches, matches); COMPLETED(null, allMatches); } }); } catch (e) { COMPLETED(e); } }); }); }); return vscode_helpers.from(await WF.start()) .select(m => Path.resolve(m)) .distinct() .toArray(); } exports.glob = glob; /** * Multi pattern version of 'Glob.sync()' function. * * @param {string|string[]} patterns One or more patterns. * @param {Glob.IOptions} [opts] Custom options. * * @return {string[]} The matches. */ function globSync(patterns, opts) { opts = normalizeGlobOptions(opts, { sync: true, }); const ALL_MATCHES = []; vscode_helpers.asArray(patterns).forEach(p => { ALL_MATCHES.push .apply(ALL_MATCHES, Glob.sync(p, opts)); }); return vscode_helpers.from(ALL_MATCHES) .select(m => Path.resolve(m)) .distinct() .toArray(); } exports.globSync = globSync; async function invokeForStats(path, useLSTAT, func, defaultValue) { path = vscode_helpers.toStringSafe(path); useLSTAT = vscode_helpers.toBooleanSafe(useLSTAT, true); if (await exists(path)) { const STATS = useLSTAT ? (await FSExtra.lstat(path)) : (await FSExtra.stat(path)); if (STATS) { return func(STATS); } } return defaultValue; } function invokeForStatsSync(path, useLSTAT, func, defaultValue) { path = vscode_helpers.toStringSafe(path); useLSTAT = vscode_helpers.toBooleanSafe(useLSTAT, true); if (FS.existsSync(path)) { const STATS = useLSTAT ? FS.lstatSync(path) : FS.statSync(path); if (STATS) { return func(STATS); } } return defaultValue; } /** * Checks if a path exists and is a block device. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {Promise<boolean>} The promise with the value that indicates if condition matches or not. */ async function isBlockDevice(path, useLSTAT = true) { return invokeForStats(path, useLSTAT, (stats) => stats.isBlockDevice(), false); } exports.isBlockDevice = isBlockDevice; /** * Checks if a path exists and is a block device. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {boolean} A value that indicates if condition matches or not. */ function isBlockDeviceSync(path, useLSTAT = true) { return invokeForStatsSync(path, useLSTAT, (stats) => stats.isBlockDevice(), false); } exports.isBlockDeviceSync = isBlockDeviceSync; /** * Checks if a path exists and is a character device. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {Promise<boolean>} The promise with the value that indicates if condition matches or not. */ async function isCharacterDevice(path, useLSTAT = true) { return invokeForStats(path, useLSTAT, (stats) => stats.isCharacterDevice(), false); } exports.isCharacterDevice = isCharacterDevice; /** * Checks if a path exists and is a character device. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {boolean} A value that indicates if condition matches or not. */ function isCharacterDeviceSync(path, useLSTAT = true) { return invokeForStatsSync(path, useLSTAT, (stats) => stats.isCharacterDevice(), false); } exports.isCharacterDeviceSync = isCharacterDeviceSync; /** * Checks if a path exists and is a directory. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {Promise<boolean>} The promise with the value that indicates if condition matches or not. */ async function isDirectory(path, useLSTAT = true) { return invokeForStats(path, useLSTAT, (stats) => stats.isDirectory(), false); } exports.isDirectory = isDirectory; /** * Checks if a path exists and is a directory. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {boolean} A value that indicates if condition matches or not. */ function isDirectorySync(path, useLSTAT = true) { return invokeForStatsSync(path, useLSTAT, (stats) => stats.isDirectory(), false); } exports.isDirectorySync = isDirectorySync; /** * Checks if a path exists and is FIFO. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {Promise<boolean>} The promise with the value that indicates if condition matches or not. */ async function isFIFO(path, useLSTAT = true) { return invokeForStats(path, useLSTAT, (stats) => stats.isFIFO(), false); } exports.isFIFO = isFIFO; /** * Checks if a path exists and is FIFO. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {boolean} A value that indicates if condition matches or not. */ function isFIFOSync(path, useLSTAT = true) { return invokeForStatsSync(path, useLSTAT, (stats) => stats.isFIFO(), false); } exports.isFIFOSync = isFIFOSync; /** * Checks if a path exists and is a file. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {Promise<boolean>} The promise with the value that indicates if condition matches or not. */ async function isFile(path, useLSTAT = true) { return invokeForStats(path, useLSTAT, (stats) => stats.isFile(), false); } exports.isFile = isFile; /** * Checks if a path exists and is a file. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {boolean} A value that indicates if condition matches or not. */ function isFileSync(path, useLSTAT = true) { return invokeForStatsSync(path, useLSTAT, (stats) => stats.isFile(), false); } exports.isFileSync = isFileSync; /** * Checks if a path exists and is a socket. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {Promise<boolean>} The promise with the value that indicates if condition matches or not. */ async function isSocket(path, useLSTAT = true) { return invokeForStats(path, useLSTAT, (stats) => stats.isSocket(), false); } exports.isSocket = isSocket; /** * Checks if a path exists and is a socket. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {boolean} A value that indicates if condition matches or not. */ function isSocketSync(path, useLSTAT = true) { return invokeForStatsSync(path, useLSTAT, (stats) => stats.isSocket(), false); } exports.isSocketSync = isSocketSync; /** * Checks if a path exists and is a symbolic link. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {Promise<boolean>} The promise with the value that indicates if condition matches or not. */ async function isSymbolicLink(path, useLSTAT = true) { return invokeForStats(path, useLSTAT, (stats) => stats.isSymbolicLink(), false); } exports.isSymbolicLink = isSymbolicLink; /** * Checks if a path exists and is a symbolic link. * * @param {string} path The path to check. * @param {boolean} [useLSTAT] If (true) use 'FS.lstat()' function, otherwise 'FS.stat()'. * * @return {boolean} A value that indicates if condition matches or not. */ function isSymbolicLinkSync(path, useLSTAT = true) { return invokeForStatsSync(path, useLSTAT, (stats) => stats.isSymbolicLink(), false); } exports.isSymbolicLinkSync = isSymbolicLinkSync; function normalizeGlobOptions(opts, callerDefaultOpts) { const DEFAULT_OPTS = { absolute: true, dot: false, nocase: true, nodir: true, nonull: false, nosort: false, }; return MergeDeep({}, DEFAULT_OPTS, callerDefaultOpts, opts); } function normalizeTempFileOptions(opts) { const DEFAULT_OPTS = {}; opts = MergeDeep({}, DEFAULT_OPTS, opts); opts.dir = vscode_helpers.toStringSafe(opts.dir); if (vscode_helpers.isEmptyString(opts.dir)) { opts.dir = undefined; } opts.prefix = vscode_helpers.toStringSafe(opts.prefix); if ('' === opts.prefix) { opts.prefix = undefined; } opts.suffix = vscode_helpers.toStringSafe(opts.suffix); if ('' === opts.suffix) { opts.suffix = undefined; } return opts; } /** * Returns the size of a file system element. * * @param {string|Buffer} path The path to the element. * @param {boolean} [useLSTAT] Use 'lstat()' (true) or 'stat()' (false) function. * * @return {Promise<number>} The promise with the size. */ async function size(path, useLSTAT = true) { useLSTAT = vscode_helpers.toBooleanSafe(useLSTAT, true); return useLSTAT ? (await FSExtra.lstat(path)).size : (await FSExtra.stat(path)).size; } exports.size = size; /** * Returns the size of a file system element (sync). * * @param {string|Buffer} path The path to the element. * @param {boolean} [useLSTAT] Use 'lstatSync()' (true) or 'statSync()' (false) function. * * @return {number} The size. */ function sizeSync(path, useLSTAT = true) { useLSTAT = vscode_helpers.toBooleanSafe(useLSTAT, true); return useLSTAT ? FSExtra.lstatSync(path).size : FSExtra.statSync(path).size; } exports.sizeSync = sizeSync; /** * Invokes an action for a temp file. * * @param {Function} action The action to invoke. * @param {TempFileOptions} [opts] The custom options. * * @return {Promise<TResult>} The promise with the result of the action. */ function tempFile(action, opts) { opts = normalizeTempFileOptions(opts); return new Promise((resolve, reject) => { let completedInvoked = false; let tempFile = false; const COMPLETED = (err, result) => { if (completedInvoked) { return; } completedInvoked = true; try { if (err) { reject(err); } else { resolve(result); } } finally { tryUnlinkTempFile(tempFile, opts); } }; try { TMP.tmpName(toTmpSimpleOptions(opts), (err, path) => { if (err) { COMPLETED(err); } else { tempFile = path; try { Promise.resolve(action(tempFile)).then((result) => { COMPLETED(null, result); }).catch((e) => { COMPLETED(e); }); } catch (e) { COMPLETED(e); } } }); } catch (e) { COMPLETED(e); } }); } exports.tempFile = tempFile; function toTmpSimpleOptions(opts) { return { dir: opts.dir, keep: true, prefix: opts.prefix, postfix: opts.suffix, }; } /** * Invokes an action for a temp file (sync). * * @param {Function} action The action to invoke. * @param {TempFileOptions} [opts] The custom options. * * @return {TResult} The result of the action. */ function tempFileSync(action, opts) { opts = normalizeTempFileOptions(opts); let tempFile = false; try { tempFile = TMP.tmpNameSync(toTmpSimpleOptions(opts)); return action(tempFile); } finally { tryUnlinkTempFile(tempFile, opts); } } exports.tempFileSync = tempFileSync; function tryUnlinkTempFile(file, opts) { try { if (false !== file) { if (!vscode_helpers.toBooleanSafe(opts.keep)) { if (isFileSync(file)) { FSExtra.unlinkSync(file); } } } return true; } catch (_a) { return false; } } //# sourceMappingURL=index.js.map