render
import { render } from "jsr:@ende/markdown";function
function render(ast: Root, options: RenderOptions = [UNSUPPORTED]): stringRenders a syntax tree from parse() to HTML. The output matches the CommonMark reference implementation,
commonmark.js, and for the GitHub Flavored Markdown nodes, cmark-gfm, with one difference by default:
headings have an id attribute (their Heading.id). The headingIds: false option turns that off.
No id is written twice. Heading ids keep their values, since links and tables of contents use them; if a
footnote's id (fn-label, fnref-label) is already taken by a heading or another footnote, the footnote's id
gets a suffix (fn-label-1), and its links follow. Ids inside raw HTML aren't checked.
An admonition renders as GitHub renders an alert, without the icon: a
<div class="markdown-alert markdown-alert-note"> holding a
<p class="markdown-alert-title">Note</p> and the content. An admonition with
a title has that title in place of the kind's name.
Footnotes render as on GitHub: each footnoteReference becomes a numbered
<sup> link, and the definitions that are referenced move into a
<section class="footnotes"> at the end, numbered in the order of their first
reference, with links back to each reference. Definitions that are never
referenced aren't rendered, and a reference without a definition renders as
its source text.
ast: RootThe root of the syntax tree.
options: RenderOptions = [UNSUPPORTED]Options for rendering.
Returns
The HTML.
Example: Usage
import { parse } from "@ende/markdown/parse";
import { render } from "@ende/markdown/render";
import { assertEquals } from "@ende/assert";
assertEquals(render(parse("# Hello *world*")), "<h1 id=\"hello-world\">Hello <em>world</em></h1>\n");
assertEquals(render(parse("# Hello *world*"), { headingIds: false }), "<h1>Hello <em>world</em></h1>\n");
Example: Rendering a tree built by hand
import { render } from "@ende/markdown/render";
import { assertEquals } from "@ende/assert";
const html = render({
type: "root",
children: [{ type: "code", lang: "ts", meta: null, value: "let x = 1 < 2;" }]
});
assertEquals(html, "<pre><code class=\"language-ts\">let x = 1 < 2;\n</code></pre>\n");
Example: Footnotes
import { parse } from "@ende/markdown/parse";
import { render } from "@ende/markdown/render";
import { assertEquals } from "@ende/assert";
const html = render(parse("Hi[^1]\n\n[^1]: A note.", { gfm: true }));
assertEquals(
html,
`<p>Hi<sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup></p>
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p>A note. <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
</ol>
</section>
`
);
Example: Rewriting links
import { parse } from "@ende/markdown/parse";
import { render } from "@ende/markdown/render";
import { assertEquals } from "@ende/assert";
const html = render(parse("See [the guide](guide.md)."), { rewriteLink: url => url.replace(/\.md$/, "/") });
assertEquals(html, "<p>See <a href=\"guide/\">the guide</a>.</p>\n");
Example: Highlighting code
import { parse } from "@ende/markdown/parse";
import { render } from "@ende/markdown/render";
import { assertEquals } from "@ende/assert";
// A real highlighter would escape the code and add markup to it.
const highlight = (code: string, lang: string | null) => lang === "ts" ? `<span class="ts">${code.replaceAll("<", "<")}</span>` : undefined;
assertEquals(
render(parse("~~~ts\nlet a = 1 < 2;\n~~~"), { highlight }),
"<pre><code class=\"language-ts\"><span class=\"ts\">let a = 1 < 2;</span></code></pre>\n"
);
Example: Escaping or stripping raw HTML
import { parse } from "@ende/markdown/parse";
import { render } from "@ende/markdown/render";
import { assertEquals } from "@ende/assert";
const ast = parse("<script>alert(1)</script>\n\nHello <b>you</b>");
assertEquals(render(ast, { html: "escape" }), "<p><script>alert(1)</script></p>\n<p>Hello <b>you</b></p>\n");
assertEquals(render(ast, { html: "strip" }), "<p>Hello you</p>\n");
Example: GitHub alerts
import { parse } from "@ende/markdown/parse";
import { render } from "@ende/markdown/render";
import { assertEquals } from "@ende/assert";
assertEquals(
render(parse("> [!TIP]\n> Use `ende fmt`.", { gfm: true })),
`<div class="markdown-alert markdown-alert-tip">
<p class="markdown-alert-title">Tip</p>
<p>Use <code>ende fmt</code>.</p>
</div>
`
);