"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const error_1 = __importDefault(require("@pnpm/error"));
const can_write_to_dir_1 = require("can-write-to-dir");
const fs = require("fs");
const path = require("path");
const PATH = require("path-name");
function default_1(knownCandidates = [], { shouldAllowWrite = true } = {}) {
    var _a, _b;
    if (!process.env[PATH]) {
        throw new error_1.default('NO_PATH_ENV', `Couldn't find a global directory for executables because the "${PATH}" environment variable is not set.`);
    }
    const dirs = (_b = (_a = process.env[PATH]) === null || _a === void 0 ? void 0 : _a.split(path.delimiter)) !== null && _b !== void 0 ? _b : [];
    const nodeBinDir = path.dirname(process.execPath);
    return pickBestGlobalBinDir(dirs, [
        ...knownCandidates,
        nodeBinDir,
    ], shouldAllowWrite);
}
exports.default = default_1;
const areDirsEqual = (dir1, dir2) => path.relative(dir1, dir2) === '';
function pickBestGlobalBinDir(dirs, knownCandidates, shouldAllowWrite) {
    const noWriteAccessDirs = [];
    for (const dir of dirs) {
        const lowCaseDir = dir.toLowerCase();
        if (isUnderDir('node', lowCaseDir) ||
            isUnderDir('nodejs', lowCaseDir) ||
            isUnderDir('npm', lowCaseDir) ||
            isUnderDir('pnpm', lowCaseDir) ||
            knownCandidates.some((candidate) => areDirsEqual(candidate, dir)) ||
            dirHasNodeRelatedCommand(dir)) {
            if (canWriteToDirAndExists(dir))
                return dir;
            noWriteAccessDirs.push(dir);
        }
    }
    if (noWriteAccessDirs.length === 0) {
        throw new error_1.default('NO_GLOBAL_BIN_DIR', "Couldn't find a suitable global executables directory.", {
            hint: `There should be a node, nodejs, npm, or pnpm directory in the "${PATH}" environment variable`,
        });
    }
    if (shouldAllowWrite) {
        throw new error_1.default('GLOBAL_BIN_DIR_PERMISSION', 'No write access to the found global executable directories', {
            hint: `The found directories:
  ${noWriteAccessDirs.join('\n')}`,
        });
    }
    return noWriteAccessDirs[0];
}
const NODE_RELATED_COMMANDS = new Set(['pnpm', 'npm', 'node']);
function dirHasNodeRelatedCommand(dir) {
    try {
        return fs.readdirSync(dir, { withFileTypes: true })
            // We are searching for files or symlinks, not directories
            .filter((entry) => !entry.isDirectory())
            .map(({ name }) => name.toLowerCase())
            .some((file) => NODE_RELATED_COMMANDS.has(file.split('.')[0]));
    }
    catch (err) {
        return false;
    }
}
function isUnderDir(dir, target) {
    target = target.endsWith(path.sep) ? target : `${target}${path.sep}`;
    return target.includes(`${path.sep}${dir}${path.sep}`) ||
        target.includes(`${path.sep}.${dir}${path.sep}`);
}
function canWriteToDirAndExists(dir) {
    try {
        return can_write_to_dir_1.sync(dir);
    }
    catch (err) {
        if (err.code !== 'ENOENT')
            throw err;
        return false;
    }
}
//# sourceMappingURL=index.js.map