markdown

tcmts.content.markdown · #dpcxogzy · function · runs anywhere

Markdown as HTML (GitHub's flavour). A definition named as doc comments name one (@link, in braces) is shown as its name, in code, linked where link says (nowhere, by default). A fenced code block in a language is as highlight makes it (shiki makes one), if it does.

import type { Highlight } from "#codebase/tcmts/content";
import { Marked } from "marked";
import type { TokenizerAndRendererExtension } from "marked";

export function markdown(
  text: string,
  options: { link?: (name: string) => string | undefined; highlight?: Highlight } = {},
): string {
  const esc = (s: string) =>
    s.replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]!);
  const definitions: TokenizerAndRendererExtension = {
    name: "tcmLink",
    level: "inline",
    start: (src: string) => src.indexOf("{@link"),
    tokenizer(src: string) {
      const m = /^\{@link(?:code|plain)?\s+([\w$.-]+)(?:\s*\|\s*|\s+)?([^}]*)\}/.exec(src);
      return m ? { type: "tcmLink", raw: m[0], name: m[1]!, label: m[2]!.trim() } : undefined;
    },
    renderer(token) {
      const { name, label } = token as unknown as { name: string; label: string };
      const shown = `<code>${esc(label || name.slice(name.lastIndexOf(".") + 1))}</code>`;
      const to = options.link?.(name);
      return to === undefined ? shown : `<a href="${esc(to)}">${shown}</a>`;
    },
  };
  return new Marked({
    gfm: true,
    extensions: [definitions],
    renderer: {
      code({ text, lang: info }) {
        const lang = /^\S*/.exec(info ?? "")![0];
        const html = lang ? options.highlight?.(text, lang) : undefined;
        return html === undefined ? false : `${html}\n`;
      },
    },
  }).parse(text) as string;
}

uses

used by