import showdown from "showdown"; import yaml from "yaml"; import { promises as fs } from "fs"; 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]; } declare interface PostMetadata { name: string; unlisted?: boolean; tags?: Array; description?: string; } declare interface PostEntry { name: string; id: string; description: string | null; } const baseTemplate = await fs.readFile("template.html", { encoding: "utf-8" }); class PostCollector { allPosts: PostEntry[] = []; 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}`, ); } async run() { await fs.rm("build", { recursive: true }); await fs.mkdir("build"); await fs.mkdir("build/posts"); const posts = await fs.readdir("posts"); for (let postPath of posts) { const totalPostPath = `posts/${postPath}`; if (!postPath.endsWith(".md")) { await fs.copyFile(totalPostPath, `build/posts/${postPath}`); continue; } const postId = postPath.replace(".md", ""); const postText = await fs.readFile(totalPostPath, { encoding: "utf-8" }); const [postHeader, postBody] = splitPostHeader(postText); const postMetadata = yaml.parse(postHeader) as PostMetadata; const postHtml = this.makeHtmlForPost(postMetadata, postBody); const targetPath = `build/posts/${postId}.html`; await fs.writeFile(targetPath, postHtml, { encoding: "utf-8" }); if (!postMetadata.unlisted) this.allPosts.push({ name: postMetadata.name, id: postId, description: postMetadata.description ?? null, }); } await fs.writeFile( "build/posts/index.html", this.makeHtmlForPost( { name: "Post Index" }, "# Post List\n" + this.allPosts .map( (post) => `## [${post.name}](./${post.id}.html)\n\n${post.description ?? ""}`, ) .join("\n"), ), { encoding: "utf-8" }, ); } } await new PostCollector().run();