summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/book.js1
-rw-r--r--lib/cli/index.js11
-rw-r--r--lib/config/index.js20
-rw-r--r--lib/config/plugins.js24
-rw-r--r--lib/config/schema.js4
-rw-r--r--lib/config/validator.js3
-rw-r--r--lib/output/base.js8
-rw-r--r--lib/plugins/index.js5
-rw-r--r--test/config.js49
-rw-r--r--test/glossary.js4
-rw-r--r--test/langs.js2
-rw-r--r--test/node_modules/gitbook-plugin-test-hooks/index.js16
-rw-r--r--test/node_modules/gitbook-plugin-test-hooks/package.json7
-rw-r--r--test/page.js6
-rw-r--r--test/plugins.js16
-rw-r--r--test/readme.js2
16 files changed, 129 insertions, 49 deletions
diff --git a/lib/book.js b/lib/book.js
index d7834ee..400296e 100644
--- a/lib/book.js
+++ b/lib/book.js
@@ -180,6 +180,7 @@ Book.prototype.parse = function() {
that.log.debug.ln('Preparing book for language', lang.id);
var langBook = new Book(_.extend({}, that.opts, {
parent: that,
+ config: that.config.dump(),
root: that.resolve(lang.id)
}));
diff --git a/lib/cli/index.js b/lib/cli/index.js
index 33df69f..58a0e1b 100644
--- a/lib/cli/index.js
+++ b/lib/cli/index.js
@@ -113,14 +113,19 @@ module.exports = {
// Generate the book
.then(function() {
return Book.setup(helper.nodeFS, input, {
- 'config': {
- 'defaultsPlugins': ['livereload']
- },
'logLevel': kwargs.log
})
.then(function(book) {
return book.parse()
.then(function() {
+ // Add livereload plugin
+ book.config.set('plugins',
+ book.config.get('plugins')
+ .concat([
+ { name: 'livereload' }
+ ])
+ );
+
var Out = helper.FORMATS[kwargs.format];
var output = new Out(book);
diff --git a/lib/config/index.js b/lib/config/index.js
index 272e92a..7f75733 100644
--- a/lib/config/index.js
+++ b/lib/config/index.js
@@ -22,13 +22,15 @@ function Config(book, baseConfig) {
this.log = book.log;
this.path = '';
- this.replace(baseConfig || {});
+ this.baseConfig = baseConfig || {};
+ this.replace({});
}
// Load configuration of the book
// and verify that the configuration is satisfying
Config.prototype.load = function() {
var that = this;
+ var isLanguageBook = this.book.isLanguageBook();
// Try all potential configuration file
return Promise.some(CONFIG_FILES, function(filename) {
@@ -47,19 +49,19 @@ Config.prototype.load = function() {
});
})
.then(function() {
- if (!that.book.isLanguageBook()) {
+ if (!isLanguageBook) {
if (!gitbook.satisfies(that.options.gitbook)) {
throw new Error('GitBook version doesn\'t satisfy version required by the book: '+that.options.gitbook);
}
if (that.options.gitbook != '*' && !semver.satisfies(semver.inc(gitbook.version, 'patch'), that.options.gitbook)) {
that.log.warn.ln('gitbook version specified in your book.json might be too strict for future patches, \''+(_.first(gitbook.version.split('.'))+'.x.x')+'\' is more adequate');
}
- }
- that.options.plugins = plugins.toList(that.options.plugins);
- that.options.defaultsPlugins = plugins.toList(that.options.defaultsPlugins || '', false);
- that.options.plugins = _.union(that.options.plugins, that.options.defaultsPlugins);
- that.options.plugins = _.uniq(that.options.plugins, 'name');
+ that.options.plugins = plugins.toList(that.options.plugins);
+ } else {
+ // Multilingual book should inherits the plugins list from parent
+ that.options.plugins = that.book.parent.config.get('plugins');
+ }
that.options.gitbook = gitbook.version;
});
@@ -69,6 +71,10 @@ Config.prototype.load = function() {
Config.prototype.replace = function(options) {
var that = this;
+ // Extend base config
+ options = _.defaults(_.cloneDeep(options), this.baseConfig);
+
+ // Validate the config
this.options = validator.validate(options);
// options.input == book.root
diff --git a/lib/config/plugins.js b/lib/config/plugins.js
index c75cd55..5d98736 100644
--- a/lib/config/plugins.js
+++ b/lib/config/plugins.js
@@ -9,7 +9,7 @@ function isDefaultPlugin(name, version) {
}
// Normalize a list of plugins to use
-function normalizePluginsList(plugins, addDefaults) {
+function normalizePluginsList(plugins) {
// Normalize list to an array
plugins = _.isString(plugins) ? plugins.split(',') : (plugins || []);
@@ -25,8 +25,7 @@ function normalizePluginsList(plugins, addDefaults) {
var version = parts[1];
return {
'name': name,
- 'version': version, // optional
- 'isDefault': isDefaultPlugin(name, version)
+ 'version': version // optional
};
});
@@ -41,19 +40,15 @@ function normalizePluginsList(plugins, addDefaults) {
.value();
// Merge with defaults
- if (addDefaults !== false) {
- _.each(DEFAULT_PLUGINS, function(plugin) {
- if (_.find(plugins, { name: plugin })) {
- return;
- }
+ _.each(DEFAULT_PLUGINS, function(plugin) {
+ if (_.find(plugins, { name: plugin })) {
+ return;
+ }
- plugins.push({
- 'name': plugin,
- 'isDefault': true
- });
+ plugins.push({
+ 'name': plugin
});
- }
-
+ });
// Remove plugin that start with '-'
plugins = _.filter(plugins, function(plugin) {
return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == '-');
@@ -66,6 +61,7 @@ function normalizePluginsList(plugins, addDefaults) {
}
module.exports = {
+ isDefaultPlugin: isDefaultPlugin,
toList: normalizePluginsList
};
diff --git a/lib/config/schema.js b/lib/config/schema.js
index ac7d05e..34a6c76 100644
--- a/lib/config/schema.js
+++ b/lib/config/schema.js
@@ -179,10 +179,6 @@ module.exports = {
},
'version': {
'type': 'string'
- },
- 'isDefault': {
- 'type': 'boolean',
- 'default': false
}
},
'additionalProperties': false,
diff --git a/lib/config/validator.js b/lib/config/validator.js
index 0ea278f..764b19a 100644
--- a/lib/config/validator.js
+++ b/lib/config/validator.js
@@ -1,4 +1,3 @@
-var _ = require('lodash');
var jsonschema = require('jsonschema');
var jsonSchemaDefaults = require('json-schema-defaults');
var mergeDefaults = require('merge-defaults');
@@ -9,8 +8,6 @@ var error = require('../utils/error');
// Validate a book.json content
// And return a mix with the default value
function validate(bookJson) {
- bookJson = _.cloneDeep(bookJson);
-
var v = new jsonschema.Validator();
var result = v.validate(bookJson, schema, {
propertyName: 'config'
diff --git a/lib/output/base.js b/lib/output/base.js
index 025e850..a1d8804 100644
--- a/lib/output/base.js
+++ b/lib/output/base.js
@@ -27,11 +27,7 @@ function Output(book, opts, parent) {
this.log = this.book.log;
// Create plugins manager
- if (this.parent) {
- this.plugins = this.parent.plugins;
- } else {
- this.plugins = new PluginsManager(this.book);
- }
+ this.plugins = new PluginsManager(this.book);
// Create template engine
this.template = new TemplateEngine(this);
@@ -52,7 +48,7 @@ Output.prototype.generate = function() {
// Load all plugins
.then(function() {
- return Promise(that.parent? null: that.plugins.loadAll())
+ return that.plugins.loadAll()
.then(function() {
that.template.addFilters(that.plugins.getFilters());
that.template.addBlocks(that.plugins.getBlocks());
diff --git a/lib/plugins/index.js b/lib/plugins/index.js
index 2ebbcc8..8280542 100644
--- a/lib/plugins/index.js
+++ b/lib/plugins/index.js
@@ -5,6 +5,7 @@ var Promise = require('../utils/promise');
var fs = require('../utils/fs');
var BookPlugin = require('./plugin');
var registry = require('./registry');
+var pluginsConfig = require('../config/plugins');
/*
PluginsManager is an interface to work with multiple plugins at once:
@@ -82,8 +83,8 @@ PluginsManager.prototype._setup = function(plugin) {
// Install all plugins for the book
PluginsManager.prototype.install = function() {
var that = this;
- var plugins = _.filter(this.book.config.get('plugins'), {
- isDefault: false
+ var plugins = _.filter(this.book.config.get('plugins'), function(plugin) {
+ return !pluginsConfig.isDefaultPlugin(plugin.name);
});
if (plugins.length == 0) {
diff --git a/test/config.js b/test/config.js
index 7a96a5c..be28fc9 100644
--- a/test/config.js
+++ b/test/config.js
@@ -46,7 +46,7 @@ describe('Configuration', function() {
return mock.setupDefaultBook()
.then(function(_book) {
book = _book;
- return book.prepareConfig();
+ return book.config.load();
});
});
@@ -64,7 +64,7 @@ describe('Configuration', function() {
})
.then(function(_book) {
book = _book;
- return book.prepareConfig();
+ return book.config.load();
});
});
@@ -82,7 +82,7 @@ describe('Configuration', function() {
})
.then(function(_book) {
book = _book;
- return book.prepareConfig();
+ return book.config.load();
});
});
@@ -90,5 +90,48 @@ describe('Configuration', function() {
book.config.get('title', '').should.equal('Hello World');
});
});
+
+ describe('Multilingual', function() {
+ var book;
+
+ before(function() {
+ return mock.setupDefaultBook({
+ 'book.json': {
+ title: 'Hello World',
+ pluginsConfig: {
+ 'test': {
+ 'hello': true
+ }
+ }
+ },
+ 'LANGS.md': '# Languages\n\n'
+ + '* [en](./en)\n'
+ + '* [fr](./fr)\n\n',
+ 'en/README.md': '# Hello',
+ 'fr/README.md': '# Bonjour',
+ 'en/book.json': { description: 'In english' },
+ 'fr/book.json': { description: 'En francais' }
+ })
+ .then(function(_book) {
+ book = _book;
+ return book.parse();
+ });
+ });
+
+ it('should correctly extend configuration', function() {
+ book.config.get('title', '').should.equal('Hello World');
+ book.config.get('description', '').should.equal('');
+
+ var en = book.books[0];
+ en.config.get('title', '').should.equal('Hello World');
+ en.config.get('description', '').should.equal('In english');
+ en.config.get('pluginsConfig.test.hello').should.equal(true);
+
+ var fr = book.books[1];
+ fr.config.get('title', '').should.equal('Hello World');
+ fr.config.get('description', '').should.equal('En francais');
+ fr.config.get('pluginsConfig.test.hello').should.equal(true);
+ });
+ });
});
diff --git a/test/glossary.js b/test/glossary.js
index e1ba82a..d6d1af6 100644
--- a/test/glossary.js
+++ b/test/glossary.js
@@ -7,7 +7,7 @@ describe('Glossary', function() {
'GLOSSARY.md': ''
})
.then(function(book) {
- return book.prepareConfig()
+ return book.config.load()
.then(function() {
return book.glossary.load();
@@ -27,7 +27,7 @@ describe('Glossary', function() {
})
.then(function(_book) {
book = _book;
- return book.prepareConfig();
+ return book.config.load();
})
.then(function() {
return book.glossary.load();
diff --git a/test/langs.js b/test/langs.js
index dbde992..91dbd5a 100644
--- a/test/langs.js
+++ b/test/langs.js
@@ -6,7 +6,7 @@ describe('Langs', function() {
'LANGS.md': ''
})
.then(function(book) {
- return book.prepareConfig()
+ return book.config.load()
.then(function() {
return book.langs.load();
diff --git a/test/node_modules/gitbook-plugin-test-hooks/index.js b/test/node_modules/gitbook-plugin-test-hooks/index.js
new file mode 100644
index 0000000..c0666ca
--- /dev/null
+++ b/test/node_modules/gitbook-plugin-test-hooks/index.js
@@ -0,0 +1,16 @@
+var should = require('should');
+
+module.exports = {
+ hooks: {
+ 'init': function() {
+ global._hooks = [];
+ global._hooks.push('init');
+ },
+ 'finish': function() {
+ global._hooks.push('finish');
+ },
+ 'finish:before': function() {
+ global._hooks.push('finish:before');
+ }
+ }
+};
diff --git a/test/node_modules/gitbook-plugin-test-hooks/package.json b/test/node_modules/gitbook-plugin-test-hooks/package.json
new file mode 100644
index 0000000..adb12a8
--- /dev/null
+++ b/test/node_modules/gitbook-plugin-test-hooks/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "gitbook-plugin-test-hooks",
+ "version": "1.0.0",
+ "engines": {
+ "gitbook": "*"
+ }
+} \ No newline at end of file
diff --git a/test/page.js b/test/page.js
index 37acc95..f11d55e 100644
--- a/test/page.js
+++ b/test/page.js
@@ -32,7 +32,7 @@ describe('Page', function() {
'variables/page/next.md': '{{ page.next.title }} {{ page.next.path }}',
'variables/page/dir/ltr.md': 'This is english: {{ page.dir }}',
'variables/page/dir/rtl.md': 'بسيطة {{ page.dir }}',
- 'variables/book/title.md': '{{ book.title}}',
+ 'variables/config/title.md': '{{ config.title}}',
'GLOSSARY.md': '# Glossary\n\n\n## abracadabra\n\nthis is the description'
}, [
@@ -318,8 +318,8 @@ describe('Page', function() {
.should.be.fulfilledWith('<p>Test Variables variables/page/title.md</p>\n');
});
- it('should set book.title', function() {
- var page = book.addPage('variables/book/title.md');
+ it('should set config.title', function() {
+ var page = book.addPage('variables/config/title.md');
return page.toHTML(output)
.should.be.fulfilledWith('<p>Hello World</p>\n');
});
diff --git a/test/plugins.js b/test/plugins.js
index 172e00c..4d9cdf1 100644
--- a/test/plugins.js
+++ b/test/plugins.js
@@ -175,5 +175,21 @@ describe('Plugins', function() {
blocks.testContext.process({ body: 'Hello' });
});
});
+
+ describe('Hooks', function() {
+ var plugin;
+
+ before(function() {
+ plugin = new BookPlugin(book, 'test-hooks');
+ return plugin.load(PLUGINS_ROOT);
+ });
+
+ it('can call a hook', function() {
+ return plugin.hook('init')
+ .then(function() {
+ global._hooks.should.deepEqual(['init']);
+ });
+ });
+ });
});
diff --git a/test/readme.js b/test/readme.js
index 16aa81a..0cf66ff 100644
--- a/test/readme.js
+++ b/test/readme.js
@@ -6,7 +6,7 @@ describe('Readme', function() {
'README.md': ''
})
.then(function(book) {
- return book.prepareConfig()
+ return book.config.load()
.then(function() {
return book.readme.load();