"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.pruneLockfile = exports.pruneSharedLockfile = void 0;
const constants_1 = require("@pnpm/constants");
const dependency_path_1 = require("dependency-path");
const R = require("ramda");
__exportStar(require("@pnpm/lockfile-types"), exports);
function pruneSharedLockfile(lockfile, opts) {
    var _a;
    const copiedPackages = !lockfile.packages ? {} : copyPackageSnapshots(lockfile.packages, {
        devDepPaths: R.unnest(R.values(lockfile.importers).map((deps) => { var _a; return resolvedDepsToDepPaths((_a = deps.devDependencies) !== null && _a !== void 0 ? _a : {}); })),
        optionalDepPaths: R.unnest(R.values(lockfile.importers).map((deps) => { var _a; return resolvedDepsToDepPaths((_a = deps.optionalDependencies) !== null && _a !== void 0 ? _a : {}); })),
        prodDepPaths: R.unnest(R.values(lockfile.importers).map((deps) => { var _a; return resolvedDepsToDepPaths((_a = deps.dependencies) !== null && _a !== void 0 ? _a : {}); })),
        warn: (_a = opts === null || opts === void 0 ? void 0 : opts.warn) !== null && _a !== void 0 ? _a : ((msg) => undefined),
    });
    const prunnedLockfile = {
        ...lockfile,
        packages: copiedPackages,
    };
    if (R.isEmpty(prunnedLockfile.packages)) {
        delete prunnedLockfile.packages;
    }
    return prunnedLockfile;
}
exports.pruneSharedLockfile = pruneSharedLockfile;
function pruneLockfile(lockfile, pkg, importerId, opts) {
    var _a;
    const packages = {};
    const importer = lockfile.importers[importerId];
    const lockfileSpecs = (_a = importer.specifiers) !== null && _a !== void 0 ? _a : {};
    const optionalDependencies = R.keys(pkg.optionalDependencies);
    const dependencies = R.difference(R.keys(pkg.dependencies), optionalDependencies);
    const devDependencies = R.difference(R.difference(R.keys(pkg.devDependencies), optionalDependencies), dependencies);
    const allDeps = [
        ...optionalDependencies,
        ...devDependencies,
        ...dependencies,
    ];
    const specifiers = {};
    const lockfileDependencies = {};
    const lockfileOptionalDependencies = {};
    const lockfileDevDependencies = {};
    Object.keys(lockfileSpecs).forEach((depName) => {
        var _a, _b, _c;
        if (!allDeps.includes(depName))
            return;
        specifiers[depName] = lockfileSpecs[depName];
        if ((_a = importer.dependencies) === null || _a === void 0 ? void 0 : _a[depName]) {
            lockfileDependencies[depName] = importer.dependencies[depName];
        }
        else if ((_b = importer.optionalDependencies) === null || _b === void 0 ? void 0 : _b[depName]) {
            lockfileOptionalDependencies[depName] = importer.optionalDependencies[depName];
        }
        else if ((_c = importer.devDependencies) === null || _c === void 0 ? void 0 : _c[depName]) {
            lockfileDevDependencies[depName] = importer.devDependencies[depName];
        }
    });
    if (importer.dependencies) {
        for (const dep of R.keys(importer.dependencies)) {
            if (!lockfileDependencies[dep] && importer.dependencies[dep].startsWith('link:') &&
                // If the linked dependency was removed from package.json
                // then it is removed from pnpm-lock.yaml as well
                !(lockfileSpecs[dep] && !allDeps[dep])) {
                lockfileDependencies[dep] = importer.dependencies[dep];
            }
        }
    }
    const updatedImporter = {
        specifiers,
    };
    const prunnedLockfile = {
        importers: {
            ...lockfile.importers,
            [importerId]: updatedImporter,
        },
        lockfileVersion: lockfile.lockfileVersion || constants_1.LOCKFILE_VERSION,
        packages: lockfile.packages,
    };
    if (!R.isEmpty(packages)) {
        prunnedLockfile.packages = packages;
    }
    if (!R.isEmpty(lockfileDependencies)) {
        updatedImporter.dependencies = lockfileDependencies;
    }
    if (!R.isEmpty(lockfileOptionalDependencies)) {
        updatedImporter.optionalDependencies = lockfileOptionalDependencies;
    }
    if (!R.isEmpty(lockfileDevDependencies)) {
        updatedImporter.devDependencies = lockfileDevDependencies;
    }
    return pruneSharedLockfile(prunnedLockfile, opts);
}
exports.pruneLockfile = pruneLockfile;
function copyPackageSnapshots(originalPackages, opts) {
    const copiedSnapshots = {};
    const ctx = {
        copiedSnapshots,
        nonOptional: new Set(),
        notProdOnly: new Set(),
        originalPackages,
        walked: new Set(),
        warn: opts.warn,
    };
    copyDependencySubGraph(ctx, opts.devDepPaths, {
        dev: true,
        optional: false,
    });
    copyDependencySubGraph(ctx, opts.optionalDepPaths, {
        dev: false,
        optional: true,
    });
    copyDependencySubGraph(ctx, opts.prodDepPaths, {
        dev: false,
        optional: false,
    });
    return copiedSnapshots;
}
function resolvedDepsToDepPaths(deps) {
    return Object.entries(deps)
        .map(([alias, ref]) => dependency_path_1.refToRelative(ref, alias))
        .filter((depPath) => depPath !== null);
}
function copyDependencySubGraph(ctx, depPaths, opts) {
    var _a, _b, _c, _d;
    for (const depPath of depPaths) {
        const key = `${depPath}:${opts.optional.toString()}:${opts.dev.toString()}`;
        if (ctx.walked.has(key))
            continue;
        ctx.walked.add(key);
        if (!ctx.originalPackages[depPath]) {
            // local dependencies don't need to be resolved in pnpm-lock.yaml
            // except local tarball dependencies
            if (depPath.startsWith('link:') || depPath.startsWith('file:') && !depPath.endsWith('.tar.gz'))
                continue;
            ctx.warn(`Cannot find resolution of ${depPath} in lockfile`);
            continue;
        }
        const depLockfile = ctx.originalPackages[depPath];
        ctx.copiedSnapshots[depPath] = depLockfile;
        if (opts.optional && !ctx.nonOptional.has(depPath)) {
            depLockfile.optional = true;
        }
        else {
            ctx.nonOptional.add(depPath);
            delete depLockfile.optional;
        }
        if (opts.dev) {
            ctx.notProdOnly.add(depPath);
            depLockfile.dev = true;
        }
        else if (depLockfile.dev === true) { // keeping if dev is explicitly false
            delete depLockfile.dev;
        }
        else if (depLockfile.dev === undefined && !ctx.notProdOnly.has(depPath)) {
            depLockfile.dev = false;
        }
        const newDependencies = resolvedDepsToDepPaths(R.omit((_b = Object.keys((_a = depLockfile.peerDependencies) !== null && _a !== void 0 ? _a : {})) !== null && _b !== void 0 ? _b : [], (_c = depLockfile.dependencies) !== null && _c !== void 0 ? _c : {}));
        copyDependencySubGraph(ctx, newDependencies, opts);
        const newOptionalDependencies = resolvedDepsToDepPaths((_d = depLockfile.optionalDependencies) !== null && _d !== void 0 ? _d : {});
        copyDependencySubGraph(ctx, newOptionalDependencies, { dev: opts.dev, optional: true });
    }
}
//# sourceMappingURL=index.js.map