presentation/renderers/text.renderer.ts
presentation/renderers/text.renderer.ts is a file in Bane's Lab Site. 64 lines of code and 10 definitions.
import { CITE_ATTRIBUTE, CITE_CLASS } from "#configuration/constants/chapter.constants";
import type { ElementTag } from "#types/element.types";
import { NO_CLASS } from "#configuration/constants/element.constants";
import type { Run } from "#types/markup.types";
import { convertMarkup } from "#core/converters/markup.converter";
import { createElement } from "#core/factories/element.factory";
import { createLink } from "#presentation/components/link.component";
const TAG_BY_KIND: ReadonlyMap<Run["kind"], ElementTag> = new Map([
["strong", "strong"],
["emphasis", "em"],
["code", "code"],
["link", "a"],
["break", "br"],
["cite", "span"],
]);
const renderRun = function renderRun(run: Run): Node {
const tag = TAG_BY_KIND.get(run.kind);
if (tag === undefined) {
return document.createTextNode(run.text);
}
if (run.kind === "link" && run.href !== undefined) {
return createLink(run.href, NO_CLASS, [run.text]);
}
if (run.kind === "cite") {
return createElement("span", {
attributes: { [CITE_ATTRIBUTE]: run.text },
className: CITE_CLASS,
text: run.text,
});
}
return createElement(tag, run.kind === "break" ? {} : { text: run.text });
};
const isEmphasized = function isEmphasized(run: Run): boolean {
return run.kind === "emphasis" || run.emphasis === true;
};
const renderInside = function renderInside(run: Run): Node {
return run.kind === "emphasis" ? document.createTextNode(run.text) : renderRun(run);
};
const renderMarkup = function renderMarkup(markup: string): readonly Node[] {
const nodes: Node[] = [];
let open: HTMLElement | null = null;
for (const run of convertMarkup(markup)) {
if (!isEmphasized(run)) {
open = null;
nodes.push(renderRun(run));
continue;
}
if (open === null) {
open = createElement("em");
nodes.push(open);
}
open.append(renderInside(run));
}
return nodes;
};
export const plainText = function plainText(markup: string): string {
return convertMarkup(markup)
.map((run) => run.text)
.join(NO_CLASS);
};
export const fillMarkup = function fillMarkup<T extends Element>(element: T, markup: string): T {
element.replaceChildren(...renderMarkup(markup));
return element;
};