"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 R = require("ramda");
const rimraf = require("rimraf-then");
const isCI = require("is-ci");
const getRegistryName_1 = require("../resolve/npm/getRegistryName");
const npa = require("npm-package-arg");
const shrinkwrapLogger = pnpm_logger_1.default('shrinkwrap');
exports.SHRINKWRAP_FILENAME = 'shrinkwrap.yaml';
exports.PRIVATE_SHRINKWRAP_FILENAME = path.join('node_modules', '.shrinkwrap.yaml');
const SHRINKWRAP_VERSION = 2;
function getDefaultShrinkwrap(registry) {
    return {
        version: SHRINKWRAP_VERSION,
        dependencies: {},
        packages: {},
        registry,
    };
}
function readPrivate(pkgPath, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const shrinkwrapPath = path.join(pkgPath, exports.PRIVATE_SHRINKWRAP_FILENAME);
        let shrinkwrap;
        try {
            shrinkwrap = yield loadYamlFile(shrinkwrapPath);
        }
        catch (err) {
            if (err.code !== 'ENOENT') {
                throw err;
            }
            return getDefaultShrinkwrap(opts.registry);
        }
        if (shrinkwrap && shrinkwrap.version === SHRINKWRAP_VERSION) {
            return shrinkwrap;
        }
        if (opts.force || isCI) {
            shrinkwrapLogger.warn(`Ignoring not compatible shrinkwrap file at ${shrinkwrapPath}`);
            return getDefaultShrinkwrap(opts.registry);
        }
        throw new ShrinkwrapBreakingChangeError(shrinkwrapPath);
    });
}
exports.readPrivate = readPrivate;
function read(pkgPath, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const shrinkwrapPath = path.join(pkgPath, exports.SHRINKWRAP_FILENAME);
        let shrinkwrap;
        try {
            shrinkwrap = yield loadYamlFile(shrinkwrapPath);
        }
        catch (err) {
            if (err.code !== 'ENOENT') {
                throw err;
            }
            return getDefaultShrinkwrap(opts.registry);
        }
        if (shrinkwrap && shrinkwrap.version === SHRINKWRAP_VERSION) {
            return shrinkwrap;
        }
        if (opts.force || isCI) {
            shrinkwrapLogger.warn(`Ignoring not compatible shrinkwrap file at ${shrinkwrapPath}`);
            return getDefaultShrinkwrap(opts.registry);
        }
        throw new ShrinkwrapBreakingChangeError(shrinkwrapPath);
    });
}
exports.read = read;
function save(pkgPath, shrinkwrap) {
    const shrinkwrapPath = path.join(pkgPath, exports.SHRINKWRAP_FILENAME);
    const privateShrinkwrapPath = path.join(pkgPath, exports.PRIVATE_SHRINKWRAP_FILENAME);
    // empty shrinkwrap is not saved
    if (Object.keys(shrinkwrap.dependencies).length === 0) {
        return Promise.all([
            rimraf(shrinkwrapPath),
            rimraf(privateShrinkwrapPath),
        ]);
    }
    const formatOpts = {
        sortKeys: true,
        lineWidth: 1000,
        noCompatMode: true,
    };
    return Promise.all([
        writeYamlFile(shrinkwrapPath, shrinkwrap, formatOpts),
        writeYamlFile(privateShrinkwrapPath, shrinkwrap, formatOpts),
    ]);
}
exports.save = save;
function prune(shr) {
    return {
        version: SHRINKWRAP_VERSION,
        dependencies: shr.dependencies,
        registry: shr.registry,
        packages: copyDependencyTree(shr, shr.registry),
    };
}
exports.prune = prune;
function copyDependencyTree(shr, registry) {
    const resolvedPackages = {};
    let pkgIds = R.keys(shr.dependencies).map((rawPkgSpec) => {
        const spec = npa(rawPkgSpec);
        return getPkgShortId(shr.dependencies[rawPkgSpec], spec.name);
    });
    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;
            }
            const depShr = shr.packages[pkgId];
            resolvedPackages[pkgId] = depShr;
            if (typeof depShr === 'string')
                continue;
            const newDependencies = R.keys(depShr.dependencies)
                .map((pkgName) => getPkgShortId((depShr.dependencies && depShr.dependencies[pkgName]), pkgName))
                .filter((newPkgId) => !resolvedPackages[newPkgId] && pkgIds.indexOf(newPkgId) === -1);
            nextPkgIds = R.union(nextPkgIds, newDependencies);
        }
        pkgIds = nextPkgIds;
    }
    return resolvedPackages;
}
function shortIdToFullId(shortId, registry) {
    if (shortId[0] === '/') {
        const registryName = getRegistryName_1.default(registry);
        return `${registryName}${shortId}`;
    }
    return shortId;
}
exports.shortIdToFullId = shortIdToFullId;
function getPkgShortId(reference, pkgName) {
    if (reference.indexOf('/') === -1) {
        return `/${pkgName}/${reference}`;
    }
    return reference;
}
exports.getPkgShortId = getPkgShortId;
function getPkgId(reference, pkgName, registry) {
    if (reference.indexOf('/') === -1) {
        const registryName = getRegistryName_1.default(registry);
        return `${registryName}/${pkgName}/${reference}`;
    }
    return reference;
}
exports.getPkgId = getPkgId;
function pkgIdToRef(pkgId, pkgVersion, resolution, standardRegistry) {
    if (resolution.type)
        return pkgId;
    const registryName = getRegistryName_1.default(standardRegistry);
    if (pkgId.startsWith(`${registryName}/`)) {
        return pkgVersion;
    }
    return pkgId;
}
exports.pkgIdToRef = pkgIdToRef;
function pkgShortId(pkgId, standardRegistry) {
    const registryName = getRegistryName_1.default(standardRegistry);
    if (pkgId.startsWith(`${registryName}/`)) {
        return pkgId.substr(pkgId.indexOf('/'));
    }
    return pkgId;
}
exports.pkgShortId = pkgShortId;
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