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