"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const error_1 = require("@pnpm/error");
const supi_1 = require("supi");
const createStoreController_1 = require("../createStoreController");
const findWorkspacePackages_1 = require("../findWorkspacePackages");
const getPinnedVersion_1 = require("../getPinnedVersion");
const getSaveType_1 = require("../getSaveType");
const readImporterManifest_1 = require("../readImporterManifest");
const requireHooks_1 = require("../requireHooks");
const updateToLatestSpecsFromManifest_1 = require("../updateToLatestSpecsFromManifest");
const recursive_1 = require("./recursive");
const OVERWRITE_UPDATE_OPTIONS = {
    allowNew: true,
    update: false,
};
/**
 * Perform installation.
 * @example
 *     installCmd([ 'lodash', 'foo' ], { silent: true })
 */
async function installCmd(input, opts, invocation) {
    // `pnpm install ""` is going to be just `pnpm install`
    input = input.filter(Boolean);
    const dir = opts.dir || process.cwd();
    const localPackages = opts.linkWorkspacePackages && opts.workspaceDir
        ? findWorkspacePackages_1.arrayOfLocalPackagesToMap(await findWorkspacePackages_1.default(opts.workspaceDir, opts))
        : undefined;
    if (!opts.ignorePnpmfile) {
        opts.hooks = requireHooks_1.default(opts.lockfileDir || dir, opts);
    }
    const store = await createStoreController_1.default(opts);
    const installOpts = {
        ...opts,
        // In case installation is done in a multi-package repository
        // The dependencies should be built first,
        // so ignoring scripts for now
        ignoreScripts: !!localPackages || opts.ignoreScripts,
        localPackages,
        storeController: store.ctrl,
        storeDir: store.dir,
        forceHoistPattern: typeof opts.rawLocalConfig['hoist-pattern'] !== 'undefined' || typeof opts.rawLocalConfig['hoist'] !== 'undefined',
        forceIndependentLeaves: typeof opts.rawLocalConfig['independent-leaves'] !== 'undefined',
        forceShamefullyHoist: typeof opts.rawLocalConfig['shamefully-hoist'] !== 'undefined',
    };
    let { manifest, writeImporterManifest } = await readImporterManifest_1.tryReadImporterManifest(opts.dir, opts);
    if (manifest === null) {
        if (opts.update) {
            throw new error_1.default('NO_IMPORTER_MANIFEST', 'No package.json found');
        }
        manifest = {};
    }
    if (opts.update && opts.latest) {
        if (!input || !input.length) {
            input = updateToLatestSpecsFromManifest_1.default(manifest, opts.include);
        }
        else {
            input = updateToLatestSpecsFromManifest_1.createLatestSpecs(input, manifest);
        }
        delete installOpts.include;
    }
    if (!input || !input.length) {
        if (invocation === 'add') {
            throw new error_1.default('MISSING_PACKAGE_NAME', '`pnpm add` requires the package name');
        }
        const updatedManifest = await supi_1.install(manifest, installOpts);
        if (opts.update === true && opts.save !== false) {
            await writeImporterManifest(updatedManifest);
        }
    }
    else {
        const [updatedImporter] = await supi_1.mutateModules([
            {
                allowNew: opts.allowNew,
                binsDir: installOpts.bin,
                dependencySelectors: input,
                manifest,
                mutation: 'installSome',
                peer: opts.savePeer,
                pinnedVersion: getPinnedVersion_1.default(opts),
                rootDir: installOpts.dir,
                targetDependenciesField: getSaveType_1.default(installOpts),
            },
        ], installOpts);
        if (opts.save !== false) {
            await writeImporterManifest(updatedImporter.manifest);
        }
    }
    if (opts.linkWorkspacePackages && opts.workspaceDir) {
        // TODO: reuse somehow the previous read of packages
        // this is not optimal
        const allWorkspacePkgs = await findWorkspacePackages_1.default(opts.workspaceDir, opts);
        await recursive_1.recursive(allWorkspacePkgs, [], {
            ...opts,
            ...OVERWRITE_UPDATE_OPTIONS,
            ignoredPackages: new Set([dir]),
            packageSelectors: [
                {
                    pattern: dir,
                    scope: 'dependencies',
                    selectBy: 'location',
                },
            ],
            workspaceDir: opts.workspaceDir,
        }, 'install', 'install');
        if (opts.ignoreScripts)
            return;
        await supi_1.rebuild([
            {
                buildIndex: 0,
                manifest: await readImporterManifest_1.readImporterManifestOnly(opts.dir, opts),
                rootDir: opts.dir,
            },
        ], {
            ...opts,
            pending: true,
            storeController: store.ctrl,
            storeDir: store.dir,
        });
    }
}
exports.default = installCmd;
