264 lines
8 KiB
JavaScript
264 lines
8 KiB
JavaScript
'use strict'
|
|
|
|
const pug = require('pug')
|
|
const marked = require('marked')
|
|
const fs = require('fs').promises
|
|
const http = require('http')
|
|
|
|
const unit = (...args) => null
|
|
const log = process.env.VERBOSE ? console.log : unit
|
|
|
|
const walk = async (path, filename) => {
|
|
log('[walk]', path)
|
|
const type = await fs.lstat(path)
|
|
if (type.isFile()) return {type: 'file', path: path, name: filename || path, tags:[]}
|
|
if (!type.isDirectory()) return null
|
|
|
|
const files = await fs.readdir(path)
|
|
return {
|
|
type: 'folder',
|
|
path: path,
|
|
name: filename || path,
|
|
tags: [],
|
|
children: await Promise.all(files.map(file => walk(`${path}/${file}`, file)))
|
|
}
|
|
}
|
|
|
|
const ext_static = ['.css', '.js', '.otf', '.png', '.svg', '.txt', '.png', '.jpg', '.webp', 'client', 'server', '.pdf', '.ttf']
|
|
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 is_templated = f => is_md(f) /* || is_rst(f) */
|
|
const is_document = f => is_templated(f) || is_pug(f)
|
|
|
|
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_templated(tree.name)) {
|
|
tree.template = markdown_template
|
|
log('[propagate_md_layout]', tree ? tree.path : null, markdown_template ? markdown_template.path : null)
|
|
} 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 = tree => {
|
|
if (tree.type != 'folder') return tree
|
|
|
|
const lh = e => log('[elagate]', e.path) && false
|
|
tree.children = tree.children.filter(e => !(e.name[0] == '_') || lh(e))
|
|
tree.children.forEach(elagate)
|
|
return tree
|
|
}
|
|
|
|
const tag_document = tree => {
|
|
if (tree.type == 'file' && is_document(tree.name) && tree.name[0] != '@') {
|
|
tree.tags.push('document_leaf', 'document')
|
|
log('[tag_document]', tree.path, 'document_leaf')
|
|
} else if (tree.type == 'folder') {
|
|
tree.children.forEach(tag_document)
|
|
if(tree.children.some(c => c.tags.includes('document'))) {
|
|
tree.tags.push('document_branch', 'document')
|
|
log('[tag_document]', tree.path, 'document_branch')
|
|
}
|
|
}
|
|
return tree
|
|
}
|
|
|
|
const reference_index = indexes => tree => {
|
|
if (tree.type != 'folder') return tree;
|
|
|
|
const index = tree.children.find(e => indexes.includes(e.name))
|
|
if (index) {
|
|
tree.index = index
|
|
tree.tags.push('has_index')
|
|
log('[reference_index]', tree.path, index.name)
|
|
index.tags.push('is_index')
|
|
}
|
|
tree.children.forEach(reference_index(indexes))
|
|
|
|
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
|
|
log('[propagate_nice_name]', [...tree.nice_path, tree.nice_name].join('|'))
|
|
}
|
|
|
|
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)
|
|
}
|
|
log('[prepare_copy]',tree.generate.src,'->',tree.generate.out)
|
|
} 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.old_url = tree.url
|
|
tree.url = rm_prefix(old_prefix)(rm_suffix(...ext_pug)(tree.path)) + '.html'
|
|
tree.generate = {
|
|
cmd: 'pug',
|
|
src: tree.path,
|
|
out: new_prefix + tree.url
|
|
}
|
|
log('[prepare_pug]',tree.generate.src,'->',tree.generate.out)
|
|
}
|
|
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.old_url = tree.url
|
|
tree.url = rm_prefix(old_prefix)(rm_suffix(...ext_md)(tree.path)) + '.html'
|
|
tree.generate = {
|
|
cmd: 'pug',
|
|
src: tree.template.path,
|
|
markdown: tree.path,
|
|
out: new_prefix + tree.url
|
|
}
|
|
log('[prepare_md]',tree.generate.markdown,'+',tree.generate.src,'->',tree.generate.out)
|
|
}
|
|
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)
|
|
}
|
|
log('[prepare_folder]',tree.generate.out)
|
|
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 })
|
|
log('[do_folder]',tree.generate.out)
|
|
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)
|
|
log('[do_copy]',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,
|
|
root: root,
|
|
prt: prt,
|
|
element: tree
|
|
})
|
|
await fs.writeFile(tree.generate.out, html)
|
|
log('[do_pug]',tree.generate.out)
|
|
} else if (tree.type == 'folder')
|
|
await Promise.all(tree.children.map(do_pug(tree,root)))
|
|
|
|
return tree
|
|
}
|
|
|
|
const rm_tree = t => {
|
|
if (t == null) return
|
|
if (t.type == 'file') {
|
|
log('[do_clean] file', t.path)
|
|
return fs.unlink(t.path)
|
|
}
|
|
|
|
return Promise
|
|
.all(t.children.map(rm_tree))
|
|
.then(_ => {
|
|
log('[do_clean] path', t.path)
|
|
return fs.rmdir(t.path)
|
|
})
|
|
}
|
|
|
|
const do_clean = path => tree =>
|
|
walk(path)
|
|
.catch(_ => null)
|
|
.then(rm_tree)
|
|
.then(_ => tree)
|
|
|
|
const listen = async t =>
|
|
process.env.LISTEN &&
|
|
http.createServer(async (req,res) => {
|
|
const file = fs.readFile(__dirname + '/static/' + decodeURI(req.url))
|
|
.catch(_ => fs.readFile(__dirname + '/static/' + decodeURI(req.url) + '/index.html'))
|
|
|
|
try {
|
|
const f = await file
|
|
res.writeHead(200)
|
|
res.end(f)
|
|
} catch (e) {
|
|
console.error(e)
|
|
res.writeHead(404)
|
|
res.end("404 not found")
|
|
}
|
|
}).listen(process.env.LISTEN);
|
|
|
|
const conf = { src: './src', dest: './static'}
|
|
walk(conf.src)
|
|
.then(propagate_md_layout)
|
|
.then(elagate)
|
|
.then(tag_document)
|
|
.then(reference_index(['index.md', 'index.pug']))
|
|
.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(v => {log(v) ; return v})
|
|
.then(do_clean(conf.dest))
|
|
.then(do_folder)
|
|
.then(do_copy)
|
|
.then(do_pug())
|
|
.then(listen)
|
|
.catch(console.error)
|