@stryke/fs
Version:
A package containing various file system utilities that expand the functionality of NodeJs's built-in `fs` module.
1 lines • 7.29 kB
Source Map (JSON)
{"version":3,"file":"command-exists.mjs","names":["constants"],"sources":["../src/command-exists.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { exec, execSync } from \"node:child_process\";\nimport { accessSync } from \"node:fs\";\nimport { access, constants } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\n\nconst isUsingWindows = process.platform == \"win32\";\n\nasync function fileNotExists(commandName: string) {\n try {\n await access(commandName, constants.F_OK);\n return false;\n // eslint-disable-next-line unused-imports/no-unused-vars, ts/no-unused-vars\n } catch (_) {\n return true;\n }\n}\n\nfunction fileNotExistsSync(commandName: string) {\n try {\n accessSync(commandName, constants.F_OK);\n return false;\n // eslint-disable-next-line unused-imports/no-unused-vars, ts/no-unused-vars\n } catch (_) {\n return true;\n }\n}\n\nasync function localExecutable(commandName: string) {\n return access(commandName, constants.F_OK | constants.X_OK);\n}\n\nfunction localExecutableSync(commandName: string) {\n try {\n accessSync(commandName, constants.F_OK | constants.X_OK);\n return true;\n // eslint-disable-next-line unused-imports/no-unused-vars, ts/no-unused-vars\n } catch (_) {\n return false;\n }\n}\n\nasync function commandExistsUnix(\n commandName: string,\n cleanedCommandName: string\n) {\n const isFile = await fileNotExists(commandName);\n\n if (!isFile) {\n exec(\n `command -v ${cleanedCommandName} 2>/dev/null` +\n ` && { echo >&1 ${cleanedCommandName}; exit 0; }`\n );\n\n await localExecutable(commandName);\n }\n}\n\nasync function commandExistsWindows(\n commandName: string,\n cleanedCommandName: string\n) {\n // Regex from Julio from: https://stackoverflow.com/questions/51494579/regex-windows-path-validator\n if (!/^(?!(?:.*\\s|.*\\.|\\W+)$)(?:[a-z]:)?[^<>:\"|?*\\n]+$/im.test(commandName)) {\n return;\n }\n\n exec(`where ${cleanedCommandName}`);\n}\n\nfunction commandExistsUnixSync(\n commandName: string,\n cleanedCommandName: string\n): boolean {\n if (fileNotExistsSync(commandName)) {\n try {\n const stdout = execSync(\n `command -v ${cleanedCommandName} 2>/dev/null` +\n ` && { echo >&1 ${cleanedCommandName}; exit 0; }`\n );\n\n return !!stdout;\n // eslint-disable-next-line unused-imports/no-unused-vars, ts/no-unused-vars\n } catch (_) {\n return false;\n }\n }\n return localExecutableSync(commandName);\n}\n\nfunction commandExistsWindowsSync(\n commandName: string,\n cleanedCommandName: string\n) {\n // Regex from Julio from: https://stackoverflow.com/questions/51494579/regex-windows-path-validator\n if (!/^(?!(?:.*\\s|.*\\.|\\W+)$)(?:[a-z]:)?[^<>:\"|?*\\n]+$/im.test(commandName)) {\n return false;\n }\n try {\n const stdout = execSync(`where ${cleanedCommandName}`, { stdio: [] });\n\n return !!stdout;\n // eslint-disable-next-line unused-imports/no-unused-vars, ts/no-unused-vars\n } catch (_) {\n return false;\n }\n}\n\nfunction cleanInput(s: string) {\n if (/[^\\w/:=-]/.test(s)) {\n s = `'${s.replace(/'/g, \"'\\\\''\")}'`;\n s = s\n .replace(/^(?:'')+/g, \"\") // un-duplicate single-quote at the beginning\n .replace(/\\\\'''/g, \"\\\\'\"); // remove non-escaped single-quote if there are enclosed between 2 escaped\n }\n return s;\n}\n\nconst cleanWindowsInput = (s: string) => {\n const isPathName = /\\\\/.test(s);\n if (isPathName) {\n return `\"${dirname(s)}:${basename(s)}\"`;\n }\n return `\"${s}\"`;\n};\n\n/**\n * Asynchronously checks if a command exists in the system.\n *\n * @remarks\n * This function will check if the command is available in the system's PATH and if it is executable.\n * @param commandName - The name of the command to check for existence\n * @returns A promise that resolves to `true` if the command exists and is executable, `false` otherwise\n */\nexport async function commandExists(commandName: string) {\n const cleanedCommandName = cleanInput(commandName);\n\n if (typeof Promise !== \"undefined\") {\n return commandExists(commandName);\n }\n if (isUsingWindows) {\n return commandExistsWindows(commandName, cleanedCommandName);\n } else {\n return commandExistsUnix(commandName, cleanedCommandName);\n }\n}\n\n/**\n * Synchronously checks if a command exists in the system.\n *\n * @remarks\n * This function will check if the command is available in the system's PATH and if it is executable.\n * @param commandName - The name of the command to check for existence\n * @returns `true` if the command exists and is executable, `false` otherwise\n */\nexport function commandExistsSync(commandName: string): boolean {\n if (isUsingWindows) {\n return commandExistsWindowsSync(\n commandName,\n cleanWindowsInput(commandName)\n );\n } else {\n return commandExistsUnixSync(commandName, cleanInput(commandName));\n }\n}\n"],"mappings":";;;;;;AAuBA,MAAM,iBAAiB,QAAQ,YAAY;AAE3C,eAAe,cAAc,aAAqB;AAChD,KAAI;AACF,QAAM,OAAO,aAAaA,YAAU,KAAK;AACzC,SAAO;UAEA,GAAG;AACV,SAAO;;;AAIX,SAAS,kBAAkB,aAAqB;AAC9C,KAAI;AACF,aAAW,aAAaA,YAAU,KAAK;AACvC,SAAO;UAEA,GAAG;AACV,SAAO;;;AAIX,eAAe,gBAAgB,aAAqB;AAClD,QAAO,OAAO,aAAaA,YAAU,OAAOA,YAAU,KAAK;;AAG7D,SAAS,oBAAoB,aAAqB;AAChD,KAAI;AACF,aAAW,aAAaA,YAAU,OAAOA,YAAU,KAAK;AACxD,SAAO;UAEA,GAAG;AACV,SAAO;;;AAIX,eAAe,kBACb,aACA,oBACA;AAGA,KAAI,CAAC,MAFgB,cAAc,YAAY,EAElC;AACX,OACE,cAAc,mBAAmB,6BACb,mBAAmB,aACxC;AAED,QAAM,gBAAgB,YAAY;;;AAItC,eAAe,qBACb,aACA,oBACA;AAEA,KAAI,CAAC,qDAAqD,KAAK,YAAY,CACzE;AAGF,MAAK,SAAS,qBAAqB;;AAGrC,SAAS,sBACP,aACA,oBACS;AACT,KAAI,kBAAkB,YAAY,CAChC,KAAI;AAMF,SAAO,CAAC,CALO,SACb,cAAc,mBAAmB,6BACb,mBAAmB,aAG1B;UAER,GAAG;AACV,SAAO;;AAGX,QAAO,oBAAoB,YAAY;;AAGzC,SAAS,yBACP,aACA,oBACA;AAEA,KAAI,CAAC,qDAAqD,KAAK,YAAY,CACzE,QAAO;AAET,KAAI;AAGF,SAAO,CAAC,CAFO,SAAS,SAAS,sBAAsB,EAAE,OAAO,EAAE,EAAE,CAErD;UAER,GAAG;AACV,SAAO;;;AAIX,SAAS,WAAW,GAAW;AAC7B,KAAI,YAAY,KAAK,EAAE,EAAE;AACvB,MAAI,IAAI,EAAE,QAAQ,MAAM,QAAQ,CAAC;AACjC,MAAI,EACD,QAAQ,aAAa,GAAG,CACxB,QAAQ,UAAU,MAAM;;AAE7B,QAAO;;AAGT,MAAM,qBAAqB,MAAc;AAEvC,KADmB,KAAK,KAAK,EACf,CACZ,QAAO,IAAI,QAAQ,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC;AAEvC,QAAO,IAAI,EAAE;;;;;;;;;;AAWf,eAAsB,cAAc,aAAqB;CACvD,MAAM,qBAAqB,WAAW,YAAY;AAElD,KAAI,OAAO,YAAY,YACrB,QAAO,cAAc,YAAY;AAEnC,KAAI,eACF,QAAO,qBAAqB,aAAa,mBAAmB;KAE5D,QAAO,kBAAkB,aAAa,mBAAmB;;;;;;;;;;AAY7D,SAAgB,kBAAkB,aAA8B;AAC9D,KAAI,eACF,QAAO,yBACL,aACA,kBAAkB,YAAY,CAC/B;KAED,QAAO,sBAAsB,aAAa,WAAW,YAAY,CAAC"}