11cb0ef41Sopenharmony_ciconst { isexe, sync: isexeSync } = require('isexe') 21cb0ef41Sopenharmony_ciconst { join, delimiter, sep, posix } = require('path') 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ciconst isWindows = process.platform === 'win32' 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci// used to check for slashed in commands passed in. always checks for the posix 71cb0ef41Sopenharmony_ci// seperator on all platforms, and checks for the current separator when not on 81cb0ef41Sopenharmony_ci// a posix platform. don't use the isWindows check for this since that is mocked 91cb0ef41Sopenharmony_ci// in tests but we still need the code to actually work when called. that is also 101cb0ef41Sopenharmony_ci// why it is ignored from coverage. 111cb0ef41Sopenharmony_ci/* istanbul ignore next */ 121cb0ef41Sopenharmony_ciconst rSlash = new RegExp(`[${posix.sep}${sep === posix.sep ? '' : sep}]`.replace(/(\\)/g, '\\$1')) 131cb0ef41Sopenharmony_ciconst rRel = new RegExp(`^\\.${rSlash.source}`) 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ciconst getNotFoundError = (cmd) => 161cb0ef41Sopenharmony_ci Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' }) 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciconst getPathInfo = (cmd, { 191cb0ef41Sopenharmony_ci path: optPath = process.env.PATH, 201cb0ef41Sopenharmony_ci pathExt: optPathExt = process.env.PATHEXT, 211cb0ef41Sopenharmony_ci delimiter: optDelimiter = delimiter, 221cb0ef41Sopenharmony_ci}) => { 231cb0ef41Sopenharmony_ci // If it has a slash, then we don't bother searching the pathenv. 241cb0ef41Sopenharmony_ci // just check the file itself, and that's it. 251cb0ef41Sopenharmony_ci const pathEnv = cmd.match(rSlash) ? [''] : [ 261cb0ef41Sopenharmony_ci // windows always checks the cwd first 271cb0ef41Sopenharmony_ci ...(isWindows ? [process.cwd()] : []), 281cb0ef41Sopenharmony_ci ...(optPath || /* istanbul ignore next: very unusual */ '').split(optDelimiter), 291cb0ef41Sopenharmony_ci ] 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci if (isWindows) { 321cb0ef41Sopenharmony_ci const pathExtExe = optPathExt || 331cb0ef41Sopenharmony_ci ['.EXE', '.CMD', '.BAT', '.COM'].join(optDelimiter) 341cb0ef41Sopenharmony_ci const pathExt = pathExtExe.split(optDelimiter).flatMap((item) => [item, item.toLowerCase()]) 351cb0ef41Sopenharmony_ci if (cmd.includes('.') && pathExt[0] !== '') { 361cb0ef41Sopenharmony_ci pathExt.unshift('') 371cb0ef41Sopenharmony_ci } 381cb0ef41Sopenharmony_ci return { pathEnv, pathExt, pathExtExe } 391cb0ef41Sopenharmony_ci } 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci return { pathEnv, pathExt: [''] } 421cb0ef41Sopenharmony_ci} 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ciconst getPathPart = (raw, cmd) => { 451cb0ef41Sopenharmony_ci const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw 461cb0ef41Sopenharmony_ci const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : '' 471cb0ef41Sopenharmony_ci return prefix + join(pathPart, cmd) 481cb0ef41Sopenharmony_ci} 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ciconst which = async (cmd, opt = {}) => { 511cb0ef41Sopenharmony_ci const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt) 521cb0ef41Sopenharmony_ci const found = [] 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci for (const envPart of pathEnv) { 551cb0ef41Sopenharmony_ci const p = getPathPart(envPart, cmd) 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci for (const ext of pathExt) { 581cb0ef41Sopenharmony_ci const withExt = p + ext 591cb0ef41Sopenharmony_ci const is = await isexe(withExt, { pathExt: pathExtExe, ignoreErrors: true }) 601cb0ef41Sopenharmony_ci if (is) { 611cb0ef41Sopenharmony_ci if (!opt.all) { 621cb0ef41Sopenharmony_ci return withExt 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci found.push(withExt) 651cb0ef41Sopenharmony_ci } 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci if (opt.all && found.length) { 701cb0ef41Sopenharmony_ci return found 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci if (opt.nothrow) { 741cb0ef41Sopenharmony_ci return null 751cb0ef41Sopenharmony_ci } 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci throw getNotFoundError(cmd) 781cb0ef41Sopenharmony_ci} 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ciconst whichSync = (cmd, opt = {}) => { 811cb0ef41Sopenharmony_ci const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt) 821cb0ef41Sopenharmony_ci const found = [] 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci for (const pathEnvPart of pathEnv) { 851cb0ef41Sopenharmony_ci const p = getPathPart(pathEnvPart, cmd) 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci for (const ext of pathExt) { 881cb0ef41Sopenharmony_ci const withExt = p + ext 891cb0ef41Sopenharmony_ci const is = isexeSync(withExt, { pathExt: pathExtExe, ignoreErrors: true }) 901cb0ef41Sopenharmony_ci if (is) { 911cb0ef41Sopenharmony_ci if (!opt.all) { 921cb0ef41Sopenharmony_ci return withExt 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci found.push(withExt) 951cb0ef41Sopenharmony_ci } 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci if (opt.all && found.length) { 1001cb0ef41Sopenharmony_ci return found 1011cb0ef41Sopenharmony_ci } 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci if (opt.nothrow) { 1041cb0ef41Sopenharmony_ci return null 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci throw getNotFoundError(cmd) 1081cb0ef41Sopenharmony_ci} 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_cimodule.exports = which 1111cb0ef41Sopenharmony_ciwhich.sync = whichSync 112