"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 rimraf = require("rimraf-then");
const path = require("path");
const dp = require("dependency-path");
const package_store_1 = require("package-store");
const R = require("ramda");
const removeTopDependency_1 = require("../removeTopDependency");
const logger_1 = require("@pnpm/logger");
const getSaveType_1 = require("../getSaveType");
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({
                name: depName[0],
                dev: Boolean(opts.oldShrinkwrap.devDependencies && opts.oldShrinkwrap.devDependencies[depName[0]]),
                optional: Boolean(opts.oldShrinkwrap.optionalDependencies && opts.oldShrinkwrap.optionalDependencies[depName[0]]),
            }, {
                modules: rootModules,
                bin: opts.bin,
            });
        }));
        const oldPkgIds = getPackageIds(opts.oldShrinkwrap.registry, opts.oldShrinkwrap.packages || {});
        const newPkgIds = getPackageIds(opts.newShrinkwrap.registry, opts.newShrinkwrap.packages || {});
        const notDependents = R.difference(oldPkgIds, newPkgIds);
        if (notDependents.length) {
            logger_1.default.info(`Removing ${notDependents.length} orphan packages from node_modules`);
            yield Promise.all(notDependents.map((notDependent) => __awaiter(this, void 0, void 0, function* () {
                if (opts.storeIndex[notDependent]) {
                    opts.storeIndex[notDependent].splice(opts.storeIndex[notDependent].indexOf(opts.prefix), 1);
                    if (opts.pruneStore && !opts.storeIndex[notDependent].length) {
                        delete opts.storeIndex[notDependent];
                        yield rimraf(path.join(opts.store, notDependent));
                    }
                }
                yield rimraf(path.join(rootModules, `.${notDependent}`));
            })));
        }
        const newDependents = R.difference(newPkgIds, oldPkgIds);
        newDependents.forEach(newDependent => {
            opts.storeIndex[newDependent] = opts.storeIndex[newDependent] || [];
            if (opts.storeIndex[newDependent].indexOf(opts.prefix) === -1) {
                opts.storeIndex[newDependent].push(opts.prefix);
            }
        });
        yield package_store_1.save(opts.store, opts.storeIndex);
        return notDependents;
    });
}
exports.default = removeOrphanPkgs;
function getPackageIds(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