"use strict";
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
// Map SIGINT & SIGTERM to process exit
// so that lockfiles are removed automatically
process
    .once('SIGINT', () => process.exit(0))
    .once('SIGTERM', () => process.exit(0));
// Patch the global fs module here at the app level
const chalk_1 = require("chalk");
const fs = require("fs");
const gfs = require("graceful-fs");
gfs.gracefulify(fs);
const loud_rejection_1 = require("loud-rejection");
loud_rejection_1.default();
const config_1 = require("@pnpm/config");
const logger_1 = require("@pnpm/logger");
const isCI = require("is-ci");
const nopt = require("nopt");
const checkForUpdates_1 = require("./checkForUpdates");
const cmd_1 = require("./cmd");
const getCommandFullName_1 = require("./getCommandFullName");
const getConfig_1 = require("./getConfig");
const loggers_1 = require("./loggers");
require("./logging/fileLogger");
const pnpmPkgJson_1 = require("./pnpmPkgJson");
const reporter_1 = require("./reporter");
cmd_1.default['install-test'] = cmd_1.default.installTest;
const GLOBAL_OPTIONS = new Set(['filter', 'help', 'prefix']);
const INSTALL_CLI_OPTIONS = new Set([
    'child-concurrency',
    'dev',
    'engine-strict',
    'frozen-lockfile',
    'force',
    'global-pnpmfile',
    'global',
    'hoist',
    'hoist-pattern',
    'ignore-pnpmfile',
    'ignore-scripts',
    'ignore-workspace-root-check',
    'independent-leaves',
    'link-workspace-packages',
    'lock',
    'lockfile-directory',
    'lockfile-only',
    'lockfile',
    'package-import-method',
    'pnpmfile',
    'prefer-frozen-lockfile',
    'prefer-offline',
    'production',
    'recursive',
    'registry',
    'reporter',
    'save-dev',
    'save-exact',
    'save-optional',
    'save-peer',
    'save-prod',
    'save-workspace-protocol',
    'shamefully-hoist',
    'shared-workspace-lockfile',
    'side-effects-cache-readonly',
    'side-effects-cache',
    'store',
    'strict-peer-dependencies',
    'offline',
    'only',
    'optional',
    'use-running-store-server',
    'use-store-server',
    'verify-store-integrity',
    'workspace-prefix',
]);
const SUPPORTED_CLI_OPTIONS = {
    'add': INSTALL_CLI_OPTIONS,
    'help': new Set([]),
    'import': new Set([]),
    'install': INSTALL_CLI_OPTIONS,
    'install-test': INSTALL_CLI_OPTIONS,
    'link': new Set([
        'only',
        'package-import-method',
        'production',
        'registry',
        'reporter',
        'save-dev',
        'save-exact',
        'save-optional',
    ]),
    'list': new Set([
        'depth',
        'dev',
        'global',
        'json',
        'long',
        'only',
        'optional',
        'parseable',
        'production',
        'recursive',
    ]),
    'outdated': new Set([
        'depth',
        'global',
        'long',
        'recursive',
        'table',
    ]),
    'pack': new Set([]),
    'prune': new Set([]),
    'publish': new Set([
        'tag',
    ]),
    'rebuild': new Set([
        'recursive',
    ]),
    'recursive': new Set([
        'bail',
        'link-workspace-packages',
        'shared-workspace-lockfile',
        'sort',
        'workspace-concurrency',
    ]),
    'restart': new Set([]),
    'root': new Set([
        'global',
    ]),
    'run': new Set([
        'recursive',
    ]),
    'server': new Set([
        'background',
        'ignore-stop-requests',
        'ignore-upload-requests',
        'port',
        'protocol',
        'store',
    ]),
    'start': new Set([]),
    'stop': new Set([]),
    'store': new Set([
        'registry',
    ]),
    'test': new Set([
        'recursive',
    ]),
    'uninstall': new Set([
        'force',
        'global-pnpmfile',
        'global',
        'lockfile-directory',
        'lockfile-only',
        'lockfile',
        'package-import-method',
        'pnpmfile',
        'recursive',
        'reporter',
        'shared-workspace-lockfile',
        'store',
    ]),
    'unlink': new Set([
        'recursive',
    ]),
    'update': new Set([
        'depth',
        'dev',
        'engine-strict',
        'force',
        'global-pnpmfile',
        'ignore-pnpmfile',
        'ignore-scripts',
        'latest',
        'lockfile-directory',
        'lockfile-only',
        'lockfile',
        'offline',
        'only',
        'optional',
        'package-import-method',
        'pnpmfile',
        'prefer-offline',
        'production',
        'recursive',
        'registry',
        'reporter',
        'save-exact',
        'shamefully-hoist',
        'shared-workspace-lockfile',
        'side-effects-cache-readonly',
        'side-effects-cache',
        'store',
        'use-running-store-server',
    ]),
    'why': new Set([
        'recursive',
    ]),
};
const supportedCmds = new Set([
    'add',
    'install',
    'uninstall',
    'update',
    'link',
    'pack',
    'prune',
    'publish',
    'install-test',
    'restart',
    'server',
    'start',
    'stop',
    'store',
    'list',
    'unlink',
    'help',
    'root',
    'outdated',
    'rebuild',
    'recursive',
    'import',
    'test',
    'run',
    'why',
]);
async function run(inputArgv) {
    // tslint:disable
    const shortHands = {
        's': ['--loglevel', 'silent'],
        'd': ['--loglevel', 'info'],
        'dd': ['--loglevel', 'verbose'],
        'ddd': ['--loglevel', 'silly'],
        'L': ['--latest'],
        'noreg': ['--no-registry'],
        'N': ['--no-registry'],
        'r': ['--recursive'],
        'no-reg': ['--no-registry'],
        'silent': ['--loglevel', 'silent'],
        'verbose': ['--loglevel', 'verbose'],
        'quiet': ['--loglevel', 'warn'],
        'q': ['--loglevel', 'warn'],
        'h': ['--usage'],
        'H': ['--usage'],
        '?': ['--usage'],
        'help': ['--usage'],
        'v': ['--version'],
        'f': ['--force'],
        'desc': ['--description'],
        'no-desc': ['--no-description'],
        'local': ['--no-global'],
        'l': ['--long'],
        'm': ['--message'],
        'p': ['--parseable'],
        'porcelain': ['--parseable'],
        'prod': ['--production'],
        'g': ['--global'],
        'S': ['--save'],
        'D': ['--save-dev'],
        'P': ['--save-prod'],
        'E': ['--save-exact'],
        'O': ['--save-optional'],
        'y': ['--yes'],
        'n': ['--no-yes'],
        'B': ['--save-bundle'],
        'C': ['--prefix'],
        'lockfile-directory': ['--shrinkwrap-directory'],
        'lockfile-only': ['--shrinkwrap-only'],
        'shared-workspace-lockfile': ['--shared-workspace-shrinkwrap'],
        'frozen-lockfile': ['--frozen-shrinkwrap'],
        'prefer-frozen-lockfile': ['--prefer-frozen-shrinkwrap'],
        'W': ['--ignore-workspace-root-check'],
    };
    // tslint:enable
    const _a = nopt(config_1.types, shortHands, inputArgv, 0), { argv } = _a, cliConf = __rest(_a, ["argv"]);
    process.env['npm_config_argv'] = JSON.stringify(argv);
    let cmd = getCommandFullName_1.default(argv.remain[0])
        || 'help';
    if (!supportedCmds.has(cmd)) {
        cmd = 'help';
    }
    if (cliConf['dry-run']) {
        console.error(`Error: 'dry-run' is not supported yet, sorry!`);
        process.exit(1);
    }
    let subCmd = argv.remain[1] && getCommandFullName_1.default(argv.remain[1]);
    const filterArgs = [];
    // `pnpm install ""` is going to be just `pnpm install`
    const cliArgs = argv.remain.slice(1).filter(Boolean);
    if (cmd !== 'recursive' && (inputArgv.includes('--filter') || cliConf['recursive'] === true)) {
        subCmd = cmd;
        cmd = 'recursive';
        cliArgs.unshift(subCmd);
    }
    else if (subCmd && !supportedCmds.has(subCmd)) {
        subCmd = null;
    }
    const allowedOptions = !subCmd
        ? SUPPORTED_CLI_OPTIONS[cmd]
        : new Set([...Array.from(SUPPORTED_CLI_OPTIONS[cmd]), ...Array.from(SUPPORTED_CLI_OPTIONS[subCmd])]);
    for (const cliOption of Object.keys(cliConf)) {
        if (!GLOBAL_OPTIONS.has(cliOption) && !allowedOptions.has(cliOption)) {
            console.error(`${chalk_1.default.bgRed.black('\u2009ERROR\u2009')} ${chalk_1.default.red(`Unknown option '${cliOption}'`)}`);
            console.log(`For help, run: pnpm help ${cmd}`);
            process.exit(1);
            return;
        }
    }
    let config;
    try {
        config = await getConfig_1.default(cliConf, {
            command: subCmd ? [cmd, subCmd] : [cmd],
            excludeReporter: false,
        });
        config.forceSharedLockfile = typeof config.workspacePrefix === 'string' && config.sharedWorkspaceLockfile === true;
        config.argv = argv;
        if (config.filter) {
            Array.prototype.push.apply(config.filter, filterArgs);
        }
        else {
            config.filter = filterArgs;
        }
    }
    catch (err) {
        // Reporting is not initialized at this point, so just printing the error
        console.error(`${chalk_1.default.bgRed.black('\u2009ERROR\u2009')} ${chalk_1.default.red(err.message)}`);
        console.log(`For help, run: pnpm help ${cmd}`);
        process.exit(1);
        return;
    }
    if ((cmd === 'add' || cmd === 'install') &&
        typeof config.workspacePrefix === 'string') {
        if (cliArgs.length === 0) {
            subCmd = cmd;
            cmd = 'recursive';
            cliArgs.unshift(subCmd);
        }
        else if (config.workspacePrefix === config.prefix &&
            !config.ignoreWorkspaceRootCheck) {
            // Reporting is not initialized at this point, so just printing the error
            console.error(`${chalk_1.default.bgRed.black('\u2009ERROR\u2009')} ${chalk_1.default.red('Running this command will add the dependency to the workspace root, ' +
                'which might not be what you want - if you really meant it, ' +
                'make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).')}`);
            console.log(`For help, run: pnpm help ${cmd}`);
            process.exit(1);
            return;
        }
    }
    const selfUpdate = config.global && (cmd === 'install' || cmd === 'update') && argv.remain.includes(pnpmPkgJson_1.default.name);
    // Don't check for updates
    //   1. on CI environments
    //   2. when in the middle of an actual update
    if (!isCI && !selfUpdate) {
        checkForUpdates_1.default();
    }
    const reporterType = (() => {
        if (config.loglevel === 'silent')
            return 'silent';
        if (config.reporter)
            return config.reporter;
        if (isCI || !process.stdout.isTTY)
            return 'append-only';
        return 'default';
    })();
    reporter_1.default(reporterType, {
        cmd,
        config,
        subCmd,
    });
    delete config.reporter; // This is a silly workaround because supi expects a function as config.reporter
    if (selfUpdate) {
        await cmd_1.default.server(['stop'], config); // tslint:disable-line:no-any
    }
    // NOTE: we defer the next stage, otherwise reporter might not catch all the logs
    await new Promise((resolve, reject) => {
        setTimeout(() => {
            if (cliConf['shamefully-flatten'] === true) {
                logger_1.default.info({
                    message: 'Installing a flat node_modules. Use flat node_modules only if you rely on buggy dependencies that you cannot fix.',
                    prefix: config.prefix,
                });
            }
            if (config.force === true) {
                logger_1.default.warn({
                    message: 'using --force I sure hope you know what you are doing',
                    prefix: config.prefix,
                });
            }
            if (cmd !== 'recursive') {
                loggers_1.scopeLogger.debug({
                    selected: 1,
                    workspacePrefix: config.workspacePrefix,
                });
            }
            try {
                const result = cmd_1.default[cmd](cliArgs, config, argv.remain[0]);
                if (result instanceof Promise) {
                    result
                        .then((output) => {
                        if (typeof output === 'string') {
                            process.stdout.write(output);
                        }
                        resolve();
                    })
                        .catch(reject);
                }
                else {
                    if (typeof result === 'string') {
                        process.stdout.write(result);
                    }
                    resolve();
                }
            }
            catch (err) {
                reject(err);
            }
        }, 0);
    });
}
exports.default = run;
