test.build/core/converters/catalog.converter.test.ts

test.build/core/converters/catalog.converter.test.ts is a file in Codebase Testing. 75 lines of code and 0 definitions.

import { describe, expect, it } from "vitest";
import { idsLeaves, siteBuildOf, siteLeaf } from "@banes-lab/build-scripts/core/converters/catalog.converter.ts";
import type { Discovery } from "@banes-lab/build-scripts/types/site.types.ts";
import type { Entry } from "@banes-lab/build-scripts/types/catalog.types.ts";

const SITE = "https://example.test";

const DISCOVERY: Discovery = {
    author: "Ada",
    consent: "Crawl freely.",
    name: "Example",
    pages: [],
    routes: [],
    site: SITE,
    summary: "An example site.",
};

const ENTRY: Entry = {
    bytes: 12,
    fingerprint: "f",
    href: null,
    json: `${SITE}/json/api/route`,
    kind: "route",
    markdown: `${SITE}/api/route.md`,
    ref: "api:route",
    summary: null,
    title: "Learning route",
};

describe("idsLeaves, siteBuildOf and siteLeaf", () => {
    it("writes the id manifest as one shard per ref prefix, the build stamp and the root index", () => {
        const section = { ...ENTRY, ref: "chapter:/pag#grammar", title: "Grammar" };
        const [api, chapter, head] = idsLeaves([ENTRY, section, { ...ENTRY, ref: "api:search" }], SITE);
        expect(api?.identity.address.json).toBe("/json/api/ids/api");
        expect(api?.data).toMatchObject({
            count: 2,
            group: "api",
            rows: [
                ["api:route", "route", "Learning route", null, ENTRY.json, ENTRY.markdown, 12, "f"],
                ["api:search", "route", "Learning route", null, ENTRY.json, ENTRY.markdown, 12, "f"],
            ],
        });
        expect(chapter?.data).toMatchObject({ count: 1, group: "chapter" });
        expect(head?.data).toMatchObject({
            count: 3,
            kinds: ["index", "route"],
            shards: [
                { count: 2, group: "api", json: `${SITE}/json/api/ids/api` },
                { count: 1, group: "chapter", json: `${SITE}/json/api/ids/chapter` },
            ],
        });
        const idsHead = { ...ENTRY, fingerprint: "b1", json: `${SITE}/json/api/ids`, ref: "api:ids" };
        const build = siteBuildOf([idsHead], { "/a": { fingerprint: "x", lastmod: "2026-09-20" } }, SITE);
        expect(build).toStrictEqual({ build: "b1", published: ["/json/api/ids"], updated: "2026-09-20", version: 2 });
        expect(() => siteBuildOf([], {}, SITE)).toThrow("id manifest head");
        const parts = { collections: [], documents: [], pages: [], queries: [ENTRY], trees: [] };
        const site = siteLeaf(DISCOVERY, parts, build);
        expect(Reflect.get(site.data, "published")).toBeUndefined();
        expect(site.identity.address).toStrictEqual({ json: "/json/api", markdown: "/api.md" });
        expect(site.data).toMatchObject({ build: "b1", updated: "2026-09-20", version: 2 });
        expect(site.markdown).toContain("## Address patterns");
        expect(site.markdown).toContain(`[Learning route](${SITE}/api/route.md)`);
        expect(site.markdown).toContain("Crawl freely.");
        expect(site.markdown).toContain("Catalog version 2, last changed on 2026-09-20, build b1.");
    });

    it("splits a group over the part budget into numbered shards the head lists in order", () => {
        const long = "x".repeat(2048);
        const many = Array.from({ length: 400 }, (_unused, at) => ({
            ...ENTRY,
            ref: `lexicon:t${String(at)}`,
            summary: long,
        }));
        const leaves = idsLeaves(many, SITE);
        const shards = leaves.slice(0, -1);
        expect(shards.length).toBeGreaterThan(1);
        expect(shards[0]?.identity.address.json).toBe("/json/api/ids/lexicon/_1");
        expect(shards[0]?.identity.title).toContain("part 1 of");
    });
});