ts-ioc-container 58.0.0 → 60.0.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 (42) hide show
  1. package/README.md +90 -11
  2. package/cjm/container/AutoResolveModule.js +1 -1
  3. package/cjm/container/Container.js +9 -16
  4. package/cjm/container/EmptyContainer.js +3 -7
  5. package/cjm/hooks/HookContext.js +2 -3
  6. package/cjm/hooks/onConstruct.js +4 -4
  7. package/cjm/hooks/onConstructAsync.js +4 -4
  8. package/cjm/hooks/onContainerDisposed.js +4 -4
  9. package/cjm/index.js +9 -9
  10. package/cjm/injector/IInjector.js +6 -2
  11. package/cjm/provider/Provider.js +12 -2
  12. package/cjm/registration/IRegistration.js +3 -1
  13. package/cjm/utils/ProxyRegistry.js +55 -0
  14. package/esm/container/AutoResolveModule.js +1 -1
  15. package/esm/container/Container.js +9 -16
  16. package/esm/container/EmptyContainer.js +3 -7
  17. package/esm/hooks/HookContext.js +2 -3
  18. package/esm/hooks/onConstruct.js +2 -2
  19. package/esm/hooks/onConstructAsync.js +2 -2
  20. package/esm/hooks/onContainerDisposed.js +2 -2
  21. package/esm/index.js +5 -5
  22. package/esm/injector/IInjector.js +6 -2
  23. package/esm/provider/Provider.js +12 -2
  24. package/esm/registration/IRegistration.js +2 -1
  25. package/esm/utils/ProxyRegistry.js +51 -0
  26. package/package.json +1 -1
  27. package/typings/container/Container.d.ts +4 -6
  28. package/typings/container/EmptyContainer.d.ts +4 -6
  29. package/typings/container/IContainer.d.ts +6 -6
  30. package/typings/hooks/HookContext.d.ts +2 -2
  31. package/typings/hooks/onConstruct.d.ts +1 -3
  32. package/typings/hooks/onConstructAsync.d.ts +1 -1
  33. package/typings/hooks/onContainerDisposed.d.ts +1 -1
  34. package/typings/index.d.ts +6 -6
  35. package/typings/injector/IInjector.d.ts +3 -0
  36. package/typings/provider/IProvider.d.ts +2 -1
  37. package/typings/provider/Provider.d.ts +3 -1
  38. package/typings/registration/IRegistration.d.ts +2 -1
  39. package/typings/utils/ProxyRegistry.d.ts +19 -0
  40. package/cjm/utils/proxy.js +0 -48
  41. package/esm/utils/proxy.js +0 -39
  42. package/typings/utils/proxy.d.ts +0 -6
