89 lines
2.7 KiB
TypeScript
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());
|