@lppedd/di-wise-neo 0.14.2 → 0.15.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/README.md CHANGED
@@ -435,11 +435,11 @@ Normally, attempting to do that would result in a `ReferenceError`:
435
435
 
436
436
  > ReferenceError: Cannot access 'IStore' before initialization
437
437
 
438
- We can work around this problem by using the `forwardRef` helper function:
438
+ We can work around this problem by using the `tokenRef` helper function:
439
439
 
440
440
  ```ts
441
441
  export class ExtensionContext {
442
- constructor(@OptionalAll(forwardRef(() => IStore)) readonly stores: Store[]) {}
442
+ constructor(@OptionalAll(tokenRef(() => IStore)) readonly stores: Store[]) {}
443
443
 
444
444
  /* ... */
445
445
  }
@@ -119,6 +119,33 @@ declare function createType<T>(typeName: string): Type<T>;
119
119
  */
120
120
  declare function createType<T>(typeName: string, provider: Provider<T>, options?: RegistrationOptions): ProviderType<T>;
121
121
 
122
+ interface ClassRef<Instance extends object> {
123
+ readonly getRefClass: () => Constructor<Instance>;
124
+ }
125
+ interface TokensRef<Value = any> {
126
+ readonly getRefTokens: () => Set<Token<Value>>;
127
+ }
128
+ interface TokenRef<Value = any> {
129
+ readonly getRefToken: () => Token<Value>;
130
+ }
131
+ /**
132
+ * Allows referencing a class declared later in the file by wrapping it
133
+ * in a lazily evaluated function.
134
+ *
135
+ * @__NO_SIDE_EFFECTS__
136
+ */
137
+ declare function classRef<Instance extends object>(Class: () => Constructor<Instance>): ClassRef<Instance>;
138
+ /**
139
+ * Allows referencing tokens declared later in the file by wrapping them
140
+ * in a lazily evaluated function.
141
+ */
142
+ declare function tokenRef<Value>(token: () => Tokens<Value>): TokensRef<Value>;
143
+ /**
144
+ * Allows referencing a token declared later in the file by wrapping it
145
+ * in a lazily evaluated function.
146
+ */
147
+ declare function tokenRef<Value>(token: () => Token<Value>): TokenRef<Value>;
148
+
122
149
  /**
123
150
  * Provides a class instance for a token via a class constructor.
124
151
  */
@@ -126,7 +153,7 @@ interface ClassProvider<Instance extends object> {
126
153
  /**
127
154
  * The class to instantiate for the token.
128
155
  */
129
- readonly useClass: Constructor<Instance>;
156
+ readonly useClass: Constructor<Instance> | ClassRef<Instance>;
130
157
  /**
131
158
  * An optional name to qualify this provider.
132
159
  * If specified, the token must be resolved using the same name.
@@ -597,23 +624,6 @@ declare function AutoRegister(): ClassDecorator;
597
624
  */
598
625
  declare function EagerInstantiate(): ClassDecorator;
599
626
 
600
- interface TokensRef<Value = any> {
601
- readonly getRefTokens: () => Set<Token<Value>>;
602
- }
603
- interface TokenRef<Value = any> {
604
- readonly getRefToken: () => Token<Value>;
605
- }
606
- /**
607
- * Allows referencing tokens declared later in the file by wrapping them
608
- * in a lazily evaluated function.
609
- */
610
- declare function forwardRef<Value>(token: () => Tokens<Value>): TokensRef<Value>;
611
- /**
612
- * Allows referencing a token declared later in the file by wrapping it
613
- * in a lazily evaluated function.
614
- */
615
- declare function forwardRef<Value>(token: () => Token<Value>): TokenRef<Value>;
616
-
617
627
  /**
618
628
  * Parameter decorator that injects the instance associated with the given class.
619
629
  *
@@ -636,7 +646,7 @@ declare function Inject<Value>(token: Token<Value>): ParameterDecorator;
636
646
  * Parameter decorator that injects the value associated with the given token.
637
647
  *
638
648
  * Allows referencing a token declared later in the file by using the
639
- * {@link forwardRef} helper function.
649
+ * {@link tokenRef} helper function.
640
650
  *
641
651
  * Throws an error if:
642
652
  * - The token is not registered in the container.
@@ -646,7 +656,7 @@ declare function Inject<Value>(token: Token<Value>): ParameterDecorator;
646
656
  * @example
647
657
  * ```ts
