@travetto/di 3.1.0-rc.2 → 3.1.0-rc.4
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 +3 -3
- package/support/transformer.injectable.ts +35 -15
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.4",
|
|
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.1.0-rc.
|
|
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.4"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|
|
36
36
|
"@travetto/transformer": {
|
|
@@ -3,6 +3,7 @@ import ts from 'typescript';
|
|
|
3
3
|
import {
|
|
4
4
|
TransformerState, DecoratorMeta, OnClass, OnProperty, OnStaticMethod, DecoratorUtil, LiteralUtil, OnSetter
|
|
5
5
|
} from '@travetto/transformer';
|
|
6
|
+
import { ForeignType } from '@travetto/transformer/src/resolver/types';
|
|
6
7
|
|
|
7
8
|
const INJECTABLE_MOD = '@travetto/di/src/decorator';
|
|
8
9
|
|
|
@@ -11,6 +12,12 @@ const INJECTABLE_MOD = '@travetto/di/src/decorator';
|
|
|
11
12
|
*/
|
|
12
13
|
export class InjectableTransformer {
|
|
13
14
|
|
|
15
|
+
static foreignTarget(state: TransformerState, ret: ForeignType): ts.Expression {
|
|
16
|
+
return state.fromLiteral({
|
|
17
|
+
Ⲑid: `${ret.source.split('node_modules')[1]}+${ret.name}`
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
/**
|
|
15
22
|
* Handle a specific declaration param/property
|
|
16
23
|
*/
|
|
@@ -25,14 +32,26 @@ export class InjectableTransformer {
|
|
|
25
32
|
const callExpr = existing?.expression as ts.CallExpression;
|
|
26
33
|
const args: ts.Expression[] = [...(callExpr?.arguments ?? [])];
|
|
27
34
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
const payload: { target?: unknown, qualifier?: unknown, optional?: boolean } = {};
|
|
36
|
+
|
|
37
|
+
if (!!param.questionToken) {
|
|
38
|
+
payload.optional = true;
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
const keyParam = ts.isSetAccessorDeclaration(param) ? param.parameters[0] : param;
|
|
34
|
-
const
|
|
35
|
-
|
|
42
|
+
const type = state.resolveType(keyParam);
|
|
43
|
+
|
|
44
|
+
if (type.key === 'managed') {
|
|
45
|
+
payload.target = state.getOrImport(type);
|
|
46
|
+
} else if (type.key === 'foreign') {
|
|
47
|
+
payload.target = this.foreignTarget(state, type);
|
|
48
|
+
} else {
|
|
49
|
+
const file = param.getSourceFile().fileName;
|
|
50
|
+
const src = state.getFileImportName(file);
|
|
51
|
+
throw new Error(`Unable to import non-external type: ${param.getText()} ${type.key}: ${src}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
args.unshift(state.fromLiteral(payload));
|
|
36
55
|
|
|
37
56
|
return args;
|
|
38
57
|
}
|
|
@@ -52,7 +71,7 @@ export class InjectableTransformer {
|
|
|
52
71
|
if (clause.token === ts.SyntaxKind.ImplementsKeyword) {
|
|
53
72
|
for (const typeExpression of clause.types) {
|
|
54
73
|
const resolvedType = state.resolveType(typeExpression);
|
|
55
|
-
if (resolvedType.key === '
|
|
74
|
+
if (resolvedType.key === 'managed') {
|
|
56
75
|
const resolved = state.getOrImport(resolvedType);
|
|
57
76
|
interfaces.push(resolved);
|
|
58
77
|
}
|
|
@@ -134,21 +153,22 @@ export class InjectableTransformer {
|
|
|
134
153
|
const dependencies = node.parameters.map(x => this.processDeclaration(state, x));
|
|
135
154
|
|
|
136
155
|
// Read target from config or resolve
|
|
137
|
-
|
|
156
|
+
const config: { dependencies: unknown[], target?: unknown, qualifier?: unknown, src?: unknown } = {
|
|
157
|
+
dependencies,
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
159
|
+
src: (node.parent as ts.ClassDeclaration).name,
|
|
160
|
+
};
|
|
138
161
|
const ret = state.resolveReturnType(node);
|
|
139
|
-
if (ret.key === '
|
|
140
|
-
target = state.getOrImport(ret);
|
|
162
|
+
if (ret.key === 'managed') {
|
|
163
|
+
config.target = state.getOrImport(ret);
|
|
164
|
+
} else if (ret.key === 'foreign') {
|
|
165
|
+
config.target = this.foreignTarget(state, ret);
|
|
141
166
|
}
|
|
142
167
|
|
|
143
168
|
// Build decl
|
|
144
169
|
const args = [...(dec && ts.isCallExpression(dec.expression) ? dec.expression.arguments : [undefined])];
|
|
145
170
|
|
|
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
|
-
}));
|
|
171
|
+
args.unshift(state.extendObjectLiteral(config));
|
|
152
172
|
|
|
153
173
|
// Replace decorator
|
|
154
174
|
return state.factory.updateMethodDeclaration(
|