markdownHtml
uses tcmts.cli.pages.highlight, which uses tcmts.cli.pages.jsxPieces, which uses tcmts.core.ts.parse, which uses tcmts.core.ts.compiler, which uses process
Markdown as HTML for a page: tcm-page:<hash> links (a doc's links to code, a page's to other pages) open that
definition's page, images kept in the codebase (tcm-page:<hash> too) are shown, each a link to its page, and
TypeScript code blocks are highlighted. Other links are kept only to http(s), mailto and relative addresses
(safeHref): a README, a comment or a contribution's description can't make a javascript: link.
import type { Codebase } from "#codebase/tcmts/cli/codebase"; import { formatOf, isBytes } from "#codebase/tcmts/cli/files"; import { esc, highlight, IMAGE_TYPES } from "#codebase/tcmts/cli/pages"; import { codeHref, safeHref } from "#codebase/tcmts/share"; import { Marked } from "marked"; import type { Tokens } from "marked"; export function markdownHtml(cb: Codebase, md: string): string { return new Marked({ gfm: true, renderer: { link({ href, tokens }: Tokens.Link) { const text = this.parser.parseInline(tokens); if (href.startsWith("tcm-page:")) { const name = cb.store.pathsOf(href.slice(9))[0]; return name ? `<a href="${codeHref(name)}">${text}</a>` : text; } // (a link to anywhere but a page, a site or an address is its text: no javascript: URL is ever made a link) const safe = safeHref(href); return safe === undefined ? text : `<a href="${esc(safe)}">${text}</a>`; }, image({ href, text, title }: Tokens.Image) { const alt = esc(text); const t = title ? ` title="${esc(title)}"` : ""; if (!href.startsWith("tcm-page:")) return `<img src="${esc(href)}" alt="${alt}"${t}>`; // a file of the codebase: the image itself, in the page, a link to the file's page (it full size) const hash = href.slice(9); const rec = cb.store.getDef(hash); const name = cb.store.pathsOf(hash)[0]; const format = rec?.kind === "file" ? formatOf(rec) : ""; const src = rec && format === "svg" && !isBytes(rec) ? `data:image/svg+xml;charset=utf-8,${encodeURIComponent(rec.sourceText)}` : rec && IMAGE_TYPES[format] && isBytes(rec) ? `data:${IMAGE_TYPES[format]};base64,${rec.sourceText}` : undefined; if (!src) return alt; const img = `<img src="${src}" alt="${alt}"${t}>`; return name ? `<a class="figure" href="${codeHref(name)}">${img}</a>` : img; }, code({ text, lang }: Tokens.Code) { const ts = lang && ["ts", "tsx", "typescript", "js", "jsx", "javascript"].includes(lang); return `<pre class="code">${ts ? highlight(text, [], new Set(), lang!.endsWith("x")) : esc(text)}</pre>\n`; }, html({ text }: Tokens.HTML | Tokens.Tag) { return esc(text); }, }, }).parse(md) as string; }
uses
- tcmts.cli.codebase.Codebase
- tcmts.cli.files.formatOf
- tcmts.cli.files.isBytes
- tcmts.cli.pages.IMAGE_TYPES
- tcmts.cli.pages.esc
- tcmts.cli.pages.highlight
- tcmts.share.codeHref
- tcmts.share.safeHref