real-executable-path
Version:
Find the first instance of an executable in the PATH, with expanding all symbolic links
59 lines (43 loc) • 1.73 kB
JavaScript
;
const {promisify} = require('util');
const {realpath} = require('fs');
const inspectWithKind = require('inspect-with-kind');
const isPlainObj = require('is-plain-obj');
const which = require('which');
const ARG_ERROR = 'Expected 1 or 2 arguments (<string>[, <Object>])';
const TYPE_ERROR = 'Expected an executable name inside the PATH (<string>), for exmaple `ls`, `git` and `node`';
const OPTION_ERROR = 'Expected an option object to be passed to `node-which` https://www.npmjs.com/package/which (`null` by default)';
const promisifiedRealpath = promisify(realpath);
const promisifiedWhich = promisify(which);
module.exports = async function realExecutablePath(...args) {
const argLen = args.length;
if (argLen === 0) {
const error = new RangeError(`${ARG_ERROR}, but got no arguments.`);
error.code = 'ERR_MISSING_ARGS';
throw error;
}
if (argLen !== 1 && argLen !== 2) {
throw new RangeError(`${ARG_ERROR}, but got ${argLen} arguments.`);
}
const [cmd, options] = args;
if (typeof cmd !== 'string') {
const error = new TypeError(`${TYPE_ERROR}, but got a non-string value ${inspectWithKind(cmd)}.`);
error.code = 'ERR_INVALID_ARG_TYPE';
throw error;
}
if (cmd.length === 0) {
throw new Error(`${TYPE_ERROR.replace(' (<string>)', '')}, but got '' (empty string).`);
}
if (argLen === 1) {
return promisifiedRealpath(await promisifiedWhich(cmd));
}
if (!isPlainObj(options)) {
throw new TypeError(`${OPTION_ERROR}, but got ${inspectWithKind(options)}.`);
}
if (options.all) {
throw new Error(`\`all\` option is not supported, but a value ${
inspectWithKind(options.all)
} was provided.`);
}
return promisifiedRealpath(await promisifiedWhich(cmd, options));
};