ditox 1.4.0 → 2.1.0
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 +7 -6
- package/dist/{index.d.ts → browser/index.d.ts} +133 -13
- package/dist/browser/index.js +2 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/cjs/ditox.d.ts +125 -0
- package/dist/cjs/ditox.js +210 -0
- package/dist/cjs/ditox.js.map +1 -0
- package/dist/cjs/index.d.ts +6 -0
- package/dist/cjs/index.js +28 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/modules.d.ts +124 -0
- package/dist/cjs/modules.js +110 -0
- package/dist/cjs/modules.js.map +1 -0
- package/dist/cjs/utils-deprecated.d.ts +59 -0
- package/dist/cjs/utils-deprecated.js +66 -0
- package/dist/cjs/utils-deprecated.js.map +1 -0
- package/dist/cjs/utils.d.ts +136 -0
- package/dist/cjs/utils.js +156 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/ditox.d.ts +125 -0
- package/{lib/index.js → dist/esm/ditox.js} +10 -201
- package/dist/esm/ditox.js.map +1 -0
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/modules.d.ts +124 -0
- package/dist/esm/modules.js +103 -0
- package/dist/esm/modules.js.map +1 -0
- package/dist/esm/utils-deprecated.d.ts +59 -0
- package/dist/esm/utils-deprecated.js +59 -0
- package/dist/esm/utils-deprecated.js.map +1 -0
- package/dist/esm/utils.d.ts +136 -0
- package/dist/esm/utils.js +145 -0
- package/dist/esm/utils.js.map +1 -0
- package/{lib → dist/umd}/index.d.ts +133 -13
- package/dist/umd/index.js +2 -0
- package/dist/umd/index.js.map +1 -0
- package/docs/.nojekyll +1 -0
- package/docs/README.md +364 -98
- package/docs/classes/{resolvererror.md → ResolverError.md} +14 -12
- package/package.json +16 -17
- package/src/ditox.test.ts +10 -1
- package/src/index.ts +18 -11
- package/src/modules.test.ts +32 -0
- package/src/modules.ts +4 -4
- package/src/utils-deprecated.test.ts +286 -0
- package/src/utils-deprecated.ts +87 -0
- package/src/utils.test.ts +173 -58
- package/src/utils.ts +164 -66
- package/CHANGELOG.md +0 -110
- package/dist/index.browser.js +0 -2
- package/dist/index.browser.js.flow +0 -4
- package/dist/index.browser.js.map +0 -1
- package/dist/index.js +0 -411
- package/dist/index.js.flow +0 -4
- package/dist/index.js.map +0 -1
- package/dist/index.module.d.ts +0 -301
- package/dist/index.module.js +0 -393
- package/dist/index.module.js.flow +0 -4
- package/dist/index.module.js.map +0 -1
- package/dist/index.umd.d.ts +0 -301
- package/dist/index.umd.js +0 -2
- package/dist/index.umd.js.flow +0 -4
- package/dist/index.umd.js.map +0 -1
- package/lib/index.js.flow +0 -4
- package/lib/index.js.map +0 -1
- package/mod.ts +0 -2
- package/src/ditox.js.flow +0 -131
- package/src/index.js.flow +0 -34
- package/src/modules.js.flow +0 -156
- package/src/utils.js.flow +0 -113
package/src/utils.test.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {createContainer, optional, ResolverError, token} from './ditox';
|
|
2
2
|
import {
|
|
3
3
|
bindMultiValue,
|
|
4
|
-
getProps,
|
|
5
|
-
getValues,
|
|
6
4
|
injectable,
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
injectableClass,
|
|
6
|
+
resolveValue,
|
|
9
7
|
resolveValues,
|
|
8
|
+
tryResolveValue,
|
|
9
|
+
tryResolveValues,
|
|
10
10
|
} from './utils';
|
|
11
11
|
|
|
12
12
|
const NUMBER = token<number>('number');
|
|
13
13
|
const STRING = token<string>('string');
|
|
14
14
|
|
|
15
|
-
describe('bindMultiValue', () => {
|
|
15
|
+
describe('bindMultiValue()', () => {
|
|
16
16
|
const NUMBERS = token<Array<number>>('numbers');
|
|
17
17
|
|
|
18
18
|
it('should append a value to an array declared by a token', () => {
|
|
@@ -53,13 +53,53 @@ describe('bindMultiValue', () => {
|
|
|
53
53
|
});
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
describe('
|
|
56
|
+
describe('tryResolveValue()', () => {
|
|
57
|
+
it('should return an object with values by the tokens', () => {
|
|
58
|
+
const container = createContainer();
|
|
59
|
+
container.bindValue(NUMBER, 1);
|
|
60
|
+
container.bindValue(STRING, 'abc');
|
|
61
|
+
|
|
62
|
+
const props: {a: number; b: string} = tryResolveValue(container, {
|
|
63
|
+
a: NUMBER,
|
|
64
|
+
b: STRING,
|
|
65
|
+
});
|
|
66
|
+
expect(props).toEqual({a: 1, b: 'abc'});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should return "undefined" item in case a value is not provided', () => {
|
|
70
|
+
const container = createContainer();
|
|
71
|
+
container.bindValue(NUMBER, 1);
|
|
72
|
+
|
|
73
|
+
const props = tryResolveValue(container, {a: NUMBER, b: STRING});
|
|
74
|
+
expect(props).toEqual({a: 1, b: undefined});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should return values of optional tokens in case they are not provided', () => {
|
|
78
|
+
const container = createContainer();
|
|
79
|
+
container.bindValue(NUMBER, 1);
|
|
80
|
+
|
|
81
|
+
const OPTIONAL_STRING = optional(STRING, 'value');
|
|
82
|
+
|
|
83
|
+
const props = tryResolveValue(container, {
|
|
84
|
+
a: NUMBER,
|
|
85
|
+
b: STRING,
|
|
86
|
+
c: OPTIONAL_STRING,
|
|
87
|
+
});
|
|
88
|
+
expect(props).toEqual({a: 1, b: undefined, c: 'value'});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('tryResolveValues()', () => {
|
|
57
93
|
it('should return values for the tokens', () => {
|
|
58
94
|
const container = createContainer();
|
|
59
95
|
container.bindValue(NUMBER, 1);
|
|
60
96
|
container.bindValue(STRING, 'abc');
|
|
61
97
|
|
|
62
|
-
const values: [number, string] =
|
|
98
|
+
const values: [number, string] = tryResolveValues(
|
|
99
|
+
container,
|
|
100
|
+
NUMBER,
|
|
101
|
+
STRING,
|
|
102
|
+
);
|
|
63
103
|
expect(values).toEqual([1, 'abc']);
|
|
64
104
|
});
|
|
65
105
|
|
|
@@ -67,7 +107,7 @@ describe('getValues', () => {
|
|
|
67
107
|
const container = createContainer();
|
|
68
108
|
container.bindValue(NUMBER, 1);
|
|
69
109
|
|
|
70
|
-
const values =
|
|
110
|
+
const values = tryResolveValues(container, NUMBER, STRING);
|
|
71
111
|
expect(values).toEqual([1, undefined]);
|
|
72
112
|
});
|
|
73
113
|
|
|
@@ -77,7 +117,7 @@ describe('getValues', () => {
|
|
|
77
117
|
|
|
78
118
|
const OPTIONAL_STRING = optional(STRING, 'value');
|
|
79
119
|
|
|
80
|
-
const values =
|
|
120
|
+
const values = tryResolveValues(container, NUMBER, STRING, OPTIONAL_STRING);
|
|
81
121
|
expect(values).toEqual([1, undefined, 'value']);
|
|
82
122
|
});
|
|
83
123
|
|
|
@@ -85,7 +125,7 @@ describe('getValues', () => {
|
|
|
85
125
|
const container = createContainer();
|
|
86
126
|
container.bindValue(NUMBER, 1);
|
|
87
127
|
|
|
88
|
-
const values =
|
|
128
|
+
const values = tryResolveValues(
|
|
89
129
|
container,
|
|
90
130
|
NUMBER,
|
|
91
131
|
NUMBER,
|
|
@@ -102,7 +142,43 @@ describe('getValues', () => {
|
|
|
102
142
|
});
|
|
103
143
|
});
|
|
104
144
|
|
|
105
|
-
describe('
|
|
145
|
+
describe('resolveValue()', () => {
|
|
146
|
+
it('should an object with resolved values from the container for the specified token props', () => {
|
|
147
|
+
const container = createContainer();
|
|
148
|
+
container.bindValue(NUMBER, 1);
|
|
149
|
+
container.bindValue(STRING, 'abc');
|
|
150
|
+
|
|
151
|
+
const props: {a: number; b: string} = resolveValue(container, {
|
|
152
|
+
a: NUMBER,
|
|
153
|
+
b: STRING,
|
|
154
|
+
});
|
|
155
|
+
expect(props).toEqual({a: 1, b: 'abc'});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should throw an error in case a value is not provided', () => {
|
|
159
|
+
const container = createContainer();
|
|
160
|
+
container.bindValue(NUMBER, 1);
|
|
161
|
+
|
|
162
|
+
expect(() => {
|
|
163
|
+
resolveValue(container, {a: NUMBER, b: STRING});
|
|
164
|
+
}).toThrowError(
|
|
165
|
+
new ResolverError(`Token "${STRING.symbol.description}" is not provided`),
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should resolve values of optional tokens in case they are not provided', () => {
|
|
170
|
+
const container = createContainer();
|
|
171
|
+
container.bindValue(NUMBER, 1);
|
|
172
|
+
|
|
173
|
+
const props = resolveValue(container, {
|
|
174
|
+
a: NUMBER,
|
|
175
|
+
b: optional(STRING, 'value'),
|
|
176
|
+
});
|
|
177
|
+
expect(props).toEqual({a: 1, b: 'value'});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('resolveValues()', () => {
|
|
106
182
|
it('should resolve tokens from the container', () => {
|
|
107
183
|
const container = createContainer();
|
|
108
184
|
container.bindValue(NUMBER, 1);
|
|
@@ -127,12 +203,30 @@ describe('resolveValues', () => {
|
|
|
127
203
|
const container = createContainer();
|
|
128
204
|
container.bindValue(NUMBER, 1);
|
|
129
205
|
|
|
130
|
-
const values =
|
|
206
|
+
const values = resolveValues(container, NUMBER, optional(STRING, 'value'));
|
|
131
207
|
expect(values).toEqual([1, 'value']);
|
|
132
208
|
});
|
|
209
|
+
|
|
210
|
+
it('should resolve a dictionary of tokens', () => {
|
|
211
|
+
const container = createContainer();
|
|
212
|
+
container.bindValue(NUMBER, 1);
|
|
213
|
+
|
|
214
|
+
const values = resolveValue(container, {
|
|
215
|
+
a: NUMBER,
|
|
216
|
+
b: optional(STRING, 'value'),
|
|
217
|
+
});
|
|
218
|
+
expect(values).toEqual({
|
|
219
|
+
a: 1,
|
|
220
|
+
b: 'value',
|
|
221
|
+
});
|
|
222
|
+
});
|
|
133
223
|
});
|
|
134
224
|
|
|
135
225
|
describe('injectable()', () => {
|
|
226
|
+
function join({a, b}: {a: number; b: string}): string {
|
|
227
|
+
return `${a}/${b}`;
|
|
228
|
+
}
|
|
229
|
+
|
|
136
230
|
it('should inject values from Container as arguments of the factory', () => {
|
|
137
231
|
const container = createContainer();
|
|
138
232
|
container.bindValue(NUMBER, 1);
|
|
@@ -174,83 +268,104 @@ describe('injectable()', () => {
|
|
|
174
268
|
|
|
175
269
|
expect(decoratedFactory(container)).toBe('1value');
|
|
176
270
|
});
|
|
177
|
-
});
|
|
178
271
|
|
|
179
|
-
|
|
180
|
-
it('should return an object with values by the tokens', () => {
|
|
272
|
+
it('should inject values from Container as an object for the first argument of the factory', () => {
|
|
181
273
|
const container = createContainer();
|
|
182
274
|
container.bindValue(NUMBER, 1);
|
|
183
|
-
container.bindValue(STRING, '
|
|
275
|
+
container.bindValue(STRING, '2');
|
|
184
276
|
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
});
|
|
189
|
-
expect(props).toEqual({a: 1, b: 'abc'});
|
|
277
|
+
const decoratedFactory = injectable(join, {a: NUMBER, b: STRING});
|
|
278
|
+
|
|
279
|
+
expect(decoratedFactory(container)).toBe('1/2');
|
|
190
280
|
});
|
|
191
281
|
|
|
192
|
-
it('should
|
|
282
|
+
it('should throw ResolverError error in case a value is not provided', () => {
|
|
193
283
|
const container = createContainer();
|
|
194
284
|
container.bindValue(NUMBER, 1);
|
|
195
285
|
|
|
196
|
-
const
|
|
197
|
-
|
|
286
|
+
const decoratedFactory = injectable(join, {a: NUMBER, b: STRING});
|
|
287
|
+
|
|
288
|
+
expect(() => decoratedFactory(container)).toThrowError(
|
|
289
|
+
new ResolverError(`Token "${STRING.symbol.description}" is not provided`),
|
|
290
|
+
);
|
|
198
291
|
});
|
|
199
292
|
|
|
200
|
-
it('should
|
|
293
|
+
it('should inject values of optional tokens in case values are not provided', () => {
|
|
201
294
|
const container = createContainer();
|
|
202
295
|
container.bindValue(NUMBER, 1);
|
|
203
296
|
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
const props = getProps(container, {
|
|
297
|
+
const decoratedFactory = injectable(join, {
|
|
207
298
|
a: NUMBER,
|
|
208
|
-
b: STRING,
|
|
209
|
-
c: OPTIONAL_STRING,
|
|
299
|
+
b: optional(STRING, 'value'),
|
|
210
300
|
});
|
|
211
|
-
|
|
301
|
+
|
|
302
|
+
expect(decoratedFactory(container)).toBe('1/value');
|
|
212
303
|
});
|
|
213
304
|
});
|
|
214
305
|
|
|
215
|
-
describe('
|
|
216
|
-
|
|
306
|
+
describe('injectableClass()', () => {
|
|
307
|
+
class TestClass {
|
|
308
|
+
a: number;
|
|
309
|
+
b: string;
|
|
310
|
+
|
|
311
|
+
constructor(a: number, b: string) {
|
|
312
|
+
this.a = a;
|
|
313
|
+
this.b = b;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
concat(): string {
|
|
317
|
+
return this.a + this.b;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
it('should inject values from Container as arguments of the constructor', () => {
|
|
217
322
|
const container = createContainer();
|
|
218
323
|
container.bindValue(NUMBER, 1);
|
|
219
|
-
container.bindValue(STRING, '
|
|
324
|
+
container.bindValue(STRING, '2');
|
|
220
325
|
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
});
|
|
225
|
-
expect(props).toEqual({a: 1, b: 'abc'});
|
|
326
|
+
const factory = injectableClass(TestClass, NUMBER, STRING);
|
|
327
|
+
|
|
328
|
+
expect(factory(container).concat()).toBe('12');
|
|
226
329
|
});
|
|
227
330
|
|
|
228
|
-
it('should throw
|
|
331
|
+
it('should throw ResolverError error in case a value is not provided', () => {
|
|
229
332
|
const container = createContainer();
|
|
230
333
|
container.bindValue(NUMBER, 1);
|
|
231
334
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
335
|
+
const factory = injectableClass(TestClass, NUMBER, STRING);
|
|
336
|
+
|
|
337
|
+
expect(() => factory(container)).toThrowError(
|
|
235
338
|
new ResolverError(`Token "${STRING.symbol.description}" is not provided`),
|
|
236
339
|
);
|
|
237
340
|
});
|
|
238
341
|
|
|
239
|
-
it('should
|
|
342
|
+
it('should inject values of optional tokens in case values are not provided', () => {
|
|
240
343
|
const container = createContainer();
|
|
241
344
|
container.bindValue(NUMBER, 1);
|
|
242
345
|
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
346
|
+
const factory = injectableClass(
|
|
347
|
+
TestClass,
|
|
348
|
+
NUMBER,
|
|
349
|
+
optional(STRING, 'value'),
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
expect(factory(container).concat()).toBe('1value');
|
|
248
353
|
});
|
|
249
354
|
});
|
|
250
355
|
|
|
251
|
-
describe('
|
|
252
|
-
|
|
253
|
-
|
|
356
|
+
describe('injectableClass()', () => {
|
|
357
|
+
class TestClass {
|
|
358
|
+
a: number;
|
|
359
|
+
b: string;
|
|
360
|
+
|
|
361
|
+
constructor(props: {a: number; b: string}) {
|
|
362
|
+
this.a = props.a;
|
|
363
|
+
this.b = props.b;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
join(): string {
|
|
367
|
+
return `${this.a}/${this.b}`;
|
|
368
|
+
}
|
|
254
369
|
}
|
|
255
370
|
|
|
256
371
|
it('should inject values from Container as an object for the first argument of the factory', () => {
|
|
@@ -258,18 +373,18 @@ describe('injectableProps()', () => {
|
|
|
258
373
|
container.bindValue(NUMBER, 1);
|
|
259
374
|
container.bindValue(STRING, '2');
|
|
260
375
|
|
|
261
|
-
const
|
|
376
|
+
const factory = injectableClass(TestClass, {a: NUMBER, b: STRING});
|
|
262
377
|
|
|
263
|
-
expect(
|
|
378
|
+
expect(factory(container).join()).toBe('1/2');
|
|
264
379
|
});
|
|
265
380
|
|
|
266
381
|
it('should throw ResolverError error in case a value is not provided', () => {
|
|
267
382
|
const container = createContainer();
|
|
268
383
|
container.bindValue(NUMBER, 1);
|
|
269
384
|
|
|
270
|
-
const
|
|
385
|
+
const factory = injectableClass(TestClass, {a: NUMBER, b: STRING});
|
|
271
386
|
|
|
272
|
-
expect(() =>
|
|
387
|
+
expect(() => factory(container)).toThrowError(
|
|
273
388
|
new ResolverError(`Token "${STRING.symbol.description}" is not provided`),
|
|
274
389
|
);
|
|
275
390
|
});
|
|
@@ -278,11 +393,11 @@ describe('injectableProps()', () => {
|
|
|
278
393
|
const container = createContainer();
|
|
279
394
|
container.bindValue(NUMBER, 1);
|
|
280
395
|
|
|
281
|
-
const
|
|
396
|
+
const factory = injectableClass(TestClass, {
|
|
282
397
|
a: NUMBER,
|
|
283
398
|
b: optional(STRING, 'value'),
|
|
284
399
|
});
|
|
285
400
|
|
|
286
|
-
expect(
|
|
401
|
+
expect(factory(container).join()).toBe('1/value');
|
|
287
402
|
});
|
|
288
403
|
});
|
package/src/utils.ts
CHANGED
|
@@ -5,6 +5,19 @@ type TokenProps<Props extends ValuesProps> = {
|
|
|
5
5
|
[K in keyof Props]: Token<Props[K]>;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Checks if a value is the token
|
|
10
|
+
*/
|
|
11
|
+
export function isToken<T>(value: unknown): value is Token<T> {
|
|
12
|
+
return (
|
|
13
|
+
value !== undefined &&
|
|
14
|
+
value !== null &&
|
|
15
|
+
typeof value === 'object' &&
|
|
16
|
+
'symbol' in value &&
|
|
17
|
+
typeof (value as any).symbol === 'symbol'
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
8
21
|
/**
|
|
9
22
|
* Rebinds the array by the token with added new value.
|
|
10
23
|
* @param container - Dependency container.
|
|
@@ -13,7 +26,7 @@ type TokenProps<Props extends ValuesProps> = {
|
|
|
13
26
|
*/
|
|
14
27
|
export function bindMultiValue<T>(
|
|
15
28
|
container: Container,
|
|
16
|
-
token: Token<
|
|
29
|
+
token: Token<ReadonlyArray<T>>,
|
|
17
30
|
value: T,
|
|
18
31
|
): void {
|
|
19
32
|
const prevValues = container.get(token) ?? [];
|
|
@@ -22,41 +35,154 @@ export function bindMultiValue<T>(
|
|
|
22
35
|
}
|
|
23
36
|
|
|
24
37
|
/**
|
|
25
|
-
*
|
|
38
|
+
* Tries to resolve a value by the provided token.
|
|
39
|
+
*
|
|
40
|
+
* If an argument is an object which has tokens as its properties,
|
|
41
|
+
* then returns an object containing resolved values as properties.
|
|
42
|
+
|
|
26
43
|
* If a token is not found, then `undefined` value is used.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const value = tryResolveValue(container, tokenA);
|
|
48
|
+
* console.log(value); // 1
|
|
49
|
+
*
|
|
50
|
+
* const props = tryResolveValue(container, {a: tokenA, b: tokenB});
|
|
51
|
+
* console.log(props); // {a: 1, b: 2}
|
|
52
|
+
* ```
|
|
27
53
|
*/
|
|
28
|
-
export function
|
|
29
|
-
Tokens extends Token<unknown>[],
|
|
54
|
+
export function tryResolveValue<
|
|
55
|
+
Tokens extends Token<unknown> | {[key: string]: Token<unknown>},
|
|
56
|
+
Values extends Tokens extends Token<infer V>
|
|
57
|
+
? V | undefined
|
|
58
|
+
: Tokens extends TokenProps<infer Props>
|
|
59
|
+
? Partial<Props>
|
|
60
|
+
: never,
|
|
61
|
+
>(container: Container, token: Tokens): Values {
|
|
62
|
+
if (isToken(token)) {
|
|
63
|
+
return container.get(token) as Values;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const obj: any = {};
|
|
67
|
+
Object.keys(token).forEach((key) => (obj[key] = container.get(token[key])));
|
|
68
|
+
return obj;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Returns an array of resolved values or objects with resolved values.
|
|
73
|
+
*
|
|
74
|
+
* If an item of the array is an object which has tokens as its properties,
|
|
75
|
+
* then returns an object containing resolved values as properties.
|
|
76
|
+
|
|
77
|
+
* If a token is not found, then `undefined` value is used.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const items1 = tryResolveValues(container, tokenA);
|
|
82
|
+
* console.log(items1); // [1]
|
|
83
|
+
*
|
|
84
|
+
* const items2 = tryResolveValues(container, tokenA, {a: tokenA, b: tokenB});
|
|
85
|
+
* console.log(items2); // [1, {a: 1, b: 2}]
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function tryResolveValues<
|
|
89
|
+
Tokens extends (Token<unknown> | {[key: string]: Token<unknown>})[],
|
|
30
90
|
Values extends {
|
|
31
|
-
[K in keyof Tokens]: Tokens[K] extends Token<infer V>
|
|
91
|
+
[K in keyof Tokens]: Tokens[K] extends Token<infer V>
|
|
92
|
+
? V | undefined
|
|
93
|
+
: Tokens[K] extends TokenProps<infer Props>
|
|
94
|
+
? Partial<Props>
|
|
95
|
+
: never;
|
|
32
96
|
},
|
|
33
97
|
>(container: Container, ...tokens: Tokens): Values {
|
|
34
|
-
return tokens.map(container
|
|
98
|
+
return tokens.map((item) => tryResolveValue(container, item)) as Values;
|
|
35
99
|
}
|
|
36
100
|
|
|
37
101
|
/**
|
|
38
|
-
*
|
|
102
|
+
* Resolves a value by the provided token.
|
|
103
|
+
*
|
|
104
|
+
* If an argument is an object which has tokens as its properties,
|
|
105
|
+
* then returns an object containing resolved values as properties.
|
|
106
|
+
|
|
107
|
+
* If a value is not found by the token, then `ResolverError` is thrown.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const value = resolveValue(container, tokenA);
|
|
112
|
+
* console.log(value); // 1
|
|
113
|
+
*
|
|
114
|
+
* const props = resolveValue(container, {a: tokenA, b: tokenB});
|
|
115
|
+
* console.log(props); // {a: 1, b: 2}
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export function resolveValue<
|
|
119
|
+
Tokens extends Token<unknown> | {[key: string]: Token<unknown>},
|
|
120
|
+
Values extends Tokens extends Token<infer V>
|
|
121
|
+
? V
|
|
122
|
+
: Tokens extends TokenProps<infer Props>
|
|
123
|
+
? Props
|
|
124
|
+
: never,
|
|
125
|
+
>(container: Container, token: Tokens): Values {
|
|
126
|
+
if (isToken(token)) {
|
|
127
|
+
return container.resolve(token) as Values;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const obj: any = {};
|
|
131
|
+
Object.keys(token).forEach(
|
|
132
|
+
(key) => (obj[key] = container.resolve(token[key])),
|
|
133
|
+
);
|
|
134
|
+
return obj;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Returns an array of resolved values or objects with resolved values.
|
|
139
|
+
*
|
|
140
|
+
* If an item of the array is an object which has tokens as its properties,
|
|
141
|
+
* then returns an object containing resolved values as properties.
|
|
142
|
+
|
|
39
143
|
* If a token is not found, then `ResolverError` is thrown.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const items1 = resolveValues(container, tokenA);
|
|
148
|
+
* console.log(items1); // [1]
|
|
149
|
+
*
|
|
150
|
+
* const items2 = resolveValues(container, tokenA, {a: tokenA, b: tokenB});
|
|
151
|
+
* console.log(items2); // [1, {a: 1, b: 2}]
|
|
152
|
+
* ```
|
|
40
153
|
*/
|
|
41
154
|
export function resolveValues<
|
|
42
|
-
Tokens extends Token<unknown>[],
|
|
155
|
+
Tokens extends (Token<unknown> | {[key: string]: Token<unknown>})[],
|
|
43
156
|
Values extends {
|
|
44
|
-
[K in keyof Tokens]: Tokens[K] extends Token<infer V>
|
|
157
|
+
[K in keyof Tokens]: Tokens[K] extends Token<infer V>
|
|
158
|
+
? V
|
|
159
|
+
: Tokens[K] extends TokenProps<infer Props>
|
|
160
|
+
? Props
|
|
161
|
+
: never;
|
|
45
162
|
},
|
|
46
163
|
>(container: Container, ...tokens: Tokens): Values {
|
|
47
|
-
return tokens.map(container
|
|
164
|
+
return tokens.map((item) => resolveValue(container, item)) as Values;
|
|
48
165
|
}
|
|
49
166
|
|
|
50
167
|
/**
|
|
51
|
-
* Decorates a factory by passing resolved
|
|
168
|
+
* Decorates a factory by passing resolved values as factory arguments.
|
|
169
|
+
*
|
|
170
|
+
* If an argument is an object which has tokens as its properties,
|
|
171
|
+
* then returns an object containing resolved values as properties.
|
|
172
|
+
*
|
|
52
173
|
* @param factory - A factory.
|
|
53
174
|
* @param tokens - Tokens which correspond to factory arguments.
|
|
175
|
+
*
|
|
54
176
|
* @return Decorated factory which takes a dependency container as a single argument.
|
|
55
177
|
*/
|
|
56
178
|
export function injectable<
|
|
57
|
-
Tokens extends Token<unknown>[],
|
|
179
|
+
Tokens extends (Token<unknown> | {[key: string]: Token<unknown>})[],
|
|
58
180
|
Values extends {
|
|
59
|
-
[K in keyof Tokens]: Tokens[K] extends Token<infer V>
|
|
181
|
+
[K in keyof Tokens]: Tokens[K] extends Token<infer V>
|
|
182
|
+
? V
|
|
183
|
+
: Tokens[K] extends TokenProps<infer Props>
|
|
184
|
+
? Props
|
|
185
|
+
: never;
|
|
60
186
|
},
|
|
61
187
|
Result,
|
|
62
188
|
>(
|
|
@@ -71,62 +197,34 @@ export function injectable<
|
|
|
71
197
|
}
|
|
72
198
|
|
|
73
199
|
/**
|
|
74
|
-
*
|
|
75
|
-
* If a token is not found, then `undefined` value is used.
|
|
200
|
+
* Decorates a class by passing resolved values as arguments to its constructor.
|
|
76
201
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* const props = getProps(container, {a: tokenA, b: tokenB});
|
|
80
|
-
* console.log(props); // {a: 1, b: 2}
|
|
81
|
-
* ```
|
|
82
|
-
*/
|
|
83
|
-
export function getProps<Props extends ValuesProps>(
|
|
84
|
-
container: Container,
|
|
85
|
-
tokens: TokenProps<Props>,
|
|
86
|
-
): Partial<Props> {
|
|
87
|
-
const obj: any = {...tokens};
|
|
88
|
-
Object.keys(obj).forEach((key) => (obj[key] = container.get(obj[key])));
|
|
89
|
-
return obj;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Returns an object with resolved properties which are specified by token properties.
|
|
94
|
-
* If a token is not found, then `ResolverError` is thrown.
|
|
202
|
+
* If an argument is an object which has tokens as its properties,
|
|
203
|
+
* then returns an object containing resolved values as properties.
|
|
95
204
|
*
|
|
96
|
-
* @
|
|
97
|
-
*
|
|
98
|
-
* const props = resolveProps(container, {a: tokenA, b: tokenB});
|
|
99
|
-
* console.log(props); // {a: 1, b: 2}
|
|
100
|
-
* ```
|
|
101
|
-
*/
|
|
102
|
-
export function resolveProps<Props extends ValuesProps>(
|
|
103
|
-
container: Container,
|
|
104
|
-
tokens: TokenProps<Props>,
|
|
105
|
-
): Props {
|
|
106
|
-
const obj: any = {...tokens};
|
|
107
|
-
Object.keys(obj).forEach((key) => (obj[key] = container.resolve(obj[key])));
|
|
108
|
-
return obj;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Decorates a factory by passing a resolved object with tokens as the first argument.
|
|
113
|
-
* @param factory - A factory.
|
|
114
|
-
* @param tokens - Object with tokens.
|
|
115
|
-
* @return Decorated factory which takes a dependency container as a single argument.
|
|
205
|
+
* @param constructor - Constructor of a class
|
|
206
|
+
* @param tokens - Tokens which correspond to constructor arguments
|
|
116
207
|
*
|
|
117
|
-
* @
|
|
118
|
-
*
|
|
119
|
-
* const factory = ({a, b}: {a: number, b: number}) => a + b;
|
|
120
|
-
* const decoratedFactory = injectableProps(factory, {a: tokenA, b: tokenB});
|
|
121
|
-
* const result = decoratedFactory(container);
|
|
122
|
-
* ```
|
|
208
|
+
* @return A factory function which takes a dependency container as a single argument
|
|
209
|
+
* and returns a new created class.
|
|
123
210
|
*/
|
|
124
|
-
export function
|
|
125
|
-
|
|
126
|
-
|
|
211
|
+
export function injectableClass<
|
|
212
|
+
Tokens extends (Token<unknown> | {[key: string]: Token<unknown>})[],
|
|
213
|
+
Values extends {
|
|
214
|
+
[K in keyof Tokens]: Tokens[K] extends Token<infer V>
|
|
215
|
+
? V
|
|
216
|
+
: Tokens[K] extends TokenProps<infer Props>
|
|
217
|
+
? Props
|
|
218
|
+
: never;
|
|
219
|
+
},
|
|
220
|
+
Result,
|
|
221
|
+
>(
|
|
222
|
+
this: unknown,
|
|
223
|
+
constructor: new (...params: Values) => Result,
|
|
224
|
+
...tokens: Tokens
|
|
127
225
|
): (container: Container) => Result {
|
|
128
|
-
return
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
226
|
+
return injectable<Tokens, Values, Result>(
|
|
227
|
+
(...values) => new constructor(...values),
|
|
228
|
+
...tokens,
|
|
229
|
+
);
|
|
132
230
|
}
|