@milkdown/preset-commonmark
Version:
The commonmark preset of [milkdown](https://milkdown.dev/).
75 lines (62 loc) • 2.12 kB
text/typescript
import type { Node } from '@milkdown/transformer'
import { $remark } from '@milkdown/utils'
import { withMeta } from '../__internal__'
const isParent = (node: Node): node is Node & { children: Node[] } =>
!!(node as Node & { children: Node[] }).children
const isHTML = (
node: Node
): node is Node & { children: Node[]; value: unknown } => node.type === 'html'
function flatMapWithDepth(
ast: Node,
fn: (node: Node, index: number, parent: Node | null) => Node[]
) {
return transform(ast, 0, null)[0]
function transform(node: Node, index: number, parent: Node | null) {
if (isParent(node)) {
const out = []
for (let i = 0, n = node.children.length; i < n; i++) {
const nthChild = node.children[i]
if (nthChild) {
const xs = transform(nthChild, i, node)
if (xs) {
for (let j = 0, m = xs.length; j < m; j++) {
const item = xs[j]
if (item) out.push(item)
}
}
}
}
node.children = out
}
return fn(node, index, parent)
}
}
// List of container node types that can contain block-level content
// and thus may need HTML content to be wrapped in paragraphs
const BLOCK_CONTAINER_TYPES = ['root', 'blockquote', 'listItem']
/// @internal
/// This plugin should be deprecated after we support HTML.
export const remarkHtmlTransformer = $remark(
'remarkHTMLTransformer',
() => () => (tree: Node) => {
flatMapWithDepth(tree, (node, _index, parent) => {
if (!isHTML(node)) return [node]
// If the parent is a block container that expects block content,
// wrap the HTML in a paragraph node
if (parent && BLOCK_CONTAINER_TYPES.includes(parent.type)) {
node.children = [{ ...node }]
delete node.value
;(node as { type: string }).type = 'paragraph'
}
return [node]
})
}
)
withMeta(remarkHtmlTransformer.plugin, {
displayName: 'Remark<remarkHtmlTransformer>',
group: 'Remark',
})
withMeta(remarkHtmlTransformer.options, {
displayName: 'RemarkConfig<remarkHtmlTransformer>',
group: 'Remark',
})