diff options
author | Aaron O'Mullan <aaron.omullan@friendco.de> | 2014-07-29 21:50:15 -0700 |
---|---|---|
committer | Aaron O'Mullan <aaron.omullan@friendco.de> | 2014-07-29 21:50:26 -0700 |
commit | 60a7c28e66c77cd93fd5c60fdea5d0bb07b92b52 (patch) | |
tree | 058ce0f8e3968cc47cf85d8a38dd71d6a390d98f /lib | |
parent | 5dff9b795ee75f0a98d53b41fef953a2fb10f9c4 (diff) | |
download | gitbook-60a7c28e66c77cd93fd5c60fdea5d0bb07b92b52.zip gitbook-60a7c28e66c77cd93fd5c60fdea5d0bb07b92b52.tar.gz gitbook-60a7c28e66c77cd93fd5c60fdea5d0bb07b92b52.tar.bz2 |
Support generating a plugin's book info dynamically
Diffstat (limited to 'lib')
-rw-r--r-- | lib/generate/generator.js | 4 | ||||
-rw-r--r-- | lib/generate/plugin.js | 178 |
2 files changed, 113 insertions, 69 deletions
diff --git a/lib/generate/generator.js b/lib/generate/generator.js index d664eef..ad5f8ab 100644 --- a/lib/generate/generator.js +++ b/lib/generate/generator.js @@ -14,13 +14,13 @@ var BaseGenerator = function(options) { }; BaseGenerator.prototype.callHook = function(name, data) { - return this.plugins.hook(name, this, data); + return this.plugins.hook(name, data); }; BaseGenerator.prototype.loadPlugins = function() { var that = this; - return Plugin.fromList(this.options.plugins, this.options.input) + return Plugin.fromList(this.options.plugins, this.options.input, this) .then(function(_plugins) { that.plugins = _plugins; diff --git a/lib/generate/plugin.js b/lib/generate/plugin.js index 3eacc19..cf24bc0 100644 --- a/lib/generate/plugin.js +++ b/lib/generate/plugin.js @@ -10,11 +10,15 @@ var pkg = require("../../package.json"); var RESOURCES = ["js", "css"]; -var Plugin = function(name, root) { +var Plugin = function(name, root, generator) { this.name = name; this.root = root; this.packageInfos = {}; this.infos = {}; + this.generator = generator; + + // Bind methods + _.bindAll(this); _.each([ "gitbook-plugin-"+name, @@ -43,28 +47,50 @@ Plugin.prototype.load = function(name, baseDir) { } }; +Plugin.prototype.normalizeResource = function(resource) { + // Parse the resource path + var parsed = url.parse(resource); + + // This is a remote resource + // so we will simply link to using it's URL + if (parsed.protocol) { + return { + "url": resource + }; + } + + // This will be copied over from disk + // and shipped with the book's build + return { "path": this.name+"/"+resource }; +}; + // Return resources -Plugin.prototype.getResources = function(resource) { - if (!this.infos.book || !this.infos.book[resource]) { - return []; +Plugin.prototype.getResources = function() { + var book = this.infos.book; + + // Nothing specified, fallback to default + if (!book) { + return Q({}); } - return _.chain(this.infos.book[resource]) - .map(function(resource) { - var parsed = url.parse(resource); - if (parsed.protocol) return {"url": resource} - else return { "path": this.name+"/"+resource }; - }.bind(this)) - .value(); + + // Dynamic function + if(typeof book === "function") { + // Call giving it the context of our generator + return Q().then(book.bind(this.generator)); + } + + // Plain data object + return Q(book); }; // Test if it's a valid plugin Plugin.prototype.isValid = function() { return ( - this.packageInfos - && this.packageInfos.name - && this.packageInfos.engines - && this.packageInfos.engines.gitbook - && semver.satisfies(pkg.version, this.packageInfos.engines.gitbook) + this.packageInfos && + this.packageInfos.name && + this.packageInfos.engines && + this.packageInfos.engines.gitbook && + semver.satisfies(pkg.version, this.packageInfos.engines.gitbook) ); }; @@ -74,7 +100,10 @@ Plugin.prototype.resolveFile = function(filename) { }; // Resolve file path -Plugin.prototype.callHook = function(name, context, data) { +Plugin.prototype.callHook = function(name, data) { + // Our generator will be the context to apply + var context = this.generator; + var hookFunc = this.infos.hooks? this.infos.hooks[name] : null; data = data || {}; @@ -114,7 +143,7 @@ Plugin.normalizeNames = function(names) { return name.length > 0 && name[0] == "-"; }) .map(function(name) { - return name.slice(1) + return name.slice(1); }) .value(); @@ -133,69 +162,84 @@ Plugin.normalizeNames = function(names) { }; // Extract data from a list of plugin -Plugin.fromList = function(names, root) { +Plugin.fromList = function(names, root, generator) { var failed = []; // Load plugins var plugins = _.map(names, function(name) { - var plugin = new Plugin(name, root); + var plugin = new Plugin(name, root, generator); if (!plugin.isValid()) failed.push(name); return plugin; }); if (_.size(failed) > 0) return Q.reject(new Error("Error loading plugins: "+failed.join(","))); - // Get all resources - var resources = _.chain(RESOURCES) - .map(function(resource) { - return [ - resource, - _.chain(plugins) - .map(function(plugin) { - return plugin.getResources(resource); - }) + // Get resources of plugins + return Q.all(_.map(plugins, function(plugin) { + return plugin.getResources(); + })) + // Extract resources out + // css, js, etc ... + .then(function(resources) { + // Group by resource types + return _.chain(RESOURCES) + .map(function(resourceType) { + // Get resources from all the plugins for this current type + return _.chain(resources) + .pluck(resourceType) + .compact() .flatten() - .value() - ]; - }) - .object() - .value(); - resources.html = {} - - _.each(plugins, function(plugin) { - if (!plugin.infos.book || !plugin.infos.book.html) return; - var html = plugin.infos.book.html || {}; - _.each(html, function(code, key) { - if (!_.isFunction(code)) code = _.constant(code); - if (!resources.html[key]) resources.html[key] = []; - resources.html[key].push(code); + .value(); }) - }); - - return Q({ - 'list': plugins, - 'resources': resources, - 'hook': function(name, context, data) { - return _.reduce(plugins, function(prev, plugin) { - return prev.then(function(ret) { - return plugin.callHook(name, context, ret); - }) - }, Q(data)); - }, - 'template': function(name) { - var withTpl = _.find(plugins, function(plugin) { - return (plugin.infos.templates - && plugin.infos.templates[name]); + .object() + .value(); + }) + // Extract html snippets + .then(function(resources) { + // Map of html resources by name added by each plugin + resources.html = plugins.reduce(function(accu, plugin) { + var html = plugin.infos.book.html || {}; + _.each(html, function(code, key) { + // Turn into function if not one already + if (!_.isFunction(code)) code = _.constant(code); + // Append + accu[key] = (accu[key] || []).concat([code]); }); - if (!withTpl) return null; - return withTpl.resolveFile(withTpl.infos.templates[name]); - }, - 'html': function(tag, context, options) { - return _.map(resources.html[tag] || [], function(code) { - return code.call(context, options); - }).join("\n"); - } + return accu; + }, {}); + + return resources; + }) + // Return big multi-plugin object + .then(function(resources) { + return { + 'list': plugins, + 'resources': resources, + 'hook': function(name, data) { + return _.reduce(plugins, function(prev, plugin) { + return prev.then(function(ret) { + return plugin.callHook(name, ret); + }); + }, Q(data)); + }, + 'template': function(name) { + var withTpl = _.find(plugins, function(plugin) { + return ( + plugin.infos.templates && + plugin.infos.templates[name] + ); + }); + + if (!withTpl) return null; + return withTpl.resolveFile(withTpl.infos.templates[name]); + }, + 'html': function(tag, context, options) { + return _.map(resources.html[tag] || [], function(code) { + return code.call(context, options); + }).join("\n"); + } + }; }); }; |