import { Marked } from "https://deno.land/x/markdown/mod.ts" /** references a forum post */ type ForumEntry = { forum?: number; topic?: number; post: number; } | number; /** the structure of the front matter */ interface PolicyYFM { name: string; description: string; aliases?: string[]; ignore?: boolean; autoupdate?: { forums?: ForumEntry | ForumEntry[]; wiki?: string | string[]; }; } const decoder = new TextDecoder("utf-8"); const encoder = new TextEncoder(); /** the source of the index page */ const index = { prefix: ` The Mana World Policies
\n
\n\n" }; /** the _redirects file used by netlify */ let _redirects = ""; /** the [routes] portion of the yaml file used by Render */ let render_yaml = ""; /** a map of all generated path aliases */ const routes: Map> = new Map(); console.info(">> Building the static site..."); // empty the build directory await Deno.remove("build", { recursive: true }); // loop through policy files for await (const dirEntry of Deno.readDir("policies")) { const file: string = dirEntry.name; const [shortName, type] = file.split("."); if (type.toLowerCase() !== "md") { console.log(`Unsupported policy file format: ${file}`); continue; } const rawPolicy = decoder.decode(await Deno.readFile(`policies/${file}`)); if (!rawPolicy.trimStart().startsWith("---")) { console.log(`Ignoring policy file with no front matter: ${file}`); continue; } // parse front matter and markdown: const {content: html, meta: YFM} = Marked.parse(rawPolicy); if (Reflect.has(YFM, "ignore") || file.startsWith(".")) { console.log(`Ignoring disabled policy file: ${file}`); continue; } // add to the index page index.list += `
  • ${YFM.name}
  • \n`; // add to the netlify redirect file _redirects += `/${shortName} /${shortName}/index.html 200!\n`; /** a Set of all aliases for this policy */ const aliases: Set = new Set(Reflect.has(YFM, "aliases") ? YFM.aliases : []); /** generates aliases from common path substitutions */ const generateCommonAliases = (path: string) => { const substitutions = [ ["-", "_"], ["_", "-"], ["-"], ["_"], ]; for (const substitution of substitutions) { const replacement = path.replace(substitution[0], substitution[1] ?? ""); aliases.add(replacement); aliases.add(replacement.toLowerCase()); } // lower case aliases.add(path.toLowerCase()); }; // built-in aliases generateCommonAliases(shortName); // process path aliases (and duplicate before iterating) for (const alias of new Set(aliases)) { generateCommonAliases(alias); } // make sure we don't include the article itself in its alias Set aliases.delete(shortName); // add all aliases to the netlify _redirects file and the Render yaml file for (const alias of aliases) { _redirects += `/${alias} /${shortName} 302\n` render_yaml += `- type: redirect\n source: /${alias}\n destination: /${shortName}\n`; } // record the aliases in the global routes map routes.set(shortName, aliases); // wrap the generated html inside our template const policyPage = encoder.encode(` The Mana World – ${YFM.name}
    ${html}
    `.trim()); // create a subdirectory for it await Deno.mkdir(`build/${shortName}`, {recursive: true}); await Deno.writeFile(`build/${shortName}/index.html`, policyPage, {create: true}); await Deno.mkdir(`build/${shortName}/raw`, {recursive: true}); await Deno.writeFile(`build/${shortName}/raw/index.html`, encoder.encode(html), {create: true}); } // write the index page const indexPage = encoder.encode(index.prefix + index.list + index.suffix); await Deno.writeFile("build/index.html", indexPage, {create: true}); // write the _redirects file (netlify) await Deno.writeFile("build/_redirects", encoder.encode(_redirects), {create: true}); // write the render.yaml file (render) await Deno.writeFile("build/render.yaml", encoder.encode(render_yaml), {create: true}); // write the routes.json file (generic) const routes_obj: any = {}; for (const [route, aliases] of routes) { routes_obj[route] = [...aliases]; // convert the Map } await Deno.writeFile("build/routes.json", encoder.encode(JSON.stringify(routes_obj)), {create: true}); // copy static assets for await (const dirEntry of Deno.readDir("src/static")) { await Deno.copyFile(`src/static/${dirEntry.name}`, `build/${dirEntry.name}`,); } console.info(">> Build success ✅");