156 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			156 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /*! | ||
|  |  * 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 | ||
|  |   }); | ||
|  | } |