aboutsummaryrefslogblamecommitdiff
path: root/render.js
blob: 8fb7545002fc9bf754d7e2b243a411824546638b (plain) (tree)
1
2
3
4
5
6
7
8
9





                                 


                                                    
                                        
                     





















                                                                                          
                                                     







                                                                                               
                                                       
                                     
                                                                                                            







                                                                                                
                         
                                        



                                                                         









                                                                      
                                                                               












                                                                               
                                                                  












                                                                                         
                                                                 















                                                                                        
                                                                                           













                                                             
                                             








                                                                 
                                      




                                                 
                                                      
                                                           

                                      















                                                                                                           
                                     









                                                           
                







                                            
                       
'use strict'

const pug = require('pug')
const marked = require('marked')
const fs = require('fs').promises

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}
  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 is_templated = f => is_md(f) /* || is_rst(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('[elegate]', e.path) && false
  tree.children = tree.children.filter(e => !(e.name[0] == '_') || lh(e))
  tree.children.forEach(elagate)
  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.generate = {
      cmd: 'pug',
      src: tree.path,
      out: new_prefix + rm_prefix(old_prefix)(rm_suffix(...ext_pug)(tree.path)) + '.html'
    }
    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.generate = {
      cmd: 'pug',
      src: tree.template.path,
      markdown: tree.path,
      out: new_prefix + rm_prefix(old_prefix)(rm_suffix(...ext_md)(tree.path)) + '.html'
    }
    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,
      prt: prt,
      root: root,
      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 conf = { src: './src', dest: './static'}
walk(conf.src)
  .then(propagate_md_layout)
  .then(elagate)
  .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())
  .catch(console.error)