mini-site-generator
Version:
A marvelously minimal static site generator.
215 lines (191 loc) • 5.89 kB
JavaScript
const fs = require('fs');
const path = require('path');
const minify = require('html-minifier').minify;
const minOps = {collapseWhitespace: true};
const filters = ['node_modules'];
let puts = [];
const defaultPuts = [{in:'./', out:'./'}];
function testPut(put, label){
if (put.substr(put.length - 1) !== '/') {
throw new Error('Mini Site Generator: ' +label+ ' should end with a "/" Got:' +put);
}
return put;
}
for (let j = 0; j < process.argv.length; j++) {
//if we find an -io, the next 2 args should be for us! input output!
if (process.argv[j] == '-io') {
var input = makePathAbsolute(testPut(process.argv[j + 1], 'input'));
var output = makePathAbsolute(testPut(process.argv[j + 2], 'output'));
puts.push({
in: input,
out: output
});
j+=2;
}
}
if (puts.length == 0) {
puts = defaultPuts;
}
function errorHandler(err){
if (err) { console.log('err', err); }
}
/**
* Takes an address
* Returns true if that address points to a folder
*/
function isDirectory(sourceAddres){
return fs.lstatSync(sourceAddres).isDirectory();
}
/**
* Takes an array of addresses (files / folders / anything!)
* Returns an array of page addresses
*/
function pages(addresses){
var pages = [];
addresses.forEach(function(address){
if (address.indexOf('.page.js') !== -1) {
pages.push(address);
}
});
return pages;
}
/**
* Takes an array of addresses (files / folders / anything!)
* Returns an array of folder addresses
*/
function folders(addresses){
var folders = [];
addresses.forEach(function(address){
if (isDirectory(address)){
folders.push(address + '/');
}
});
return folders;
}
/**
* Takes an address of a folder
* Returns an array of the items within that folder
*/
function contents(dir){
return fs.readdirSync(dir);;
}
/**
* Takes an array of items (strings)
* Returns all those that do not match filters
*/
function filterContents(items, filters){
var filteredItems = [];
items.forEach(function(item){
var didPass = true;
filters.forEach(function(filter){
if (filter === item) {
didPass = false;
}
});
if (didPass) {
filteredItems.push(item);
}
});
return filteredItems;
}
/**
* Takes an address (dir) and an array of items (files / folders)
* Returns an array of addresses (for each item)
*/
function contentAddresses(dir, items){
var returnAdds = [];
items.forEach(function(item){
returnAdds.push(path.resolve(dir, item));
});
return returnAdds;
}
/**
* Takes a page filename
* Returns the dist filename
*/
function srcToDistName(srcFileName){
return srcFileName.replace('.page.js', '.html');
}
/**
* Takes a source address (meant for pages)
* Returns the dist address
*/
function srcToDistAddress(srcAddress, siteConfig){
return srcAddress.replace(siteConfig.in, siteConfig.out);
}
/**
* Takes the address of a page src
* Returns the markup generated by said page src
*/
function generateMarkup(pageAddress){
var generator = require(pageAddress);
return minify(generator(), minOps);
}
function makePathAbsolute(relativePath){
const absPath = path.resolve(relativePath);
return absPath;
}
//=================================================== Leaving pure functions behind now
//=================================================== Moving into the land of flow control
/**
* Takes an array of src page addresses and the site configuration object
* Creates the dist address, generates the dist markup, saves the markup into the dist address
*/
function buildPages(pageAddressList, siteConfig){
pageAddressList.forEach(function(srcPageAddress){
var distFilename = srcToDistName(srcPageAddress);
var distFileAddress = srcToDistAddress(distFilename, siteConfig);
fs.writeFile(distFileAddress, generateMarkup(srcPageAddress), errorHandler);
});
}
/**
* Takes a folder address
* Makes it if it doesn't exist already
*/
function ensureFolderAddress(folderAddress){
if (!fs.existsSync(folderAddress)) {
fs.mkdirSync(folderAddress);
}
return folderAddress;
}
/**
* Recursivly steps through all the child folders
* Takes a folder address (dir)
* Gets the pages in the given dir and runs the page builder on them
* Gets the folders within the given dir
* Passes each folder to itself.
*/
function stepIntoDir(dir, siteConfig){
var dirContents = filterContents(contents(dir), filters);
var pageList = pages(dirContents);
if (pageList.length > 0) {
ensureFolderAddress(srcToDistAddress(dir, siteConfig));
}
var pageAddressList = contentAddresses(dir, pageList);
buildPages(pageAddressList, siteConfig);
var fullAddressList = contentAddresses(dir, dirContents);
var folderAddressList = folders(fullAddressList);
folderAddressList.forEach(function(folderAddress){
stepIntoDir(folderAddress, siteConfig);
});
};
//stop the string template literal html tag from throwing an undefined
if (typeof html == 'undefined') {
html = function(strings, ...keys){
let returnString = '';
strings.forEach(function(str, i){
returnString += str;
if (typeof keys[i] !== 'undefined') {
returnString += keys[i];
}
});
return returnString;
}
}
/**
* Iterate over every given input / output!
* This is the beginning :)
*/
puts.forEach(function(put){
stepIntoDir(put.in, put);
});