Merge pull request #482 from GitbookIO/feature/includes

Add include support, with variables and the whole shebang
This commit is contained in:
Aaron O'Mullan
2014-10-15 21:29:23 +02:00
7 changed files with 96 additions and 52 deletions
+23
View File
@@ -14,12 +14,35 @@ var BaseGenerator = function(options) {
this.options.plugins = Plugin.normalizeNames(this.options.plugins);
this.options.plugins = _.union(this.options.plugins, this.options.defaultsPlugins);
this.plugins = [];
// Include variables (not yet loaded)
this.variables = {};
};
BaseGenerator.prototype.callHook = function(name, data) {
return this.plugins.hook(name, data);
};
// Sets up generator
BaseGenerator.prototype.load = function() {
return this.loadVariables()
.then(this.loadPlugins.bind(this));
};
BaseGenerator.prototype.loadVariables = function() {
var that = this;
return fs.readFile(path.join(this.options.input, 'variables.json'), 'utf8')
.then(function(content) {
try {
that.variables = JSON.parse(content);
} catch(err) {
console.log('No variables.json');
}
})
.fail(function() {});
};
BaseGenerator.prototype.loadPlugins = function() {
var that = this;
+1 -1
View File
@@ -40,7 +40,7 @@ var loadGenerator = function(options) {
.then(function() {
var generator = new generators[options.generator](options);
return generator.loadPlugins()
return generator.load()
.then(_.constant(generator));
});
};
+18 -17
View File
@@ -23,6 +23,16 @@ var Generator = function() {
};
util.inherits(Generator, BaseGenerator);
// Add template loading to load
Generator.prototype.load = function() {
var that = this;
return BaseGenerator.prototype.load.apply(this)
.then(function() {
return that.loadTemplates();
});
};
// Load all templates
Generator.prototype.loadTemplates = function() {
this.template = swig.compileFile(
@@ -36,16 +46,6 @@ Generator.prototype.loadTemplates = function() {
);
};
// Load plugins
Generator.prototype.loadPlugins = function() {
var that = this;
return BaseGenerator.prototype.loadPlugins.apply(this)
.then(function() {
return that.loadTemplates();
});
};
// Generate a template
Generator.prototype._writeTemplate = function(tpl, options, output, interpolate) {
var that = this;
@@ -118,16 +118,17 @@ Generator.prototype.prepareFile = function(content, _input) {
return _callHook("page:before");
})
.then(function() {
// Lex page
return parse.lex(page.content);
})
.then(function(lexed) {
page.lexed = lexed;
// Lex, parse includes and get
// Get HTML generated sections
return parse.page(lexed, {
return parse.page(page.content, {
// Local files path
dir: path.dirname(_input) || '/',
// Project's include folder
includes_dir: path.join(that.options.input, '_includes'),
// Output directory
outdir: path.dirname(_input) || '/',
// Templating variables
variables: that.variables,
});
})
.then(function(sections) {
-20
View File
@@ -1,20 +0,0 @@
var fs = require('graceful-fs');
var path = require('path');
module.exports = function(code, folder) {
folder = folder || '';
return code.replace(/{{([\s\S]+?)}}/g, function(match, filename) {
// Normalize filename
var fname = path.join(folder, filename.trim());
// Try including snippet from FS
try {
// Trim trailing newlines/space of imported snippets
return fs.readFileSync(fname, 'utf8').trimRight();
} catch(err) {}
// If fails leave content as is
return match;
});
};
+48
View File
@@ -0,0 +1,48 @@
var _ = require('lodash');
var fs = require('graceful-fs');
var path = require('path');
// Include helper
function importInclude(name, paths) {
return paths
.map(function(folder) {
// Try including snippet from FS
try {
var fname = path.join(folder, name);
// Trim trailing newlines/space of imported snippets
return fs.readFileSync(fname, 'utf8').trimRight();
} catch(err) {}
})
.filter(Boolean)[0];
}
function includer(ctx, folders) {
return function(key) {
key = key.trim();
return ctx[key] || importInclude(key, folders);
};
}
module.exports = function(markdown, folder, ctx) {
// List of folders to search for includes
var folders = [];
// Handle folder arg (string or array)
if(_.isString(folder)) {
folders = [folder];
} else if(_.isArray(folder)) {
folders = folder;
}
// variable context
ctx = ctx || {};
// Memoized include function (to cache lookups)
var _include = _.memoize(includer(ctx, folders));
return markdown.replace(/{{([\s\S]+?)}}/g, function(match, key) {
// If fails leave content as is
return _include(key) || match;
});
};
+5 -10
View File
@@ -5,7 +5,7 @@ var hljs = require('highlight.js');
var lex = require('./lex');
var renderer = require('./renderer');
var codeInclude = require('./code_include');
var include = require('./include');
var lnormalize = require('../utils/lang').normalize;
@@ -51,7 +51,7 @@ function parsePage(src, options) {
options = options || {};
// Lex if not already lexed
return (_.isArray(src) ? src : lex(src))
return (_.isArray(src) ? src : lex(include(src, [options.dir, options.includes_dir], options.variables)))
.map(function(section) {
// Transform given type
if(section.type === 'exercise') {
@@ -74,20 +74,15 @@ function parsePage(src, options) {
// Main language
var lang = validLangs ? langs[0] : null;
// codeInclude shortcut
var ci = function(code) {
return codeInclude(code, options.dir);
};
return {
id: section.id,
type: section.type,
content: render(nonCodeNodes, options),
lang: lang,
code: {
base: ci(codeNodes[0].text),
solution: ci(codeNodes[1].text),
validation: ci(codeNodes[2].text),
base: codeNodes[0].text,
solution: codeNodes[1].text,
validation: codeNodes[2].text,
// Context is optional
context: codeNodes[3] ? codeNodes[3].text : null,
}
+1 -4
View File
@@ -1,8 +1,6 @@
var url = require('url');
var inherits = require('util').inherits;
var links = require('../utils').links;
var codeInclude = require('./code_include');
var path = require('path');
@@ -130,8 +128,7 @@ GitBookRenderer.prototype.listitem = function(text) {
GitBookRenderer.prototype.code = function(code, lang, escaped) {
return GitBookRenderer.super_.prototype.code.call(
this,
// Import code snippets
codeInclude(code, this._extra_options.dir),
code,
lang,
escaped
);