ts-ioc-container 23.2.11 → 23.3.1
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 +267 -160
- package/cjs/container/Container.d.ts +1 -1
- package/cjs/index.d.ts +5 -3
- package/cjs/index.js +12 -36
- package/cjs/index.js.map +1 -1
- package/cjs/{IInjector.d.ts → injector/IInjector.d.ts} +2 -2
- package/{esm → cjs/injector}/IInjector.js.map +1 -1
- package/cjs/injector/ProxyInjector.d.ts +6 -0
- package/cjs/injector/ProxyInjector.js +42 -0
- package/cjs/injector/ProxyInjector.js.map +1 -0
- package/cjs/injector/ReflectionInjector.d.ts +10 -0
- package/cjs/injector/ReflectionInjector.js +68 -0
- package/cjs/injector/ReflectionInjector.js.map +1 -0
- package/cjs/injector/SimpleInjector.d.ts +6 -0
- package/cjs/injector/SimpleInjector.js +42 -0
- package/cjs/injector/SimpleInjector.js.map +1 -0
- package/cjs/provider/ArgsProvider.d.ts +2 -2
- package/cjs/provider/ArgsProvider.js.map +1 -1
- package/cjs/reflection.d.ts +2 -0
- package/cjs/reflection.js +38 -1
- package/cjs/reflection.js.map +1 -1
- package/cjs/utils.d.ts +2 -0
- package/cjs/utils.js +37 -1
- package/cjs/utils.js.map +1 -1
- package/esm/container/Container.d.ts +1 -1
- package/esm/index.d.ts +5 -3
- package/esm/index.js +4 -1
- package/esm/index.js.map +1 -1
- package/esm/{IInjector.d.ts → injector/IInjector.d.ts} +2 -2
- package/{cjs → esm/injector}/IInjector.js.map +1 -1
- package/esm/injector/ProxyInjector.d.ts +6 -0
- package/esm/injector/ProxyInjector.js +20 -0
- package/esm/injector/ProxyInjector.js.map +1 -0
- package/esm/injector/ReflectionInjector.d.ts +10 -0
- package/esm/injector/ReflectionInjector.js +19 -0
- package/esm/injector/ReflectionInjector.js.map +1 -0
- package/esm/injector/SimpleInjector.d.ts +6 -0
- package/esm/injector/SimpleInjector.js +6 -0
- package/esm/injector/SimpleInjector.js.map +1 -0
- package/esm/provider/ArgsProvider.d.ts +2 -2
- package/esm/provider/ArgsProvider.js.map +1 -1
- package/esm/reflection.d.ts +2 -0
- package/esm/reflection.js +8 -0
- package/esm/reflection.js.map +1 -1
- package/esm/utils.d.ts +2 -0
- package/esm/utils.js +14 -0
- package/esm/utils.js.map +1 -1
- package/package.json +2 -3
- /package/cjs/{IInjector.js → injector/IInjector.js} +0 -0
- /package/esm/{IInjector.js → injector/IInjector.js} +0 -0
package/README.md
CHANGED
|
@@ -19,13 +19,20 @@
|
|
|
19
19
|
|
|
20
20
|
## Install
|
|
21
21
|
```shell script
|
|
22
|
-
npm install ts-ioc-container
|
|
22
|
+
npm install ts-ioc-container reflect-metadata
|
|
23
23
|
```
|
|
24
24
|
```shell script
|
|
25
|
-
yarn add ts-ioc-container
|
|
25
|
+
yarn add ts-ioc-container reflect-metadata
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Setup
|
|
29
|
+
### reflect-metadata
|
|
30
|
+
Add it in main file of your project. It should be first line of code.
|
|
31
|
+
```typescript
|
|
32
|
+
import 'reflect-metadata';
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### tsconfig.json
|
|
29
36
|
```json
|
|
30
37
|
{
|
|
31
38
|
"compilerOptions": {
|
|
@@ -35,21 +42,103 @@ yarn add ts-ioc-container ts-constructor-injector reflect-metadata
|
|
|
35
42
|
}
|
|
36
43
|
```
|
|
37
44
|
|
|
45
|
+
## Container
|
|
46
|
+
Container consists of:
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
- Injector - injects dependencies to constructor
|
|
49
|
+
- Providers - templates that create instances of dependencies
|
|
41
50
|
|
|
42
|
-
###
|
|
51
|
+
### Basic usage
|
|
43
52
|
|
|
44
53
|
```typescript
|
|
45
|
-
import
|
|
46
|
-
import {
|
|
54
|
+
import 'reflect-metadata';
|
|
55
|
+
import { Container } from "ts-ioc-container";
|
|
56
|
+
|
|
57
|
+
class Logger {
|
|
58
|
+
public name = 'Logger';
|
|
59
|
+
}
|
|
47
60
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
class App {
|
|
62
|
+
constructor(@inject(by('ILogger')) public logger: ILogger) {
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const container = new Container(new ReflectionInjector()).register('ILogger', Provider.fromClass(Logger));
|
|
67
|
+
container.resolve(App).resolve.logger.name === 'Logger'; // true
|
|
68
|
+
|
|
69
|
+
container.dispose();
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Scopes
|
|
73
|
+
- scope - is a container that can be created from another container. It's a sub-container.
|
|
74
|
+
- NOTICE: when you create a scope of container then all providers are cloned to new scope. Every provider has method `clone` that clones itself.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { Container, ReflectionInjector } from "ts-ioc-container";
|
|
78
|
+
|
|
79
|
+
const container = new Container(new ReflectionInjector());
|
|
80
|
+
const scope = container.createScope();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Tags
|
|
84
|
+
|
|
85
|
+
- tag - is a string that can be used mark each container and scope
|
|
86
|
+
- every provider can be registered per certain tags and cannot be resolved from container with other tags. Only from parent one with certain tags.
|
|
87
|
+
- NOTICE: when you create a scope of container with tags which not includes in provider tags then this provider will not be cloned to new scope.
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { Container, perTags, ReflectionInjector } from "ts-ioc-container";
|
|
91
|
+
|
|
92
|
+
const container = new Container(new ReflectionInjector(), { tags: ['root'] }).register('ILogger', Provider.fromClass(Logger).pipe(perTags('root')));
|
|
93
|
+
const scope = container.createScope(['child']);
|
|
94
|
+
|
|
95
|
+
scope.resolve('ILogger'); // it will be resolved from container, not from scope
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Instances
|
|
99
|
+
- you can get instances from container and scope which were created by injector
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { Container, ReflectionInjector } from "ts-ioc-container";
|
|
103
|
+
|
|
104
|
+
const container = new Container(new ReflectionInjector()).register('ILogger', Provider.fromClass(Logger));
|
|
105
|
+
const scope = container.createScope();
|
|
106
|
+
|
|
107
|
+
const logger1 = container.resolve('ILogger');
|
|
108
|
+
const logger2 = scope.resolve('ILogger');
|
|
109
|
+
|
|
110
|
+
expect(scope.getInstances().length).toBe(1);
|
|
111
|
+
expect(container.getInstances().length).toBe(2);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Disposing
|
|
115
|
+
- container can be disposed
|
|
116
|
+
- when container is disposed then all scopes are disposed too
|
|
117
|
+
- when container is disposed then it unregisters all providers and remove all instances
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { asSingleton, Container, perTags, ReflectionInjector, ContainerDisposedError } from "ts-ioc-container";
|
|
121
|
+
|
|
122
|
+
const container = new Container(new ReflectionInjector(), { tags: ['root'] }).register('ILogger', Provider.fromClass(Logger));
|
|
123
|
+
const scope = container.createScope(['child']);
|
|
124
|
+
|
|
125
|
+
const logger = scope.resolve('ILogger');
|
|
126
|
+
container.dispose();
|
|
127
|
+
|
|
128
|
+
expect(() => scope.resolve('ILogger')).toThrow(ContainerDisposedError);
|
|
129
|
+
expect(() => container.resolve('ILogger')).toThrow(ContainerDisposedError);
|
|
130
|
+
expect(container.getInstances().length).toBe(0);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Injectors
|
|
134
|
+
- `ReflectionInjector` - injects dependencies using `@inject` decorator
|
|
135
|
+
- `ProxyInjector` - injects dependencies as dictionary `Record<string, unknown>`
|
|
136
|
+
- `SimpleInjector` - just passes container to constructor with others arguments
|
|
137
|
+
|
|
138
|
+
### Reflection injector
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { Container, IContainer, IInjector, Provider, by, inject, resolve } from "ts-ioc-container";
|
|
53
142
|
|
|
54
143
|
class Logger implements ILogger {
|
|
55
144
|
info(message: string) {
|
|
@@ -58,15 +147,19 @@ class Logger implements ILogger {
|
|
|
58
147
|
}
|
|
59
148
|
|
|
60
149
|
class App {
|
|
61
|
-
constructor(@inject(
|
|
150
|
+
constructor(@inject((container, ...args) => container.resolve('ILogger', ...args)) private logger: ILogger) {
|
|
62
151
|
}
|
|
63
152
|
|
|
153
|
+
// OR
|
|
154
|
+
// constructor(@inject(by('ILogger')) private logger: ILogger) {
|
|
155
|
+
// }
|
|
156
|
+
|
|
64
157
|
run() {
|
|
65
158
|
this.logger.info('Hello world');
|
|
66
159
|
}
|
|
67
160
|
}
|
|
68
161
|
|
|
69
|
-
const container = new Container(
|
|
162
|
+
const container = new Container(new ReflectionInjector())
|
|
70
163
|
.register('ILogger', Provider.fromClass(Logger));
|
|
71
164
|
|
|
72
165
|
const app = container.resolve(App);
|
|
@@ -76,13 +169,7 @@ app.run();
|
|
|
76
169
|
### Simple injector
|
|
77
170
|
|
|
78
171
|
```typescript
|
|
79
|
-
import { IContainer } from "ts-
|
|
80
|
-
|
|
81
|
-
const injector: IInjector = {
|
|
82
|
-
resolve<T>(container: IContainer, Target: constructor<T>, ...deps: unknown[]): T {
|
|
83
|
-
return new Target(container, ...deps);
|
|
84
|
-
},
|
|
85
|
-
};
|
|
172
|
+
import { SimpleInjector, IContainer } from "ts-ioc-container";
|
|
86
173
|
|
|
87
174
|
class Logger implements ILogger {
|
|
88
175
|
info(message: string) {
|
|
@@ -96,13 +183,13 @@ class App {
|
|
|
96
183
|
constructor(private container: IContainer) {
|
|
97
184
|
this.logger = container.resolve('ILogger');
|
|
98
185
|
}
|
|
99
|
-
|
|
186
|
+
|
|
100
187
|
run() {
|
|
101
188
|
this.logger.info('Hello world');
|
|
102
189
|
}
|
|
103
190
|
}
|
|
104
191
|
|
|
105
|
-
const container = new Container(
|
|
192
|
+
const container = new Container(new SimpleInjector())
|
|
106
193
|
.register('ILogger', Provider.fromClass(Logger));
|
|
107
194
|
|
|
108
195
|
const app = container.resolve(App);
|
|
@@ -112,24 +199,7 @@ app.run();
|
|
|
112
199
|
### Proxy injector
|
|
113
200
|
|
|
114
201
|
```typescript
|
|
115
|
-
import { IContainer } from "ts-
|
|
116
|
-
|
|
117
|
-
const injector: IInjector = {
|
|
118
|
-
resolve<T>(container: IContainer, Target: constructor<T>, ...deps: unknown[]): T {
|
|
119
|
-
const args = deps.reduce((acc, it) => ({ ...acc, ...it }), {});
|
|
120
|
-
const proxy = new Proxy(
|
|
121
|
-
{},
|
|
122
|
-
{
|
|
123
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
124
|
-
get(target: {}, prop: string | symbol): any {
|
|
125
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
126
|
-
return args.hasOwnProperty(prop) ? args[prop] : container.resolve(prop);
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
);
|
|
130
|
-
return new Target(proxy);
|
|
131
|
-
},
|
|
132
|
-
};
|
|
202
|
+
import { ProxyInjector, IContainer } from "ts-ioc-container";
|
|
133
203
|
|
|
134
204
|
class Logger implements ILogger {
|
|
135
205
|
info(message: string) {
|
|
@@ -140,182 +210,142 @@ class Logger implements ILogger {
|
|
|
140
210
|
class App {
|
|
141
211
|
private logger: ILogger;
|
|
142
212
|
|
|
143
|
-
constructor({logger}: {logger: ILogger}) {
|
|
213
|
+
constructor({ logger }: { logger: ILogger }) {
|
|
144
214
|
this.logger = logger;
|
|
145
215
|
}
|
|
146
|
-
|
|
216
|
+
|
|
147
217
|
run() {
|
|
148
218
|
this.logger.info('Hello world');
|
|
149
219
|
}
|
|
150
220
|
}
|
|
151
221
|
|
|
152
|
-
const container = new Container(
|
|
222
|
+
const container = new Container(new ProxyInjector())
|
|
153
223
|
.register('logger', Provider.fromClass(Logger));
|
|
154
224
|
|
|
155
225
|
const app = container.resolve(App);
|
|
156
226
|
app.run();
|
|
157
227
|
```
|
|
158
228
|
|
|
159
|
-
##
|
|
229
|
+
## Providers
|
|
230
|
+
All providers are registered in container and cloned for every sub-scope.
|
|
231
|
+
|
|
232
|
+
- `Provider` - basic provider
|
|
233
|
+
- `SingletonProvider` - provider that creates only one instance in every scope where it's resolved
|
|
234
|
+
- `TaggedProvider` - provider that can be resolved only from container with certain tags and their sub scopes
|
|
235
|
+
- `ArgsProvider` - provider that encapsulates arguments to pass it to constructor.
|
|
160
236
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
- `perTags(...tags: string[])` - makes provider available only in scope with certain tags and their sub scopes
|
|
165
|
-
- `withArgs(...args: unknown[])` - passes arguments to constructor
|
|
166
|
-
- `withArgsFn(fn: (scope: IContainer) => unknown[])` - passes arguments to constructor as function result
|
|
237
|
+
### Provider
|
|
238
|
+
|
|
239
|
+
From function
|
|
167
240
|
|
|
168
241
|
```typescript
|
|
169
|
-
import { Provider
|
|
242
|
+
import { Provider } from "ts-ioc-container";
|
|
170
243
|
|
|
171
|
-
|
|
172
|
-
|
|
244
|
+
container.register('ILogger', new Provider((container, ...args) => new Logger(container, ...args)));
|
|
245
|
+
```
|
|
173
246
|
|
|
174
|
-
|
|
175
|
-
container.register('ILogger', Provider.fromClass(Logger).pipe(perTags('root')));
|
|
247
|
+
From class
|
|
176
248
|
|
|
177
|
-
|
|
178
|
-
|
|
249
|
+
```typescript
|
|
250
|
+
import { Provider } from "ts-ioc-container";
|
|
179
251
|
|
|
180
|
-
|
|
181
|
-
|
|
252
|
+
container.register('ILogger', Provider.fromClass(Logger));
|
|
253
|
+
```
|
|
182
254
|
|
|
183
|
-
|
|
184
|
-
container.register('ILogger', Provider.fromClass(Logger).pipe(withArgs('dev'), asSingleton()));
|
|
255
|
+
From value
|
|
185
256
|
|
|
186
|
-
|
|
187
|
-
|
|
257
|
+
```typescript
|
|
258
|
+
import { Provider } from "ts-ioc-container";
|
|
188
259
|
|
|
189
260
|
container.register('ILogger', Provider.fromValue(new Logger()));
|
|
190
261
|
```
|
|
191
262
|
|
|
192
|
-
|
|
263
|
+
`pipe` - decorates provider by other providers
|
|
193
264
|
|
|
194
265
|
```typescript
|
|
195
|
-
import { asSingleton, perTags,
|
|
266
|
+
import { asSingleton, perTags, Provider, SingletonProvider, TaggedProvider } from "ts-ioc-container";
|
|
196
267
|
|
|
197
|
-
|
|
268
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe((provider) => new SingletonProvider(provider)), (provider) => new TaggedProvider(provider, ['root']));
|
|
269
|
+
|
|
270
|
+
// OR
|
|
271
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe(asSingleton(), perTags('root')));
|
|
272
|
+
|
|
273
|
+
// OR
|
|
198
274
|
@provider(asSingleton(), perTags('root'))
|
|
199
275
|
class Logger {
|
|
200
|
-
info(message: string) {
|
|
201
|
-
console.log(message);
|
|
202
|
-
}
|
|
203
276
|
}
|
|
204
277
|
|
|
205
|
-
|
|
206
|
-
.add(Registration.fromClass(Logger));
|
|
207
|
-
const logger = container.resolve<ILogger>('ILogger');
|
|
208
|
-
logger.info('Hello world');
|
|
278
|
+
container.register('ILogger', Provider.fromClass(Logger));
|
|
209
279
|
```
|
|
210
280
|
|
|
211
|
-
|
|
281
|
+
### Singleton provider
|
|
212
282
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
import { inject } from "ts-constructor-injector";
|
|
283
|
+
- Singleton provider creates only one instance in every scope where it's resolved.
|
|
284
|
+
- NOTICE: if you create a scope 'A' of container 'root' then Logger of A !== Logger of root.
|
|
216
285
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
class Engine {
|
|
220
|
-
constructor(@inject(by('ILogger')) private logger: ILogger) {
|
|
221
|
-
}
|
|
222
|
-
}
|
|
286
|
+
```typescript
|
|
287
|
+
import { Provider, SingletonProvider, asSingleton } from "ts-ioc-container";
|
|
223
288
|
|
|
289
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe((provider) => new SingletonProvider(provider)));
|
|
224
290
|
// OR
|
|
291
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe(asSingleton()));
|
|
225
292
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
@perRoot
|
|
229
|
-
@forKey('IEngine')
|
|
230
|
-
class Engine {
|
|
231
|
-
constructor(@inject(by('ILogger')) private logger: ILogger) {
|
|
232
|
-
}
|
|
233
|
-
}
|
|
293
|
+
container.resolve('ILogger') === container.resolve('ILogger'); // true
|
|
234
294
|
|
|
235
|
-
const
|
|
236
|
-
|
|
295
|
+
const scope = container.createScope();
|
|
296
|
+
scope.resolve('ILogger') === scope.resolve('ILogger'); // true
|
|
297
|
+
container.resolve('ILogger') !== scope.resolve('ILogger'); // true. NOTICE: because every provider is cloned for every child scope from parent one
|
|
237
298
|
```
|
|
238
299
|
|
|
239
|
-
|
|
300
|
+
### Tagged provider
|
|
301
|
+
You need tagged provider when you want to resolve provider only from container with certain tags and their sub scopes.
|
|
302
|
+
It doesn't make a clones in scopes with tags that are not in provider's tags. Usually it's used with `SingletonProvider`.
|
|
240
303
|
|
|
241
304
|
```typescript
|
|
242
|
-
import {
|
|
243
|
-
Container,
|
|
244
|
-
IInjector,
|
|
245
|
-
ContainerHook,
|
|
246
|
-
Injector,
|
|
247
|
-
Registration,
|
|
248
|
-
} from "ts-request-mediator";
|
|
249
|
-
import { getHooks, hook } from "ts-constructor-injector";
|
|
305
|
+
import { Provider, TaggedProvider, asSingleton, perTags } from "ts-ioc-container";
|
|
250
306
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
initialize() {
|
|
255
|
-
console.log('initialized');
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
@hook('OnDispose')
|
|
259
|
-
dispose() {
|
|
260
|
-
console.log('disposed');
|
|
261
|
-
}
|
|
262
|
-
}
|
|
307
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe((provider) => new TaggedProvider(provider, ['root'])));
|
|
308
|
+
// OR
|
|
309
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe(perTags('root', 'parent')));
|
|
263
310
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
for (const h of getHooks(instance, 'OnConstruct')) {
|
|
268
|
-
// @ts-ignore
|
|
269
|
-
instance[h]();
|
|
270
|
-
}
|
|
271
|
-
return instance;
|
|
272
|
-
},
|
|
273
|
-
}
|
|
311
|
+
// with sigleton
|
|
312
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe(perTags('root', 'parent')).pipe(asSingleton()));
|
|
313
|
+
container.resolve('ILogger') === container.resolve('ILogger'); // true
|
|
274
314
|
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
for (const instance of container.getInstances()) {
|
|
279
|
-
for (const h of getHooks(instance, 'OnDispose')) {
|
|
280
|
-
// @ts-ignore
|
|
281
|
-
instance[h]();
|
|
282
|
-
}
|
|
283
|
-
}
|
|
315
|
+
const scope = container.createScope();
|
|
316
|
+
scope.resolve('ILogger') === scope.resolve('ILogger'); // true
|
|
317
|
+
container.resolve('ILogger') === scope.resolve('ILogger'); // true
|
|
284
318
|
```
|
|
285
319
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
-
|
|
320
|
+
### Args provider
|
|
321
|
+
- You need args provider when you want to pass arguments to constructor on step when you compose container.
|
|
322
|
+
- NOTICE: args from this provider has higher priority than args from `resolve` method.
|
|
289
323
|
|
|
290
324
|
```typescript
|
|
291
|
-
import {
|
|
292
|
-
import { forKey, provider, Registration, asSingleton, perTags } from "ts-request-mediator";
|
|
325
|
+
import { Provider, ArgsProvider, withArgs, withArgsFn } from "ts-ioc-container";
|
|
293
326
|
|
|
294
|
-
@forKey('IEngine')
|
|
295
|
-
@provider(perTags('root'), asSingleton())
|
|
296
327
|
class Logger {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
@forKey('IEngine')
|
|
300
|
-
@provider(perTags('home'), asSingleton())
|
|
301
|
-
class Engine {
|
|
302
|
-
constructor(@inject(by('ILogger')) private logger: ILogger) {
|
|
328
|
+
constructor(public type: string, public name: string) {
|
|
303
329
|
}
|
|
304
330
|
}
|
|
305
331
|
|
|
306
|
-
|
|
307
|
-
.add(Registration.fromClass(Logger))
|
|
308
|
-
.add(Registration.fromClass(Engine));
|
|
332
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe((provider) => new ArgsProvider(provider, () => ['FileLogger'])));
|
|
309
333
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
334
|
+
// OR
|
|
335
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe(withArgsFn(() => ['FileLogger'])));
|
|
336
|
+
// OR
|
|
337
|
+
container.register('ILogger', Provider.fromClass(Logger).pipe(withArgs('FileLogger')));
|
|
338
|
+
|
|
339
|
+
container.resolve('ILogger', 'Main').type === 'FileLogger'; // true
|
|
340
|
+
container.resolve('ILogger', 'Main').name === 'Main'; // true
|
|
313
341
|
```
|
|
314
342
|
|
|
315
343
|
## Container modules
|
|
316
344
|
|
|
345
|
+
if you want to encapsulate some logic to enrich container you can use `IContainerModule`.
|
|
346
|
+
|
|
317
347
|
```typescript
|
|
318
|
-
import { Registration } from "ts-
|
|
348
|
+
import { Registration } from "ts-ioc-container";
|
|
319
349
|
|
|
320
350
|
class Development implements IContainerModule {
|
|
321
351
|
applyTo(container: IContainer): void {
|
|
@@ -334,14 +364,95 @@ const container = new Container(injector, { tags: ['root'] })
|
|
|
334
364
|
.add(process.env.NODE_ENV === 'production' ? new Production() : new Development());
|
|
335
365
|
```
|
|
336
366
|
|
|
367
|
+
## Registration module (Provider + DependencyKey)
|
|
368
|
+
It's built-in module that encapsulates logic of registration provider by dependency key `forKey`. Just a sugar
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
import { asSingleton, perTags, forKey, Registration, Provider } from "ts-ioc-container";
|
|
372
|
+
|
|
373
|
+
@forKey('ILogger')
|
|
374
|
+
@provider(asSingleton(), perTags('root'))
|
|
375
|
+
class Logger {
|
|
376
|
+
info(message: string) {
|
|
377
|
+
console.log(message);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
container.register(Registration.fromClass(Logger));
|
|
382
|
+
|
|
383
|
+
// OR
|
|
384
|
+
|
|
385
|
+
@provider(asSingleton(), perTags('root'))
|
|
386
|
+
class Logger {
|
|
387
|
+
info(message: string) {
|
|
388
|
+
console.log(message);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
container.register('ILogger', Provider.fromClass(Logger));
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Hooks
|
|
396
|
+
You can mark methods of your classes as hooks. It's useful when you want to do something after construct of dispose classes.
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
import {
|
|
400
|
+
Container,
|
|
401
|
+
IInjector,
|
|
402
|
+
ContainerHook,
|
|
403
|
+
Injector,
|
|
404
|
+
Registration,
|
|
405
|
+
getHooks,
|
|
406
|
+
hook,
|
|
407
|
+
} from "ts-ioc-container";
|
|
408
|
+
|
|
409
|
+
class MyInjector implements IInjector {
|
|
410
|
+
private injector = new ReflectionInjector();
|
|
411
|
+
|
|
412
|
+
resolve<T>(container: IContainer, value: constructor<T>, ...deps: unknown[]): T {
|
|
413
|
+
const instance = this.injector.resolve(container, value, ...deps);
|
|
414
|
+
for (const h of getHooks(instance, 'onConstruct')) {
|
|
415
|
+
// @ts-ignore
|
|
416
|
+
instance[h]();
|
|
417
|
+
}
|
|
418
|
+
return instance;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
@forKey('ILogger')
|
|
423
|
+
class Logger {
|
|
424
|
+
@hook('onConstruct')
|
|
425
|
+
initialize() {
|
|
426
|
+
console.log('initialized');
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
@hook('onDispose')
|
|
430
|
+
dispose() {
|
|
431
|
+
console.log('disposed');
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const container = new Container(new MyInjector())
|
|
436
|
+
.add(Registration.fromClass(Logger));
|
|
437
|
+
const logger = container.resolve<ILogger>('ILogger'); // initialized
|
|
438
|
+
|
|
439
|
+
for (const instance of container.getInstances()) {
|
|
440
|
+
for (const h of getHooks(instance, 'onDispose')) {
|
|
441
|
+
// @ts-ignore
|
|
442
|
+
instance[h](); // disposed
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
337
447
|
## Mocking / Tests
|
|
448
|
+
`AutoMockedContainer`. It will generate mocks for every dependency that you didn't define.
|
|
338
449
|
|
|
339
450
|
```typescript
|
|
340
451
|
import {
|
|
341
452
|
AutoMockedContainer,
|
|
342
453
|
Container,
|
|
343
454
|
DependencyKey,
|
|
344
|
-
} from "ts-
|
|
455
|
+
} from "ts-ioc-container";
|
|
345
456
|
import { Mock } from "moq.ts";
|
|
346
457
|
|
|
347
458
|
export class MoqContainer extends AutoMockedContainer {
|
|
@@ -351,10 +462,6 @@ export class MoqContainer extends AutoMockedContainer {
|
|
|
351
462
|
return this.resolveMock<T>(key).object();
|
|
352
463
|
}
|
|
353
464
|
|
|
354
|
-
dispose(): void {
|
|
355
|
-
this.mocks.clear();
|
|
356
|
-
}
|
|
357
|
-
|
|
358
465
|
resolveMock<T>(key: DependencyKey): IMock<T> {
|
|
359
466
|
if (!this.mocks.has(key)) {
|
|
360
467
|
this.mocks.set(key, new Mock());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DependencyKey, IContainer, IContainerModule, InjectionToken, Tag, Tagged } from './IContainer';
|
|
2
|
-
import { IInjector } from '../IInjector';
|
|
2
|
+
import { IInjector } from '../injector/IInjector';
|
|
3
3
|
import { IProvider } from '../provider/IProvider';
|
|
4
4
|
export declare class Container implements IContainer, Tagged {
|
|
5
5
|
private readonly injector;
|
package/cjs/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { IContainer, InjectionToken } from './container/IContainer';
|
|
2
1
|
export { IContainer, Resolvable, IContainerModule, isDependencyKey, DependencyKey, InjectionToken, Tag, } from './container/IContainer';
|
|
3
2
|
export { constructor } from './utils';
|
|
4
3
|
export { Container } from './container/Container';
|
|
5
4
|
export { ResolveDependency, IProvider } from './provider/IProvider';
|
|
6
|
-
export { IInjector } from './IInjector';
|
|
5
|
+
export { IInjector } from './injector/IInjector';
|
|
7
6
|
export { DependencyNotFoundError } from './container/DependencyNotFoundError';
|
|
8
7
|
export { MethodNotImplementedError } from './container/MethodNotImplementedError';
|
|
9
8
|
export { ContainerDisposedError } from './container/ContainerDisposedError';
|
|
@@ -14,4 +13,7 @@ export { perTags } from './provider/TaggedProvider';
|
|
|
14
13
|
export { AutoMockedContainer } from './container/AutoMockedContainer';
|
|
15
14
|
export { forKey, Registration } from './registration/Registration';
|
|
16
15
|
export { DependencyMissingKeyError } from './registration/DependencyMissingKeyError';
|
|
17
|
-
export
|
|
16
|
+
export { ReflectionInjector, inject, by } from './injector/ReflectionInjector';
|
|
17
|
+
export { SimpleInjector } from './injector/SimpleInjector';
|
|
18
|
+
export { ProxyInjector } from './injector/ProxyInjector';
|
|
19
|
+
export { hook, getHooks } from './reflection';
|
package/cjs/index.js
CHANGED
|
@@ -1,31 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __read = (this && this.__read) || function (o, n) {
|
|
3
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
4
|
-
if (!m) return o;
|
|
5
|
-
var i = m.call(o), r, ar = [], e;
|
|
6
|
-
try {
|
|
7
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
8
|
-
}
|
|
9
|
-
catch (error) { e = { error: error }; }
|
|
10
|
-
finally {
|
|
11
|
-
try {
|
|
12
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
13
|
-
}
|
|
14
|
-
finally { if (e) throw e.error; }
|
|
15
|
-
}
|
|
16
|
-
return ar;
|
|
17
|
-
};
|
|
18
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
19
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
20
|
-
if (ar || !(i in from)) {
|
|
21
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
22
|
-
ar[i] = from[i];
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
26
|
-
};
|
|
27
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
-
exports.by = exports.DependencyMissingKeyError = exports.Registration = exports.forKey = exports.AutoMockedContainer = exports.perTags = exports.asSingleton = exports.withArgs = exports.withArgsFn = exports.provider = exports.Provider = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.Container = exports.isDependencyKey = void 0;
|
|
3
|
+
exports.getHooks = exports.hook = exports.ProxyInjector = exports.SimpleInjector = exports.by = exports.inject = exports.ReflectionInjector = exports.DependencyMissingKeyError = exports.Registration = exports.forKey = exports.AutoMockedContainer = exports.perTags = exports.asSingleton = exports.withArgs = exports.withArgsFn = exports.provider = exports.Provider = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.Container = exports.isDependencyKey = void 0;
|
|
29
4
|
var IContainer_1 = require("./container/IContainer");
|
|
30
5
|
Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
|
|
31
6
|
var Container_1 = require("./container/Container");
|
|
@@ -53,14 +28,15 @@ Object.defineProperty(exports, "forKey", { enumerable: true, get: function () {
|
|
|
53
28
|
Object.defineProperty(exports, "Registration", { enumerable: true, get: function () { return Registration_1.Registration; } });
|
|
54
29
|
var DependencyMissingKeyError_1 = require("./registration/DependencyMissingKeyError");
|
|
55
30
|
Object.defineProperty(exports, "DependencyMissingKeyError", { enumerable: true, get: function () { return DependencyMissingKeyError_1.DependencyMissingKeyError; } });
|
|
56
|
-
var
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
exports.
|
|
31
|
+
var ReflectionInjector_1 = require("./injector/ReflectionInjector");
|
|
32
|
+
Object.defineProperty(exports, "ReflectionInjector", { enumerable: true, get: function () { return ReflectionInjector_1.ReflectionInjector; } });
|
|
33
|
+
Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return ReflectionInjector_1.inject; } });
|
|
34
|
+
Object.defineProperty(exports, "by", { enumerable: true, get: function () { return ReflectionInjector_1.by; } });
|
|
35
|
+
var SimpleInjector_1 = require("./injector/SimpleInjector");
|
|
36
|
+
Object.defineProperty(exports, "SimpleInjector", { enumerable: true, get: function () { return SimpleInjector_1.SimpleInjector; } });
|
|
37
|
+
var ProxyInjector_1 = require("./injector/ProxyInjector");
|
|
38
|
+
Object.defineProperty(exports, "ProxyInjector", { enumerable: true, get: function () { return ProxyInjector_1.ProxyInjector; } });
|
|
39
|
+
var reflection_1 = require("./reflection");
|
|
40
|
+
Object.defineProperty(exports, "hook", { enumerable: true, get: function () { return reflection_1.hook; } });
|
|
41
|
+
Object.defineProperty(exports, "getHooks", { enumerable: true, get: function () { return reflection_1.getHooks; } });
|
|
66
42
|
//# sourceMappingURL=index.js.map
|
package/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;;AAAA,qDAQgC;AAJ5B,6GAAA,eAAe,OAAA;AAMnB,mDAAkD;AAAzC,sGAAA,SAAS,OAAA;AAGlB,+EAA8E;AAArE,kIAAA,uBAAuB,OAAA;AAChC,mFAAkF;AAAzE,sIAAA,yBAAyB,OAAA;AAClC,6EAA4E;AAAnE,gIAAA,sBAAsB,OAAA;AAC/B,gDAAyD;AAAhD,oGAAA,QAAQ,OAAA;AAAE,oGAAA,QAAQ,OAAA;AAC3B,wDAAuE;AAAtD,0GAAA,UAAU,OAAA;AAAE,wGAAA,QAAQ,OAAA;AACrC,kEAA2D;AAAlD,gHAAA,WAAW,OAAA;AACpB,4DAAoD;AAA3C,yGAAA,OAAO,OAAA;AAChB,uEAAsE;AAA7D,0HAAA,mBAAmB,OAAA;AAC5B,4DAAmE;AAA1D,sGAAA,MAAM,OAAA;AAAE,4GAAA,YAAY,OAAA;AAC7B,sFAAqF;AAA5E,sIAAA,yBAAyB,OAAA;AAClC,oEAA+E;AAAtE,wHAAA,kBAAkB,OAAA;AAAE,4GAAA,MAAM,OAAA;AAAE,wGAAA,EAAE,OAAA;AACvC,4DAA2D;AAAlD,gHAAA,cAAc,OAAA;AACvB,0DAAyD;AAAhD,8GAAA,aAAa,OAAA;AACtB,2CAA8C;AAArC,kGAAA,IAAI,OAAA;AAAE,sGAAA,QAAQ,OAAA"}
|