Skip to Content

@stesura/markdown

Converts between markdown and ProseMirror blocks of the Stesura schema. Neither direction throws: whatever can’t be converted is simplified or dropped and reported as a Warning. The AI package uses it to exchange documents with the model.

Parse

parseMarkdown

Parse markdown into section_content children, plus note bodies. Never throws: unsupported constructs are reported, and a failure (e.g. stack exhaustion on deeply nested input) yields no blocks with a warning.

Parameters:
NameTypeDefault
markdownstring
optionsParseOptions
Returns:
ParseResult

ParseOptions

What parseMarkdown takes: the target schema plus document context for validation.

NameTypeDefault
knownListRefsreadonly string[]

listRefs in doc.attrs.listConfigs. When given, num= refs are validated (exact, then case-insensitive, else inferred with a warning) and a sole ref becomes the inference default.

nearbyNumbering{ listRef: string; instanceId?: string; }

Numbering of the block next to the parse target. It wins listRef inference, and lists with its listRef continue its instanceId (like applyListRef).

knownStylesreadonly string[]

Style ids in the document’s stylesheet. When given, style= is validated (exact, then case-insensitive, else the implied style with a warning); otherwise trusted.

noteRefs{ footnotes?: ReadonlySet<string>; endnotes?: ReadonlySet<string>; }

The document’s note refs by kind. Endnotes serialize as footnotes, so this is what turns their anchors back into endnote anchors (MD-26); unknown refs become footnote anchors. Also keeps definitions of known refs that aren’t anchored in the parsed markdown.

resolveImageSrc(blockId: string) => string | null

Resolves an image:<blockId> sentinel back to its source (SEC-67). If it can’t, the image is kept without a source and a warning is raised.

fenceHandlersReadonly<Record<string, FenceHandler>>

Fence handlers keyed by info-string language, consulted before a fence becomes a code_block. How packages bring their own block nodes in.

schemaSchema<any, any>

ParseResult

Result of parseMarkdown.

NameTypeDefault
blocksNode[]

Top-level block nodes, ready to be placed inside a section_content.

noteBodiesMap<string, Node[]>

Bodies of [^ref]: … definitions, keyed by ref. They belong in the doc-level footnotes/endnotes containers, so applying them is the caller’s job (MD-23).

warningsWarning[]

Serialize

serializeBlocks

Serialize section_content children to markdown. Never throws: unsupported content is reported, and a failure yields empty markdown with a warning.

Parameters:
NameTypeDefault
blocksreadonly Node[]
optionsSerializeOptions
Returns:
SerializeResult

SerializeOptions

What serializeBlocks takes.

NameTypeDefault
profile"read" | "plain"

“read” (default): AI-facing, emits {#id style=X …} block attrs where they differ from what the markdown implies. “plain”: markdown without attrs.

footnotesNode

The doc-level footnotes node; when given, [^ref]: … definitions are appended.

endnotesNode

The doc-level endnotes node; endnotes print as footnotes.

nodeHandlersReadonly<Record<string, PmNodeHandler>>

Node handlers merged over the defaults (same name replaces). How packages serialize their own nodes; a node without a handler is reported.

labelOf(node: Node) => string | undefined

A block’s clause label, printed as label="5.2(a)" in the read profile.

numberingOf(node: Node) => ResolvedNumbering | null | undefined

A block’s numbering after the style cascade (getResolvedNumbering). A style-numbered block’s list and level are derived, not on the node: without this it serializes as unnumbered.

crossReferenceTextOf(node: Node) => string

A cross-reference’s label (crossReferenceText(node, state)). Without it, the label the editor showing the node last computed, else its stored text.

redlineboolean

Tracked insertions and deletions inline, as {+new+} and [-old-]: a redline to read.

SerializeResult

Result of serializeBlocks.

NameTypeDefault
markdownstring
warningsWarning[]

Warnings

Warning

A non-fatal degradation. Neither direction throws: lossy input degrades and is reported here. Messages are written to be shown verbatim to the model.

NameTypeDefault
codeWarningCode
messagestring

WarningCode

export type WarningCode = | "unsupported-node" | "unsupported-mark" | "dropped-content" | "clamped-heading-level" | "invalid-block-attr" | "invalid-inline-token" | "unknown-style" | "unknown-list-ref" | "inferred-list-ref" | "table-simplified" | "ignored-footnote-definition";

The kind of loss a Warning reports.

Extensions

Packages bring markdown support for their own nodes as a MarkdownExtension (for example mermaidMarkdown from @stesura/mermaid). Register it once per schema, and every conversion on that schema uses it, including the AI tools’:

import { registerMarkdownExtensions } from '@stesura/markdown' import { mermaidMarkdown } from '@stesura/mermaid' registerMarkdownExtensions(schema, mermaidMarkdown)

registerMarkdownExtensions

Makes every parseMarkdown/serializeBlocks call on schema use these extensions (e.g. mermaidMarkdown), callers that know nothing about them included: the AI tools, attachments, text actions. Later registrations win on a shared key; options passed to a call win over all of them.

Parameters:
NameTypeDefault
schemaSchema<any, any>
extensionsMarkdownExtension[]
Returns:
void

MarkdownExtension

A package’s markdown support for its own nodes, spread into both parseMarkdown and serializeBlocks options.

NameTypeDefault
fenceHandlersReadonly<Record<string, FenceHandler>>
nodeHandlersReadonly<Record<string, PmNodeHandler>>

FenceHandler

Builds a node from a fenced code block of one info-string language (e.g. mermaid). null falls back to a plain code_block.

Parameters:
NameTypeDefault
valuestring
attrsBlockAttrs
schemaSchema<any, any>
Returns:
Node | null

MarkdownNodeHandler

A PM → mdast node handler, as SerializeOptions.nodeHandlers takes it.

Parameters:
NameTypeDefault
nodeNode
parentNode
stateState<string, string>
Returns:
Nodes | Nodes[] | null
Last updated on