1
|
/*!
|
2
|
* use <https://github.com/jonschlinkert/use>
|
3
|
*
|
4
|
* Copyright (c) 2015-2017, Jon Schlinkert.
|
5
|
* Released under the MIT License.
|
6
|
*/
|
7
|
|
8
|
'use strict';
|
9
|
|
10
|
module.exports = function base(app, options) {
|
11
|
if (!isObject(app) && typeof app !== 'function') {
|
12
|
throw new TypeError('expected an object or function');
|
13
|
}
|
14
|
|
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, []);
|
19
|
}
|
20
|
|
21
|
/**
|
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.
|
25
|
*
|
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.
|
29
|
*
|
30
|
* ```js
|
31
|
* var use = require('use');
|
32
|
*
|
33
|
* // define a plugin
|
34
|
* function foo(app) {
|
35
|
* // do stuff
|
36
|
* }
|
37
|
*
|
38
|
* var app = function(){};
|
39
|
* use(app);
|
40
|
*
|
41
|
* // register plugins
|
42
|
* app.use(foo);
|
43
|
* app.use(bar);
|
44
|
* app.use(baz);
|
45
|
* ```
|
46
|
* @name .use
|
47
|
* @param {Function} `fn` plugin function to call
|
48
|
* @api public
|
49
|
*/
|
50
|
|
51
|
define(app, 'use', use);
|
52
|
|
53
|
/**
|
54
|
* Run all plugins on `fns`. Any plugin that returns a function
|
55
|
* when called by `use` is pushed onto the `fns` array.
|
56
|
*
|
57
|
* ```js
|
58
|
* var config = {};
|
59
|
* app.run(config);
|
60
|
* ```
|
61
|
* @name .run
|
62
|
* @param {Object} `value` Object to be modified by plugins.
|
63
|
* @return {Object} Returns the object passed to `run`
|
64
|
* @api public
|
65
|
*/
|
66
|
|
67
|
define(app, 'run', function(val) {
|
68
|
if (!isObject(val)) return;
|
69
|
|
70
|
if (!val.use || !val.run) {
|
71
|
define(val, prop, val[prop] || []);
|
72
|
define(val, 'use', use);
|
73
|
}
|
74
|
|
75
|
if (!val[prop] || val[prop].indexOf(base) === -1) {
|
76
|
val.use(base);
|
77
|
}
|
78
|
|
79
|
var self = this || app;
|
80
|
var fns = self[prop];
|
81
|
var len = fns.length;
|
82
|
var idx = -1;
|
83
|
|
84
|
while (++idx < len) {
|
85
|
val.use(fns[idx]);
|
86
|
}
|
87
|
return val;
|
88
|
});
|
89
|
|
90
|
/**
|
91
|
* Call plugin `fn`. If a function is returned push it into the
|
92
|
* `fns` array to be called by the `run` method.
|
93
|
*/
|
94
|
|
95
|
function use(type, fn, options) {
|
96
|
var offset = 1;
|
97
|
|
98
|
if (typeof type === 'string' || Array.isArray(type)) {
|
99
|
fn = wrap(type, fn);
|
100
|
offset++;
|
101
|
} else {
|
102
|
options = fn;
|
103
|
fn = type;
|
104
|
}
|
105
|
|
106
|
if (typeof fn !== 'function') {
|
107
|
throw new TypeError('expected a function');
|
108
|
}
|
109
|
|
110
|
var self = this || app;
|
111
|
var fns = self[prop];
|
112
|
|
113
|
var args = [].slice.call(arguments, offset);
|
114
|
args.unshift(self);
|
115
|
|
116
|
if (typeof opts.hook === 'function') {
|
117
|
opts.hook.apply(self, args);
|
118
|
}
|
119
|
|
120
|
var val = fn.apply(self, args);
|
121
|
if (typeof val === 'function' && fns.indexOf(val) === -1) {
|
122
|
fns.push(val);
|
123
|
}
|
124
|
return self;
|
125
|
}
|
126
|
|
127
|
/**
|
128
|
* Wrap a named plugin function so that it's only called on objects of the
|
129
|
* given `type`
|
130
|
*
|
131
|
* @param {String} `type`
|
132
|
* @param {Function} `fn` Plugin function
|
133
|
* @return {Function}
|
134
|
*/
|
135
|
|
136
|
function wrap(type, fn) {
|
137
|
return function plugin() {
|
138
|
return this.type === type ? fn.apply(this, arguments) : plugin;
|
139
|
};
|
140
|
}
|
141
|
|
142
|
return app;
|
143
|
};
|
144
|
|
145
|
function isObject(val) {
|
146
|
return val && typeof val === 'object' && !Array.isArray(val);
|
147
|
}
|
148
|
|
149
|
function define(obj, key, val) {
|
150
|
Object.defineProperty(obj, key, {
|
151
|
configurable: true,
|
152
|
writable: true,
|
153
|
value: val
|
154
|
});
|
155
|
}
|