Mutation/query helpers —
replaceNode,wrapNode,flattenNode,findFirst/All,cloneNode.
Module mdAstManipulation | Source packages/front/office/md/src/ast/manipulation.js | Deps mdErrors, mdNode | Worker-safe yes
High-level API for transforming a parsed AST. Operates on the linked-list shape (firstChild / lastChild / prev / next / parent). replaceNode, wrapNode and flattenNode mutate the tree in place (a replaced or flattened node is unlinked, not destroyed, so the argument stays a valid object); findFirst / findAll only read; cloneNode copies. The module also returns the ContractError class it throws.
Resolve
import { runtime } from '@awacloud/fw';
import { fw_require, modules } from '@awacloud/md';
runtime.registerAll(fw_require);
runtime.registerAll(modules);
const { replaceNode, wrapNode, flattenNode, findFirst, findAll, cloneNode } = runtime.resolve('mdAstManipulation');
Direct factory call (manually chaining its 2 deps):
import { mdAstManipulation, mdErrors, mdNode } from '@awacloud/md';
const m = mdAstManipulation.factory(mdErrors.factory(), mdNode.factory());
API
| Method | Signature | Returns |
|---|---|---|
replaceNode |
(old: Node, fresh: Node) => Node |
fresh |
wrapNode |
(node: Node, wrapper: Node) => Node |
wrapper |
flattenNode |
(node: Node) => void |
— (lifts children) |
findFirst |
(root, pred) => Node | null |
First match |
findAll |
(root, pred) => Node[] |
All matches |
cloneNode |
(node, deep=false) => Node |
Scalar copy + (deep) children |
Examples
Case 1 — replace a link
const { findAll, replaceNode } = runtime.resolve('mdAstManipulation');
const { Node } = runtime.resolve('mdNode');
const md = runtime.resolve('md');
const ast = md.parse('see [old](http://x).');
const link = findAll(ast, n => n.type === 'link')[0];
const txt = new Node('text'); txt.literal = '[redacted]';
replaceNode(link, txt);
Case 2 — wrap a node
const { wrapNode } = runtime.resolve('mdAstManipulation');
const { Node } = runtime.resolve('mdNode');
const md = runtime.resolve('md');
const para = md.parse('hello').firstChild;
const wrap = new Node('block_quote');
wrapNode(para, wrap);
// the paragraph is now a child of the block_quote
Case 3 — flatten (unwrap)
const { flattenNode } = runtime.resolve('mdAstManipulation');
const md = runtime.resolve('md');
const emphNode = md.parse('a *b* c').firstChild.firstChild.next; // the `emph` node
flattenNode(emphNode); // emphNode's children take its place
Notes
replaceNode/wrapNode/flattenNodethrowContractError(codesmd/replace-node-no-parent,md/wrap-node-no-parent,md/flatten-node-no-parent) if the node argument has no parent.cloneNodedefaults to shallow: copies the scalar slots (type,level,literal, …) +data(shallowObject.assign). Withdeep=true, recursively copies children.findFirst/findAlltraverse depth-first viaWalker; for a predicate that doesn't depend on the parent, this is optimal.- The operations preserve
prev/next/parentlinked-list consistency — no leaks.
See also
ast/node— underlying primitives +Walker/walk()- Read+write — extract + transform + re-emit pattern