proxydi 0.0.12 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,38 @@
1
+ const injectableClasses = {};
2
+ const constructorInjections = {};
3
+ function injectable(dependencyOrDependencies, autoInjecions) {
4
+ return function (value, context) {
5
+ if ((context === null || context === undefined ? undefined : context.kind) !== 'class') {
6
+ throw new Error('@injectable decorator should decorate classes');
7
+ }
8
+ const name = dependencyOrDependencies
9
+ ? Array.isArray(dependencyOrDependencies)
10
+ ? context.name
11
+ : dependencyOrDependencies
12
+ : context.name;
13
+ const injectToConstructor = dependencyOrDependencies
14
+ ? Array.isArray(dependencyOrDependencies)
15
+ ? dependencyOrDependencies
16
+ : autoInjecions
17
+ : autoInjecions;
18
+ if (injectableClasses[name]) {
19
+ throw new Error(`ProxyDi has already regisered dependency ${String(name)} by @injectable`);
20
+ }
21
+ injectableClasses[name] = value;
22
+ if (injectToConstructor) {
23
+ constructorInjections[name] = injectToConstructor;
24
+ }
25
+ };
26
+ }
27
+ function findInjectableId(injectable) {
28
+ for (const [id, DependencyClass] of Object.entries(injectableClasses)) {
29
+ if (DependencyClass === injectable) {
30
+ return id;
31
+ }
32
+ }
33
+ throw new Error(`Class is not @injectable: ${injectable.name}`);
34
+ }
35
+
1
36
  const INJECTIONS = Symbol('injections');
2
37
  /**
3
38
  * This symbol constant defines a property name.
@@ -26,7 +61,11 @@ const IS_INSTANCE_PROXY = Symbol('isInstanceProxy');
26
61
  const inject = (dependencyId) => {
27
62
  return function (_value, context) {
28
63
  if ((context === null || context === undefined ? undefined : context.kind) === 'field') {
29
- const id = dependencyId ? dependencyId : context.name;
64
+ const id = dependencyId
65
+ ? typeof dependencyId === 'function'
66
+ ? findInjectableId(dependencyId)
67
+ : dependencyId
68
+ : context.name;
30
69
  const injection = {
31
70
  property: context.name,
32
71
  dependencyId: id,
@@ -45,41 +84,6 @@ const inject = (dependencyId) => {
45
84
  };
46
85
  };
47
86
 
48
- const injectableClasses = {};
49
- const constructorInjections = {};
50
- function injectable(dependencyOrDependencies, autoInjecions) {
51
- return function (value, context) {
52
- if ((context === null || context === undefined ? undefined : context.kind) !== 'class') {
53
- throw new Error('@injectable decorator should decorate classes');
54
- }
55
- const name = dependencyOrDependencies
56
- ? Array.isArray(dependencyOrDependencies)
57
- ? context.name
58
- : dependencyOrDependencies
59
- : context.name;
60
- const injectToConstructor = dependencyOrDependencies
61
- ? Array.isArray(dependencyOrDependencies)
62
- ? dependencyOrDependencies
63
- : autoInjecions
64
- : autoInjecions;
65
- if (injectableClasses[name]) {
66
- throw new Error(`ProxyDi has already regisered dependency ${String(name)} by @injectable`);
67
- }
68
- injectableClasses[name] = value;
69
- if (injectToConstructor) {
70
- constructorInjections[name] = injectToConstructor;
71
- }
72
- };
73
- }
74
- function findInjectableId(injectable) {
75
- for (const [id, DependencyClass] of Object.entries(injectableClasses)) {
76
- if (DependencyClass === injectable) {
77
- return id;
78
- }
79
- }
80
- throw new Error(`Class is not @injectable: ${injectable.name}`);
81
- }
82
-
83
87
  const DEFAULT_SETTINGS = {
84
88
  allowRegisterAnything: false,
85
89
  allowRewriteDependencies: false,
@@ -126,6 +130,7 @@ const makeInjectionProxy = (injection, injectionOwner, container) => {
126
130
  },
127
131
  });
128
132
  };
133
+
129
134
  function makeDependencyProxy(dependency) {
130
135
  const injectionValues = {};
131
136
  return new Proxy(dependency, {
@@ -146,18 +151,9 @@ function makeDependencyProxy(dependency) {
146
151
  }
147
152
 
148
153
  function makeConstructorDependencyProxy(container, dependencyId) {
149
- // let values: Record<string | symbol, any> = {};
150
- // let wasResolved = false;
151
154
  function getDependency() {
152
155
  if (container.isKnown(dependencyId)) {
153
156
  const dependency = container.resolve(dependencyId);
154
- // if (!wasResolved) {
155
- // for (const key in values) {
156
- // dependency[key] = values[key];
157
- // }
158
- // values = {};
159
- // wasResolved = true;
160
- // }
161
157
  return dependency;
162
158
  }
163
159
  else {
@@ -166,20 +162,12 @@ function makeConstructorDependencyProxy(container, dependencyId) {
166
162
  }
167
163
  return new Proxy({}, {
168
164
  get: function (target, prop, receiver) {
169
- // if (values[prop]) {
170
- // return values[prop];
171
- // }
172
165
  const dependency = getDependency();
173
166
  return Reflect.get(dependency, prop, receiver);
174
167
  },
175
168
  set: function (_target, prop, value) {
176
- // if (!container.isKnown(dependencyId)) {
177
- // values[prop] = value;
178
- // return true;
179
- // } else {
180
169
  const dependency = getDependency();
181
170
  return Reflect.set(dependency, prop, value);
182
- //}
183
171
  },
184
172
  has: function (_target, prop) {
185
173
  const dependency = getDependency();
@@ -202,56 +190,73 @@ function middleware() {
202
190
  };
203
191
  }
204
192
 
205
- class MiddlewareListener {
193
+ class MiddlewareManager {
206
194
  constructor(parent) {
207
195
  this.parent = parent;
208
- this.listeners = {
196
+ this.handlers = {
209
197
  register: [],
210
198
  remove: [],
199
+ resolve: [],
211
200
  };
212
201
  }
213
202
  add(middleware) {
214
- if (isRegistingMiddleware(middleware)) {
203
+ if (isRegistrator(middleware)) {
215
204
  middleware.onRegister && this.on('register', middleware.onRegister);
216
205
  }
217
- if (isRemovingMiddleware(middleware)) {
206
+ if (isRemover(middleware)) {
218
207
  middleware.onRemove && this.on('remove', middleware.onRemove);
219
208
  }
209
+ if (isResolver(middleware)) {
210
+ middleware.onResolve && this.on('resolve', middleware.onResolve);
211
+ }
220
212
  }
221
213
  remove(middleware) {
222
- if (isRegistingMiddleware(middleware)) {
214
+ if (isRegistrator(middleware)) {
223
215
  middleware.onRegister &&
224
216
  this.off('register', middleware.onRegister);
225
217
  }
226
- if (isRemovingMiddleware(middleware)) {
218
+ if (isRemover(middleware)) {
227
219
  middleware.onRemove && this.off('remove', middleware.onRemove);
228
220
  }
221
+ if (isResolver(middleware)) {
222
+ middleware.onResolve && this.off('resolve', middleware.onResolve);
223
+ }
229
224
  }
230
225
  on(event, listener) {
231
- this.listeners[event].push(listener);
226
+ this.handlers[event].push(listener);
232
227
  }
233
- onRegister(container, dependencyId, dependency) {
228
+ onRegister(context) {
234
229
  var _a;
235
- this.listeners.register.forEach((listener) => listener(container, dependencyId, dependency));
236
- (_a = this.parent) === null || _a === undefined ? undefined : _a.onRegister(container, dependencyId, dependency);
230
+ this.handlers.register.forEach((listener) => listener(context));
231
+ (_a = this.parent) === null || _a === undefined ? undefined : _a.onRegister(context);
237
232
  }
238
- onRemove(container, dependencyId) {
233
+ onRemove(context) {
239
234
  var _a;
240
- this.listeners.remove.forEach((listener) => listener(container, dependencyId));
241
- (_a = this.parent) === null || _a === undefined ? undefined : _a.onRemove(container, dependencyId);
235
+ this.handlers.remove.forEach((listener) => listener(context));
236
+ (_a = this.parent) === null || _a === undefined ? undefined : _a.onRemove(context);
237
+ }
238
+ onResolve(context) {
239
+ let result = context;
240
+ this.handlers.resolve.forEach((listener) => {
241
+ result = listener(result);
242
+ });
243
+ return result;
242
244
  }
243
245
  off(event, listener) {
244
- const index = this.listeners[event].indexOf(listener);
246
+ const index = this.handlers[event].indexOf(listener);
245
247
  if (index !== -1) {
246
- this.listeners[event].splice(index, 1);
248
+ this.handlers[event].splice(index, 1);
247
249
  }
248
250
  }
249
251
  }
250
- function isRegistingMiddleware(middleware) {
251
- return middleware.onRegister;
252
+ function isRegistrator(middleware) {
253
+ return !!middleware.onRegister;
252
254
  }
253
- function isRemovingMiddleware(middleware) {
254
- return middleware.onRemove;
255
+ function isRemover(middleware) {
256
+ return !!middleware.onRemove;
257
+ }
258
+ function isResolver(middleware) {
259
+ return !!middleware.onResolve;
255
260
  }
256
261
 
257
262
  /**
@@ -272,26 +277,63 @@ class ProxyDiContainer {
272
277
  /**
273
278
  * Holds proxies for dependencies registered in parent containers to provide for it dependencies from this container
274
279
  */
275
- this.parentDependencyProxies = {};
280
+ this.inContextProxies = {};
281
+ this.resolveImpl = (dependencyId) => {
282
+ const proxy = this.inContextProxies[dependencyId];
283
+ if (proxy) {
284
+ return proxy;
285
+ }
286
+ const instance = this.findDependency(dependencyId);
287
+ if (instance) {
288
+ if (instance[PROXYDI_CONTAINER] !== this &&
289
+ typeof instance === 'object' &&
290
+ this.settings.resolveInContainerContext) {
291
+ const proxy = makeDependencyProxy(instance);
292
+ this.injectDependenciesTo(proxy);
293
+ this.inContextProxies[dependencyId] = proxy;
294
+ return proxy;
295
+ }
296
+ return instance;
297
+ }
298
+ const InjectableClass = injectableClasses[dependencyId];
299
+ return this.register(InjectableClass, dependencyId);
300
+ };
276
301
  this.id = ProxyDiContainer.idCounter++;
277
- this.middlewareListener = new MiddlewareListener(parent === null || parent === undefined ? undefined : parent.middlewareListener);
302
+ this.middlewareManager = new MiddlewareManager(parent === null || parent === undefined ? undefined : parent.middlewareManager);
278
303
  if (parent) {
279
304
  this.parent = parent;
280
305
  this.parent.addChild(this);
281
306
  }
282
307
  this.settings = Object.assign(Object.assign({}, DEFAULT_SETTINGS), settings);
283
308
  }
