import type { Block, CardBlock, CodeBlock, DefinitionBlock, FigureBlock, GlossaryBlock, GroupBlock, GroupEntry, LessonBlock, LinkBlock, ListBlock, MarkdownBlock, MermaidBlock, MetricBlock, SourceBlock, TableBlock, TextBlock, WalkBlock, } from "#types/block.types"; import { appendChildren, createElement } from "#core/factories/element.factory"; import type { GrammarBlock } from "#types/grammar.types"; import { createCodeBlock } from "#presentation/components/code.component"; import { fillMarkup } from "#presentation/renderers/text.renderer"; import { renderCards } from "#presentation/renderers/card.renderer"; import { renderDefinition } from "#presentation/renderers/definition.renderer"; import { renderDiagram } from "#presentation/renderers/diagram.renderer"; import { renderDocument } from "#presentation/renderers/markdown.renderer"; import { renderFigure } from "#presentation/renderers/figure.renderer"; import { renderGlossary } from "#presentation/renderers/glossary.block.renderer"; import { renderGrammarBlock } from "#presentation/renderers/grammar.renderer"; import { renderLesson } from "#presentation/renderers/lesson.renderer"; import { renderLinks } from "#presentation/renderers/link.renderer"; import { renderMetrics } from "#presentation/renderers/metric.renderer"; import { renderSource } from "#presentation/renderers/source.renderer"; import { renderTable } from "#presentation/renderers/table.renderer"; import { renderWalk } from "#presentation/renderers/walk.renderer"; const renderText = function renderText(block: TextBlock): Element { const className = block.note === true ? "block-note" : "block-text"; return fillMarkup(createElement("p", { className }), block.text); }; const renderList = function renderList(block: ListBlock): Element { const wrapper = createElement("div", { className: "block-list" }); if (block.label !== undefined) { wrapper.append(createElement("h4", { className: "block-label", text: block.label })); } const list = createElement(block.ordered === true ? "ol" : "ul", {}); appendChildren( list, block.items.map((item) => fillMarkup(createElement("li", {}), item)), ); wrapper.append(list); return wrapper; }; const renderGroup = function renderGroup(group: GroupEntry): Element { const wrapper = createElement("div", { className: "block-group" }); if (group.title !== undefined) { wrapper.append(fillMarkup(createElement("h4", { className: "block-label" }), group.title)); } if (group.content !== undefined) { wrapper.append(fillMarkup(createElement("p", { className: "block-text" }), group.content)); } if (group.items !== undefined) { wrapper.append(renderList({ items: group.items, kind: "list" })); } if (group.entries !== undefined) { wrapper.append(renderGlossary({ entries: group.entries, kind: "glossary" })); } return wrapper; }; const renderGroups = function renderGroups(block: GroupBlock): Element { const className = block.tone === undefined ? "block-groups" : `block-groups ${block.tone}`; const wrapper = createElement("div", { className }); appendChildren(wrapper, block.groups.map(renderGroup)); return wrapper; }; type CompositeBlock = CardBlock | FigureBlock | LessonBlock | MermaidBlock | MetricBlock | WalkBlock; type CodedBlock = CodeBlock | DefinitionBlock | MarkdownBlock | SourceBlock; const renderCoded = function renderCoded(block: CodedBlock): Element { switch (block.kind) { case "code": { return createCodeBlock(block.code, block.title, block.language); } case "source": { return renderSource(block); } case "markdown": { return renderDocument(block); } case "definition": { return renderDefinition(block); } default: { return renderDefinition(block); } } }; const renderComposite = function renderComposite(block: CompositeBlock): Element { switch (block.kind) { case "card": { return renderCards(block); } case "lesson": { return renderLesson(block); } case "figure": { return renderFigure(block); } case "mermaid": { return renderDiagram(block); } case "walk": { return renderWalk(block); } case "metric": { return renderMetrics(block); } default: { return renderMetrics(block); } } }; type SimpleBlock = GlossaryBlock | GroupBlock | LinkBlock | ListBlock | TableBlock | TextBlock; const COMPOSITE_KINDS = new Set(["card", "figure", "lesson", "mermaid", "metric", "walk"]); const CODED_KINDS = new Set(["code", "definition", "markdown", "source"]); const GRAMMAR_KINDS = new Set(["check", "compare", "diagram", "keyword", "type"]); const isComposite = function isComposite(block: Block): block is CompositeBlock { return COMPOSITE_KINDS.has(block.kind); }; const isCoded = function isCoded(block: Block): block is CodedBlock { return CODED_KINDS.has(block.kind); }; const isGrammar = function isGrammar(block: Block): block is GrammarBlock { return GRAMMAR_KINDS.has(block.kind); }; const renderSimple = function renderSimple(block: SimpleBlock): Element { switch (block.kind) { case "text": { return renderText(block); } case "list": { return renderList(block); } case "glossary": { return renderGlossary(block); } case "table": { return renderTable(block); } case "group": { return renderGroups(block); } case "link": { return renderLinks(block); } default: { return renderLinks(block); } } }; export const renderBlock = function renderBlock(block: Block): Element { if (isGrammar(block)) { return renderGrammarBlock(block); } if (isCoded(block)) { return renderCoded(block); } if (isComposite(block)) { return renderComposite(block); } return renderSimple(block); };