648
658
  * class Wizard {
649
- * constructor(@Inject(forwardRef(() => Wand)) readonly wand: Wand) {}
659
+ * constructor(@Inject(tokenRef(() => Wand)) readonly wand: Wand) {}
650
660
  * }
651
661
  * // Other code...
652
662
  * class Wand {}
@@ -674,11 +684,11 @@ declare function Injectable<This extends object, Value extends This>(...tokens:
674
684
  * The container uses {@link ExistingProvider} under the hood.
675
685
  *
676
686
  * Allows referencing tokens that are declared later in the file by using
677
- * the {@link forwardRef} helper function.
687
+ * the {@link tokenRef} helper function.
678
688
  *
679
689
  * @example
680
690
  * ```ts
681
- * @Injectable(forwardRef() => Weapon) // Weapon is declared after Wand
691
+ * @Injectable(tokenRef() => Weapon) // Weapon is declared after Wand
682
692
  * class Wizard {}
683
693
  * // Other code...
684
694
  * class Weapon {}
@@ -709,7 +719,7 @@ declare function InjectAll<Value>(token: Token<Value>): ParameterDecorator;
709
719
  * associated with the given token.
710
720
  *
711
721
  * Allows referencing a token declared later in the file by using the
712
- * {@link forwardRef} helper function.
722
+ * {@link tokenRef} helper function.
713
723
  *
714
724
  * Throws an error if:
715
725
  * - The token is not registered in the container.
@@ -718,7 +728,7 @@ declare function InjectAll<Value>(token: Token<Value>): ParameterDecorator;
718
728
  * @example
719
729
  * ```ts
720
730
  * class Wizard {
721
- * constructor(@InjectAll(forwardRef(() => Wand)) readonly wands: Wand[]) {}
731
+ * constructor(@InjectAll(tokenRef(() => Wand)) readonly wands: Wand[]) {}
722
732
  * }
723
733
  * // Other code...
724
734
  * class Wand {}
@@ -767,7 +777,7 @@ declare function Optional<Value>(token: Token<Value>): ParameterDecorator;
767
777
  * or `undefined` if the token is not registered in the container.
768
778
  *
769
779
  * Allows referencing a token declared later in the file by using the
770
- * {@link forwardRef} helper function.
780
+ * {@link tokenRef} helper function.
771
781
  *
772
782
  * Throws an error if a circular dependency is detected. Use function injection
773
783
  * with {@link optionalBy} if resolving circular dependencies is necessary.
@@ -775,7 +785,7 @@ declare function Optional<Value>(token: Token<Value>): ParameterDecorator;
775
785
  * @example
776
786
  * ```ts
777
787
  * class Wizard {
778
- * constructor(@Optional(forwardRef(() => Wand)) readonly wand: Wand | undefined) {}
788
+ * constructor(@Optional(tokenRef(() => Wand)) readonly wand: Wand | undefined) {}
779
789
  * }
780
790
  * // Other code...
781
791
  * class Wand {}
@@ -805,14 +815,14 @@ declare function OptionalAll<Value>(token: Token<Value>): ParameterDecorator;
805
815
  * in the container.
806
816
  *
807
817
  * Allows referencing a token declared later in the file by using the
808
- * {@link forwardRef} helper function.
818
+ * {@link tokenRef} helper function.
809
819
  *
810
820
  * Throws an error if a circular dependency is detected.
811
821
  *
812
822
  * @example
813
823
  * ```ts
814
824
  * class Wizard {
815
- * constructor(@OptionalAll(forwardRef(() => Wand)) readonly wands: Wand[]) {}
825
+ * constructor(@OptionalAll(tokenRef(() => Wand)) readonly wands: Wand[]) {}
816
826
  * }
817
827
  * // Other code...
818
828
  * class Wand {}
@@ -1137,5 +1147,5 @@ declare function optionalAll<Instance extends object>(Class: Constructor<Instanc
1137
1147
  */
1138
1148
  declare function optionalAll<Value>(token: Token<Value>): Value[];
1139
1149
 
1140
- export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Named, Optional, OptionalAll, Scope, Scoped, applyMiddleware, build, createContainer, createType, forwardRef, inject, injectAll, injectBy, optional, optionalAll, optionalBy, setClassIdentityMapping };
1141
- export type { ClassProvider, Constructor, Container, ContainerOptions, ExistingProvider, FactoryProvider, Middleware, MiddlewareComposer, Provider, ProviderType, RegistrationOptions, Token, TokenRef, Tokens, TokensRef, Type, ValueProvider };
1150
+ export { AutoRegister, EagerInstantiate, Inject, InjectAll, Injectable, Injector, Named, Optional, OptionalAll, Scope, Scoped, applyMiddleware, build, classRef, createContainer, createType, inject, injectAll, injectBy, optional, optionalAll, optionalBy, setClassIdentityMapping, tokenRef };
1151
+ export type { ClassProvider, ClassRef, Constructor, Container, ContainerOptions, ExistingProvider, FactoryProvider, Middleware, MiddlewareComposer, Provider, ProviderType, RegistrationOptions, Token, TokenRef, Tokens, TokensRef, Type, ValueProvider };
package/dist/cjs/index.js CHANGED
@@ -34,7 +34,7 @@ function throwResolutionError(tokenInfo, aliases, cause) {
34
34
  function throwParameterResolutionError(ctor, methodKey, dependency, cause) {
35
35
  const location = getLocation(ctor, methodKey);
36
36
  const tokenName = getFullTokenName([
37
- dependency.tokenRef.getRefToken(),
37
+ dependency.tokenRef?.getRefToken(),
38
38
  dependency.name
39
39
  ]);
40
40
  const msg = tag(`failed to resolve dependency for ${location}(parameter #${dependency.index}: ${tokenName})`);
@@ -56,7 +56,7 @@ function getTokenName(token) {
56
56
  return token.name || "<unnamed>";
57
57
  }
58
58
  function getFullTokenName([token, name]) {
59
- const tokenName = token.name || "<unnamed>";
59
+ const tokenName = token ? token.name || "<unnamed>" : "<undefined token>";
60
60
  return name ? `${tokenName}["${name}"]` : tokenName;
61
61
  }
62
62
  function getCause(error) {
@@ -186,6 +186,47 @@ function injectAll(token) {
186
186
  return context.container.resolveAll(token);
187
187
  }
188
188
 
189
+ /**
190
+ * Allows referencing a class declared later in the file by wrapping it
191
+ * in a lazily evaluated function.
192
+ *
193
+ * @__NO_SIDE_EFFECTS__
194
+ */ function classRef(Class) {
195
+ return {
196
+ getRefClass: ()=>Class()
197
+ };
198
+ }
199
+ // @__NO_SIDE_EFFECTS__
200
+ function tokenRef(token) {
201
+ return {
202
+ getRefTokens: ()=>{
203
+ // Normalize the single token here so that we don't have to do it at every getRefTokens call site
204
+ const tokenOrTokens = token();
205
+ const tokensArray = Array.isArray(tokenOrTokens) ? tokenOrTokens : [
206
+ tokenOrTokens
207
+ ];
208
+ return new Set(tokensArray);
209
+ },
210
+ getRefToken: ()=>{
211
+ const tokenOrTokens = token();
212
+ check(!Array.isArray(tokenOrTokens), "internal error: ref tokens should be a single token");
213
+ return tokenOrTokens;
214
+ }
215
+ };
216
+ }
217
+ // @internal
218
+ function isClassRef(value) {
219
+ return value && typeof value === "object" && typeof value.getRefClass === "function";
220
+ }
221
+ // @internal
222
+ function isTokensRef(value) {
223
+ return value && typeof value === "object" && typeof value.getRefTokens === "function";
224
+ }
225
+ // @internal
226
+ function isTokenRef(value) {
227
+ return value && typeof value === "object" && typeof value.getRefToken === "function";
228
+ }
229
+
189
230
  // @internal
190
231
  class Metadata {
191
232
  constructor(Class){
@@ -234,7 +275,8 @@ class Metadata {
234
275
  }
235
276
  }
236
277
  // @internal
237
- function getMetadata(Class) {
278
+ function getMetadata(classOrRef) {
279
+ const Class = isClassRef(classOrRef) ? classOrRef.getRefClass() : classOrRef;
238
280
  const originalClass = classIdentityMap.get(Class) ?? Class;
239
281
  let metadata = metadataMap.get(originalClass);
240
282
  if (!metadata) {
@@ -890,6 +932,7 @@ function isDisposable(value) {
890
932
  }
891
933
  return [];
892
934
  }
935
+ // Call context: decorator-based injection
893
936
  injectMethodDependencies(registration, instance) {
894
937
  const dependencies = registration.dependencies;
895
938
  if (dependencies) {
@@ -913,6 +956,7 @@ function isDisposable(value) {
913
956
  }
914
957
  return instance;
915
958
  }
959
+ // Call context: decorator-based injection
916
960
  resolveArgs(deps, ctor, instance, methodKey) {
917
961
  const sortedDeps = deps.sort((a, b)=>a.index - b.index);
918
962
  const args = [];
@@ -925,8 +969,10 @@ function isDisposable(value) {
925
969
  }
926
970
  return args;
927
971
  }
972
+ // Call context: decorator-based injection
928
973
  resolveDependency(dependency, instance) {
929
- const token = dependency.tokenRef.getRefToken();
974
+ const token = dependency.tokenRef?.getRefToken();
975
+ check(token, `token passed to @${dependency.appliedBy} was undefined (possible circular imports)`);
930
976
  const name = dependency.name;
931
977
  switch(dependency.appliedBy){
932
978
  case "Inject":
@@ -1007,33 +1053,6 @@ function isDisposable(value) {
1007
1053
  };
1008
1054
  }
1009
1055
 
1010
- // @__NO_SIDE_EFFECTS__
1011
- function forwardRef(token) {
1012
- return {
1013
- getRefTokens: ()=>{
1014
- // Normalize the single token here so that we don't have to do it at every getRefTokens call site
1015
- const tokenOrTokens = token();
1016
- const tokensArray = Array.isArray(tokenOrTokens) ? tokenOrTokens : [
1017
- tokenOrTokens
1018
- ];
1019
- return new Set(tokensArray);
1020
- },
1021
- getRefToken: ()=>{
1022
- const tokenOrTokens = token();
1023
- check(!Array.isArray(tokenOrTokens), "internal error: ref tokens should be a single token");
1024
- return tokenOrTokens;
1025
- }
1026
- };
1027
- }
1028
- // @internal
1029
- function isTokensRef(value) {
1030
- return value && typeof value === "object" && typeof value.getRefTokens === "function";
1031
- }
1032
- // @internal
1033
- function isTokenRef(value) {
1034
- return value && typeof value === "object" && typeof value.getRefToken === "function";
1035
- }
1036
-
1037
1056
  // @internal
1038
1057
  function updateParameterMetadata(decorator, target, methodKey, parameterIndex, updateFn) {
1039
1058
  // Error out immediately if the decorator has been applied to a static method
@@ -1089,7 +1108,7 @@ function Inject(token) {
1089
1108
  updateParameterMetadata("Inject", target, propertyKey, parameterIndex, (dependency)=>{
1090
1109
  checkSingleDecorator(dependency, target, propertyKey, parameterIndex);
1091
1110
  dependency.appliedBy = "Inject";
1092
- dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
1111
+ dependency.tokenRef = isTokenRef(token) ? token : tokenRef(()=>token);
1093
1112
  });
1094
1113
  };
1095
1114
  }
@@ -1099,7 +1118,7 @@ function Injectable(...args) {
1099
1118
  return function(Class) {
1100
1119
  const metadata = getMetadata(Class);
1101
1120
  const arg0 = args[0];
1102
- const tokensRef = isTokensRef(arg0) ? arg0 : forwardRef(()=>args);
1121
+ const tokensRef = isTokensRef(arg0) ? arg0 : tokenRef(()=>args);
1103
1122
  const existingTokensRef = metadata.tokensRef;
1104
1123
  metadata.tokensRef = {
1105
1124
  getRefTokens: ()=>{
@@ -1119,7 +1138,7 @@ function InjectAll(token) {
1119
1138
  updateParameterMetadata("InjectAll", target, propertyKey, parameterIndex, (dependency)=>{
1120
1139
  checkSingleDecorator(dependency, target, propertyKey, parameterIndex);
1121
1140
  dependency.appliedBy = "InjectAll";
1122
- dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
1141
+ dependency.tokenRef = isTokenRef(token) ? token : tokenRef(()=>token);
1123
1142
  checkNamedDecorator(dependency, target, propertyKey, parameterIndex);
1124
1143
  });
1125
1144
  };
@@ -1172,7 +1191,7 @@ function Optional(token) {
1172
1191
  updateParameterMetadata("Optional", target, propertyKey, parameterIndex, (dependency)=>{
1173
1192
  checkSingleDecorator(dependency, target, propertyKey, parameterIndex);
1174
1193
  dependency.appliedBy = "Optional";
1175
- dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
1194
+ dependency.tokenRef = isTokenRef(token) ? token : tokenRef(()=>token);
1176
1195
  });
1177
1196
  };
1178
1197
  }
@@ -1183,7 +1202,7 @@ function OptionalAll(token) {
1183
1202
  updateParameterMetadata("OptionalAll", target, propertyKey, parameterIndex, (dependency)=>{
1184
1203
  checkSingleDecorator(dependency, target, propertyKey, parameterIndex);
1185
1204
  dependency.appliedBy = "OptionalAll";
1186
- dependency.tokenRef = isTokenRef(token) ? token : forwardRef(()=>token);
1205
+ dependency.tokenRef = isTokenRef(token) ? token : tokenRef(()=>token);
1187
1206
  checkNamedDecorator(dependency, target, propertyKey, parameterIndex);
1188
1207
  });
1189
1208
  };
@@ -1321,9 +1340,9 @@ exports.Scope = Scope;
1321
1340
  exports.Scoped = Scoped;
1322
1341
  exports.applyMiddleware = applyMiddleware;
1323
1342
  exports.build = build;
1343
+ exports.classRef = classRef;
1324
1344
  exports.createContainer = createContainer;
1325
1345
  exports.createType = createType;
1326
- exports.forwardRef = forwardRef;
1327
1346
  exports.inject = inject;
1328
1347
  exports.injectAll = injectAll;
1329
1348
  exports.injectBy = injectBy;
@@ -1331,4 +1350,5 @@ exports.optional = optional;
1331
1350
  exports.optionalAll = optionalAll;
1332
1351
  exports.optionalBy = optionalBy;
1333
1352
  exports.setClassIdentityMapping = setClassIdentityMapping;
1353
+ exports.tokenRef = tokenRef;
1334
1354
  //# sourceMappingURL=index.js.map