"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.filterPkgsBySelectorObjects = exports.filterPackages = exports.readProjects = exports.parsePackageSelector = void 0;
const find_workspace_packages_1 = __importDefault(require("@pnpm/find-workspace-packages"));
const matcher_1 = __importDefault(require("@pnpm/matcher"));
const pkgs_graph_1 = __importDefault(require("pkgs-graph"));
const getChangedPackages_1 = __importDefault(require("./getChangedPackages"));
const parsePackageSelector_1 = __importDefault(require("./parsePackageSelector"));
exports.parsePackageSelector = parsePackageSelector_1.default;
const isSubdir = require("is-subdir");
const R = require("ramda");
async function readProjects(workspaceDir, pkgSelectors, opts) {
    const allProjects = await find_workspace_packages_1.default(workspaceDir, {});
    const { selectedProjectsGraph } = await filterPkgsBySelectorObjects(allProjects, pkgSelectors, {
        linkWorkspacePackages: opts === null || opts === void 0 ? void 0 : opts.linkWorkspacePackages,
        workspaceDir,
    });
    return { allProjects, selectedProjectsGraph };
}
exports.readProjects = readProjects;
async function filterPackages(pkgs, filter, opts) {
    const packageSelectors = filter
        .map((f) => parsePackageSelector_1.default(f, opts.prefix));
    return filterPkgsBySelectorObjects(pkgs, packageSelectors, opts);
}
exports.filterPackages = filterPackages;
function filterPkgsBySelectorObjects(pkgs, packageSelectors, opts) {
    const { graph } = pkgs_graph_1.default(pkgs, { linkWorkspacePackages: opts.linkWorkspacePackages });
    if (packageSelectors === null || packageSelectors === void 0 ? void 0 : packageSelectors.length) {
        return filterGraph(graph, packageSelectors, {
            workspaceDir: opts.workspaceDir,
        });
    }
    else {
        return Promise.resolve({ selectedProjectsGraph: graph, unmatchedFilters: [] });
    }
}
exports.filterPkgsBySelectorObjects = filterPkgsBySelectorObjects;
async function filterGraph(pkgGraph, packageSelectors, opts) {
    const [excludeSelectors, includeSelectors] = R.partition((selector) => selector.exclude === true, packageSelectors);
    const fg = _filterGraph.bind(null, pkgGraph, opts);
    const include = includeSelectors.length === 0
        ? { selected: Object.keys(pkgGraph), unmatchedFilters: [] }
        : await fg(includeSelectors);
    const exclude = await fg(excludeSelectors);
    return {
        selectedProjectsGraph: R.pick(R.difference(include.selected, exclude.selected), pkgGraph),
        unmatchedFilters: [...include.unmatchedFilters, ...exclude.unmatchedFilters],
    };
}
exports.default = filterGraph;
async function _filterGraph(pkgGraph, opts, packageSelectors) {
    var _a;
    const cherryPickedPackages = [];
    const walkedDependencies = new Set();
    const walkedDependents = new Set();
    const graph = pkgGraphToGraph(pkgGraph);
    const unmatchedFilters = [];
    let reversedGraph;
    for (const selector of packageSelectors) {
        let entryPackages = null;
        if (selector.diff) {
            entryPackages = await getChangedPackages_1.default(Object.keys(pkgGraph), selector.diff, { workspaceDir: (_a = selector.parentDir) !== null && _a !== void 0 ? _a : opts.workspaceDir });
        }
        else if (selector.parentDir) {
            entryPackages = matchPackagesByPath(pkgGraph, selector.parentDir);
        }
        if (selector.namePattern) {
            if (!entryPackages) {
                entryPackages = matchPackages(pkgGraph, selector.namePattern);
            }
            else {
                entryPackages = matchPackages(R.pick(entryPackages, pkgGraph), selector.namePattern);
            }
        }
        if (!entryPackages) {
            throw new Error(`Unsupported package selector: ${JSON.stringify(selector)}`);
        }
        if (entryPackages.length === 0) {
            if (selector.namePattern) {
                unmatchedFilters.push(selector.namePattern);
            }
            if (selector.parentDir) {
                unmatchedFilters.push(selector.parentDir);
            }
        }
        if (selector.includeDependencies) {
            pickSubgraph(graph, entryPackages, walkedDependencies, { includeRoot: !selector.excludeSelf });
        }
        if (selector.includeDependents) {
            if (!reversedGraph) {
                reversedGraph = reverseGraph(graph);
            }
            pickSubgraph(reversedGraph, entryPackages, walkedDependents, { includeRoot: !selector.excludeSelf });
        }
        if (!selector.includeDependencies && !selector.includeDependents) {
            Array.prototype.push.apply(cherryPickedPackages, entryPackages);
        }
    }
    const walked = new Set([...walkedDependencies, ...walkedDependents]);
    cherryPickedPackages.forEach((cherryPickedPackage) => walked.add(cherryPickedPackage));
    return {
        selected: Array.from(walked),
        unmatchedFilters,
    };
}
function pkgGraphToGraph(pkgGraph) {
    const graph = {};
    Object.keys(pkgGraph).forEach((nodeId) => {
        graph[nodeId] = pkgGraph[nodeId].dependencies;
    });
    return graph;
}
function reverseGraph(graph) {
    const reversedGraph = {};
    Object.keys(graph).forEach((dependentNodeId) => {
        graph[dependentNodeId].forEach((dependencyNodeId) => {
            if (!reversedGraph[dependencyNodeId]) {
                reversedGraph[dependencyNodeId] = [dependentNodeId];
            }
            else {
                reversedGraph[dependencyNodeId].push(dependentNodeId);
            }
        });
    });
    return reversedGraph;
}
function matchPackages(graph, pattern) {
    const match = matcher_1.default(pattern);
    return Object.keys(graph).filter((id) => graph[id].package.manifest.name && match(graph[id].package.manifest.name));
}
function matchPackagesByPath(graph, pathStartsWith) {
    return Object.keys(graph).filter((parentDir) => isSubdir(pathStartsWith, parentDir));
}
function pickSubgraph(graph, nextNodeIds, walked, opts) {
    for (const nextNodeId of nextNodeIds) {
        if (!walked.has(nextNodeId)) {
            if (opts.includeRoot) {
                walked.add(nextNodeId);
            }
            if (graph[nextNodeId])
                pickSubgraph(graph, graph[nextNodeId], walked, { includeRoot: true });
        }
    }
}
//# sourceMappingURL=index.js.map