import { ANATOMY_PAGE, FAQ_PAGE, GRAMMAR_PAGE, METHODOLOGY_PAGE } from "@banes-lab/web/core/ids/page.ids.ts"; import { CALLOUT_LEAD, CALLOUT_TAIL, CHAPTER_SUMMARIES, INTRO_TEXT, LOOP_LEAD, PROBLEM_ITEMS, PROBLEM_LEAD, STANCE_ITEMS, STANCE_LEAD, STANCE_TAIL, START_LEAD, WHY_ITEMS, WHY_LEAD, WORKS_LEAD, WORKS_NOTE, } from "@banes-lab/content/configuration/strings/readme.strings.ts"; import { LOOP_SECTION_ID, STANCE_SECTION_ID } from "@banes-lab/web/core/ids/methodology.start.ids.ts"; import { PLAN_TAB, START_TAB } from "@banes-lab/web/core/ids/methodology.ids.ts"; import { anchorOf, firstSentenceOf } from "@banes-lab/content/core/normalizers/readme.normalizer.ts"; import { describe, expect, it } from "vitest"; import { readStructuredPage, readmeInputsOf } from "@banes-lab/content/core/loaders/readme.loader.ts"; import type { Attribution } from "@banes-lab/content/types/chapter.types.ts"; import { BADGE_LOGO } from "@banes-lab/web/core/assets/image.assets.ts"; import type { ReadmeInputs } from "@banes-lab/content/types/readme.types.ts"; import { renderChapters } from "@banes-lab/content/core/renderers/chapter.renderer.ts"; import { renderFaq } from "@banes-lab/content/core/renderers/faq.renderer.ts"; import { renderReadme } from "@banes-lab/content/core/renderers/readme.renderer.ts"; const ATTRIBUTION: Attribution = { author: "Author", copyright: "© 2025 ", coveredBy: "Documentation is covered by ", licenseName: "CC BY-SA 4.0", licenseUrl: "https://creativecommons.org/licenses/by-sa/4.0/", work: " - Work", }; const INPUTS: ReadmeInputs = { exhibits: [ { description: "The grammar.", page: GRAMMAR_PAGE, tabs: [{ id: "introduction", label: "Introduction", sections: [] }], title: "PAG", }, { description: "The tree.", page: ANATOMY_PAGE, tabs: [], title: "Anatomy" }, ], faq: { description: "Questions.", page: FAQ_PAGE, tabs: [ { id: FAQ_PAGE, label: FAQ_PAGE, sections: [ { diagram: null, id: "origin", intro: null, lessons: [], subsections: [ { content: "Because [the loop](/disciplined-methodology#the-loop) says so.", title: "Why?", }, ], title: "Origin", }, ], }, ], title: "FAQ", }, heading: "Disciplined Methodology", methodology: { description: "The method.", page: METHODOLOGY_PAGE, tabs: [ { id: START_TAB, label: "Start", sections: [ { diagram: "flowchart TB\n a --> b", id: LOOP_SECTION_ID, intro: "Every piece of work has the same shape.", lessons: [], subsections: [], title: "The loop", }, { diagram: null, id: STANCE_SECTION_ID, intro: "Four sentences carry the stance, as [the four] draws and [the loop](/disciplined-methodology#the-loop) frames. The rest follows.", lessons: [{ principle: "Read before you claim.", problem: "Claims go unread." }], subsections: [], title: "The stance", }, ], }, { id: PLAN_TAB, label: "Plan", sections: [] }, ], title: "Methodology", }, subtitle: "Constraints and checks", }; describe("anchorOf and firstSentenceOf", () => { it("slugs a heading the way a hosted markdown page anchors it and cuts a text at its first sentence", () => { expect(anchorOf("The stance, read whole")).toBe("#the-stance-read-whole"); expect(firstSentenceOf("Four sentences carry the stance. The rest follows.")).toBe( "Four sentences carry the stance.", ); expect(firstSentenceOf("No stop here")).toBe("No stop here"); }); }); describe("renderReadme", () => { const readme = renderReadme(INPUTS, ATTRIBUTION); it("keeps the archived shape: centered header, callout, title and pitch, the authored sections, the derived stance, exhibits, reading path, loop and FAQ, attribution", () => { expect(readme.startsWith('