-
-
Save f-space/57baa35d8bd83602e9e8bc19a9c8a091 to your computer and use it in GitHub Desktop.
Deno script to convert Markdown to RPG Maker forum format
This file contains 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
// Command: | |
// $ deno run --allow-read --allow-write md2rmbb.ts source.md | |
// License: | |
// CC0 (https://creativecommons.org/publicdomain/zero/1.0/) | |
import { Marked, Renderer } from "https://deno.land/x/markdown@v2.0.0/mod.ts"; | |
import { parse } from "https://deno.land/std@0.88.0/flags/mod.ts"; | |
import { | |
basename, | |
dirname, | |
resolve, | |
} from "https://deno.land/std@0.88.0/path/mod.ts"; | |
const BB = (() => { | |
const tag = (name: string, attrs: readonly string[], body: string) => { | |
const option = attrs.length !== 0 ? `=${attrs.join(",")}` : ""; | |
return `[${name}${option}]${body}[/${name}]`; | |
}; | |
const bold = (body: string) => tag("B", [], body); | |
const italic = (body: string) => tag("I", [], body); | |
const underline = (body: string) => tag("U", [], body); | |
const strike = (body: string) => tag("S", [], body); | |
const color = (color: string, body: string) => tag("COLOR", [color], body); | |
const font = (name: string, body: string) => tag("FONT", [name], body); | |
const size = (size: string, body: string) => tag("SIZE", [size], body); | |
const url = (link: string, body: string) => | |
tag("URL", link ? [link] : [], body); | |
const email = (address: string, body: string) => | |
tag("EMAIL", address ? [address] : [], body); | |
const user = (id: string, body: string) => tag("USER", [id], body); | |
const img = (body: string) => tag("IMG", [], body); | |
const media = (site: string, body: string) => tag("MEDIA", [site], body); | |
const list = (ordered: boolean, body: string) => | |
tag("LIST", ordered ? ["1"] : [], body); | |
const item = (body: string) => `[*] ${body}`; | |
const left = (body: string) => tag("LEFT", [], body); | |
const center = (body: string) => tag("CENTER", [], body); | |
const right = (body: string) => tag("RIGHT", [], body); | |
const quote = (person: string, body: string) => | |
tag("QUOTE", person ? [person] : [], body); | |
const spoiler = (title: string, body: string) => | |
tag("SPOILER", title ? [title] : [], body); | |
const ispoiler = (body: string) => tag("ISPOILER", [], body); | |
const code = (lang: string, body: string) => | |
tag("CODE", lang ? [lang] : [], body); | |
const icode = (body: string) => tag("ICODE", [], body); | |
const indent = (body: string) => tag("INDENT", [], body); | |
const table = (body: string) => tag("TABLE", [], body); | |
const tr = (body: string) => tag("TR", [], body); | |
const th = (body: string) => tag("TH", [], body); | |
const td = (body: string) => tag("TD", [], body); | |
const heading = (level: number, body: string) => | |
tag("HEADING", [String(level)], body); | |
const plain = (body: string) => tag("PLAIN", [], body); | |
const hr = () => tag("HR", [], ""); | |
return { | |
bold, | |
italic, | |
underline, | |
strike, | |
color, | |
font, | |
size, | |
url, | |
email, | |
user, | |
img, | |
media, | |
list, | |
item, | |
left, | |
center, | |
right, | |
quote, | |
spoiler, | |
ispoiler, | |
code, | |
icode, | |
indent, | |
table, | |
tr, | |
th, | |
td, | |
heading, | |
plain, | |
hr, | |
}; | |
})(); | |
class ForumRenderer extends Renderer { | |
text(text: string) { | |
return text; | |
} | |
br() { | |
return "\n"; | |
} | |
strong(text: string) { | |
return BB.bold(text); | |
} | |
em(text: string) { | |
return BB.italic(text); | |
} | |
del(text: string) { | |
return BB.strike(text); | |
} | |
link(href: string, _title: string, text: string) { | |
return BB.url(href, text); | |
} | |
image(href: string, _title: string, _text: string) { | |
return BB.img(href); | |
} | |
codespan(text: string) { | |
return BB.icode(text); | |
} | |
heading(text: string, level: number) { | |
if (level <= 3) { | |
return `${BB.heading(level, text)}\n`; | |
} else { | |
throw new Error(`h${level} not supported`); | |
} | |
} | |
paragraph(text: string) { | |
return /^\s*$/.test(text) ? "" : `${text.replace(/\n/g, "")}\n\n`; | |
} | |
list(body: string, ordered?: boolean) { | |
return `${BB.list(ordered ?? false, `\n${body}`)}\n\n`; | |
} | |
listitem(text: string) { | |
return `${BB.item(text)}\n`; | |
} | |
table(header: string, body: string) { | |
return `${BB.table(`\n${header}\n${body}`)}\n\n`; | |
} | |
tablerow(content: string) { | |
return `${BB.tr(content)}\n`; | |
} | |
tablecell( | |
content: string, | |
flags: { header?: boolean; align?: "center" | "left" | "right" }, | |
) { | |
const align = (content: string, align?: "center" | "left" | "right") => { | |
switch (align) { | |
case undefined: | |
return content; | |
case "center": | |
return BB.center(content); | |
case "left": | |
return BB.left(content); | |
case "right": | |
return BB.right(content); | |
default: | |
throw new Error(`align '${align}' not supported`); | |
} | |
}; | |
const body = align(content, flags.align); | |
return flags.header ? BB.th(body) : BB.td(body); | |
} | |
blockquote(quote: string) { | |
return `${BB.quote("", quote)}\n\n`; | |
} | |
code(code: string, lang?: string) { | |
return `${BB.code(lang ?? "", code)}\n\n`; | |
} | |
html(text: string) { | |
if (/^\s*<!--.*-->\s*$/.test(text)) { | |
return ""; | |
} else { | |
throw new Error("html not supported"); | |
} | |
} | |
hr() { | |
return BB.hr(); | |
} | |
} | |
Marked.setOptions({ | |
renderer: new ForumRenderer(), | |
escape: (s) => s, | |
}); | |
const { _: args } = parse(Deno.args); | |
const src = String(args[0]); | |
const dst = resolve(dirname(src), basename(src, ".md") + ".txt"); | |
const decoder = new TextDecoder(); | |
const encoder = new TextEncoder(); | |
const input = await Deno.readFile(src); | |
const markdown = decoder.decode(input); | |
const result = Marked.parse(markdown); | |
const output = encoder.encode(result.content); | |
await Deno.writeFile(dst, output); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment