core/converters/index.converter.ts

core/converters/index.converter.ts is a file in Bane's Lab Build Scripts. 89 lines of code and 20 definitions.

import { CATALOG_FILE_BUDGET, INDEX_PART_BUDGET, INDEX_PART_KIND } from "#configuration/constants/catalog.constants";
import type { Entries, IndexPart, IndexPlan, IndexPlans, IndexScope } from "#types/index.types";
import type { Entry, Identity, Leaf } from "#types/catalog.types";
import {
    collectionIndexPlans,
    facetIndexPlans,
    facetLevelPlans,
    levelIndexPlans,
} from "#core/converters/index.filter.converter";
import { emptyIndex, indexPartTitle } from "#configuration/strings/catalog.strings";
import { packedParts, serialize } from "#core/stores/catalog.store";
import { pageIndexPlans, tabIndexPlans } from "#core/converters/index.page.converter";
import { Buffer } from "node:buffer";
import { indexPart } from "#core/resolvers/catalog.resolver";
import { renderIndex } from "#core/formatters/index.formatter";
import { sourceIndexPlans } from "#core/converters/index.source.converter";

const PART_REF_MARK = "/";

export const indexPlansOf = function indexPlansOf(scope: IndexScope): IndexPlans {
    const collectionRefs = new Map(
        [...scope.collections.entries()].map(([collection, index]) => [collection, Object.keys(index)]),
    );
    const collections = collectionIndexPlans(collectionRefs, scope.groups, scope.site);
    const pages = pageIndexPlans(scope.discovery, scope.plans);
    const source = sourceIndexPlans(scope.files, scope.localPath);
    const facetLevels = facetLevelPlans(scope.groups);
    return {
        collections,
        facetCollections: facetLevels.collections,
        facetFields: facetLevels.fields,
        facets: facetIndexPlans(scope.groups),
        folders: source.folders,
        levels: levelIndexPlans({ collections, facets: facetLevels.collections, pages, trees: source.trees }),
        pages,
        tabs: tabIndexPlans(scope.discovery, scope.plans),
        trees: source.trees,
    };
};

const entriesOf = function entriesOf(entries: Entries, refs: readonly string[]): readonly Entry[] {
    return refs.flatMap((ref) => {
        const entry = entries.get(ref);
        return entry === undefined ? [] : [entry];
    });
};

const partLeaves = function partLeaves(plan: IndexPlan, listed: readonly Entry[], site: string): readonly Leaf[] {
    const parts = packedParts(listed, INDEX_PART_BUDGET);
    const leaves = parts.map((entries, index): Leaf => {
        const part = index + 1;
        const title = indexPartTitle(plan.identity.title, part, parts.length);
        const identity: Identity = {
            address: indexPart(plan.identity.address, String(part)),
            href: null,
            kind: INDEX_PART_KIND,
            ref: plan.identity.ref + PART_REF_MARK + String(part),
            summary: null,
            title,
        };
        const data = { entries, part, ref: identity.ref, title, total: parts.length };
        return { data, identity, markdown: renderIndex(identity, { ref: identity.ref, title }, entries, site) };
    });
    const summaries = leaves.map((leaf, index): IndexPart => ({
        count: parts[index]?.length ?? 0,
        first: parts[index]?.at(0)?.title ?? "",
        json: site + leaf.identity.address.json,
        last: parts[index]?.at(-1)?.title ?? "",
        markdown: leaf.identity.address.markdown === null ? null : site + leaf.identity.address.markdown,
    }));
    const data = { ...plan.data, count: listed.length, parts: summaries };
    return [...leaves, { data, identity: plan.identity, markdown: renderIndex(plan.identity, data, [], site) }];
};

export const indexLeaves = function indexLeaves(
    plans: readonly IndexPlan[],
    entries: Entries,
    site: string,
): readonly Leaf[] {
    return plans.flatMap((plan) => {
        const listed = entriesOf(entries, plan.refs);
        if (listed.length === 0) {
            throw new Error(emptyIndex(plan.identity.ref));
        }
        const data = { ...plan.data, entries: listed };
        if (Buffer.byteLength(serialize(data)) > CATALOG_FILE_BUDGET) {
            return partLeaves(plan, listed, site);
        }
        return [{ data, identity: plan.identity, markdown: renderIndex(plan.identity, plan.data, listed, site) }];
    });
};

export const isIndexHead = function isIndexHead(entry: Entry): boolean {
    return entry.kind !== INDEX_PART_KIND;
};