@@ -70,9 +70,9 @@ export class Container {
70
70
  createScope({ tags } = {}) {
71
71
  this.validateContainer();
72
72
  const scope = new Container({ injector: this.injector, parent: this, tags })
73
- .addOnConstructHook(...this.onConstructHookList)
74
- .addOnDisposeHook(...this.onDisposeHookList)
75
- .addOnScopeCreatedHook(...this.onScopeCreatedHookList);
73
+ .onConstruct(...this.onConstructHookList)
74
+ .onInstanceDisposed(...this.onDisposeHookList)
75
+ .onScopeCreated(...this.onScopeCreatedHookList);
76
76
  for (const registration of this.getRegistrations()) {
77
77
  registration.applyTo(scope);
78
78
  }
@@ -94,9 +94,8 @@ export class Container {
94
94
  dispose() {
95
95
  this.validateContainer();
96
96
  this.isDisposed = true;
97
- while (this.onDisposeHookList.length) {
98
- const onDispose = this.onDisposeHookList.shift();
99
- onDispose(this);
97
+ for (const hook of this.onDisposeHookList) {
98
+ hook(this);
100
99
  }
101
100
  this.parent.removeScope(this);
102
101
  this.parent = new EmptyContainer();
@@ -108,6 +107,7 @@ export class Container {
108
107
  this.instances.clear();
109
108
  this.registrations = [];
110
109
  this.onConstructHookList.length = 0;
110
+ this.onDisposeHookList.length = 0;
111
111
  this.onScopeCreatedHookList.length = 0;
112
112
  }
113
113
  addRegistration(registration) {
@@ -121,15 +121,15 @@ export class Container {
121
121
  hasRegistration(key) {
122
122
  return this.registrations.some((r) => r.getKeyOrFail() === key) || this.parent.hasRegistration(key);
123
123
  }
124
- addOnConstructHook(...hooks) {
124
+ onConstruct(...hooks) {
125
125
  this.onConstructHookList.push(...hooks);
126
126
  return this;
127
127
  }
128
- addOnDisposeHook(...hooks) {
128
+ onInstanceDisposed(...hooks) {
129
129
  this.onDisposeHookList.push(...hooks);
130
130
  return this;
131
131
  }
132
- addOnScopeCreatedHook(...hooks) {
132
+ onScopeCreated(...hooks) {
133
133
  this.onScopeCreatedHookList.push(...hooks);
134
134
  return this;
135
135
  }
@@ -145,13 +145,6 @@ export class Container {
145
145
  hasInstance(instance) {
146
146
  return this.instances.has(instance);
147
147
  }
148
- getScopeByInstanceOrFail(instance) {
149
- this.validateContainer();
150
- if (this.hasInstance(instance)) {
151
- return this;
152
- }
153
- return this.parent.getScopeByInstanceOrFail(instance);
154
- }
155
148
  removeScope(child) {
156
149
  this.scopes = this.scopes.filter((s) => s !== child);
157
150
  }
@@ -1,6 +1,5 @@
1
1
  import { MethodNotImplementedError } from '../errors/MethodNotImplementedError.js';
2
2
  import { DependencyNotFoundError } from '../errors/DependencyNotFoundError.js';
3
- import { ContainerNotFoundError } from '../errors/ContainerNotFoundError.js';
4
3
  export class EmptyContainer {
5
4
  get isDisposed() {
6
5
  throw new MethodNotImplementedError();
@@ -12,9 +11,6 @@ export class EmptyContainer {
12
11
  getScopes() {
13
12
  return [];
14
13
  }
15
- getScopeByInstanceOrFail(instance) {
16
- throw new ContainerNotFoundError('Cannot find scope for the given instance');
17
- }
18
14
  getInstances() {
19
15
  return [];
20
16
  }
@@ -61,13 +57,13 @@ export class EmptyContainer {
61
57
  resolveOneByAlias(alias, options) {
62
58
  throw new DependencyNotFoundError(`Cannot find alias ${alias.toString()}`);
63
59
  }
64
- addOnDisposeHook(...hooks) {
60
+ onInstanceDisposed(...hooks) {
65
61
  throw new MethodNotImplementedError();
66
62
  }
67
- addOnConstructHook(...hooks) {
63
+ onConstruct(...hooks) {
68
64
  throw new MethodNotImplementedError();
69
65
  }
70
- addOnScopeCreatedHook(...hooks) {
66
+ onScopeCreated(...hooks) {
71
67
  throw new MethodNotImplementedError();
72
68
  }
73
69
  }
@@ -1,14 +1,13 @@
1
- import { getProxyTarget, isProxy } from '../utils/proxy.js';
2
1
  import { resolveArgs } from '../injector/MetadataInjector.js';
3
2
  export class HookContext {
3
+ instance;
4
4
  scope;
5
5
  methodName;
6
- instance;
7
6
  initialArgs = [];
8
7
  constructor(instance, scope, methodName) {
8
+ this.instance = instance;
9
9
  this.scope = scope;
10
10
  this.methodName = methodName;
11
- this.instance = isProxy(instance) ? getProxyTarget(instance) : instance;
12
11
  }
13
12
  resolveArgs(...args) {
14
13
  return resolveArgs(this.instance.constructor, this.methodName)(this.scope, {
@@ -2,13 +2,13 @@ import { hook, prependHooks } from './hook.js';
2
2
  import { HooksRunner } from './HooksRunner.js';
3
3
  export const onConstructHooksRunner = new HooksRunner('onConstruct');
4
4
  export const onConstruct = (...fns) => hook('onConstruct', prependHooks(...fns));
5
- export class AddOnConstructHookModule {
5
+ export class OnConstructModule {
6
6
  onException;
7
7
  constructor(onException) {
8
8
  this.onException = onException;
9
9
  }
10
10
  applyTo(container) {
11
- container.addOnConstructHook((instance, scope) => {
11
+ container.onConstruct((instance, scope) => {
12
12
  try {
13
13
  onConstructHooksRunner.execute(instance, { scope });
14
14
  }
@@ -2,13 +2,13 @@ import { hook, prependHooks } from './hook.js';
2
2
  import { HooksRunner } from './HooksRunner.js';
3
3
  export const onConstructAsyncHooksRunner = new HooksRunner('onConstructAsync');
4
4
  export const onConstructAsync = (...fns) => hook('onConstructAsync', prependHooks(...fns));
5
- export class AddOnConstructAsyncHookModule {
5
+ export class OnConstructAsyncModule {
6
6
  onException;
7
7
  constructor(onException) {
8
8
  this.onException = onException;
9
9
  }
10
10
  applyTo(container) {
11
- container.addOnConstructHook((instance, scope) => {
11
+ container.onConstruct((instance, scope) => {
12
12
  if (!onConstructAsyncHooksRunner.hasHooks(instance)) {
13
13
  return;
14
14
  }
@@ -2,9 +2,9 @@ import { hook, prependHooks } from './hook.js';
2
2
  import { HooksRunner } from './HooksRunner.js';
3
3
  export const onContainerDisposedHooksRunner = new HooksRunner('onContainerDisposed');
4
4
  export const onContainerDisposed = (...fns) => hook('onContainerDisposed', prependHooks(...fns));
5
- export class AddOnDisposeHookModule {
5
+ export class OnDisposeModule {
6
6
  applyTo(container) {
7
- container.addOnDisposeHook((scope) => {
7
+ container.onInstanceDisposed((scope) => {
8
8
  for (const instance of scope.getInstances()) {
9
9
  onContainerDisposedHooksRunner.execute(instance, { scope });
10
10
  }
package/esm/index.js CHANGED
@@ -7,7 +7,7 @@ export { MetadataInjector, inject, arg, args, argsFn, resolveArgs } from './inje
7
7
  export { SimpleInjector } from './injector/SimpleInjector.js';
8
8
  export { ProxyInjector } from './injector/ProxyInjector.js';
9
9
  export { Provider } from './provider/Provider.js';
10
- export { isProviderPipe, registerPipe, toBindToken, toProviderFn, toRegistrationFn, register, bindTo, scope, scopeAccess, lazy, autoResolve, singleton, decorate, appendArgs, appendArgsFn, } from './registration/IRegistration.js';
10
+ export { isProviderPipe, registerPipe, toBindToken, toProviderFn, toRegistrationFn, register, bindTo, scope, scopeAccess, lazy, autoResolve, singleton, decorate, appendArgs, appendArgsFn, onResolve, } from './registration/IRegistration.js';
11
11
  export { Registration } from './registration/Registration.js';
12
12
  export { ContainerError } from './errors/ContainerError.js';
13
13
  export { DependencyNotFoundError } from './errors/DependencyNotFoundError.js';
@@ -22,9 +22,9 @@ export { UnsupportedTokenTypeError } from './errors/UnsupportedTokenTypeError.js
22
22
  export { getHooks, hook, hasHooks, appendHooks, prependHooks, append, prepend, } from './hooks/hook.js';
23
23
  export { HookContext, createHookContextFactory, createHookContext } from './hooks/HookContext.js';
24
24
  export { injectProp } from './hooks/injectProp.js';
25
- export { onConstructHooksRunner, onConstruct, AddOnConstructHookModule, } from './hooks/onConstruct.js';
26
- export { onConstructAsyncHooksRunner, onConstructAsync, AddOnConstructAsyncHookModule } from './hooks/onConstructAsync.js';
27
- export { onContainerDisposedHooksRunner, onContainerDisposed, AddOnDisposeHookModule, } from './hooks/onContainerDisposed.js';
25
+ export { onConstructHooksRunner, onConstruct, OnConstructModule } from './hooks/onConstruct.js';
26
+ export { onConstructAsyncHooksRunner, onConstructAsync, OnConstructAsyncModule } from './hooks/onConstructAsync.js';
27
+ export { onContainerDisposedHooksRunner, onContainerDisposed, OnDisposeModule } from './hooks/onContainerDisposed.js';
28
28
  export { HooksRunner } from './hooks/HooksRunner.js';
29
29
  export { InjectionToken } from './token/InjectionToken.js';
30
30
  export { toToken, toMappedToken, argToToken } from './token/toToken.js';
@@ -45,5 +45,5 @@ export { shallowCache } from './utils/shallowCache.js';
45
45
  export { once } from './utils/once.js';
46
46
  export { select } from './select.js';
47
47
  export { pipe } from './utils/fp.js';
48
- export { createProxy, unwrapProxyTarget } from './utils/proxy.js';
48
+ export { ProxyRegistry } from './utils/ProxyRegistry.js';
49
49
  export { Is, resolveConstructor } from './utils/basic.js';
@@ -1,7 +1,11 @@
1
- import { toLazyIf } from '../utils/proxy.js';
1
+ import { ProxyRegistry } from '../utils/ProxyRegistry.js';
2
2
  export class Injector {
3
+ proxyRegistry;
4
+ constructor(proxyRegistry = ProxyRegistry.getInstance()) {
5
+ this.proxyRegistry = proxyRegistry;
6
+ }
3
7
  resolve(scope, Target, { args, lazy } = {}) {
4
- return toLazyIf(() => {
8
+ return this.proxyRegistry.toLazyIf(() => {
5
9
  const instance = this.createInstance(scope, Target, { args });
6
10
  scope.addInstance(instance);
7
11
  return instance;
@@ -19,6 +19,7 @@ export class Provider {
19
19
  cache = new Map();
20
20
  getKey;
21
21
  isDisposed = false;
22
+ onResolveHookList = [];
22
23
  constructor(resolveDependency) {
23
24
  this.resolveDependency = resolveDependency;
24
25
  }
@@ -34,11 +35,15 @@ export class Provider {
34
35
  return this.cache.get(key);
35
36
  }
36
37
  resolveDep(scope, { args = [], lazy } = {}) {
37
- const dependency = this.resolveDependency(scope, {
38
+ let dependency = this.resolveDependency(scope, {
38
39
  args: this.argsFnList.reduce((acc, current) => current(scope, { args: acc }), args),
39
40
  lazy: lazy ?? this.isLazy,
40
41
  });
41
- return this.mappers.reduce((acc, current) => current(acc, scope), dependency);
42
+ dependency = this.mappers.reduce((acc, current) => current(acc, scope), dependency);
43
+ for (const onResolve of this.onResolveHookList) {
44
+ onResolve(dependency, scope);
45
+ }
46
+ return dependency;
42
47
  }
43
48
  map(...mappers) {
44
49
  this.mappers.push(...mappers);
@@ -73,6 +78,10 @@ export class Provider {
73
78
  this.getKey = getCacheKey;
74
79
  return this;
75
80
  }
81
+ onResolve(...hooks) {
82
+ this.onResolveHookList.push(...hooks);
83
+ return this;
84
+ }
76
85
  dispose() {
77
86
  ProviderDisposedError.assert(!this.isDisposed, 'Provider is already disposed');
78
87
  this.isDisposed = true;
@@ -82,5 +91,6 @@ export class Provider {
82
91
  this.accessRules.splice(0, this.accessRules.length);
83
92
  this.mappers.splice(0, this.mappers.length);
84
93
  this.argsFnList.splice(0, this.argsFnList.length);
94
+ this.onResolveHookList.splice(0, this.onResolveHookList.length);
85
95
  }
86
96
  }
@@ -1,4 +1,4 @@
1
- import { isDependencyKey } from '../container/IContainer.js';
1
+ import { isDependencyKey, } from '../container/IContainer.js';
2
2
  import { SingleToken } from '../token/SingleToken.js';
3
3
  import { addClassMeta, getClassMeta } from '../metadata/class.js';
4
4
  export const isProviderPipe = (obj) => obj !== null && typeof obj === 'object' && 'mapProvider' in obj;
@@ -35,3 +35,4 @@ export const lazy = () => registerPipe((p) => p.lazy());
35
35
  export const autoResolve = () => registerPipe((p) => p.autoResolve());
36
36
  export const decorate = (...fns) => registerPipe((p) => p.map(...fns));
37
37
  export const singleton = (getCacheKey) => registerPipe((p) => p.singleton(getCacheKey));
38
+ export const onResolve = (...hooks) => registerPipe((p) => p.onResolve(...hooks));
@@ -0,0 +1,51 @@
1
+ export class ProxyRegistry {
2
+ static instance;
3
+ states = new WeakMap();
4
+ constructor() { }
5
+ static getInstance() {
6
+ ProxyRegistry.instance ??= new ProxyRegistry();
7
+ return ProxyRegistry.instance;
8
+ }
9
+ unwrap(value) {
10
+ return this.isProxy(value) ? this.getTarget(value) : value;
11
+ }
12
+ createProxy(target, handler = {}) {
13
+ const proxy = new Proxy(target, handler);
14
+ return this.register(proxy, { getTarget: () => target });
15
+ }
16
+ createLazyProxy(resolveInstance) {
17
+ let instance;
18
+ const state = {
19
+ getTarget: () => {
20
+ instance = instance ?? this.unwrap(resolveInstance());
21
+ return instance;
22
+ },
23
+ };
24
+ const proxy = new Proxy({}, {
25
+ get: (_, prop) => {
26
+ const target = state.getTarget();
27
+ return target[prop];
28
+ },
29
+ set: (_, prop, value) => {
30
+ const target = state.getTarget();
31
+ target[prop] = value;
32
+ return true;
33
+ },
34
+ });
35
+ return this.register(proxy, state);
36
+ }
37
+ toLazyIf(resolveInstance, isLazy = false) {
38
+ return isLazy ? this.createLazyProxy(resolveInstance) : resolveInstance();
39
+ }
40
+ isProxy(value) {
41
+ return this.states.has(value);
42
+ }
43
+ getTarget(value) {
44
+ const target = this.states.get(value).getTarget();
45
+ return this.unwrap(target);
46
+ }
47
+ register(proxy, state) {
48
+ this.states.set(proxy, state);
49
+ return proxy;
50
+ }
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "58.0.0",
3
+ "version": "60.0.0",
4
4
  "description": "Fast, lightweight TypeScript dependency injection container with a clean API, scoped lifecycles, decorators, tokens, hooks, lazy injection, customizable providers, and no global container objects.",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -1,8 +1,7 @@
1
- import { type AutoResolveOptions, type CreateScopeOptions, type DependencyKey, type IContainer, type IContainerModule, type OnScopeCreatedHook, type RegisterOptions, ResolveManyOptions, type ResolveOneOptions, type Tag } from './IContainer.js';
1
+ import { type AutoResolveOptions, type CreateScopeOptions, type DependencyKey, type IContainer, type IContainerModule, type InstanceHook, type RegisterOptions, ResolveManyOptions, type ResolveOneOptions, type ScopeHook, type Tag } from './IContainer.js';
2
2
  import { type IInjector } from '../injector/IInjector.js';
3
3
  import { type IProvider } from '../provider/IProvider.js';
4
4
  import { type IRegistration } from '../registration/IRegistration.js';
5
- import { OnConstructHook } from '../hooks/onConstruct.js';
6
5
  import { OnDisposeHook } from '../hooks/onContainerDisposed.js';
7
6
  import { constructor, Instance } from '../utils/basic.js';
8
7
  export declare class Container implements IContainer {
@@ -33,13 +32,12 @@ export declare class Container implements IContainer {
33
32
  addRegistration(registration: IRegistration): this;
34
33
  getRegistrations(): IRegistration[];
35
34
  hasRegistration(key: DependencyKey): boolean;
36
- addOnConstructHook(...hooks: OnConstructHook[]): this;
37
- addOnDisposeHook(...hooks: OnDisposeHook[]): this;
38
- addOnScopeCreatedHook(...hooks: OnScopeCreatedHook[]): this;
35
+ onConstruct(...hooks: InstanceHook[]): this;
36
+ onInstanceDisposed(...hooks: OnDisposeHook[]): this;
37
+ onScopeCreated(...hooks: ScopeHook[]): this;
39
38
  addInstance(instance: Instance): void;
40
39
  getScopes(): IContainer[];
41
40
  hasInstance(instance: Instance): boolean;
42
- getScopeByInstanceOrFail(instance: Instance): IContainer;
43
41
  removeScope(child: IContainer): void;
44
42
  useModule(module: IContainerModule): this;
45
43
  getParent(): IContainer;
@@ -1,15 +1,13 @@
1
- import { type AutoResolveOptions, type DependencyKey, type IContainer, type IContainerModule, type OnScopeCreatedHook, type ResolveManyOptions, type ResolveOneOptions, type Tag } from './IContainer.js';
1
+ import { type AutoResolveOptions, type DependencyKey, type IContainer, type IContainerModule, type ScopeHook, type ResolveManyOptions, type ResolveOneOptions, type Tag, type InstanceHook } from './IContainer.js';
2
2
  import { type IProvider } from '../provider/IProvider.js';
3
3
  import { type IRegistration } from '../registration/IRegistration.js';
4
4
  import { OnDisposeHook } from '../hooks/onContainerDisposed.js';
5
- import { OnConstructHook } from '../hooks/onConstruct.js';
6
5
  import { type constructor, type Instance } from '../utils/basic.js';
7
6
  export declare class EmptyContainer implements IContainer {
8
7
  get isDisposed(): boolean;
9
8
  addInstance(instance: Instance): void;
10
9
  getParent(): undefined;
11
10
  getScopes(): never[];
12
- getScopeByInstanceOrFail(instance: Instance): IContainer;
13
11
  getInstances(): never[];
14
12
  hasInstance(instance: Instance): boolean;
15
13
  createScope(): IContainer;
@@ -26,7 +24,7 @@ export declare class EmptyContainer implements IContainer {
26
24
  resolve<T>(key: constructor<T> | DependencyKey, options?: ResolveOneOptions): T;
27
25
  resolveByAlias<T>(alias: DependencyKey, options?: ResolveManyOptions): T[];
28
26
  resolveOneByAlias<T>(alias: DependencyKey, options?: ResolveOneOptions): T;
29
- addOnDisposeHook(...hooks: OnDisposeHook[]): this;
30
- addOnConstructHook(...hooks: OnConstructHook[]): this;
31
- addOnScopeCreatedHook(...hooks: OnScopeCreatedHook[]): this;
27
+ onInstanceDisposed(...hooks: OnDisposeHook[]): this;
28
+ onConstruct(...hooks: InstanceHook[]): this;
29
+ onScopeCreated(...hooks: ScopeHook[]): this;
32
30
  }
@@ -1,6 +1,5 @@
1
1
  import { type IProvider, ProviderOptions } from '../provider/IProvider.js';
2
2
  import { type IRegistration } from '../registration/IRegistration.js';
3
- import { OnConstructHook } from '../hooks/onConstruct.js';
4
3
  import { OnDisposeHook } from '../hooks/onContainerDisposed.js';
5
4
  import { type WithArgs } from '../injector/IInjector.js';
6
5
  import { type constructor, Instance } from '../utils/basic.js';
@@ -30,15 +29,17 @@ export interface IContainerModule {
30
29
  }
31
30
  export type CreateScopeOptions = Partial<WithTags>;
32
31
  export type AutoResolveOptions = Partial<WithArgs>;
33
- export type OnScopeCreatedHook = (scope: IContainer) => void;
34
32
  export type RegisterOptions = {
35
33
  aliases?: DependencyKey[];
36
34
  };
35
+ export type ScopeHook = (scope: IContainer) => void;
36
+ export type InstanceHook = (instance: Instance, scope: IContainer) => void;
37
+ export type DependencyHook = (dependency: unknown, scope: IContainer) => void;
37
38
  export interface IContainer extends Tagged {
38
39
  readonly isDisposed: boolean;
39
- addOnConstructHook(...hooks: OnConstructHook[]): this;
40
- addOnDisposeHook(...hooks: OnDisposeHook[]): this;
41
- addOnScopeCreatedHook(...hooks: OnScopeCreatedHook[]): this;
40
+ onConstruct(...hooks: InstanceHook[]): this;
41
+ onInstanceDisposed(...hooks: OnDisposeHook[]): this;
42
+ onScopeCreated(...hooks: ScopeHook[]): this;
42
43
  register(key: DependencyKey, value: IProvider, options?: RegisterOptions): this;
43
44
  addRegistration(registration: IRegistration): this;
44
45
  getRegistrations(): IRegistration[];
@@ -49,7 +50,6 @@ export interface IContainer extends Tagged {
49
50
  createScope(options?: CreateScopeOptions): IContainer;
50
51
  autoResolve(options?: AutoResolveOptions): this;
51
52
  getScopes(): IContainer[];
52
- getScopeByInstanceOrFail(instance: Instance): IContainer;
53
53
  removeScope(child: IContainer): void;
54
54
  useModule(module: IContainerModule): this;
55
55
  getParent(): IContainer | undefined;
@@ -15,9 +15,9 @@ export interface IHookContext {
15
15
  getInitialArgs(): unknown[];
16
16
  }
17
17
  export declare class HookContext implements IHookContext {
18
- scope: IContainer;
19
- methodName?: string | undefined;
20
18
  readonly instance: Instance;
19
+ readonly scope: IContainer;
20
+ readonly methodName?: string | undefined;
21
21
  private initialArgs;
22
22
  constructor(instance: Instance, scope: IContainer, methodName?: string | undefined);
23
23
  resolveArgs(...args: unknown[]): unknown[];
@@ -1,13 +1,11 @@
1
1
  import { HookType } from './hook.js';
2
2
  import type { IContainer, IContainerModule } from '../container/IContainer.js';
3
- import { Instance } from '../utils/basic.js';
4
3
  import { HooksRunner } from './HooksRunner.js';
5
4
  import type { ExecutionContext } from '../ExecutionContext.js';
6
5
  export declare const onConstructHooksRunner: HooksRunner;
7
6
  export declare const onConstruct: (...fns: HookType[]) => (target: object, propertyKey: string | symbol) => void;
8
- export type OnConstructHook = (instance: Instance, scope: IContainer) => void;
9
7
  export type OnExceptionHandler = (ex: unknown, context: ExecutionContext) => void;
10
- export declare class AddOnConstructHookModule implements IContainerModule {
8
+ export declare class OnConstructModule implements IContainerModule {
11
9
  private readonly onException?;
12
10
  constructor(onException?: OnExceptionHandler | undefined);
13
11
  applyTo(container: IContainer): void;
@@ -4,7 +4,7 @@ import { HooksRunner } from './HooksRunner.js';
4
4
  import type { OnExceptionHandler } from './onConstruct.js';
5
5
  export declare const onConstructAsyncHooksRunner: HooksRunner;
6
6
  export declare const onConstructAsync: (...fns: HookType[]) => (target: object, propertyKey: string | symbol) => void;
7
- export declare class AddOnConstructAsyncHookModule implements IContainerModule {
7
+ export declare class OnConstructAsyncModule implements IContainerModule {
8
8
  private readonly onException?;
9
9
  constructor(onException?: OnExceptionHandler | undefined);
10
10
  applyTo(container: IContainer): void;
@@ -4,6 +4,6 @@ import { HooksRunner } from './HooksRunner.js';
4
4
  export declare const onContainerDisposedHooksRunner: HooksRunner;
5
5
  export declare const onContainerDisposed: (...fns: HookType[]) => (target: object, propertyKey: string | symbol) => void;
6
6
  export type OnDisposeHook = (scope: IContainer) => void;
7
- export declare class AddOnDisposeHookModule implements IContainerModule {
7
+ export declare class OnDisposeModule implements IContainerModule {
8
8
  applyTo(container: IContainer): void;
9
9
  }
@@ -1,4 +1,4 @@
1
- export { type IContainer, type Resolvable, type IContainerModule, type DependencyKey, type Tag, type Tagged, type ResolveOneOptions, type ResolveManyOptions, type OnScopeCreatedHook, type AutoResolveOptions, isDependencyKey, } from './container/IContainer.js';
1
+ export { type IContainer, type Resolvable, type IContainerModule, type DependencyKey, type Tag, type Tagged, type ResolveOneOptions, type ResolveManyOptions, type ScopeHook, type InstanceHook, type DependencyHook, type AutoResolveOptions, isDependencyKey, } from './container/IContainer.js';
2
2
  export { Container } from './container/Container.js';
3
3
  export { AutoResolveModule } from './container/AutoResolveModule.js';
4
4
  export { EmptyContainer } from './container/EmptyContainer.js';
@@ -8,7 +8,7 @@ export { SimpleInjector } from './injector/SimpleInjector.js';
8
8
  export { ProxyInjector } from './injector/ProxyInjector.js';
9
9
  export { type ResolveDependency, type IProvider, type DecorateFn, type ArgsFn, type ProviderOptions, type GetCacheKey, type ScopeAccessOptions, type ScopeAccessRule, } from './provider/IProvider.js';
10
10
  export { Provider } from './provider/Provider.js';
11
- export { type IRegistration, type ReturnTypeOfRegistration, type ScopeMatchRule, type ProviderPipe, type Bindable, type ProviderMapper, type RegistrationMapper, isProviderPipe, registerPipe, toBindToken, toProviderFn, toRegistrationFn, register, bindTo, scope, scopeAccess, lazy, autoResolve, singleton, decorate, appendArgs, appendArgsFn, } from './registration/IRegistration.js';
11
+ export { type IRegistration, type ReturnTypeOfRegistration, type ScopeMatchRule, type ProviderPipe, type Bindable, type ProviderMapper, type RegistrationMapper, isProviderPipe, registerPipe, toBindToken, toProviderFn, toRegistrationFn, register, bindTo, scope, scopeAccess, lazy, autoResolve, singleton, decorate, appendArgs, appendArgsFn, onResolve, } from './registration/IRegistration.js';
12
12
  export { Registration } from './registration/Registration.js';
13
13
  export { ContainerError } from './errors/ContainerError.js';
14
14
  export { DependencyNotFoundError } from './errors/DependencyNotFoundError.js';
@@ -23,9 +23,9 @@ export { UnsupportedTokenTypeError } from './errors/UnsupportedTokenTypeError.js
23
23
  export { getHooks, hook, hasHooks, appendHooks, prependHooks, append, prepend, type HookFn, type HookClass, type HookType, type MapHooksFn, type InjectFn, type HooksOfClass, } from './hooks/hook.js';
24
24
  export { HookContext, createHookContextFactory, createHookContext, type IHookContext } from './hooks/HookContext.js';
25
25
  export { injectProp } from './hooks/injectProp.js';
26
- export { onConstructHooksRunner, onConstruct, AddOnConstructHookModule, type OnExceptionHandler, } from './hooks/onConstruct.js';
27
- export { onConstructAsyncHooksRunner, onConstructAsync, AddOnConstructAsyncHookModule } from './hooks/onConstructAsync.js';
28
- export { onContainerDisposedHooksRunner, onContainerDisposed, AddOnDisposeHookModule, } from './hooks/onContainerDisposed.js';
26
+ export { onConstructHooksRunner, onConstruct, OnConstructModule, type OnExceptionHandler } from './hooks/onConstruct.js';
27
+ export { onConstructAsyncHooksRunner, onConstructAsync, OnConstructAsyncModule } from './hooks/onConstructAsync.js';
28
+ export { onContainerDisposedHooksRunner, onContainerDisposed, OnDisposeModule } from './hooks/onContainerDisposed.js';
29
29
  export { HooksRunner, type HooksRunnerContext, type MapHookContext } from './hooks/HooksRunner.js';
30
30
  export { InjectionToken } from './token/InjectionToken.js';
31
31
  export { type Injectable, toToken, toMappedToken, argToToken } from './token/toToken.js';
@@ -47,5 +47,5 @@ export { once } from './utils/once.js';
47
47
  export { type ExecutionContext } from './ExecutionContext.js';
48
48
  export { select } from './select.js';
49
49
  export { pipe, type MapFn } from './utils/fp.js';
50
- export { createProxy, unwrapProxyTarget } from './utils/proxy.js';
50
+ export { ProxyRegistry, type IProxyRegistry } from './utils/ProxyRegistry.js';
51
51
  export { type Branded, type constructor, type Instance, Is, resolveConstructor } from './utils/basic.js';
@@ -1,5 +1,6 @@
1
1
  import { type IContainer, ResolveOneOptions } from '../container/IContainer.js';
2
2
  import { ProviderOptions } from '../provider/IProvider.js';
3
+ import { type IProxyRegistry } from '../utils/ProxyRegistry.js';
3
4
  import { type constructor } from '../utils/basic.js';
4
5
  export type WithArgs = {
5
6
  args: unknown[];
@@ -12,6 +13,8 @@ export interface IInjectFnResolver<T> {
12
13
  resolve(s: IContainer, options?: ResolveOneOptions): T;
13
14
  }
14
15
  export declare abstract class Injector {
16
+ private readonly proxyRegistry;
17
+ constructor(proxyRegistry?: IProxyRegistry);
15
18
  resolve<T>(scope: IContainer, Target: constructor<T>, { args, lazy }?: ProviderOptions): T;
16
19
  protected abstract createInstance<T>(scope: IContainer, Target: constructor<T>, options?: InjectOptions): T;
17
20
  }
@@ -1,4 +1,4 @@
1
- import { IContainer, Tagged } from '../container/IContainer.js';
1
+ import { type DependencyHook, IContainer, Tagged } from '../container/IContainer.js';
2
2
  import { InjectOptions } from '../injector/IInjector.js';
3
3
  export type WithLazy = {
4
4
  lazy: boolean;
@@ -25,4 +25,5 @@ export interface IProvider<T = any> {
25
25
  isAutoResolvable(): boolean;
26
26
  singleton(getCacheKey?: GetCacheKey): this;
27
27
  dispose(): void;
28
+ onResolve(...hooks: DependencyHook[]): this;
28
29
  }
@@ -1,5 +1,5 @@
1
1
  import { type ArgsFn, type DecorateFn, type GetCacheKey, type IProvider, type ProviderOptions, type ResolveDependency, type ScopeAccessOptions, type ScopeAccessRule } from './IProvider.js';
2
- import type { DependencyKey, IContainer } from '../container/IContainer.js';
2
+ import type { DependencyHook, DependencyKey, IContainer } from '../container/IContainer.js';
3
3
  import { type constructor } from '../utils/basic.js';
4
4
  export declare class Provider<T = any> implements IProvider<T> {
5
5
  private readonly resolveDependency;
@@ -14,6 +14,7 @@ export declare class Provider<T = any> implements IProvider<T> {
14
14
  private cache;
15
15
  private getKey;
16
16
  private isDisposed;
17
+ private readonly onResolveHookList;
17
18
  constructor(resolveDependency: ResolveDependency<T>);
18
19
  resolve(scope: IContainer, options: ProviderOptions): T;
19
20
  private resolveDep;
@@ -25,5 +26,6 @@ export declare class Provider<T = any> implements IProvider<T> {
25
26
  addArgsFn(...fns: ArgsFn[]): this;
26
27
  hasAccess(options: ScopeAccessOptions): boolean;
27
28
  singleton(getCacheKey?: GetCacheKey): this;
29
+ onResolve(...hooks: DependencyHook[]): this;
28
30
  dispose(): void;
29
31
  }
@@ -1,4 +1,4 @@
1
- import { type DependencyKey, type IContainer, type IContainerModule } from '../container/IContainer.js';
1
+ import { type DependencyHook, type DependencyKey, type IContainer, type IContainerModule } from '../container/IContainer.js';
2
2
  import type { ArgsFn, DecorateFn, GetCacheKey, IProvider, ScopeAccessRule } from '../provider/IProvider.js';
3
3
  import { BindToken } from '../token/BindToken.js';
4
4
  import { MapFn } from '../utils/fp.js';
@@ -36,3 +36,4 @@ export declare const lazy: <T>() => ProviderPipe<T>;
36
36
  export declare const autoResolve: <T>() => ProviderPipe<T>;
37
37
  export declare const decorate: (...fns: DecorateFn[]) => ProviderPipe<unknown>;
38
38
  export declare const singleton: <T = unknown>(getCacheKey?: GetCacheKey) => ProviderPipe<T>;
39
+ export declare const onResolve: <T = unknown>(...hooks: DependencyHook[]) => ProviderPipe<T>;
@@ -0,0 +1,19 @@
1
+ export interface IProxyRegistry {
2
+ unwrap<T extends object>(value: T): T;
3
+ createProxy<T extends object>(target: T, handler?: ProxyHandler<T>): T;
4
+ createLazyProxy<T extends object>(resolveInstance: () => T): T;
5
+ toLazyIf<T extends object>(resolveInstance: () => T, isLazy?: boolean): T;
6
+ }
7
+ export declare class ProxyRegistry implements IProxyRegistry {
8
+ private static instance?;
9
+ private readonly states;
10
+ private constructor();
11
+ static getInstance(): ProxyRegistry;
12
+ unwrap<T extends object>(value: T): T;
13
+ createProxy<T extends object>(target: T, handler?: ProxyHandler<T>): T;
14
+ createLazyProxy<T extends object>(resolveInstance: () => T): T;
15
+ toLazyIf<T extends object>(resolveInstance: () => T, isLazy?: boolean): T;
16
+ private isProxy;
17
+ private getTarget;
18
+ private register;
19
+ }
@@ -1,48 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.unwrapProxyTarget = void 0;
4
- exports.isProxy = isProxy;
5
- exports.getProxyTarget = getProxyTarget;
6
- exports.createProxy = createProxy;
7
- exports.lazyProxy = lazyProxy;
8
- exports.toLazyIf = toLazyIf;
9
- const proxyStateMap = new WeakMap();
10
- const unwrapProxyTarget = (value) => {
11
- return isProxy(value) ? getProxyTarget(value) : value;
12
- };
13
- exports.unwrapProxyTarget = unwrapProxyTarget;
14
- function isProxy(value) {
15
- return proxyStateMap.has(value);
16
- }
17
- function getProxyTarget(value) {
18
- const target = proxyStateMap.get(value).getTarget();
19
- return (0, exports.unwrapProxyTarget)(target);
20
- }
21
- function createProxy(target, handler = {}) {
22
- const proxy = new Proxy(target, handler);
23
- proxyStateMap.set(proxy, { getTarget: () => target });
24
- return proxy;
25
- }
26
- function lazyProxy(resolveInstance) {
27
- let instance;
28
- const state = {
29
- getTarget: () => {
30
- instance = instance ?? (0, exports.unwrapProxyTarget)(resolveInstance());
31
- return instance;
32
- },
33
- };
34
- const proxy = new Proxy({}, {
35
- get: (_, prop) => {
36
- const target = state.getTarget();
37
- return target[prop];
38
- },
39
- });
40
- proxyStateMap.set(proxy, state);
41
- return proxy;
42
- }
43
- function toLazyIf(resolveInstance, isLazy = false) {
44
- if (isLazy) {
45
- return lazyProxy(resolveInstance);
46
- }
47
- return resolveInstance();
48
- }