1 |
|
2 | var Container, ModuleNotFound, construct, getArguments, runFactory, throwNotFound;
|
3 |
|
4 | ModuleNotFound = require('./ModuleNotFound');
|
5 |
|
6 | getArguments = require('./get-arguments');
|
7 |
|
8 | construct = function(c, args) {
|
9 | var F;
|
10 | F = (function() {
|
11 | function F() {
|
12 | c.apply(this, args);
|
13 | }
|
14 |
|
15 | return F;
|
16 |
|
17 | })();
|
18 | F.prototype = c.prototype;
|
19 | return new F();
|
20 | };
|
21 |
|
22 | runFactory = function(factory, args) {
|
23 | return factory.apply(null, args);
|
24 | };
|
25 |
|
26 | throwNotFound = function(name, parent) {
|
27 | throw new ModuleNotFound(name, parent);
|
28 | };
|
29 |
|
30 | module.exports = Container = (function() {
|
31 | function Container(conf, _parents) {
|
32 | if (conf == null) {
|
33 | conf = {};
|
34 | }
|
35 | this._parents = _parents != null ? _parents : [];
|
36 | this._modules = conf.modules || {};
|
37 | this._registrations = {};
|
38 | this._instances = {};
|
39 | }
|
40 |
|
41 | Container.prototype.factory = function(name, func) {
|
42 | if (!(func instanceof Function)) {
|
43 | throw new Error('A factory must be a function');
|
44 | }
|
45 | return this._register('factory', name, func);
|
46 | };
|
47 |
|
48 | Container.prototype.value = function(name, value) {
|
49 | return this._register('value', name, value);
|
50 | };
|
51 |
|
52 | Container.prototype["class"] = function(name, constructor) {
|
53 | if (!(constructor instanceof Function)) {
|
54 | throw new TypeError('A constructor must be a function');
|
55 | }
|
56 | return this._register('class', name, constructor);
|
57 | };
|
58 |
|
59 | Container.prototype.get = function(name) {
|
60 | var registeredAt;
|
61 | if (!this.isRegistered(name)) {
|
62 | throwNotFound(name);
|
63 | }
|
64 | registeredAt = this._registeredAt(name);
|
65 | if (registeredAt === 'local') {
|
66 | if (!this._isInstantiated(name)) {
|
67 | this._instantiate(name);
|
68 | }
|
69 | return this._instances[name];
|
70 | } else {
|
71 | return this._parents[registeredAt].get(name);
|
72 | }
|
73 | };
|
74 |
|
75 | Container.prototype._isInstantiated = function(name) {
|
76 | return Object.keys(this._instances).indexOf(name) !== -1;
|
77 | };
|
78 |
|
79 | Container.prototype._registeredAt = function(name) {
|
80 | var i, j, len, p, parentIndex, ref;
|
81 | if (this._registrations[name] != null) {
|
82 | return 'local';
|
83 | } else {
|
84 | ref = this._parents;
|
85 | for (i = j = 0, len = ref.length; j < len; i = ++j) {
|
86 | p = ref[i];
|
87 | if (p._registeredAt(name) != null) {
|
88 | parentIndex = i;
|
89 | }
|
90 | }
|
91 | return parentIndex;
|
92 | }
|
93 | };
|
94 |
|
95 | Container.prototype.isRegistered = function(name) {
|
96 | return this._registeredAt(name) !== void 0;
|
97 | };
|
98 |
|
99 | Container.prototype.getRegistrations = function() {
|
100 | var all, p;
|
101 | if (this._parents.length === 0) {
|
102 | return this._registrations;
|
103 | }
|
104 | all = (function() {
|
105 | var j, len, ref, results;
|
106 | ref = this._parents;
|
107 | results = [];
|
108 | for (j = 0, len = ref.length; j < len; j++) {
|
109 | p = ref[j];
|
110 | results.push(p.getRegistrations());
|
111 | }
|
112 | return results;
|
113 | }).call(this);
|
114 | all.push(this._registrations);
|
115 | return all.reduce(function(acc, item) {
|
116 | Object.keys(item).forEach(function(key) {
|
117 | return acc[key] = item[key];
|
118 | });
|
119 | return acc;
|
120 | }, {});
|
121 | };
|
122 |
|
123 | Container.prototype.getArguments = function(name) {
|
124 | if (this._modules[name] != null) {
|
125 | return this._modules[name];
|
126 | } else {
|
127 | return getArguments(this._registrations[name].value);
|
128 | }
|
129 | };
|
130 |
|
131 | Container.prototype.loadAll = function() {
|
132 | var j, len, p, ref;
|
133 | ref = this._parents;
|
134 | for (j = 0, len = ref.length; j < len; j++) {
|
135 | p = ref[j];
|
136 | p.loadAll();
|
137 | }
|
138 | return Object.keys(this._registrations).forEach((function(_this) {
|
139 | return function(name) {
|
140 | if (!_this._isInstantiated(name)) {
|
141 | return _this._instantiate(name);
|
142 | }
|
143 | };
|
144 | })(this));
|
145 | };
|
146 |
|
147 | Container.prototype.shutdown = function() {
|
148 | var j, len, p, ref, results;
|
149 | Object.keys(this._instances).forEach((function(_this) {
|
150 | return function(key) {
|
151 | var ref;
|
152 | return (ref = _this._instances[key]) != null ? typeof ref.__amendShutdown === "function" ? ref.__amendShutdown() : void 0 : void 0;
|
153 | };
|
154 | })(this));
|
155 | ref = this._parents;
|
156 | results = [];
|
157 | for (j = 0, len = ref.length; j < len; j++) {
|
158 | p = ref[j];
|
159 | results.push(p.shutdown());
|
160 | }
|
161 | return results;
|
162 | };
|
163 |
|
164 | Container.prototype._register = function(type, name, value) {
|
165 | return this._registrations[name] = {
|
166 | value: value,
|
167 | type: type
|
168 | };
|
169 | };
|
170 |
|
171 | Container.prototype._instantiate = function(name, parent) {
|
172 | var instance, module, type, value;
|
173 | module = this._registrations[name];
|
174 | if (module == null) {
|
175 | throwNotFound(name, parent);
|
176 | }
|
177 | type = module.type;
|
178 | value = module.value;
|
179 | instance = type === 'value' ? value : this._instantiateWithDependencies(name, value, type);
|
180 | this._instances[name] = instance;
|
181 | return instance;
|
182 | };
|
183 |
|
184 | Container.prototype._instantiateWithDependencies = function(name, value, type) {
|
185 | var args, dependencies;
|
186 | args = this.getArguments(name);
|
187 | dependencies = args.map((function(_this) {
|
188 | return function(depName) {
|
189 | var registeredAt;
|
190 | registeredAt = _this._registeredAt(depName);
|
191 | if (registeredAt === 'local') {
|
192 | if (_this._isInstantiated(depName)) {
|
193 | return _this._instances[depName];
|
194 | } else {
|
195 | return _this._instantiate(depName, name);
|
196 | }
|
197 | } else if (registeredAt != null) {
|
198 | return _this._parents[registeredAt].get(depName);
|
199 | } else {
|
200 | return throwNotFound(depName, name);
|
201 | }
|
202 | };
|
203 | })(this));
|
204 | if (type === 'factory') {
|
205 | return runFactory(value, dependencies);
|
206 | }
|
207 | if (type === 'class') {
|
208 | return construct(value, dependencies);
|
209 | }
|
210 | };
|
211 |
|
212 | return Container;
|
213 |
|
214 | })();
|