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); } } };