Packages

md

Render Markdown to HTML, turn HTML back into Markdown, and strip unsafe content from Markdown you did not write.

import "std:md"

md converts between Markdown and HTML. Use it to publish posts and docs, to show user-written text on a web page, or to bring HTML from elsewhere into Markdown. It understands GitHub Flavored Markdown: tables, task lists, strikethrough and autolinks.

osl
import "std:md"

Markdown to HTML#

md.toHTML returns a string. Every heading gets an id, so you can link to it.

main.osl
import "std:md"

string text = "# Hello there\n\nSome *emphasis*, **strong text** and `code`.\n\n- one\n- two\n"
log md.toHTML(text)
Click the code to edit it

Try it: add a ## Second heading and see its id.

GitHub extensions#

Tables, task lists and strikethrough work as they do on GitHub.

main.osl
import "std:md"

string text = [
  "| name | qty |",
  "|------|-----|",
  "| bolt | 12 |",
  "",
  "- [x] write",
  "- [ ] test",
  "",
  "~~old~~ new"
].join("\n")
log md.toHTML(text)
Click the code to edit it

Untrusted input is made safe#

Raw HTML and javascript: links in the text are dropped, so you can render what visitors type without opening the door to script injection. The raw tags are replaced by comments.

main.osl
import "std:md"

log md.toHTML("hi <script>steal()</script> [click](javascript:alert(1)) [ok](https://example.com)")
Click the code to edit it

Notice that the text between the tags stays as plain text. If you trust the source, such as your own documents, pass {unsafe: true} to keep raw HTML:

main.osl
import "std:md"

log md.toHTML("A <kbd>Ctrl</kbd> key", {unsafe: true})
Click the code to edit it

HTML to Markdown#

md.fromHTML goes the other way. It returns a result: HTML it can't convert is a ParseError.

main.osl
import "std:md"

string html = [
  `<h1>Title</h1>`,
  `<p>Hello <b>bold</b> and <a href="http://example.com">a link</a>.</p>`,
  `<ul><li>one</li><li>two</li></ul>`
].join("")
log md.fromHTML(html).unwrap()
Click the code to edit it

This is useful for importing pages you scraped or for turning rich-text editor output into something you can store and diff.

Try it: add an <h2> and an <em> to the HTML.

Sanitising Markdown#

md.sanitize takes Markdown and returns Markdown with raw HTML tags and unsafe links removed. It does this by rendering to safe HTML and converting back, so the result is still Markdown you can store.

main.osl
import "std:md"

string cleaned = md.sanitize(
  "**bold** <script>x()</script> [bad](javascript:alert(1)) [good](https://example.com)"
).unwrap()
log cleaned
Click the code to edit it

Tag text such as x() survives as plain text, and the unsafe link loses its address. Sanitise what you store, or render with toHTML, which applies the same rules.

A small page generator#

Put it together with fs to turn a Markdown file into a page:

main.osl
import "std:md"
import "std:fs"

fs.writeFile("post.md", "# First post\n\nWritten in *Markdown*.\n").unwrap()
string body = md.toHTML(fs.readFile("post.md").unwrap())
string page = "<!doctype html>\n<title>Post</title>\n" ++ body
fs.writeFile("post.html", page).unwrap()
log fs.readFile("post.html").unwrap()
Click the code to edit it
Quick check

A visitor posts <script>alert(1)</script> in a comment. What does md.toHTML(comment) do with it?

Your turn

A heading helper

Write heading(text) that returns the HTML for a level-one heading with that text, and print it for Hello.

main.osl
Ctrl Enter runs
Expected output
<h1 id="hello">Hello</h1>

API reference#

4 members, generated from the std:md source of OSL 9.3.0.

Functions

#md.fromHTML(string html) result<string, error>

fromHTML converts HTML to Markdown. Fails with ParseError when the HTML can't be converted.

#md.sanitize(string text) result<string, error>

sanitize returns Markdown text with raw HTML and unsafe links removed, by rendering it to safe HTML and converting that back to Markdown. Fails with ParseError when the rendered HTML can't be converted back.

#md.toHTML(string text, object? options) string

toHTML renders Markdown text as HTML, with GitHub Flavored Markdown (tables, task lists, strikethrough, autolinks) and an id on every heading. Raw HTML in the text and javascript: links are dropped unless the unsafe option is true; only set it for text you trust. Options: unsafe (boolean, default false).

#md.toHTMLUnsafe(any text) string

Deprecated. Deprecated: use md.toHTML(text, {unsafe: true}) instead.

toHTMLUnsafe renders Markdown text as HTML and keeps any raw HTML in it.