# core/renderers/readme.renderer.ts

> 184 lines of code and 27 definitions.

Tree: Build tree
Language: typescript
Layer: product
Canonical: https://banes-lab.com/anatomy/build#file-build-core-renderers-readme-renderer-ts
Source text: https://banes-lab.com/assets/sources/source.99f1f65b82d496c8b4c440ef9fe66dd1f8da727ac9de6f4aeebafbb52a43a78f.generated.txt

## Definitions

- `renderReadme` (lexical_declaration, line 176, exported)
- `reading` (lexical_declaration, line 164)
- `exhibitChapters` (lexical_declaration, line 144)
- `chapterEntry` (lexical_declaration, line 129)
- `stance` (lexical_declaration, line 138)
- `works` (lexical_declaration, line 134)
- `exhibits` (lexical_declaration, line 152)
- `stepGroup` (lexical_declaration, line 160)
- `loop` (lexical_declaration, line 168)
- `ATTRIBUTION_SPACE` (lexical_declaration, line 93)
- `ITEM_INDENT` (lexical_declaration, line 94)
- `header` (lexical_declaration, line 96)
- `owner` (lexical_declaration, line 97)
- `licence` (lexical_declaration, line 103)
- `icons` (lexical_declaration, line 104)
- `logo` (lexical_declaration, line 105)
- `callout` (lexical_declaration, line 109)
- `grammar` (lexical_declaration, line 110)
- `lines` (lexical_declaration, line 111)
- `sectionsOf` (lexical_declaration, line 125)
- `summary` (lexical_declaration, line 130)
- `target` (lexical_declaration, line 139)
- `tail` (lexical_declaration, line 140)
- `folder` (lexical_declaration, line 148)
- `items` (lexical_declaration, line 153)
- `diagram` (lexical_declaration, line 169)
- `body` (lexical_declaration, line 177, exported)

## Uses

