All formats

comrak

LanguageRust
LicenseBSD-2-Clause
Repositorygithub.com/kivikakk/comrak
Documentationdocs.rs/comrak
Depends ontyped-arena, caseless, finl_unicode, memchr, phf, smallvec; optional syntect (highlighting), emojis, clap (CLI)
Read / writeparses CommonMark + GFM + many extensions; renders HTML, CommonMark and XML

comrak is a Rust port of GitHub’s cmark-gfm. It passes the CommonMark and GFM spec tests, builds an arena-allocated AST of AstNodes, and renders it with format_html, format_commonmark or format_xml. Options are grouped into extension, parse and render. Beyond GFM (strikethrough, table, autolink, tasklist) it supports footnotes, front matter, header IDs, description lists, superscript and subscript, alerts, math, wiki links, underline, spoilers, emoji shortcodes and more. The Ruby gem commonmarker and many Rust tools use it.

Like cmark, it’s safe by default: raw HTML and dangerous links are removed unless you set render.r#unsafe = true.

Installation#

Shell
cargo add comrak

Basic usage: convert Markdown to HTML#

Rust
use comrak::{markdown_to_html, Options};
use std::fs;

fn main() -> std::io::Result<()> {
    let markdown = fs::read_to_string("README.md")?;

    let mut options = Options::default();
    options.extension.strikethrough = true;
    options.extension.table = true;
    options.extension.autolink = true;
    options.extension.tasklist = true;
    options.extension.footnotes = true;

    let html = markdown_to_html(&markdown, &options);
    fs::write("README.html", html)?;
    Ok(())
}

How to add heading IDs and skip front matter#

Rust
let mut options = Options::default();
options.extension.header_id_prefix = Some(String::new());          // <h2 id="install">
options.extension.front_matter_delimiter = Some("---".to_string()); // YAML block becomes a FrontMatter node
Rust
use comrak::nodes::NodeValue;
use comrak::{parse_document, Arena, Options};

let arena = Arena::new();
let root = parse_document(&arena, &markdown, &Options::default());
for node in root.descendants() {
    match &node.data().value {
        NodeValue::Heading(h) => println!("heading level {}", h.level),
        NodeValue::Link(link) => println!("link: {}", link.url),
        _ => {}
    }
}

How to change the document and render it#

Rust
use comrak::nodes::NodeValue;
use comrak::{format_commonmark, format_html, parse_document, Arena, Options};

let arena = Arena::new();
let options = Options::default();
let root = parse_document(&arena, &markdown, &options);
for node in root.descendants() {
    if let NodeValue::Link(ref mut link) = node.data_mut().value {
        link.url = link.url.replace("http://", "https://");
    }
}

let mut html = String::new();
format_html(root, &options, &mut html).unwrap();
let mut md = String::new();
format_commonmark(root, &options, &mut md).unwrap();

How to render untrusted input#

Keep the defaults: raw HTML is omitted and javascript: links are dropped. If you need raw HTML, set options.render.r#unsafe = true and sanitize the output with a crate like ammonia. options.render.escape = true shows raw HTML as text instead of dropping it.

Tips#