-
Notifications
You must be signed in to change notification settings - Fork 501
/
di.js
154 lines (117 loc) · 2.59 KB
/
di.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
147
148
149
150
151
152
153
154
/**
* Dependency injection
*
* @author Mohammad Fares <[email protected]>
*/
var path = require('path'),
_ = require('lodash');
/**
* Dependency injection
*/
function DI() {
/**
* Injected dependecies
* @type {Object}
*/
this._dependencies = {};
/**
* A wrapper proxy object to set traps
* @type {Proxy}
*/
this._proxy = new Proxy(this, {
get: this.getHandler,
set: this.setHandler
});
return this._proxy;
}
/**
* Trap for getting a property value
*
* @param {Object} target
* @param {String} key
* @return {*}
*/
DI.prototype.getHandler = function(target, key) {
if (key in target) {
return target[key];
}
if (key in target._dependencies) {
return target._dependencies[key];
}
};
/**
* Trap for setting a property value
*
* @param {Object} target
* @param {String} key
* @param {*} value
* @return {*}
*/
DI.prototype.setHandler = function(target, key, value) {
if (key in target) {
throw new Error(`It is not allowed to set '${key}'`);
}
target._dependencies[key] = value;
return true;
};
/**
* Require and set a package
*
* - Require the module
* - Add the module as depndency
* - Format the key as
* - Convert the moduleName to camelCase
* - Remove the extension
* - Resolve third party packages as the native `require`.
* - Resolve our own scripts with paths relative to
* the app's root path `require`.
*
* @param {String} moduleName
* @param {String} key (Optional) (Default: the moduleName camel cased)
*/
DI.prototype.require = function(moduleName, key) {
var parsedModuleName = path.parse(moduleName);
// Default value for key
if (typeof key == 'undefined') {
key = _.camelCase(parsedModuleName.name);
}
// Is not a third party package
if (parsedModuleName.dir != '') {
// Resolve the path to an absolute path
moduleName = path.resolve(this._getAppRootPath(), moduleName);
}
this._dependencies[key] = require(moduleName);
};
/**
* Inject a dependency
*
* @param {String} key
* @param {*} value
*/
DI.prototype.set = function(key, value) {
this[key] = value;
};
/**
* Get an injected dependency
*
* @param {String} key
* @return {*}
*/
DI.prototype.get = function(key) {
return this[key];
};
/**
* Get the root path of the app
*
* - Follow the module.parent.parent... etc until null
*
* @return {String}
*/
DI.prototype._getAppRootPath = function() {
var parent = module.parent;
while (parent.parent) {
parent = parent.parent;
}
return path.dirname(parent.filename);
};
module.exports = DI;