import { DIAGRAM_KIND, EXHIBIT_PAGES, LESSON_KIND, PAYLOAD_BLOCKS_KEY, PAYLOAD_DESCRIPTION_KEY, PAYLOAD_DIAGRAM_KEY, PAYLOAD_INTRO_KEY, PAYLOAD_META_KEY, PAYLOAD_PRINCIPLE_KEY, PAYLOAD_PROBLEM_KEY, PAYLOAD_SUBSECTIONS_KEY, PAYLOAD_SUBTITLE_KEY, PAYLOAD_TEXT_KEY, } from "#configuration/constants/readme.constants"; import { FAQ_PAGE, METHODOLOGY_PAGE } from "@banes-lab/web/core/ids/page.ids.ts"; import { PAYLOAD_CONTENT_KEY, PAYLOAD_ID_KEY, PAYLOAD_KIND_KEY, PAYLOAD_LABEL_KEY, PAYLOAD_SECTIONS_KEY, PAYLOAD_TABS_KEY, PAYLOAD_TITLE_KEY, } from "#configuration/constants/leak.constants"; import type { ReadmeInputs, ReadmeLesson, ReadmePage, ReadmeSection, ReadmeSubsection, ReadmeTab, } from "#types/readme.types"; import { payloadFileOf } from "#core/loaders/payload.loader"; import { readJsonOrNull } from "#core/persistence/report.persistence"; const isRecord = function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; }; const textAt = function textAt(record: Record, key: string): string | null { const value = record[key]; return typeof value === "string" ? value : null; }; const listAt = function listAt(record: Record, key: string): Record[] { const value = record[key]; return Array.isArray(value) ? value.filter(isRecord) : []; }; const lessonsOf = function lessonsOf(blocks: readonly Record[]): ReadmeLesson[] { return blocks.flatMap((block) => { const problem = textAt(block, PAYLOAD_PROBLEM_KEY); const principle = textAt(block, PAYLOAD_PRINCIPLE_KEY); return block[PAYLOAD_KIND_KEY] === LESSON_KIND && problem !== null && principle !== null ? [{ principle, problem }] : []; }); }; const subsectionOf = function subsectionOf(record: Record): ReadmeSubsection { return { content: textAt(record, PAYLOAD_TEXT_KEY), title: textAt(record, PAYLOAD_TITLE_KEY) ?? "" }; }; const diagramOf = function diagramOf(blocks: readonly Record[]): string | null { const block = blocks.find((candidate) => candidate[PAYLOAD_KIND_KEY] === DIAGRAM_KIND); return block === undefined ? null : textAt(block, PAYLOAD_DIAGRAM_KEY); }; const sectionOf = function sectionOf(record: Record): ReadmeSection { const subsections = listAt(record, PAYLOAD_SUBSECTIONS_KEY); const blocks = [ ...listAt(record, PAYLOAD_BLOCKS_KEY), ...subsections.flatMap((sub) => listAt(sub, PAYLOAD_BLOCKS_KEY)), ]; return { diagram: diagramOf(blocks), id: textAt(record, PAYLOAD_ID_KEY) ?? "", intro: textAt(record, PAYLOAD_INTRO_KEY), lessons: lessonsOf(blocks), subsections: subsections.map(subsectionOf), title: textAt(record, PAYLOAD_TITLE_KEY) ?? "", }; }; const tabOf = function tabOf(record: Record): ReadmeTab { return { id: textAt(record, PAYLOAD_ID_KEY) ?? "", label: textAt(record, PAYLOAD_LABEL_KEY) ?? "", sections: listAt(record, PAYLOAD_SECTIONS_KEY).map(sectionOf), }; }; const tabsOf = function tabsOf(content: Record, page: string): ReadmeTab[] { const tabs = listAt(content, PAYLOAD_TABS_KEY); if (tabs.length > 0) { return tabs.map(tabOf); } return [{ id: page, label: page, sections: listAt(content, PAYLOAD_SECTIONS_KEY).map(sectionOf) }]; }; export const readStructuredPage = function readStructuredPage(page: string): ReadmePage | null { const parsed = readJsonOrNull(payloadFileOf(page)); if (!isRecord(parsed) || !isRecord(parsed[PAYLOAD_CONTENT_KEY])) { return null; } const content = parsed[PAYLOAD_CONTENT_KEY]; return { description: textAt(parsed, PAYLOAD_DESCRIPTION_KEY) ?? "", page, tabs: tabsOf(content, page), title: textAt(parsed, PAYLOAD_LABEL_KEY) ?? "", }; }; const metaOf = function metaOf(page: string, key: string): string { const parsed = readJsonOrNull(payloadFileOf(page)); const content = isRecord(parsed) ? parsed[PAYLOAD_CONTENT_KEY] : null; const meta = isRecord(content) ? content[PAYLOAD_META_KEY] : null; return isRecord(meta) ? (textAt(meta, key) ?? "") : ""; }; export const readmeInputsOf = function readmeInputsOf(): ReadmeInputs | null { const methodology = readStructuredPage(METHODOLOGY_PAGE); const faq = readStructuredPage(FAQ_PAGE); const exhibits = EXHIBIT_PAGES.map(readStructuredPage); const present = exhibits.filter((page): page is ReadmePage => page !== null); if (methodology === null || faq === null || present.length !== exhibits.length) { return null; } return { exhibits: present, faq, heading: metaOf(METHODOLOGY_PAGE, PAYLOAD_TITLE_KEY), methodology, subtitle: metaOf(METHODOLOGY_PAGE, PAYLOAD_SUBTITLE_KEY), }; };