UNPKG

fixings

Version:

A general-purpose plugin system to add your own plugin system to any project

139 lines (127 loc) 3.56 kB
/** * Fixings/Eat class * * Eat (consumer) class for running a set of hooks. * * @version 1.0.0 * @author Drew Sommer * @license MIT */ /** @ignore */ const DepTree = require('deptree') class Eat { /** * Create a new hook consumer (do not create directly, use Fixings class) * @param {Hook} hook - The hook to iterate over * @param {String} name - Variable name for plugin $name * @param {String} before - Variable name for plugin $before * @param {String} after - Variable name for plugin $after * @example * var Eater = new Eat(...) */ constructor(hook, name, before, after) { this.hook = hook this.cur = 0 // Create a new dependency resolver var depTree = new DepTree() // Add dependencies for afters and befores for (var plugin of this.hook.plugins) { depTree.add(plugin[name]) if (plugin[after]) depTree.add(plugin[name], plugin[after]) if (plugin[before]) depTree.add(plugin[before], plugin[name]) } var resolved = depTree.resolve() // Update hook ordering for (var n of resolved) { for (let i=0; i<this.hook.plugins.length; i++) { if (n === this.hook.plugins[i][name]) { this.hook.order.push(i) break } } } // Fill in missing plugins in order (they come after any ordered plugins) var accounted = [] for (let i of this.hook.order) { accounted.push(this.hook.plugins[i][name]) } for (let i=0; i<this.hook.plugins.length; i++) { if(!accounted.includes(this.hook.plugins[i][name])) { this.hook.order.push(i) accounted.push(this.hook.plugins[i][name]) } } } /** * Get the next plugin in the hook * @returns {?PluginHook} Returns the plugin to run, or null if all plugins ran * @example * var plugin = Eater.next() * while (plugin) { * plugin.handler(...) * plugin = Eater.next() * } */ next() { if (this.cur >= this.hook.order.length) return null var plugin = this.hook.plugins[this.hook.order[this.cur]] this.cur++ return plugin } /** * @typedef {function(nextCallback)} * @callback * @param {?Error} - Error message or null (if no error) * @param {?PluginHook} - Plugin hook to run, or null if all plugins ran */ /** * Get the next plugin in the hook asyncronously * @param {nextCallback} [callback=null] - Callback function * @async * @returns {?PluginHook} - Plugin hook to run, or null if all plugins ran * @throws {Error} - If an error occured * @example * // Not recommended * Eater.nextAsync((error, plugin) => { * plugin.handler(...) * Eater.nextAsync((error, plugin) => {...}) * }) * @example * var plugin = await Eater.nextAsync() * while (plugin) { * plugin.handler(...) * plugin = await Eater.nextAsync() * } * @example * var plugin * Eater.nextAsync() * .then(plug => { plugin = plug }) * .catch(...) * while(plugin) { * plugin.handler(...) * Eater.nextAsync() * .then(plug => { plugin = plug }) * .catch(...) * } */ nextAsync(callback=null) { if (typeof callback === 'function') { setImmediate(() => { try { callback(null, this.next()) } catch (error) { callback(error) } }) } else { return new Promise((resolve, reject) => { try { resolve(this.next()) } catch (error) { reject(error) } }) } } } module.exports = Eat