@travetto/di 3.3.1 → 3.3.2

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
@@ -98,6 +98,33 @@ class Config {
98
98
 
99
99
  Given the `static` method `initService`, the function will be provided as a valid candidate for `CoolService`. Instead of calling the constructor of the type directly, this function will work as a factory for producing the injectable.
100
100
 
101
+ **Code: Example Conditional Dependency**
102
+ ```typescript
103
+ import { GlobalEnv } from '@travetto/base';
104
+ import { Inject, Injectable } from '@travetto/di';
105
+
106
+ @Injectable({ enabled: !GlobalEnv.devMode })
107
+ class ProductionLogger {
108
+ async log() {
109
+ console.log('This will only run in production');
110
+ }
111
+ }
112
+
113
+ @Injectable()
114
+ class RuntimeService {
115
+ @Inject()
116
+ logger?: ProductionLogger;
117
+
118
+ action(): void {
119
+ // Only injected when available, in prod
120
+ this.logger?.log();
121
+ // Do work
122
+ }
123
+ }
124
+ ```
125
+
126
+ In this example, the enabled flag is specified in relationship to the deployment environment. When coupled with optional properties, and optional chaining, allows for seamless inclusion of optional dependencies at runtime.
127
+
101
128
  **Note**: Other modules are able to provide aliases to [@Injectable](https://github.com/travetto/travetto/tree/main/module/di/src/decorator.ts#L31) that also provide additional functionality. For example, the [Configuration](https://github.com/travetto/travetto/tree/main/module/config#readme "Configuration support") module @Config or the [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.") module @Controller decorator registers the associated class as an injectable element.
102
129
 
103
130
  ## Injection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/di",
3
- "version": "3.3.1",
3
+ "version": "3.3.2",
4
4
  "description": "Dependency registration/management and injection support.",
5
5
  "keywords": [
6
6
  "ast-transformations",
@@ -27,10 +27,10 @@
27
27
  "directory": "module/di"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/registry": "^3.3.1"
30
+ "@travetto/registry": "^3.3.2"
31
31
  },
32
32
  "peerDependencies": {
33
- "@travetto/transformer": "^3.3.0"
33
+ "@travetto/transformer": "^3.3.1"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@travetto/transformer": {
package/src/registry.ts CHANGED
@@ -271,6 +271,7 @@ class $DependencyRegistry extends MetadataRegistry<InjectableConfig> {
271
271
 
272
272
  return {
273
273
  class: cls,
274
+ enabled: true,
274
275
  target: cls,
275
276
  interfaces: [],
276
277
  dependencies: {
@@ -297,7 +298,7 @@ class $DependencyRegistry extends MetadataRegistry<InjectableConfig> {
297
298
  /**
298
299
  * Get all available candidate types for the target
299
300
  */
300
- getCandidateTypes<T>(target: Class<T>): InjectableConfig[] {
301
+ getCandidateTypes<T>(target: Class<T>): InjectableConfig<T>[] {
301
302
  const targetId = target.Ⲑid;
302
303
  const qualifiers = this.targetToClass.get(targetId)!;
303
304
  const uniqueQualifiers = qualifiers ? Array.from(new Set(qualifiers.values())) : [];
@@ -305,6 +306,15 @@ class $DependencyRegistry extends MetadataRegistry<InjectableConfig> {
305
306
  return uniqueQualifiers.map(id => this.get(id)! as InjectableConfig<T>);
306
307
  }
307
308
 
309
+ /**
310
+ * Get candidate instances by target type, with an optional filter
311
+ */
312
+ getCandidateInstances<T>(target: Class, predicate?: (cfg: InjectableConfig<T>) => boolean): Promise<T[]> {
313
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
314
+ const inputs = this.getCandidateTypes<T>(target as Class<T>).filter(x => !predicate || predicate(x));
315
+ return Promise.all(inputs.map(l => this.getInstance<T>(l.class, l.qualifier)));
316
+ }
317
+
308
318
  /**
309
319
  * Register a constructor with dependencies
310
320
  */
@@ -327,6 +337,7 @@ class $DependencyRegistry extends MetadataRegistry<InjectableConfig> {
327
337
  registerClass<T>(cls: Class<T>, pConfig: Partial<InjectableConfig<T>> = {}): void {
328
338
  const config = this.getOrCreatePending(pConfig.class ?? cls);
329
339
 
340
+ config.enabled = pConfig.enabled ?? config.enabled;
330
341
  config.class = cls;
331
342
  config.qualifier = pConfig.qualifier ?? config.qualifier ?? Symbol.for(cls.Ⲑid);
332
343
  if (pConfig.interfaces) {
@@ -360,6 +371,7 @@ class $DependencyRegistry extends MetadataRegistry<InjectableConfig> {
360
371
  }): void {
361
372
  const finalConfig: Partial<InjectableConfig> = {};
362
373
 
374
+ finalConfig.enabled = config.enabled ?? true;
363
375
  finalConfig.factory = config.fn;
364
376
  finalConfig.target = config.target;
365
377
  finalConfig.qualifier = config.qualifier;
@@ -415,6 +427,10 @@ class $DependencyRegistry extends MetadataRegistry<InjectableConfig> {
415
427
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
416
428
  const config = this.getOrCreatePending(cls) as InjectableConfig<T>;
417
429
 
430
+ if (!(typeof config.enabled === 'boolean' ? config.enabled : config.enabled())) {
431
+ return config; // Do not setup if disabled
432
+ }
433
+
418
434
  // Allow for the factory to fulfill the target
419
435
  let parentClass = config.factory ? config.target : Object.getPrototypeOf(cls);
420
436
 
@@ -539,19 +555,6 @@ class $DependencyRegistry extends MetadataRegistry<InjectableConfig> {
539
555
  }
540
556
  }
541
557
 
542
- /**
543
- * Reset registry
544
- */
545
- override onReset(): void {
546
- super.onReset();
547
- this.pendingFinalize = [];
548
- this.instances.clear();
549
- this.instancePromises.clear();
550
- this.targetToClass.clear();
551
- this.classToTarget.clear();
552
- this.factories.clear();
553
- }
554
-
555
558
  /**
556
559
  * Inject fields into instance
557
560
  */
package/src/types.ts CHANGED
@@ -36,6 +36,10 @@ export interface Dependency<T = unknown> extends Core<T> {
36
36
  * Injectable configuration
37
37
  */
38
38
  export interface InjectableConfig<T = unknown> extends Core<T> {
39
+ /**
40
+ * Is this injectable enabled
41
+ */
42
+ enabled: boolean | (() => boolean);
39
43
  /**
40
44
  * Reference for the class
41
45
  */
@@ -65,6 +69,10 @@ export interface InjectableConfig<T = unknown> extends Core<T> {
65
69
  * Factory configuration
66
70
  */
67
71
  export interface InjectableFactoryConfig<T = unknown> extends Core<T> {
72
+ /**
73
+ * Is this injectable enabled
74
+ */
75
+ enabled: boolean | (() => boolean);
68
76
  /**
69
77
  * Src of the factory method
70
78
  */
@@ -14,7 +14,6 @@ class $DynamicDependencyRegistry {
14
14
  #registryResolveTarget: <T>(target: ClassTarget<T>, qualifier?: symbol, resolution?: ResolutionType) => Resolved<T>;
15
15
  #registryOnInstallFinalize: <T>(target: Class<T>) => InjectableConfig<T>;
16
16
  #registryDestroyInstance: <T>(target: Class<T>, qualifier: symbol) => void;
17
- #registryOnReset: () => void;
18
17
 
19
18
  /**
20
19
  * Proxy the created instance
@@ -86,22 +85,15 @@ class $DynamicDependencyRegistry {
86
85
  }
87
86
  }
88
87
 
89
- onReset(): void {
90
- this.#registryOnReset();
91
- this.#proxies.clear();
92
- }
93
-
94
88
  register(registry: typeof DependencyRegistry): void {
95
89
  this.#registry = registry;
96
90
  this.#registryCreateInstance = registry['createInstance'].bind(registry);
97
91
  this.#registryResolveTarget = registry['resolveTarget'].bind(registry);
98
92
  this.#registryOnInstallFinalize = registry['onInstallFinalize'].bind(registry);
99
93
  this.#registryDestroyInstance = registry['destroyInstance'].bind(registry);
100
- this.#registryOnReset = registry['onReset'].bind(registry);
101
94
 
102
95
  this.#registry['createInstance'] = this.createInstance.bind(this);
103
96
  this.#registry['destroyInstance'] = this.destroyInstance.bind(this);
104
- this.#registry['onReset'] = this.onReset.bind(this);
105
97
  this.#registry['onInstallFinalize'] = this.onInstallFinalize.bind(this);
106
98
  }
107
99
  }