diff options
Diffstat (limited to 'render.js')
-rw-r--r-- | render.js | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/render.js b/render.js new file mode 100644 index 0000000..e394400 --- /dev/null +++ b/render.js @@ -0,0 +1,172 @@ +'use strict' + +const pug = require('pug') +const marked = require('marked') +const fs = require('fs').promises + +const walk = async (path, filename) => { + const type = await fs.lstat(path) + if (type.isFile()) return {type: 'file', path: path, name: filename || path} + if (!type.isDirectory()) return null + + const files = await fs.readdir(path) + return { + type: 'folder', + path: path, + name: filename || path, + children: await Promise.all(files.map(file => walk(`${path}/${file}`, file))) + } +} + +const ext_static = ['.css', '.js', '.otf', '.png', '.svg', '.txt', 'client', 'server'] +const ext_md = ['.md', '.markdown'] +const ext_pug = ['.pug', '.jade'] + +const suffix = file => ext => file.substring(file.length - ext.length) == ext ? ext : null +const suffixl = (...l) => file => l.find(suffix(file)) +const is_static = suffixl(...ext_static) +const is_md = suffixl(...ext_md) +const is_pug = suffixl(...ext_pug) + +const prefix = file => ext => file.substring(0, ext.length) == ext ? ext : null +const prefixl = (...l) => file => l.find(prefix(file)) + +const rm_prefix = (...l) => file => file.substring(prefixl(...l)(file).length) +const rm_suffix = (...l) => file => file.substring(0, file.length - suffixl(...l)(file).length) + +const propagate_md_layout = (tree, markdown_template) => { + if (tree.type == 'file' && is_md(tree.name)) { + tree.template = markdown_template + } else if (tree.type == 'folder') { + const find_md_tpl = tree.children.filter(c => c.type == 'file' && c.name == '_markdown.pug') + const new_md_tpl = find_md_tpl.length > 0 ? find_md_tpl[0] : markdown_template + tree.children.forEach(c => propagate_md_layout(c, new_md_tpl)) + } + return tree +} + +const elagate_templates = tree => { + if (tree.type != 'folder') return tree + + tree.children = tree.children.filter(e => !(e.type == 'file' && e.name[0] == '_')) + tree.children.forEach(elagate_templates) + return tree +} + +const propagate_nice_name = prefix => tree => { + const without_prefix = tree.path.substring(prefix.length) + const splitted = without_prefix.split('/').filter(v => v.length > 0) + if (splitted.length > 0) { + tree.nice_path = splitted.slice(0, -1) + tree.nice_name = splitted[splitted.length - 1].split('.')[0] + tree.url = without_prefix + } + + if (tree.type == 'folder') tree.children.forEach(propagate_nice_name(prefix)) + return tree +} + +const prepare_copy = (old_prefix, new_prefix, exts) => tree => { + if (tree.type == 'file' && is_static(tree.name)) { + tree.generate = { + cmd: 'copy', + src: tree.path, + out: new_prefix + rm_prefix(old_prefix)(tree.path) + } + } else if (tree.type == 'folder') { + tree.children.forEach(prepare_copy(old_prefix, new_prefix, exts)) + } + return tree +} + +const prepare_pug = (old_prefix, new_prefix) => tree => { + if (tree.type == 'file' && is_pug(tree.name)) { + tree.generate = { + cmd: 'pug', + src: tree.path, + out: new_prefix + rm_prefix(old_prefix)(rm_suffix(...ext_pug)(tree.path)) + '.html' + } + } + else if (tree.type == 'folder') { + tree.children.forEach(prepare_pug(old_prefix, new_prefix)) + } + + return tree +} + +const prepare_md = (old_prefix, new_prefix) => tree => { + if (tree.type == 'file' && is_md(tree.name)) { + tree.generate = { + cmd: 'pug', + src: tree.template.path, + markdown: tree.path, + out: new_prefix + rm_prefix(old_prefix)(rm_suffix(...ext_md)(tree.path)) + '.html' + } + } + else if (tree.type == 'folder') { + tree.children.forEach(prepare_md(old_prefix, new_prefix)) + } + + return tree +} + +const prepare_folder = (old_prefix, new_prefix) => tree => { + if (tree.type == 'folder') { + tree.generate = { + cmd: 'mkdir', + out: new_prefix + rm_prefix(old_prefix)(tree.path) + } + tree.children.forEach(prepare_folder(old_prefix, new_prefix)) + } + + return tree +} + +const do_folder = async tree => { + if (!tree.generate || tree.generate.cmd != 'mkdir') return tree + await fs.mkdir(tree.generate.out, { recursive: true }) + await Promise.all(tree.children.map(do_folder)) + return tree +} + +const do_copy = async tree => { + if (tree.generate && tree.generate.cmd == 'copy') + await fs.copyFile(tree.generate.src, tree.generate.out) + else if (tree.type == 'folder') + await Promise.all(tree.children.map(do_copy)) + + return tree +} + +const do_pug = (prt, root) => async tree => { + prt = prt || tree + root = root || tree + if (tree.generate && tree.generate.cmd == 'pug') { + const html = pug.renderFile(tree.generate.src, { + markdown: tree.generate.markdown ? marked(await fs.readFile(tree.generate.markdown, 'utf-8')) : null, + prt: prt, + root: root, + element: tree + }) + await fs.writeFile(tree.generate.out, html) + } else if (tree.type == 'folder') + await Promise.all(tree.children.map(do_pug(tree,root))) + + return tree +} + + +const conf = { src: './src', dest: './static'} +walk(conf.src) + .then(propagate_md_layout) + .then(elagate_templates) + .then(propagate_nice_name(conf.src)) + .then(prepare_copy(conf.src, conf.dest)) + .then(prepare_pug(conf.src, conf.dest)) + .then(prepare_md(conf.src, conf.dest)) + .then(prepare_folder(conf.src, conf.dest)) + .then(do_folder) + .then(do_copy) + .then(do_pug()) + .then(v => console.log("done")) + .catch(console.error) |