"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("@pnpm/types");
const yaml = require("js-yaml");
const mkdirp = require("mkdirp-promise");
const path = require("path");
const R = require("ramda");
const rimraf = require("rimraf-then");
const promisify = require("util.promisify");
const writeFileAtomicCB = require("write-file-atomic");
const constants_1 = require("./constants");
const logger_1 = require("./logger");
const writeFileAtomic = promisify(writeFileAtomicCB);
const SHRINKWRAP_YAML_FORMAT = {
    lineWidth: 1000,
    noCompatMode: true,
    noRefs: true,
    sortKeys: true,
};
function writeWantedOnly(pkgPath, wantedShrinkwrap, opts) {
    return writeShrinkwrap(constants_1.WANTED_SHRINKWRAP_FILENAME, pkgPath, wantedShrinkwrap, opts);
}
exports.writeWantedOnly = writeWantedOnly;
function writeCurrentOnly(pkgPath, currentShrinkwrap, opts) {
    return writeShrinkwrap(constants_1.CURRENT_SHRINKWRAP_FILENAME, pkgPath, currentShrinkwrap, opts);
}
exports.writeCurrentOnly = writeCurrentOnly;
function writeShrinkwrap(shrinkwrapFilename, pkgPath, wantedShrinkwrap, opts) {
    const shrinkwrapPath = path.join(pkgPath, shrinkwrapFilename);
    // empty shrinkwrap is not saved
    if (isEmptyShrinkwrap(wantedShrinkwrap)) {
        return rimraf(shrinkwrapPath);
    }
    const yamlDoc = yaml.safeDump(normalizeShrinkwrap(wantedShrinkwrap, opts && opts.forceSharedFormat === true || false), SHRINKWRAP_YAML_FORMAT);
    return writeFileAtomic(shrinkwrapPath, yamlDoc);
}
function isEmptyShrinkwrap(shr) {
    return R.values(shr.importers).every((importer) => R.isEmpty(importer.specifiers || {}) && R.isEmpty(importer.dependencies || {}));
}
function normalizeShrinkwrap(shr, forceSharedFormat) {
    if (forceSharedFormat === false && R.equals(R.keys(shr.importers), ['.'])) {
        const shrToSave = Object.assign({}, shr, shr.importers['.']);
        delete shrToSave.importers;
        for (const depType of types_1.DEPENDENCIES_FIELDS) {
            if (R.isEmpty(shrToSave[depType])) {
                delete shrToSave[depType];
            }
        }
        if (R.isEmpty(shrToSave.packages)) {
            delete shrToSave.packages;
        }
        return normalizeShrinkwrapVersion(shrToSave);
    }
    else {
        const shrToSave = Object.assign({}, shr, { importers: R.keys(shr.importers).reduce((acc, alias) => {
                const importer = shr.importers[alias];
                const normalizedImporter = {
                    specifiers: importer.specifiers,
                };
                for (const depType of types_1.DEPENDENCIES_FIELDS) {
                    if (!R.isEmpty(importer[depType] || {})) {
                        normalizedImporter[depType] = importer[depType];
                    }
                }
                acc[alias] = normalizedImporter;
                return acc;
            }, {}) });
        if (R.isEmpty(shrToSave.packages)) {
            delete shrToSave.packages;
        }
        delete shrToSave.registry;
        return normalizeShrinkwrapVersion(shrToSave);
    }
}
function normalizeShrinkwrapVersion(shr) {
    if (shr.shrinkwrapVersion < 4 && shr.shrinkwrapVersion.toString().indexOf('.') !== -1) {
        const [majorVersion, minorVersion] = shr.shrinkwrapVersion.toString().split('.').map((v) => parseInt(v, 10));
        if (minorVersion > 0) {
            shr['shrinkwrapMinorVersion'] = minorVersion;
        }
        shr.shrinkwrapVersion = majorVersion;
    }
    return shr;
}
function write(pkgPath, wantedShrinkwrap, currentShrinkwrap, opts) {
    const wantedShrinkwrapPath = path.join(pkgPath, constants_1.WANTED_SHRINKWRAP_FILENAME);
    const currentShrinkwrapPath = path.join(pkgPath, constants_1.CURRENT_SHRINKWRAP_FILENAME);
    // empty shrinkwrap is not saved
    if (isEmptyShrinkwrap(wantedShrinkwrap)) {
        return Promise.all([
            rimraf(wantedShrinkwrapPath),
            rimraf(currentShrinkwrapPath),
        ]);
    }
    const forceSharedFormat = opts && opts.forceSharedFormat === true || false;
    const yamlDoc = yaml.safeDump(normalizeShrinkwrap(wantedShrinkwrap, forceSharedFormat), SHRINKWRAP_YAML_FORMAT);
    // in most cases the `shrinkwrap.yaml` and `node_modules/.shrinkwrap.yaml` are equal
    // in those cases the YAML document can be stringified only once for both files
    // which is more efficient
    if (wantedShrinkwrap === currentShrinkwrap) {
        return Promise.all([
            writeFileAtomic(wantedShrinkwrapPath, yamlDoc),
            mkdirp(path.dirname(currentShrinkwrapPath)).then(() => writeFileAtomic(currentShrinkwrapPath, yamlDoc)),
        ]);
    }
    logger_1.default.debug({
        message: '`shrinkwrap.yaml` differs from `node_modules/.shrinkwrap.yaml`',
        prefix: pkgPath,
    });
    const currentYamlDoc = yaml.safeDump(normalizeShrinkwrap(currentShrinkwrap, forceSharedFormat), SHRINKWRAP_YAML_FORMAT);
    return Promise.all([
        writeFileAtomic(wantedShrinkwrapPath, yamlDoc),
        mkdirp(path.dirname(currentShrinkwrapPath)).then(() => writeFileAtomic(currentShrinkwrapPath, currentYamlDoc)),
    ]);
}
exports.default = write;
//# sourceMappingURL=write.js.map