gallery.badmanners.xyz/src/utils/markdown_to_bbcode.ts

89 lines
2.7 KiB
TypeScript

import { Marked, type RendererObject } from "marked";
import { decode } from "tiny-decode";
import { parsePartialHTMLTag } from "./parse_partial_html_tag";
const renderer: RendererObject = {
code({ text }) {
return `\n[code]${text}[/code]\n`;
},
blockquote({ tokens }) {
return `\n[quote]${this.parser.parseInline(tokens)}[/quote]\n`;
},
html(token) {
const { type, raw } = token;
if (type === "html") {
const tag = parsePartialHTMLTag(raw);
switch (tag.tag) {
case "a":
if (tag.type === "open") {
if (tag.attributes?.href) {
return `[url=${tag.attributes.href}]`;
}
} else if (tag.type === "close") {
return "[/url]";
}
console.error("ERROR: unhandled anchor in markdownToBbcode.html", token, tag);
throw new Error("Unhandled anchor HTML token in BBCode renderer");
}
}
console.error("ERROR: unhandled token in markdownToBbcode.html", token);
throw new Error("Unknown HTML token not supported by BBCode renderer");
},
heading({ tokens }) {
return `\n${this.parser.parseInline(tokens)}\n`;
},
hr() {
return `\n===\n`;
},
list({ ordered, items }) {
const tag = ordered ? "ol" : "ul";
return `\n[${tag}]\n${items.map(this.listitem).join("\n")}[/${tag}]\n`;
},
listitem({ tokens }) {
return `[li]${this.parser.parseInline(tokens)}[/li]\n`;
},
checkbox(token) {
console.error("ERROR: unhandled token in markdownToBbcode.checkbox", token);
throw new Error("Not supported by BBCode: checkbox");
},
paragraph({ tokens }) {
return `\n${this.parser.parseInline(tokens)}\n`;
},
table({ header, rows }) {
return `\n[table]\n${this.tablerow({ text: header.map(this.tablecell).join("\n") })}\n${rows
.map((row) => this.tablerow({ text: row.map(this.tablecell).join("\n") }))
.join("\n")}[/table]\n`;
},
tablerow({ text }) {
return `[tr]\n${text}[/tr]\n`;
},
tablecell({ header, tokens }) {
const tag = header ? "th" : "td";
return `[${tag}]${this.parser.parseInline(tokens)}[/${tag}]\n`;
},
strong({ tokens }) {
return `[b]${this.parser.parseInline(tokens)}[/b]`;
},
em({ tokens }) {
return `[i]${this.parser.parseInline(tokens)}[/i]`;
},
codespan({ text }) {
return text;
},
br() {
return "\n\n";
},
del({ tokens }) {
return `[s]${this.parser.parseInline(tokens)}[/s]`;
},
link({ href, tokens }) {
return `[url=${href}]${this.parser.parseInline(tokens)}[/url]`;
},
image({ href }) {
return `[img]${href}[/img]`;
},
};
const bbcodeRenderer = new Marked({ renderer, async: false });
export const markdownToBbcode = (text: string) => decode(bbcodeRenderer.parse(text, { async: false }).trim());