-
Notifications
You must be signed in to change notification settings - Fork 21
/
plugin.js
146 lines (133 loc) · 4.13 KB
/
plugin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
var _plugins = [];
var _byName = {};
var _cache = {};
// Only support debug mode on browser and node, not web workers.
var isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
var isNode =
typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
var isDebug =
(isBrowser && document.location.search.includes('JS_PLUGIN_DEBUG')) ||
(isNode && process.env && process.env.JS_PLUGIN_DEBUG);
function _isFunc(o) {
return !!(o.constructor && o.call && o.apply);
}
function _get(obj, prop) {
var arr = prop.split('.');
for (var i = 0; i < arr.length; i++) {
if (!(arr[i] in obj)) return undefined;
obj = obj[arr[i]];
}
return obj;
}
function _has(obj, prop) {
var arr = prop.split('.');
for (var i = 0; i < arr.length; i++) {
if (!(arr[i] in obj)) return undefined;
obj = obj[arr[i]];
}
return true;
}
module.exports = {
config: {},
register: function (p) {
if (!p.name) {
console.log('Every plugin should have a name.');
console.log(p);
throw new Error('Every plugin should have a name.');
}
if (_byName[p.name]) {
throw new Error('Plugin "' + p.name + '" already exits.');
}
_cache = {};
_plugins = _plugins.slice();
var pos = _plugins.length;
_plugins.forEach((p2, i) => {
if (p2.deps && p2.deps.indexOf(p.name) >= 0) {
pos = Math.min(pos, i);
}
});
_plugins.splice(pos, 0, p);
_byName[p.name] = p;
if (p.initialize) {
p.initialize();
}
},
unregister: function (name) {
var p = _byName[name];
if (!p) throw new Error('Plugin "' + name + '" does\'t exist.');
var i = _plugins.indexOf(p);
if (i === -1)
throw new Error(
'Plugin "' +
name +
'" does\'t exist in _plugins but in _byName. This seems to be a bug of js-plugin.'
);
_cache = {};
delete _byName[name];
_plugins = _plugins.slice();
_plugins.splice(i, 1);
},
getPlugin: function (name) {
return _byName[name];
},
getPlugins: function (prop) {
if (!prop) {
prop = '.';
}
if (!_cache[prop]) {
_cache[prop] = _plugins.filter((p) => {
if (p.deps && p.deps.some((dep) => !_byName[dep])) {
// If deps not exist, then not load it.
const notExistDeps = p.deps.filter((dep) => !_byName[dep]);
console.log(
`Plugin ${p.name} is not loaded because its deps do not exist: ${notExistDeps}.`
);
return false;
}
return prop === '.' ? true : _has(p, prop);
});
}
return _cache[prop];
},
processRawPlugins: function (callback) {
// This method allows to process _plugins so that it could
// do some unified pre-process before application starts.
callback(_plugins);
_cache = {};
},
invoke: function (prop) {
var args = Array.prototype.slice.call(arguments, 1);
if (!prop) throw new Error('Invoke on plugin should have prop argument');
var noCall = /^!/.test(prop);
var throws = this.config.throws || /!$/.test(prop);
prop = prop.replace(/^!|!$/g, '');
var arr = prop.split('.');
arr.pop();
var obj = arr.join('.');
return this.getPlugins(prop).map(function (p) {
var method = _get(p, prop);
if (!_isFunc(method) || noCall) return method;
try {
isDebug && console.log('Before', p.name, prop, args);
return method.apply(_get(p, obj), args);
} catch (err) {
// When a plugin failed, doesn't break the app
console.log('Failed to invoke plugin: ' + p.name + '!' + prop);
if (throws) throw err;
else console.log(err);
} finally {
isDebug && console.log('After ', p.name, prop, args);
}
return null;
});
},
sort: function (arr, sortProp) {
// A helper method to sort an array according to 'order' (or by sortProp) property of the array element.
sortProp = sortProp || 'order';
arr.sort((a, b) => {
var order1 = a.hasOwnProperty(sortProp) ? a[sortProp] : 1000000;
var order2 = b.hasOwnProperty(sortProp) ? b[sortProp] : 1000000;
return order1 - order2;
});
}
};