Created
April 10, 2024 21:46
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as Markdoc from "@markdoc/markdoc"; | |
import {Parser} from "htmlparser2"; | |
const mappings = { | |
p: 'paragraph', | |
li: 'item', | |
table: 'table', | |
tr: 'tr', | |
td: 'td', | |
tbody: 'tbody', | |
thead: 'thead', | |
b: 'strong', | |
strong: 'strong', | |
i: 'em', | |
em: 'em', | |
}; | |
function convertNode(name: string, attrs: Record<string, any>): Markdoc.Node | undefined { | |
switch (name) { | |
case 'ul': | |
return new Markdoc.Ast.Node('list', {ordered: false}); | |
case 'ol': | |
return new Markdoc.Ast.Node('list', {ordered: true}); | |
case 'h1': | |
case 'h2': | |
case 'h3': | |
case 'h4': | |
const level = ['h1', 'h2', 'h3', 'h4'].indexOf(name) + 1; | |
return new Markdoc.Ast.Node('heading', {level}); | |
case 'pre': | |
return new Markdoc.Ast.Node('fence', {content: ''}); | |
case 'code': | |
return new Markdoc.Ast.Node('code', {content: ''}); | |
case 'img': | |
return new Markdoc.Ast.Node('tag', {src: attrs.src}, [], 'image'); | |
case 'a': | |
return new Markdoc.Ast.Node('link', {href: attrs.href, title: attrs.title}); | |
default: | |
const type = mappings[name]; | |
if (type) return new Markdoc.Ast.Node(type); | |
} | |
} | |
export function convert(content: string) { | |
const root = new Markdoc.Ast.Node('document'); | |
const stack: {name: string, node?: Markdoc.Node}[] = [{name: 'root', node: root}]; | |
const parser = new Parser({ | |
onopentag(name, attrs) { | |
const {node: last} = stack.findLast(({node}) => node); | |
const node = last.type === 'fence' ? | |
null : convertNode(name, attrs); | |
if (node) { | |
const item = node.type === 'table' ? | |
new Markdoc.Ast.Node('tag', {}, [node], 'table') : node; | |
last.push(item); | |
} | |
stack.push({name, node}); | |
}, | |
onclosetag(name) { | |
stack.pop(); | |
}, | |
ontext(content) { | |
const {node: last} = stack.findLast(({node}) => node); | |
const text = new Markdoc.Ast.Node('text', {content: content.replace(" ", " ")}); | |
last.push(text); | |
const code = stack.findLast(({node}) => ['fence', 'code'].includes(node?.type)); | |
if (code) code.node.attributes.content += content; | |
} | |
}); | |
parser.write(content); | |
return root; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment