"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("@pnpm/constants");
const lockfile_utils_1 = require("@pnpm/lockfile-utils");
const logger_1 = require("@pnpm/logger");
const package_is_installable_1 = require("@pnpm/package-is-installable");
const dp = require("dependency-path");
const R = require("ramda");
const filterImporter_1 = require("./filterImporter");
const LockfileMissingDependencyError_1 = require("./LockfileMissingDependencyError");
const logger = logger_1.default('lockfile');
function filterByImportersAndEngine(lockfile, importerIds, opts) {
    const importerDeps = importerIds
        .map((importerId) => lockfile.importers[importerId])
        .map((importer) => ({
        ...(opts.include.dependencies && importer.dependencies || {}),
        ...(opts.include.devDependencies && importer.devDependencies || {}),
        ...(opts.include.optionalDependencies && importer.optionalDependencies || {}),
    }))
        .map(R.toPairs);
    const directDepPaths = R.unnest(importerDeps)
        .map(([pkgName, ref]) => dp.refToRelative(ref, pkgName))
        .filter((nodeId) => nodeId !== null);
    const packages = lockfile.packages &&
        pickPkgsWithAllDeps(lockfile.packages, directDepPaths, {
            currentEngine: opts.currentEngine,
            engineStrict: opts.engineStrict,
            failOnMissingDependencies: opts.failOnMissingDependencies,
            include: opts.include,
            includeIncompatiblePackages: opts.includeIncompatiblePackages === true,
            lockfileDir: opts.lockfileDir,
            skipped: opts.skipped,
        }) || {};
    const importers = importerIds.reduce((acc, importerId) => {
        acc[importerId] = filterImporter_1.default(lockfile.importers[importerId], opts.include);
        if (acc[importerId].optionalDependencies) {
            for (const depName of Object.keys(acc[importerId].optionalDependencies || {})) {
                const depPath = dp.refToRelative(acc[importerId].optionalDependencies[depName], depName);
                if (depPath && !packages[depPath]) {
                    delete acc[importerId].optionalDependencies[depName];
                }
            }
        }
        return acc;
    }, { ...lockfile.importers });
    return {
        importers,
        lockfileVersion: lockfile.lockfileVersion,
        packages,
    };
}
exports.default = filterByImportersAndEngine;
function pickPkgsWithAllDeps(pkgSnapshots, depPaths, opts) {
    const pickedPackages = {};
    pkgAllDeps({ pkgSnapshots, pickedPackages }, depPaths, true, opts);
    return pickedPackages;
}
function pkgAllDeps(ctx, depPaths, parentIsInstallable, opts) {
    for (const depPath of depPaths) {
        if (ctx.pickedPackages[depPath])
            continue;
        const pkgSnapshot = ctx.pkgSnapshots[depPath];
        if (!pkgSnapshot && !depPath.startsWith('link:')) {
            if (opts.failOnMissingDependencies) {
                throw new LockfileMissingDependencyError_1.default(depPath);
            }
            logger.debug(`No entry for "${depPath}" in ${constants_1.WANTED_LOCKFILE}`);
            continue;
        }
        let installable;
        if (!parentIsInstallable) {
            installable = false;
            if (!ctx.pickedPackages[depPath] && pkgSnapshot.optional === true) {
                opts.skipped.add(depPath);
            }
        }
        else {
            const pkg = {
                ...lockfile_utils_1.nameVerFromPkgSnapshot(depPath, pkgSnapshot),
                cpu: pkgSnapshot.cpu,
                engines: pkgSnapshot.engines,
                os: pkgSnapshot.os,
            };
            // TODO: depPath is not the package ID. Should be fixed
            installable = opts.includeIncompatiblePackages || package_is_installable_1.default(pkgSnapshot.id || depPath, pkg, {
                engineStrict: opts.engineStrict,
                lockfileDir: opts.lockfileDir,
                nodeVersion: opts.currentEngine.nodeVersion,
                optional: pkgSnapshot.optional === true,
                pnpmVersion: opts.currentEngine.pnpmVersion,
            }) !== false;
            if (!installable) {
                if (!ctx.pickedPackages[depPath] && pkgSnapshot.optional === true) {
                    opts.skipped.add(depPath);
                }
            }
            else {
                opts.skipped.delete(depPath);
            }
        }
        ctx.pickedPackages[depPath] = pkgSnapshot;
        const nextRelDepPaths = R.toPairs({
            ...pkgSnapshot.dependencies,
            ...(opts.include.optionalDependencies && pkgSnapshot.optionalDependencies || {}),
        })
            .map(([pkgName, ref]) => {
            var _a;
            if ((_a = pkgSnapshot.peerDependencies) === null || _a === void 0 ? void 0 : _a[pkgName])
                return null;
            return dp.refToRelative(ref, pkgName);
        })
            .filter((nodeId) => nodeId !== null);
        pkgAllDeps(ctx, nextRelDepPaths, installable, opts);
    }
}
//# sourceMappingURL=filterLockfileByImportersAndEngine.js.map