core/converters/graph.site.converter.ts
core/converters/graph.site.converter.ts is a file in Bane's Lab Build Scripts. 121 lines of code and 28 definitions.
import {
CHAPTER_PREFIX,
PAGE_KIND,
PART_KIND,
ROUTE_PREFIX,
SECTION_KIND,
SITE_LAYER,
TAB_KIND,
} from "#configuration/constants/graph.constants";
import type { Graph, SiteCodes } from "#types/graph.types";
import type { GraphEdge, GraphNode } from "@banes-lab/web/types/graph.types.js";
import type { DiscoveredRoute } from "#types/site.types";
import type { SectionPlan } from "#types/section.types";
import { TAG_FIELD_BY_KIND } from "@banes-lab/content/configuration/constants/panel.constants.ts";
import { citationOf } from "#core/converters/graph.code.converter";
import { isRecord } from "#core/selectors/base.selector";
const PART_PREFIX = "part:";
const PART_MARK = "/";
const NUMBER_MARK = ".";
const KIND_KEY = "kind";
const CAPTION_KEY = "caption";
const listOf = function listOf(value: unknown, key: string): readonly unknown[] {
const held = isRecord(value) ? value[key] : null;
return Array.isArray(held) ? held : [];
};
const captionOf = function captionOf(block: unknown): string | null {
if (!isRecord(block)) {
return null;
}
const kind = typeof block[KIND_KEY] === "string" ? block[KIND_KEY] : "";
const tag = block[TAG_FIELD_BY_KIND.get(kind) ?? CAPTION_KEY];
return typeof tag === "string" && tag.length > 0 ? tag : null;
};
export const captionsOf = function captionsOf(section: unknown): readonly string[] {
const blocks = [
...listOf(section, "blocks"),
...listOf(section, "subsections").flatMap((subsection) => listOf(subsection, "blocks")),
];
return blocks.flatMap((block) => {
const caption = captionOf(block);
return caption === null ? [] : [caption];
});
};
const refOf = function refOf(path: string): string {
return ROUTE_PREFIX + path;
};
export const routeGraph = function routeGraph(
routes: readonly DiscoveredRoute[],
plans: readonly SectionPlan[],
codes: SiteCodes,
contains: string,
): Graph {
const pages = new Map(routes.filter((route) => route.tab === null).map((route) => [route.page, route.path]));
const nodes: GraphNode[] = routes.map((route) => ({
address: null,
citation: null,
fields: {},
href: route.path,
kind: route.tab === null ? PAGE_KIND : TAB_KIND,
layer: SITE_LAYER,
number: (route.tab === null ? codes.pages.get(route.page) : codes.tabs.get(route.path)) ?? null,
ref: refOf(route.path),
title: route.label,
}));
const tabs = routes.flatMap((route) => {
const page = pages.get(route.page);
return route.tab === null || page === undefined
? []
: [{ from: refOf(page), relation: contains, to: refOf(route.path) }];
});
const sections = plans.map((plan) => ({ from: refOf(plan.tab.path), relation: contains, to: plan.identity.ref }));
return { edges: [...tabs, ...sections], nodes };
};
export const siteNodes = function siteNodes(
plans: readonly SectionPlan[],
numbers: ReadonlyMap<string, string>,
codes: SiteCodes,
): readonly GraphNode[] {
return plans.map((plan) => ({
address: plan.identity.address,
citation: citationOf(plan, numbers, codes),
fields: {},
href: plan.identity.href,
kind: SECTION_KIND,
layer: SITE_LAYER,
number: numbers.get(plan.identity.ref) ?? null,
ref: plan.identity.ref,
title: plan.identity.title,
}));
};
export const partGraph = function partGraph(
plans: readonly SectionPlan[],
numbers: ReadonlyMap<string, string>,
codes: SiteCodes,
contains: string,
): Graph {
const nodes: GraphNode[] = [];
const edges: GraphEdge[] = [];
for (const plan of plans) {
const section = plan.identity.ref;
const number = numbers.get(section) ?? null;
const citation = citationOf(plan, numbers, codes);
captionsOf(plan.section).forEach((caption, index) => {
const ordinal = String(index + 1);
const ref = PART_PREFIX + section.slice(CHAPTER_PREFIX.length) + PART_MARK + ordinal;
nodes.push({
address: null,
citation: citation === null ? null : citation + NUMBER_MARK + ordinal,
fields: {},
href: plan.identity.href,
kind: PART_KIND,
layer: SITE_LAYER,
number: number === null ? null : number + NUMBER_MARK + ordinal,
ref,
title: caption,
});
edges.push({ from: section, relation: contains, to: ref });
});
}
return { edges, nodes };
};