/
lube.js
125 lines (114 loc) · 3.87 KB
/
lube.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
'use strict';
var unsatisfiedRequirement = {
};
function insertRequires(instance, requireArray) {
for (var i = 0; i < requireArray.length; i++) {
if (!instance._components[requireArray[i]]) {
instance._components[requireArray[i]] = unsatisfiedRequirement;
}
}
}
function insertProvides(instance, name, promise, context, replace) {
if (!replace && (
instance._components[name] &&
instance._components[name] !== unsatisfiedRequirement
)
)
throw new Error('Plugin that provides ' + name + ' is already registered.');
instance._components[name] = { context: context, promise: promise };
}
function useOne(instance, plugin, replace) {
if (!plugin)
return;
insertRequires(instance, plugin.req);
insertProvides(
instance,
plugin.provides,
plugin.providePromise,
plugin.context,
replace
);
}
/**
* Simple container to provide a DI. All components are returned as promises.
* Lifecycle of components are handled by client application by nesting promises.
**/
module.exports = function (){
return {
_components: {},
/**
* Registeres a component to inject. If there is a component with the same name
* already registered and replaceIfExists is false, throws.
* @param {Object|Object[]} component - Definition of a component(s)
* @param {boolean} replaceIfExists - Specifies whether a component with the same name should be replaced with this one.
* @returns {Object} Container
**/
use: function use (component, replaceIfExists) {
if(component instanceof Array)
{
for(var i = 0; i < component.length; i++ )
{
useOne(this, component[i], replaceIfExists);
}
}
else
{
useOne(this, component, replaceIfExists);
}
return this;
},
/**
* Check whether all compontents have satisfied dependecies.
* @returns {Object} Container
**/
check: function check ()
{
//make sure no _plugin is unsatisfied requirement
for(var name in this._components){
if(this._components[name] === unsatisfiedRequirement)
{
throw new Error(name + ' hasn\'t been satisfied');
}
}
return this;
},
/**
* Returns all components with name matching the regular expression
* @param {Regex} nameRegex - regular expression to filter components
* @param {Object} lifecycleContainer - object that holds already resolved components
* @return {Promise[]} All matching components. If none of the components matches returns promise of an empty array.
**/
allComponents: function allComponents (nameRegex, lifecycleContainer){
var promises = [];
for(var name in this._components)
{
if(name.match(nameRegex))
{
promises.push(this.component(name, lifecycleContainer));
}
}
return Promise.all(promises);
},
/**
* Returns first component that matches the name
* @param {string} name - Component name to match
* @param {Object} lifecycleContainer - object that holds already resolved components
* @return {Promise} Matched component or throws
**/
component: function component (name, lifecycleContainer) //promise for registered component
{
if(!this._components[name])
throw new Error('Cant provide ' + name);
var component = this._components[name];
if (lifecycleContainer && lifecycleContainer[name])
{
//context already contains this component
return lifecycleContainer[name];
}
var componentPromise = component.promise.call(component.context || this, this);
if (lifecycleContainer)
lifecycleContainer[name] = componentPromise;
return componentPromise;
}
};
};