@lppedd/di-wise-neo 0.9.1 → 0.9.3
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.js +149 -129
- package/dist/cjs/index.js.map +1 -1
- package/dist/es/index.mjs +149 -129
- package/dist/es/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
@@ -1,32 +1,5 @@
|
|
1
1
|
Object.defineProperty(exports, '__esModule', { value: true });
|
2
2
|
|
3
|
-
/**
|
4
|
-
* Type API.
|
5
|
-
*/ /**
|
6
|
-
* Creates a type token.
|
7
|
-
*
|
8
|
-
* @example
|
9
|
-
* ```ts
|
10
|
-
* const ISpell = createType<Spell>("Spell");
|
11
|
-
* ```
|
12
|
-
*
|
13
|
-
* @__NO_SIDE_EFFECTS__
|
14
|
-
*/ function createType(typeName) {
|
15
|
-
const type = {
|
16
|
-
name: `Type<${typeName}>`,
|
17
|
-
inter: createType,
|
18
|
-
union: createType,
|
19
|
-
toString () {
|
20
|
-
return type.name;
|
21
|
-
}
|
22
|
-
};
|
23
|
-
return type;
|
24
|
-
}
|
25
|
-
// @internal
|
26
|
-
function isConstructor(token) {
|
27
|
-
return typeof token === "function";
|
28
|
-
}
|
29
|
-
|
30
3
|
// @internal
|
31
4
|
function check(condition, message) {
|
32
5
|
if (!condition) {
|
@@ -39,18 +12,35 @@ function expectNever(value) {
|
|
39
12
|
}
|
40
13
|
// @internal
|
41
14
|
function throwUnregisteredError(token, name) {
|
42
|
-
const type = isConstructor(token) ? "class" : "token";
|
43
15
|
const spec = name !== undefined ? `[name=${name}]` : "";
|
44
|
-
throw new Error(tag(`unregistered
|
16
|
+
throw new Error(tag(`unregistered token ${getTokenName(token)}${spec}`));
|
45
17
|
}
|
46
18
|
// @internal
|
47
|
-
function throwExistingUnregisteredError(
|
48
|
-
|
49
|
-
|
50
|
-
|
19
|
+
function throwExistingUnregisteredError(token, cause) {
|
20
|
+
const message = tag(`failed to resolve token ${getTokenName(token)}`);
|
21
|
+
throw isError(cause) ? new Error(`${message}\n [cause] ${untag(cause.message)}`, {
|
22
|
+
cause
|
23
|
+
}) : new Error(`${message}\n [cause] the aliased token ${getTokenName(cause)} is not registered`);
|
24
|
+
}
|
25
|
+
// @internal
|
26
|
+
function throwParameterResolutionError(ctor, methodKey, dependency, cause) {
|
27
|
+
const location = getLocation(ctor, methodKey);
|
28
|
+
const token = dependency.tokenRef.getRefToken();
|
29
|
+
const message = tag(`failed to resolve dependency for ${location}(parameter #${dependency.index}: ${token.name})`);
|
30
|
+
throw new Error(`${message}\n [cause] ${untag(cause.message)}`, {
|
31
|
+
cause
|
32
|
+
});
|
33
|
+
}
|
34
|
+
// @internal
|
35
|
+
function getLocation(ctor, methodKey) {
|
36
|
+
const ctorName = ctor.name || "<unnamed>";
|
37
|
+
return methodKey ? `${ctorName}.${String(methodKey)}` : ctorName;
|
38
|
+
}
|
39
|
+
// @internal
|
40
|
+
function getTokenName(token) {
|
41
|
+
return token.name || "<unnamed>";
|
51
42
|
}
|
52
43
|
function isError(value) {
|
53
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
54
44
|
return value && value.stack && value.message && typeof value.message === "string";
|
55
45
|
}
|
56
46
|
function tag(message) {
|
@@ -82,7 +72,7 @@ class KeyedStack {
|
|
82
72
|
};
|
83
73
|
}
|
84
74
|
constructor(){
|
85
|
-
this.myEntries =
|
75
|
+
this.myEntries = [];
|
86
76
|
this.myKeys = new WeakSet();
|
87
77
|
}
|
88
78
|
}
|
@@ -115,6 +105,7 @@ class WeakRefMap {
|
|
115
105
|
// @internal
|
116
106
|
function createResolution() {
|
117
107
|
return {
|
108
|
+
tokenStack: [],
|
118
109
|
stack: new KeyedStack(),
|
119
110
|
values: new WeakRefMap(),
|
120
111
|
dependents: new WeakRefMap()
|
@@ -175,7 +166,7 @@ function injectAll(token) {
|
|
175
166
|
class Metadata {
|
176
167
|
constructor(Class){
|
177
168
|
this.dependencies = {
|
178
|
-
|
169
|
+
ctor: [],
|
179
170
|
methods: new Map()
|
180
171
|
};
|
181
172
|
this.tokensRef = {
|
@@ -191,15 +182,15 @@ class Metadata {
|
|
191
182
|
set name(name) {
|
192
183
|
this.provider.name = name;
|
193
184
|
}
|
194
|
-
|
195
|
-
const i = this.dependencies.
|
185
|
+
getCtorDependency(index) {
|
186
|
+
const i = this.dependencies.ctor.findIndex((d)=>d.index === index);
|
196
187
|
if (i > -1) {
|
197
|
-
return this.dependencies.
|
188
|
+
return this.dependencies.ctor[i];
|
198
189
|
}
|
199
190
|
const dependency = {
|
200
191
|
index: index
|
201
192
|
};
|
202
|
-
this.dependencies.
|
193
|
+
this.dependencies.ctor.push(dependency);
|
203
194
|
return dependency;
|
204
195
|
}
|
205
196
|
getMethodDependency(method, index) {
|
@@ -313,6 +304,33 @@ const Scope = {
|
|
313
304
|
Container: "Container"
|
314
305
|
};
|
315
306
|
|
307
|
+
/**
|
308
|
+
* Type API.
|
309
|
+
*/ /**
|
310
|
+
* Creates a type token.
|
311
|
+
*
|
312
|
+
* @example
|
313
|
+
* ```ts
|
314
|
+
* const ISpell = createType<Spell>("Spell");
|
315
|
+
* ```
|
316
|
+
*
|
317
|
+
* @__NO_SIDE_EFFECTS__
|
318
|
+
*/ function createType(typeName) {
|
319
|
+
const type = {
|
320
|
+
name: `Type<${typeName}>`,
|
321
|
+
inter: createType,
|
322
|
+
union: createType,
|
323
|
+
toString () {
|
324
|
+
return type.name;
|
325
|
+
}
|
326
|
+
};
|
327
|
+
return type;
|
328
|
+
}
|
329
|
+
// @internal
|
330
|
+
function isConstructor(token) {
|
331
|
+
return typeof token === "function";
|
332
|
+
}
|
333
|
+
|
316
334
|
// @internal
|
317
335
|
function getTypeName(value) {
|
318
336
|
switch(typeof value){
|
@@ -327,9 +345,9 @@ function getTypeName(value) {
|
|
327
345
|
}
|
328
346
|
const proto = Object.getPrototypeOf(value);
|
329
347
|
if (proto && proto !== Object.prototype) {
|
330
|
-
const
|
331
|
-
if (typeof
|
332
|
-
return
|
348
|
+
const ctor = proto.constructor;
|
349
|
+
if (typeof ctor === "function" && ctor.name) {
|
350
|
+
return ctor.name;
|
333
351
|
}
|
334
352
|
}
|
335
353
|
}
|
@@ -445,7 +463,6 @@ const builders = new WeakSet();
|
|
445
463
|
// @internal
|
446
464
|
// @internal
|
447
465
|
function isDisposable(value) {
|
448
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
449
466
|
return value && typeof value === "object" && typeof value.dispose === "function";
|
450
467
|
}
|
451
468
|
|
@@ -550,13 +567,13 @@ function isDisposable(value) {
|
|
550
567
|
}
|
551
568
|
// Eager-instantiate only if the class is container-scoped
|
552
569
|
if (metadata.eagerInstantiate && registration.options?.scope === Scope.Container) {
|
553
|
-
this.resolveProviderValue(
|
570
|
+
this.resolveProviderValue(Class, registration);
|
554
571
|
}
|
555
572
|
} else {
|
556
573
|
const [token, provider, options] = args;
|
557
574
|
const existingProvider = isExistingProvider(provider);
|
558
575
|
const name = existingProvider ? undefined : provider.name;
|
559
|
-
check(name === undefined || name.trim(),
|
576
|
+
check(name === undefined || name.trim(), `the name qualifier for token ${getTokenName(token)} must not be empty`);
|
560
577
|
if (isClassProvider(provider)) {
|
561
578
|
const metadata = getMetadata(provider.useClass);
|
562
579
|
const registration = {
|
@@ -573,7 +590,7 @@ function isDisposable(value) {
|
|
573
590
|
this.myTokenRegistry.set(token, registration);
|
574
591
|
// Eager-instantiate only if the provided class is container-scoped
|
575
592
|
if (metadata.eagerInstantiate && registration.options?.scope === Scope.Container) {
|
576
|
-
this.resolveProviderValue(
|
593
|
+
this.resolveProviderValue(token, registration);
|
577
594
|
}
|
578
595
|
} else {
|
579
596
|
if (existingProvider) {
|
@@ -663,17 +680,15 @@ function isDisposable(value) {
|
|
663
680
|
}
|
664
681
|
resolveRegistration(token, registration, name) {
|
665
682
|
let currRegistration = registration;
|
666
|
-
|
667
|
-
|
668
|
-
const targetToken = currProvider.useExisting;
|
683
|
+
while(isExistingProvider(currRegistration.provider)){
|
684
|
+
const targetToken = currRegistration.provider.useExisting;
|
669
685
|
currRegistration = this.myTokenRegistry.get(targetToken, name);
|
670
686
|
if (!currRegistration) {
|
671
687
|
throwExistingUnregisteredError(token, targetToken);
|
672
688
|
}
|
673
|
-
currProvider = currRegistration.provider;
|
674
689
|
}
|
675
690
|
try {
|
676
|
-
return this.resolveProviderValue(
|
691
|
+
return this.resolveProviderValue(token, currRegistration);
|
677
692
|
} catch (e) {
|
678
693
|
// If we were trying to resolve a token registered via ExistingProvider,
|
679
694
|
// we must add the cause of the error to the message
|
@@ -700,16 +715,15 @@ function isDisposable(value) {
|
|
700
715
|
}
|
701
716
|
return undefined;
|
702
717
|
}
|
703
|
-
resolveProviderValue(
|
704
|
-
|
718
|
+
resolveProviderValue(token, registration) {
|
719
|
+
const provider = registration.provider;
|
705
720
|
if (isClassProvider(provider)) {
|
706
721
|
const Class = provider.useClass;
|
707
|
-
|
708
|
-
return this.resolveScopedValue(registration, (args)=>new Class(...args));
|
722
|
+
return this.resolveScopedValue(token, registration, (args)=>new Class(...args));
|
709
723
|
}
|
710
724
|
if (isFactoryProvider(provider)) {
|
711
725
|
const factory = provider.useFactory;
|
712
|
-
return this.resolveScopedValue(registration, factory);
|
726
|
+
return this.resolveScopedValue(token, registration, factory);
|
713
727
|
}
|
714
728
|
if (isValueProvider(provider)) {
|
715
729
|
return provider.useValue;
|
@@ -717,7 +731,7 @@ function isDisposable(value) {
|
|
717
731
|
check(!isExistingProvider(provider), "internal error: unexpected ExistingProvider");
|
718
732
|
expectNever(provider);
|
719
733
|
}
|
720
|
-
resolveScopedValue(registration, factory) {
|
734
|
+
resolveScopedValue(token, registration, factory) {
|
721
735
|
let context = useInjectionContext();
|
722
736
|
if (!context || context.container !== this) {
|
723
737
|
context = {
|
@@ -730,12 +744,16 @@ function isDisposable(value) {
|
|
730
744
|
const options = registration.options;
|
731
745
|
if (resolution.stack.has(provider)) {
|
732
746
|
const dependentRef = resolution.dependents.get(provider);
|
733
|
-
check(dependentRef,
|
747
|
+
check(dependentRef, ()=>{
|
748
|
+
const path = resolution.tokenStack.map((t)=>t.name).join(" → ");
|
749
|
+
return `circular dependency detected while resolving ${path} → ${token.name}`;
|
750
|
+
});
|
734
751
|
return dependentRef.current;
|
735
752
|
}
|
736
753
|
const scope = this.resolveScope(options?.scope, context);
|
737
754
|
const cleanups = [
|
738
755
|
provideInjectionContext(context),
|
756
|
+
resolution.tokenStack.push(token) && (()=>resolution.tokenStack.pop()),
|
739
757
|
!isBuilder(provider) && resolution.stack.push(provider, {
|
740
758
|
provider,
|
741
759
|
scope
|
@@ -749,8 +767,8 @@ function isDisposable(value) {
|
|
749
767
|
if (valueRef) {
|
750
768
|
return valueRef.current;
|
751
769
|
}
|
752
|
-
const args = this.
|
753
|
-
const value = this.
|
770
|
+
const args = this.resolveCtorDependencies(registration);
|
771
|
+
const value = this.injectMethodDependencies(registration, factory(args));
|
754
772
|
registration.value = {
|
755
773
|
current: value
|
756
774
|
};
|
@@ -762,8 +780,8 @@ function isDisposable(value) {
|
|
762
780
|
if (valueRef) {
|
763
781
|
return valueRef.current;
|
764
782
|
}
|
765
|
-
const args = this.
|
766
|
-
const value = this.
|
783
|
+
const args = this.resolveCtorDependencies(registration);
|
784
|
+
const value = this.injectMethodDependencies(registration, factory(args));
|
767
785
|
resolution.values.set(provider, {
|
768
786
|
current: value
|
769
787
|
});
|
@@ -771,8 +789,8 @@ function isDisposable(value) {
|
|
771
789
|
}
|
772
790
|
case Scope.Transient:
|
773
791
|
{
|
774
|
-
const args = this.
|
775
|
-
return this.
|
792
|
+
const args = this.resolveCtorDependencies(registration);
|
793
|
+
return this.injectMethodDependencies(registration, factory(args));
|
776
794
|
}
|
777
795
|
}
|
778
796
|
} finally{
|
@@ -786,72 +804,74 @@ function isDisposable(value) {
|
|
786
804
|
}
|
787
805
|
return scope;
|
788
806
|
}
|
789
|
-
|
807
|
+
resolveCtorDependencies(registration) {
|
790
808
|
const dependencies = registration.dependencies;
|
791
809
|
if (dependencies) {
|
792
810
|
check(isClassProvider(registration.provider), `internal error: not a ClassProvider`);
|
793
|
-
const ctorDeps = dependencies.
|
811
|
+
const ctorDeps = dependencies.ctor.filter((d)=>d.appliedBy);
|
794
812
|
if (ctorDeps.length > 0) {
|
795
813
|
// Let's check if all necessary constructor parameters are decorated.
|
796
814
|
// If not, we cannot safely create an instance.
|
797
815
|
const ctor = registration.provider.useClass;
|
798
816
|
check(ctor.length === ctorDeps.length, ()=>{
|
799
|
-
const
|
817
|
+
const location = getLocation(ctor);
|
818
|
+
const msg = `${location} expected ${ctor.length} decorated constructor parameters`;
|
800
819
|
return msg + `, but found ${ctorDeps.length}`;
|
801
820
|
});
|
802
|
-
return
|
803
|
-
const token = dep.tokenRef.getRefToken();
|
804
|
-
switch(dep.appliedBy){
|
805
|
-
case "Inject":
|
806
|
-
return this.resolve(token, dep.name);
|
807
|
-
case "InjectAll":
|
808
|
-
return this.resolveAll(token);
|
809
|
-
case "Optional":
|
810
|
-
return this.resolve(token, true, dep.name);
|
811
|
-
case "OptionalAll":
|
812
|
-
return this.resolveAll(token, true);
|
813
|
-
}
|
814
|
-
});
|
821
|
+
return this.resolveArgs(ctorDeps, ctor);
|
815
822
|
}
|
816
823
|
}
|
817
824
|
return [];
|
818
825
|
}
|
819
|
-
|
826
|
+
injectMethodDependencies(registration, instance) {
|
820
827
|
const dependencies = registration.dependencies;
|
821
828
|
if (dependencies) {
|
822
829
|
check(isClassProvider(registration.provider), `internal error: not a ClassProvider`);
|
823
830
|
const ctor = registration.provider.useClass;
|
824
831
|
// Perform method injection
|
825
832
|
for (const entry of dependencies.methods){
|
826
|
-
const
|
833
|
+
const methodKey = entry[0];
|
827
834
|
const methodDeps = entry[1].filter((d)=>d.appliedBy);
|
828
835
|
// Let's check if all necessary method parameters are decorated.
|
829
836
|
// If not, we cannot safely invoke the method.
|
830
|
-
|
831
|
-
const method = instance[key];
|
837
|
+
const method = instance[methodKey];
|
832
838
|
check(methodDeps.length === method.length, ()=>{
|
833
|
-
const
|
834
|
-
|
835
|
-
|
836
|
-
const args = methodDeps.sort((a, b)=>a.index - b.index).map((dep)=>{
|
837
|
-
const token = dep.tokenRef.getRefToken();
|
838
|
-
switch(dep.appliedBy){
|
839
|
-
case "Inject":
|
840
|
-
return injectBy(instance, token, dep.name);
|
841
|
-
case "InjectAll":
|
842
|
-
return injectAll(token);
|
843
|
-
case "Optional":
|
844
|
-
return optionalBy(instance, token, dep.name);
|
845
|
-
case "OptionalAll":
|
846
|
-
return optionalAll(token);
|
847
|
-
}
|
839
|
+
const location = getLocation(ctor, methodKey);
|
840
|
+
const msg = `${location} expected ${method.length} decorated method parameters`;
|
841
|
+
return msg + `, but found ${methodDeps.length}`;
|
848
842
|
});
|
849
|
-
|
843
|
+
const args = this.resolveArgs(methodDeps, ctor, instance, methodKey);
|
850
844
|
method.bind(instance)(...args);
|
851
845
|
}
|
852
846
|
}
|
853
847
|
return instance;
|
854
848
|
}
|
849
|
+
resolveArgs(deps, ctor, instance, methodKey) {
|
850
|
+
const sortedDeps = deps.sort((a, b)=>a.index - b.index);
|
851
|
+
const args = [];
|
852
|
+
for (const dep of sortedDeps){
|
853
|
+
try {
|
854
|
+
args.push(this.resolveDependency(dep, instance));
|
855
|
+
} catch (e) {
|
856
|
+
throwParameterResolutionError(ctor, methodKey, dep, e);
|
857
|
+
}
|
858
|
+
}
|
859
|
+
return args;
|
860
|
+
}
|
861
|
+
resolveDependency(dependency, instance) {
|
862
|
+
const token = dependency.tokenRef.getRefToken();
|
863
|
+
const name = dependency.name;
|
864
|
+
switch(dependency.appliedBy){
|
865
|
+
case "Inject":
|
866
|
+
return instance ? injectBy(instance, token, name) : this.resolve(token, name);
|
867
|
+
case "InjectAll":
|
868
|
+
return instance ? injectAll(token) : this.resolveAll(token);
|
869
|
+
case "Optional":
|
870
|
+
return instance ? optionalBy(instance, token, name) : this.resolve(token, true, name);
|
871
|
+
case "OptionalAll":
|
872
|
+
return instance ? optionalAll(token) : this.resolveAll(token, true);
|
873
|
+
}
|
874
|
+
}
|
855
875
|
checkDisposed() {
|
856
876
|
check(!this.myDisposed, "the container is disposed");
|
857
877
|
}
|
@@ -907,11 +927,13 @@ function isDisposable(value) {
|
|
907
927
|
* @__NO_SIDE_EFFECTS__
|
908
928
|
*/ function EagerInstantiate() {
|
909
929
|
return function(Class) {
|
910
|
-
const
|
930
|
+
const ctor = Class;
|
931
|
+
const metadata = getMetadata(ctor);
|
911
932
|
const currentScope = metadata.scope;
|
912
933
|
check(!currentScope || currentScope.value === Scope.Container, ()=>{
|
913
934
|
const { value, appliedBy } = currentScope;
|
914
|
-
|
935
|
+
const className = getTokenName(ctor);
|
936
|
+
return `class ${className}: Scope.${value} was already set by @${appliedBy},\n ` + `but @EagerInstantiate is trying to set a conflicting Scope.Container.\n ` + `Only one decorator should set the class scope, or all must agree on the same value.`;
|
915
937
|
});
|
916
938
|
metadata.eagerInstantiate = true;
|
917
939
|
metadata.scope = {
|
@@ -941,30 +963,28 @@ function forwardRef(token) {
|
|
941
963
|
}
|
942
964
|
// @internal
|
943
965
|
function isTokensRef(value) {
|
944
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
945
966
|
return value && typeof value === "object" && typeof value.getRefTokens === "function";
|
946
967
|
}
|
947
968
|
// @internal
|
948
969
|
function isTokenRef(value) {
|
949
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
950
970
|
return value && typeof value === "object" && typeof value.getRefToken === "function";
|
951
971
|
}
|
952
972
|
|
953
973
|
// @internal
|
954
|
-
function updateParameterMetadata(decorator, target,
|
974
|
+
function updateParameterMetadata(decorator, target, methodKey, parameterIndex, updateFn) {
|
955
975
|
// Error out immediately if the decorator has been applied to a static method
|
956
|
-
if (
|
957
|
-
check(false, `@${decorator} cannot be used on static method ${target.name}.${String(
|
976
|
+
if (methodKey !== undefined && typeof target === "function") {
|
977
|
+
check(false, `@${decorator} cannot be used on static method ${target.name}.${String(methodKey)}`);
|
958
978
|
}
|
959
|
-
if (
|
979
|
+
if (methodKey === undefined) {
|
960
980
|
// Constructor
|
961
981
|
const metadata = getMetadata(target);
|
962
|
-
const dependency = metadata.
|
982
|
+
const dependency = metadata.getCtorDependency(parameterIndex);
|
963
983
|
updateFn(dependency);
|
964
984
|
} else {
|
965
985
|
// Instance method
|
966
986
|
const metadata = getMetadata(target.constructor);
|
967
|
-
const dependency = metadata.getMethodDependency(
|
987
|
+
const dependency = metadata.getMethodDependency(methodKey, parameterIndex);
|
968
988
|
updateFn(dependency);
|
969
989
|
}
|
970
990
|
}
|
@@ -973,30 +993,30 @@ function updateParameterMetadata(decorator, target, propertyKey, parameterIndex,
|
|
973
993
|
// understand which one "wins", unless the user is aware of the decorator evaluation order.
|
974
994
|
//
|
975
995
|
// @internal
|
976
|
-
function checkSingleDecorator(dependency, target,
|
996
|
+
function checkSingleDecorator(dependency, target, methodKey, parameterIndex) {
|
977
997
|
check(dependency.appliedBy === undefined, ()=>{
|
978
|
-
const
|
979
|
-
return `multiple injection decorators on ${
|
998
|
+
const param = describeParam(target, methodKey, parameterIndex);
|
999
|
+
return `multiple injection decorators on ${param}, but only one is allowed`;
|
980
1000
|
});
|
981
1001
|
}
|
982
1002
|
// Checks that the `@Named` decorator is not used in combination with
|
983
1003
|
// `@InjectAll` or `@OptionalAll`, which ignore the name qualification.
|
984
1004
|
//
|
985
1005
|
// @internal
|
986
|
-
function checkNamedDecorator(dependency, target,
|
1006
|
+
function checkNamedDecorator(dependency, target, methodKey, parameterIndex) {
|
987
1007
|
const { appliedBy, name } = dependency;
|
988
1008
|
check(name === undefined || appliedBy !== "InjectAll" && appliedBy !== "OptionalAll", ()=>{
|
989
|
-
const
|
990
|
-
return `@Named has no effect on ${
|
1009
|
+
const param = describeParam(target, methodKey, parameterIndex);
|
1010
|
+
return `@Named has no effect on ${param} when used with @${appliedBy}`;
|
991
1011
|
});
|
992
1012
|
}
|
993
1013
|
// Returns a human-readable description of the parameter location.
|
994
1014
|
// For example: "Wizard constructor parameter 2" or "Wizard.set parameter 0"
|
995
1015
|
//
|
996
1016
|
// @internal
|
997
|
-
function
|
998
|
-
const location =
|
999
|
-
return `${location}
|
1017
|
+
function describeParam(target, methodKey, parameterIndex) {
|
1018
|
+
const location = methodKey === undefined ? target.name : `${target.constructor.name}.${String(methodKey)}`;
|
1019
|
+
return `${location}(parameter #${parameterIndex})`;
|
1000
1020
|
}
|
1001
1021
|
|
1002
1022
|
function Inject(token) {
|
@@ -1058,20 +1078,21 @@ function InjectAll(token) {
|
|
1058
1078
|
*
|
1059
1079
|
* @__NO_SIDE_EFFECTS__
|
1060
1080
|
*/ function Named(name) {
|
1061
|
-
check(name.trim(), "the @Named qualifier
|
1081
|
+
check(name.trim(), "the @Named qualifier must not be empty");
|
1062
1082
|
return function(target, propertyKey, parameterIndex) {
|
1063
1083
|
if (parameterIndex === undefined) {
|
1064
1084
|
// The decorator has been applied to the class
|
1065
1085
|
const ctor = target;
|
1066
1086
|
const metadata = getMetadata(ctor);
|
1067
|
-
|
1087
|
+
const className = getTokenName(ctor);
|
1088
|
+
check(metadata.name === undefined, `multiple @Named decorators on class ${className}, but only one is allowed`);
|
1068
1089
|
metadata.name = name;
|
1069
1090
|
} else {
|
1070
1091
|
// The decorator has been applied to a method parameter
|
1071
1092
|
updateParameterMetadata("Named", target, propertyKey, parameterIndex, (dependency)=>{
|
1072
1093
|
check(dependency.name === undefined, ()=>{
|
1073
|
-
const
|
1074
|
-
return `multiple @Named decorators on ${
|
1094
|
+
const param = describeParam(target, propertyKey, parameterIndex);
|
1095
|
+
return `multiple @Named decorators on ${param}, but only one is allowed`;
|
1075
1096
|
});
|
1076
1097
|
dependency.name = name;
|
1077
1098
|
checkNamedDecorator(dependency, target, propertyKey, parameterIndex);
|
@@ -1124,12 +1145,14 @@ function OptionalAll(token) {
|
|
1124
1145
|
* @__NO_SIDE_EFFECTS__
|
1125
1146
|
*/ function Scoped(scope) {
|
1126
1147
|
return function(Class) {
|
1127
|
-
const
|
1148
|
+
const ctor = Class;
|
1149
|
+
const metadata = getMetadata(ctor);
|
1128
1150
|
const currentScope = metadata.scope;
|
1129
1151
|
check(!currentScope || currentScope.value === scope, ()=>{
|
1130
1152
|
const { value, appliedBy } = currentScope;
|
1131
1153
|
const by = appliedBy === "Scoped" ? `another @${appliedBy} decorator` : `@${appliedBy}`;
|
1132
|
-
|
1154
|
+
const className = getTokenName(ctor);
|
1155
|
+
return `class ${className}: Scope.${value} was already set by ${by},\n ` + `but @Scoped is trying to set a conflicting Scope.${scope}.\n ` + `Only one decorator should set the class scope, or all must agree on the same value.`;
|
1133
1156
|
});
|
1134
1157
|
metadata.scope = {
|
1135
1158
|
value: scope,
|
@@ -1211,10 +1234,7 @@ function OptionalAll(token) {
|
|
1211
1234
|
use (key, wrap) {
|
1212
1235
|
// We need to bind the 'this' context of the function to the container
|
1213
1236
|
// before passing it to the middleware wrapper.
|
1214
|
-
//
|
1215
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call
|
1216
1237
|
const fn = container[key].bind(container);
|
1217
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
1218
1238
|
container[key] = wrap(fn);
|
1219
1239
|
return composer;
|
1220
1240
|
}
|