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