"use strict";
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 __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const isEqual_1 = __importDefault(require("lodash/isEqual"));
const propertyOf_1 = __importDefault(require("lodash/propertyOf"));
const cli_options_1 = __importStar(require("../cli-options"));
const logging_1 = require("../lib/logging");
const cache_1 = __importDefault(require("./cache"));
const determinePackageManager_1 = __importDefault(require("./determinePackageManager"));
const exists_1 = __importDefault(require("./exists"));
const programError_1 = __importDefault(require("./programError"));
/** Trims and filters out empty values from a filter expression. */
function parseFilterExpression(filterExpression) {
    if (typeof filterExpression === 'string') {
        return filterExpression.trim();
    }
    else if (Array.isArray(filterExpression) &&
        (filterExpression.length === 0 || typeof filterExpression[0] === 'string')) {
        const filtered = filterExpression.map(s => s.trim()).filter(x => x);
        return filtered.length > 0 ? filtered : undefined;
    }
    else {
        return filterExpression;
    }
}
/** Initializes, validates, sets defaults, and consolidates program options. */
async function initOptions(runOptions, { cli } = {}) {
    var _a, _b, _c, _d, _e;
    const { default: chalkDefault, Chalk } = await import('chalk');
    const chalk = runOptions.color ? new Chalk({ level: 1 }) : chalkDefault;
    // if not executed on the command-line (i.e. executed as a node module), set the defaults
    if (!cli) {
        // set cli defaults since they are not set by commander in this case
        const cliDefaults = cli_options_1.default.reduce((acc, curr) => ({
            ...acc,
            ...(curr.default != null ? { [curr.long]: curr.default } : null),
        }), {});
        // set default options that are specific to module usage
        const moduleDefaults = {
            jsonUpgraded: true,
            silent: runOptions.silent || (runOptions.loglevel === undefined && !runOptions.verbose),
            args: [],
        };
        runOptions = { ...cliDefaults, ...moduleDefaults, ...runOptions };
    }
    // convert packageData to string to convert RunOptions to Options
    const options = {
        ...runOptions,
        ...(runOptions.packageData && typeof runOptions.packageData !== 'string'
            ? { packageData: JSON.stringify(runOptions.packageData, null, 2) }
            : null),
        cli,
    };
    // consolidate loglevel
    const loglevel = options.silent || ((_a = options.format) === null || _a === void 0 ? void 0 : _a.includes('lines')) ? 'silent' : options.verbose ? 'verbose' : options.loglevel;
    const json = Object.keys(options)
        .filter(option => option.startsWith('json'))
        .some((0, propertyOf_1.default)(options));
    if (!json && loglevel !== 'silent' && options.rcConfigPath && !options.doctor) {
        (0, logging_1.print)(options, `Using config file ${options.rcConfigPath}`);
    }
    // warn about deprecated options
    const deprecatedOptions = cli_options_1.default.filter(({ long, deprecated }) => (deprecated && options[long]) ||
        // special case to deprecate a value but not the entire option
        (long === 'packageManager' && options.packageManager === 'staticRegistry'));
    if (deprecatedOptions.length > 0) {
        deprecatedOptions.forEach(({ long, description }) => {
            const deprecationMessage = long === 'packageManager'
                ? '--packageManager staticRegistry is deprecated. Use --registryType json.'
                : `--${long}: ${description}`;
            (0, logging_1.print)(options, chalk.yellow(deprecationMessage), 'warn');
        });
        (0, logging_1.print)(options, '', 'warn');
    }
    // validate options with predefined choices
    cli_options_1.default.forEach(({ long, choices }) => {
        if (!choices || choices.length === 0)
            return;
        const value = options[long];
        const values = Array.isArray(value) ? value : [value];
        if (values.length === 0)
            return;
        // make sure the option value is valid
        // if an array of values is given, make sure each one is a valid choice
        if (values.every(value => !choices.includes(value))) {
            (0, programError_1.default)(options, `Invalid option value: --${long} ${value}. Valid values are: ${choices.join(', ')}.`);
        }
    });
    // validate options.cwd
    if (options.cwd && !(await (0, exists_1.default)(options.cwd))) {
        (0, programError_1.default)(options, `No such directory: ${options.cwd}`);
    }
    // trim filter args
    // disallow non-matching filter and args
    const args = parseFilterExpression(options.args);
    const filter = parseFilterExpression(options.filter);
    const filterVersion = parseFilterExpression(options.filterVersion);
    const reject = parseFilterExpression(options.reject);
    const rejectVersion = parseFilterExpression(options.rejectVersion);
    // convert to string for comparison purposes
    // otherwise ['a b'] will not match ['a', 'b']
    if (options.filter && args && !(0, isEqual_1.default)(args.join(' '), Array.isArray(filter) ? filter.join(' ') : filter)) {
        (0, programError_1.default)(options, 'Cannot specify a filter using both --filter and args. Did you forget to quote an argument?\nSee: https://github.com/raineorshine/npm-check-updates/issues/759#issuecomment-723587297');
    }
    // disallow packageFile and --deep
    else if (options.packageFile && options.deep) {
        (0, programError_1.default)(options, `Cannot specify both --packageFile and --deep. --deep is an alias for --packageFile '**/package.json'`);
    }
    // disallow --workspace and --workspaces
    else if (((_b = options.workspace) === null || _b === void 0 ? void 0 : _b.length) && options.workspaces) {
        (0, programError_1.default)(options, 'Cannot specify both --workspace and --workspaces.');
    }
    // disallow --workspace(s) and --deep
    else if (options.deep && (((_c = options.workspace) === null || _c === void 0 ? void 0 : _c.length) || options.workspaces)) {
        (0, programError_1.default)(options, `Cannot specify both --deep and --workspace${options.workspaces ? 's' : ''}.`);
    }
    // disallow --workspace(s) and --doctor
    else if (options.doctor && (((_d = options.workspace) === null || _d === void 0 ? void 0 : _d.length) || options.workspaces)) {
        (0, programError_1.default)(options, `Doctor mode is not currently supported with --workspace${options.workspaces ? 's' : ''}.`);
    }
    // disallow missing registry path when using registryType
    else if (options.packageManager === 'staticRegistry' && !options.registry) {
        (0, programError_1.default)(options, 'When --package-manager staticRegistry is specified, you must provide the path for the registry file with --registry.');
    }
    else if (options.registryType === 'json' && !options.registry) {
        (0, programError_1.default)(options, 'When --registryType json is specified, you must provide the path for the registry file with --registry. Run "ncu --help registryType" for details.');
    }
    const target = options.target || 'latest';
    const autoPre = target === 'newest' || target === 'greatest';
    const packageManager = await (0, determinePackageManager_1.default)(options);
    const resolvedOptions = {
        ...options,
        ...(options.deep ? { packageFile: '**/package.json' } : null),
        ...(packageManager === 'deno' && options.dep !== cli_options_1.cliOptionsMap.dep.default ? { dep: ['imports'] } : null),
        ...(options.format && options.format.length > 0 ? { format: options.format } : null),
        filter: args || filter,
        filterVersion,
        // add shortcut for any keys that start with 'json'
        json,
        loglevel,
        minimal: options.minimal === undefined ? false : options.minimal,
        // default to false, except when newest or greatest are set
        // this is overriden on a per-dependency basis in queryVersions to allow prereleases to be upgraded to newer prereleases
        ...(options.pre != null || autoPre ? { pre: options.pre != null ? !!options.pre : autoPre } : null),
        reject,
        rejectVersion,
        target,
        // imply upgrade in interactive mode when json is not specified as the output
        ...(options.interactive && options.upgrade === undefined ? { upgrade: !json } : null),
        packageManager,
        registryType: options.registryType || (((_e = options.registry) === null || _e === void 0 ? void 0 : _e.endsWith('.json')) ? 'json' : 'npm'),
    };
    resolvedOptions.cacher = await (0, cache_1.default)(resolvedOptions);
    // print 'Using yarn/pnpm/etc' when autodetected
    // use resolved options so that options.json is set
    if (!options.packageManager && packageManager !== 'npm') {
        (0, logging_1.print)(resolvedOptions, `Using ${packageManager}`);
    }
    return resolvedOptions;
}
exports.default = initOptions;
//# sourceMappingURL=initOptions.js.map