Created
April 10, 2024 21:46
-
-
Save rpaul-stripe/b5e30060a5aa217201c20d25a0331eca to your computer and use it in GitHub Desktop.
This file contains hidden or 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