как же мы раньше без этой прелести жили
const fs = require('fs')
const path = require('path')
let rootDir = path.join(__dirname, '..')
// [url]https://github.com/nervgh/koa-architect[/url]
exports.get = {
'index': async function (ctx) {
ctx.state.root = await readRoutesRecursive(rootDir, new Node('', 'admin'))
ctx.render(__dirname, 'views/index')
}
}
// TODO: Should we move this code to a standalone package?
class Node {
/**
* @param {String} prefix
* @param {String} name
*/
constructor(prefix, name) {
this.name = name
this.path = `${prefix}/${name}`
this.children = []
}
/**
* @return {Object}
*/
toJSON() {
return Object.assign({}, this)
}
}
/**
* A few promisified fs methods
* @type {Object}
*/
const fsp = {
lstat: promisify(fs.lstat),
readdir: promisify(fs.readdir)
}
/**
* @param {String} dir
* @param {Node} node
* @return {Promise.<Node>}
*/
async function readRoutesRecursive(dir, node) {
for(let name of await fsp.readdir(dir)) {
if (await isDirectory(path.join(dir, name))) {
let tryMiddleware = path.join(dir, name, 'middleware')
if (await isDirectory(tryMiddleware)) {
node.children.push(await readRoutesRecursive(tryMiddleware, new Node(node.path, name)))
} else {
node.children.push(new Node(node.path, name))
}
}
}
return node
}
/**
* @param {String} pathString
* @return {Promise.<Boolean>}
*/
async function isDirectory(pathString) {
try {
let stat = await fsp.lstat(pathString)
return stat.isDirectory()
} catch (err) {
return false
}
}
/**
* @param {Function} fn
* @param {*} ctx
* @return {Function}
*/
function promisify(fn, ctx) {
return (...args) => {
return new Promise((resolve, reject) => {
args.push((err, data) => err ? reject(err) : resolve(data))
fn.apply(ctx, args)
})
}
}