@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 CHANGED
@@ -28,7 +28,7 @@ function isConstructor(token) {
28
28
  }
29
29
 
30
30
  // @internal
31
- function assert(condition, message) {
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
- invariant(!this.has(key));
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
- invariant(!this.get(key));
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
- assert(context, `${name} can only be invoked within an injection context`);
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
- assert(!internals.has(token), `cannot register reserved token ${token.name}`);
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
- assert(existing.length === 0, `a ${token.name} token named '${registration.name}' is already registered`);
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
- assert(registrations.length < 2, `internal error: more than one registration named '${name}'`);
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
- assert(name === undefined || name.trim(), "the provider name qualifier cannot be empty or blank");
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
- assert(token !== provider.useExisting, `the useExisting token ${token.name} cannot be the same as the token being registered`);
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
- assert(registration.provider === provider, "internal error: mismatching provider");
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
- if (isExistingProvider(provider)) {
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
- assert(dependentRef, "circular dependency detected");
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
- assert(isClassProvider(registration.provider), `internal error: not a ClassProvider`);
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
- assert(ctor.length === ctorDeps.length, ()=>{
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
- assert(isClassProvider(registration.provider), `internal error: not a ClassProvider`);
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
- assert(methodDeps.length === method.length, ()=>{
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
- assert(!this.myDisposed, "the container is disposed");
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
- assert(!currentScope || currentScope.value === Scope.Container, ()=>{
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
- assert(!Array.isArray(tokenOrTokens), "internal error: ref tokens should be a single token");
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
- assert(false, `@${decorator} cannot be used on static method ${target.name}.${String(propertyKey)}`);
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
- assert(!dependency.appliedBy, ()=>{
987
- const where = propertyKey === undefined ? `${target.name} constructor` : `${target.constructor.name}.${String(propertyKey)}`;
988
- return `${where} parameter ${parameterIndex} declares multiple injection decorators, but only one is allowed`;
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
- if (!name.trim()) {
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
- assert(!metadata.name, `a @Named('${metadata.name}') qualifier has already been applied to ${ctor.name}`);
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
- assert(!dependency.name, `a @Named('${dependency.name}') qualifier has already been applied to the parameter`);
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
- assert(!currentScope || currentScope.value === scope, ()=>{
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.`;