ts-ioc-container 59.0.0 → 60.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.
Files changed (55) hide show
  1. package/README.md +90 -11
  2. package/cjm/container/AutoResolveModule.js +1 -1
  3. package/cjm/container/Container.js +11 -17
  4. package/cjm/container/EmptyContainer.js +3 -7
  5. package/cjm/hooks/HookContext.js +1 -1
  6. package/cjm/hooks/hook.js +3 -2
  7. package/cjm/hooks/onConstruct.js +4 -4
  8. package/cjm/hooks/onConstructAsync.js +4 -4
  9. package/cjm/hooks/onContainerDisposed.js +4 -4
  10. package/cjm/index.js +10 -7
  11. package/cjm/injector/MetadataInjector.js +4 -4
  12. package/cjm/metadata/class.js +2 -2
  13. package/cjm/metadata/method.js +2 -2
  14. package/cjm/metadata/parameter.js +2 -2
  15. package/cjm/metadata/target.js +9 -0
  16. package/cjm/provider/Provider.js +12 -2
  17. package/cjm/registration/IRegistration.js +3 -1
  18. package/cjm/utils/ProxyRegistry.js +3 -1
  19. package/cjm/utils/basic.js +0 -4
  20. package/cjm/utils/errorHandler.js +3 -2
  21. package/esm/container/AutoResolveModule.js +1 -1
  22. package/esm/container/Container.js +11 -17
  23. package/esm/container/EmptyContainer.js +3 -7
  24. package/esm/hooks/HookContext.js +1 -1
  25. package/esm/hooks/hook.js +3 -2
  26. package/esm/hooks/onConstruct.js +2 -2
  27. package/esm/hooks/onConstructAsync.js +2 -2
  28. package/esm/hooks/onContainerDisposed.js +2 -2
  29. package/esm/index.js +7 -6
  30. package/esm/injector/MetadataInjector.js +4 -4
  31. package/esm/metadata/class.js +1 -1
  32. package/esm/metadata/method.js +1 -1
  33. package/esm/metadata/parameter.js +1 -1
  34. package/esm/metadata/target.js +6 -0
  35. package/esm/provider/Provider.js +12 -2
  36. package/esm/registration/IRegistration.js +2 -1
  37. package/esm/utils/ProxyRegistry.js +1 -0
  38. package/esm/utils/basic.js +0 -3
  39. package/esm/utils/errorHandler.js +3 -2
  40. package/package.json +1 -1
  41. package/typings/container/Container.d.ts +4 -6
  42. package/typings/container/EmptyContainer.d.ts +4 -6
  43. package/typings/container/IContainer.d.ts +6 -6
  44. package/typings/hooks/hook.d.ts +2 -2
  45. package/typings/hooks/onConstruct.d.ts +1 -3
  46. package/typings/hooks/onConstructAsync.d.ts +1 -1
  47. package/typings/hooks/onContainerDisposed.d.ts +1 -1
  48. package/typings/index.d.ts +8 -7
  49. package/typings/injector/MetadataInjector.d.ts +2 -2
  50. package/typings/metadata/target.d.ts +2 -0
  51. package/typings/provider/IProvider.d.ts +2 -1
  52. package/typings/provider/Provider.d.ts +3 -1
  53. package/typings/registration/IRegistration.d.ts +2 -1
  54. package/typings/utils/ProxyRegistry.d.ts +1 -0
  55. package/typings/utils/basic.d.ts +0 -1
package/README.md CHANGED
@@ -48,6 +48,7 @@ provider pipelines, aliases, and custom injector strategies.
48
48
  - [Visibility](#visibility) `visible`
49
49
  - [Alias](#alias) `asAlias`
50
50
  - [Decorator](#decorator) `decorate`
51
+ - [On resolve](#on-resolve) `onResolve`
51
52
  - [Registration](#registration) `@register`
52
53
  - [Token](#token) `bindTo`
53
54
  - [Scope](#scope) `scope`
@@ -2376,6 +2377,84 @@ describe('Decorator Pattern', () => {
2376
2377
 
2377
2378
  ```
2378
2379
 
2380
+ ### On resolve
2381
+
2382
+ Sometimes you don't want to change the dependency, only to react to it. Use the `onResolve(...)` pipe — it appends a `DependencyHook` that receives the resolved dependency and the resolving scope.
2383
+
2384
+ - `provider(onResolve((instance, scope) => tracker.track(instance)))`
2385
+
2386
+ Hooks run after the whole `decorate(...)` chain, so they always observe the fully decorated dependency, and their return value is ignored — `onResolve` can never swap the dependency out. They fire per resolution, which means a `singleton()` provider runs them only on the resolve that fills the cache.
2387
+
2388
+ ```typescript
2389
+ import 'reflect-metadata';
2390
+ import { Container, type IContainer, onResolve, register, Registration as R, singleton } from 'ts-ioc-container';
2391
+
2392
+ /**
2393
+ * Observability Domain - onResolve hooks
2394
+ *
2395
+ * `onResolve(...)` attaches side effects to a provider. Every time the provider
2396
+ * hands a dependency back, each hook is called with that dependency and the
2397
+ * resolving scope.
2398
+ *
2399
+ * Unlike `decorate(...)`, a hook cannot replace the dependency - its return
2400
+ * value is ignored. Use `decorate` to change what the caller gets, and
2401
+ * `onResolve` to react to what the caller got: tracking, metrics, registering
2402
+ * the instance with an external bus.
2403
+ *
2404
+ * Hooks always run after the whole `decorate` chain, so they observe the fully
2405
+ * decorated dependency no matter where `onResolve` sits in the pipe list.
2406
+ */
2407
+ describe('onResolve', () => {
2408
+ it('should observe every resolved dependency without changing it', () => {
2409
+ const resolved: Array<{ name: string; fromRequest: boolean }> = [];
2410
+
2411
+ const track = (dependency: unknown, scope: IContainer) => {
2412
+ resolved.push({ name: (dependency as Connection).name, fromRequest: scope.hasTag('request') });
2413
+ };
2414
+
2415
+ @register(onResolve(track))
2416
+ class Connection {
2417
+ readonly name = 'Connection';
2418
+ }
2419
+
2420
+ const app = new Container({ tags: ['application'] }).addRegistration(R.fromClass(Connection));
2421
+ const request = app.createScope({ tags: ['request'] });
2422
+
2423
+ const connection = request.resolve<Connection>('Connection');
2424
+
2425
+ // The caller still receives the untouched instance
2426
+ expect(connection).toBeInstanceOf(Connection);
2427
+ // ...and the hook saw it, together with the scope it was resolved from
2428
+ expect(resolved).toEqual([{ name: 'Connection', fromRequest: true }]);
2429
+ });
2430
+
2431
+ it('should run once for a singleton and on every resolve otherwise', () => {
2432
+ let poolCount = 0;
2433
+ let sessionCount = 0;
2434
+
2435
+ @register(singleton(), onResolve(() => poolCount++))
2436
+ class ConnectionPool {}
2437
+
2438
+ @register(onResolve(() => sessionCount++))
2439
+ class Session {}
2440
+
2441
+ const app = new Container({ tags: ['application'] })
2442
+ .addRegistration(R.fromClass(ConnectionPool))
2443
+ .addRegistration(R.fromClass(Session));
2444
+
2445
+ app.resolve('ConnectionPool');
2446
+ app.resolve('ConnectionPool');
2447
+ app.resolve('Session');
2448
+ app.resolve('Session');
2449
+
2450
+ // A singleton caches the dependency, so hooks fire on the resolve that filled the cache
2451
+ expect(poolCount).toBe(1);
2452
+ expect(sessionCount).toBe(2);
2453
+ });
2454
+ });
2455
+
2456
+ ```
2457
+
2379
2458
  ## Registration
2380
2459
 
2381
2460
  Registration is provider factory which registers provider in container.
@@ -2759,7 +2838,7 @@ runs `h1` before `h2`.
2759
2838
  ```typescript
2760
2839
  import 'reflect-metadata';
2761
2840
  import {
2762
- AddOnConstructHookModule,
2841
+ OnConstructModule,
2763
2842
  Container,
2764
2843
  type ExecutionContext,
2765
2844
  type HookFn,
@@ -2787,7 +2866,7 @@ describe('onConstruct', function () {
2787
2866
  }
2788
2867
 
2789
2868
  const container = new Container()
2790
- .useModule(new AddOnConstructHookModule())
2869
+ .useModule(new OnConstructModule())
2791
2870
  .addRegistration(R.fromValue('postgres://localhost:5432').bindTo('ConnectionString'));
2792
2871
 
2793
2872
  const db = container.resolve(DatabaseConnection);
@@ -2808,7 +2887,7 @@ describe('onConstruct', function () {
2808
2887
 
2809
2888
  let captured: { ex: unknown; context: ExecutionContext } | undefined;
2810
2889
  const container = new Container().useModule(
2811
- new AddOnConstructHookModule((ex, context) => {
2890
+ new OnConstructModule((ex, context) => {
2812
2891
  captured = { ex, context };
2813
2892
  }),
2814
2893
  );
@@ -2828,7 +2907,7 @@ describe('onConstruct', function () {
2828
2907
  init() {}
2829
2908
  }
2830
2909
 
2831
- const container = new Container().useModule(new AddOnConstructHookModule());
2910
+ const container = new Container().useModule(new OnConstructModule());
2832
2911
 
2833
2912
  expect(() => container.resolve(BrokenService)).toThrow(failure);
2834
2913
  });
@@ -2843,7 +2922,7 @@ describe('onConstruct', function () {
2843
2922
 
2844
2923
  let scope: IContainer | undefined;
2845
2924
  const container = new Container().useModule(
2846
- new AddOnConstructHookModule((_ex, context) => {
2925
+ new OnConstructModule((_ex, context) => {
2847
2926
  scope = context.scope;
2848
2927
  }),
2849
2928
  );
@@ -2860,13 +2939,13 @@ describe('onConstruct', function () {
2860
2939
  ### OnConstructAsync
2861
2940
 
2862
2941
  `@onConstructAsync` runs promise-returning initialization. Resolution stays
2863
- synchronous: `AddOnConstructAsyncHookModule` starts the hooks when the instance
2942
+ synchronous: `OnConstructAsyncModule` starts the hooks when the instance
2864
2943
  is created and they settle afterwards, so `resolve` returns before they finish.
2865
2944
 
2866
2945
  ```typescript
2867
2946
  import 'reflect-metadata';
2868
2947
  import {
2869
- AddOnConstructAsyncHookModule,
2948
+ OnConstructAsyncModule,
2870
2949
  Container,
2871
2950
  type ExecutionContext,
2872
2951
  type HookFn,
@@ -2904,7 +2983,7 @@ describe('onConstructAsync', function () {
2904
2983
  }
2905
2984
 
2906
2985
  const container = new Container()
2907
- .useModule(new AddOnConstructAsyncHookModule())
2986
+ .useModule(new OnConstructAsyncModule())
2908
2987
  .addRegistration(R.fromValue('postgres://localhost:5432').bindTo('ConnectionString'));
2909
2988
 
2910
2989
  const db = container.resolve(DatabaseConnection);
@@ -2928,7 +3007,7 @@ describe('onConstructAsync', function () {
2928
3007
 
2929
3008
  let captured: { ex: unknown; context: ExecutionContext } | undefined;
2930
3009
  const container = new Container().useModule(
2931
- new AddOnConstructAsyncHookModule((ex, context) => {
3010
+ new OnConstructAsyncModule((ex, context) => {
2932
3011
  captured = { ex, context };
2933
3012
  }),
2934
3013
  );
@@ -2950,7 +3029,7 @@ describe('onConstructAsync', function () {
2950
3029
  ```typescript
2951
3030
  import 'reflect-metadata';
2952
3031
  import {
2953
- AddOnDisposeHookModule,
3032
+ OnDisposeModule,
2954
3033
  bindTo,
2955
3034
  Container,
2956
3035
  type HookFn,
@@ -2993,7 +3072,7 @@ class Logger {
2993
3072
  describe('onContainerDisposed', function () {
2994
3073
  it('should invoke hooks on all instances when container is disposed', function () {
2995
3074
  const container = new Container()
2996
- .useModule(new AddOnDisposeHookModule())
3075
+ .useModule(new OnDisposeModule())
2997
3076
  .addRegistration(R.fromClass(Logger))
2998
3077
  .addRegistration(R.fromClass(LogsRepo));
2999
3078
 
@@ -7,7 +7,7 @@ class AutoResolveModule {
7
7
  this.options = options;
8
8
  }
9
9
  applyTo(container) {
10
- container.addOnScopeCreatedHook((scope) => scope.autoResolve(this.options));
10
+ container.onScopeCreated((scope) => scope.autoResolve(this.options));
11
11
  }
12
12
  }
13
13
  exports.AutoResolveModule = AutoResolveModule;
@@ -5,6 +5,7 @@ const EmptyContainer_1 = require("./EmptyContainer");
5
5
  const ContainerDisposedError_1 = require("../errors/ContainerDisposedError");
6
6
  const MetadataInjector_1 = require("../injector/MetadataInjector");
7
7
  const AliasMap_1 = require("./AliasMap");
8
+ const ProxyRegistry_1 = require("../utils/ProxyRegistry");
8
9
  const DependencyNotFoundError_1 = require("../errors/DependencyNotFoundError");
9
10
  const basic_1 = require("../utils/basic");
10
11
  const array_1 = require("../utils/array");
@@ -73,9 +74,9 @@ class Container {
73
74
  createScope({ tags } = {}) {
74
75
  this.validateContainer();
75
76
  const scope = new Container({ injector: this.injector, parent: this, tags })
76
- .addOnConstructHook(...this.onConstructHookList)
77
- .addOnDisposeHook(...this.onDisposeHookList)
78
- .addOnScopeCreatedHook(...this.onScopeCreatedHookList);
77
+ .onConstruct(...this.onConstructHookList)
78
+ .onInstanceDisposed(...this.onDisposeHookList)
79
+ .onScopeCreated(...this.onScopeCreatedHookList);
79
80
  for (const registration of this.getRegistrations()) {
80
81
  registration.applyTo(scope);
81
82
  }
@@ -97,9 +98,8 @@ class Container {
97
98
  dispose() {
98
99
  this.validateContainer();
99
100
  this.isDisposed = true;
100
- while (this.onDisposeHookList.length) {
101
- const onDispose = this.onDisposeHookList.shift();
102
- onDispose(this);
101
+ for (const hook of this.onDisposeHookList) {
102
+ hook(this);
103
103
  }
104
104
  this.parent.removeScope(this);
105
105
  this.parent = new EmptyContainer_1.EmptyContainer();
@@ -111,6 +111,7 @@ class Container {
111
111
  this.instances.clear();
112
112
  this.registrations = [];
113
113
  this.onConstructHookList.length = 0;
114
+ this.onDisposeHookList.length = 0;
114
115
  this.onScopeCreatedHookList.length = 0;
115
116
  }
116
117
  addRegistration(registration) {
@@ -124,15 +125,15 @@ class Container {
124
125
  hasRegistration(key) {
125
126
  return this.registrations.some((r) => r.getKeyOrFail() === key) || this.parent.hasRegistration(key);
126
127
  }
127
- addOnConstructHook(...hooks) {
128
+ onConstruct(...hooks) {
128
129
  this.onConstructHookList.push(...hooks);
129
130
  return this;
130
131
  }
131
- addOnDisposeHook(...hooks) {
132
+ onInstanceDisposed(...hooks) {
132
133
  this.onDisposeHookList.push(...hooks);
133
134
  return this;
134
135
  }
135
- addOnScopeCreatedHook(...hooks) {
136
+ onScopeCreated(...hooks) {
136
137
  this.onScopeCreatedHookList.push(...hooks);
137
138
  return this;
138
139
  }
@@ -146,14 +147,7 @@ class Container {
146
147
  return [...this.scopes];
147
148
  }
148
149
  hasInstance(instance) {
149
- return this.instances.has(instance);
150
- }
151
- getScopeByInstanceOrFail(instance) {
152
- this.validateContainer();
153
- if (this.hasInstance(instance)) {
154
- return this;
155
- }
156
- return this.parent.getScopeByInstanceOrFail(instance);
150
+ return this.instances.has((0, ProxyRegistry_1.unwrapProxy)(instance));
157
151
  }
158
152
  removeScope(child) {
159
153
  this.scopes = this.scopes.filter((s) => s !== child);
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EmptyContainer = void 0;
4
4
  const MethodNotImplementedError_1 = require("../errors/MethodNotImplementedError");
5
5
  const DependencyNotFoundError_1 = require("../errors/DependencyNotFoundError");
6
- const ContainerNotFoundError_1 = require("../errors/ContainerNotFoundError");
7
6
  class EmptyContainer {
8
7
  get isDisposed() {
9
8
  throw new MethodNotImplementedError_1.MethodNotImplementedError();
@@ -15,9 +14,6 @@ class EmptyContainer {
15
14
  getScopes() {
16
15
  return [];
17
16
  }
18
- getScopeByInstanceOrFail(instance) {
19
- throw new ContainerNotFoundError_1.ContainerNotFoundError('Cannot find scope for the given instance');
20
- }
21
17
  getInstances() {
22
18
  return [];
23
19
  }
@@ -64,13 +60,13 @@ class EmptyContainer {
64
60
  resolveOneByAlias(alias, options) {
65
61
  throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find alias ${alias.toString()}`);
66
62
  }
67
- addOnDisposeHook(...hooks) {
63
+ onInstanceDisposed(...hooks) {
68
64
  throw new MethodNotImplementedError_1.MethodNotImplementedError();
69
65
  }
70
- addOnConstructHook(...hooks) {
66
+ onConstruct(...hooks) {
71
67
  throw new MethodNotImplementedError_1.MethodNotImplementedError();
72
68
  }
73
- addOnScopeCreatedHook(...hooks) {
69
+ onScopeCreated(...hooks) {
74
70
  throw new MethodNotImplementedError_1.MethodNotImplementedError();
75
71
  }
76
72
  }
@@ -13,7 +13,7 @@ class HookContext {
13
13
  this.methodName = methodName;
14
14
  }
15
15
  resolveArgs(...args) {
16
- return (0, MetadataInjector_1.resolveArgs)(this.instance.constructor, this.methodName)(this.scope, {
16
+ return (0, MetadataInjector_1.resolveArgs)(this.instance, this.methodName)(this.scope, {
17
17
  args: [...this.initialArgs, ...args],
18
18
  });
19
19
  }
package/cjm/hooks/hook.js CHANGED
@@ -4,6 +4,7 @@ exports.hook = exports.toHookFn = exports.prepend = exports.append = exports.pre
4
4
  exports.getHooks = getHooks;
5
5
  exports.hasHooks = hasHooks;
6
6
  const basic_1 = require("../utils/basic");
7
+ const target_1 = require("../metadata/target");
7
8
  const appendHooks = (...fns) => (...prev) => [...prev, ...fns];
8
9
  exports.appendHooks = appendHooks;
9
10
  const prependHooks = (...fns) => (...prev) => [...fns, ...prev];
@@ -26,7 +27,7 @@ const getConstructorChain = (ctor) => {
26
27
  };
27
28
  function getHooks(target, key) {
28
29
  const merged = new Map();
29
- for (const ctor of getConstructorChain(target.constructor).reverse()) {
30
+ for (const ctor of getConstructorChain((0, target_1.resolveConstructor)(target)).reverse()) {
30
31
  const ownHooks = Reflect.getOwnMetadata(key, ctor);
31
32
  if (ownHooks) {
32
33
  for (const [methodName, fns] of ownHooks) {
@@ -37,7 +38,7 @@ function getHooks(target, key) {
37
38
  return merged;
38
39
  }
39
40
  function hasHooks(target, key) {
40
- return getConstructorChain(target.constructor).some((ctor) => Reflect.hasOwnMetadata(key, ctor));
41
+ return getConstructorChain((0, target_1.resolveConstructor)(target)).some((ctor) => Reflect.hasOwnMetadata(key, ctor));
41
42
  }
42
43
  const hook = (key, mapFn) => (target, propertyKey) => {
43
44
  const hooks = Reflect.hasOwnMetadata(key, target.constructor)
@@ -1,18 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = void 0;
3
+ exports.OnConstructModule = exports.onConstruct = exports.onConstructHooksRunner = void 0;
4
4
  const hook_1 = require("./hook");
5
5
  const HooksRunner_1 = require("./HooksRunner");
6
6
  exports.onConstructHooksRunner = new HooksRunner_1.HooksRunner('onConstruct');
7
7
  const onConstruct = (...fns) => (0, hook_1.hook)('onConstruct', (0, hook_1.prependHooks)(...fns));
8
8
  exports.onConstruct = onConstruct;
9
- class AddOnConstructHookModule {
9
+ class OnConstructModule {
10
10
  onException;
11
11
  constructor(onException) {
12
12
  this.onException = onException;
13
13
  }
14
14
  applyTo(container) {
15
- container.addOnConstructHook((instance, scope) => {
15
+ container.onConstruct((instance, scope) => {
16
16
  try {
17
17
  exports.onConstructHooksRunner.execute(instance, { scope });
18
18
  }
@@ -25,4 +25,4 @@ class AddOnConstructHookModule {
25
25
  });
26
26
  }
27
27
  }
28
- exports.AddOnConstructHookModule = AddOnConstructHookModule;
28
+ exports.OnConstructModule = OnConstructModule;
@@ -1,18 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AddOnConstructAsyncHookModule = exports.onConstructAsync = exports.onConstructAsyncHooksRunner = void 0;
3
+ exports.OnConstructAsyncModule = exports.onConstructAsync = exports.onConstructAsyncHooksRunner = void 0;
4
4
  const hook_1 = require("./hook");
5
5
  const HooksRunner_1 = require("./HooksRunner");
6
6
  exports.onConstructAsyncHooksRunner = new HooksRunner_1.HooksRunner('onConstructAsync');
7
7
  const onConstructAsync = (...fns) => (0, hook_1.hook)('onConstructAsync', (0, hook_1.prependHooks)(...fns));
8
8
  exports.onConstructAsync = onConstructAsync;
9
- class AddOnConstructAsyncHookModule {
9
+ class OnConstructAsyncModule {
10
10
  onException;
11
11
  constructor(onException) {
12
12
  this.onException = onException;
13
13
  }
14
14
  applyTo(container) {
15
- container.addOnConstructHook((instance, scope) => {
15
+ container.onConstruct((instance, scope) => {
16
16
  if (!exports.onConstructAsyncHooksRunner.hasHooks(instance)) {
17
17
  return;
18
18
  }
@@ -25,4 +25,4 @@ class AddOnConstructAsyncHookModule {
25
25
  });
26
26
  }
27
27
  }
28
- exports.AddOnConstructAsyncHookModule = AddOnConstructAsyncHookModule;
28
+ exports.OnConstructAsyncModule = OnConstructAsyncModule;
@@ -1,18 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AddOnDisposeHookModule = exports.onContainerDisposed = exports.onContainerDisposedHooksRunner = void 0;
3
+ exports.OnDisposeModule = exports.onContainerDisposed = exports.onContainerDisposedHooksRunner = void 0;
4
4
  const hook_1 = require("./hook");
5
5
  const HooksRunner_1 = require("./HooksRunner");
6
6
  exports.onContainerDisposedHooksRunner = new HooksRunner_1.HooksRunner('onContainerDisposed');
7
7
  const onContainerDisposed = (...fns) => (0, hook_1.hook)('onContainerDisposed', (0, hook_1.prependHooks)(...fns));
8
8
  exports.onContainerDisposed = onContainerDisposed;
9
- class AddOnDisposeHookModule {
9
+ class OnDisposeModule {
10
10
  applyTo(container) {
11
- container.addOnDisposeHook((scope) => {
11
+ container.onInstanceDisposed((scope) => {
12
12
  for (const instance of scope.getInstances()) {
13
13
  exports.onContainerDisposedHooksRunner.execute(instance, { scope });
14
14
  }
15
15
  });
16
16
  }
17
17
  }
18
- exports.AddOnDisposeHookModule = AddOnDisposeHookModule;
18
+ exports.OnDisposeModule = OnDisposeModule;
package/cjm/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createHookContext = exports.createHookContextFactory = exports.HookContext = exports.prepend = exports.append = exports.prependHooks = exports.appendHooks = exports.hasHooks = exports.hook = exports.getHooks = exports.UnsupportedTokenTypeError = exports.CannonSingletonApplyTwiceError = exports.UnexpectedHookResultError = exports.ProviderDisposedError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.ContainerNotFoundError = exports.DependencyNotFoundError = exports.ContainerError = exports.Registration = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.autoResolve = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.toRegistrationFn = exports.toProviderFn = exports.toBindToken = exports.registerPipe = exports.isProviderPipe = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.argsFn = exports.args = exports.arg = exports.inject = exports.MetadataInjector = exports.Injector = exports.EmptyContainer = exports.AutoResolveModule = exports.Container = exports.isDependencyKey = void 0;
4
- exports.pipe = exports.select = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.getClassMeta = exports.addClassMeta = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.argToToken = exports.toMappedToken = exports.toToken = exports.InjectionToken = exports.HooksRunner = exports.AddOnDisposeHookModule = exports.onContainerDisposed = exports.onContainerDisposedHooksRunner = exports.AddOnConstructAsyncHookModule = exports.onConstructAsync = exports.onConstructAsyncHooksRunner = exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = void 0;
5
- exports.resolveConstructor = exports.Is = exports.ProxyRegistry = void 0;
3
+ exports.createHookContextFactory = exports.HookContext = exports.prepend = exports.append = exports.prependHooks = exports.appendHooks = exports.hasHooks = exports.hook = exports.getHooks = exports.UnsupportedTokenTypeError = exports.CannonSingletonApplyTwiceError = exports.UnexpectedHookResultError = exports.ProviderDisposedError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.ContainerNotFoundError = exports.DependencyNotFoundError = exports.ContainerError = exports.Registration = exports.onResolve = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.autoResolve = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.toRegistrationFn = exports.toProviderFn = exports.toBindToken = exports.registerPipe = exports.isProviderPipe = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.argsFn = exports.args = exports.arg = exports.inject = exports.MetadataInjector = exports.Injector = exports.EmptyContainer = exports.AutoResolveModule = exports.Container = exports.isDependencyKey = void 0;
4
+ exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.getClassMeta = exports.addClassMeta = exports.resolveConstructor = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.argToToken = exports.toMappedToken = exports.toToken = exports.InjectionToken = exports.HooksRunner = exports.OnDisposeModule = exports.onContainerDisposed = exports.onContainerDisposedHooksRunner = exports.OnConstructAsyncModule = exports.onConstructAsync = exports.onConstructAsyncHooksRunner = exports.OnConstructModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = exports.createHookContext = void 0;
5
+ exports.Is = exports.unwrapProxy = exports.ProxyRegistry = exports.pipe = exports.select = void 0;
6
6
  var IContainer_1 = require("./container/IContainer");
7
7
  Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
8
8
  var Container_1 = require("./container/Container");
@@ -42,6 +42,7 @@ Object.defineProperty(exports, "singleton", { enumerable: true, get: function ()
42
42
  Object.defineProperty(exports, "decorate", { enumerable: true, get: function () { return IRegistration_1.decorate; } });
43
43
  Object.defineProperty(exports, "appendArgs", { enumerable: true, get: function () { return IRegistration_1.appendArgs; } });
44
44
  Object.defineProperty(exports, "appendArgsFn", { enumerable: true, get: function () { return IRegistration_1.appendArgsFn; } });
45
+ Object.defineProperty(exports, "onResolve", { enumerable: true, get: function () { return IRegistration_1.onResolve; } });
45
46
  var Registration_1 = require("./registration/Registration");
46
47
  Object.defineProperty(exports, "Registration", { enumerable: true, get: function () { return Registration_1.Registration; } });
47
48
  var ContainerError_1 = require("./errors/ContainerError");
@@ -81,15 +82,15 @@ Object.defineProperty(exports, "injectProp", { enumerable: true, get: function (
81
82
  var onConstruct_1 = require("./hooks/onConstruct");
82
83
  Object.defineProperty(exports, "onConstructHooksRunner", { enumerable: true, get: function () { return onConstruct_1.onConstructHooksRunner; } });
83
84
  Object.defineProperty(exports, "onConstruct", { enumerable: true, get: function () { return onConstruct_1.onConstruct; } });
84
- Object.defineProperty(exports, "AddOnConstructHookModule", { enumerable: true, get: function () { return onConstruct_1.AddOnConstructHookModule; } });
85
+ Object.defineProperty(exports, "OnConstructModule", { enumerable: true, get: function () { return onConstruct_1.OnConstructModule; } });
85
86
  var onConstructAsync_1 = require("./hooks/onConstructAsync");
86
87
  Object.defineProperty(exports, "onConstructAsyncHooksRunner", { enumerable: true, get: function () { return onConstructAsync_1.onConstructAsyncHooksRunner; } });
87
88
  Object.defineProperty(exports, "onConstructAsync", { enumerable: true, get: function () { return onConstructAsync_1.onConstructAsync; } });
88
- Object.defineProperty(exports, "AddOnConstructAsyncHookModule", { enumerable: true, get: function () { return onConstructAsync_1.AddOnConstructAsyncHookModule; } });
89
+ Object.defineProperty(exports, "OnConstructAsyncModule", { enumerable: true, get: function () { return onConstructAsync_1.OnConstructAsyncModule; } });
89
90
  var onContainerDisposed_1 = require("./hooks/onContainerDisposed");
90
91
  Object.defineProperty(exports, "onContainerDisposedHooksRunner", { enumerable: true, get: function () { return onContainerDisposed_1.onContainerDisposedHooksRunner; } });
91
92
  Object.defineProperty(exports, "onContainerDisposed", { enumerable: true, get: function () { return onContainerDisposed_1.onContainerDisposed; } });
92
- Object.defineProperty(exports, "AddOnDisposeHookModule", { enumerable: true, get: function () { return onContainerDisposed_1.AddOnDisposeHookModule; } });
93
+ Object.defineProperty(exports, "OnDisposeModule", { enumerable: true, get: function () { return onContainerDisposed_1.OnDisposeModule; } });
93
94
  var HooksRunner_1 = require("./hooks/HooksRunner");
94
95
  Object.defineProperty(exports, "HooksRunner", { enumerable: true, get: function () { return HooksRunner_1.HooksRunner; } });
95
96
  var InjectionToken_1 = require("./token/InjectionToken");
@@ -114,6 +115,8 @@ var ConstantToken_1 = require("./token/ConstantToken");
114
115
  Object.defineProperty(exports, "ConstantToken", { enumerable: true, get: function () { return ConstantToken_1.ConstantToken; } });
115
116
  var GroupInstanceToken_1 = require("./token/GroupInstanceToken");
116
117
  Object.defineProperty(exports, "GroupInstanceToken", { enumerable: true, get: function () { return GroupInstanceToken_1.GroupInstanceToken; } });
118
+ var target_1 = require("./metadata/target");
119
+ Object.defineProperty(exports, "resolveConstructor", { enumerable: true, get: function () { return target_1.resolveConstructor; } });
117
120
  var class_1 = require("./metadata/class");
118
121
  Object.defineProperty(exports, "addClassMeta", { enumerable: true, get: function () { return class_1.addClassMeta; } });
119
122
  Object.defineProperty(exports, "getClassMeta", { enumerable: true, get: function () { return class_1.getClassMeta; } });
@@ -152,6 +155,6 @@ var fp_1 = require("./utils/fp");
152
155
  Object.defineProperty(exports, "pipe", { enumerable: true, get: function () { return fp_1.pipe; } });
153
156
  var ProxyRegistry_1 = require("./utils/ProxyRegistry");
154
157
  Object.defineProperty(exports, "ProxyRegistry", { enumerable: true, get: function () { return ProxyRegistry_1.ProxyRegistry; } });
158
+ Object.defineProperty(exports, "unwrapProxy", { enumerable: true, get: function () { return ProxyRegistry_1.unwrapProxy; } });
155
159
  var basic_1 = require("./utils/basic");
156
160
  Object.defineProperty(exports, "Is", { enumerable: true, get: function () { return basic_1.Is; } });
157
- Object.defineProperty(exports, "resolveConstructor", { enumerable: true, get: function () { return basic_1.resolveConstructor; } });
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveArgs = exports.args = exports.arg = exports.argsFn = exports.MetadataInjector = void 0;
4
4
  exports.inject = inject;
5
5
  const IInjector_1 = require("./IInjector");
6
- const basic_1 = require("../utils/basic");
6
+ const target_1 = require("../metadata/target");
7
7
  const parameter_1 = require("../metadata/parameter");
8
8
  const toToken_1 = require("../token/toToken");
9
9
  class MetadataInjector extends IInjector_1.Injector {
@@ -16,7 +16,7 @@ exports.MetadataInjector = MetadataInjector;
16
16
  const hookMetaKey = (methodName = 'constructor') => `inject:${methodName}`;
17
17
  function inject(fn, ...mappers) {
18
18
  return (target, propertyKey, parameterIndex) => {
19
- (0, parameter_1.addParamMeta)(hookMetaKey(propertyKey), () => (0, toToken_1.toMappedToken)(fn, mappers))(basic_1.Is.instance(target) ? target.constructor : target, propertyKey, parameterIndex);
19
+ (0, parameter_1.addParamMeta)(hookMetaKey(propertyKey), () => (0, toToken_1.toMappedToken)(fn, mappers))((0, target_1.resolveConstructor)(target), propertyKey, parameterIndex);
20
20
  };
21
21
  }
22
22
  const argsFn = (predicate) => (c, { args = [] }) => args.find((value, index) => predicate(value, index));
@@ -25,8 +25,8 @@ const arg = (index) => (0, exports.argsFn)((value, i) => i === index);
25
25
  exports.arg = arg;
26
26
  const args = (c, { args = [] }) => args;
27
27
  exports.args = args;
28
- const resolveArgs = (Target, methodName) => {
29
- const tokens = (0, parameter_1.getParamMeta)(hookMetaKey(methodName), Target);
28
+ const resolveArgs = (target, methodName) => {
29
+ const tokens = (0, parameter_1.getParamMeta)(hookMetaKey(methodName), target);
30
30
  return (scope, { args = [], lazy }) => tokens.map((fn) => fn.resolve(scope, { args: args.map(toToken_1.argToToken).map((t) => t.resolve(scope)), lazy }));
31
31
  };
32
32
  exports.resolveArgs = resolveArgs;
@@ -2,14 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.addClassMeta = void 0;
4
4
  exports.getClassMeta = getClassMeta;
5
- const basic_1 = require("../utils/basic");
5
+ const target_1 = require("./target");
6
6
  const addClassMeta = (key, mapFn) => (target) => {
7
7
  const value = Reflect.getOwnMetadata(key, target);
8
8
  Reflect.defineMetadata(key, mapFn(value), target);
9
9
  };
10
10
  exports.addClassMeta = addClassMeta;
11
11
  function getClassMeta(target, key) {
12
- return Reflect.getOwnMetadata(key, (0, basic_1.resolveConstructor)(target));
12
+ return Reflect.getOwnMetadata(key, (0, target_1.resolveConstructor)(target));
13
13
  }
14
14
  const addClassLabel = (key, label) => (0, exports.addClassMeta)('label', (prev = new Map()) => prev.set(key, label));
15
15
  exports.addClassLabel = addClassLabel;
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = void 0;
4
- const basic_1 = require("../utils/basic");
4
+ const target_1 = require("./target");
5
5
  const addMethodMeta = (key, mapFn) => (target, propertyKey) => {
6
6
  const metadata = Reflect.getMetadata(key, target.constructor, propertyKey);
7
7
  Reflect.defineMetadata(key, mapFn(metadata), target.constructor, propertyKey);
8
8
  };
9
9
  exports.addMethodMeta = addMethodMeta;
10
- const getMethodMeta = (key, target, propertyKey) => Reflect.getMetadata(key, (0, basic_1.resolveConstructor)(target), propertyKey);
10
+ const getMethodMeta = (key, target, propertyKey) => Reflect.getMetadata(key, (0, target_1.resolveConstructor)(target), propertyKey);
11
11
  exports.getMethodMeta = getMethodMeta;
12
12
  const addMethodLabel = (key, label) => (0, exports.addMethodMeta)('label', (prev = new Map()) => prev.set(key, label));
13
13
  exports.addMethodLabel = addMethodLabel;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = void 0;
4
- const basic_1 = require("../utils/basic");
4
+ const target_1 = require("./target");
5
5
  const addParamMeta = (key, mapFn) => (target, _, parameterIndex) => {
6
6
  const metadata = Reflect.getOwnMetadata(key, target) ?? [];
7
7
  metadata[parameterIndex] = mapFn(metadata[parameterIndex]);
@@ -9,7 +9,7 @@ const addParamMeta = (key, mapFn) => (target, _, parameterIndex) => {
9
9
  };
10
10
  exports.addParamMeta = addParamMeta;
11
11
  const getParamMeta = (key, target) => {
12
- return Reflect.getOwnMetadata(key, (0, basic_1.resolveConstructor)(target)) ?? [];
12
+ return Reflect.getOwnMetadata(key, (0, target_1.resolveConstructor)(target)) ?? [];
13
13
  };
14
14
  exports.getParamMeta = getParamMeta;
15
15
  const addParamLabel = (key, label) => (0, exports.addParamMeta)('label', (prev) => {
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveConstructor = resolveConstructor;
4
+ const basic_1 = require("../utils/basic");
5
+ const ProxyRegistry_1 = require("../utils/ProxyRegistry");
6
+ function resolveConstructor(target) {
7
+ const value = (0, ProxyRegistry_1.unwrapProxy)(target);
8
+ return basic_1.Is.constructor(value) ? value : value.constructor;
9
+ }
@@ -22,6 +22,7 @@ class Provider {
22
22
  cache = new Map();
23
23
  getKey;
24
24
  isDisposed = false;
25
+ onResolveHookList = [];
25
26
  constructor(resolveDependency) {
26
27
  this.resolveDependency = resolveDependency;
27
28
  }
@@ -37,11 +38,15 @@ class Provider {
37
38
  return this.cache.get(key);
38
39
  }
39
40
  resolveDep(scope, { args = [], lazy } = {}) {
40
- const dependency = this.resolveDependency(scope, {
41
+ let dependency = this.resolveDependency(scope, {
41
42
  args: this.argsFnList.reduce((acc, current) => current(scope, { args: acc }), args),
42
43
  lazy: lazy ?? this.isLazy,
43
44
  });
44
- return this.mappers.reduce((acc, current) => current(acc, scope), dependency);
45
+ dependency = this.mappers.reduce((acc, current) => current(acc, scope), dependency);
46
+ for (const onResolve of this.onResolveHookList) {
47
+ onResolve(dependency, scope);
48
+ }
49
+ return dependency;
45
50
  }
46
51
  map(...mappers) {
47
52
  this.mappers.push(...mappers);
@@ -76,6 +81,10 @@ class Provider {
76
81
  this.getKey = getCacheKey;
77
82
  return this;
78
83
  }
84
+ onResolve(...hooks) {
85
+ this.onResolveHookList.push(...hooks);
86
+ return this;
87
+ }
79
88
  dispose() {
80
89
  ProviderDisposedError_1.ProviderDisposedError.assert(!this.isDisposed, 'Provider is already disposed');
81
90
  this.isDisposed = true;
@@ -85,6 +94,7 @@ class Provider {
85
94
  this.accessRules.splice(0, this.accessRules.length);
86
95
  this.mappers.splice(0, this.mappers.length);
87
96
  this.argsFnList.splice(0, this.argsFnList.length);
97
+ this.onResolveHookList.splice(0, this.onResolveHookList.length);
88
98
  }
89
99
  }
90
100
  exports.Provider = Provider;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.singleton = exports.decorate = exports.autoResolve = exports.lazy = exports.scopeAccess = exports.appendArgsFn = exports.appendArgs = exports.scope = exports.bindTo = exports.register = exports.getTransformers = exports.toRegistrationFn = exports.toProviderFn = exports.toBindToken = exports.registerPipe = exports.isProviderPipe = void 0;
3
+ exports.onResolve = exports.singleton = exports.decorate = exports.autoResolve = exports.lazy = exports.scopeAccess = exports.appendArgsFn = exports.appendArgs = exports.scope = exports.bindTo = exports.register = exports.getTransformers = exports.toRegistrationFn = exports.toProviderFn = exports.toBindToken = exports.registerPipe = exports.isProviderPipe = void 0;
4
4
  const IContainer_1 = require("../container/IContainer");
5
5
  const SingleToken_1 = require("../token/SingleToken");
6
6
  const class_1 = require("../metadata/class");
@@ -54,3 +54,5 @@ const decorate = (...fns) => (0, exports.registerPipe)((p) => p.map(...fns));
54
54
  exports.decorate = decorate;
55
55
  const singleton = (getCacheKey) => (0, exports.registerPipe)((p) => p.singleton(getCacheKey));
56
56
  exports.singleton = singleton;
57
+ const onResolve = (...hooks) => (0, exports.registerPipe)((p) => p.onResolve(...hooks));
58
+ exports.onResolve = onResolve;