diff options
author | Samy Pessé <samypesse@gmail.com> | 2016-02-22 10:11:44 +0100 |
---|---|---|
committer | Samy Pessé <samypesse@gmail.com> | 2016-02-22 10:11:44 +0100 |
commit | de31b900803892ef0a441ccffba5d5f6a6c42105 (patch) | |
tree | 555addb3679a767c2f51b253d40feb9016638c28 /lib/plugins | |
parent | ccc585ca1fd47ea6cb24cf16b82fd58304840d9c (diff) | |
download | gitbook-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.js | 5 | ||||
-rw-r--r-- | lib/plugins/plugin.js | 114 |
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; |