Markdown
Crate carries two text modules that work together: crate.text.markdown turns a block-structured JSON document into Markdown source, and crate.text.markdownVibe turns Markdown source into HTML.
crate.text.markdown
Section titled “crate.text.markdown”Editor-style rich-text fields are usually stored as a list of typed blocks rather than as prose. toMarkdown flattens such a document:
import crate.text.markdown;
auto article = `{ "blocks": [ { "type": "header", "data": { "text": "Release notes" } }, { "type": "paragraph", "data": { "text": "Bulk operations landed." } } ]}`.parseJsonString;
auto source = article.toMarkdown;Block type | Rendered as |
|---|---|
header | ## <text> |
paragraph | <text> |
Every block is followed by a blank line, and the result is stripped. A document with no blocks array, or one whose blocks are all of unrecognized types, produces an empty string — unknown types are skipped rather than rejected, so a newer editor’s document degrades instead of failing.
toHeader and toParagraph are exposed if you need to render a single block.
crate.text.markdownVibe
Section titled “crate.text.markdownVibe”A Markdown-to-HTML filter, extended past vanilla Markdown with tables, attributes, figures, and a document outline.
import crate.text.markdownVibe;
auto html = filterMarkdown(source, MarkdownFlags.backtickCodeBlocks | MarkdownFlags.tables);filterMarkdown has four forms: return a string or write into an output range dst, each taking either a MarkdownFlags value or a MarkdownSettings object.
MarkdownSettings
Section titled “MarkdownSettings”| Field | Default | Purpose |
|---|---|---|
flags | vanillaMarkdown | Which extensions the parser recognizes |
headingBaseLevel | 1 | Level the first heading renders at, so embedded content can sit under a page title |
urlFilter | null | string delegate(string url, bool isImage) — rewrite every link and image target |
allowedURISchemas | ["http", "https", "ftp", "mailto"] | Schemas permitted in link and image targets |
The schema allow-list is a security control, not a convenience: a javascript: URI in a link is blocked and escaped rather than emitted.
MarkdownFlags
Section titled “MarkdownFlags”| Flag | Effect |
|---|---|
none / vanillaMarkdown | Standard Markdown only |
keepLineBreaks | Single newlines become <br>; suits plain-text sources such as email |
backtickCodeBlocks | Fenced code blocks |
noInlineHtml | Embedded HTML is escaped instead of passed through |
tables | Markdown Extra / GitHub table syntax |
attributes | { … } after a link or image adds HTML attributes to the element |
figures | - %%% list syntax produces <figure>, - ### produces <figcaption> |
forumDefault | keepLineBreaks, backtickCodeBlocks, noInlineHtml and tables combined |
Flags are a bit set — combine them with |.
Document Outline
Section titled “Document Outline”getMarkdownOutline returns the heading tree without rendering the document, which is what a table-of-contents component needs:
Section[] outline = getMarkdownOutline(source);
struct Section { size_t headingLevel; string caption; string anchor; Section[] subSections;}anchor is the slug generated for the heading — lowercased, with dashes for spaces — and matches the id filterMarkdown puts on the rendered heading, so outline entries link to the right place.
Limits
Section titled “Limits”The parser is not fully CommonMark compliant. vanillaMarkdown is the intent — standard Markdown — rather than a conformance claim.