ufh/docs/render.ts

70 lines
1.7 KiB
TypeScript

import * as marked from "npm:marked";
if (!Deno.args[0]) throw new Error("needs a file as cli arg");
const filename = Deno.args[0];
const input = Deno.readTextFileSync(filename);
const rendered = marked.lexer(input).map(renderBlock).filter(i => i);
console.log(JSON.stringify({ doc: rendered, name: filename }));
// console.log(rendered);
interface Token {
type: string,
text: string,
tokens?: Array<Token>,
[key: string]: any,
}
function renderBlock(token: Token): any {
switch (token.type) {
case "paragraph": {
return renderInline(token);
}
case "heading": {
return { type: "header", level: token.depth, content: renderInline(token) };
}
case "list": {
return {
type: token.ordered ? "ol" : "ul",
items: token.items.map(i => {
if (i.tokens.length === 1) renderBlock(i.tokens[0]);
return i.tokens.map(renderBlock);
}),
};
}
case "code": {
return {
type: "code",
lang: token.lang,
content: renderInline(token),
};
}
case "space": {
return null;
}
case "text": {
return renderInline(token);
}
case "table": {
return {
type: "table",
headers: token.header.map(renderInline),
rows: token.rows.map(row => row.map(renderInline)),
}
}
default: {
return token;
}
}
}
function renderInline(token: Token): string {
const text = token.tokens ? token.tokens.map(renderInline).join("") : token.text;
switch (token.type) {
case "em": return `~italic{${text}}`;
case "strong": return `~bold{${text}}`;
case "link": return `~link{${text}}{${token.href}}`;
case "codespan": return `~code{${text}}`;
default: return `${text}`;
}
}