gmi-web/to-html.js

83 lines
2.5 KiB
JavaScript
Raw Normal View History

2021-01-29 06:15:23 +00:00
const fs = require("fs");
const path = require("path");
2021-01-28 23:07:57 +00:00
const TOKENS_EXT = /\.tokens\.json$/;
2021-01-29 00:24:22 +00:00
// https://developer.mozilla.org/en-US/docs/Web/Media/Formats
const IMG_EXT = /\.(apng|avif|gif|jpg|jpeg|jfif|pjpeg|pjp|png|svg|webp)$/;
const AUDIO_EXT = /\.(mp3|wav|aac|aacp|mpeg|off|flac)$/;
const VIDEO_EXT = /\.(mp4|webm)$/;
module.exports = (options) => (file, cb) => {
2021-01-29 06:15:23 +00:00
if (!TOKENS_EXT.test(file.path)) return cb(null);
2021-01-29 00:24:22 +00:00
2021-01-29 06:15:23 +00:00
// TODO: meta: language, description, canonical
2021-01-28 23:07:57 +00:00
file.contents = Buffer.from(`<!DOCTYPE html>
<html>
<meta charset="utf-8">
2021-01-28 23:13:02 +00:00
<meta name="viewport" content="width=device-width,initial-scale=1">${
2021-01-29 00:24:22 +00:00
options.css
2021-01-29 06:15:23 +00:00
? `\n<meta name="color-scheme" content="dark light">\n<style>${fs.readFileSync(
path.resolve(__dirname, "./gmi.min.css"),
"utf8"
)}</style>`
2021-01-29 06:48:39 +00:00
: "a, audio {display: block;}"
2021-01-28 23:13:02 +00:00
}
2021-01-28 23:07:57 +00:00
<body>
2021-01-29 00:24:22 +00:00
${toHTML(JSON.parse(file.contents.toString("utf8")), options)}
2021-01-28 23:07:57 +00:00
</body>
</html>
`);
2021-01-29 00:24:22 +00:00
file.path = file.path.replace(TOKENS_EXT, ".html");
2021-01-29 06:15:23 +00:00
if (!options.silent) console.log(file.path);
2021-01-28 23:07:57 +00:00
return cb(null, file);
};
2021-01-29 00:24:22 +00:00
function toHTML(tokens, options) {
2021-01-28 23:13:02 +00:00
let body = [];
2021-01-28 23:07:57 +00:00
2021-01-28 23:13:02 +00:00
let cursor = tokens.shift();
2021-01-28 23:07:57 +00:00
while (tokens.length) {
if (cursor.pre) {
2021-01-28 23:13:02 +00:00
body.push(`<pre${cursor.alt ? `title="${cursor.alt}"` : ""}>`);
const closing = tokens.findIndex((token) => token.pre);
body = body.concat(tokens.slice(0, closing).map(({ text }) => text));
body.push("</pre>");
tokens = tokens.slice(closing + 1);
2021-01-28 23:07:57 +00:00
}
if (cursor.li) {
2021-01-28 23:13:02 +00:00
body.push(`<ul>`);
const closing = tokens.findIndex((token) => !token.li);
body = body.concat(tokens.slice(0, closing).map(line));
body.push("</ul>");
tokens = tokens.slice(closing + 1);
2021-01-28 23:07:57 +00:00
}
2021-01-29 00:24:22 +00:00
body.push(line(cursor, options));
2021-01-28 23:13:02 +00:00
cursor = tokens.shift();
2021-01-28 23:07:57 +00:00
}
2021-01-28 23:13:02 +00:00
return body.join("\n");
2021-01-28 23:07:57 +00:00
}
2021-01-29 00:24:22 +00:00
function line(
{ text, href, title, pre, alt, h1, h2, h3, li, quote },
{ inline }
) {
2021-01-28 23:07:57 +00:00
if (text) return `<p>${text}</p>`;
2021-01-29 00:24:22 +00:00
if (href) {
if (inline.images && IMG_EXT.test(href))
return `<img src="${href}" title="${title}"/>`;
if (inline.audio && AUDIO_EXT.test(href))
return `<audio controls src="${href}" title="${title}"></audio>`;
if (inline.video && VIDEO_EXT.test(href))
return `<video controls src="${href}" title="${title}"/></video>`;
return `<a href="${href}">${title || href}</a>`;
}
2021-01-28 23:07:57 +00:00
if (h1) return `<h1>${h1}</h1>`;
if (h2) return `<h2>${h2}</h2>`;
if (h3) return `<h3>${h3}</h3>`;
if (li) return `<li>${li}</li>`;
if (quote) return `<blockquote>${quote}</blockquote>`;
return `<p><br></p>`;
}