Skip to content

Instantly share code, notes, and snippets.

@stevenkaspar
Last active September 22, 2017 20:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevenkaspar/9702bee7d1530e628ac383edf47da753 to your computer and use it in GitHub Desktop.
Save stevenkaspar/9702bee7d1530e628ac383edf47da753 to your computer and use it in GitHub Desktop.
'use strict';
const gulp = require('gulp');
const shell = require('gulp-shell')
const spawn = require('child_process').spawn;
const fs = require('fs');
const mkdirp = require('mkdirp');
const pug = require('pug');
const marked = require('marked');
const path = require('path');
const site_base = `${__dirname}/_site`;
const templates_base = `${site_base}/_templates`;
const required_config = [
{
key: 'slug',
type: 'string'
},
{
key: 'title',
type: 'string'
},
{
key: 'template',
type: 'string'
}
];
const walk_filters = [
'_templates',
'private'
];
const base_locals = {
header_links: {
'Home': __dirname + '/index.html',
'About': __dirname + '/about.html'
},
stylesheet: __dirname + '/dist/app.css'
}
let validateConfig = config => {
for(let required_key of required_config){
if(!config[required_key.key] || typeof config[required_key.key] !== required_key.type){
throw new Error(`Config Error => ${required_key.key} is required and needs to be type ${required_key.type}`);
}
}
}
// parses a file with its expected config
let parseFile = file_path => {
// read contents
const contents = fs.readFileSync(file_path, 'utf8');
// parse contents
const match = /^---{(.|\n)+^}---$/mg.exec(contents);
if(match === null){
throw new Error(`Post config not found for ${file_path}`);
}
try {
// get config that should be in valid JSON format
const config = JSON.parse(match[0].substring(3, match[0].length - 3));
validateConfig(config);
// everything after the JSON config is the content of the file
const content = contents.substring(match[0].length);
return {
config: config,
content: {
md: content,
html: marked(content)
}
};
}
catch(e){
console.warn(`${file_path} => ${e.message}`);
console.warn('This is most likely an error in your JSON config at the top of your file');
console.warn(match[0]);
}
return null;
}
let createDestStructure = (root, structure, locals) => {
for(let dir_name in structure.children){
const dir_path = `${root}/${dir_name}`;
// create the directory
mkdirp.sync(dir_path);
createDestStructure(`${dir_path}`, structure.children[dir_name], locals);
}
// for each file we need to write the file in its final HTML form
for(let file of structure.files){
const fn = pug.compileFile(`${templates_base}/${file.config.template}`, {
pretty: true
});
// compile all pages with the same locals so that we can use pug extends properly
const compiled_page = fn(Object.assign({}, file, locals));
// finally write the file in it's fully compiled HTML format
fs.writeFileSync(`${root}/${file.config.slug}.html`, compiled_page, 'utf8');
}
}
let createPugDestStructure = (root, structure, locals) => {
for(let dir_name in structure.children){
const dir_path = `${root}/${dir_name}`;
// create the directory
mkdirp.sync(dir_path);
createPugDestStructure(`${dir_path}`, structure.children[dir_name], locals);
}
// for each file we need to write the file in its final HTML form
for(let file_path of structure.files){
const fn = pug.compileFile(file_path, {
pretty: true
});
const compiled_page = fn(locals);
fs.writeFileSync(`${root}/${path.basename(file_path, '.pug')}.html`, compiled_page, 'utf8');
}
}
let getStructBit = () => {
return {
children: {},
files: []
}
}
gulp.task('build-site-pages', done => {
const walk = require('walk');
const source = `${site_base}`;
let md_structure = getStructBit();
let pug_structure = getStructBit();
/**
* Defines the npm walk options
*
* We are only really concerned about the file listener because it will handle
* creating the directory
*/
const walk_options = {
filters: walk_filters,
listeners: {
file: function (root, fileStats, next) {
/**
* The md process and the pug process are basically the same and should
* probably be consolidated somewhat
*/
if(fileStats.name.split('.').slice(-1)[0] === 'md'){
const project_path = root.replace(source, '').split('/').filter(p => p.length);
let current_level = md_structure;
if(project_path.length === 0){
const parsed_file = parseFile(`${root}/${fileStats.name}`);
if(parsed_file !== null){
current_level.files.push(parsed_file);
}
}
else {
let i = 0;
while(i < project_path.length){
if(!current_level.children[project_path[i]]){
current_level.children[project_path[i]] = getStructBit();
}
if(i === project_path.length - 1) {
const parsed_file = parseFile(`${root}/${fileStats.name}`);
if(parsed_file !== null){
current_level.children[project_path[i]].files.push(parsed_file);
}
}
else {
current_level = current_level.children[project_path[i]];
}
i++;
}
}
next();
}
/**
* pug files are not parsed but we only get the path because we will
* compile them later
*/
else if(fileStats.name.split('.').slice(-1)[0] === 'pug'){
const project_path = root.replace(source, '').split('/').filter(p => p.length);
let current_level = pug_structure;
if(project_path.length === 0){
current_level.files.push(`${root}/${fileStats.name}`);
}
else {
let i = 0;
while(i < project_path.length){
if(!current_level.children[project_path[i]]){
current_level.children[project_path[i]] = getStructBit();
}
if(i === project_path.length - 1) {
current_level.children[project_path[i]].files.push(`${root}/${fileStats.name}`);
}
else {
current_level = current_level.children[project_path[i]];
}
i++;
}
}
next();
}
},
errors: (a,b,c) => console.log(a,b,c)
}
}
const walker = walk.walkSync(source, walk_options);
// console.log(JSON.stringify(md_structure, null, '\t'));
// console.log(JSON.stringify(pug_structure, null, '\t'));
const locals = Object.assign({}, base_locals, {
md_structure: md_structure,
pug_structure: pug_structure
});
// compile and write md files
createDestStructure(`${__dirname}`, md_structure, locals);
// compile and write pug files
createPugDestStructure(`${__dirname}`, pug_structure, locals);
done();
});
gulp.task('default', ['build-site-pages']);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment