1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | const reflect_1 = require("./reflect");
|
7 | const debug_1 = __importDefault(require("debug"));
|
8 | const promiseHelpers_1 = require("./promiseHelpers");
|
9 | const events_1 = require("events");
|
10 | var log = debug_1.default('akala:core:injector');
|
11 | function ctorToFunction() {
|
12 | var args = [null];
|
13 | for (var i = 0; i < arguments.length; i++)
|
14 | args[i + 1] = arguments[i];
|
15 | return new (Function.prototype.bind.apply(this, args));
|
16 | }
|
17 | class Injector {
|
18 | constructor(parent) {
|
19 | this.parent = parent;
|
20 | this.notifier = new events_1.EventEmitter();
|
21 | this.inspecting = false;
|
22 | this.browsingForJSON = false;
|
23 | this.injectables = {};
|
24 | if (this.parent == null)
|
25 | this.parent = exports.defaultInjector;
|
26 | this.register('$injector', this);
|
27 | }
|
28 | setInjectables(value) {
|
29 | this.injectables = value;
|
30 | }
|
31 | keys() {
|
32 | return Object.keys(this.injectables);
|
33 | }
|
34 | merge(i) {
|
35 | var self = this;
|
36 | Object.getOwnPropertyNames(i.injectables).forEach(function (property) {
|
37 | if (property != '$injector')
|
38 | self.registerDescriptor(property, Object.getOwnPropertyDescriptor(i.injectables, property));
|
39 | });
|
40 | }
|
41 | notify(name, value) {
|
42 | if (typeof value == 'undefined')
|
43 | value = Object.getOwnPropertyDescriptor(this.injectables, name);
|
44 | if (this.notifier.listenerCount(name) > 0)
|
45 | this.notifier.emit(name, value);
|
46 | if (this.parent)
|
47 | this.parent.notify(name, value);
|
48 | }
|
49 | onResolve(name, handler) {
|
50 | if (!handler)
|
51 | return new Promise((resolve, reject) => {
|
52 | this.onResolve(name, resolve);
|
53 | });
|
54 | var value = this.resolve(name);
|
55 | if (value !== undefined && value !== null) {
|
56 | handler(value);
|
57 | return;
|
58 | }
|
59 | this.notifier.once(name, (prop) => {
|
60 | if (prop.get)
|
61 | handler(prop.get());
|
62 | else
|
63 | handler(prop.value);
|
64 | });
|
65 | if (this.parent)
|
66 | this.parent.onResolve(name, handler);
|
67 | }
|
68 | inject(a, ...b) {
|
69 | if (typeof a == 'function')
|
70 | return this.injectWithName(a['$inject'] || reflect_1.getParamNames(a), a);
|
71 | var self = this;
|
72 | return function (c) {
|
73 | if (typeof b == 'undefined')
|
74 | b = [];
|
75 | b.unshift(a);
|
76 | var oldf = self.injectWithName(b, c.value);
|
77 | c.value = function () {
|
78 | return oldf.apply(this, arguments);
|
79 | };
|
80 | };
|
81 | }
|
82 | injectAsync(a, ...b) {
|
83 | if (typeof a == 'function')
|
84 | return this.injectWithNameAsync(a['$inject'] || reflect_1.getParamNames(a), a);
|
85 | if (typeof b == 'undefined')
|
86 | b = [];
|
87 | b.unshift(a);
|
88 | var self = this;
|
89 | return function (c) {
|
90 | var f = c.value;
|
91 | c.value = function () {
|
92 | return self.injectWithNameAsync(b, f);
|
93 | };
|
94 | };
|
95 | }
|
96 | injectNew(ctor) {
|
97 | return this.inject(ctorToFunction.bind(ctor));
|
98 | }
|
99 | resolve(param) {
|
100 | log('resolving ' + param);
|
101 | if (typeof (this.injectables[param]) != 'undefined') {
|
102 | log(`resolved ${param}`);
|
103 | log.extend('verbose')(`resolved ${param} to ${this.injectables[param]}`);
|
104 | return this.injectables[param];
|
105 | }
|
106 | var indexOfDot = param.indexOf('.');
|
107 | if (~indexOfDot) {
|
108 | var keys = param.split('.');
|
109 | return keys.reduce((result, key, i) => {
|
110 | if (result instanceof Proxy)
|
111 | return result[key];
|
112 | if (result instanceof Injector)
|
113 | return result.resolve(key);
|
114 | if (promiseHelpers_1.isPromiseLike(result))
|
115 | return result.then((result) => { return result[key]; });
|
116 | if (result === this.injectables && typeof (result[key]) == 'undefined' && this.parent) {
|
117 | return this.parent.resolve(key);
|
118 | }
|
119 | return result && result[key];
|
120 | }, this.injectables);
|
121 | }
|
122 | if (this.parent) {
|
123 | log('trying parent injector');
|
124 | return this.parent.resolve(param);
|
125 | }
|
126 | return null;
|
127 | }
|
128 | resolveAsync(name) {
|
129 | return this.onResolve(name);
|
130 | log('resolving ' + name);
|
131 | if (typeof (this.injectables[name]) != 'undefined') {
|
132 | log('resolved ' + name + ' to %o', this.injectables[name]);
|
133 | return this.injectables[name];
|
134 | }
|
135 | if (this.parent) {
|
136 | log('trying parent injector');
|
137 | return this.parent.resolveAsync(name);
|
138 | }
|
139 | return this.onResolve(name);
|
140 | }
|
141 | inspect() {
|
142 | if (this.inspecting)
|
143 | return;
|
144 | this.inspecting = true;
|
145 | console.log(this.injectables);
|
146 | this.inspecting = false;
|
147 | }
|
148 | toJSON() {
|
149 | console.log(arguments);
|
150 | var wasBrowsingForJSON = this.browsingForJSON;
|
151 | this.browsingForJSON = true;
|
152 | if (!wasBrowsingForJSON)
|
153 | return this.injectables;
|
154 | this.browsingForJSON = wasBrowsingForJSON;
|
155 | return undefined;
|
156 | }
|
157 | injectNewWithName(toInject, ctor) {
|
158 | return this.injectWithName(toInject, ctorToFunction.bind(ctor));
|
159 | }
|
160 | injectWithNameAsync(toInject, a) {
|
161 | if (!toInject || toInject.length == 0)
|
162 | return Promise.resolve(a());
|
163 | var paramNames = reflect_1.getParamNames(a);
|
164 | var self = this;
|
165 | var wait = false;
|
166 | return new Promise((resolve, reject) => {
|
167 | if (paramNames.length == toInject.length || paramNames.length == 0) {
|
168 | if (toInject.length == paramNames.length && paramNames.length == 0)
|
169 | resolve(a.call(null));
|
170 | else {
|
171 | var args = [];
|
172 | for (var param of toInject) {
|
173 | args[args.length] = self.resolveAsync(param);
|
174 | if (promiseHelpers_1.isPromiseLike(args[args.length - 1]))
|
175 | wait = true;
|
176 | }
|
177 | if (wait)
|
178 | return Promise.all(args.map(function (v) {
|
179 | if (promiseHelpers_1.isPromiseLike(v))
|
180 | return v;
|
181 | return Promise.resolve(v);
|
182 | })).then((args) => { resolve(a.apply(null, args)); });
|
183 | else
|
184 | resolve(a.apply(null, args));
|
185 | }
|
186 | }
|
187 | else
|
188 | reject('the number of arguments does not match the number of injected parameters');
|
189 | });
|
190 | }
|
191 | injectWithName(toInject, a) {
|
192 | var self = this;
|
193 | if (toInject && toInject.length > 0) {
|
194 | var paramNames = reflect_1.getParamNames(a);
|
195 | if (paramNames.length == toInject.length || paramNames.length == 0) {
|
196 | if (toInject.length == paramNames.length && paramNames.length == 0)
|
197 | return a;
|
198 | return function (instance) {
|
199 | var args = [];
|
200 | for (var param of toInject) {
|
201 | args[args.length] = self.resolve(param);
|
202 | }
|
203 | return a.apply(instance, args);
|
204 | };
|
205 | }
|
206 | }
|
207 | return function (instance, ...otherArgs) {
|
208 | var args = [];
|
209 | var unknownArgIndex = 0;
|
210 | for (var param of toInject) {
|
211 | var resolved = self.resolve(param);
|
212 | if (resolved && paramNames && paramNames.indexOf(param) == args.length)
|
213 | args[args.length] = resolved;
|
214 | else if (typeof (otherArgs[unknownArgIndex]) != 'undefined')
|
215 | args[args.length] = otherArgs[unknownArgIndex++];
|
216 | else
|
217 | args[args.length] = resolved;
|
218 | }
|
219 | if (otherArgs && otherArgs.length > unknownArgIndex) {
|
220 | args.concat(otherArgs.slice(unknownArgIndex));
|
221 | }
|
222 | return a.apply(instance, args);
|
223 | };
|
224 | }
|
225 | exec(...toInject) {
|
226 | var self = this;
|
227 | return function (f) {
|
228 | return self.injectWithName(toInject, f)(this);
|
229 | };
|
230 | }
|
231 | unregister(name) {
|
232 | var registration = Object.getOwnPropertyDescriptor(this.injectables, name);
|
233 | if (registration)
|
234 | delete this.injectables[name];
|
235 | }
|
236 | register(name, value, override) {
|
237 | if (typeof (value) != 'undefined' && value !== null)
|
238 | this.registerDescriptor(name, { value: value, enumerable: true, configurable: true }, override);
|
239 | return value;
|
240 | }
|
241 | registerFactory(name, value, override) {
|
242 | this.register(name + 'Factory', value, override);
|
243 | this.registerDescriptor(name, {
|
244 | get: function () {
|
245 | return value();
|
246 | }, enumerable: true, configurable: true
|
247 | }, override);
|
248 | return value;
|
249 | }
|
250 | factory(name, override) {
|
251 | var inj = this;
|
252 | return function (fact) {
|
253 | return inj.registerFactory(name, fact, override);
|
254 | };
|
255 | }
|
256 | service(name, override, ...toInject) {
|
257 | var inj = this;
|
258 | var singleton;
|
259 | if (typeof toInject == 'undefined')
|
260 | toInject = [];
|
261 | if (typeof override == 'string') {
|
262 | toInject.unshift(override);
|
263 | override = false;
|
264 | }
|
265 | return function (fact) {
|
266 | inj.registerDescriptor(name, {
|
267 | get() {
|
268 | if (singleton)
|
269 | return singleton;
|
270 | return singleton = inj.injectNewWithName(toInject, fact)();
|
271 | }
|
272 | });
|
273 | };
|
274 | }
|
275 | registerDescriptor(name, value, override) {
|
276 | log('registering ' + name);
|
277 | if (!override && typeof (this.injectables[name]) != 'undefined')
|
278 | throw new Error('There is already a registered item for ' + name);
|
279 | if (typeof (this.injectables[name]) !== 'undefined')
|
280 | this.unregister(name);
|
281 | Object.defineProperty(this.injectables, name, value);
|
282 | this.notify(name, value);
|
283 | }
|
284 | }
|
285 | exports.Injector = Injector;
|
286 | exports.defaultInjector = new Injector();
|
287 |
|
\ | No newline at end of file |