core/converters/graph.segment.converter.ts

core/converters/graph.segment.converter.ts is a file in Bane's Lab Build Scripts. 51 lines of code and 15 definitions.

import type { ChunkNode, ChunkTarget, GraphChunk, GraphNode } from "@banes-lab/web/types/graph.types.js";
import type { ChunkRules, Graph } from "#types/graph.types";

const targetOf = function targetOf(node: GraphNode): ChunkTarget {
    return { href: node.href, number: node.number, title: node.title };
};

const containersOf = function containersOf(graph: Graph, rules: ChunkRules): ReadonlyMap<string, string> {
    return new Map(
        graph.edges.filter((edge) => edge.relation === rules.contains).map((edge) => [edge.to, edge.from] as const),
    );
};

export const chunksOf = function chunksOf(graph: Graph, rules: ChunkRules): ReadonlyMap<string, GraphChunk> {
    const nodes = new Map(graph.nodes.map((node) => [node.ref, node]));
    const containers = containersOf(graph, rules);
    const relations = new Map<string, Map<string, ChunkTarget[]>>();
    const add = function add(from: string, relation: string, to: string): void {
        const target = nodes.get(to);
        if (!nodes.has(from) || target === undefined || !rules.keptRelations.has(relation)) {
            return;
        }
        const held = relations.get(from) ?? new Map<string, ChunkTarget[]>();
        held.set(relation, [...(held.get(relation) ?? []), targetOf(target)]);
        relations.set(from, held);
    };
    for (const edge of graph.edges.filter((held) => !rules.skipsSource(held.from))) {
        add(edge.from, edge.relation, edge.to);
        const reverse = rules.pairs.find((pair) => pair.forward === edge.relation)?.reverse;
        if (reverse !== undefined) {
            add(edge.to, reverse, edge.from);
        }
        const container = containers.get(edge.to);
        if (reverse !== undefined && container !== undefined && rules.rollsUp.has(reverse)) {
            add(container, reverse, edge.from);
        }
    }
    const chunks = new Map<string, Record<string, ChunkNode>>();
    for (const [ref, held] of relations) {
        const node = nodes.get(ref);
        if (node !== undefined) {
            const key = rules.keyOf(ref);
            const chunk = chunks.get(key) ?? {};
            chunk[ref] = {
                kind: node.kind,
                number: node.number,
                relations: [...held].map(([relation, targets]) => ({ relation, targets })),
                title: node.title,
            };
            chunks.set(key, chunk);
        }
    }
    return chunks;
};