summaryrefslogtreecommitdiff
path: root/src/build.ts
blob: 94022dce7a8246743fe262ca6d571d24b86fc25a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import { Marked } from "https://deno.land/x/markdown/mod.ts"
import * as yaml from "https://deno.land/x/js_yaml_port/js-yaml.js"

// the structure of the front matter
interface PolicyYFM {
	name: string
	description: string;
	aliases?: string[];
	ignore?: boolean;
}

const decoder = new TextDecoder("utf-8");
const encoder = new TextEncoder();

const index = {
	prefix: `
<!doctype html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>The Mana World Policies</title>
	<meta name="description" content="Active policies on The Mana World">
	<link rel="stylesheet" href="style.css">
	<link rel="canonical" href="https://policies.themanaworld.org/">
</head>
<body>
<main>
<nav>
<h1>TMW Policies</h1>
<ul>
`.trim(), list: "", suffix: "</ul>\n</nav>\n</main>\n</body>\n</html>"
};

// the _redirects file used by netlify
let redirects = "";

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 = dirEntry.name;
	const rawPolicy = decoder.decode(await Deno.readFile(`policies/${file}`));

	if (!rawPolicy.trimStart().startsWith("---")) {
		console.log(`Ignoring policy file with no front matter: ${file}`);
		continue;
	}

	// find the closing tag
	const endFrontMatter = rawPolicy.slice(3).indexOf("---");

	if (endFrontMatter === -1) {
		throw new SyntaxError(`Couldn't find end of front matter in ${file}`);
	}

	// mark the boundaries
	const rawYAML = rawPolicy.slice(3, endFrontMatter + 3).trim();
	const rawBody = rawPolicy.slice(3 + endFrontMatter + 3).trim();

	const [shortName, type] = file.split(".");

	if (type.toLowerCase() !== "md") {
		console.log(`Unsupported policy file format: ${file}`);
		continue;
	}

	// parse the front matter as yaml
	const YFM: PolicyYFM = yaml.safeLoad(rawYAML, {filename: file});

	if (Reflect.has(YFM, "ignore") || file.startsWith(".")) {
		console.log(`Ignoring disabled policy file: ${file}`);
		continue;
	}

	// add to the index page
	index.list += `<li><a href="/${shortName}" title="${YFM.description}" aria-label="${YFM.description}">${YFM.name}</a></li>\n`;

	// add to the netlify redirect file
	redirects += `/${shortName} /${shortName}/index.html 200!\n`;
	
	// built-in aliases
	if (shortName != shortName.replace("-", "_")) {
		redirects += `/${shortName.replace("-", "_")} /${shortName} 302\n`;
	} if (shortName != shortName.replace("-", "")) {
		redirects += `/${shortName.replace("-", "")} /${shortName} 302\n`;
	}
	
	// process path aliases
	if (Reflect.has(YFM, "aliases")) {
		for (const alias of YFM.aliases as string[]) {
			redirects += `/${alias} /${shortName} 302\n`;

			if (alias != alias.toLowerCase()) {
				redirects += `/${alias.toLocaleLowerCase()} /${shortName} 302\n`;
			}
		}
	}

	// convert from markdown to html
	const html: string = Marked.parse(rawBody);

	// wrap the generated html inside our template
	const policyPage = encoder.encode(`
<!doctype html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>The Mana World – ${YFM.name}</title>
	<meta name="description" content="${YFM.description}">
	<link rel="stylesheet" href="../style.css">
	<link rel="canonical" href="https://policies.themanaworld.org/${shortName}">
</head>
<body>
<article>
${html}
</article>
<footer>Copyright &copy The Mana World &mdash; Generated on ${(new Date()).toISOString()}</footer>
</body>
</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});

// 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 ✅");