@travetto/di 3.1.0-rc.3 → 3.1.0-rc.5
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 +39 -0
- package/package.json +2 -2
- package/support/transformer.injectable.ts +32 -16
package/README.md
CHANGED
|
@@ -195,6 +195,45 @@ class Config {
|
|
|
195
195
|
}
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
+
## Non-Framework Dependencies
|
|
199
|
+
The module is built around the framework's management of class registration, and being able to decorate the code with [@Injectable](https://github.com/travetto/travetto/tree/main/module/di/src/decorator.ts#L31) decorators. There may also be a desire to leverage external code and pull it into the dependency injection framework. This could easily be achieved using a wrapper class that is owned by the framework.
|
|
200
|
+
|
|
201
|
+
It is also possible to directly reference external types, and they will be converted into unique symbols. These symbols cannot be used manually, but can be leveraged using [@Inject](https://github.com/travetto/travetto/tree/main/module/di/src/decorator.ts#L31) decorators.
|
|
202
|
+
|
|
203
|
+
**Code: Example External Dependencies**
|
|
204
|
+
```typescript
|
|
205
|
+
import { EventEmitter } from 'events';
|
|
206
|
+
import { Writable } from 'stream';
|
|
207
|
+
|
|
208
|
+
import { Inject, Injectable, InjectableFactory } from '@travetto/di';
|
|
209
|
+
|
|
210
|
+
class Source {
|
|
211
|
+
@InjectableFactory()
|
|
212
|
+
static emitter(): EventEmitter {
|
|
213
|
+
return new EventEmitter();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
@InjectableFactory(Symbol.for('custom-1'))
|
|
217
|
+
static writable(): Writable {
|
|
218
|
+
return {} as Writable;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@InjectableFactory(Symbol.for('custom-2'))
|
|
222
|
+
static writableAlt(): Writable {
|
|
223
|
+
return {} as Writable;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@Injectable()
|
|
228
|
+
class Service {
|
|
229
|
+
@Inject()
|
|
230
|
+
emitter: EventEmitter;
|
|
231
|
+
|
|
232
|
+
@Inject(Symbol.for('custom-2'))
|
|
233
|
+
writable: Writable;
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
198
237
|
## Manual Invocation
|
|
199
238
|
Some times you will need to lookup a dependency dynamically, or you want to control the injection process at a more granular level. To achieve that you will need to directly access the [DependencyRegistry](https://github.com/travetto/travetto/tree/main/module/di/src/registry.ts#L1). The registry allows for requesting a dependency by class reference:
|
|
200
239
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/di",
|
|
3
|
-
"version": "3.1.0-rc.
|
|
3
|
+
"version": "3.1.0-rc.5",
|
|
4
4
|
"description": "Dependency registration/management and injection support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ast-transformations",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@travetto/registry": "^3.1.0-rc.3"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@travetto/transformer": "^3.1.0-rc.
|
|
33
|
+
"@travetto/transformer": "^3.1.0-rc.5"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|
|
36
36
|
"@travetto/transformer": {
|
|
@@ -25,14 +25,26 @@ export class InjectableTransformer {
|
|
|
25
25
|
const callExpr = existing?.expression as ts.CallExpression;
|
|
26
26
|
const args: ts.Expression[] = [...(callExpr?.arguments ?? [])];
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const payload: { target?: unknown, qualifier?: unknown, optional?: boolean } = {};
|
|
29
|
+
|
|
30
|
+
if (!!param.questionToken) {
|
|
31
|
+
payload.optional = true;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
const keyParam = ts.isSetAccessorDeclaration(param) ? param.parameters[0] : param;
|
|
34
|
-
const
|
|
35
|
-
|
|
35
|
+
const type = state.resolveType(keyParam);
|
|
36
|
+
|
|
37
|
+
if (type.key === 'managed') {
|
|
38
|
+
payload.target = state.getOrImport(type);
|
|
39
|
+
} else if (type.key === 'foreign') {
|
|
40
|
+
payload.target = state.getForeignTarget(state, type);
|
|
41
|
+
} else {
|
|
42
|
+
const file = param.getSourceFile().fileName;
|
|
43
|
+
const src = state.getFileImportName(file);
|
|
44
|
+
throw new Error(`Unable to import non-external type: ${param.getText()} ${type.key}: ${src}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
args.unshift(state.fromLiteral(payload));
|
|
36
48
|
|
|
37
49
|
return args;
|
|
38
50
|
}
|
|
@@ -52,7 +64,7 @@ export class InjectableTransformer {
|
|
|
52
64
|
if (clause.token === ts.SyntaxKind.ImplementsKeyword) {
|
|
53
65
|
for (const typeExpression of clause.types) {
|
|
54
66
|
const resolvedType = state.resolveType(typeExpression);
|
|
55
|
-
if (resolvedType.key === '
|
|
67
|
+
if (resolvedType.key === 'managed') {
|
|
56
68
|
const resolved = state.getOrImport(resolvedType);
|
|
57
69
|
interfaces.push(resolved);
|
|
58
70
|
}
|
|
@@ -134,21 +146,25 @@ export class InjectableTransformer {
|
|
|
134
146
|
const dependencies = node.parameters.map(x => this.processDeclaration(state, x));
|
|
135
147
|
|
|
136
148
|
// Read target from config or resolve
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
149
|
+
const config: { dependencies: unknown[], target?: unknown, qualifier?: unknown, src?: unknown } = {
|
|
150
|
+
dependencies,
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
152
|
+
src: (node.parent as ts.ClassDeclaration).name,
|
|
153
|
+
};
|
|
154
|
+
let ret = state.resolveReturnType(node);
|
|
155
|
+
if (ret.key === 'literal' && ret.ctor === Promise && ret.typeArguments) {
|
|
156
|
+
ret = ret.typeArguments![0];
|
|
157
|
+
}
|
|
158
|
+
if (ret.key === 'managed') {
|
|
159
|
+
config.target = state.getOrImport(ret);
|
|
160
|
+
} else if (ret.key === 'foreign') {
|
|
161
|
+
config.target = state.getForeignTarget(state, ret);
|
|
141
162
|
}
|
|
142
163
|
|
|
143
164
|
// Build decl
|
|
144
165
|
const args = [...(dec && ts.isCallExpression(dec.expression) ? dec.expression.arguments : [undefined])];
|
|
145
166
|
|
|
146
|
-
args.unshift(state.extendObjectLiteral(
|
|
147
|
-
dependencies,
|
|
148
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
149
|
-
src: (node.parent as ts.ClassDeclaration).name,
|
|
150
|
-
target
|
|
151
|
-
}));
|
|
167
|
+
args.unshift(state.extendObjectLiteral(config));
|
|
152
168
|
|
|
153
169
|
// Replace decorator
|
|
154
170
|
return state.factory.updateMethodDeclaration(
|