toDocTree(md, options?): DocDocument
Converts a Markdown string to a typed DocDocument tree (plain JSON, no HTML, no ANSI).
Import
import { toDocTree } from 'md-to-rich'
// or sub-path:
import { toDocTree } from 'md-to-rich/doc-tree'
Signature
function toDocTree(md: string, options?: DocTreeOptions): DocDocument
DocTreeOptions inherits from BaseOptions (gfm, remarkPlugins).
JSON Output Example
import { toDocTree } from 'md-to-rich'
const tree = toDocTree('# Hello\n\nThis is **bold** and *italic*.')
{
"type": "document",
"children": [
{
"type": "heading",
"depth": 1,
"children": [
{ "type": "text", "value": "Hello", "bold": false, "italic": false, "strikethrough": false }
]
},
{
"type": "paragraph",
"children": [
{ "type": "text", "value": "This is ", "bold": false, "italic": false, "strikethrough": false },
{ "type": "text", "value": "bold", "bold": true, "italic": false, "strikethrough": false },
{ "type": "text", "value": " and ", "bold": false, "italic": false, "strikethrough": false },
{ "type": "text", "value": "italic", "bold": false, "italic": true, "strikethrough": false },
{ "type": "text", "value": ".", "bold": false, "italic": false, "strikethrough": false }
]
}
]
}
Use Cases
toDocTree outputs a plain JSON tree with no runtime dependencies — ideal for:
- ProseMirror — map
DocBlockNode→PMNode,DocTextmarks →PMMark - Slate — map
DocBlockNode→ Slate element,DocText→ Slate leaf - Quill — convert to Delta operations
- Custom renderers — traverse the tree to build any output format
- Server-side storage — store structured content and re-render later
Tree Traversal Example
import { toDocTree } from 'md-to-rich'
import type { DocBlockNode, DocInlineNode, DocDocument } from 'md-to-rich'
function collectText(doc: DocDocument): string[] {
const texts: string[] = []
function visitInline(node: DocInlineNode) {
if (node.type === 'text') texts.push(node.value)
if (node.type === 'link') node.children.forEach(visitInline)
}
function visitBlock(node: DocBlockNode) {
if ('children' in node) {
for (const child of node.children) {
if ('value' in child || child.type === 'text' || child.type === 'link') {
visitInline(child as DocInlineNode)
} else {
visitBlock(child as DocBlockNode)
}
}
}
}
doc.children.forEach(visitBlock)
return texts
}
Notes
- Nested
strong/emphasis/deletemarks are flattened intoDocTextboolean flags (bold,italic,strikethrough). A node that is both bold and italic will havebold: true, italic: true. DocListItem.checkedistrue/falsefor GFM task list items andnullfor regular list items.DocTableRow.isHeaderistruefor the first row (the header row) in a GFM table.DocList.startis the first item number of an ordered list,nullfor unordered lists (2.1.0+).- GFM footnotes produce
footnoteReferenceinline nodes, with thefootnoteDefinitionblocks moved to the end of the document (2.1.0+). - Reference-style links and images resolve to ordinary
linkandimagenodes (2.1.0+).
See Doc Tree Node Types for the complete type reference.
FAQ
Does toDocTree() keep raw HTML?
No. Raw HTML in the Markdown is dropped: an HTML block disappears, and inline tags such as <b> are removed while the text between them stays as plain, unformatted DocText. Link and image URLs are sanitised like toHtml()'s from md-to-rich 2.0.1, so javascript: and data: URLs become #; see Security.
Can I store toDocTree() output as JSON?
Yes. A DocDocument is made of plain objects, arrays, strings, numbers, booleans and null (never undefined), so JSON.parse(JSON.stringify(tree)) gives back an identical tree. That makes it safe to save in a database column or send over an API.
Does toDocTree() include heading IDs or source positions?
No. DocHeading has only depth and children, and no node carries line or column positions. If you need heading slugs, toHtml() generates them with its headingIds option; see the toHtml() API.
Related
- Markdown to ProseMirror: a complete ProseMirror adapter
- Markdown to Slate: a complete Slate converter
- Markdown to Quill: build a Quill Delta