guidebook
Version:
Use your leanpub sources to write an interactive guidebook
132 lines (104 loc) • 3.81 kB
JavaScript
var async = require('async');
var marked = require('marked');
var debug = require('debug')('guidebook');
var express = require('express');
var fs = require('fs');
var path = require('path');
var parseSections = require('altpub-sections');
var toc = require('altpub-toc');
var gendocs = require('gendocs');
var http = require('http');
var out = require('out');
/**
# guidebook
The `guidebook` module (and CLI) is a simple way to enable interaction with
your markdown sources for a [leanpub](https://leanpub.com) authored books
with an interactive guidebook. This approach has been developed for working
with the [rtc.io](http://rtc.io/) modules and as such uses a browser based
interface.
## Why?
Because I don't like doing things more than once, and it seemed like most of
the component pieces were available to make this possible.
## Usage
Once you have installed guidebook on your local machine, then you should be
able to run the `guidebook` command in a leanpub compatible folder.
## Included Fonts
Please note that the guidebook default rendering and installable module
includes the following fonts sourced from
[Google Fonts](http://www.google.com/fonts):
- Inconsolata (Ralph Levein - SIL Open Font License, 1.1)
- Roboto Slab (Christian Robertson - Apache 2.0)
- Source Code Pro (Paul D. Hunt - SIL Open Font License, 1.1)
Fonts are distributed under their original licenses.
**/
module.exports = function(opts, callback) {
// initialise the basepath
var parentPath = module && module.parent && path.dirname(module.parent.filename);
var basePath = (opts || {}).basePath || parentPath || process.cwd();
var bookPath = path.resolve(basePath, 'manuscript');
var port = (opts || {}).port || process.env.NODE_PORT || 3000;
var server;
// create the cdn
var cdn = require('./cdn')({
basePath: basePath
});
function createServer(entries, callback) {
cdn.use(require('./pages/router.js')(entries, bookPath, opts).middleware);
cdn.use(express.static(__dirname + '/public'));
debug('creating server to serve ' + entries.length + ' entries');
callback(null, http.createServer(cdn), cdn);
}
function genDocs(entries, callback) {
async.map(entries, genDocsForEntry, function(err, entries) {
debug('completed generating docs for ' + entries.length + ' entries');
callback(err, entries);
});
}
function genDocsForEntry(entry, callback) {
reloadEntry({
name: entry,
filename: path.join(bookPath, entry)
}, callback);
}
function reloadEntry(entry, callback) {
fs.readFile(entry.filename, { encoding: 'utf8' }, function(err, content) {
if (err) {
return callback(err);
}
debug('running gendocs for file: ' + entry.name);
gendocs({ input: content, cwd: bookPath }, function(err, markdown) {
debug('gendocs complete for file: ' + entry.name);
// set the markdown for the entry
entry.markdown = markdown;
// generate the html
entry.html = markdown && marked(parseSections(markdown));
// trigger the callback
callback(err, entry);
});
});
}
function watchContent(entries, callback) {
// setup all the watchers
entries.forEach(function(entry) {
var timer;
fs.watch(entry.filename, function(evt, filename) {
if (evt === 'change') {
clearTimeout(timer);
timer = setTimeout(function() {
reloadEntry(entry, function() {});
}, 10);
}
});
});
callback(null, entries);
}
async.waterfall([
function(callback) {
callback(null, path.join(bookPath, 'Book.txt'));
},
toc.load,
genDocs,
watchContent,
createServer
], callback || function() {});
};