'use strict';

var require$$0 = require('fs');
var require$$1 = require('fs/promises');
var require$$1$1 = require('path');

var cjs = {};

var posix = {};

var hasRequiredPosix;
function requirePosix() {
  if (hasRequiredPosix) return posix;
  hasRequiredPosix = 1;
  /**
   * This is the Posix implementation of isexe, which uses the file
   * mode and uid/gid values.
   *
   * @module
   */
  Object.defineProperty(posix, "__esModule", {
    value: true
  });
  posix.sync = posix.isexe = void 0;
  const fs_1 = require$$0;
  const promises_1 = require$$1;
  /**
   * Determine whether a path is executable according to the mode and
   * current (or specified) user and group IDs.
   */
  const isexe = async (path, options = {}) => {
    const {
      ignoreErrors = false
    } = options;
    try {
      return checkStat(await (0, promises_1.stat)(path), options);
    } catch (e) {
      const er = e;
      if (ignoreErrors || er.code === 'EACCES') return false;
      throw er;
    }
  };
  posix.isexe = isexe;
  /**
   * Synchronously determine whether a path is executable according to
   * the mode and current (or specified) user and group IDs.
   */
  const sync = (path, options = {}) => {
    const {
      ignoreErrors = false
    } = options;
    try {
      return checkStat((0, fs_1.statSync)(path), options);
    } catch (e) {
      const er = e;
      if (ignoreErrors || er.code === 'EACCES') return false;
      throw er;
    }
  };
  posix.sync = sync;
  const checkStat = (stat, options) => stat.isFile() && checkMode(stat, options);
  const checkMode = (stat, options) => {
    const myUid = options.uid ?? process.getuid?.();
    const myGroups = options.groups ?? process.getgroups?.() ?? [];
    const myGid = options.gid ?? process.getgid?.() ?? myGroups[0];
    if (myUid === undefined || myGid === undefined) {
      throw new Error('cannot get uid or gid');
    }
    const groups = new Set([myGid, ...myGroups]);
    const mod = stat.mode;
    const uid = stat.uid;
    const gid = stat.gid;
    const u = parseInt('100', 8);
    const g = parseInt('010', 8);
    const o = parseInt('001', 8);
    const ug = u | g;
    return !!(mod & o || mod & g && groups.has(gid) || mod & u && uid === myUid || mod & ug && myUid === 0);
  };
  return posix;
}

var win32 = {};

var hasRequiredWin32;
function requireWin32() {
  if (hasRequiredWin32) return win32;
  hasRequiredWin32 = 1;
  /**
   * This is the Windows implementation of isexe, which uses the file
   * extension and PATHEXT setting.
   *
   * @module
   */
  Object.defineProperty(win32, "__esModule", {
    value: true
  });
  win32.sync = win32.isexe = void 0;
  const fs_1 = require$$0;
  const promises_1 = require$$1;
  /**
   * Determine whether a path is executable based on the file extension
   * and PATHEXT environment variable (or specified pathExt option)
   */
  const isexe = async (path, options = {}) => {
    const {
      ignoreErrors = false
    } = options;
    try {
      return checkStat(await (0, promises_1.stat)(path), path, options);
    } catch (e) {
      const er = e;
      if (ignoreErrors || er.code === 'EACCES') return false;
      throw er;
    }
  };
  win32.isexe = isexe;
  /**
   * Synchronously determine whether a path is executable based on the file
   * extension and PATHEXT environment variable (or specified pathExt option)
   */
  const sync = (path, options = {}) => {
    const {
      ignoreErrors = false
    } = options;
    try {
      return checkStat((0, fs_1.statSync)(path), path, options);
    } catch (e) {
      const er = e;
      if (ignoreErrors || er.code === 'EACCES') return false;
      throw er;
    }
  };
  win32.sync = sync;
  const checkPathExt = (path, options) => {
    const {
      pathExt = process.env.PATHEXT || ''
    } = options;
    const peSplit = pathExt.split(';');
    if (peSplit.indexOf('') !== -1) {
      return true;
    }
    for (let i = 0; i < peSplit.length; i++) {
      const p = peSplit[i].toLowerCase();
      const ext = path.substring(path.length - p.length).toLowerCase();
      if (p && ext === p) {
        return true;
      }
    }
    return false;
  };
  const checkStat = (stat, path, options) => stat.isFile() && checkPathExt(path, options);
  return win32;
}

var options = {};

var hasRequiredOptions;
function requireOptions() {
  if (hasRequiredOptions) return options;
  hasRequiredOptions = 1;
  Object.defineProperty(options, "__esModule", {
    value: true
  });
  return options;
}

