@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 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",
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.3"
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
- let optional: ts.Expression | undefined = undefined;
29
- if (optional === undefined && !!param.questionToken) {
30
- optional = state.fromLiteral(true);
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 target = state.getOrImport(state.resolveExternalType(keyParam));
35
- args.unshift(state.fromLiteral({ target, optional }));
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 === 'external') {
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
- let target;
138
- const ret = state.resolveReturnType(node);
139
- if (ret.key === 'external') {
140
- target = state.getOrImport(ret);
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(