Custom
AST API
Traverse and modify the ComarkTree AST after parsing using the visit() utility.
The comark/utils module exports visit — a tree traversal utility for transforming AST nodes inside a post hook.
visit(tree, checker, visitor)
Traverses all nodes in a ComarkTree, calling visitor on every node that passes checker.
Parameters:
tree- TheComarkTreeto traversechecker- A predicate(node: ComarkNode) => boolean— returntrueto visit a nodevisitor- A transform(node: ComarkNode) => ComarkNode | false | void— seeComarkNode
Returns: void — mutations are applied in place
The visitor return value controls what happens to the node:
| Return value | Effect |
|---|---|
void | Leave the node unchanged |
ComarkNode | Replace the node with the returned value |
false | Remove the node from the tree |
Example:
import { defineComarkPlugin } from 'comark/parse'
import { visit } from 'comark/utils'
export default defineComarkPlugin(() => ({
name: 'word-count',
post(state) {
let count = 0
visit(state.tree,
(node) => typeof node === 'string',
(node) => { count += (node as string).split(/\s+/).filter(Boolean).length }
)
state.tree.meta.wordCount = count
},
}))Use Cases
Replacing Nodes
Return a new node to replace the matched one. The following example wraps bare URL text nodes in anchor elements:
import type { ComarkNode } from 'comark'
import { defineComarkPlugin } from 'comark/parse'
import { visit } from 'comark/utils'
export default defineComarkPlugin(() => ({
name: 'auto-link',
post(state) {
const urlPattern = /https?:\/\/[^\s]+/g
visit(state.tree,
(node) => typeof node === 'string',
(node) => {
const text = node as string
if (!urlPattern.test(text)) return
return ['a', { href: text }, text] as ComarkNode
}
)
},
}))Mutating Attributes
Return void and mutate the node in place when you only need to update attributes:
import { defineComarkPlugin } from 'comark/parse'
import { visit } from 'comark/utils'
export default defineComarkPlugin(() => ({
name: 'styled-tables',
post(state) {
visit(state.tree,
(node) => Array.isArray(node) && node[0] === 'table',
(node) => {
const el = node as [string, Record<string, any>, ...any[]]
el[1].class = [el[1].class, 'styled-table'].filter(Boolean).join(' ')
}
)
},
}))Removing Nodes
Return false to remove matched nodes entirely:
import { defineComarkPlugin } from 'comark/parse'
import { visit } from 'comark/utils'
export default defineComarkPlugin(() => ({
name: 'strip-html-comments',
post(state) {
visit(state.tree,
(node) => Array.isArray(node) && node[0] === null,
() => false
)
},
}))