You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
3.4 KiB
155 lines
3.4 KiB
/*! |
|
* use <https://github.com/jonschlinkert/use> |
|
* |
|
* Copyright (c) 2015-2017, Jon Schlinkert. |
|
* Released under the MIT License. |
|
*/ |
|
|
|
'use strict'; |
|
|
|
module.exports = function base(app, options) { |
|
if (!isObject(app) && typeof app !== 'function') { |
|
throw new TypeError('expected an object or function'); |
|
} |
|
|
|
var opts = isObject(options) ? options : {}; |
|
var prop = typeof opts.prop === 'string' ? opts.prop : 'fns'; |
|
if (!Array.isArray(app[prop])) { |
|
define(app, prop, []); |
|
} |
|
|
|
/** |
|
* Define a plugin function to be passed to use. The only |
|
* parameter exposed to the plugin is `app`, the object or function. |
|
* passed to `use(app)`. `app` is also exposed as `this` in plugins. |
|
* |
|
* Additionally, **if a plugin returns a function, the function will |
|
* be pushed onto the `fns` array**, allowing the plugin to be |
|
* called at a later point by the `run` method. |
|
* |
|
* ```js |
|
* var use = require('use'); |
|
* |
|
* // define a plugin |
|
* function foo(app) { |
|
* // do stuff |
|
* } |
|
* |
|
* var app = function(){}; |
|
* use(app); |
|
* |
|
* // register plugins |
|
* app.use(foo); |
|
* app.use(bar); |
|
* app.use(baz); |
|
* ``` |
|
* @name .use |
|
* @param {Function} `fn` plugin function to call |
|
* @api public |
|
*/ |
|
|
|
define(app, 'use', use); |
|
|
|
/** |
|
* Run all plugins on `fns`. Any plugin that returns a function |
|
* when called by `use` is pushed onto the `fns` array. |
|
* |
|
* ```js |
|
* var config = {}; |
|
* app.run(config); |
|
* ``` |
|
* @name .run |
|
* @param {Object} `value` Object to be modified by plugins. |
|
* @return {Object} Returns the object passed to `run` |
|
* @api public |
|
*/ |
|
|
|
define(app, 'run', function(val) { |
|
if (!isObject(val)) return; |
|
|
|
if (!val.use || !val.run) { |
|
define(val, prop, val[prop] || []); |
|
define(val, 'use', use); |
|
} |
|
|
|
if (!val[prop] || val[prop].indexOf(base) === -1) { |
|
val.use(base); |
|
} |
|
|
|
var self = this || app; |
|
var fns = self[prop]; |
|
var len = fns.length; |
|
var idx = -1; |
|
|
|
while (++idx < len) { |
|
val.use(fns[idx]); |
|
} |
|
return val; |
|
}); |
|
|
|
/** |
|
* Call plugin `fn`. If a function is returned push it into the |
|
* `fns` array to be called by the `run` method. |
|
*/ |
|
|
|
function use(type, fn, options) { |
|
var offset = 1; |
|
|
|
if (typeof type === 'string' || Array.isArray(type)) { |
|
fn = wrap(type, fn); |
|
offset++; |
|
} else { |
|
options = fn; |
|
fn = type; |
|
} |
|
|
|
if (typeof fn !== 'function') { |
|
throw new TypeError('expected a function'); |
|
} |
|
|
|
var self = this || app; |
|
var fns = self[prop]; |
|
|
|
var args = [].slice.call(arguments, offset); |
|
args.unshift(self); |
|
|
|
if (typeof opts.hook === 'function') { |
|
opts.hook.apply(self, args); |
|
} |
|
|
|
var val = fn.apply(self, args); |
|
if (typeof val === 'function' && fns.indexOf(val) === -1) { |
|
fns.push(val); |
|
} |
|
return self; |
|
} |
|
|
|
/** |
|
* Wrap a named plugin function so that it's only called on objects of the |
|
* given `type` |
|
* |
|
* @param {String} `type` |
|
* @param {Function} `fn` Plugin function |
|
* @return {Function} |
|
*/ |
|
|
|
function wrap(type, fn) { |
|
return function plugin() { |
|
return this.type === type ? fn.apply(this, arguments) : plugin; |
|
}; |
|
} |
|
|
|
return app; |
|
}; |
|
|
|
function isObject(val) { |
|
return val && typeof val === 'object' && !Array.isArray(val); |
|
} |
|
|
|
function define(obj, key, val) { |
|
Object.defineProperty(obj, key, { |
|
configurable: true, |
|
writable: true, |
|
value: val |
|
}); |
|
}
|
|
|