"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = exports.completion = exports.commandNames = exports.help = exports.cliOptionsTypes = exports.rcOptionsTypes = void 0;
const cli_utils_1 = require("@pnpm/cli-utils");
const common_cli_options_help_1 = require("@pnpm/common-cli-options-help");
const config_1 = require("@pnpm/config");
const error_1 = require("@pnpm/error");
const find_workspace_packages_1 = require("@pnpm/find-workspace-packages");
const manifest_utils_1 = require("@pnpm/manifest-utils");
const pnpmfile_1 = require("@pnpm/pnpmfile");
const store_connection_manager_1 = require("@pnpm/store-connection-manager");
const R = require("ramda");
const renderHelp = require("render-help");
const supi_1 = require("supi");
const getSaveType_1 = require("./getSaveType");
const recursive_1 = require("./recursive");
class RemoveMissingDepsError extends error_1.default {
    constructor(opts) {
        let message = 'Cannot remove ';
        message += `${opts.nonMatchedDependencies.map(dep => `'${dep}'`).join(', ')}: `;
        if (opts.availableDependencies.length > 0) {
            message += `no such ${opts.nonMatchedDependencies.length > 1 ? 'dependencies' : 'dependency'} `;
            message += `found${opts.targetDependenciesField ? ` in '${opts.targetDependenciesField}'` : ''}`;
            const hint = `Available dependencies: ${opts.availableDependencies.join(', ')}`;
            super('CANNOT_REMOVE_MISSING_DEPS', message, { hint });
            return;
        }
        message += opts.targetDependenciesField
            ? `project has no '${opts.targetDependenciesField}'`
            : 'project has no dependencies of any kind';
        super('CANNOT_REMOVE_MISSING_DEPS', message);
    }
}
function rcOptionsTypes() {
    return R.pick([
        'global-dir',
        'global-pnpmfile',
        'global',
        'lockfile-dir',
        'lockfile-directory',
        'lockfile-only',
        'lockfile',
        'package-import-method',
        'pnpmfile',
        'reporter',
        'save-dev',
        'save-optional',
        'save-prod',
        'shared-workspace-lockfile',
        'store',
        'store-dir',
        'virtual-store-dir',
    ], config_1.types);
}
exports.rcOptionsTypes = rcOptionsTypes;
exports.cliOptionsTypes = () => ({
    ...rcOptionsTypes(),
    ...R.pick(['force'], config_1.types),
    recursive: Boolean,
});
function help() {
    return renderHelp({
        aliases: ['rm', 'uninstall', 'un'],
        description: `Removes packages from \`node_modules\` and from the project's \`package.json\`.`,
        descriptionLists: [
            {
                title: 'Options',
                list: [
                    {
                        description: `Remove from every package found in subdirectories \
or from every workspace package, when executed inside a workspace. \
For options that may be used with \`-r\`, see "pnpm help recursive"`,
                        name: '--recursive',
                        shortAlias: '-r',
                    },
                    {
                        description: 'Remove the dependency only from "devDependencies"',
                        name: '--save-dev',
                        shortAlias: '-D',
                    },
                    {
                        description: 'Remove the dependency only from "optionalDependencies"',
                        name: '--save-optional',
                        shortAlias: '-O',
                    },
                    {
                        description: 'Remove the dependency only from "dependencies"',
                        name: '--save-prod',
                        shortAlias: '-P',
                    },
                    common_cli_options_help_1.OPTIONS.globalDir,
                    ...common_cli_options_help_1.UNIVERSAL_OPTIONS,
                ],
            },
            common_cli_options_help_1.FILTERING,
        ],
        url: cli_utils_1.docsUrl('remove'),
        usages: ['pnpm remove <pkg>[@<version>]...'],
    });
}
exports.help = help;
// Unlike npm, pnpm does not treat "r" as an alias of "remove".
// This way we avoid the confusion about whether "pnpm r" means remove, run, or recursive.
exports.commandNames = ['remove', 'uninstall', 'rm', 'un'];
exports.completion = (cliOpts, params) => {
    return cli_utils_1.readDepNameCompletions(cliOpts.dir);
};
async function handler(opts, params) {
    var _a;
    if (params.length === 0)
        throw new error_1.default('MUST_REMOVE_SOMETHING', 'At least one dependency name should be specified for removal');
    if (opts.recursive && opts.allProjects && opts.selectedProjectsGraph && opts.workspaceDir) {
        await recursive_1.default(opts.allProjects, params, { ...opts, selectedProjectsGraph: opts.selectedProjectsGraph, workspaceDir: opts.workspaceDir }, 'remove');
        return;
    }
    const store = await store_connection_manager_1.createOrConnectStoreController(opts);
    const removeOpts = Object.assign(opts, {
        storeController: store.ctrl,
        storeDir: store.dir,
    });
    if (!opts.ignorePnpmfile) {
        removeOpts['hooks'] = pnpmfile_1.requireHooks(opts.lockfileDir || opts.dir, opts);
    }
    removeOpts['workspacePackages'] = opts.workspaceDir
        ? find_workspace_packages_1.arrayOfWorkspacePackagesToMap(await find_workspace_packages_1.default(opts.workspaceDir, opts))
        : undefined;
    const targetDependenciesField = getSaveType_1.default(opts);
    const { manifest: currentManifest, writeProjectManifest, } = await cli_utils_1.readProjectManifest(opts.dir, opts);
    const availableDependencies = Object.keys(targetDependenciesField === undefined
        ? manifest_utils_1.getAllDependenciesFromManifest(currentManifest)
        : (_a = currentManifest[targetDependenciesField]) !== null && _a !== void 0 ? _a : {});
    const nonMatchedDependencies = R.without(availableDependencies, params);
    if (nonMatchedDependencies.length !== 0) {
        throw new RemoveMissingDepsError({
            availableDependencies,
            nonMatchedDependencies,
            targetDependenciesField,
        });
    }
    const [mutationResult] = await supi_1.mutateModules([
        {
            binsDir: opts.bin,
            dependencyNames: params,
            manifest: currentManifest,
            mutation: 'uninstallSome',
            rootDir: opts.dir,
            targetDependenciesField,
        },
    ], removeOpts);
    await writeProjectManifest(mutationResult.manifest);
}
exports.handler = handler;
//# sourceMappingURL=remove.js.map