core/converters/catalog.converter.ts

core/converters/catalog.converter.ts is a file in Bane's Lab Build Scripts. 129 lines of code and 32 definitions.

import { ADDRESS_GROUP_TITLES, COLLECTION_TITLES, addressGroupTitle } from "@banes-lab/web/strings/catalog.strings";
import {
    CANONICAL_FORM,
    IDS_TITLE,
    NO_MANIFEST_HEAD,
    indexPartTitle,
    untitledGroup,
} from "#configuration/strings/catalog.strings";
import { CATALOG_VERSION, INDEX_KIND, INDEX_PART_BUDGET } from "#configuration/constants/catalog.constants";
import type { Entry, Identity, Leaf, SiteBuild, SiteParts } from "#types/catalog.types";
import { idsIndex, idsShard, indexPart, localAddress, siteIndex } from "#core/resolvers/catalog.resolver";
import type { Discovery } from "#types/site.types";
import type { RouteLedger } from "#types/route.types";
import { grammarRows } from "#core/converters/catalog.grammar.converter";
import { groupedBy } from "#core/converters/base.converter";
import { latestStamp } from "#core/converters/route.converter";
import { packedParts } from "#core/stores/catalog.store";
import { renderSiteIndex } from "#core/formatters/index.formatter";
import { trainingConsent } from "#configuration/strings/site.strings";

const SITE_REF = "api:";
const IDS_REF = "api:ids";
const IDS_SHARD_PREFIX = "api:ids/";
const PART_REF_MARK = "/";
const REF_SEPARATOR = ":";
const ID_COLUMNS = ["ref", "kind", "title", "summary", "json", "markdown", "bytes", "fingerprint"] as const;

const groupOf = function groupOf(entry: Entry): string {
    return entry.ref.slice(0, entry.ref.indexOf(REF_SEPARATOR));
};

const groupNameOf = function groupNameOf(group: string): string {
    const collection = COLLECTION_TITLES.get(group);
    const name = collection === undefined ? ADDRESS_GROUP_TITLES.get(group) : collection.toLowerCase();
    if (name === undefined) {
        throw new Error(untitledGroup(group));
    }
    return name;
};

const rowOf = function rowOf(entry: Entry): readonly unknown[] {
    return [
        entry.ref,
        entry.kind,
        entry.title,
        entry.summary,
        entry.json,
        entry.markdown,
        entry.bytes,
        entry.fingerprint,
    ];
};

interface IdsShard {
    readonly count: number;
    readonly group: string;
    readonly leaf: Leaf;
}

const groupShards = function groupShards(group: string, members: readonly Entry[]): readonly IdsShard[] {
    const parts = packedParts(members, INDEX_PART_BUDGET);
    const groupTitle = addressGroupTitle(groupNameOf(group));
    return parts.map((rows, index): IdsShard => {
        const single = parts.length === 1;
        const part = index + 1;
        const ref = IDS_SHARD_PREFIX + group + (single ? "" : PART_REF_MARK + String(part));
        const title = single ? groupTitle : indexPartTitle(groupTitle, part, parts.length);
        const address = single ? idsShard(group) : indexPart(idsShard(group), String(part));
        const leaf: Leaf = {
            data: { columns: ID_COLUMNS, count: rows.length, group, ref, rows: rows.map(rowOf), title },
            identity: { address, href: null, kind: INDEX_KIND, ref, summary: null, title },
            markdown: null,
        };
        return { count: rows.length, group, leaf };
    });
};

export const idsLeaves = function idsLeaves(entries: readonly Entry[], site: string): readonly Leaf[] {
    const grouped = [...groupedBy(entries, groupOf).entries()].flatMap(([group, members]) =>
        groupShards(group, members),
    );
    const shards = grouped.map((shard) => shard.leaf);
    const listed = grouped.map(({ count, group, leaf }) => ({ count, group, json: site + leaf.identity.address.json }));
    const kinds = [...new Set([...entries, ...shards.map((shard) => shard.identity)].map((entry) => entry.kind))];
    const head: Leaf = {
        data: {
            count: entries.length,
            kinds: kinds.toSorted((left, right) => left.localeCompare(right)),
            ref: IDS_REF,
            shards: listed,
            title: IDS_TITLE,
        },
        identity: { address: idsIndex(), href: null, kind: INDEX_KIND, ref: IDS_REF, summary: null, title: IDS_TITLE },
        markdown: null,
    };
    return [...shards, head];
};

export const siteBuildOf = function siteBuildOf(
    entries: readonly Entry[],
    ledger: RouteLedger,
    site: string,
): SiteBuild {
    const head = entries.find((entry) => entry.ref === IDS_REF);
    if (head === undefined) {
        throw new Error(NO_MANIFEST_HEAD);
    }
    return {
        build: head.fingerprint,
        published: entries.map((entry) => localAddress(site, entry.json)),
        updated: latestStamp(ledger),
        version: CATALOG_VERSION,
    };
};

export const siteLeaf = function siteLeaf(discovery: Discovery, parts: SiteParts, build: SiteBuild): Leaf {
    const { published, ...stamp } = build;
    const identity: Identity = {
        address: siteIndex(),
        href: "/",
        kind: INDEX_KIND,
        ref: SITE_REF,
        summary: discovery.summary,
        title: discovery.name,
    };
    const data = {
        ...parts,
        ...stamp,
        canonical: CANONICAL_FORM,
        consent: trainingConsent(discovery.consent, discovery.author, discovery.site),
        grammar: grammarRows(published),
        ref: SITE_REF,
        site: discovery.site,
        summary: discovery.summary,
        title: discovery.name,
    };
    return { data, identity, markdown: renderSiteIndex(data, discovery.site) };
};