summaryrefslogtreecommitdiffstats
path: root/lib/plugins
diff options
context:
space:
mode:
authorSamy Pessé <samypesse@gmail.com>2016-02-22 10:11:44 +0100
committerSamy Pessé <samypesse@gmail.com>2016-02-22 10:11:44 +0100
commitde31b900803892ef0a441ccffba5d5f6a6c42105 (patch)
tree555addb3679a767c2f51b253d40feb9016638c28 /lib/plugins
parentccc585ca1fd47ea6cb24cf16b82fd58304840d9c (diff)
downloadgitbook-de31b900803892ef0a441ccffba5d5f6a6c42105.zip
gitbook-de31b900803892ef0a441ccffba5d5f6a6c42105.tar.gz
gitbook-de31b900803892ef0a441ccffba5d5f6a6c42105.tar.bz2
Add validation of plugin's config after loading
Diffstat (limited to 'lib/plugins')
-rw-r--r--lib/plugins/index.js5
-rw-r--r--lib/plugins/plugin.js114
2 files changed, 113 insertions, 6 deletions
diff --git a/lib/plugins/index.js b/lib/plugins/index.js
index 343c569..00ee7d1 100644
--- a/lib/plugins/index.js
+++ b/lib/plugins/index.js
@@ -104,4 +104,9 @@ PluginsManager.prototype.hook = function(name, input) {
}, input);
};
+// Extract all resources for a namespace
+PluginsManager.prototype.resources = function(namespace) {
+
+};
+
module.exports = PluginsManager;
diff --git a/lib/plugins/plugin.js b/lib/plugins/plugin.js
index 9f9cc35..df79184 100644
--- a/lib/plugins/plugin.js
+++ b/lib/plugins/plugin.js
@@ -1,6 +1,9 @@
var _ = require('lodash');
var path = require('path');
var resolve = require('resolve');
+var mergeDefaults = require('merge-defaults');
+var jsonschema = require('jsonschema');
+var jsonSchemaDefaults = require('json-schema-defaults');
var Promise = require('../utils/promise');
var error = require('../utils/error');
@@ -11,6 +14,8 @@ var HOOKS = [
'init', 'finish', 'finish:before', 'config', 'page', 'page:before'
];
+var RESOURCES = ['js', 'css'];
+
// Return true if an error is a "module not found"
// Wait on https://github.com/substack/node-resolve/pull/81 to be merged
function isModuleNotFound(err) {
@@ -37,18 +42,23 @@ BookPlugin.prototype.isLoaded = function() {
};
// Load this plugin
-BookPlugin.prototype.load = function() {
+// An optional folder to search in can be passed
+BookPlugin.prototype.load = function(folder) {
var that = this;
if (this.isLoaded()) {
return Promise.reject(new Error('Plugin "' + this.id + '" is already loaded'));
}
- // Try loading plugins from different location
- var p = Promise.some([
+ // Fodlers to search plugins in
+ var searchPaths = _.compact([
+ folder,
this.book.resolve('node_modules'),
__dirname
- ], function(baseDir) {
+ ]);
+
+ // Try loading plugins from different location
+ var p = Promise.some(searchPaths, function(baseDir) {
// Locate plugin and load pacjage.json
try {
var res = resolve.sync(that.npmId + '/package.json', { basedir: baseDir });
@@ -82,13 +92,21 @@ BookPlugin.prototype.load = function() {
return true;
})
- .then(that.validate);
+ .then(that.validate)
+
+ // Validate the configuration and update it
+ .then(function() {
+ var config = that.book.config.get(that.getConfigKey(), {});
+ return that.validateConfig(config);
+ })
+ .then(function(config) {
+ that.book.config.set(that.getConfigKey(), config);
+ });
this.log.info('Loading plugin "' + this.id + '" ...');
return this.log.info.promise(p);
};
-
// Verify the definition of a plugin
// Also verify that the plugin accepts the current gitbook version
// This method throws erros if plugin is invalid
@@ -113,6 +131,42 @@ BookPlugin.prototype.validate = function() {
}
};
+// Normalize, validate configuration for this plugin using its schema
+// Throw an error when shcema is not respected
+BookPlugin.prototype.validateConfig = function(config) {
+ var that = this;
+
+ return Promise()
+ .then(function() {
+ var schema = that.packageInfos.gitbook || {};
+ if (!schema) return config;
+
+ // Normalize schema
+ schema.id = '/'+that.getConfigKey();
+ schema.type = 'object';
+
+ // Validate and throw if invalid
+ var v = new jsonschema.Validator();
+ var result = v.validate(config, schema, {
+ propertyName: that.getConfigKey()
+ });
+
+ // Throw error
+ if (result.errors.length > 0) {
+ throw new error.ConfigurationError(new Error(result.errors[0].stack));
+ }
+
+ // Insert default values
+ var defaults = jsonSchemaDefaults(schema);
+ return mergeDefaults(config, defaults);
+ });
+};
+
+// Return key for configuration
+BookPlugin.prototype.getConfigKey = function() {
+ return 'pluginsConfig.'+this.id;
+};
+
// Call a hook and returns its result
BookPlugin.prototype.hook = function(name, input) {
// Our book will be the context to apply
@@ -134,4 +188,52 @@ BookPlugin.prototype.hook = function(name, input) {
});
};
+// Return resources without normalization
+BookPlugin.prototype._getResources = function(base) {
+ base = base;
+ var book = this.infos[base];
+
+ // Compatibility with version 1.x.x
+ if (base == 'website') book = book || this.infos.book;
+
+ // Nothing specified, fallback to default
+ if (!book) {
+ return Promise({});
+ }
+
+ // Dynamic function
+ if(typeof book === 'function') {
+ // Call giving it the context of our book
+ return Promise().then(book.bind(this.book));
+ }
+
+ // Plain data object
+ return Promise(_.cloneDeep(book));
+};
+
+// Normalize resources and return them
+BookPlugin.prototype.getResources = function(base) {
+ var that = this;
+
+ return this._getResources(base)
+ .then(function(resources) {
+
+ _.each(RESOURCES, function(resourceType) {
+ resources[resourceType] = (resources[resourceType] || []).map(that.normalizeResource);
+ });
+
+ return resources;
+ });
+};
+
+// Normalize filters and return them
+BookPlugin.prototype.getFilters = function() {
+ return this.content.filters || {};
+};
+
+// Normalize blocks and return them
+BookPlugin.prototype.getBlocks = function() {
+ return this.content.blocks || {};
+};
+
module.exports = BookPlugin;