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.
- package/README.md +90 -11
- package/cjm/container/AutoResolveModule.js +1 -1
- package/cjm/container/Container.js +9 -16
- package/cjm/container/EmptyContainer.js +3 -7
- package/cjm/hooks/HookContext.js +2 -3
- package/cjm/hooks/onConstruct.js +4 -4
- package/cjm/hooks/onConstructAsync.js +4 -4
- package/cjm/hooks/onContainerDisposed.js +4 -4
- package/cjm/index.js +9 -9
- package/cjm/injector/IInjector.js +6 -2
- package/cjm/provider/Provider.js +12 -2
- package/cjm/registration/IRegistration.js +3 -1
- package/cjm/utils/ProxyRegistry.js +55 -0
- package/esm/container/AutoResolveModule.js +1 -1
- package/esm/container/Container.js +9 -16
- package/esm/container/EmptyContainer.js +3 -7
- package/esm/hooks/HookContext.js +2 -3
- package/esm/hooks/onConstruct.js +2 -2
- package/esm/hooks/onConstructAsync.js +2 -2
- package/esm/hooks/onContainerDisposed.js +2 -2
- package/esm/index.js +5 -5
- package/esm/injector/IInjector.js +6 -2
- package/esm/provider/Provider.js +12 -2
- package/esm/registration/IRegistration.js +2 -1
- package/esm/utils/ProxyRegistry.js +51 -0
- package/package.json +1 -1
- package/typings/container/Container.d.ts +4 -6
- package/typings/container/EmptyContainer.d.ts +4 -6
- package/typings/container/IContainer.d.ts +6 -6
- package/typings/hooks/HookContext.d.ts +2 -2
- package/typings/hooks/onConstruct.d.ts +1 -3
- package/typings/hooks/onConstructAsync.d.ts +1 -1
- package/typings/hooks/onContainerDisposed.d.ts +1 -1
- package/typings/index.d.ts +6 -6
- package/typings/injector/IInjector.d.ts +3 -0
- package/typings/provider/IProvider.d.ts +2 -1
- package/typings/provider/Provider.d.ts +3 -1
- package/typings/registration/IRegistration.d.ts +2 -1
- package/typings/utils/ProxyRegistry.d.ts +19 -0
- package/cjm/utils/proxy.js +0 -48
- package/esm/utils/proxy.js +0 -39
- 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
|
-
.
|
|
74
|
-
.
|
|
75
|
-
.
|
|
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
|
-
|
|
98
|
-
|
|
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
|
-
|
|
124
|
+
onConstruct(...hooks) {
|
|
125
125
|
this.onConstructHookList.push(...hooks);
|
|
126
126
|
return this;
|
|
127
127
|
}
|
|
128
|
-
|
|
128
|
+
onInstanceDisposed(...hooks) {
|
|
129
129
|
this.onDisposeHookList.push(...hooks);
|
|
130
130
|
return this;
|
|
131
131
|
}
|
|
132
|
-
|
|
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
|
-
|
|
60
|
+
onInstanceDisposed(...hooks) {
|
|
65
61
|
throw new MethodNotImplementedError();
|
|
66
62
|
}
|
|
67
|
-
|
|
63
|
+
onConstruct(...hooks) {
|
|
68
64
|
throw new MethodNotImplementedError();
|
|
69
65
|
}
|
|
70
|
-
|
|
66
|
+
onScopeCreated(...hooks) {
|
|
71
67
|
throw new MethodNotImplementedError();
|
|
72
68
|
}
|
|
73
69
|
}
|
package/esm/hooks/HookContext.js
CHANGED
|
@@ -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, {
|
package/esm/hooks/onConstruct.js
CHANGED
|
@@ -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
|
|
5
|
+
export class OnConstructModule {
|
|
6
6
|
onException;
|
|
7
7
|
constructor(onException) {
|
|
8
8
|
this.onException = onException;
|
|
9
9
|
}
|
|
10
10
|
applyTo(container) {
|
|
11
|
-
container.
|
|
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
|
|
5
|
+
export class OnConstructAsyncModule {
|
|
6
6
|
onException;
|
|
7
7
|
constructor(onException) {
|
|
8
8
|
this.onException = onException;
|
|
9
9
|
}
|
|
10
10
|
applyTo(container) {
|
|
11
|
-
container.
|
|
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
|
|
5
|
+
export class OnDisposeModule {
|
|
6
6
|
applyTo(container) {
|
|
7
|
-
container.
|
|
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,
|
|
26
|
-
export { onConstructAsyncHooksRunner, onConstructAsync,
|
|
27
|
-
export { onContainerDisposedHooksRunner, onContainerDisposed,
|
|
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 {
|
|
48
|
+
export { ProxyRegistry } from './utils/ProxyRegistry.js';
|
|
49
49
|
export { Is, resolveConstructor } from './utils/basic.js';
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import {
|
|
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;
|
package/esm/provider/Provider.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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": "
|
|
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
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
|
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
|
|
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
|
|
7
|
+
export declare class OnDisposeModule implements IContainerModule {
|
|
8
8
|
applyTo(container: IContainer): void;
|
|
9
9
|
}
|
package/typings/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { type IContainer, type Resolvable, type IContainerModule, type DependencyKey, type Tag, type Tagged, type ResolveOneOptions, type ResolveManyOptions, type
|
|
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,
|
|
27
|
-
export { onConstructAsyncHooksRunner, onConstructAsync,
|
|
28
|
-
export { onContainerDisposedHooksRunner, onContainerDisposed,
|
|
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 {
|
|
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
|
+
}
|
package/cjm/utils/proxy.js
DELETED
|
@@ -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
|
-
}
|