@lppedd/di-wise-neo 0.9.0 → 0.9.1
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 +52 -38
- package/dist/cjs/index.js.map +1 -1
- package/dist/es/index.mjs +52 -38
- package/dist/es/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
@@ -28,7 +28,7 @@ function isConstructor(token) {
|
|
28
28
|
}
|
29
29
|
|
30
30
|
// @internal
|
31
|
-
function
|
31
|
+
function check(condition, message) {
|
32
32
|
if (!condition) {
|
33
33
|
throw new Error(tag(typeof message === "string" ? message : message()));
|
34
34
|
}
|
@@ -60,13 +60,6 @@ function untag(message) {
|
|
60
60
|
return message.startsWith("[di-wise-neo]") ? message.substring(13).trimStart() : message;
|
61
61
|
}
|
62
62
|
|
63
|
-
// @internal
|
64
|
-
function invariant(condition) {
|
65
|
-
if (!condition) {
|
66
|
-
throw new Error("invariant violation");
|
67
|
-
}
|
68
|
-
}
|
69
|
-
|
70
63
|
// @internal
|
71
64
|
class KeyedStack {
|
72
65
|
has(key) {
|
@@ -77,7 +70,7 @@ class KeyedStack {
|
|
77
70
|
return entry?.value;
|
78
71
|
}
|
79
72
|
push(key, value) {
|
80
|
-
|
73
|
+
check(!this.has(key), "invariant violation");
|
81
74
|
this.myKeys.add(key);
|
82
75
|
this.myEntries.push({
|
83
76
|
key,
|
@@ -108,7 +101,7 @@ class WeakRefMap {
|
|
108
101
|
return undefined;
|
109
102
|
}
|
110
103
|
set(key, value) {
|
111
|
-
|
104
|
+
check(!this.get(key), "invariant violation");
|
112
105
|
this.myMap.set(key, new WeakRef(value));
|
113
106
|
return ()=>{
|
114
107
|
this.myMap.delete(key);
|
@@ -132,7 +125,7 @@ const [provideInjectionContext, useInjectionContext] = createInjectionContext();
|
|
132
125
|
// @internal
|
133
126
|
function ensureInjectionContext(name) {
|
134
127
|
const context = useInjectionContext();
|
135
|
-
|
128
|
+
check(context, `${name} can only be invoked within an injection context`);
|
136
129
|
return context;
|
137
130
|
}
|
138
131
|
function createInjectionContext() {
|
@@ -362,13 +355,13 @@ class TokenRegistry {
|
|
362
355
|
] || this.getAllFromParent(token, name);
|
363
356
|
}
|
364
357
|
set(token, registration) {
|
365
|
-
|
358
|
+
check(!internals.has(token), `cannot register reserved token ${token.name}`);
|
366
359
|
let registrations = this.myMap.get(token);
|
367
360
|
if (!registrations) {
|
368
361
|
this.myMap.set(token, registrations = []);
|
369
362
|
} else if (registration.name !== undefined) {
|
370
363
|
const existing = registrations.filter((r)=>r.name === registration.name);
|
371
|
-
|
364
|
+
check(existing.length === 0, `a ${token.name} token named '${registration.name}' is already registered`);
|
372
365
|
}
|
373
366
|
registrations.push(registration);
|
374
367
|
}
|
@@ -422,7 +415,7 @@ class TokenRegistry {
|
|
422
415
|
let registrations = thisRegistrations || this.myParent?.getAllFromParent(token, name);
|
423
416
|
if (registrations && name !== undefined) {
|
424
417
|
registrations = registrations.filter((r)=>r.name === name);
|
425
|
-
|
418
|
+
check(registrations.length < 2, `internal error: more than one registration named '${name}'`);
|
426
419
|
}
|
427
420
|
return registrations ?? [];
|
428
421
|
}
|
@@ -563,7 +556,7 @@ function isDisposable(value) {
|
|
563
556
|
const [token, provider, options] = args;
|
564
557
|
const existingProvider = isExistingProvider(provider);
|
565
558
|
const name = existingProvider ? undefined : provider.name;
|
566
|
-
|
559
|
+
check(name === undefined || name.trim(), "the provider name qualifier cannot be empty or blank");
|
567
560
|
if (isClassProvider(provider)) {
|
568
561
|
const metadata = getMetadata(provider.useClass);
|
569
562
|
const registration = {
|
@@ -584,7 +577,7 @@ function isDisposable(value) {
|
|
584
577
|
}
|
585
578
|
} else {
|
586
579
|
if (existingProvider) {
|
587
|
-
|
580
|
+
check(token !== provider.useExisting, `the useExisting token ${token.name} cannot be the same as the token being registered`);
|
588
581
|
}
|
589
582
|
this.myTokenRegistry.set(token, {
|
590
583
|
name: name,
|
@@ -708,7 +701,7 @@ function isDisposable(value) {
|
|
708
701
|
return undefined;
|
709
702
|
}
|
710
703
|
resolveProviderValue(registration, provider) {
|
711
|
-
|
704
|
+
check(registration.provider === provider, "internal error: mismatching provider");
|
712
705
|
if (isClassProvider(provider)) {
|
713
706
|
const Class = provider.useClass;
|
714
707
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
@@ -721,9 +714,7 @@ function isDisposable(value) {
|
|
721
714
|
if (isValueProvider(provider)) {
|
722
715
|
return provider.useValue;
|
723
716
|
}
|
724
|
-
|
725
|
-
assert(false, "internal error: unexpected ExistingProvider");
|
726
|
-
}
|
717
|
+
check(!isExistingProvider(provider), "internal error: unexpected ExistingProvider");
|
727
718
|
expectNever(provider);
|
728
719
|
}
|
729
720
|
resolveScopedValue(registration, factory) {
|
@@ -739,7 +730,7 @@ function isDisposable(value) {
|
|
739
730
|
const options = registration.options;
|
740
731
|
if (resolution.stack.has(provider)) {
|
741
732
|
const dependentRef = resolution.dependents.get(provider);
|
742
|
-
|
733
|
+
check(dependentRef, "circular dependency detected");
|
743
734
|
return dependentRef.current;
|
744
735
|
}
|
745
736
|
const scope = this.resolveScope(options?.scope, context);
|
@@ -798,13 +789,13 @@ function isDisposable(value) {
|
|
798
789
|
resolveConstructorDependencies(registration) {
|
799
790
|
const dependencies = registration.dependencies;
|
800
791
|
if (dependencies) {
|
801
|
-
|
792
|
+
check(isClassProvider(registration.provider), `internal error: not a ClassProvider`);
|
802
793
|
const ctorDeps = dependencies.constructor.filter((d)=>d.appliedBy);
|
803
794
|
if (ctorDeps.length > 0) {
|
804
795
|
// Let's check if all necessary constructor parameters are decorated.
|
805
796
|
// If not, we cannot safely create an instance.
|
806
797
|
const ctor = registration.provider.useClass;
|
807
|
-
|
798
|
+
check(ctor.length === ctorDeps.length, ()=>{
|
808
799
|
const msg = `expected ${ctor.length} decorated constructor parameters in ${ctor.name}`;
|
809
800
|
return msg + `, but found ${ctorDeps.length}`;
|
810
801
|
});
|
@@ -828,7 +819,7 @@ function isDisposable(value) {
|
|
828
819
|
injectDependencies(registration, instance) {
|
829
820
|
const dependencies = registration.dependencies;
|
830
821
|
if (dependencies) {
|
831
|
-
|
822
|
+
check(isClassProvider(registration.provider), `internal error: not a ClassProvider`);
|
832
823
|
const ctor = registration.provider.useClass;
|
833
824
|
// Perform method injection
|
834
825
|
for (const entry of dependencies.methods){
|
@@ -838,7 +829,7 @@ function isDisposable(value) {
|
|
838
829
|
// If not, we cannot safely invoke the method.
|
839
830
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
840
831
|
const method = instance[key];
|
841
|
-
|
832
|
+
check(methodDeps.length === method.length, ()=>{
|
842
833
|
const msg = `expected ${method.length} decorated method parameters`;
|
843
834
|
return msg + ` in ${ctor.name}.${String(key)}, but found ${methodDeps.length}`;
|
844
835
|
});
|
@@ -862,7 +853,7 @@ function isDisposable(value) {
|
|
862
853
|
return instance;
|
863
854
|
}
|
864
855
|
checkDisposed() {
|
865
|
-
|
856
|
+
check(!this.myDisposed, "the container is disposed");
|
866
857
|
}
|
867
858
|
}
|
868
859
|
|
@@ -918,7 +909,7 @@ function isDisposable(value) {
|
|
918
909
|
return function(Class) {
|
919
910
|
const metadata = getMetadata(Class);
|
920
911
|
const currentScope = metadata.scope;
|
921
|
-
|
912
|
+
check(!currentScope || currentScope.value === Scope.Container, ()=>{
|
922
913
|
const { value, appliedBy } = currentScope;
|
923
914
|
return `class ${Class.name}: 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.`;
|
924
915
|
});
|
@@ -943,7 +934,7 @@ function forwardRef(token) {
|
|
943
934
|
},
|
944
935
|
getRefToken: ()=>{
|
945
936
|
const tokenOrTokens = token();
|
946
|
-
|
937
|
+
check(!Array.isArray(tokenOrTokens), "internal error: ref tokens should be a single token");
|
947
938
|
return tokenOrTokens;
|
948
939
|
}
|
949
940
|
};
|
@@ -963,7 +954,7 @@ function isTokenRef(value) {
|
|
963
954
|
function updateParameterMetadata(decorator, target, propertyKey, parameterIndex, updateFn) {
|
964
955
|
// Error out immediately if the decorator has been applied to a static method
|
965
956
|
if (propertyKey !== undefined && typeof target === "function") {
|
966
|
-
|
957
|
+
check(false, `@${decorator} cannot be used on static method ${target.name}.${String(propertyKey)}`);
|
967
958
|
}
|
968
959
|
if (propertyKey === undefined) {
|
969
960
|
// Constructor
|
@@ -983,11 +974,30 @@ function updateParameterMetadata(decorator, target, propertyKey, parameterIndex,
|
|
983
974
|
//
|
984
975
|
// @internal
|
985
976
|
function checkSingleDecorator(dependency, target, propertyKey, parameterIndex) {
|
986
|
-
|
987
|
-
const
|
988
|
-
return
|
977
|
+
check(dependency.appliedBy === undefined, ()=>{
|
978
|
+
const location = getLocation(target, propertyKey, parameterIndex);
|
979
|
+
return `multiple injection decorators on ${location}, but only one is allowed`;
|
989
980
|
});
|
990
981
|
}
|
982
|
+
// Checks that the `@Named` decorator is not used in combination with
|
983
|
+
// `@InjectAll` or `@OptionalAll`, which ignore the name qualification.
|
984
|
+
//
|
985
|
+
// @internal
|
986
|
+
function checkNamedDecorator(dependency, target, propertyKey, parameterIndex) {
|
987
|
+
const { appliedBy, name } = dependency;
|
988
|
+
check(name === undefined || appliedBy !== "InjectAll" && appliedBy !== "OptionalAll", ()=>{
|
989
|
+
const location = getLocation(target, propertyKey, parameterIndex);
|
990
|
+
return `@Named has no effect on ${location} when used with @${appliedBy}`;
|
991
|
+
});
|
992
|
+
}
|
993
|
+
// Returns a human-readable description of the parameter location.
|
994
|
+
// For example: "Wizard constructor parameter 2" or "Wizard.set parameter 0"
|
995
|
+
//
|
996
|
+
// @internal
|
997
|
+
function getLocation(target, propertyKey, parameterIndex) {
|
998
|
+
const location = propertyKey === undefined ? `${target.name} constructor` : `${target.constructor.name}.${String(propertyKey)}`;
|
999
|
+
return `${location} parameter ${parameterIndex}`;
|
1000
|
+
}
|
991
1001
|
|
992
1002
|
function Inject(token) {
|
993
1003
|
return function(target, propertyKey, parameterIndex) {
|
@@ -1025,6 +1035,7 @@ function InjectAll(token) {
|
|
1025
1035
|
checkSingleDecorator(dependency, target, propertyKey, parameterIndex);
|
1026
1036
|
dependency.appliedBy = "InjectAll";
|
1027
1037
|
dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
|
1038
|
+
checkNamedDecorator(dependency, target, propertyKey, parameterIndex);
|
1028
1039
|
});
|
1029
1040
|
};
|
1030
1041
|
}
|
@@ -1047,21 +1058,23 @@ function InjectAll(token) {
|
|
1047
1058
|
*
|
1048
1059
|
* @__NO_SIDE_EFFECTS__
|
1049
1060
|
*/ function Named(name) {
|
1050
|
-
|
1051
|
-
assert(false, "the @Named qualifier cannot be empty or blank");
|
1052
|
-
}
|
1061
|
+
check(name.trim(), "the @Named qualifier cannot be empty or blank");
|
1053
1062
|
return function(target, propertyKey, parameterIndex) {
|
1054
1063
|
if (parameterIndex === undefined) {
|
1055
1064
|
// The decorator has been applied to the class
|
1056
1065
|
const ctor = target;
|
1057
1066
|
const metadata = getMetadata(ctor);
|
1058
|
-
|
1067
|
+
check(metadata.name === undefined, `multiple @Named decorators on class ${ctor.name}, but only one is allowed`);
|
1059
1068
|
metadata.name = name;
|
1060
1069
|
} else {
|
1061
1070
|
// The decorator has been applied to a method parameter
|
1062
1071
|
updateParameterMetadata("Named", target, propertyKey, parameterIndex, (dependency)=>{
|
1063
|
-
|
1072
|
+
check(dependency.name === undefined, ()=>{
|
1073
|
+
const location = getLocation(target, propertyKey, parameterIndex);
|
1074
|
+
return `multiple @Named decorators on ${location}, but only one is allowed`;
|
1075
|
+
});
|
1064
1076
|
dependency.name = name;
|
1077
|
+
checkNamedDecorator(dependency, target, propertyKey, parameterIndex);
|
1065
1078
|
});
|
1066
1079
|
}
|
1067
1080
|
};
|
@@ -1083,6 +1096,7 @@ function OptionalAll(token) {
|
|
1083
1096
|
checkSingleDecorator(dependency, target, propertyKey, parameterIndex);
|
1084
1097
|
dependency.appliedBy = "OptionalAll";
|
1085
1098
|
dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
|
1099
|
+
checkNamedDecorator(dependency, target, propertyKey, parameterIndex);
|
1086
1100
|
});
|
1087
1101
|
};
|
1088
1102
|
}
|
@@ -1112,7 +1126,7 @@ function OptionalAll(token) {
|
|
1112
1126
|
return function(Class) {
|
1113
1127
|
const metadata = getMetadata(Class);
|
1114
1128
|
const currentScope = metadata.scope;
|
1115
|
-
|
1129
|
+
check(!currentScope || currentScope.value === scope, ()=>{
|
1116
1130
|
const { value, appliedBy } = currentScope;
|
1117
1131
|
const by = appliedBy === "Scoped" ? `another @${appliedBy} decorator` : `@${appliedBy}`;
|
1118
1132
|
return `class ${Class.name}: 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.`;
|