"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const core_loggers_1 = require("@pnpm/core-loggers");
const logger_1 = require("@pnpm/logger");
const modules_cleaner_1 = require("@pnpm/modules-cleaner");
const modules_yaml_1 = require("@pnpm/modules-yaml");
const utils_1 = require("@pnpm/utils");
const dp = require("dependency-path");
const path = require("path");
const pnpm_shrinkwrap_1 = require("pnpm-shrinkwrap");
const constants_1 = require("../constants");
const getContext_1 = require("../getContext");
const lock_1 = require("../lock");
const safeIsInnerLink_1 = require("../safeIsInnerLink");
const shamefullyFlattenGraph_1 = require("../shamefullyFlattenGraph");
const shrinkwrapsEqual_1 = require("../shrinkwrapsEqual");
const extendUninstallOptions_1 = require("./extendUninstallOptions");
const removeDeps_1 = require("./removeDeps");
function uninstall(pkgsToUninstall, maybeOpts) {
    return __awaiter(this, void 0, void 0, function* () {
        const reporter = maybeOpts && maybeOpts.reporter;
        if (reporter) {
            logger_1.streamParser.on('data', reporter);
        }
        const opts = yield extendUninstallOptions_1.default(maybeOpts);
        if (opts.lock) {
            yield lock_1.default(opts.prefix, _uninstall, {
                locks: opts.locks,
                prefix: opts.prefix,
                stale: opts.lockStaleDuration,
            });
        }
        else {
            yield _uninstall();
        }
        if (reporter) {
            logger_1.streamParser.removeListener('data', reporter);
        }
        function _uninstall() {
            return __awaiter(this, void 0, void 0, function* () {
                const ctx = yield getContext_1.getContextForSingleImporter(opts);
                if (!ctx.pkg) {
                    throw new Error('No package.json found - cannot uninstall');
                }
                return uninstallInContext(pkgsToUninstall, ctx, opts);
            });
        }
    });
}
exports.default = uninstall;
function uninstallInContext(pkgsToUninstall, ctx, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const makePartialCurrentShrinkwrap = !shrinkwrapsEqual_1.default(ctx.currentShrinkwrap, ctx.wantedShrinkwrap);
        const pkgJsonPath = path.join(ctx.prefix, 'package.json');
        const saveType = utils_1.getSaveType(opts);
        const pkg = yield removeDeps_1.default(pkgJsonPath, pkgsToUninstall, { prefix: opts.prefix, saveType });
        const newShr = pnpm_shrinkwrap_1.prune(ctx.wantedShrinkwrap, pkg, ctx.importerId, (message) => logger_1.default.warn({ message, prefix: ctx.prefix }));
        const removedPkgIds = yield modules_cleaner_1.prune({
            importers: [
                {
                    bin: opts.bin,
                    hoistedAliases: ctx.hoistedAliases,
                    id: ctx.importerId,
                    modulesDir: ctx.modulesDir,
                    prefix: ctx.prefix,
                    shamefullyFlatten: opts.shamefullyFlatten,
                },
            ],
            newShrinkwrap: newShr,
            oldShrinkwrap: ctx.currentShrinkwrap,
            shrinkwrapDirectory: opts.shrinkwrapDirectory,
            storeController: opts.storeController,
            virtualStoreDir: ctx.virtualStoreDir,
        });
        ctx.pendingBuilds = ctx.pendingBuilds.filter((pkgId) => !removedPkgIds.has(dp.resolve(newShr.registry, pkgId)));
        yield opts.storeController.close();
        const currentShrinkwrap = makePartialCurrentShrinkwrap
            ? pnpm_shrinkwrap_1.prune(ctx.currentShrinkwrap, pkg, ctx.importerId)
            : newShr;
        if (opts.shrinkwrap) {
            yield pnpm_shrinkwrap_1.write(ctx.shrinkwrapDirectory, newShr, currentShrinkwrap);
        }
        else {
            yield pnpm_shrinkwrap_1.writeCurrentOnly(ctx.shrinkwrapDirectory, currentShrinkwrap);
        }
        yield removeOuterLinks(pkgsToUninstall, ctx.modulesDir, {
            bin: opts.bin,
            prefix: opts.prefix,
            storePath: ctx.storePath,
        });
        if (opts.shamefullyFlatten) {
            ctx.hoistedAliases = (yield shamefullyFlattenGraph_1.shamefullyFlattenGraphByShrinkwrap(currentShrinkwrap, ctx.importerId, {
                modulesDir: ctx.modulesDir,
                prefix: opts.prefix,
                virtualStoreDir: ctx.virtualStoreDir,
            })) || {};
        }
        yield modules_yaml_1.write(ctx.virtualStoreDir, Object.assign({}, ctx.modulesFile, { importers: Object.assign({}, ctx.modulesFile && ctx.modulesFile.importers, { [ctx.importerId]: {
                    hoistedAliases: ctx.hoistedAliases,
                    shamefullyFlatten: opts.shamefullyFlatten,
                } }), included: ctx.include, independentLeaves: opts.independentLeaves, layoutVersion: constants_1.LAYOUT_VERSION, packageManager: `${opts.packageManager.name}@${opts.packageManager.version}`, pendingBuilds: ctx.pendingBuilds, skipped: Array.from(ctx.skipped).filter((pkgId) => !removedPkgIds.has(pkgId)), store: ctx.storePath }));
        core_loggers_1.summaryLogger.debug({ prefix: opts.prefix });
    });
}
exports.uninstallInContext = uninstallInContext;
function removeOuterLinks(pkgsToUninstall, modulesDir, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const safeIsInnerLinkOpts = {
            hideAlienModules: true,
            prefix: opts.prefix,
            storePath: opts.storePath,
        };
        // These packages are not in package.json, they were just linked in not installed
        for (const pkgToUninstall of pkgsToUninstall) {
            if ((yield safeIsInnerLink_1.default(modulesDir, pkgToUninstall, safeIsInnerLinkOpts)) !== true) {
                yield modules_cleaner_1.removeDirectDependency({
                    dev: false,
                    name: pkgToUninstall,
                    optional: false,
                }, {
                    bin: opts.bin,
                    modulesDir,
                    prefix: opts.prefix,
                });
            }
        }
    });
}
//# sourceMappingURL=index.js.map