"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 path = require("path");
const getContext_1 = require("./getContext");
const extendOptions_1 = require("./extendOptions");
const uninstall_1 = require("./uninstall");
const getPkgDirs_1 = require("../fs/getPkgDirs");
const readPkg_1 = require("../fs/readPkg");
const lock_1 = require("./lock");
function prune(maybeOpts) {
    return __awaiter(this, void 0, void 0, function* () {
        const opts = extendOptions_1.default(maybeOpts);
        const ctx = yield getContext_1.default(opts);
        return lock_1.default(ctx.storePath, function () {
            return __awaiter(this, void 0, void 0, function* () {
                if (!ctx.pkg) {
                    throw new Error('No package.json found - cannot prune');
                }
                const pkg = ctx.pkg;
                const extraneousPkgs = yield getExtraneousPkgs(pkg, ctx.root, opts.production);
                yield uninstall_1.uninstallInContext(extraneousPkgs, ctx.pkg, ctx, opts);
            });
        }, { stale: opts.lockStaleDuration });
    });
}
exports.prune = prune;
function prunePkgs(pkgsToPrune, maybeOpts) {
    return __awaiter(this, void 0, void 0, function* () {
        const opts = extendOptions_1.default(maybeOpts);
        const ctx = yield getContext_1.default(opts);
        return lock_1.default(ctx.storePath, function () {
            return __awaiter(this, void 0, void 0, function* () {
                if (!ctx.pkg) {
                    throw new Error('No package.json found - cannot prune');
                }
                const pkg = ctx.pkg;
                const extraneousPkgs = yield getExtraneousPkgs(pkg, ctx.root, opts.production);
                const notPrunable = pkgsToPrune.filter(pkgToPrune => extraneousPkgs.indexOf(pkgToPrune) === -1);
                if (notPrunable.length) {
                    const err = new Error(`Unable to prune ${notPrunable.join(', ')} because it is not an extraneous package`);
                    err['code'] = 'PRUNE_NOT_EXTR';
                    throw err;
                }
                yield uninstall_1.uninstallInContext(pkgsToPrune, ctx.pkg, ctx, opts);
            });
        }, { stale: opts.lockStaleDuration });
    });
}
exports.prunePkgs = prunePkgs;
function getExtraneousPkgs(pkg, root, production) {
    return __awaiter(this, void 0, void 0, function* () {
        const saveTypes = getSaveTypes(production);
        const savedDepsMap = saveTypes.reduce((allDeps, deps) => Object.assign({}, allDeps, pkg[deps]), {});
        const savedDeps = Object.keys(savedDepsMap);
        const modules = path.join(root, 'node_modules');
        const pkgsInFS = yield getPkgsInFS(modules);
        const extraneousPkgs = pkgsInFS.filter((pkgInFS) => savedDeps.indexOf(pkgInFS) === -1);
        return extraneousPkgs;
    });
}
const prodDepTypes = ['dependencies', 'optionalDependencies'];
const devOnlyDepTypes = ['devDependencies'];
function getSaveTypes(production) {
    if (production) {
        return prodDepTypes;
    }
    return prodDepTypes.concat(devOnlyDepTypes);
}
function getPkgsInFS(modules) {
    return __awaiter(this, void 0, void 0, function* () {
        const pkgDirs = yield getPkgDirs_1.default(modules);
        const pkgs = yield Promise.all(pkgDirs.map(readPkg_1.default));
        return pkgs.map(pkg => pkg.name);
    });
}
//# sourceMappingURL=prune.js.map