Move conrefs to a separate mixin

This commit is contained in:
Samy Pessé
2016-02-14 22:49:55 +01:00
parent cfefa7d579
commit fef822145d
15 changed files with 142 additions and 117 deletions
+1 -1
View File
@@ -167,7 +167,7 @@ Summary.prototype.find = function(filter) {
};
// Return the first TOCArticle for a specific page (or path)
Summary.prototype.getByPage = function(page) {
Summary.prototype.getArticle = function(page) {
if (!_.isString(page)) page = page.path;
return this.find(function(article) {
-4
View File
@@ -10,7 +10,6 @@ var Glossary = require('./backbone/glossary');
var Summary = require('./backbone/summary');
var Langs = require('./backbone/langs');
var Page = require('./page');
var TemplateEngine = require('./template');
var pathUtil = require('./utils/path');
var error = require('./utils/error');
var Promise = require('./utils/promise');
@@ -90,9 +89,6 @@ function Book(opts) {
// List of page in the book
this.pages = {};
// Templating engine
this.template = new TemplateEngine(this);
_.bindAll(this);
}
+9 -3
View File
@@ -1,5 +1,6 @@
var _ = require('lodash');
var Ignore = require('ignore');
var path = require('path');
var Promise = require('../utils/promise');
var PluginsManager = require('../plugins');
@@ -107,7 +108,7 @@ Output.prototype.prepare = function() {
// Write a page (parsable file), ex: markdown, etc
Output.prototype.onPage = function(page) {
return page.parse(this);
return page.toHTML(this);
};
// Copy an asset file (non-parsable), ex: images, etc
@@ -134,9 +135,14 @@ Output.prototype.onOutputImage = function(page, imgFile) {
return page.relative(imgFile);
};
// By default don;t resolve conrefs
Output.prototype.onResolveTemplate = function(from, to) {
// Read a template by its source URL
Output.prototype.onGetTemplate = function(sourceUrl) {
throw new Error('template not found '+sourceUrl);
};
// Generate a source URL for a template
Output.prototype.onResolveTemplate = function(from, to) {
return path.resolve(path.dirname(from), to);
};
// Finish the generation
+47 -2
View File
@@ -1,7 +1,9 @@
var util = require('util');
var path = require('path');
var Output = require('./base');
var Git = require('../utils/git');
var fs = require('../utils/fs');
var pathUtil = require('../utils/path');
/*
@@ -14,9 +16,52 @@ function ConrefsLoader() {
}
util.inherits(ConrefsLoader, Output);
// Resolve an include in the template engine
ConrefsLoader.prototype.onResolveTemplate = function(from, to) {
// Read a template by its source URL
ConrefsLoader.prototype.onGetTemplate = function(sourceURL) {
var that = this;
return this.git.resolve(sourceURL)
.then(function(filepath) {
// Is local file
if (!filepath) {
filepath = that.book.resolve(sourceURL);
} else {
that.book.log.debug.ln('resolve from git', sourceURL, 'to', filepath);
}
// Read file from absolute path
return fs.readFile(filepath)
.then(function(source) {
return source.toString('utf8');
//return that.engine.interpolate(filepath, source);
})
.then(function(source) {
return {
src: source,
path: filepath
};
});
});
};
// Generate a source URL for a template
ConrefsLoader.prototype.onResolveTemplate = 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);
};
module.exports = ConrefsLoader;
+1 -1
View File
@@ -17,7 +17,7 @@ JSONOutput.prototype.onPage = function(page) {
var that = this;
// Parse the page
return page.parse(this)
return page.toHTML(this)
// Write as json
.then(function() {
+5 -3
View File
@@ -129,17 +129,19 @@ HTMLPipeline.prototype.transformHeadings = function() {
// Outline SVG from the HML
HTMLPipeline.prototype.transformSvgs = function() {
var that = this;
return this._transform('svg', function($svg) {
var content = [
'<?xml version="1.0" encoding="UTF-8"?>',
renderDOM(this.$, $svg)
renderDOM(that.$, $svg)
].join('\n');
return Promise(this.opts.onOutputSVG(content))
return Promise(that.opts.onOutputSVG(content))
.then(function(filename) {
if (!filename) return;
$svg.replaceWith(this.$('<img>').attr('src', filename));
$svg.replaceWith(that.$('<img>').attr('src', filename));
});
});
};
+3 -3
View File
@@ -106,7 +106,7 @@ Page.prototype.read = function() {
// Return templating context for this page
// This is used both for themes and page parsing
Page.prototype.getContext = function() {
var article = this.book.summary.find(this);
var article = this.book.summary.getArticle(this);
return {
file: {
@@ -122,7 +122,7 @@ Page.prototype.getContext = function() {
};
// Parse the page and return its content
Page.prototype.parse = function(output) {
Page.prototype.toHTML = function(output) {
var that = this;
this.log.debug.ln('start parsing file', this.path);
@@ -137,7 +137,7 @@ Page.prototype.parse = function(output) {
// Render template
.then(function() {
return that.book.template.renderString(that.content, that.getContext(), {
return output.template.renderString(that.content, that.getContext(), {
file: that.path
})
.then(that.update);
+1 -1
View File
@@ -27,7 +27,7 @@ function TemplateEngine(output) {
this.log = this.book.log;
// Create file loader
this.loader = new Loader(this);
this.loader = new Loader(output);
// Create nunjucks instance
this.env = new nunjucks.Environment(
+13 -52
View File
@@ -1,74 +1,35 @@
var path = require('path');
var nunjucks = require('nunjucks');
var location = require('../utils/location');
var Git = require('../utils/git');
var pathUtil = require('../utils/path');
/*
Simple nunjucks loader which is passing the reponsability to the Output
*/
// 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());
init: function(output, opts) {
this.output = output;
},
getSource: function(sourceURL, callback) {
var that = this;
this.output.onGetTemplate(sourceURL)
.then(function(out) {
// We disable cache since content is modified (shortcuts, ...)
out.noCache = true;
this.git.resolve(sourceURL)
.then(function(filepath) {
// Is local file
if (!filepath) {
filepath = that.book.resolve(sourceURL);
} else {
that.book.log.debug.ln('resolve from git', sourceURL, '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
};
});
return out;
})
.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);
return this.output.onResolveTemplate(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);
return location.isRelative(filename);
}
});
+2 -2
View File
@@ -10,7 +10,7 @@ var fs = require('./fs');
var GIT_PREFIX = 'git+';
function Git(tmpDir) {
function Git() {
this.tmpDir;
this.cloned = {};
}
@@ -84,7 +84,7 @@ Git.prototype.resolveRoot = function(filepath) {
var relativeToGit, repoId;
// No git repo cloned, or file is not in a git repository
if (!pathUtil.isInRoot(this.tmpDir, filepath)) return null;
if (!this.tmpDir || !pathUtil.isInRoot(this.tmpDir, filepath)) return null;
// Extract first directory (is the repo id)
relativeToGit = path.relative(this.tmpDir, filepath);
+1 -1
View File
@@ -64,7 +64,7 @@
"gitbook-markdown-css": "1.0.1"
},
"scripts": {
"test": "node_modules/.bin/mocha --reporter spec --timeout 15000 ./test/all.js"
"test": "node_modules/.bin/mocha --reporter spec --bail --timeout 15000 ./test/all.js"
},
"repository": {
"type": "git",
+1
View File
@@ -10,6 +10,7 @@ require('./parse');
require('./git');
require('./template');
require('./conrefs');
// Output
require('./output-json');
+49
View File
@@ -0,0 +1,49 @@
var mock = require('./mock');
var ConrefsLoader = require('../lib/output/conrefs');
describe('Conrefs Loader', function() {
var output;
before(function() {
return mock.outputDefaultBook(ConrefsLoader, {
'test.md': 'World'
})
.then(function(_output) {
output = _output;
});
});
it('should include a local file', function() {
return output.template.renderString('Hello {% include "./test.md" %}')
.should.be.fulfilledWith('Hello World');
});
it('should include a git url', function() {
return output.template.renderString('Hello {% include "./test.md" %}')
.should.be.fulfilledWith('Hello World');
});
it('should reject file out of scope', function() {
return output.template.renderString('Hello {% include "../test.md" %}')
.should.be.rejected();
});
describe('Git Urls', function() {
it('should include a file from a git repo', function() {
return output.template.renderString('{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md" %}')
.should.be.fulfilledWith('Hello from git');
});
it('should handle deep inclusion (1)', function() {
return output.template.renderString('{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test2.md" %}')
.should.be.fulfilledWith('First Hello. Hello from git');
});
it('should handle deep inclusion (2)', function() {
return output.template.renderString('{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test3.md" %}')
.should.be.fulfilledWith('First Hello. Hello from git');
});
});
});
+2 -2
View File
@@ -54,7 +54,7 @@ describe('Page', function() {
it('should add a default ID to headings', function() {
var page = book.addPage('heading.md');
return page.parse(output)
return page.toHTML(output)
.then(function() {
page.content.should.be.html({
'h1#hello': {
@@ -73,7 +73,7 @@ describe('Page', function() {
before(function() {
page = book.addPage('links.md');
return page.parse(output);
return page.toHTML(output);
});
it('should replace links to page to .html', function() {
+7 -42
View File
@@ -1,63 +1,28 @@
var mock = require('./mock');
var pkg = require('../package.json');
var Output = require('../lib/output/base');
describe('Template', function() {
var book;
var output;
before(function() {
return mock.setupDefaultBook({
return mock.outputDefaultBook(Output, {
'test.md': 'World'
})
.then(function(_book) {
book = _book;
return book.parse();
.then(function(_output) {
output = _output;
});
});
describe('.renderString', function() {
it('should render a simple string', function() {
return book.template.renderString('Hello World')
return output.template.renderString('Hello World')
.should.be.fulfilledWith('Hello World');
});
it('should render with variable', function() {
return book.template.renderString('Version is {{ gitbook.version }}')
return output.template.renderString('Version is {{ gitbook.version }}')
.should.be.fulfilledWith('Version is '+pkg.version);
});
});
describe('Conrefs Loader', function() {
it('should include a local file', function() {
return book.template.renderString('Hello {% include "./test.md" %}')
.should.be.fulfilledWith('Hello World');
});
it('should include a git url', function() {
return book.template.renderString('Hello {% include "./test.md" %}')
.should.be.fulfilledWith('Hello World');
});
it('should reject file out of scope', function() {
return book.template.renderString('Hello {% include "../test.md" %}')
.should.be.rejected();
});
describe('Git Urls', function() {
it('should include a file from a git repo', function() {
return book.template.renderString('{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md" %}')
.should.be.fulfilledWith('Hello from git');
});
it('should handle deep inclusion (1)', function() {
return book.template.renderString('{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test2.md" %}')
.should.be.fulfilledWith('First Hello. Hello from git');
});
it('should handle deep inclusion (2)', function() {
return book.template.renderString('{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test3.md" %}')
.should.be.fulfilledWith('First Hello. Hello from git');
});
});
});
});