@lppedd/di-wise-neo 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.d.ts +55 -6
- package/dist/cjs/index.js +61 -19
- package/dist/cjs/index.js.map +1 -1
- package/dist/es/index.d.mts +55 -6
- package/dist/es/index.mjs +61 -20
- package/dist/es/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/es/index.d.mts
CHANGED
|
@@ -274,18 +274,46 @@ type Provider<Value = any> = ClassProvider<Value & object> | FactoryProvider<Val
|
|
|
274
274
|
* Container creation options.
|
|
275
275
|
*/
|
|
276
276
|
interface ContainerOptions {
|
|
277
|
+
/**
|
|
278
|
+
* The default scope for registrations.
|
|
279
|
+
*
|
|
280
|
+
* @defaultValue Scope.Transient
|
|
281
|
+
*/
|
|
282
|
+
readonly defaultScope: Scope;
|
|
277
283
|
/**
|
|
278
284
|
* Whether to automatically register an unregistered class when resolving it as a token.
|
|
279
285
|
*
|
|
280
286
|
* @defaultValue false
|
|
281
287
|
*/
|
|
282
288
|
readonly autoRegister: boolean;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Child container creation options.
|
|
292
|
+
*/
|
|
293
|
+
interface ChildContainerOptions extends ContainerOptions {
|
|
283
294
|
/**
|
|
284
|
-
*
|
|
295
|
+
* Whether to copy {@link ContainerHook}(s) from the parent container.
|
|
285
296
|
*
|
|
286
|
-
* @defaultValue
|
|
297
|
+
* @defaultValue true
|
|
287
298
|
*/
|
|
288
|
-
readonly
|
|
299
|
+
readonly copyHooks: boolean;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* A hook into the lifecycle of a container-managed value.
|
|
303
|
+
*/
|
|
304
|
+
interface ContainerHook {
|
|
305
|
+
/**
|
|
306
|
+
* Called when the container provides a value for a {@link Token}.
|
|
307
|
+
* - For _container_ scoped tokens, it is called only once when the token is first resolved and cached.
|
|
308
|
+
* - For _resolution_ scoped tokens, it is called once per token resolution graph.
|
|
309
|
+
* - For _transient_ scoped tokens, it is called each time the token is resolved,
|
|
310
|
+
* which might mean multiple times per resolution graph.
|
|
311
|
+
*/
|
|
312
|
+
readonly onProvide: (value: unknown) => void;
|
|
313
|
+
/**
|
|
314
|
+
* Called when a _container_ scoped value is about to be disposed.
|
|
315
|
+
*/
|
|
316
|
+
readonly onDispose: (value: unknown) => void;
|
|
289
317
|
}
|
|
290
318
|
/**
|
|
291
319
|
* Container API.
|
|
@@ -308,7 +336,7 @@ interface Container {
|
|
|
308
336
|
*
|
|
309
337
|
* You can pass specific options to override the inherited ones.
|
|
310
338
|
*/
|
|
311
|
-
createChild(options?: Partial<
|
|
339
|
+
createChild(options?: Partial<ChildContainerOptions>): Container;
|
|
312
340
|
/**
|
|
313
341
|
* Clears and returns all distinct cached values from this container's internal registry.
|
|
314
342
|
* Values from {@link ValueProvider} registrations are not included, as they are never cached.
|
|
@@ -571,6 +599,18 @@ interface Container {
|
|
|
571
599
|
* in the container's internal registry.
|
|
572
600
|
*/
|
|
573
601
|
tryResolveAll<Value>(token: Token<Value>): Value[];
|
|
602
|
+
/**
|
|
603
|
+
* Adds a hook to observe the lifecycle of container-managed values.
|
|
604
|
+
*
|
|
605
|
+
* Does nothing if the hook has already been added.
|
|
606
|
+
*/
|
|
607
|
+
addHook(hook: ContainerHook): void;
|
|
608
|
+
/**
|
|
609
|
+
* Removes a previously added hook.
|
|
610
|
+
*
|
|
611
|
+
* Does nothing if the hook has not been added yet.
|
|
612
|
+
*/
|
|
613
|
+
removeHook(hook: ContainerHook): void;
|
|
574
614
|
/**
|
|
575
615
|
* Disposes this container and all its cached values.
|
|
576
616
|
*
|
|
@@ -938,6 +978,15 @@ declare function injectAll<Instance extends object>(Class: Constructor<Instance>
|
|
|
938
978
|
*/
|
|
939
979
|
declare function injectAll<Value>(token: Token<Value>): Value[];
|
|
940
980
|
|
|
981
|
+
/**
|
|
982
|
+
* Asserts that the current stack frame is within an injection context,
|
|
983
|
+
* meaning it has access to injection functions (`inject`, `optional`, etc.).
|
|
984
|
+
*
|
|
985
|
+
* @param fn The function performing the assertion, or a string name used in the error message.
|
|
986
|
+
* @throws {Error} If the current stack frame is not within an injection context.
|
|
987
|
+
*/
|
|
988
|
+
declare function assertInjectionContext(fn: Function | string): void;
|
|
989
|
+
|
|
941
990
|
/**
|
|
942
991
|
* Injector API.
|
|
943
992
|
*/
|
|
@@ -1147,5 +1196,5 @@ declare function optionalAll<Instance extends object>(Class: Constructor<Instanc
|
|
|
1147
1196
|
*/
|
|
1148
1197
|
declare function optionalAll<Value>(token: Token<Value>): Value[];
|
|
1149
1198
|
|
|
1150
|
-
export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Named, Optional, OptionalAll, Scope, Scoped, applyMiddleware, build, classRef, createContainer, createType, inject, injectAll, injectBy, optional, optionalAll, optionalBy, setClassIdentityMapping, tokenRef };
|
|
1151
|
-
export type { ClassProvider, ClassRef, Constructor, Container, ContainerOptions, ExistingProvider, FactoryProvider, Middleware, MiddlewareComposer, Provider, ProviderType, RegistrationOptions, Token, TokenRef, Tokens, TokensRef, Type, ValueProvider };
|
|
1199
|
+
export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Named, Optional, OptionalAll, Scope, Scoped, applyMiddleware, assertInjectionContext, build, classRef, createContainer, createType, inject, injectAll, injectBy, optional, optionalAll, optionalBy, setClassIdentityMapping, tokenRef };
|
|
1200
|
+
export type { ChildContainerOptions, ClassProvider, ClassRef, Constructor, Container, ContainerHook, ContainerOptions, ExistingProvider, FactoryProvider, Middleware, MiddlewareComposer, Provider, ProviderType, RegistrationOptions, Token, TokenRef, Tokens, TokensRef, Type, ValueProvider };
|
package/dist/es/index.mjs
CHANGED
|
@@ -32,7 +32,7 @@ function throwResolutionError(tokenInfo, aliases, cause) {
|
|
|
32
32
|
function throwParameterResolutionError(ctor, methodKey, dependency, cause) {
|
|
33
33
|
const location = getLocation(ctor, methodKey);
|
|
34
34
|
const tokenName = getFullTokenName([
|
|
35
|
-
dependency.tokenRef
|
|
35
|
+
dependency.tokenRef?.getRefToken(),
|
|
36
36
|
dependency.name
|
|
37
37
|
]);
|
|
38
38
|
const msg = tag(`failed to resolve dependency for ${location}(parameter #${dependency.index}: ${tokenName})`);
|
|
@@ -54,7 +54,7 @@ function getTokenName(token) {
|
|
|
54
54
|
return token.name || "<unnamed>";
|
|
55
55
|
}
|
|
56
56
|
function getFullTokenName([token, name]) {
|
|
57
|
-
const tokenName = token.name || "<unnamed>";
|
|
57
|
+
const tokenName = token ? token.name || "<unnamed>" : "<undefined token>";
|
|
58
58
|
return name ? `${tokenName}["${name}"]` : tokenName;
|
|
59
59
|
}
|
|
60
60
|
function getCause(error) {
|
|
@@ -142,6 +142,16 @@ function ensureInjectionContext(name) {
|
|
|
142
142
|
check(context, `${name} can only be invoked within an injection context`);
|
|
143
143
|
return context;
|
|
144
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Asserts that the current stack frame is within an injection context,
|
|
147
|
+
* meaning it has access to injection functions (`inject`, `optional`, etc.).
|
|
148
|
+
*
|
|
149
|
+
* @param fn The function performing the assertion, or a string name used in the error message.
|
|
150
|
+
* @throws {Error} If the current stack frame is not within an injection context.
|
|
151
|
+
*/ function assertInjectionContext(fn) {
|
|
152
|
+
const name = typeof fn === "function" ? `${fn.name || "<unnamed>"}()` : fn;
|
|
153
|
+
ensureInjectionContext(name);
|
|
154
|
+
}
|
|
145
155
|
function createInjectionContext() {
|
|
146
156
|
let current = null;
|
|
147
157
|
function provide(next) {
|
|
@@ -214,15 +224,15 @@ function tokenRef(token) {
|
|
|
214
224
|
}
|
|
215
225
|
// @internal
|
|
216
226
|
function isClassRef(value) {
|
|
217
|
-
return value && typeof value === "object" && typeof value.getRefClass === "function";
|
|
227
|
+
return value != null && typeof value === "object" && typeof value.getRefClass === "function";
|
|
218
228
|
}
|
|
219
229
|
// @internal
|
|
220
230
|
function isTokensRef(value) {
|
|
221
|
-
return value && typeof value === "object" && typeof value.getRefTokens === "function";
|
|
231
|
+
return value != null && typeof value === "object" && typeof value.getRefTokens === "function";
|
|
222
232
|
}
|
|
223
233
|
// @internal
|
|
224
234
|
function isTokenRef(value) {
|
|
225
|
-
return value && typeof value === "object" && typeof value.getRefToken === "function";
|
|
235
|
+
return value != null && typeof value === "object" && typeof value.getRefToken === "function";
|
|
226
236
|
}
|
|
227
237
|
|
|
228
238
|
// @internal
|
|
@@ -531,21 +541,22 @@ const builders = new WeakSet();
|
|
|
531
541
|
// @internal
|
|
532
542
|
// @internal
|
|
533
543
|
function isDisposable(value) {
|
|
534
|
-
return value && typeof value === "object" && typeof value.dispose === "function";
|
|
544
|
+
return value != null && typeof value === "object" && typeof value.dispose === "function";
|
|
535
545
|
}
|
|
536
546
|
|
|
537
547
|
/**
|
|
538
548
|
* The default implementation of a di-wise-neo {@link Container}.
|
|
539
549
|
*/ class ContainerImpl {
|
|
540
|
-
constructor(parent, options){
|
|
550
|
+
constructor(parent, hooks, options){
|
|
541
551
|
this.myChildren = new Set();
|
|
542
552
|
this.myDisposed = false;
|
|
543
553
|
this.myParent = parent;
|
|
554
|
+
this.myHooks = hooks ?? new Set();
|
|
544
555
|
this.myOptions = {
|
|
545
|
-
|
|
546
|
-
|
|
556
|
+
defaultScope: options?.defaultScope ?? Scope.Transient,
|
|
557
|
+
autoRegister: options?.autoRegister ?? false
|
|
547
558
|
};
|
|
548
|
-
this.myTokenRegistry = new TokenRegistry(
|
|
559
|
+
this.myTokenRegistry = new TokenRegistry(parent?.myTokenRegistry);
|
|
549
560
|
}
|
|
550
561
|
get registry() {
|
|
551
562
|
return this.myTokenRegistry;
|
|
@@ -563,9 +574,10 @@ function isDisposable(value) {
|
|
|
563
574
|
}
|
|
564
575
|
createChild(options) {
|
|
565
576
|
this.checkDisposed();
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
defaultScope: options?.defaultScope ?? this.myOptions.defaultScope
|
|
577
|
+
const hooks = options?.copyHooks === false ? undefined : new Set(this.myHooks);
|
|
578
|
+
const container = new ContainerImpl(this, hooks, {
|
|
579
|
+
defaultScope: options?.defaultScope ?? this.myOptions.defaultScope,
|
|
580
|
+
autoRegister: options?.autoRegister ?? this.myOptions.autoRegister
|
|
569
581
|
});
|
|
570
582
|
this.myChildren.add(container);
|
|
571
583
|
return container;
|
|
@@ -649,6 +661,12 @@ function isDisposable(value) {
|
|
|
649
661
|
this.checkDisposed();
|
|
650
662
|
return this.resolveAllToken(token, true);
|
|
651
663
|
}
|
|
664
|
+
addHook(hook) {
|
|
665
|
+
this.myHooks.add(hook);
|
|
666
|
+
}
|
|
667
|
+
removeHook(hook) {
|
|
668
|
+
this.myHooks.delete(hook);
|
|
669
|
+
}
|
|
652
670
|
dispose() {
|
|
653
671
|
if (this.myDisposed) {
|
|
654
672
|
return;
|
|
@@ -667,12 +685,14 @@ function isDisposable(value) {
|
|
|
667
685
|
for (const registration of registrations){
|
|
668
686
|
const value = registration.value?.current;
|
|
669
687
|
if (isDisposable(value) && !disposedRefs.has(value)) {
|
|
688
|
+
this.notifyDisposeHooks(value);
|
|
670
689
|
disposedRefs.add(value);
|
|
671
690
|
value.dispose();
|
|
672
691
|
}
|
|
673
692
|
}
|
|
674
693
|
// Allow values to be GCed
|
|
675
694
|
disposedRefs.clear();
|
|
695
|
+
this.myHooks.clear();
|
|
676
696
|
}
|
|
677
697
|
registerClass(Class) {
|
|
678
698
|
const metadata = getMetadata(Class);
|
|
@@ -701,7 +721,9 @@ function isDisposable(value) {
|
|
|
701
721
|
}
|
|
702
722
|
});
|
|
703
723
|
}
|
|
704
|
-
// Eager-instantiate only if the class is container-scoped
|
|
724
|
+
// Eager-instantiate only if the class is container-scoped.
|
|
725
|
+
// Note that we are comparing the scope using the registration configured just above,
|
|
726
|
+
// which takes into account both the metadata and the container option as a fallback.
|
|
705
727
|
if (metadata.eagerInstantiate && registration.options?.scope === Scope.Container) {
|
|
706
728
|
this.resolveProviderValue(Class, registration);
|
|
707
729
|
}
|
|
@@ -723,7 +745,9 @@ function isDisposable(value) {
|
|
|
723
745
|
dependencies: metadata.dependencies
|
|
724
746
|
};
|
|
725
747
|
this.myTokenRegistry.set(token, registration);
|
|
726
|
-
// Eager-instantiate only if the provided class is container-scoped
|
|
748
|
+
// Eager-instantiate only if the provided class is container-scoped.
|
|
749
|
+
// Note that we are comparing the scope using the registration configured just above,
|
|
750
|
+
// which takes into account both the metadata and the container option as a fallback.
|
|
727
751
|
if (metadata.eagerInstantiate && registration.options?.scope === Scope.Container) {
|
|
728
752
|
this.resolveProviderValue(token, registration);
|
|
729
753
|
}
|
|
@@ -837,7 +861,7 @@ function isDisposable(value) {
|
|
|
837
861
|
}
|
|
838
862
|
if (isFactoryProvider(provider)) {
|
|
839
863
|
const factory = provider.useFactory;
|
|
840
|
-
return this.resolveScopedValue(token, registration, factory);
|
|
864
|
+
return this.resolveScopedValue(token, registration, ()=>factory());
|
|
841
865
|
}
|
|
842
866
|
if (isValueProvider(provider)) {
|
|
843
867
|
return provider.useValue;
|
|
@@ -886,6 +910,7 @@ function isDisposable(value) {
|
|
|
886
910
|
registration.value = {
|
|
887
911
|
current: value
|
|
888
912
|
};
|
|
913
|
+
this.notifyProvideHooks(value);
|
|
889
914
|
return value;
|
|
890
915
|
}
|
|
891
916
|
case Scope.Resolution:
|
|
@@ -899,12 +924,15 @@ function isDisposable(value) {
|
|
|
899
924
|
resolution.values.set(provider, {
|
|
900
925
|
current: value
|
|
901
926
|
});
|
|
927
|
+
this.notifyProvideHooks(value);
|
|
902
928
|
return value;
|
|
903
929
|
}
|
|
904
930
|
case Scope.Transient:
|
|
905
931
|
{
|
|
906
932
|
const args = this.resolveCtorDependencies(registration);
|
|
907
|
-
|
|
933
|
+
const value = this.injectMethodDependencies(registration, factory(args));
|
|
934
|
+
this.notifyProvideHooks(value);
|
|
935
|
+
return value;
|
|
908
936
|
}
|
|
909
937
|
}
|
|
910
938
|
} finally{
|
|
@@ -953,6 +981,7 @@ function isDisposable(value) {
|
|
|
953
981
|
}
|
|
954
982
|
return instance;
|
|
955
983
|
}
|
|
984
|
+
// Call context: decorator-based injection
|
|
956
985
|
resolveArgs(deps, ctor, instance, methodKey) {
|
|
957
986
|
const sortedDeps = deps.sort((a, b)=>a.index - b.index);
|
|
958
987
|
const args = [];
|
|
@@ -965,8 +994,10 @@ function isDisposable(value) {
|
|
|
965
994
|
}
|
|
966
995
|
return args;
|
|
967
996
|
}
|
|
997
|
+
// Call context: decorator-based injection
|
|
968
998
|
resolveDependency(dependency, instance) {
|
|
969
|
-
const token = dependency.tokenRef
|
|
999
|
+
const token = dependency.tokenRef?.getRefToken();
|
|
1000
|
+
check(token, `token passed to @${dependency.appliedBy} was undefined (possible circular imports)`);
|
|
970
1001
|
const name = dependency.name;
|
|
971
1002
|
switch(dependency.appliedBy){
|
|
972
1003
|
case "Inject":
|
|
@@ -979,6 +1010,16 @@ function isDisposable(value) {
|
|
|
979
1010
|
return instance ? optionalAll(token) : this.tryResolveAll(token);
|
|
980
1011
|
}
|
|
981
1012
|
}
|
|
1013
|
+
notifyProvideHooks(value) {
|
|
1014
|
+
for (const hook of this.myHooks){
|
|
1015
|
+
hook.onProvide(value);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
notifyDisposeHooks(value) {
|
|
1019
|
+
for (const hook of this.myHooks){
|
|
1020
|
+
hook.onDispose(value);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
982
1023
|
checkDisposed() {
|
|
983
1024
|
check(!this.myDisposed, "container is disposed");
|
|
984
1025
|
}
|
|
@@ -987,7 +1028,7 @@ function isDisposable(value) {
|
|
|
987
1028
|
/**
|
|
988
1029
|
* Creates a new container.
|
|
989
1030
|
*/ function createContainer(options) {
|
|
990
|
-
return new ContainerImpl(undefined, options);
|
|
1031
|
+
return new ContainerImpl(undefined, undefined, options);
|
|
991
1032
|
}
|
|
992
1033
|
|
|
993
1034
|
/**
|
|
@@ -1321,5 +1362,5 @@ function OptionalAll(token) {
|
|
|
1321
1362
|
return container;
|
|
1322
1363
|
}
|
|
1323
1364
|
|
|
1324
|
-
export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Named, Optional, OptionalAll, Scope, Scoped, applyMiddleware, build, classRef, createContainer, createType, inject, injectAll, injectBy, optional, optionalAll, optionalBy, setClassIdentityMapping, tokenRef };
|
|
1365
|
+
export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Named, Optional, OptionalAll, Scope, Scoped, applyMiddleware, assertInjectionContext, build, classRef, createContainer, createType, inject, injectAll, injectBy, optional, optionalAll, optionalBy, setClassIdentityMapping, tokenRef };
|
|
1325
1366
|
//# sourceMappingURL=index.mjs.map
|