UNPKG

bookmaker

Version:

Create books from a folder of markdown files

201 lines (178 loc) 4.79 kB
var EventEmitter = require('events').EventEmitter var parser = require('markdown-parse') var fs = require('fs') var async = require('async') var util = require('util') var globby = require('globby') var resize = require('imagemagickresizer')() var path = require('path') var mkdirp = require('mkdirp') function BookMaker(source, options){ EventEmitter.call(this) this._source = source this._options = options } util.inherits(BookMaker, EventEmitter) // an array of relative glob results BookMaker.prototype.globs = function(glob, done){ var self = this; if(typeof(glob)==='string'){ glob = [glob] } globby(glob, { cwd:self._source }, done) } // an array of absolute file paths from globs BookMaker.prototype.files = function(glob, done){ var self = this; this.globs(glob, function(err, files){ if(err) return done(err) files = files.map(function(file){ return path.normalize(self._source + '/' + file) }) done(null, files) }) } BookMaker.prototype.fileCopies = function(glob, dest, done){ var self = this; this.globs(glob, function(err, files){ if(err) return done(err) files = files.map(function(file){ return { source:path.normalize(self._source + '/' + file), dest:path.normalize(dest + '/' + file) } }) done(null, files) }) } BookMaker.prototype.load = function(configGlob, pagesGlob, done){ var self = this; async.parallel({ config:function(next){ self.loadConfigs(configGlob, next) }, pages:function(next){ self.loadPages(pagesGlob, next) } }, function(err, result){ if(err) return done(err) var book = result.config book.pages = result.pages done(null, book) }) } BookMaker.prototype.loadPages = function(glob, done){ var self = this; self.files(glob, function(err, files){ async.map(files, function(file, nextFile){ fs.readFile(file, 'utf8', function(err, content){ if(err) return nextFile(err) parser(content, nextFile) }) }, done) }) } BookMaker.prototype.loadConfigs = function(glob, done){ var self = this; self.files(glob, function(err, files){ if(err) return done(err) var config = {} files.filter(function(file){ return file.match(/\.json/) }).map(function(file){ return require(file) }).forEach(function(data){ Object.keys(data || {}).forEach(function(key){ config[key] = data[key] }) }) done(null, config) }) } BookMaker.prototype.ensureFolder = function(filepath, done){ var folder = path.dirname(filepath) mkdirp(folder, done) } BookMaker.prototype.copyFiles = function(glob, dest, done){ var self = this; if(!fs.existsSync(dest)){ return done(dest + ' does not exist') } self.fileCopies(glob, dest, function(err, files){ if(err) return done(err) async.forEach(files, function(file, next){ self.ensureFolder(file.dest, function(){ if(err) return next(err) var source = fs.createReadStream(file.source) var dest = fs.createWriteStream(file.dest) dest.on('error', next) dest.on('close', next) source.pipe(dest) }) }, done) }) } BookMaker.prototype.resizeImages = function(glob, dest, size, done){ var self = this; if(!fs.existsSync(dest)){ return done(dest + ' does not exist') } if(typeof(size)==='string'){ var parts = size.replace(/\s/g, '').split('x') size = { width:parts[0], height:parts[1] } } self.fileCopies(glob, dest, function(err, files){ if(err) return done(err) async.forEach(files, function(file, next){ self.ensureFolder(file.dest, function(){ if(err) return next(err) resize.image(file.source, file.dest, size, next) }) }, done) }) } BookMaker.prototype.write = function(dest, config, done){ var self = this; if(!fs.existsSync(dest)){ return done(dest + ' does not exist') } if(!config.config){ return done('config setting does not exist') } if(!config.pages){ return done('pages setting does not exist') } var bookjson = config.bookjson || 'book.json' async.parallel({ book:function(next){ self.load(config.config, config.pages, function(err, book){ fs.writeFile(dest + '/' + bookjson, JSON.stringify(book, null, 4), 'utf8', next) }) }, files:function(next){ if(!config.files){ return next() } self.copyFiles(config.files, dest, next) }, images:function(next){ if(!config.images){ return next() } if(config.imageSize){ self.resizeImages(config.images, dest, config.imageSize, next) } else{ self.copyFiles(config.images, dest, next) } } }, done) } module.exports = function(source, options){ return new BookMaker(source, options) }