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