284
- register(dependency, dependencyId) {
309
+ registerMiddleware(middleware) {
310
+ this.middlewareManager.add(middleware);
311
+ }
312
+ removeMiddleware(middleware) {
313
+ this.middlewareManager.remove(middleware);
314
+ }
315
+ register(dependency, dependecyId) {
285
316
  var _a;
286
- if (this.dependencies[dependencyId]) {
317
+ let id = dependecyId;
318
+ if (!id) {
319
+ if (typeof dependency === 'function') {
320
+ try {
321
+ id = findInjectableId(dependency);
322
+ }
323
+ catch (_b) {
324
+ id = dependency.name;
325
+ }
326
+ }
327
+ }
328
+ if (this.dependencies[id]) {
287
329
  if (!this.settings.allowRewriteDependencies) {
288
- throw new Error(`ProxyDi already has dependency for ${String(dependencyId)}`);
330
+ throw new Error(`ProxyDi already has dependency for ${String(id)}`);
289
331
  }
290
332
  }
291
333
  let instance;
292
334
  const isClass = typeof dependency === 'function';
293
335
  if (isClass) {
294
- instance = this.createInstance(dependency, dependencyId);
336
+ instance = this.createInstance(dependency, id);
295
337
  }
296
338
  else {
297
339
  instance = dependency;
@@ -302,15 +344,20 @@ class ProxyDiContainer {
302
344
  }
303
345
  if (isObject) {
304
346
  instance[PROXYDI_CONTAINER] = this;
305
- instance[DEPENDENCY_ID] = dependencyId;
347
+ instance[DEPENDENCY_ID] = id;
306
348
  }
307
349
  this.injectDependenciesTo(instance);
308
- this.dependencies[dependencyId] = instance;
350
+ this.dependencies[id] = instance;
309
351
  const constructorName = (_a = instance.constructor) === null || _a === undefined ? undefined : _a.name;
310
352
  if (constructorName && middlewaresClasses[constructorName]) {
311
- this.middlewareListener.add(instance);
353
+ this.middlewareManager.add(instance);
312
354
  }
313
- this.middlewareListener.onRegister(this, dependencyId, instance);
355
+ let context = {
356
+ container: this,
357
+ dependencyId: id,
358
+ dependency: instance,
359
+ };
360
+ this.middlewareManager.onRegister(context);
314
361
  return instance;
315
362
  }
316
363
  createInstance(Dependency, dependencyId) {
@@ -328,37 +375,32 @@ class ProxyDiContainer {
328
375
  * @returns True if the dependency is known, false otherwise.
329
376
  */
330
377
  isKnown(dependencyId) {
331
- return !!(this.parentDependencyProxies[dependencyId] ||
378
+ return !!(this.inContextProxies[dependencyId] ||
332
379
  this.dependencies[dependencyId] ||
333
380
  (this.parent && this.parent.isKnown(dependencyId)) ||
334
381
  injectableClasses[dependencyId]);
335
382
  }
336
383
  resolve(dependency) {
337
384
  if (typeof dependency === 'function') {
338
- const id = findInjectableId(dependency);
385
+ let id;
386
+ try {
387
+ id = findInjectableId(dependency);
388
+ }
389
+ catch (_a) {
390
+ id = dependency.name;
391
+ }
339
392
  return this.resolve(id);
340
393
  }
341
394
  if (!this.isKnown(dependency)) {
342
395
  throw new Error(`Can't resolve unknown dependency: ${String(dependency)}`);
343
396
  }
344
- const proxy = this.parentDependencyProxies[dependency];
345
- if (proxy) {
346
- return proxy;
347
- }
348
- const instance = this.findDependency(dependency);
349
- if (instance) {
350
- if (instance[PROXYDI_CONTAINER] !== this &&
351
- typeof instance === 'object' &&
352
- this.settings.resolveInContainerContext) {
353
- const proxy = makeDependencyProxy(instance);
354
- this.injectDependenciesTo(proxy);
355
- this.parentDependencyProxies[dependency] = proxy;
356
- return proxy;
357
- }
358
- return instance;
359
- }
360
- const InjectableClass = injectableClasses[dependency];
361
- return this.register(InjectableClass, dependency);
397
+ let context = {
398
+ container: this,
399
+ dependencyId: dependency,
400
+ dependency: this.resolveImpl(dependency),
401
+ };
402
+ context = this.middlewareManager.onResolve(context);
403
+ return context.dependency;
362
404
  }
363
405
  /**
364
406
  * Injects dependencies to the given object based on its defined injections metadata. Does not affect the container.
@@ -418,7 +460,7 @@ class ProxyDiContainer {
418
460
  if (dependency) {
419
461
  const constructorName = (_a = dependency.constructor) === null || _a === undefined ? undefined : _a.name;
420
462
  if (constructorName && middlewaresClasses[constructorName]) {
421
- this.middlewareListener.remove(dependency);
463
+ this.middlewareManager.remove(dependency);
422
464
  }
423
465
  const dependencyInjects = dependency[INJECTIONS]
424
466
  ? dependency[INJECTIONS]
@@ -428,7 +470,11 @@ class ProxyDiContainer {
428
470
  });
429
471
  delete dependency[DEPENDENCY_ID];
430
472
  delete this.dependencies[id];
431
- this.middlewareListener.onRemove(this, id);
473
+ this.middlewareManager.onRemove({
474
+ container: this,
475
+ dependencyId: id,
476
+ dependency,
477
+ });
432
478
  }
433
479
  }
434
480
  /**