"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 errorTypes_1 = require("../errorTypes");
const pnpm_logger_1 = require("pnpm-logger");
const loadYamlFile = require("load-yaml-file");
const writeYamlFile = require("write-yaml-file");
const values = require("lodash.values");
const union = require("lodash.union");
const rimraf = require("rimraf-then");
const shrinkwrapLogger = pnpm_logger_1.default('shrinkwrap');
const SHRINKWRAP_FILENAME = 'shrinkwrap.yaml';
const SHRINKWRAP_VERSION = 1;
function getDefaultShrinkwrap() {
    return {
        version: SHRINKWRAP_VERSION,
        dependencies: {},
        packages: {},
    };
}
function read(pkgPath, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const shrinkwrapPath = path.join(pkgPath, SHRINKWRAP_FILENAME);
        let shrinkwrap;
        try {
            shrinkwrap = yield loadYamlFile(shrinkwrapPath);
        }
        catch (err) {
            if (err.code !== 'ENOENT') {
                throw err;
            }
            return getDefaultShrinkwrap();
        }
        if (shrinkwrap && shrinkwrap.version === SHRINKWRAP_VERSION) {
            return shrinkwrap;
        }
        if (opts.force) {
            shrinkwrapLogger.warn(`Ignoring not compatible shrinkwrap file at ${shrinkwrapPath}`);
            return getDefaultShrinkwrap();
        }
        throw new ShrinkwrapBreakingChangeError(shrinkwrapPath);
    });
}
exports.read = read;
function save(pkgPath, shrinkwrap) {
    const shrinkwrapPath = path.join(pkgPath, SHRINKWRAP_FILENAME);
    // empty shrinkwrap is not saved
    if (Object.keys(shrinkwrap.dependencies).length === 0) {
        return rimraf(shrinkwrapPath);
    }
    const prunedShr = prune(shrinkwrap);
    return writeYamlFile(shrinkwrapPath, prunedShr, {
        sortKeys: true,
        lineWidth: 1000,
        noCompatMode: true,
    });
}
exports.save = save;
function prune(shr) {
    return {
        version: SHRINKWRAP_VERSION,
        dependencies: shr.dependencies,
        packages: copyDependencyTree(shr),
    };
}
function copyDependencyTree(shr) {
    const resolvedPackages = {};
    let pkgIds = values(shr.dependencies);
    while (pkgIds.length) {
        let nextPkgIds = [];
        for (let pkgId of pkgIds) {
            if (!shr.packages[pkgId]) {
                pnpm_logger_1.default.warn(`Cannot find resolution of ${pkgId} in shrinkwrap file`);
                continue;
            }
            resolvedPackages[pkgId] = shr.packages[pkgId];
            const newDependencies = values(shr.packages[pkgId].dependencies || {})
                .filter((newPkgId) => !resolvedPackages[newPkgId] && pkgIds.indexOf(newPkgId) === -1);
            nextPkgIds = union(nextPkgIds, newDependencies);
        }
        pkgIds = nextPkgIds;
    }
    return resolvedPackages;
}
class ShrinkwrapBreakingChangeError extends errorTypes_1.PnpmError {
    constructor(filename) {
        super('SHRINKWRAP_BREAKING_CHANGE', `Shrinkwrap file ${filename} not compatible with current pnpm`);
        this.filename = filename;
    }
}
//# sourceMappingURL=shrinkwrap.js.map