@travetto/di 3.3.0 → 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 +27 -0
- package/package.json +3 -3
- package/src/registry.ts +17 -14
- package/src/types.ts +8 -0
- package/support/dynamic.injection.ts +0 -8
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.
|
|
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.
|
|
30
|
+
"@travetto/registry": "^3.3.2"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@travetto/transformer": "^3.3.
|
|
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
|
}
|