Markdown

:= [
    Heading({ level : Level, content : List(Inline) }),
    Paragraph(List(Inline)),
    Blockquote(List(Markdown)),
    ListBlock({ kind : ListKind, loose : Bool, items : List({ task : TaskState, blocks : List(Markdown) }) }),
    Code({ info : Str, pre : Str }),
    ThematicBreak,
    Table({ header : List(List(Inline)), align : List(Alignment), rows : List(List(List(Inline))) }),
    HtmlBlock(Str),
    Frontmatter(Str),
]

A Markdown document as a tree of blocks with inline content.

The parser follows CommonMark 0.31.2 plus these GitHub Flavored Markdown extensions: tables, task list items, strikethrough (~~text~~) and extended autolinks (www.example.com, https://example.com and me@example.com without angle brackets). It also accepts one extension of its own: a frontmatter block between two --- lines at the very start of a document, kept raw as Frontmatter.

Markdown has no syntax errors, so parsing never fails: Markdown.parse_str returns List(Markdown) directly, and text that looks like broken syntax is kept as text. Soft line breaks are kept as "\n" inside Text. Block quotes and lists nest at most 1,000 levels deep, and so do emphasis, strikethrough, links and images; deeper markers, delimiters and brackets are read as text.

Security: raw HTML passes through unchanged as HtmlBlock and HtmlInline, with no GFM tagfilter, and link destinations are not checked (a javascript: URL is kept as written). If you render untrusted Markdown to HTML, sanitize the HTML or drop those nodes and unsafe URLs yourself.

to_inspect : Markdown -> Str

Render a Markdown block in Roc source-like notation for inspection.

is_eq : _

Compare two Markdown syntax trees structurally.

to_hash : _

Hash a Markdown syntax tree, so that it can be a Dict key or Set element.

parse_str : Str -> List(Markdown)

Parse a whole Markdown document into its blocks.

Every input is a document, so this never fails. A leading frontmatter block becomes the first block, Frontmatter.

expect Markdown.parse_str("# Hi\n\nSome *text*.") == [
    Heading({ level: One, content: [Text("Hi")] }),
    Paragraph([Text("Some "), Emphasis([Text("text")]), Text(".")]),
]
parse_inlines : Str -> List(Inline)

Parse inline content, such as a single line of a table cell or a title, without any block structure. Reference links cannot resolve here, because their definitions are blocks: use Markdown.parse_str for those.

expect Markdown.parse_inlines("**Bold** and `code`") == [
    Strong([Text("Bold")]),
    Text(" and "),
    InlineCode("code"),
]
frontmatter : List(Markdown) -> Try(Str, [Missing])

The raw text of the document's frontmatter, or Err(Missing) when the document has none.

expect Markdown.frontmatter(Markdown.parse_str("---\ntitle: Hi\n---\nBody")) == Ok("title: Hi\n")
expect Markdown.frontmatter(Markdown.parse_str("Body")) == Err(Missing)

Level

:= [One, Two, Three, Four, Five, Six]

Heading levels from one through six.

to_inspect : Level -> Str

Render a heading level for inspection.

to_str : Level -> Str

Convert a heading level to its decimal representation.

is_eq : _

Compare two heading levels.

to_hash : _

Hash this value, so that it can be a Dict key or Set element.

ListKind

:= [
    Unordered,
    Ordered({ start : U64 }),
]

The marker and starting number of a Markdown list.

to_inspect : ListKind -> Str

Render a list kind for inspection.

to_str : ListKind -> Str

Convert a list kind to a compact string.

is_eq : _

Compare two list kinds structurally.

to_hash : _

Hash this value, so that it can be a Dict key or Set element.

TaskState

:= [
    NoTask,
    Unchecked,
    Checked,
]

Whether a list item is a task and, if so, whether it is checked.

to_inspect : TaskState -> Str

Render a task state for inspection.

to_str : TaskState -> Str

Convert a task state to a compact string.

is_eq : _

Compare two task states.

to_hash : _

Hash this value, so that it can be a Dict key or Set element.

Alignment

:= [
    Default,
    Left,
    Center,
    Right,
]

Column alignment declared by a Markdown table delimiter row.

to_inspect : Alignment -> Str

Render a table alignment for inspection.

to_str : Alignment -> Str

Convert a table alignment to a compact string.

is_eq : _

Compare two table alignments.

to_hash : _

Hash this value, so that it can be a Dict key or Set element.

LinkTarget : {
    href : Str,
    title : Try(Str, [Missing]),
}

Destination and optional title of a link or image.

Inline

:= [
    Text(Str),
    Strong(List(Inline)),
    Emphasis(List(Inline)),
    Strikethrough(List(Inline)),
    InlineCode(Str),
    Link({ label : List(Inline), target : LinkTarget }),
    Image({ alt : List(Inline), target : LinkTarget }),
    HardBreak,
    HtmlInline(Str),
]

Inline Markdown syntax nodes.

to_inspect : Inline -> Str

Render an inline node in Roc source-like notation for inspection.

is_eq : _

Compare two inline syntax trees structurally.

to_hash : _

Hash this value, so that it can be a Dict key or Set element.