"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 dp = require("dependency-path");
const path = require("path");
const R = require("ramda");
const rimraf = require("rimraf-then");
const getSaveType_1 = require("../getSaveType");
const loggers_1 = require("../loggers");
const removeTopDependency_1 = require("../removeTopDependency");
function removeOrphanPkgs(opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const oldPkgs = R.toPairs(R.mergeAll(R.map((depType) => opts.oldShrinkwrap[depType], getSaveType_1.dependenciesTypes)));
        const newPkgs = R.toPairs(R.mergeAll(R.map((depType) => opts.newShrinkwrap[depType], getSaveType_1.dependenciesTypes)));
        const removedTopDeps = R.difference(oldPkgs, newPkgs);
        const rootModules = path.join(opts.prefix, 'node_modules');
        yield Promise.all(removedTopDeps.map((depName) => {
            return removeTopDependency_1.default({
                dev: Boolean(opts.oldShrinkwrap.devDependencies && opts.oldShrinkwrap.devDependencies[depName[0]]),
                name: depName[0],
                optional: Boolean(opts.oldShrinkwrap.optionalDependencies && opts.oldShrinkwrap.optionalDependencies[depName[0]]),
            }, {
                bin: opts.bin,
                dryRun: opts.dryRun,
                modules: rootModules,
            });
        }));
        const oldDepPaths = getPkgsDepPaths(opts.oldShrinkwrap.registry, opts.oldShrinkwrap.packages || {});
        const newDepPaths = getPkgsDepPaths(opts.newShrinkwrap.registry, opts.newShrinkwrap.packages || {});
        const notDependents = R.difference(oldDepPaths, newDepPaths);
        loggers_1.statsLogger.debug({ removed: notDependents.length });
        if (!opts.dryRun) {
            if (notDependents.length) {
                if (opts.shamefullyFlatten && opts.oldShrinkwrap.packages) {
                    yield Promise.all(notDependents.map((notDependent) => __awaiter(this, void 0, void 0, function* () {
                        if (opts.hoistedAliases[notDependent]) {
                            yield Promise.all(opts.hoistedAliases[notDependent].map((alias) => __awaiter(this, void 0, void 0, function* () {
                                yield removeTopDependency_1.default({
                                    dev: false,
                                    name: alias,
                                    optional: false,
                                }, {
                                    bin: opts.bin,
                                    modules: rootModules,
                                    muteLogs: true,
                                });
                            })));
                        }
                        delete opts.hoistedAliases[notDependent];
                    })));
                }
                yield Promise.all(notDependents.map((notDependent) => __awaiter(this, void 0, void 0, function* () {
                    yield rimraf(path.join(rootModules, `.${notDependent}`));
                })));
            }
            const newDependents = R.difference(newDepPaths, oldDepPaths);
            yield opts.storeController.updateConnections(opts.prefix, {
                addDependencies: newDependents,
                prune: opts.pruneStore || false,
                removeDependencies: notDependents,
            });
            yield opts.storeController.saveState();
        }
        return new Set(notDependents);
    });
}
exports.default = removeOrphanPkgs;
function getPkgsDepPaths(registry, packages) {
    return R.uniq(R.keys(packages)
        .map((depPath) => {
        if (packages[depPath].id) {
            return packages[depPath].id;
        }
        return dp.resolve(registry, depPath);
    }));
}
//# sourceMappingURL=removeOrphanPkgs.js.map