var hasRequiredCjs;
function requireCjs() {
  if (hasRequiredCjs) return cjs;
  hasRequiredCjs = 1;
  (function (exports) {

    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 __setModuleDefault = this && this.__setModuleDefault || (Object.create ? function (o, v) {
      Object.defineProperty(o, "default", {
        enumerable: true,
        value: v
      });
    } : function (o, v) {
      o["default"] = v;
    });
    var __importStar = this && this.__importStar || function (mod) {
      if (mod && mod.__esModule) return mod;
      var result = {};
      if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
      __setModuleDefault(result, mod);
      return result;
    };
    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.sync = exports.isexe = exports.posix = exports.win32 = void 0;
    const posix = __importStar(requirePosix());
    exports.posix = posix;
    const win32 = __importStar(requireWin32());
    exports.win32 = win32;
    __exportStar(requireOptions(), exports);
    const platform = process.env._ISEXE_TEST_PLATFORM_ || process.platform;
    const impl = platform === 'win32' ? win32 : posix;
    /**
     * Determine whether a path is executable on the current platform.
     */
    exports.isexe = impl.isexe;
    /**
     * Synchronously determine whether a path is executable on the
     * current platform.
     */
    exports.sync = impl.sync;
  })(cjs);
  return cjs;
}

var lib;
var hasRequiredLib;
function requireLib() {
  if (hasRequiredLib) return lib;
  hasRequiredLib = 1;
  const {
    isexe,
    sync: isexeSync
  } = requireCjs();
  const {
    join,
    delimiter,
    sep,
    posix
  } = require$$1$1;
  const isWindows = process.platform === 'win32';

  // used to check for slashed in commands passed in. always checks for the posix
  // seperator on all platforms, and checks for the current separator when not on
  // a posix platform. don't use the isWindows check for this since that is mocked
  // in tests but we still need the code to actually work when called. that is also
  // why it is ignored from coverage.
  /* istanbul ignore next */
  const rSlash = new RegExp(`[${posix.sep}${sep === posix.sep ? '' : sep}]`.replace(/(\\)/g, '\\$1'));
  const rRel = new RegExp(`^\\.${rSlash.source}`);
  const getNotFoundError = cmd => Object.assign(new Error(`not found: ${cmd}`), {
    code: 'ENOENT'
  });
  const getPathInfo = (cmd, {
    path: optPath = process.env.PATH,
    pathExt: optPathExt = process.env.PATHEXT,
    delimiter: optDelimiter = delimiter
  }) => {
    // If it has a slash, then we don't bother searching the pathenv.
    // just check the file itself, and that's it.
    const pathEnv = cmd.match(rSlash) ? [''] : [
    // windows always checks the cwd first
    ...(isWindows ? [process.cwd()] : []), ...(optPath || /* istanbul ignore next: very unusual */'').split(optDelimiter)];
    if (isWindows) {
      const pathExtExe = optPathExt || ['.EXE', '.CMD', '.BAT', '.COM'].join(optDelimiter);
      const pathExt = pathExtExe.split(optDelimiter).flatMap(item => [item, item.toLowerCase()]);
      if (cmd.includes('.') && pathExt[0] !== '') {
        pathExt.unshift('');
      }
      return {
        pathEnv,
        pathExt,
        pathExtExe
      };
    }
    return {
      pathEnv,
      pathExt: ['']
    };
  };
  const getPathPart = (raw, cmd) => {
    const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw;
    const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : '';
    return prefix + join(pathPart, cmd);
  };
  const which = async (cmd, opt = {}) => {
    const {
      pathEnv,
      pathExt,
      pathExtExe
    } = getPathInfo(cmd, opt);
    const found = [];
    for (const envPart of pathEnv) {
      const p = getPathPart(envPart, cmd);
      for (const ext of pathExt) {
        const withExt = p + ext;
        const is = await isexe(withExt, {
          pathExt: pathExtExe,
          ignoreErrors: true
        });
        if (is) {
          if (!opt.all) {
            return withExt;
          }
          found.push(withExt);
        }
      }
    }
    if (opt.all && found.length) {
      return found;
    }
    if (opt.nothrow) {
      return null;
    }
    throw getNotFoundError(cmd);
  };
  const whichSync = (cmd, opt = {}) => {
    const {
      pathEnv,
      pathExt,
      pathExtExe
    } = getPathInfo(cmd, opt);
    const found = [];
    for (const pathEnvPart of pathEnv) {
      const p = getPathPart(pathEnvPart, cmd);
      for (const ext of pathExt) {
        const withExt = p + ext;
        const is = isexeSync(withExt, {
          pathExt: pathExtExe,
          ignoreErrors: true
        });
        if (is) {
          if (!opt.all) {
            return withExt;
          }
          found.push(withExt);
        }
      }
    }
    if (opt.all && found.length) {
      return found;
    }
    if (opt.nothrow) {
      return null;
    }
    throw getNotFoundError(cmd);
  };
  lib = which;
  which.sync = whichSync;
  return lib;
}

var which;
var hasRequiredWhich;
function requireWhich() {
  if (hasRequiredWhich) return which;
  hasRequiredWhich = 1;
  which = requireLib();
  return which;
}

var whichExports = requireWhich();

module.exports = whichExports;
