diff options
-rw-r--r-- | lib/book.js | 8 | ||||
-rw-r--r-- | lib/fs/index.js | 7 | ||||
-rw-r--r-- | lib/template/index.js | 13 | ||||
-rw-r--r-- | lib/template/loader.js | 75 | ||||
-rw-r--r-- | test/all.js | 2 |
5 files changed, 103 insertions, 2 deletions
diff --git a/lib/book.js b/lib/book.js index f615833..a2a11a7 100644 --- a/lib/book.js +++ b/lib/book.js @@ -287,6 +287,14 @@ Book.prototype.isMultilingual = function() { return this.langs.count() > 0; }; +// Return true if file is in the scope of this book +Book.prototype.isInBook = function(filename) { + return pathUtil.isInRoot( + this.root, + this.resolve(filename) + ); +}; + // Return true if file is in the scope of a child book Book.prototype.isInLanguageBook = function(filename) { return _.some(this.langs.list(), function(lang) { diff --git a/lib/fs/index.js b/lib/fs/index.js index bcd9345..4fd63e9 100644 --- a/lib/fs/index.js +++ b/lib/fs/index.js @@ -2,6 +2,7 @@ var _ = require('lodash'); var path = require('path'); var Buffer = require('buffer').Buffer; var destroy = require('destroy'); +var os = require('os'); var Promise = require('../utils/promise'); @@ -45,10 +46,14 @@ FS.prototype.readdir = function(folder) { // To implement for each fs }; - // These methods don't require to be redefined, by default it uses .exists, .read, .write, .list // For optmization, it can be redefined: +// Allocate a new temporary directory +FS.prototype.tmpdir = function() { + return path.resolve(os.tmpdir(), _.uniqueId('gitbook_tmp_')); +}; + // List files in a directory FS.prototype.listFiles = function(folder) { return this.readdir(folder) diff --git a/lib/template/index.js b/lib/template/index.js index 833ff76..a3021e6 100644 --- a/lib/template/index.js +++ b/lib/template/index.js @@ -7,6 +7,7 @@ var Promise = require('../utils/promise'); var error = require('../utils/error'); var gitbook = require('../gitbook'); var defaultBlocks = require('./blocks'); +var Loader = require('./loader'); // Return extension name for a specific block function blockExtName(name) { @@ -23,6 +24,10 @@ function TemplateEngine(book) { this.book = book; this.log = book.log; + // Create file loader + this.loader = new Loader(this); + + // Create nunjucks instance this.env = new nunjucks.Environment( this.loader, { @@ -57,6 +62,14 @@ function TemplateEngine(book) { this.addBlocks(defaultBlocks); } +// Interpolate a string content to replace shortcuts according to the filetype +TemplateEngine.prototype.interpolate = function(filepath, source) { + var parser = parsers.get(path.extname(filepath)); + var type = parser? parser.name : null; + + return this.applyShortcuts(type, source); +}; + // Add a new custom filter TemplateEngine.prototype.addFilter = function(filterName, func) { try { diff --git a/lib/template/loader.js b/lib/template/loader.js index e69de29..23ffb77 100644 --- a/lib/template/loader.js +++ b/lib/template/loader.js @@ -0,0 +1,75 @@ +var path = require('path'); +var nunjucks = require('nunjucks'); + +var Git = require('../utils/git'); +var pathUtil = require('../utils/path'); + +// The loader should handle relative and git url +var Loader = nunjucks.Loader.extend({ + async: true, + + init: function(engine, opts) { + this.engine = engine; + this.book = engine.book; + this.fs = engine.book.fs; + + this.git = new Git(this.fs.tmpdir()); + }, + + getSource: function(soureURL, callback) { + var that = this; + + this.git.resolveFile(soureURL) + .then(function(filepath) { + // Is local file + if (!filepath) { + filepath = that.book.resolve(soureURL); + } else { + that.book.log.debug.ln('resolve from git', soureURL, 'to', filepath); + } + + // Read file from absolute path + return that.fs.readAsString(filepath) + .then(function(source) { + return that.engine.interpolate(filepath, source); + }) + .then(function(source) { + return { + src: source, + path: filepath, + + // We disable cache since content is modified (shortcuts, ...) + noCache: true + }; + }); + }) + .nodeify(callback); + }, + + resolve: function(from, to) { + // If origin is in the book, we enforce result file to be in the book + if (this.book.isInBook(from)) { + return this.book.resolve( + this.book.relative(path.dirname(from)), + to + ); + } + + // If origin is in a git repository, we resolve file in the git repository + var gitRoot = this.git.resolveRoot(from); + if (gitRoot) { + return pathUtil.resolveInRoot(gitRoot, to); + } + + // If origin is not in the book (include from a git content ref) + return path.resolve(path.dirname(from), to); + }, + + // Handle all files as relative, so that nunjucks pass responsability to 'resolve' + // Only git urls are considered as absolute + isRelative: function(filename) { + return !Git.isUrl(filename); + } +}); + +module.exports = Loader; diff --git a/test/all.js b/test/all.js index 0f55603..827a182 100644 --- a/test/all.js +++ b/test/all.js @@ -7,8 +7,8 @@ require('./glossary'); require('./langs'); require('./parse'); -require('./template'); require('./git'); +require('./template'); // Output require('./output-json'); |