comrak
Version:
TypeScript and WebAssembly bindings for comrak, a blazing fast CommonMark and GFM compatible Markdown-to-HTML tool written in Rust.
384 lines (359 loc) • 11.8 kB
text/typescript
// @ts-types="./lib/comrak_wasm.d.ts"
import { markdown_to_html, type Options } from "./lib/comrak_wasm.js";
/**
* Options for the {@linkcode markdownToHTML} function.
*/
export interface ComrakOptions {
/** Enable CommonMark extensions. */
extension?: ComrakExtensionOptions;
/** Configure parse-time options. */
parse?: ComrakParseOptions;
/** Configure render-time options. */
render?: ComrakRenderOptions;
}
/** Options to select extensions. */
export interface ComrakExtensionOptions {
/** Enables the
* [autolink extension](https://github.github.com/gfm/#autolinks-extension-)
* from the GFM spec.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("Hello www.github.com.\n", { extension: { autolink: true } });
* // "<p>Hello <a href=\"http://www.github.com\">www.github.com</a>.</p>\n"
* ```
*
* @default {false}
*/
autolink?: boolean;
/** Enables the description lists extension.
*
* Each term must be defined in one paragraph, followed by a blank line, and
* then by the details. Details begins with a colon.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("Term\n\n: Definition", { extension: { descriptionLists: true } });
* // "<dl><dt>Term</dt>\n<dd>\n<p>Definition</p>\n</dd>\n</dl>\n"
* ```
*
* @default {false}
*/
descriptionLists?: boolean;
/** Enables the footnotes extension per cmark-gfm.
*
* The extension is modelled after
* [Kramdown](https://kramdown.gettalong.org/syntax.html#footnotes).
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("Hi[^x].\n\n[^x]: A greeting.\n", { extension: { footnotes: true } });
* // "<p>Hi<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup>.</p>\n<section class=\"footnotes\">\n<ol>\n<li id=\"fn1\">\n<p>A greeting. <a href=\"#fnref1\" class=\"footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\n"
* ```
*
* @default {false}
*/
footnotes?: boolean;
/** Enables the front matter extension.
*
* Front matter, which begins with the delimiter string at the beginning of
* the file and ends at the end of the next line that contains only the
* delimiter, is passed through unchanged in markdown output and omitted
* from HTML output.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("---\nlayout: post\n---\nText\n", { extension: { frontMatterDelimiter: "---" } });
* // "<p>Text</p>\n"
* ```
*
* @default {null}
*/
frontMatterDelimiter?: string | null;
/** Enables the header IDs Comrak extension.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("# README\n", { extension: { headerIDs: "user-content-" } });
* // "<h1><a href=\"#readme\" aria-hidden=\"true\" class=\"anchor\" id=\"user-content-readme\"></a>README</h1>\n"
* ```
*
* @default {null}
*/
headerIDs?: string | null;
/** Enables the
* [strikethrough extension](https://github.github.com/gfm/#strikethrough-extension-)
* from the GFM spec.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("Hello ~world~ there.\n", { extension: { strikethrough: true } });
* // "<p>Hello <del>world</del> there.</p>\n"
* ```
*
* @default {false}
*/
strikethrough?: boolean;
/** Enables the superscript Comrak extension.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("e = mc^2^.\n", { extension: { superscript: true } });
* // "<p>e = mc<sup>2</sup>.</p>\n"
* ```
*
* @default {false}
*/
superscript?: boolean;
/** Enables the
* [table extension](https://github.github.com/gfm/#tables-extension-)
* from the GFM spec.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("| a | b |\n|---|---|\n| c | d |\n", { extension: { table: true } });
* // "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n" +
* // "<tbody>\n<tr>\n<td>c</td>\n<td>d</td>\n</tr>\n</tbody>\n</table>\n"
* ```
*
* @default {false}
*/
table?: boolean;
/** Enables the
* [tagfilter extension](https://github.github.com/gfm/#disallowed-raw-html-extension-)
* from the GFM spec.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("Hello <xmp>.\n\n<xmp>", { extension: { tagfilter: true } });
* // "<p>Hello <xmp>.</p>\n<xmp>\n"
* ```
*
* @default {false}
*/
tagfilter?: boolean;
/** Enables the
* [task list items extension](https://github.github.com/gfm/#task-list-items-extension-)
* from the GFM spec.
*
* Note that the spec does not define the precise output, so only the bare essentials are rendered.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("* [x] Done\n* [ ] Not done\n", { extension: { tasklist: true } });
* // "<ul>\n<li><input type=\"checkbox\" disabled=\"\" checked=\"\" /> Done</li>\n\
* // <li><input type=\"checkbox\" disabled=\"\" /> Not done</li>\n</ul>\n"
* ```
*
* @default {false}
*/
tasklist?: boolean;
}
/** Options for parser functions. */
export interface ComrakParseOptions {
/**
* The default info string for fenced code blocks.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("\`\`\`\nfn hello();\n\`\`\`\n");
* // "<pre><code>fn hello();\n</code></pre>\n"
*
* markdownToHTML("\`\`\`\nfn hello();\n\`\`\`\n", { parse: { defaultInfoString: "rust" } });
* // "<pre><code class=\"language-rust\">fn hello();\n</code></pre>\n"
* ```
*
* @default {null}
*/
defaultInfoString?: string | null;
/** Punctuation (quotes, full-stops and hyphens) are converted into ‘smart’
* punctuation.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("'Hello,' \"world\" ...");
* // "<p>'Hello,' "world" ...</p>\n"
*
* markdownToHTML("'Hello,' \"world\" ...", { parse: { smart: true } });
* // "<p>‘Hello,’ “world” …</p>\n"
* ```
*
* @default {false}
*/
smart?: boolean;
/**
* Whether or not a simple `x` or `X` is used for tasklist or any other
* symbol is allowed.
*
* @default {false}
*/
relaxedTasklistMatching?: boolean;
}
/**
* Options for formatter functions.
*/
export interface ComrakRenderOptions {
/** Escape raw HTML instead of clobbering it.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("<i>italic text</i>");
* // "<p><!-- raw HTML omitted -->italic text<!-- raw HTML omitted --></p>\n"
*
* markdownToHTML("<i>italic text</i>", { render: { escape: true } });
* // "<p><i>italic text</i></p>\n"
* ```
*
* @default {false}
*/
escape?: boolean;
/** GitHub-style `<pre lang="xyz">` is used for fenced code blocks with info
* tags.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("\`\`\`rust\nfn hello();\n\`\`\`\n");
* // "<pre><code class=\"language-rust\">fn hello();\n</code></pre>\n"
*
* markdownToHTML("\`\`\`rust\nfn hello();\n\`\`\`\n", { render: { githubPreLang: true } });
* // "<pre lang=\"rust\"><code>fn hello();\n</code></pre>\n"
* ```
*
* @default {false}
*/
githubPreLang?: boolean;
/** [Soft line breaks](https://spec.commonmark.org/0.27/#soft-line-breaks) in
* the input translate into hard line breaks in the output.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("Hello.\nWorld.\n");
* // "<p>Hello.\nWorld.</p>\n"
*
* markdownToHTML("Hello.\nWorld.\n", { render: { hardbreaks: true } });
* // "<p>Hello.<br />\nWorld.</p>\n"
* ```
*
* @default {false}
*/
hardbreaks?: boolean;
/** Allow rendering of raw HTML and potentially dangerous links.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("<script>\nalert('xyz');\n</script>\n\n\
* Possibly <marquee>annoying</marquee>.\n\n\
* [Dangerous](javascript:alert(document.cookie)).\n\n\
* [Safe](http://commonmark.org).\n");
* // "<!-- raw HTML omitted -->\n\
* // <p>Possibly <!-- raw HTML omitted -->annoying<!-- raw HTML omitted -->.</p>\n\
* // <p><a href=\"\">Dangerous</a>.</p>\n\
* // <p><a href=\"http://commonmark.org\">Safe</a>.</p>\n"
*
* markdownToHTML("<script>\nalert('xyz');\n</script>\n\n\
* Possibly <marquee>annoying</marquee>.\n\n\
* [Dangerous](javascript:alert(document.cookie)).\n\n\
* [Safe](http://commonmark.org).\n",
* { render: { unsafe: true } });
* // "<script>\nalert(\'xyz\');\n</script>\n\
* // <p>Possibly <marquee>annoying</marquee>.</p>\n\
* // <p><a href=\"javascript:alert(document.cookie)\">Dangerous</a>.</p>\n\
* // <p><a href=\"http://commonmark.org\">Safe</a>.</p>\n"
* ```
*
* @default {false}
*/
unsafe?: boolean;
/**
* The wrap column when outputting CommonMark.
*
* @default {0}
*/
width?: number;
/** Whether to use the full info string for fenced code blocks.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("\`\`\`rust extra info\nfn hello();\n\`\`\`\n");
* // "<pre><code class=\"language-rust\">fn hello();\n</code></pre>\n"
*
* markdownToHTML("\`\`\`rust extra info\nfn hello();\n\`\`\`\n", { render: { fullInfoString: true } });
* // "<pre><code class=\"language-rust\" data-meta="extra info">fn hello();\n</code></pre>\n"
* ```
*
* @default {false}
*/
fullInfoString?: boolean;
/** The style for list items.
*
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("* Item\n* Item\n", { render: { listStyle: "star" } });
* // "<ul>\n<li>Item</li>\n<li>Item</li>\n</ul>\n"
* ```
*
* @default {"dash"}
*/
listStyle?: "dash" | "plus" | "star";
}
/**
* Render Markdown to HTML.
*
* @param markdown The Markdown string to be converted.
* @param [options] Options to customize the conversion.
* @returns The generated HTML string.
* @example
* ```ts
* import { markdownToHTML } from "comrak";
*
* markdownToHTML("Hello, **Nick**!");
* // "<p>Hello, <strong>Nick</strong>!</p>\n"
* ```
*/
export function markdownToHTML(
markdown: string,
options: ComrakOptions = {},
): string {
const { extension = {}, parse = {}, render = {} } = options;
const opts = {
extension_autolink: extension.autolink ?? false,
extension_description_lists: extension.descriptionLists ?? false,
extension_footnotes: extension.footnotes ?? false,
extension_front_matter_delimiter: extension.frontMatterDelimiter ?? "---",
extension_header_ids: extension.headerIDs ?? "",
extension_strikethrough: extension.strikethrough ?? false,
extension_superscript: extension.superscript ?? false,
extension_table: extension.table ?? false,
extension_tagfilter: extension.tagfilter ?? false,
extension_tasklist: extension.tasklist ?? false,
parse_default_info_string: parse.defaultInfoString ?? "",
parse_smart: parse.smart ?? false,
parse_relaxed_tasklist_matching: parse.relaxedTasklistMatching ?? false,
render_escape: render.escape ?? false,
render_github_pre_lang: render.githubPreLang ?? false,
render_hardbreaks: render.hardbreaks ?? false,
render_unsafe: render.unsafe ?? false,
render_width: render.width ?? 0,
render_full_info_string: render.fullInfoString ?? false,
render_list_style: render.listStyle ?? "dash",
} satisfies Options;
return markdown_to_html(markdown, opts);
}