Skip to content

Instantly share code, notes, and snippets.

@rpaul-stripe
Created April 10, 2024 21:46
Show Gist options
  • Save rpaul-stripe/b5e30060a5aa217201c20d25a0331eca to your computer and use it in GitHub Desktop.
Save rpaul-stripe/b5e30060a5aa217201c20d25a0331eca to your computer and use it in GitHub Desktop.
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