# presentation/renderers/grammar.renderer.ts

> 127 lines of code and 20 definitions.

Tree: Site tree
Language: typescript
Layer: product
Canonical: https://banes-lab.com/anatomy/tree#file-presentation-renderers-grammar-renderer-ts
Source text: https://banes-lab.com/assets/sources/source.ec2734434c1f2b27d66f85411cf6b38ef4bdab28ce21c02b199bd5208133c97b.generated.txt

## Definitions

- `renderGrammarBlock` (lexical_declaration, line 118, exported)
- `renderVerdict` (lexical_declaration, line 46)
- `renderDiagram` (lexical_declaration, line 110)
- `renderKeywords` (lexical_declaration, line 40)
- `renderCompare` (lexical_declaration, line 66)
- `renderChecks` (lexical_declaration, line 87)
- `renderTypes` (lexical_declaration, line 104)
- `renderKeyword` (lexical_declaration, line 23)
- `renderComparison` (lexical_declaration, line 55)
- `renderSignature` (lexical_declaration, line 93)
- `CHECKED_CLASS` (lexical_declaration, line 19)
- `WRONG_CLASS` (lexical_declaration, line 20)
- `CORRECT_CLASS` (lexical_declaration, line 21)
- `tooltip` (lexical_declaration, line 27)
- `caption` (lexical_declaration, line 47)
- `renderCheckItem` (lexical_declaration, line 72)
- `box` (lexical_declaration, line 73)
- `element` (lexical_declaration, line 77)
- `grid` (lexical_declaration, line 105)
- `className` (lexical_declaration, line 111)

## Uses

- [core/factories/element.factory.ts](https://banes-lab.com/source/tree/core/factories/element.factory.ts.md)

## Used by

- [presentation/renderers/block.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/block.renderer.ts.md)
- [presentation/renderers/figure.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/figure.renderer.ts.md)

## Source

```typescript
import { CHECKED_ICON, CORRECT_ICON, WRONG_ICON } from "#configuration/icons/grammar.icons";
import { CORRECT_LABEL, WRONG_LABEL } from "#configuration/strings/grammar.strings";
import type {
    CheckBlock,
    CompareBlock,
    Comparison,
    DiagramBlock,
    GrammarBlock,
    Keyword,
    KeywordBlock,
    Signature,
    TypeBlock,
} from "#types/grammar.types";
import { appendChildren, createElement } from "#core/factories/element.factory";
import { ICON_BASE_CLASS } from "#configuration/icons/element.icons";
import { SPACE } from "#configuration/constants/document.constants";
import { fillMarkup } from "#presentation/renderers/text.renderer";

const CHECKED_CLASS = "checked";
const WRONG_CLASS = "compare-wrong";
const CORRECT_CLASS = "compare-correct";

const renderKeyword = function renderKeyword(keyword: Keyword | string): Element {
    if (typeof keyword === "string") {
        return createElement("code", { className: "keyword", text: keyword });
    }
    const tooltip = createElement("div", {
        children: [createElement("span", { className: "keyword-tooltip-text", text: keyword.description })],
        className: "keyword-tooltip",
    });
    if (keyword.example !== undefined) {
        tooltip.append(createElement("code", { className: "keyword-tooltip-example", text: keyword.example }));
    }
    return createElement("div", {
        children: [createElement("code", { className: "keyword interactive", text: keyword.name }), tooltip],
        className: "keyword-wrapper",
    });
};

const renderKeywords = function renderKeywords(block: KeywordBlock): Element {
    const grid = createElement("div", { className: "keyword-grid" });
    appendChildren(grid, block.keywords.map(renderKeyword));
    return grid;
};

const renderVerdict = function renderVerdict(className: string, icon: string, label: string, code: string): Element {
    const caption = createElement("span", { className: "compare-label" });
    caption.append(createElement("i", { className: `${ICON_BASE_CLASS} ${icon}` }), SPACE + label);
    return createElement("div", {
        children: [caption, createElement("code", { className: "compare-code", text: code })],
        className,
    });
};

const renderComparison = function renderComparison(entry: Comparison): Element {
    return createElement("div", {
        children: [
            createElement("span", { className: "compare-issue", text: entry.issue }),
            renderVerdict(WRONG_CLASS, WRONG_ICON, WRONG_LABEL, entry.wrong),
            renderVerdict(CORRECT_CLASS, CORRECT_ICON, CORRECT_LABEL, entry.correct),
        ],
        className: "compare-card",
    });
};

const renderCompare = function renderCompare(block: CompareBlock): Element {
    const grid = createElement("div", { className: "compare-grid" });
    appendChildren(grid, block.entries.map(renderComparison));
    return grid;
};

const renderCheckItem = function renderCheckItem(item: string): Element {
    const box = createElement("span", {
        children: [createElement("i", { className: `${ICON_BASE_CLASS} ${CHECKED_ICON}` })],
        className: "check-box",
    });
    const element = createElement("div", {
        children: [box, fillMarkup(createElement("span", { className: "check-label" }), item)],
        className: "check-item",
    });
    element.addEventListener("click", () => {
        element.classList.toggle(CHECKED_CLASS);
    });
    return element;
};

const renderChecks = function renderChecks(block: CheckBlock): Element {
    const grid = createElement("div", { className: "check-grid" });
    appendChildren(grid, block.items.map(renderCheckItem));
    return grid;
};

const renderSignature = function renderSignature(signature: Signature): Element {
    return createElement("div", {
        children: [
            createElement("code", { className: "type-name", text: signature.name }),
            createElement("span", { className: "type-verb", text: signature.verb }),
            createElement("span", { className: "type-purpose", text: signature.purpose }),
        ],
        className: "type-card",
    });
};

const renderTypes = function renderTypes(block: TypeBlock): Element {
    const grid = createElement("div", { className: "type-grid" });
    appendChildren(grid, block.types.map(renderSignature));
    return grid;
};

const renderDiagram = function renderDiagram(block: DiagramBlock): Element {
    const className = block.grammar === true ? "diagram grammar" : "diagram";
    return createElement("div", {
        children: [createElement("pre", { children: [createElement("code", { text: block.text })], className })],
        className: "diagram-block",
    });
};

export const renderGrammarBlock = function renderGrammarBlock(block: GrammarBlock): Element {
    switch (block.kind) {
        case "keyword": {
            return renderKeywords(block);
        }
        case "compare": {
            return renderCompare(block);
        }
        case "check": {
            return renderChecks(block);
        }
        case "type": {
            return renderTypes(block);
        }
        case "diagram": {
            return renderDiagram(block);
        }
        default: {
            return renderDiagram(block);
        }
    }
};
```
