const fs = require('fs'); const path = require('path'); const showdown = require('showdown'); const frontmatter = require('front-matter'); const converter = new showdown.Converter(); // Pages to process const dir = 'src/pages'; // Where to put them const distDir = 'dist' // Required meta const requiredMeta = ['title'] // Actual processing function run() { if (!fs.existsSync(distDir)) fs.mkdirSync(distDir); getPages().forEach((page) => { const dirPath = path.join(distDir, page.path); if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath); fs.writeFileSync(path.join(dirPath, 'index.html'), buildTemplate(page.title, page.body)) }); } // Generic template const template = fs.readFileSync(path.join('src', 'pages.html')).toString(); // Inject the title and body function buildTemplate(title, body) { return template .replace('{{title}}', title) .replace('{{body}}', body) } // Validate a page's metadata function validateMeta(meta) { const attr = meta.attributes; let errs = []; requiredMeta.forEach((required) => { if (!(required in attr)) errs.push(`missing ${required}`); }); return errs } // Module stuff class Page { constructor(title, path, body, file) { this.title = title; this.path = path; this.body = body; this.file = file; } } function getPages() { const pages = []; fs.readdirSync(dir).forEach((file) => { const filePath = path.join(dir, file) const contents = fs.readFileSync(filePath); const meta = frontmatter(contents.toString()) const errs = validateMeta(meta); if (errs.length) throw `Errors in ${file}:\n${errs.join('\n')}`; const body = converter.makeHtml(meta.body); pages.push(new Page(meta.attributes.title, 'path' in meta.attributes ? meta.attributes.path : path.basename(file), body, file)); }); return pages; } module.exports = { getPages }; // Run the h*ckin' thing if (require.main === module) { run(); }