2 * use <https://github.com/jonschlinkert/use>
4 * Copyright (c) 2015-2017, Jon Schlinkert.
5 * Released under the MIT License.
10 module.exports = function base(app, options) {
11 if (!isObject(app) && typeof app !== 'function') {
12 throw new TypeError('expected an object or function');
15 var opts = isObject(options) ? options : {};
16 var prop = typeof opts.prop === 'string' ? opts.prop : 'fns';
17 if (!Array.isArray(app[prop])) {
18 define(app, prop, []);
22 * Define a plugin function to be passed to use. The only
23 * parameter exposed to the plugin is `app`, the object or function.
24 * passed to `use(app)`. `app` is also exposed as `this` in plugins.
26 * Additionally, **if a plugin returns a function, the function will
27 * be pushed onto the `fns` array**, allowing the plugin to be
28 * called at a later point by the `run` method.
31 * var use = require('use');
38 * var app = function(){};
47 * @param {Function} `fn` plugin function to call
51 define(app, 'use', use);
54 * Run all plugins on `fns`. Any plugin that returns a function
55 * when called by `use` is pushed onto the `fns` array.
62 * @param {Object} `value` Object to be modified by plugins.
63 * @return {Object} Returns the object passed to `run`
67 define(app, 'run', function(val) {
68 if (!isObject(val)) return;
70 if (!val.use || !val.run) {
71 define(val, prop, val[prop] || []);
72 define(val, 'use', use);
75 if (!val[prop] || val[prop].indexOf(base) === -1) {
79 var self = this || app;
91 * Call plugin `fn`. If a function is returned push it into the
92 * `fns` array to be called by the `run` method.
95 function use(type, fn, options) {
98 if (typeof type === 'string' || Array.isArray(type)) {
106 if (typeof fn !== 'function') {
107 throw new TypeError('expected a function');
110 var self = this || app;
111 var fns = self[prop];
113 var args = [].slice.call(arguments, offset);
116 if (typeof opts.hook === 'function') {
117 opts.hook.apply(self, args);
120 var val = fn.apply(self, args);
121 if (typeof val === 'function' && fns.indexOf(val) === -1) {
128 * Wrap a named plugin function so that it's only called on objects of the
131 * @param {String} `type`
132 * @param {Function} `fn` Plugin function
136 function wrap(type, fn) {
137 return function plugin() {
138 return this.type === type ? fn.apply(this, arguments) : plugin;
145 function isObject(val) {
146 return val && typeof val === 'object' && !Array.isArray(val);
149 function define(obj, key, val) {
150 Object.defineProperty(obj, key, {