ts-ioc-container 72.1.0 → 72.2.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/AGENTS.md +179 -0
- package/cjm/container/Container.js +2 -2
- package/cjm/container/EmptyContainer.js +17 -15
- package/cjm/errors/ArgumentNotFoundError.js +1 -0
- package/cjm/errors/CannonSingletonApplyTwiceError.js +2 -14
- package/cjm/errors/CannotApplySingletonTwiceError.js +18 -0
- package/cjm/errors/ContainerDisposedError.js +1 -0
- package/cjm/errors/ContainerError.js +1 -0
- package/cjm/errors/ContainerNotFoundError.js +1 -0
- package/cjm/errors/DependencyMissingKeyError.js +1 -0
- package/cjm/errors/DependencyNotFoundError.js +1 -0
- package/cjm/errors/MethodNotImplementedError.js +1 -0
- package/cjm/errors/ProviderDisposedError.js +1 -0
- package/cjm/errors/TypedEventDisposedError.js +1 -0
- package/cjm/errors/UnsupportedTokenTypeError.js +1 -0
- package/cjm/index.js +5 -3
- package/cjm/provider/Provider.js +6 -6
- package/cjm/registration/Registration.js +2 -2
- package/cjm/token/ConstantToken.js +4 -4
- package/cjm/token/FunctionToken.js +1 -1
- package/cjm/token/GroupInstanceToken.js +4 -4
- package/cjm/token/toToken.js +1 -1
- package/cjm/utils/TypedEvent.js +1 -1
- package/cjm/utils/array.js +1 -1
- package/esm/container/Container.js +2 -2
- package/esm/container/EmptyContainer.js +17 -15
- package/esm/errors/ArgumentNotFoundError.js +1 -0
- package/esm/errors/CannonSingletonApplyTwiceError.js +2 -13
- package/esm/errors/CannotApplySingletonTwiceError.js +14 -0
- package/esm/errors/ContainerDisposedError.js +1 -0
- package/esm/errors/ContainerError.js +1 -0
- package/esm/errors/ContainerNotFoundError.js +1 -0
- package/esm/errors/DependencyMissingKeyError.js +1 -0
- package/esm/errors/DependencyNotFoundError.js +1 -0
- package/esm/errors/MethodNotImplementedError.js +1 -0
- package/esm/errors/ProviderDisposedError.js +1 -0
- package/esm/errors/TypedEventDisposedError.js +1 -0
- package/esm/errors/UnsupportedTokenTypeError.js +1 -0
- package/esm/index.js +1 -0
- package/esm/provider/Provider.js +6 -6
- package/esm/registration/Registration.js +2 -2
- package/esm/token/ConstantToken.js +4 -4
- package/esm/token/FunctionToken.js +1 -1
- package/esm/token/GroupInstanceToken.js +4 -4
- package/esm/token/toToken.js +1 -1
- package/esm/utils/TypedEvent.js +1 -1
- package/esm/utils/array.js +1 -1
- package/lib/ExecutionContext.ts +6 -0
- package/lib/container/AliasMap.ts +30 -0
- package/lib/container/AutoResolveModule.ts +24 -0
- package/lib/container/Container.ts +311 -0
- package/lib/container/EmptyContainer.ts +166 -0
- package/lib/container/IContainer.ts +156 -0
- package/lib/errors/ArgumentNotFoundError.ts +13 -0
- package/lib/errors/CannonSingletonApplyTwiceError.ts +6 -0
- package/lib/errors/CannotApplySingletonTwiceError.ts +22 -0
- package/lib/errors/ContainerDisposedError.ts +13 -0
- package/lib/errors/ContainerError.ts +15 -0
- package/lib/errors/ContainerNotFoundError.ts +13 -0
- package/lib/errors/DependencyMissingKeyError.ts +13 -0
- package/lib/errors/DependencyNotFoundError.ts +13 -0
- package/lib/errors/MethodNotImplementedError.ts +13 -0
- package/lib/errors/ProviderDisposedError.ts +22 -0
- package/lib/errors/TypedEventDisposedError.ts +22 -0
- package/lib/errors/UnsupportedTokenTypeError.ts +13 -0
- package/lib/hooks/HookCollector.ts +109 -0
- package/lib/hooks/HookContext.ts +85 -0
- package/lib/hooks/combinators.ts +51 -0
- package/lib/hooks/hook.ts +89 -0
- package/lib/hooks/injectProp.ts +14 -0
- package/lib/index.ts +181 -0
- package/lib/injector/IInjector.ts +88 -0
- package/lib/injector/MetadataInjector.ts +100 -0
- package/lib/injector/ProxyInjector.ts +31 -0
- package/lib/injector/SimpleInjector.ts +20 -0
- package/lib/metadata/class.ts +50 -0
- package/lib/metadata/method.ts +47 -0
- package/lib/metadata/parameter.ts +60 -0
- package/lib/metadata/target.ts +25 -0
- package/lib/provider/IProvider.ts +65 -0
- package/lib/provider/Provider.ts +174 -0
- package/lib/registration/IRegistration.ts +235 -0
- package/lib/registration/Registration.ts +122 -0
- package/lib/select.ts +33 -0
- package/lib/token/BindToken.ts +13 -0
- package/lib/token/ClassToken.ts +72 -0
- package/lib/token/ConstantToken.ts +50 -0
- package/lib/token/FunctionToken.ts +79 -0
- package/lib/token/GroupAliasToken.ts +92 -0
- package/lib/token/GroupInstanceToken.ts +70 -0
- package/lib/token/InjectionToken.ts +46 -0
- package/lib/token/SingleAliasToken.ts +84 -0
- package/lib/token/SingleToken.ts +93 -0
- package/lib/token/toToken.ts +46 -0
- package/lib/utils/ProxyRegistry.ts +149 -0
- package/lib/utils/TypedEvent.ts +96 -0
- package/lib/utils/array.ts +28 -0
- package/lib/utils/basic.ts +34 -0
- package/lib/utils/debounce.ts +18 -0
- package/lib/utils/errorHandler.ts +34 -0
- package/lib/utils/fp.ts +86 -0
- package/lib/utils/getConstructorChain.ts +17 -0
- package/lib/utils/memoize.ts +24 -0
- package/lib/utils/once.ts +24 -0
- package/lib/utils/shallowCache.ts +22 -0
- package/lib/utils/task.ts +33 -0
- package/lib/utils/throttle.ts +17 -0
- package/package.json +5 -3
- package/typings/ExecutionContext.d.ts +2 -0
- package/typings/ExecutionContext.d.ts.map +1 -0
- package/typings/container/AliasMap.d.ts +1 -0
- package/typings/container/AliasMap.d.ts.map +1 -0
- package/typings/container/AutoResolveModule.d.ts +16 -0
- package/typings/container/AutoResolveModule.d.ts.map +1 -0
- package/typings/container/Container.d.ts +60 -0
- package/typings/container/Container.d.ts.map +1 -0
- package/typings/container/EmptyContainer.d.ts +51 -0
- package/typings/container/EmptyContainer.d.ts.map +1 -0
- package/typings/container/IContainer.d.ts +75 -0
- package/typings/container/IContainer.d.ts.map +1 -0
- package/typings/errors/ArgumentNotFoundError.d.ts +3 -0
- package/typings/errors/ArgumentNotFoundError.d.ts.map +1 -0
- package/typings/errors/CannonSingletonApplyTwiceError.d.ts +6 -6
- package/typings/errors/CannonSingletonApplyTwiceError.d.ts.map +1 -0
- package/typings/errors/CannotApplySingletonTwiceError.d.ts +12 -0
- package/typings/errors/CannotApplySingletonTwiceError.d.ts.map +1 -0
- package/typings/errors/ContainerDisposedError.d.ts +3 -0
- package/typings/errors/ContainerDisposedError.d.ts.map +1 -0
- package/typings/errors/ContainerError.d.ts +7 -0
- package/typings/errors/ContainerError.d.ts.map +1 -0
- package/typings/errors/ContainerNotFoundError.d.ts +3 -0
- package/typings/errors/ContainerNotFoundError.d.ts.map +1 -0
- package/typings/errors/DependencyMissingKeyError.d.ts +3 -0
- package/typings/errors/DependencyMissingKeyError.d.ts.map +1 -0
- package/typings/errors/DependencyNotFoundError.d.ts +3 -0
- package/typings/errors/DependencyNotFoundError.d.ts.map +1 -0
- package/typings/errors/MethodNotImplementedError.d.ts +3 -0
- package/typings/errors/MethodNotImplementedError.d.ts.map +1 -0
- package/typings/errors/ProviderDisposedError.d.ts +6 -0
- package/typings/errors/ProviderDisposedError.d.ts.map +1 -0
- package/typings/errors/TypedEventDisposedError.d.ts +6 -0
- package/typings/errors/TypedEventDisposedError.d.ts.map +1 -0
- package/typings/errors/UnsupportedTokenTypeError.d.ts +3 -0
- package/typings/errors/UnsupportedTokenTypeError.d.ts.map +1 -0
- package/typings/hooks/HookCollector.d.ts +36 -0
- package/typings/hooks/HookCollector.d.ts.map +1 -0
- package/typings/hooks/HookContext.d.ts +10 -0
- package/typings/hooks/HookContext.d.ts.map +1 -0
- package/typings/hooks/combinators.d.ts +23 -0
- package/typings/hooks/combinators.d.ts.map +1 -0
- package/typings/hooks/hook.d.ts +39 -0
- package/typings/hooks/hook.d.ts.map +1 -0
- package/typings/hooks/injectProp.d.ts +9 -0
- package/typings/hooks/injectProp.d.ts.map +1 -0
- package/typings/index.d.ts +2 -0
- package/typings/index.d.ts.map +1 -0
- package/typings/injector/IInjector.d.ts +32 -0
- package/typings/injector/IInjector.d.ts.map +1 -0
- package/typings/injector/MetadataInjector.d.ts +58 -0
- package/typings/injector/MetadataInjector.d.ts.map +1 -0
- package/typings/injector/ProxyInjector.d.ts +13 -0
- package/typings/injector/ProxyInjector.d.ts.map +1 -0
- package/typings/injector/SimpleInjector.d.ts +13 -0
- package/typings/injector/SimpleInjector.d.ts.map +1 -0
- package/typings/metadata/class.d.ts +27 -0
- package/typings/metadata/class.d.ts.map +1 -0
- package/typings/metadata/method.d.ts +24 -0
- package/typings/metadata/method.d.ts.map +1 -0
- package/typings/metadata/parameter.d.ts +21 -0
- package/typings/metadata/parameter.d.ts.map +1 -0
- package/typings/metadata/target.d.ts +19 -0
- package/typings/metadata/target.d.ts.map +1 -0
- package/typings/provider/IProvider.d.ts +25 -0
- package/typings/provider/IProvider.d.ts.map +1 -0
- package/typings/provider/Provider.d.ts +30 -0
- package/typings/provider/Provider.d.ts.map +1 -0
- package/typings/registration/IRegistration.d.ts +137 -0
- package/typings/registration/IRegistration.d.ts.map +1 -0
- package/typings/registration/Registration.d.ts +23 -0
- package/typings/registration/Registration.d.ts.map +1 -0
- package/typings/select.d.ts +15 -0
- package/typings/select.d.ts.map +1 -0
- package/typings/token/BindToken.d.ts +3 -0
- package/typings/token/BindToken.d.ts.map +1 -0
- package/typings/token/ClassToken.d.ts +2 -0
- package/typings/token/ClassToken.d.ts.map +1 -0
- package/typings/token/ConstantToken.d.ts +14 -0
- package/typings/token/ConstantToken.d.ts.map +1 -0
- package/typings/token/FunctionToken.d.ts +10 -0
- package/typings/token/FunctionToken.d.ts.map +1 -0
- package/typings/token/GroupAliasToken.d.ts +14 -0
- package/typings/token/GroupAliasToken.d.ts.map +1 -0
- package/typings/token/GroupInstanceToken.d.ts +19 -0
- package/typings/token/GroupInstanceToken.d.ts.map +1 -0
- package/typings/token/InjectionToken.d.ts +8 -0
- package/typings/token/InjectionToken.d.ts.map +1 -0
- package/typings/token/SingleAliasToken.d.ts +6 -0
- package/typings/token/SingleAliasToken.d.ts.map +1 -0
- package/typings/token/SingleToken.d.ts +18 -0
- package/typings/token/SingleToken.d.ts.map +1 -0
- package/typings/token/toToken.d.ts +12 -0
- package/typings/token/toToken.d.ts.map +1 -0
- package/typings/utils/ProxyRegistry.d.ts +63 -0
- package/typings/utils/ProxyRegistry.d.ts.map +1 -0
- package/typings/utils/TypedEvent.d.ts +42 -0
- package/typings/utils/TypedEvent.d.ts.map +1 -0
- package/typings/utils/array.d.ts +7 -0
- package/typings/utils/array.d.ts.map +1 -0
- package/typings/utils/basic.d.ts +12 -0
- package/typings/utils/basic.d.ts.map +1 -0
- package/typings/utils/debounce.d.ts +2 -0
- package/typings/utils/debounce.d.ts.map +1 -0
- package/typings/utils/errorHandler.d.ts +4 -0
- package/typings/utils/errorHandler.d.ts.map +1 -0
- package/typings/utils/fp.d.ts +8 -0
- package/typings/utils/fp.d.ts.map +1 -0
- package/typings/utils/getConstructorChain.d.ts +9 -0
- package/typings/utils/getConstructorChain.d.ts.map +1 -0
- package/typings/utils/memoize.d.ts +10 -0
- package/typings/utils/memoize.d.ts.map +1 -0
- package/typings/utils/once.d.ts +2 -0
- package/typings/utils/once.d.ts.map +1 -0
- package/typings/utils/shallowCache.d.ts +2 -0
- package/typings/utils/shallowCache.d.ts.map +1 -0
- package/typings/utils/task.d.ts +13 -0
- package/typings/utils/task.d.ts.map +1 -0
- package/typings/utils/throttle.d.ts +2 -0
- package/typings/utils/throttle.d.ts.map +1 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { resolveConstructor } from '../metadata/target';
|
|
2
|
+
|
|
3
|
+
/** Receives the error with the class and method it came from. */
|
|
4
|
+
export type HandleErrorParams = (error: unknown, context: { target: string; method: string }) => void;
|
|
5
|
+
|
|
6
|
+
/** Method decorator: routes a rejection of the async method to `errorHandler` instead of throwing. */
|
|
7
|
+
export const handleAsyncError =
|
|
8
|
+
(errorHandler: HandleErrorParams): MethodDecorator =>
|
|
9
|
+
(target, propertyKey, descriptor: PropertyDescriptor) => {
|
|
10
|
+
const originalMethod = descriptor.value;
|
|
11
|
+
descriptor.value = async function (...args: unknown[]) {
|
|
12
|
+
try {
|
|
13
|
+
return await originalMethod.apply(this, args);
|
|
14
|
+
} catch (e) {
|
|
15
|
+
errorHandler(e, { target: resolveConstructor(target).name, method: propertyKey as string });
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
return descriptor;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Method decorator: routes a throw of the method to `errorHandler` instead of throwing. */
|
|
22
|
+
export const handleError =
|
|
23
|
+
(errorHandler: HandleErrorParams): MethodDecorator =>
|
|
24
|
+
(target, propertyKey, descriptor: PropertyDescriptor) => {
|
|
25
|
+
const originalMethod = descriptor.value;
|
|
26
|
+
descriptor.value = function (...args: unknown[]) {
|
|
27
|
+
try {
|
|
28
|
+
return originalMethod.apply(this, args);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
errorHandler(e, { target: resolveConstructor(target).name, method: propertyKey as string });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return descriptor;
|
|
34
|
+
};
|
package/lib/utils/fp.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** A one-argument transform. */
|
|
2
|
+
export type MapFn<A, B = A> = (value: A) => B;
|
|
3
|
+
|
|
4
|
+
// Overloads for fp function to support up to 10 transformations
|
|
5
|
+
/**
|
|
6
|
+
* Composes functions left to right. With `by(...)` it maps an injected value.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* @inject(pipe(by(ConfigToken), (config) => config.apiUrl))
|
|
10
|
+
*/
|
|
11
|
+
export function pipe<A>(fn1: MapFn<A>): MapFn<A>;
|
|
12
|
+
export function pipe<A, B>(fn1: MapFn<A, B>): MapFn<A, B>;
|
|
13
|
+
export function pipe<A, B, C>(fn1: MapFn<A, B>, fn2: MapFn<B, C>): MapFn<A, C>;
|
|
14
|
+
export function pipe<A, B, C, D>(fn1: MapFn<A, B>, fn2: MapFn<B, C>, fn3: MapFn<C, D>): MapFn<A, D>;
|
|
15
|
+
export function pipe<A, B, C, D, E>(
|
|
16
|
+
fn1: MapFn<A, B>,
|
|
17
|
+
fn2: MapFn<B, C>,
|
|
18
|
+
fn3: MapFn<C, D>,
|
|
19
|
+
fn4: MapFn<D, E>,
|
|
20
|
+
): MapFn<A, E>;
|
|
21
|
+
export function pipe<A, B, C, D, E, F>(
|
|
22
|
+
fn1: MapFn<A, B>,
|
|
23
|
+
fn2: MapFn<B, C>,
|
|
24
|
+
fn3: MapFn<C, D>,
|
|
25
|
+
fn4: MapFn<D, E>,
|
|
26
|
+
fn5: MapFn<E, F>,
|
|
27
|
+
): MapFn<A, F>;
|
|
28
|
+
export function pipe<A, B, C, D, E, F, G>(
|
|
29
|
+
fn1: MapFn<A, B>,
|
|
30
|
+
fn2: MapFn<B, C>,
|
|
31
|
+
fn3: MapFn<C, D>,
|
|
32
|
+
fn4: MapFn<D, E>,
|
|
33
|
+
fn5: MapFn<E, F>,
|
|
34
|
+
fn6: MapFn<F, G>,
|
|
35
|
+
): MapFn<A, G>;
|
|
36
|
+
export function pipe<A, B, C, D, E, F, G, H>(
|
|
37
|
+
fn1: MapFn<A, B>,
|
|
38
|
+
fn2: MapFn<B, C>,
|
|
39
|
+
fn3: MapFn<C, D>,
|
|
40
|
+
fn4: MapFn<D, E>,
|
|
41
|
+
fn5: MapFn<E, F>,
|
|
42
|
+
fn6: MapFn<F, G>,
|
|
43
|
+
fn7: MapFn<G, H>,
|
|
44
|
+
): MapFn<A, H>;
|
|
45
|
+
export function pipe<A, B, C, D, E, F, G, H, I>(
|
|
46
|
+
fn1: MapFn<A, B>,
|
|
47
|
+
fn2: MapFn<B, C>,
|
|
48
|
+
fn3: MapFn<C, D>,
|
|
49
|
+
fn4: MapFn<D, E>,
|
|
50
|
+
fn5: MapFn<E, F>,
|
|
51
|
+
fn6: MapFn<F, G>,
|
|
52
|
+
fn7: MapFn<G, H>,
|
|
53
|
+
fn8: MapFn<H, I>,
|
|
54
|
+
): MapFn<A, I>;
|
|
55
|
+
export function pipe<A, B, C, D, E, F, G, H, I, J>(
|
|
56
|
+
fn1: MapFn<A, B>,
|
|
57
|
+
fn2: MapFn<B, C>,
|
|
58
|
+
fn3: MapFn<C, D>,
|
|
59
|
+
fn4: MapFn<D, E>,
|
|
60
|
+
fn5: MapFn<E, F>,
|
|
61
|
+
fn6: MapFn<F, G>,
|
|
62
|
+
fn7: MapFn<G, H>,
|
|
63
|
+
fn8: MapFn<H, I>,
|
|
64
|
+
fn9: MapFn<I, J>,
|
|
65
|
+
): MapFn<A, J>;
|
|
66
|
+
export function pipe<A, B, C, D, E, F, G, H, I, J, K>(
|
|
67
|
+
fn1: MapFn<A, B>,
|
|
68
|
+
fn2: MapFn<B, C>,
|
|
69
|
+
fn3: MapFn<C, D>,
|
|
70
|
+
fn4: MapFn<D, E>,
|
|
71
|
+
fn5: MapFn<E, F>,
|
|
72
|
+
fn6: MapFn<F, G>,
|
|
73
|
+
fn7: MapFn<G, H>,
|
|
74
|
+
fn8: MapFn<H, I>,
|
|
75
|
+
fn9: MapFn<I, J>,
|
|
76
|
+
fn10: MapFn<J, K>,
|
|
77
|
+
): MapFn<A, K>;
|
|
78
|
+
// Fallback for cases where pipes are used with spreads or variable length (same type)
|
|
79
|
+
|
|
80
|
+
export function pipe<T>(...mappers: MapFn<T>[]): MapFn<T>;
|
|
81
|
+
// Implementation
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
83
|
+
export function pipe(...mappers: MapFn<any, any>[]): MapFn<any, any> {
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
|
+
return (value: any) => mappers.reduce((acc, current) => current(acc), value);
|
|
86
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walks a constructor's prototype chain, most-derived first, and collects each
|
|
3
|
+
* class in it: `[Derived, Base, ...]`, stopping before `Function.prototype`.
|
|
4
|
+
*
|
|
5
|
+
* Reading own metadata off each entry in turn is how a class inherits what its
|
|
6
|
+
* ancestors declared — `Reflect.getOwnMetadata` never looks up the chain itself.
|
|
7
|
+
* Anything which is not a function yields an empty chain.
|
|
8
|
+
*/
|
|
9
|
+
export const getConstructorChain = (ctor: unknown): object[] => {
|
|
10
|
+
const chain: object[] = [];
|
|
11
|
+
let current = ctor;
|
|
12
|
+
while (typeof current === 'function' && current !== Function.prototype) {
|
|
13
|
+
chain.push(current);
|
|
14
|
+
current = Object.getPrototypeOf(current);
|
|
15
|
+
}
|
|
16
|
+
return chain;
|
|
17
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a two-argument function so each `(target, key)` pair is computed once
|
|
3
|
+
* and reused. `target` is held weakly, so memoizing against a class or an
|
|
4
|
+
* instance keeps nothing alive.
|
|
5
|
+
*
|
|
6
|
+
* ```typescript
|
|
7
|
+
* const hooksOf = memoize((Target: constructor<unknown>, key: string | symbol) => merge(Target, key));
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export const memoize = <T extends object, K, R>(fn: (target: T, key: K) => R): ((target: T, key: K) => R) => {
|
|
11
|
+
const cache = new WeakMap<T, Map<K, R>>();
|
|
12
|
+
|
|
13
|
+
return (target, key) => {
|
|
14
|
+
let byKey = cache.get(target);
|
|
15
|
+
if (!byKey) {
|
|
16
|
+
byKey = new Map();
|
|
17
|
+
cache.set(target, byKey);
|
|
18
|
+
}
|
|
19
|
+
if (!byKey.has(key)) {
|
|
20
|
+
byKey.set(key, fn(target, key));
|
|
21
|
+
}
|
|
22
|
+
return byKey.get(key) as R;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type RepeatOptions = {
|
|
2
|
+
index: number;
|
|
3
|
+
args: unknown[];
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
/** Method decorator: runs the method once per instance and returns the cached result afterwards. */
|
|
7
|
+
export const once =
|
|
8
|
+
({ onRepeat }: { onRepeat?: (options: RepeatOptions) => void } = {}): MethodDecorator =>
|
|
9
|
+
(target, propertyKey, descriptor: PropertyDescriptor) => {
|
|
10
|
+
const originalMethod = descriptor.value;
|
|
11
|
+
const cacheMap = new WeakMap<object, unknown>();
|
|
12
|
+
let index = 0;
|
|
13
|
+
descriptor.value = function (...args: unknown[]) {
|
|
14
|
+
index++;
|
|
15
|
+
if (cacheMap.has(this)) {
|
|
16
|
+
onRepeat?.({ index: index - 1, args });
|
|
17
|
+
return cacheMap.get(this);
|
|
18
|
+
}
|
|
19
|
+
const result = originalMethod.apply(this, args);
|
|
20
|
+
cacheMap.set(this, result);
|
|
21
|
+
return result;
|
|
22
|
+
};
|
|
23
|
+
return descriptor;
|
|
24
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Method decorator: caches results per instance by the key `getKeyByArgs` returns. */
|
|
2
|
+
export const shallowCache =
|
|
3
|
+
(getKeyByArgs: (...args: unknown[]) => unknown): MethodDecorator =>
|
|
4
|
+
(target, propertyKey, descriptor: PropertyDescriptor) => {
|
|
5
|
+
const originalMethod = descriptor.value;
|
|
6
|
+
const cacheMap = new WeakMap<object, Map<unknown, unknown>>();
|
|
7
|
+
descriptor.value = function (...args: unknown[]) {
|
|
8
|
+
let cache = cacheMap.get(this);
|
|
9
|
+
if (cache === undefined) {
|
|
10
|
+
cache = new Map();
|
|
11
|
+
cacheMap.set(this, cache);
|
|
12
|
+
}
|
|
13
|
+
const key = getKeyByArgs(...args);
|
|
14
|
+
if (cache.has(key)) {
|
|
15
|
+
return cache.get(key);
|
|
16
|
+
}
|
|
17
|
+
const result = originalMethod.apply(this, args);
|
|
18
|
+
cache.set(key, result);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
return descriptor;
|
|
22
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A unit of work which may or may not go async: the sync-until-async shape the
|
|
3
|
+
* hook machinery is built on (ADR 0013).
|
|
4
|
+
*/
|
|
5
|
+
export type Task = () => void | Promise<void>;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Runs `tasks` in order, staying synchronous until one returns a promise and
|
|
9
|
+
* awaiting the rest from that point. `undefined` when none went async.
|
|
10
|
+
*/
|
|
11
|
+
export const runInOrder = (tasks: Task[], from = 0): void | Promise<void> => {
|
|
12
|
+
for (let i = from; i < tasks.length; i++) {
|
|
13
|
+
const result = tasks[i]();
|
|
14
|
+
if (result instanceof Promise) {
|
|
15
|
+
return result.then(() => runInOrder(tasks, i + 1));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Starts every task at once. Settles once all have; `undefined` when none went
|
|
22
|
+
* async, so a fully synchronous run hands back no promise.
|
|
23
|
+
*/
|
|
24
|
+
export const runAtOnce = (tasks: Task[]): void | Promise<void> => {
|
|
25
|
+
const pending: Promise<void>[] = [];
|
|
26
|
+
for (const task of tasks) {
|
|
27
|
+
const result = task();
|
|
28
|
+
if (result instanceof Promise) {
|
|
29
|
+
pending.push(result);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return pending.length > 0 ? Promise.all(pending).then(() => undefined) : undefined;
|
|
33
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Method decorator: ignores calls within `ms` of the last accepted one (per instance). */
|
|
2
|
+
export const throttle =
|
|
3
|
+
(ms: number): MethodDecorator =>
|
|
4
|
+
(target, propertyKey, descriptor: PropertyDescriptor) => {
|
|
5
|
+
const originalMethod = descriptor.value;
|
|
6
|
+
const lastCalledMap = new WeakMap<object, number>();
|
|
7
|
+
descriptor.value = function (...args: unknown[]) {
|
|
8
|
+
const now = Date.now();
|
|
9
|
+
const lastCalled = lastCalledMap.get(this) ?? -Infinity;
|
|
10
|
+
if (now - lastCalled < ms) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
lastCalledMap.set(this, now);
|
|
14
|
+
return originalMethod.apply(this, args);
|
|
15
|
+
};
|
|
16
|
+
return descriptor;
|
|
17
|
+
};
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-ioc-container",
|
|
3
|
-
"version": "72.
|
|
3
|
+
"version": "72.2.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",
|
|
7
7
|
"registry": "https://registry.npmjs.org/"
|
|
8
8
|
},
|
|
9
9
|
"author": "ibabkin <igba14@gmail.com>",
|
|
10
|
-
"homepage": "https://
|
|
10
|
+
"homepage": "https://github.com/IgorBabkin/ts-ioc-container/tree/main/packages/ts-ioc-container#readme",
|
|
11
11
|
"license": "ISC",
|
|
12
12
|
"sideEffects": false,
|
|
13
13
|
"main": "cjm/index.js",
|
|
@@ -54,7 +54,9 @@
|
|
|
54
54
|
"files": [
|
|
55
55
|
"cjm/**/*",
|
|
56
56
|
"esm/**/*",
|
|
57
|
-
"typings/**/*"
|
|
57
|
+
"typings/**/*",
|
|
58
|
+
"lib/**/*",
|
|
59
|
+
"AGENTS.md"
|
|
58
60
|
],
|
|
59
61
|
"repository": {
|
|
60
62
|
"type": "git",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExecutionContext.d.ts","sourceRoot":"","sources":["../lib/ExecutionContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,UAAU,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AliasMap.d.ts","sourceRoot":"","sources":["../../lib/container/AliasMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,MAAM,KAAK,GAAG,aAAa,CAAC;AAElC,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwC;IAEtE,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,EAAE;IAIrD,eAAe,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI;IAenE,OAAO,IAAI,IAAI;CAGhB"}
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { type AutoResolveOptions, type IContainer, type IContainerModule } from './IContainer.js';
|
|
2
|
+
/**
|
|
3
|
+
* Enables eager resolution of providers marked with the `autoResolve()` pipe.
|
|
4
|
+
*
|
|
5
|
+
* Every scope created after this module is applied resolves its own
|
|
6
|
+
* auto-resolvable providers as part of `createScope`, so the instances exist
|
|
7
|
+
* before anyone asks for them. Child scopes inherit the behaviour, so a single
|
|
8
|
+
* `useModule` call on the root covers the whole scope tree.
|
|
9
|
+
*
|
|
10
|
+
* `options.args` are forwarded to every eagerly resolved provider of every such
|
|
11
|
+
* scope. Pass a per-scope value by calling `scope.autoResolve({ args })`
|
|
12
|
+
* directly instead.
|
|
13
|
+
*
|
|
14
|
+
* The container the module is applied to is not a created scope — call
|
|
15
|
+
* `container.autoResolve()` explicitly to eagerly resolve its own providers.
|
|
16
|
+
*/
|
|
2
17
|
export declare class AutoResolveModule implements IContainerModule {
|
|
3
18
|
private readonly options;
|
|
4
19
|
constructor(options?: AutoResolveOptions);
|
|
5
20
|
applyTo(container: IContainer): void;
|
|
6
21
|
}
|
|
22
|
+
//# sourceMappingURL=AutoResolveModule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutoResolveModule.d.ts","sourceRoot":"","sources":["../../lib/container/AutoResolveModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAE/F;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAkB,YAAW,gBAAgB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,GAAE,kBAAuB;IAE7D,OAAO,CAAC,SAAS,EAAE,UAAU,GAAG,IAAI;CAGrC"}
|
|
@@ -4,6 +4,22 @@ import { type IProvider } from '../provider/IProvider.js';
|
|
|
4
4
|
import { type IRegistration } from '../registration/IRegistration.js';
|
|
5
5
|
import { constructor, Instance } from '../utils/basic.js';
|
|
6
6
|
import { type ITypedEvent } from '../utils/TypedEvent.js';
|
|
7
|
+
/**
|
|
8
|
+
* A dependency injection scope. Each container is a node in a parent chain:
|
|
9
|
+
* a key not found here (or denied by `scopeAccess`) is resolved from the parent,
|
|
10
|
+
* and the root's parent is an {@link EmptyContainer} that throws
|
|
11
|
+
* `DependencyNotFoundError`. Child scopes come from `createScope({ tags })`,
|
|
12
|
+
* which copies the matching registrations into the child at that moment.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const app = new Container({ tags: ['application'] })
|
|
16
|
+
* .addRegistration(Registration.fromClass(Logger))
|
|
17
|
+
* .addRegistration(Registration.fromValue(config).bindTo('Config'));
|
|
18
|
+
*
|
|
19
|
+
* const request = app.createScope({ tags: ['request'] });
|
|
20
|
+
* const logger = ILoggerToken.resolve(request);
|
|
21
|
+
* request.dispose();
|
|
22
|
+
*/
|
|
7
23
|
export declare class Container implements IContainer {
|
|
8
24
|
isDisposed: boolean;
|
|
9
25
|
private parent;
|
|
@@ -25,12 +41,40 @@ export declare class Container implements IContainer {
|
|
|
25
41
|
parent?: IContainer;
|
|
26
42
|
tags?: Tag[];
|
|
27
43
|
});
|
|
44
|
+
/**
|
|
45
|
+
* @throws {ContainerDisposedError} when the container has already been disposed.
|
|
46
|
+
*/
|
|
28
47
|
register(key: DependencyKey, provider: IProvider, { aliases }?: RegisterOptions): this;
|
|
48
|
+
/**
|
|
49
|
+
* @throws {ContainerDisposedError} when the container has already been disposed.
|
|
50
|
+
* @throws {DependencyNotFoundError} when `target` cannot be resolved in this container or any parent scope.
|
|
51
|
+
*/
|
|
29
52
|
resolve<T>(target: constructor<T> | DependencyKey, { args, child, lazy }?: ResolveOneOptions): T;
|
|
53
|
+
/**
|
|
54
|
+
* @throws {ContainerDisposedError} when the container has already been disposed.
|
|
55
|
+
* @throws {DependencyNotFoundError} when a key registered under `alias` has no matching provider.
|
|
56
|
+
*/
|
|
30
57
|
resolveByAlias<T>(alias: DependencyKey, { args, child, lazy, excludedKeys }?: ResolveManyOptions): T[];
|
|
58
|
+
/**
|
|
59
|
+
* @throws {ContainerDisposedError} when the container has already been disposed.
|
|
60
|
+
* @throws {DependencyNotFoundError} when `alias` cannot be resolved in this container or any parent scope.
|
|
61
|
+
*/
|
|
31
62
|
resolveOneByAlias<T>(alias: DependencyKey, { args, child, lazy }?: ResolveOneOptions): T;
|
|
63
|
+
/**
|
|
64
|
+
* @throws {ContainerDisposedError} when the container has already been disposed.
|
|
65
|
+
*/
|
|
32
66
|
createScope({ tags }?: CreateScopeOptions): IContainer;
|
|
67
|
+
/**
|
|
68
|
+
* Eagerly resolves every provider of this scope which was marked with `autoResolve()`.
|
|
69
|
+
*
|
|
70
|
+
* `args` are forwarded to each of those providers, exactly as `resolve` forwards them.
|
|
71
|
+
*
|
|
72
|
+
* @throws {ContainerDisposedError} when the container has already been disposed.
|
|
73
|
+
*/
|
|
33
74
|
autoResolve({ args }?: AutoResolveOptions): this;
|
|
75
|
+
/**
|
|
76
|
+
* @throws {ContainerDisposedError} when the container has already been disposed.
|
|
77
|
+
*/
|
|
34
78
|
dispose(): void;
|
|
35
79
|
addRegistration(registration: IRegistration): this;
|
|
36
80
|
getRegistrations(): IRegistration[];
|
|
@@ -38,6 +82,15 @@ export declare class Container implements IContainer {
|
|
|
38
82
|
hasRegistration(key: DependencyKey): boolean;
|
|
39
83
|
addInstance(instance: Instance): void;
|
|
40
84
|
getScopes(): IContainer[];
|
|
85
|
+
/**
|
|
86
|
+
* Whether this scope created `instance`.
|
|
87
|
+
*
|
|
88
|
+
* A proxy stands for the object behind it, so it is unwrapped before the
|
|
89
|
+
* lookup - the container tracks real instances, and a caller asking about a
|
|
90
|
+
* proxy is asking about its target. Resolving a lazy proxy's target is what
|
|
91
|
+
* makes that answer possible, so a still-unresolved lazy proxy is resolved
|
|
92
|
+
* here.
|
|
93
|
+
*/
|
|
41
94
|
hasInstance(instance: Instance): boolean;
|
|
42
95
|
removeScope(child: IContainer): void;
|
|
43
96
|
useModule(module: IContainerModule): this;
|
|
@@ -45,6 +98,13 @@ export declare class Container implements IContainer {
|
|
|
45
98
|
getInstances(cascade?: boolean): Instance[];
|
|
46
99
|
hasTag(tag: Tag): boolean;
|
|
47
100
|
addTags(...tags: Tag[]): void;
|
|
101
|
+
/**
|
|
102
|
+
* @throws {ContainerDisposedError} when the container has already been disposed.
|
|
103
|
+
*/
|
|
48
104
|
private validateContainer;
|
|
105
|
+
/**
|
|
106
|
+
* @throws {DependencyNotFoundError} when no provider is registered under `key` in this container.
|
|
107
|
+
*/
|
|
49
108
|
private findProviderByKeyOrFail;
|
|
50
109
|
}
|
|
110
|
+
//# sourceMappingURL=Container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../lib/container/Container.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,29 +4,80 @@ import { type IRegistration } from '../registration/IRegistration.js';
|
|
|
4
4
|
import { type constructor, type Instance } from '../utils/basic.js';
|
|
5
5
|
import { type IInjector } from '../injector/IInjector.js';
|
|
6
6
|
import { type ITypedEvent } from '../utils/TypedEvent.js';
|
|
7
|
+
/**
|
|
8
|
+
* Terminates the parent chain of every root {@link Container}: `resolve` throws
|
|
9
|
+
* `DependencyNotFoundError`, alias lookups return nothing, and every other
|
|
10
|
+
* method throws `MethodNotImplementedError`. You rarely use it directly.
|
|
11
|
+
*/
|
|
7
12
|
export declare class EmptyContainer implements IContainer {
|
|
13
|
+
/**
|
|
14
|
+
* @throws {MethodNotImplementedError} always — the empty container has no disposal state.
|
|
15
|
+
*/
|
|
8
16
|
get isDisposed(): boolean;
|
|
9
17
|
addInstance(instance: Instance): void;
|
|
10
18
|
getParent(): undefined;
|
|
11
19
|
getScopes(): never[];
|
|
12
20
|
getInstances(): never[];
|
|
13
21
|
hasInstance(instance: Instance): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* @throws {MethodNotImplementedError} always — the empty container cannot create scopes.
|
|
24
|
+
*/
|
|
14
25
|
createScope(): IContainer;
|
|
26
|
+
/**
|
|
27
|
+
* @throws {MethodNotImplementedError} always — the empty container constructs nothing, so it has no injector.
|
|
28
|
+
*/
|
|
15
29
|
getInjector(): IInjector;
|
|
30
|
+
/**
|
|
31
|
+
* @throws {MethodNotImplementedError} always — the empty container holds no providers to resolve.
|
|
32
|
+
*/
|
|
16
33
|
autoResolve(options?: AutoResolveOptions): this;
|
|
34
|
+
/**
|
|
35
|
+
* @throws {MethodNotImplementedError} always — the empty container cannot be disposed.
|
|
36
|
+
*/
|
|
17
37
|
dispose(): void;
|
|
38
|
+
/**
|
|
39
|
+
* @throws {MethodNotImplementedError} always — the empty container cannot hold registrations.
|
|
40
|
+
*/
|
|
18
41
|
register(key: DependencyKey, value: IProvider): this;
|
|
42
|
+
/**
|
|
43
|
+
* @throws {MethodNotImplementedError} always — the empty container has no tags.
|
|
44
|
+
*/
|
|
19
45
|
hasTag(tag: Tag): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* @throws {MethodNotImplementedError} always — the empty container has no tags.
|
|
48
|
+
*/
|
|
20
49
|
addTags(...tags: Tag[]): void;
|
|
21
50
|
getRegistrations(): never[];
|
|
22
51
|
hasRegistration(key: DependencyKey): boolean;
|
|
23
52
|
removeScope(): void;
|
|
53
|
+
/**
|
|
54
|
+
* @throws {MethodNotImplementedError} always — the empty container cannot use modules.
|
|
55
|
+
*/
|
|
24
56
|
useModule(module: IContainerModule): this;
|
|
57
|
+
/**
|
|
58
|
+
* @throws {MethodNotImplementedError} always — the empty container cannot hold registrations.
|
|
59
|
+
*/
|
|
25
60
|
addRegistration(registration: IRegistration): this;
|
|
61
|
+
/**
|
|
62
|
+
* @throws {DependencyNotFoundError} always — reaching the empty container means `key` was not found in any scope.
|
|
63
|
+
*/
|
|
26
64
|
resolve<T>(key: constructor<T> | DependencyKey, options?: ResolveOneOptions): T;
|
|
27
65
|
resolveByAlias<T>(alias: DependencyKey, options?: ResolveManyOptions): T[];
|
|
66
|
+
/**
|
|
67
|
+
* @throws {DependencyNotFoundError} always — reaching the empty container means `alias` was not found in any scope.
|
|
68
|
+
*/
|
|
28
69
|
resolveOneByAlias<T>(alias: DependencyKey, options?: ResolveOneOptions): T;
|
|
70
|
+
/**
|
|
71
|
+
* @throws {MethodNotImplementedError} always — the empty container cannot hold hooks.
|
|
72
|
+
*/
|
|
29
73
|
get scopeCreated(): ITypedEvent<[IContainer]>;
|
|
74
|
+
/**
|
|
75
|
+
* @throws {MethodNotImplementedError} always — the empty container cannot hold hooks.
|
|
76
|
+
*/
|
|
30
77
|
get scopeDisposed(): ITypedEvent<[IContainer]>;
|
|
78
|
+
/**
|
|
79
|
+
* @throws {MethodNotImplementedError} always — the empty container cannot hold hooks.
|
|
80
|
+
*/
|
|
31
81
|
get registered(): ITypedEvent<[IProvider, DependencyKey, IContainer]>;
|
|
32
82
|
}
|
|
83
|
+
//# sourceMappingURL=EmptyContainer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyContainer.d.ts","sourceRoot":"","sources":["../../lib/container/EmptyContainer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,GAAG,EACT,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;GAIG;AACH,qBAAa,cAAe,YAAW,UAAU;IAC/C;;OAEG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,WAAW,CAAC,QAAQ,EAAE,QAAQ;IAE9B,SAAS;IAIT,SAAS;IAIT,YAAY;IAIZ,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO;IAIxC;;OAEG;IACH,WAAW,IAAI,UAAU;IAIzB;;OAEG;IACH,WAAW,IAAI,SAAS;IAIxB;;OAEG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI;IAI/C;;OAEG;IACH,OAAO,IAAI,IAAI;IAIf;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI;IAIpD;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO;IAIzB;;OAEG;IACH,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAI7B,gBAAgB;IAIhB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO;IAI5C,WAAW,IAAI,IAAI;IAEnB;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAIzC;;OAEG;IACH,eAAe,CAAC,YAAY,EAAE,aAAa,GAAG,IAAI;IAIlD;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,aAAa,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,CAAC;IAQ/E,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,CAAC,EAAE;IAI1E;;OAEG;IACH,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,CAAC;IAM1E;;OAEG;IACH,IAAI,YAAY,IAAI,WAAW,CAAC,CAAC,UAAU,CAAC,CAAC,CAE5C;IAED;;OAEG;IACH,IAAI,aAAa,IAAI,WAAW,CAAC,CAAC,UAAU,CAAC,CAAC,CAE7C;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,WAAW,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC,CAEpE;CACF"}
|
|
@@ -3,8 +3,11 @@ import { type IRegistration } from '../registration/IRegistration.js';
|
|
|
3
3
|
import { IInjector, type WithArgs } from '../injector/IInjector.js';
|
|
4
4
|
import { type constructor, Instance } from '../utils/basic.js';
|
|
5
5
|
import { type ITypedEvent } from '../utils/TypedEvent.js';
|
|
6
|
+
/** A registration key: a string or a symbol. */
|
|
6
7
|
export type DependencyKey = string | symbol;
|
|
8
|
+
/** Narrows `target` to a {@link DependencyKey}. */
|
|
7
9
|
export declare function isDependencyKey(target: unknown): target is DependencyKey;
|
|
10
|
+
/** A scope label (`'application'`, `'request'`, ...) matched by `scope(...)` rules. */
|
|
8
11
|
export type Tag = string;
|
|
9
12
|
type WithTags = {
|
|
10
13
|
tags: Tag[];
|
|
@@ -15,47 +18,119 @@ type WithChild = {
|
|
|
15
18
|
type WithExcludedKeys = {
|
|
16
19
|
excludedKeys: DependencyKey[];
|
|
17
20
|
};
|
|
21
|
+
/** Something carrying tags: a scope or a token. */
|
|
18
22
|
export interface Tagged {
|
|
19
23
|
hasTag(tag: Tag): boolean;
|
|
20
24
|
addTags(...tags: Tag[]): void;
|
|
21
25
|
}
|
|
26
|
+
/** Options of `resolve`: runtime `args`, `lazy`, and the invoking `child` scope. */
|
|
22
27
|
export type ResolveOneOptions = ResolveOptions & Partial<WithChild>;
|
|
28
|
+
/** Options of `resolveByAlias`: like {@link ResolveOneOptions}, plus keys to exclude. */
|
|
23
29
|
export type ResolveManyOptions = ResolveOneOptions & Partial<WithExcludedKeys>;
|
|
30
|
+
/** Something that resolves a key or a class. */
|
|
24
31
|
export interface Resolvable {
|
|
25
32
|
resolve<T>(key: constructor<T> | DependencyKey, options?: ResolveOneOptions): T;
|
|
26
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* A reusable bundle of registrations or event subscriptions applied with
|
|
36
|
+
* `container.useModule(module)`. A plain object with `applyTo` is enough.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const loggingModule: IContainerModule = {
|
|
40
|
+
* applyTo: (container) => container.addRegistration(Registration.fromClass(Logger)),
|
|
41
|
+
* };
|
|
42
|
+
*/
|
|
27
43
|
export interface IContainerModule {
|
|
28
44
|
applyTo(container: IContainer): void;
|
|
29
45
|
}
|
|
46
|
+
/** Options of `createScope`: the child scope's `tags`. */
|
|
30
47
|
export type CreateScopeOptions = Partial<WithTags>;
|
|
31
48
|
export type AutoResolveOptions = Partial<WithArgs>;
|
|
32
49
|
export type RegisterOptions = {
|
|
33
50
|
aliases?: DependencyKey[];
|
|
34
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Scope event hooks - the container's own domain: a scope was created, a scope
|
|
54
|
+
* was disposed. The listener type of `IContainer.scopeCreated` / `scopeDisposed`.
|
|
55
|
+
*
|
|
56
|
+
* The other two hook domains live with the abstraction which raises them:
|
|
57
|
+
* injector hooks on `IInjector` (`InjectorHook`), provider hooks on
|
|
58
|
+
* {@link IProvider} (`ProviderHook`). An injector is configured before it is
|
|
59
|
+
* passed to a container's constructor, so a container never hands its injector
|
|
60
|
+
* out.
|
|
61
|
+
*/
|
|
35
62
|
export type ScopeHook = (scope: IContainer) => void;
|
|
63
|
+
/**
|
|
64
|
+
* Scope event hook for a registration landing in a scope: a provider entered
|
|
65
|
+
* the provider map under `key`. Registration is always of a provider, so the
|
|
66
|
+
* name says only what varies. The listener type of `IContainer.registered`.
|
|
67
|
+
*/
|
|
36
68
|
export type RegisteredHook = (provider: IProvider, key: DependencyKey, scope: IContainer) => void;
|
|
69
|
+
/** A dependency injection scope. See {@link Container}. */
|
|
37
70
|
export interface IContainer extends Tagged {
|
|
38
71
|
readonly isDisposed: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Raised once a scope this container created is fully registered and attached.
|
|
74
|
+
* The subscriber's side only - a container raises its own scope events.
|
|
75
|
+
*/
|
|
39
76
|
readonly scopeCreated: ITypedEvent<[IContainer]>;
|
|
77
|
+
/**
|
|
78
|
+
* Raised by this container as it disposes, before its providers and instances go.
|
|
79
|
+
*/
|
|
40
80
|
readonly scopeDisposed: ITypedEvent<[IContainer]>;
|
|
81
|
+
/**
|
|
82
|
+
* Raised once a provider is registered here under a resolvable key.
|
|
83
|
+
*/
|
|
41
84
|
readonly registered: ITypedEvent<[IProvider, DependencyKey, IContainer]>;
|
|
85
|
+
/** Low-level: puts `value` under `key` in this scope only. Prefer `addRegistration`. */
|
|
42
86
|
register(key: DependencyKey, value: IProvider, options?: RegisterOptions): this;
|
|
87
|
+
/** Registers here if the registration's scope rules match, and remembers it for future child scopes. */
|
|
43
88
|
addRegistration(registration: IRegistration): this;
|
|
89
|
+
/** Registrations added to this scope and its parents - what `createScope` copies. */
|
|
44
90
|
getRegistrations(): IRegistration[];
|
|
91
|
+
/** Whether a provider is registered under `key` in this scope (parents are not checked). */
|
|
45
92
|
hasRegistration(key: DependencyKey): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Resolves a key, or constructs a class with the injector. Takes a key or a
|
|
95
|
+
* class, not a token: for a token call `token.resolve(scope)`.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* scope.resolve<ILogger>('ILogger');
|
|
99
|
+
* scope.resolve(App, { args: ['tenant-1'] });
|
|
100
|
+
*/
|
|
46
101
|
resolve<T>(target: constructor<T> | DependencyKey, options?: ResolveOneOptions): T;
|
|
102
|
+
/** Resolves every accessible dependency registered under `alias`, in this scope and its parents. */
|
|
47
103
|
resolveByAlias<T>(alias: DependencyKey, options?: ResolveManyOptions): T[];
|
|
104
|
+
/** Resolves one dependency registered under `alias`, looking here first and then in parents. */
|
|
48
105
|
resolveOneByAlias<T>(alias: DependencyKey, options?: ResolveOneOptions): T;
|
|
106
|
+
/**
|
|
107
|
+
* Creates a child scope and copies into it the registrations whose scope
|
|
108
|
+
* rules match its tags. Registrations added later are not copied into it.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* const request = app.createScope({ tags: ['request'] });
|
|
112
|
+
*/
|
|
49
113
|
createScope(options?: CreateScopeOptions): IContainer;
|
|
114
|
+
/** Resolves every provider marked with `autoResolve()`. */
|
|
50
115
|
autoResolve(options?: AutoResolveOptions): this;
|
|
116
|
+
/** Direct child scopes that are still alive. */
|
|
51
117
|
getScopes(): IContainer[];
|
|
118
|
+
/** Detaches a child scope; called by the child on dispose. */
|
|
52
119
|
removeScope(child: IContainer): void;
|
|
120
|
+
/** Applies a module to this scope. */
|
|
53
121
|
useModule(module: IContainerModule): this;
|
|
122
|
+
/** The parent scope, if any. */
|
|
54
123
|
getParent(): IContainer | undefined;
|
|
124
|
+
/** Instances constructed in this scope, and in child scopes when `cascade` is true. */
|
|
55
125
|
getInstances(cascade?: boolean): Instance[];
|
|
126
|
+
/** Whether this scope tracks `instance`. */
|
|
56
127
|
hasInstance(instance: Instance): boolean;
|
|
128
|
+
/** Raises `scopeDisposed`, drops providers and instances, and detaches from the parent. Child scopes are not disposed. */
|
|
57
129
|
dispose(): void;
|
|
130
|
+
/** Tracks an instance in this scope; called by the injector. */
|
|
58
131
|
addInstance(instance: Instance): void;
|
|
132
|
+
/** The injector shared by this scope tree, e.g. to subscribe to `onConstructed`. */
|
|
59
133
|
getInjector(): IInjector;
|
|
60
134
|
}
|
|
61
135
|
export {};
|
|
136
|
+
//# sourceMappingURL=IContainer.d.ts.map
|