Rich text / foldkit-richtext-markdown
Parse Markdown
import { parse } from 'foldkit-richtext-markdown'
let n = 0
const { document, diagnostics } = parse('> quoted\n', { mint: () => `id-${++n}` })mint supplies every identity, as it does everywhere else in the library, and the document
is decoded through the codec, so a bad construction fails loudly instead of reaching an
editor.
It reads CommonMark, plus GFM's task lists, strikethrough, and tables, and with
footnotes: true its footnotes, as foldkit-richtext's FootnoteRef and
FootnoteDefinition for a kit that declares them; without it a footnote is reported and
skipped. It reports instead of guessing: raw HTML, a link definition (a reference to one keeps
its text, unlinked), a hard line break (which becomes its
own paragraph, because a block holds no line break), and an image inside a paragraph
(Image is a block, so a paragraph holding only one is hoisted to it). Markdown is as
untrusted as pasted HTML, so a link's or an image's URL passes the same safeUrl policy
HTML import uses: a refused link keeps its text unlinked, a refused image is dropped, and
each is reported as UnsafeUrl.
print(parse(markdown)) returns the same Markdown and parse(print(document)) a document
that prints the same, which is how the two directions are tested against each other.
The same Markdown means the canonical spellings: * for emphasis, - for a bullet, backtick
fences, # headings. Text written as _hello_, * item, or a heading underlined with === is kept that way by the style parse also
returns — which spelling each construct took, first occurrence each, and never part of the
document — handed back to print:
const parsed = parse('_hello_\n\n* item\n', { mint: () => `id-${++n}` })
print(parsed.document, { style: parsed.style }).markdown // '_hello_\n\n* item\n'Blocks also keep their own spelling. style.blocks maps the id parse gave each list, heading,
fence, and rule to how that one was written, so a text with a - list and a * list, or a
setext title over ## sections, prints back as it was. A block the text did not have, such as
a list added in the rich editor, takes its construct's spelling. A list's spacing is kept the
same way: a loose list, one with a blank line between its items or inside one, prints with a
blank line between its items and their blocks, and a tight one with none, so a nested list sits
right under its item's text. Without a style, lists print tight. Emphasis stays per construct,
because runs split and merge as they are edited and their ids do not last.
A spelling that would change what the text means somewhere — _ does not open emphasis inside
a word — is not used: print reads its styled text back, and when that reads as a different
document than the canonical text, the canonical text is what it returns.