import showdown from "showdown"; import yaml from "yaml"; import { promises as fs } from "fs"; const posts = await fs.readdir("posts"); function splitPostHeader(postData: string): [string, string] { if (postData.startsWith("---\n")) { const headerEndIndex = postData.indexOf("\n---\n", 4); return [ postData.substring(4, headerEndIndex), postData.substring(headerEndIndex + 5), ]; } return ["", postData]; } await fs.rm("build", { recursive: true }); await fs.mkdir("build"); declare interface PostMetadata { name: string; unlisted?: boolean; tags?: Array; description?: string; } const baseTemplate = await fs.readFile("template.html", { encoding: "utf-8" }); function makeHtmlForPost(postMetadata: PostMetadata, markdown: string): string { const converter = new showdown.Converter(); const htmlPostBody = converter.makeHtml(markdown); const variables = { postBody: htmlPostBody, title: postMetadata.name, }; return baseTemplate.replace( /%([a-zA-Z]+)%/g, (_, match) => variables[match] ?? `Missing variable: ${match}`, ); } for (let postPath of posts) { const totalPostPath = `posts/${postPath}`; if (!postPath.endsWith(".md")) { await fs.copyFile(totalPostPath, `build/${postPath}`); continue; } const postText = await fs.readFile(totalPostPath, { encoding: "utf-8" }); const [postHeader, postBody] = splitPostHeader(postText); const postMetadata = yaml.parse(postHeader) as PostMetadata; const postHtml = makeHtmlForPost(postMetadata, postBody); const targetPath = `build/${postPath.replace(".md", ".html")}`; fs.writeFile(targetPath, postHtml, { encoding: "utf-8" }); }