Tree Utilities
Query, filter, split, and serialize the AST without writing raw loops.
The tree-utils module provides utilities for working with the AST. Most functions operate on Node and recurse into the entire tree automatically.
find / findAll
Find the first or all nodes matching a predicate anywhere in the tree:
import { find, findAll, isHeading } from "datamark/parse";
const firstH2 = find(doc.root, (n) => isHeading(n, 2));
const allCodeBlocks = findAll(doc.root, (n) => n.type === "code");filter
Top-level filter on a Node[] array (does not recurse):
import { filter } from "datamark/parse";
const paragraphs = filter(doc.root.children, (n) => n.type === "paragraph");sectionsAtDepth / sectionsByHeading
Find sections by depth or heading text:
import { sectionsAtDepth, sectionsByHeading } from "datamark/parse";
const h2s = sectionsAtDepth(doc.root, 2);
const introSection = sectionsByHeading(doc.root, "Introduction");splitBy
Split a flat array of block nodes by a predicate. Separator nodes are discarded:
import { splitBy, isHeading } from "datamark/parse";
const groups = splitBy(flatBlocks, (n) => isHeading(n, 2));
// BlockNode[][] — each group is nodes between H2sbetween / after / before
import { between, after, before } from "datamark/parse";
const intro = between(flatBlocks, isHeading(1), isHeading(2));
const rest = after(flatBlocks, (n) => isHeading(n, 1));
const preamble = before(flatBlocks, (n) => isHeading(n, 1));codeBlocks
Extract all code blocks recursively from any node:
import { codeBlocks } from "datamark/parse";
const blocks = codeBlocks(doc.root);
// CodeNode[]textContent / inlineText
Extract plain text from nodes:
import { textContent, inlineText } from "datamark/parse";
const bodyText = textContent(doc.root); // from any Node
const linkLabel = inlineText(linkNode.children); // from InlineNode[]toMarkdown
Serialize nodes back to a Markdown string:
import { toMarkdown } from "datamark/stringify";
const markdown = toMarkdown(doc.root); // from SectionNode
const markdown2 = toMarkdown(blocks); // from BlockNode[]toMarkdown is the reverse of parsing. It handles headings, paragraphs, code blocks, lists, blockquotes, tables, and inline formatting.
flatten
Convert a section tree back to a flat array of block nodes:
import { flatten } from "datamark/parse";
const blocks = flatten(doc.root);
// BlockNode[]isHeading / isCodeBlock / isTodoItem
Type guards for common node types:
import { isHeading, isCodeBlock, isTodoItem, extractTodoItems } from "datamark/parse";
if (isHeading(node, 1)) { /* ... */ }
if (isCodeBlock(node, "typescript")) { /* ... */ }
if (isTodoItem(node)) { /* ... */ }
const todos = extractTodoItems(doc.root);
// [{ text: "Buy milk", completed: false, raw: "[ ] Buy milk" }]Type guards
import { isSection, isBlockNode, isInlineNode, isParentNode } from "datamark/parse";
if (isSection(node)) {
console.log(node.heading?.depth);
}
if (isParentNode(node)) {
console.log(node.children.length);
}