render

import { render } from "jsr:@ende/markdown";

function

function render(ast: Root, options: RenderOptions = [UNSUPPORTED]): string

Renders 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: Root

The 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 &lt; 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("<", "&lt;")}</span>` : undefined;
assertEquals(
  render(parse("~~~ts\nlet a = 1 < 2;\n~~~"), { highlight }),
  "<pre><code class=\"language-ts\"><span class=\"ts\">let a = 1 &lt; 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>&lt;script&gt;alert(1)&lt;/script&gt;</p>\n<p>Hello &lt;b&gt;you&lt;/b&gt;</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>
`
);

Source