Docs/Data & text

Markdown & HTML

Turn Markdown into HTML and sanitize untrusted HTML.

On this page

valk.markdown turns Markdown into HTML, and valk.html escapes text and checks URLs for safe use in a page.

Markdown to HTML#

Valk
use valk.markdown

fn main() {
    let html = markdown.to_html("# Notes\n\nSome **bold** and `code`.\n\n- one\n- two")
    println(html)
}

Supported: # and underlined headings, paragraphs, > quotes, -, +, * and 1. lists, fenced code blocks, --- rules, inline code, *emphasis*, **bold**, ~~strikethrough~~, links and images with an optional "title", and backslash escapes.

Raw HTML in the input is not supported: every <, >, ", ' and & is escaped. The output is therefore safe to put in a page, also for Markdown from users.

Options#

Valk
use valk.markdown

fn main() {
    let options = markdown.ToHtmlOptions {
        paragraph_class: "text"
        code_class: "code-block"
        allowed_schemes: .{ "https" }
    }
    println(markdown.to_html("[ok](https://valk-lang.dev) [bad](javascript:alert(1))", options))
    // <p class="text"><a href="https://valk-lang.dev">ok</a> bad</p>
}
Option Meaning
paragraph_class class of every <p>
code_class class of the <code> in fenced code blocks
allowed_schemes Link and image schemes allowed; default http, https, mailto

A link with another scheme (javascript:, data:, ...) keeps its text but loses the link, and such an image is dropped. Relative URLs are always allowed. markdown.to_html_into(md, writer) writes to a writer.

Escape text for HTML#

Valk
use valk.html

fn main() {
    let comment = "<script>alert('hi')</script> & more"
    println(html.escape(comment)) // &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt; &amp; more
}

The result is safe as element text and inside a quoted attribute. html.EscapeOptions leaves chosen characters alone, and html.escape_into(text, writer) writes to a writer. Templates escape {{ }} output this way by default.

Check URLs in HTML#

For HTML you did not write, html.sanitize_url_attributes empties every URL attribute (href, src, ...) whose scheme is not allowed, and html.url_is_allowed checks one URL:

Valk
use valk.html

fn main() {
    println(html.url_is_allowed("https://example.com"))    // true
    println(html.url_is_allowed("javascript:alert(1)"))    // false
    println(html.sanitize_url_attributes("<a href=\"javascript:alert(1)\">x</a>")) // <a href="">x</a>
}

Both take the allowed schemes as their last argument (default http, https, mailto). They only handle URLs: they do not remove tags, scripts or event attributes. To show untrusted text, escape it; to let users format text, have them write Markdown.