- [core/normalizers/readme.normalizer.ts](https://banes-lab.com/source/build/core/normalizers/readme.normalizer.ts.md)
- [core/renderers/markdown.renderer.ts](https://banes-lab.com/source/build/core/renderers/markdown.renderer.ts.md)

## Used by

- [core/renderers/chapter.renderer.ts](https://banes-lab.com/source/build/core/renderers/chapter.renderer.ts.md)

## Source

```typescript
import {
    ADAPT_TEXT,
    ADAPT_TITLE,
    BY_AUTHOR,
    CALLOUT_BODY,
    CALLOUT_GRAMMAR,
    CALLOUT_LEAD,
    CALLOUT_TAIL,
    CHAPTER_SUMMARIES,
    CONTEXT_NOTE,
    CONTEXT_TEXT,
    CONTEXT_TITLE,
    EXHIBIT_LEAD,
    EXHIBIT_TITLE,
    EXPECT_TEXT,
    EXPECT_TITLE,
    FORMAT_TEXT,
    FORMAT_TITLE,
    INTRO_TEXT,
    LICENSED_UNDER,
    LOOP_LEAD,
    LOOP_TITLE,
    MACHINE_BODY,
    MACHINE_INDEX,
    MACHINE_LEAD,
    MACHINE_TAIL,
    PROBLEM_ITEMS,
    PROBLEM_LEAD,
    PROBLEM_TITLE,
    QUESTIONS_LEAD,
    QUESTIONS_NOTE,
    QUESTIONS_TITLE,
    QUESTION_ITEMS,
    READING_LEAD,
    READING_TITLE,
    SETUP_STEPS,
    STANCE_ITEMS,
    STANCE_LEAD,
    STANCE_TAIL,
    STANCE_TITLE,
    START_LEAD,
    START_TITLE,
    WHY_ITEMS,
    WHY_LEAD,
    WHY_TITLE,
    WORKS_LEAD,
    WORKS_NOTE,
    WORKS_TITLE,
} from "#configuration/strings/readme.strings";
import { ANATOMY_PAGE, GRAMMAR_PAGE } from "@banes-lab/web/core/ids/page.ids.ts";
import {
    ANCHOR_MARK,
    BOLD,
    CENTER_CLOSE,
    CENTER_OPEN,
    FENCE_LANGUAGE,
    HEADING_ONE,
    HEADING_THREE,
    ICON_SIZE,
    LLMS_ROUTE,
    LOGO_WIDTH,
    QUOTE_MARK,
    SENTENCE_END,
} from "#configuration/constants/readme.constants";
import { AUTHOR_PROFILE, METHODOLOGY_REPOSITORY, SITE_URL, pagePath } from "@banes-lab/web/core/assets/link.assets.ts";
import { BADGE_LOGO, LICENSE_BY, LICENSE_CC, LICENSE_SA } from "@banes-lab/web/core/assets/image.assets.ts";
import {
    CHAPTER_SEPARATOR,
    FENCE_MARK,
    FOLDER_SEPARATOR,
    LIST_ITEM,
    NESTED_ITEM,
    PARAGRAPH_BREAK,
} from "#configuration/constants/chapter.constants";
import { LOOP_SECTION_ID, STANCE_SECTION_ID } from "@banes-lab/web/core/ids/methodology.start.ids.ts";
import type { ReadmeInputs, ReadmePage, ReadmeSection, ReadmeStep, ReadmeTab } from "#types/readme.types";
import {
    attributionLine,
    bullets,
    image,
    link,
    note,
    numbered,
    section,
    tabFileOf,
} from "#core/renderers/markdown.renderer";
import { isRepositoryPage, pageFolderOf } from "#core/normalizers/readme.normalizer";
import type { Attribution } from "#types/chapter.types";
import { LINE_END } from "#configuration/constants/inventory.constants";
import { START_TAB } from "@banes-lab/web/core/ids/methodology.ids.ts";
import { renderFaq } from "#core/renderers/faq.renderer";

const ATTRIBUTION_SPACE = " ";
const ITEM_INDENT = "  ";

const header = function header(inputs: ReadmeInputs, attribution: Attribution): string {
    const owner =
        link(inputs.heading, METHODOLOGY_REPOSITORY) +
        ATTRIBUTION_SPACE +
        attribution.copyright +
        BY_AUTHOR +
        link(attribution.author, AUTHOR_PROFILE);
    const licence = LICENSED_UNDER + link(attribution.licenseName, attribution.licenseUrl);
    const icons = [LICENSE_CC, LICENSE_BY, LICENSE_SA].map((icon) => image(SITE_URL + icon, ICON_SIZE, "")).join("");
    const logo = image(SITE_URL + BADGE_LOGO, LOGO_WIDTH, inputs.heading);
    return [CENTER_OPEN, "", logo, "", owner + licence + ATTRIBUTION_SPACE + icons, "", CENTER_CLOSE].join(LINE_END);
};

const callout = function callout(inputs: ReadmeInputs): string {
    const grammar = inputs.exhibits.find((page) => page.page === GRAMMAR_PAGE);
    const lines = [
        CALLOUT_LEAD,
        "",
        CALLOUT_BODY + link(CALLOUT_GRAMMAR, SITE_URL + pagePath(GRAMMAR_PAGE)) + CALLOUT_TAIL,
        "",
        grammar?.description ?? "",
        "",
        MACHINE_LEAD,
        "",
        MACHINE_BODY + link(MACHINE_INDEX, SITE_URL + LLMS_ROUTE) + MACHINE_TAIL,
    ];
    return lines.map((line) => (line.length === 0 ? QUOTE_MARK.trim() : QUOTE_MARK + line)).join(LINE_END);
};

const sectionsOf = function sectionsOf(page: ReadmePage): readonly ReadmeSection[] {
    return page.tabs.flatMap((tab) => tab.sections);
};

const chapterEntry = function chapterEntry(tab: ReadmeTab): string {
    const summary = CHAPTER_SUMMARIES.find((entry) => entry.tab === tab.id)?.summary ?? "";
    return [HEADING_THREE + link(tab.label, tabFileOf(tab.id)), summary].join(PARAGRAPH_BREAK);
};

const works = function works(page: ReadmePage): string {
    return section(WORKS_TITLE, WORKS_LEAD, WORKS_NOTE, ...page.tabs.map(chapterEntry));
};

const stance = function stance(): string {
    const target = tabFileOf(START_TAB) + ANCHOR_MARK + STANCE_SECTION_ID;
    const tail = STANCE_TAIL + link(STANCE_TITLE, target) + SENTENCE_END;
    return section(STANCE_TITLE, STANCE_LEAD, numbered(STANCE_ITEMS), tail);
};

const exhibitChapters = function exhibitChapters(page: ReadmePage): string[] {
    if (!isRepositoryPage(page.page)) {
        return [];
    }
    const folder = pageFolderOf(page.page, page.title);
    return page.tabs.map((tab) => NESTED_ITEM + link(tab.label, folder + FOLDER_SEPARATOR + tabFileOf(tab.id)));
};

const exhibits = function exhibits(inputs: ReadmeInputs): string {
    const items = inputs.exhibits.flatMap((page) => [
        LIST_ITEM + link(page.title, SITE_URL + pagePath(page.page)) + PARAGRAPH_BREAK + ITEM_INDENT + page.description,
        ...exhibitChapters(page),
    ]);
    return section(EXHIBIT_TITLE, EXHIBIT_LEAD, items.join(LINE_END));
};

const stepGroup = function stepGroup(group: ReadmeStep): string {
    return [HEADING_THREE + group.title, numbered(group.steps)].join(PARAGRAPH_BREAK);
};

const reading = function reading(page: ReadmePage): string {
    return section(READING_TITLE, READING_LEAD, numbered(page.tabs.map((tab) => link(tab.label, tabFileOf(tab.id)))));
};

const loop = function loop(page: ReadmePage): string {
    const diagram = sectionsOf(page).find((candidate) => candidate.id === LOOP_SECTION_ID)?.diagram;
    if (diagram === null || diagram === undefined) {
        return "";
    }
    return section(LOOP_TITLE, LOOP_LEAD, [FENCE_MARK + FENCE_LANGUAGE, diagram, FENCE_MARK].join(LINE_END));
};

export const renderReadme = function renderReadme(inputs: ReadmeInputs, attribution: Attribution): string {
    const body = [
        header(inputs, attribution),
        callout(inputs),
        [HEADING_ONE + inputs.heading, BOLD + inputs.subtitle + BOLD, INTRO_TEXT].join(PARAGRAPH_BREAK),
        section(PROBLEM_TITLE, PROBLEM_LEAD, bullets(PROBLEM_ITEMS)),
        works(inputs.methodology),
        section(FORMAT_TITLE, FORMAT_TEXT),
        stance(),
        section(WHY_TITLE, WHY_LEAD, bullets(WHY_ITEMS)),
        exhibits(inputs),
        section(START_TITLE, START_LEAD, ...SETUP_STEPS.map(stepGroup)),
        section(CONTEXT_TITLE, CONTEXT_TEXT, note(CONTEXT_NOTE, SITE_URL + pagePath(ANATOMY_PAGE))),
        section(QUESTIONS_TITLE, QUESTIONS_LEAD, bullets(QUESTION_ITEMS), note(QUESTIONS_NOTE, SITE_URL + LLMS_ROUTE)),
        section(ADAPT_TITLE, ADAPT_TEXT),
        section(EXPECT_TITLE, EXPECT_TEXT),
        reading(inputs.methodology),
        loop(inputs.methodology),
        renderFaq(inputs.faq),
    ].filter((part) => part.length > 0);
    return body.join(CHAPTER_SEPARATOR) + CHAPTER_SEPARATOR + attributionLine(attribution) + LINE_END;
};
```
