calternal_collab::markdown
Markdown dialect bridge for editor content. Frontmatter belongs to the host.
This module is a port of the editor’s converter
(packages/editor/src/markdown.ts): the same reader and the same writer,
step for step. Both sides must produce the same bytes for the same
document, or opening and saving a Note in one place rewrites bytes the
user did not touch. contracts/vectors/markdown/ and the seeded
cross-language test in tests/cross_language.rs pin that contract; the
decisions are in docs/DESIGN.md §9. Reader or writer changes need the same
change in the TypeScript module, and the other way round. The server-only
conflict-anchor helper below edits a canonical tree; it does not change
the shared Markdown dialect (#634, DESIGN §33).
JavaScript semantics that matter for byte parity are kept on purpose:
trim and \s use the JavaScript whitespace set, . in a regular
expression stops at U+2028 and U+2029, and indentation widths count
UTF-16 code units.
The reader never drops source bytes: a form it cannot build as a schema
node stays literal paragraph text, which the writer escapes so that it
reads back as the same text. Markdown wiki embeds (![[file.png]]) have no
node in the editor schema, so they are plain text, and a wikilink span is
copied byte for byte in both directions.
A Note is untrusted input, so work and recursion are bounded by the input
size, not by its shape. The TypeScript reader has no such bounds. Two
bounds can therefore give a different (but lossless) document for hostile
input only: block nesting deeper than MAX_BLOCK_DEPTH, and an inline
run whose delimiter search exceeds its work budget. Both keep the text
as literal paragraph text (see markdown_to_prosemirror_tolerant).
Source: crates/calternal-collab/src/markdown.rs
Functions
Section titled “Functions”literal_document
Section titled “literal_document”pub fn literal_document(source: &str) -> ValueA document that holds the whole source as one literal paragraph. This is the last fallback when even the tolerant reader’s output cannot be stored.
Source: crates/calternal-collab/src/markdown.rs:1519
markdown_to_prosemirror
Section titled “markdown_to_prosemirror”pub fn markdown_to_prosemirror(source: &str) -> Result<Value, BridgeError>Parse the supported editor Markdown dialect into normalized schema JSON.
It never fails; the Result is kept for callers.
Source: crates/calternal-collab/src/markdown.rs:2162
markdown_to_prosemirror_tolerant
Section titled “markdown_to_prosemirror_tolerant”pub fn markdown_to_prosemirror_tolerant(source: &str) -> (Value, usize)Parse Markdown and count the blocks kept as literal text because they passed a work or depth bound. A Note always opens and no byte is dropped; the caller logs the count with the Note id (never the content).
Source: crates/calternal-collab/src/markdown.rs:2169
prosemirror_to_markdown
Section titled “prosemirror_to_markdown”pub fn prosemirror_to_markdown(pm: &Value) -> Result<String, BridgeError>Serialize a document to a Markdown body (docToMarkdown).