ts-ioc-container 32.0.0 → 32.0.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 +161 -59
- package/cjm/container/Container.js +3 -9
- package/cjm/index.js +1 -4
- package/cjm/provider/DecoratorProvider.js +1 -1
- package/cjm/provider/IProvider.js +2 -8
- package/cjm/provider/Provider.js +1 -9
- package/cjm/provider/singleton/SingletonProvider.js +1 -1
- package/cjm/utils.js +4 -1
- package/esm/container/Container.js +3 -9
- package/esm/index.js +1 -2
- package/esm/provider/DecoratorProvider.js +1 -1
- package/esm/provider/IProvider.js +2 -7
- package/esm/provider/Provider.js +2 -10
- package/esm/provider/singleton/SingletonProvider.js +1 -1
- package/esm/utils.js +4 -1
- package/package.json +2 -2
- package/typings/container/Container.d.ts +0 -1
- package/typings/index.d.ts +1 -2
- package/typings/provider/DecoratorProvider.d.ts +2 -2
- package/typings/provider/IProvider.d.ts +3 -4
- package/typings/provider/Provider.d.ts +0 -2
- package/typings/provider/singleton/SingletonProvider.d.ts +2 -2
- package/typings/utils.d.ts +1 -1
- package/cjm/provider/LazyProvider.js +0 -17
- package/esm/provider/LazyProvider.js +0 -12
- package/typings/provider/LazyProvider.d.ts +0 -8
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
- [Scope](#scope) `tags`
|
|
26
26
|
- [Instances](#instances)
|
|
27
27
|
- [Dispose](#dispose)
|
|
28
|
+
- [Lazy](#lazy)
|
|
28
29
|
- [Injector](#injector)
|
|
29
30
|
- [Metadata](#metadata) `@inject`
|
|
30
31
|
- [Simple](#simple)
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
- [Arguments](#arguments) `args`
|
|
35
36
|
- [Visibility](#visibility) `visible`
|
|
36
37
|
- [Alias](#alias) `alias`
|
|
37
|
-
- [
|
|
38
|
+
- [Decorator](#decorator)
|
|
38
39
|
- [Registration](#registration) `@register`
|
|
39
40
|
- [Key](#key) `key`
|
|
40
41
|
- [Scope](#scope) `scope`
|
|
@@ -251,6 +252,102 @@ describe('Disposing', function () {
|
|
|
251
252
|
|
|
252
253
|
```
|
|
253
254
|
|
|
255
|
+
### Lazy
|
|
256
|
+
Sometimes you want to create dependency only when somebody want to invoke it's method or property. This is what `lazy` is for.
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { by, Container, inject, MetadataInjector, provider, Registration as R, singleton } from 'ts-ioc-container';
|
|
260
|
+
|
|
261
|
+
describe('lazy provider', () => {
|
|
262
|
+
@provider(singleton())
|
|
263
|
+
class Flag {
|
|
264
|
+
isSet = false;
|
|
265
|
+
|
|
266
|
+
set() {
|
|
267
|
+
this.isSet = true;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
class Service {
|
|
272
|
+
name = 'Service';
|
|
273
|
+
|
|
274
|
+
constructor(@inject(by.key('Flag')) private flag: Flag) {
|
|
275
|
+
this.flag.set();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
greet() {
|
|
279
|
+
return 'Hello';
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
class App {
|
|
284
|
+
constructor(@inject(by.key('Service', { lazy: true })) public service: Service) {}
|
|
285
|
+
|
|
286
|
+
run() {
|
|
287
|
+
return this.service.greet();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function createContainer() {
|
|
292
|
+
const container = new Container(new MetadataInjector());
|
|
293
|
+
container.add(R.fromClass(Flag)).add(R.fromClass(Service));
|
|
294
|
+
return container;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
it('should not create an instance until method is not invoked', () => {
|
|
298
|
+
// Arrange
|
|
299
|
+
const container = createContainer();
|
|
300
|
+
|
|
301
|
+
// Act
|
|
302
|
+
const app = container.resolve(App);
|
|
303
|
+
const flag = container.resolve<Flag>('Flag');
|
|
304
|
+
|
|
305
|
+
// Assert
|
|
306
|
+
expect(flag.isSet).toBe(false);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should create an instance only when some method/property is invoked', () => {
|
|
310
|
+
// Arrange
|
|
311
|
+
const container = createContainer();
|
|
312
|
+
|
|
313
|
+
// Act
|
|
314
|
+
const app = container.resolve(App);
|
|
315
|
+
const flag = container.resolve<Flag>('Flag');
|
|
316
|
+
|
|
317
|
+
// Assert
|
|
318
|
+
expect(app.run()).toBe('Hello');
|
|
319
|
+
expect(flag.isSet).toBe(true);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should not create instance on every method invoked', () => {
|
|
323
|
+
// Arrange
|
|
324
|
+
const container = createContainer();
|
|
325
|
+
|
|
326
|
+
// Act
|
|
327
|
+
const app = container.resolve(App);
|
|
328
|
+
|
|
329
|
+
// Assert
|
|
330
|
+
expect(app.run()).toBe('Hello');
|
|
331
|
+
expect(app.run()).toBe('Hello');
|
|
332
|
+
expect(container.getInstances().filter((x) => x instanceof Service).length).toBe(1);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should create instance when property is invoked', () => {
|
|
336
|
+
// Arrange
|
|
337
|
+
const container = createContainer();
|
|
338
|
+
|
|
339
|
+
// Act
|
|
340
|
+
const app = container.resolve(App);
|
|
341
|
+
const flag = container.resolve<Flag>('Flag');
|
|
342
|
+
|
|
343
|
+
// Assert
|
|
344
|
+
expect(app.service.name).toBe('Service');
|
|
345
|
+
expect(flag.isSet).toBe(true);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
|
|
254
351
|
## Injector
|
|
255
352
|
`IInjector` is used to describe how dependencies should be injected to constructor.
|
|
256
353
|
|
|
@@ -810,91 +907,96 @@ describe('alias', () => {
|
|
|
810
907
|
|
|
811
908
|
```
|
|
812
909
|
|
|
813
|
-
###
|
|
814
|
-
Sometimes you want to
|
|
815
|
-
- `@provider(
|
|
910
|
+
### Decorator
|
|
911
|
+
Sometimes you want to decorate you class with some logic. This is what `DecoratorProvider` is for.
|
|
912
|
+
- `@provider(decorate((instance, container) => new LoggerDecorator(instance)))`
|
|
816
913
|
|
|
817
914
|
```typescript
|
|
818
|
-
import {
|
|
915
|
+
import {
|
|
916
|
+
by,
|
|
917
|
+
Container,
|
|
918
|
+
decorate,
|
|
919
|
+
IContainer,
|
|
920
|
+
inject,
|
|
921
|
+
key,
|
|
922
|
+
MetadataInjector,
|
|
923
|
+
provider,
|
|
924
|
+
register,
|
|
925
|
+
Registration as R,
|
|
926
|
+
singleton,
|
|
927
|
+
} from 'ts-ioc-container';
|
|
819
928
|
|
|
820
929
|
describe('lazy provider', () => {
|
|
821
930
|
@provider(singleton())
|
|
822
|
-
class
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
set() {
|
|
826
|
-
this.isSet = true;
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
@provider(lazy)
|
|
831
|
-
class Service {
|
|
832
|
-
name = 'Service';
|
|
931
|
+
class Logger {
|
|
932
|
+
private logs: string[] = [];
|
|
833
933
|
|
|
834
|
-
|
|
835
|
-
this.
|
|
934
|
+
log(message: string) {
|
|
935
|
+
this.logs.push(message);
|
|
836
936
|
}
|
|
837
937
|
|
|
838
|
-
|
|
839
|
-
return '
|
|
938
|
+
printLogs() {
|
|
939
|
+
return this.logs.join(',');
|
|
840
940
|
}
|
|
841
941
|
}
|
|
842
942
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
container.add(R.fromClass(Flag)).add(R.fromClass(Service));
|
|
846
|
-
return container;
|
|
943
|
+
interface IRepository {
|
|
944
|
+
save(item: Todo): Promise<void>;
|
|
847
945
|
}
|
|
848
946
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
// Act
|
|
854
|
-
const service = container.resolve<Service>('Service');
|
|
855
|
-
const flag = container.resolve<Flag>('Flag');
|
|
947
|
+
interface Todo {
|
|
948
|
+
id: string;
|
|
949
|
+
text: string;
|
|
950
|
+
}
|
|
856
951
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
952
|
+
class LogRepository implements IRepository {
|
|
953
|
+
constructor(
|
|
954
|
+
private repository: IRepository,
|
|
955
|
+
@inject(by.key('Logger')) private logger: Logger,
|
|
956
|
+
) {}
|
|
860
957
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
958
|
+
async save(item: Todo): Promise<void> {
|
|
959
|
+
this.logger.log(item.id);
|
|
960
|
+
return this.repository.save(item);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
864
963
|
|
|
865
|
-
|
|
866
|
-
const service = container.resolve<Service>('Service');
|
|
867
|
-
const flag = container.resolve<Flag>('Flag');
|
|
964
|
+
const logRepo = (dep: IRepository, scope: IContainer) => scope.resolve(LogRepository, { args: [dep] });
|
|
868
965
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
966
|
+
@register(key('IRepository'))
|
|
967
|
+
@provider(decorate(logRepo))
|
|
968
|
+
class TodoRepository implements IRepository {
|
|
969
|
+
async save(item: Todo): Promise<void> {
|
|
970
|
+
console.log('Saving todo item', item);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
873
973
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
const container = createContainer();
|
|
974
|
+
class App {
|
|
975
|
+
constructor(@inject(by.key('IRepository')) public repository: IRepository) {}
|
|
877
976
|
|
|
878
|
-
|
|
879
|
-
|
|
977
|
+
async run() {
|
|
978
|
+
await this.repository.save({ id: '1', text: 'Hello' });
|
|
979
|
+
await this.repository.save({ id: '2', text: 'Hello' });
|
|
980
|
+
}
|
|
981
|
+
}
|
|
880
982
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
}
|
|
983
|
+
function createContainer() {
|
|
984
|
+
const container = new Container(new MetadataInjector());
|
|
985
|
+
container.add(R.fromClass(TodoRepository)).add(R.fromClass(Logger));
|
|
986
|
+
return container;
|
|
987
|
+
}
|
|
886
988
|
|
|
887
|
-
it('should
|
|
989
|
+
it('should decorate repo by logger middleware', async () => {
|
|
888
990
|
// Arrange
|
|
889
991
|
const container = createContainer();
|
|
890
992
|
|
|
891
993
|
// Act
|
|
892
|
-
const
|
|
893
|
-
const
|
|
994
|
+
const app = container.resolve(App);
|
|
995
|
+
const logger = container.resolve<Logger>('Logger');
|
|
996
|
+
await app.run();
|
|
894
997
|
|
|
895
998
|
// Assert
|
|
896
|
-
expect(
|
|
897
|
-
expect(flag.isSet).toBe(true);
|
|
999
|
+
expect(logger.printLogs()).toBe('1,2');
|
|
898
1000
|
});
|
|
899
1001
|
});
|
|
900
1002
|
|
|
@@ -4,7 +4,6 @@ exports.Container = void 0;
|
|
|
4
4
|
const IContainer_1 = require("./IContainer");
|
|
5
5
|
const EmptyContainer_1 = require("./EmptyContainer");
|
|
6
6
|
const ContainerDisposedError_1 = require("../errors/ContainerDisposedError");
|
|
7
|
-
const utils_1 = require("../utils");
|
|
8
7
|
class Container {
|
|
9
8
|
constructor(injector, options = {}) {
|
|
10
9
|
this.injector = injector;
|
|
@@ -29,20 +28,15 @@ class Container {
|
|
|
29
28
|
resolve(token, { args = [], child = this, lazy } = {}) {
|
|
30
29
|
this.validateContainer();
|
|
31
30
|
if ((0, IContainer_1.isConstructor)(token)) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
const instance = this.injector.resolve(this, token, { args });
|
|
32
|
+
this.instances.add(instance);
|
|
33
|
+
return instance;
|
|
35
34
|
}
|
|
36
35
|
const provider = this.providers.get(token);
|
|
37
36
|
return provider?.isVisible(this, child)
|
|
38
37
|
? provider.resolve(this, { args, lazy })
|
|
39
38
|
: this.parent.resolve(token, { args, child, lazy });
|
|
40
39
|
}
|
|
41
|
-
resolveByInjector(token, options) {
|
|
42
|
-
const instance = this.injector.resolve(this, token, options);
|
|
43
|
-
this.instances.add(instance);
|
|
44
|
-
return instance;
|
|
45
|
-
}
|
|
46
40
|
createScope(...tags) {
|
|
47
41
|
this.validateContainer();
|
|
48
42
|
const scope = new Container(this.injector, { parent: this, tags });
|
package/cjm/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getParameterMetadata = exports.getMethodMetadata = exports.setMethodMetadata = exports.setParameterMetadata = exports.getMetadata = exports.setMetadata = exports.IMemoKey = exports.by = exports.hasHooks = exports.hook = exports.getHooks = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.Registration = exports.register = exports.scope = exports.key = exports.decorate = exports.
|
|
3
|
+
exports.getParameterMetadata = exports.getMethodMetadata = exports.setMethodMetadata = exports.setParameterMetadata = exports.getMetadata = exports.setMetadata = exports.IMemoKey = exports.by = exports.hasHooks = exports.hook = exports.getHooks = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.Registration = exports.register = exports.scope = exports.key = exports.decorate = exports.multiCache = exports.MultiCache = exports.SingletonProvider = exports.singleton = exports.Provider = exports.ProviderDecorator = exports.args = exports.argsFn = exports.alias = exports.visible = exports.provider = exports.ProxyInjector = exports.SimpleInjector = exports.inject = exports.MetadataInjector = exports.AutoMockedContainer = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
|
|
4
4
|
// Containers
|
|
5
5
|
var IContainer_1 = require("./container/IContainer");
|
|
6
6
|
Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
|
|
@@ -24,7 +24,6 @@ Object.defineProperty(exports, "visible", { enumerable: true, get: function () {
|
|
|
24
24
|
Object.defineProperty(exports, "alias", { enumerable: true, get: function () { return IProvider_1.alias; } });
|
|
25
25
|
Object.defineProperty(exports, "argsFn", { enumerable: true, get: function () { return IProvider_1.argsFn; } });
|
|
26
26
|
Object.defineProperty(exports, "args", { enumerable: true, get: function () { return IProvider_1.args; } });
|
|
27
|
-
Object.defineProperty(exports, "lazy", { enumerable: true, get: function () { return IProvider_1.lazy; } });
|
|
28
27
|
Object.defineProperty(exports, "ProviderDecorator", { enumerable: true, get: function () { return IProvider_1.ProviderDecorator; } });
|
|
29
28
|
var Provider_1 = require("./provider/Provider");
|
|
30
29
|
Object.defineProperty(exports, "Provider", { enumerable: true, get: function () { return Provider_1.Provider; } });
|
|
@@ -34,8 +33,6 @@ Object.defineProperty(exports, "SingletonProvider", { enumerable: true, get: fun
|
|
|
34
33
|
var MultiCache_1 = require("./provider/singleton/MultiCache");
|
|
35
34
|
Object.defineProperty(exports, "MultiCache", { enumerable: true, get: function () { return MultiCache_1.MultiCache; } });
|
|
36
35
|
Object.defineProperty(exports, "multiCache", { enumerable: true, get: function () { return MultiCache_1.multiCache; } });
|
|
37
|
-
var LazyProvider_1 = require("./provider/LazyProvider");
|
|
38
|
-
Object.defineProperty(exports, "makeProviderLazy", { enumerable: true, get: function () { return LazyProvider_1.makeProviderLazy; } });
|
|
39
36
|
var DecoratorProvider_1 = require("./provider/DecoratorProvider");
|
|
40
37
|
Object.defineProperty(exports, "decorate", { enumerable: true, get: function () { return DecoratorProvider_1.decorate; } });
|
|
41
38
|
// Registrations
|
|
@@ -8,7 +8,7 @@ class DecoratorProvider extends IProvider_1.ProviderDecorator {
|
|
|
8
8
|
this.provider = provider;
|
|
9
9
|
this.decorateFn = decorateFn;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
resolveInstantly(scope, options) {
|
|
12
12
|
const dependency = this.provider.resolve(scope, options);
|
|
13
13
|
return this.decorateFn(dependency, scope);
|
|
14
14
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ProviderDecorator = exports.visible = exports.alias = exports.getTransformers = exports.provider = exports.
|
|
3
|
+
exports.ProviderDecorator = exports.visible = exports.alias = exports.getTransformers = exports.provider = exports.argsFn = exports.args = void 0;
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
5
|
const metadata_1 = require("../metadata");
|
|
6
6
|
function args(...extraArgs) {
|
|
@@ -11,8 +11,6 @@ function argsFn(fn) {
|
|
|
11
11
|
return (provider) => provider.setArgs(fn);
|
|
12
12
|
}
|
|
13
13
|
exports.argsFn = argsFn;
|
|
14
|
-
const lazy = (provider) => provider.setLazy(true);
|
|
15
|
-
exports.lazy = lazy;
|
|
16
14
|
const METADATA_KEY = 'provider';
|
|
17
15
|
const provider = (...mappers) => (0, metadata_1.setMetadata)(METADATA_KEY, mappers);
|
|
18
16
|
exports.provider = provider;
|
|
@@ -34,7 +32,7 @@ class ProviderDecorator {
|
|
|
34
32
|
return this.decorated.isVisible(parent, child);
|
|
35
33
|
}
|
|
36
34
|
resolve(container, options) {
|
|
37
|
-
return this.
|
|
35
|
+
return (0, utils_1.lazyInstance)(() => this.resolveInstantly(container, options), options.lazy);
|
|
38
36
|
}
|
|
39
37
|
pipe(...mappers) {
|
|
40
38
|
return (0, utils_1.pipe)(...mappers)(this);
|
|
@@ -50,9 +48,5 @@ class ProviderDecorator {
|
|
|
50
48
|
this.decorated.setArgs(argsFn);
|
|
51
49
|
return this;
|
|
52
50
|
}
|
|
53
|
-
setLazy(lazy) {
|
|
54
|
-
this.decorated.setLazy(lazy);
|
|
55
|
-
return this;
|
|
56
|
-
}
|
|
57
51
|
}
|
|
58
52
|
exports.ProviderDecorator = ProviderDecorator;
|
package/cjm/provider/Provider.js
CHANGED
|
@@ -16,26 +16,18 @@ class Provider {
|
|
|
16
16
|
this.resolveDependency = resolveDependency;
|
|
17
17
|
this.aliases = new Set();
|
|
18
18
|
this.argsFn = () => [];
|
|
19
|
-
this.isLazy = false;
|
|
20
19
|
this.isVisibleWhen = () => true;
|
|
21
20
|
}
|
|
22
21
|
pipe(...mappers) {
|
|
23
22
|
return (0, utils_1.pipe)(...mappers)(this);
|
|
24
23
|
}
|
|
25
24
|
resolve(container, { args, lazy }) {
|
|
26
|
-
return this.resolveDependency(container, {
|
|
27
|
-
args: [...this.argsFn(container, ...args), ...args],
|
|
28
|
-
lazy: lazy ?? this.isLazy ?? false,
|
|
29
|
-
});
|
|
25
|
+
return (0, utils_1.lazyInstance)(() => this.resolveDependency(container, { args: [...this.argsFn(container, ...args), ...args] }), lazy);
|
|
30
26
|
}
|
|
31
27
|
setVisibility(predicate) {
|
|
32
28
|
this.isVisibleWhen = predicate;
|
|
33
29
|
return this;
|
|
34
30
|
}
|
|
35
|
-
setLazy(lazy) {
|
|
36
|
-
this.isLazy = lazy;
|
|
37
|
-
return this;
|
|
38
|
-
}
|
|
39
31
|
setArgs(argsFn) {
|
|
40
32
|
this.argsFn = argsFn;
|
|
41
33
|
return this;
|
|
@@ -13,7 +13,7 @@ class SingletonProvider extends IProvider_1.ProviderDecorator {
|
|
|
13
13
|
this.provider = provider;
|
|
14
14
|
this.cache = cache;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
resolveInstantly(container, options) {
|
|
17
17
|
const key = this.cache.getKey(...options.args);
|
|
18
18
|
if (!this.cache.hasValue(key)) {
|
|
19
19
|
this.cache.setValue(key, this.provider.resolve(container, options));
|
package/cjm/utils.js
CHANGED
|
@@ -18,7 +18,10 @@ const constant = (value) => () => value;
|
|
|
18
18
|
exports.constant = constant;
|
|
19
19
|
const isConstructor = (T) => typeof T === 'function' && !!T.prototype;
|
|
20
20
|
exports.isConstructor = isConstructor;
|
|
21
|
-
function lazyInstance(resolveInstance) {
|
|
21
|
+
function lazyInstance(resolveInstance, isLazy) {
|
|
22
|
+
if (!isLazy) {
|
|
23
|
+
return resolveInstance();
|
|
24
|
+
}
|
|
22
25
|
let instance;
|
|
23
26
|
return new Proxy({}, {
|
|
24
27
|
get: (_, prop) => {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { isConstructor, } from './IContainer';
|
|
2
2
|
import { EmptyContainer } from './EmptyContainer';
|
|
3
3
|
import { ContainerDisposedError } from '../errors/ContainerDisposedError';
|
|
4
|
-
import { lazyInstance } from '../utils';
|
|
5
4
|
export class Container {
|
|
6
5
|
constructor(injector, options = {}) {
|
|
7
6
|
this.injector = injector;
|
|
@@ -26,20 +25,15 @@ export class Container {
|
|
|
26
25
|
resolve(token, { args = [], child = this, lazy } = {}) {
|
|
27
26
|
this.validateContainer();
|
|
28
27
|
if (isConstructor(token)) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const instance = this.injector.resolve(this, token, { args });
|
|
29
|
+
this.instances.add(instance);
|
|
30
|
+
return instance;
|
|
32
31
|
}
|
|
33
32
|
const provider = this.providers.get(token);
|
|
34
33
|
return provider?.isVisible(this, child)
|
|
35
34
|
? provider.resolve(this, { args, lazy })
|
|
36
35
|
: this.parent.resolve(token, { args, child, lazy });
|
|
37
36
|
}
|
|
38
|
-
resolveByInjector(token, options) {
|
|
39
|
-
const instance = this.injector.resolve(this, token, options);
|
|
40
|
-
this.instances.add(instance);
|
|
41
|
-
return instance;
|
|
42
|
-
}
|
|
43
37
|
createScope(...tags) {
|
|
44
38
|
this.validateContainer();
|
|
45
39
|
const scope = new Container(this.injector, { parent: this, tags });
|
package/esm/index.js
CHANGED
|
@@ -7,11 +7,10 @@ export { MetadataInjector, inject } from './injector/MetadataInjector';
|
|
|
7
7
|
export { SimpleInjector } from './injector/SimpleInjector';
|
|
8
8
|
export { ProxyInjector } from './injector/ProxyInjector';
|
|
9
9
|
// Providers
|
|
10
|
-
export { provider, visible, alias, argsFn, args,
|
|
10
|
+
export { provider, visible, alias, argsFn, args, ProviderDecorator, } from './provider/IProvider';
|
|
11
11
|
export { Provider } from './provider/Provider';
|
|
12
12
|
export { singleton, SingletonProvider } from './provider/singleton/SingletonProvider';
|
|
13
13
|
export { MultiCache, multiCache } from './provider/singleton/MultiCache';
|
|
14
|
-
export { makeProviderLazy } from './provider/LazyProvider';
|
|
15
14
|
export { decorate } from './provider/DecoratorProvider';
|
|
16
15
|
// Registrations
|
|
17
16
|
export { key, scope, register } from './registration/IRegistration';
|
|
@@ -5,7 +5,7 @@ export class DecoratorProvider extends ProviderDecorator {
|
|
|
5
5
|
this.provider = provider;
|
|
6
6
|
this.decorateFn = decorateFn;
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
resolveInstantly(scope, options) {
|
|
9
9
|
const dependency = this.provider.resolve(scope, options);
|
|
10
10
|
return this.decorateFn(dependency, scope);
|
|
11
11
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { pipe } from '../utils';
|
|
1
|
+
import { lazyInstance, pipe } from '../utils';
|
|
2
2
|
import { getMetadata, setMetadata } from '../metadata';
|
|
3
3
|
export function args(...extraArgs) {
|
|
4
4
|
return (provider) => provider.setArgs(() => extraArgs);
|
|
@@ -6,7 +6,6 @@ export function args(...extraArgs) {
|
|
|
6
6
|
export function argsFn(fn) {
|
|
7
7
|
return (provider) => provider.setArgs(fn);
|
|
8
8
|
}
|
|
9
|
-
export const lazy = (provider) => provider.setLazy(true);
|
|
10
9
|
const METADATA_KEY = 'provider';
|
|
11
10
|
export const provider = (...mappers) => setMetadata(METADATA_KEY, mappers);
|
|
12
11
|
export const getTransformers = (Target) => getMetadata(Target, METADATA_KEY) ?? [];
|
|
@@ -24,7 +23,7 @@ export class ProviderDecorator {
|
|
|
24
23
|
return this.decorated.isVisible(parent, child);
|
|
25
24
|
}
|
|
26
25
|
resolve(container, options) {
|
|
27
|
-
return this.
|
|
26
|
+
return lazyInstance(() => this.resolveInstantly(container, options), options.lazy);
|
|
28
27
|
}
|
|
29
28
|
pipe(...mappers) {
|
|
30
29
|
return pipe(...mappers)(this);
|
|
@@ -40,8 +39,4 @@ export class ProviderDecorator {
|
|
|
40
39
|
this.decorated.setArgs(argsFn);
|
|
41
40
|
return this;
|
|
42
41
|
}
|
|
43
|
-
setLazy(lazy) {
|
|
44
|
-
this.decorated.setLazy(lazy);
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
42
|
}
|
package/esm/provider/Provider.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getTransformers, } from './IProvider';
|
|
2
|
-
import { isConstructor, pipe } from '../utils';
|
|
2
|
+
import { isConstructor, lazyInstance, pipe } from '../utils';
|
|
3
3
|
export class Provider {
|
|
4
4
|
static fromClass(Target) {
|
|
5
5
|
const transformers = getTransformers(Target);
|
|
@@ -13,26 +13,18 @@ export class Provider {
|
|
|
13
13
|
this.resolveDependency = resolveDependency;
|
|
14
14
|
this.aliases = new Set();
|
|
15
15
|
this.argsFn = () => [];
|
|
16
|
-
this.isLazy = false;
|
|
17
16
|
this.isVisibleWhen = () => true;
|
|
18
17
|
}
|
|
19
18
|
pipe(...mappers) {
|
|
20
19
|
return pipe(...mappers)(this);
|
|
21
20
|
}
|
|
22
21
|
resolve(container, { args, lazy }) {
|
|
23
|
-
return this.resolveDependency(container, {
|
|
24
|
-
args: [...this.argsFn(container, ...args), ...args],
|
|
25
|
-
lazy: lazy ?? this.isLazy ?? false,
|
|
26
|
-
});
|
|
22
|
+
return lazyInstance(() => this.resolveDependency(container, { args: [...this.argsFn(container, ...args), ...args] }), lazy);
|
|
27
23
|
}
|
|
28
24
|
setVisibility(predicate) {
|
|
29
25
|
this.isVisibleWhen = predicate;
|
|
30
26
|
return this;
|
|
31
27
|
}
|
|
32
|
-
setLazy(lazy) {
|
|
33
|
-
this.isLazy = lazy;
|
|
34
|
-
return this;
|
|
35
|
-
}
|
|
36
28
|
setArgs(argsFn) {
|
|
37
29
|
this.argsFn = argsFn;
|
|
38
30
|
return this;
|
|
@@ -9,7 +9,7 @@ export class SingletonProvider extends ProviderDecorator {
|
|
|
9
9
|
this.provider = provider;
|
|
10
10
|
this.cache = cache;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
resolveInstantly(container, options) {
|
|
13
13
|
const key = this.cache.getKey(...options.args);
|
|
14
14
|
if (!this.cache.hasValue(key)) {
|
|
15
15
|
this.cache.setValue(key, this.provider.resolve(container, options));
|
package/esm/utils.js
CHANGED
|
@@ -11,7 +11,10 @@ export function fillEmptyIndexes(baseArr, insertArr) {
|
|
|
11
11
|
}
|
|
12
12
|
export const constant = (value) => () => value;
|
|
13
13
|
export const isConstructor = (T) => typeof T === 'function' && !!T.prototype;
|
|
14
|
-
export function lazyInstance(resolveInstance) {
|
|
14
|
+
export function lazyInstance(resolveInstance, isLazy) {
|
|
15
|
+
if (!isLazy) {
|
|
16
|
+
return resolveInstance();
|
|
17
|
+
}
|
|
15
18
|
let instance;
|
|
16
19
|
return new Proxy({}, {
|
|
17
20
|
get: (_, prop) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-ioc-container",
|
|
3
|
-
"version": "32.0.
|
|
3
|
+
"version": "32.0.1",
|
|
4
4
|
"description": "Typescript IoC container",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"ts-node": "^10.9.1",
|
|
60
60
|
"typescript": "5.4.3"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "6bbe027ca4fbebf356d0520bf0e291612559866d"
|
|
63
63
|
}
|
|
@@ -18,7 +18,6 @@ export declare class Container implements IContainer {
|
|
|
18
18
|
add(registration: IRegistration): this;
|
|
19
19
|
register(key: DependencyKey, provider: IProvider): this;
|
|
20
20
|
resolve<T>(token: InjectionToken<T>, { args, child, lazy }?: ResolveOptions): T;
|
|
21
|
-
private resolveByInjector;
|
|
22
21
|
createScope(...tags: Tag[]): Container;
|
|
23
22
|
dispose(): void;
|
|
24
23
|
getInstances(): unknown[];
|
package/typings/index.d.ts
CHANGED
|
@@ -6,12 +6,11 @@ export { IInjector } from './injector/IInjector';
|
|
|
6
6
|
export { MetadataInjector, inject } from './injector/MetadataInjector';
|
|
7
7
|
export { SimpleInjector } from './injector/SimpleInjector';
|
|
8
8
|
export { ProxyInjector } from './injector/ProxyInjector';
|
|
9
|
-
export { ResolveDependency, IProvider, provider, visible, alias, argsFn, args, ArgsFn,
|
|
9
|
+
export { ResolveDependency, IProvider, provider, visible, alias, argsFn, args, ArgsFn, ProviderDecorator, } from './provider/IProvider';
|
|
10
10
|
export { Provider } from './provider/Provider';
|
|
11
11
|
export { singleton, SingletonProvider } from './provider/singleton/SingletonProvider';
|
|
12
12
|
export { MultiCache, multiCache } from './provider/singleton/MultiCache';
|
|
13
13
|
export { Cache } from './provider/singleton/Cache';
|
|
14
|
-
export { makeProviderLazy } from './provider/LazyProvider';
|
|
15
14
|
export { decorate, DecorateFn } from './provider/DecoratorProvider';
|
|
16
15
|
export { key, IRegistration, scope, register } from './registration/IRegistration';
|
|
17
16
|
export { Registration } from './registration/Registration';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { IContainer } from '../container/IContainer';
|
|
2
|
-
import { IProvider, ProviderDecorator
|
|
2
|
+
import { InstantDependencyOptions, IProvider, ProviderDecorator } from './IProvider';
|
|
3
3
|
export type DecorateFn<Instance> = (dep: Instance, scope: IContainer) => Instance;
|
|
4
4
|
export declare class DecoratorProvider<Instance> extends ProviderDecorator<Instance> {
|
|
5
5
|
private provider;
|
|
6
6
|
private decorateFn;
|
|
7
7
|
constructor(provider: IProvider<Instance>, decorateFn: DecorateFn<Instance>);
|
|
8
|
-
|
|
8
|
+
resolveInstantly(scope: IContainer, options: InstantDependencyOptions): Instance;
|
|
9
9
|
}
|
|
10
10
|
export declare const decorate: <Instance>(decorateFn: DecorateFn<Instance>) => (provider: IProvider<Instance>) => DecoratorProvider<Instance>;
|
|
@@ -4,6 +4,7 @@ export type ProviderResolveOptions = {
|
|
|
4
4
|
args: unknown[];
|
|
5
5
|
lazy?: boolean;
|
|
6
6
|
};
|
|
7
|
+
export type InstantDependencyOptions = Omit<ProviderResolveOptions, 'lazy'>;
|
|
7
8
|
export type ResolveDependency<T = unknown> = (container: IContainer, options: ProviderResolveOptions) => T;
|
|
8
9
|
export type ChildrenVisibilityPredicate = (options: {
|
|
9
10
|
child: Tagged;
|
|
@@ -12,7 +13,6 @@ export type ChildrenVisibilityPredicate = (options: {
|
|
|
12
13
|
export type ArgsFn = (l: IContainer, ...args: unknown[]) => unknown[];
|
|
13
14
|
export declare function args<T = unknown>(...extraArgs: unknown[]): MapFn<IProvider<T>>;
|
|
14
15
|
export declare function argsFn<T = unknown>(fn: ArgsFn): MapFn<IProvider<T>>;
|
|
15
|
-
export declare const lazy: <T>(provider: IProvider<T>) => IProvider<T>;
|
|
16
16
|
export interface IProvider<T = unknown> {
|
|
17
17
|
resolve(container: IContainer, options: ProviderResolveOptions): T;
|
|
18
18
|
isVisible(parent: Tagged, child: Tagged): boolean;
|
|
@@ -21,9 +21,8 @@ export interface IProvider<T = unknown> {
|
|
|
21
21
|
setArgs(argsFn: ArgsFn): this;
|
|
22
22
|
matchAliases(predicate: AliasPredicate): boolean;
|
|
23
23
|
addAliases(...aliases: Alias[]): this;
|
|
24
|
-
setLazy(lazy: boolean): this;
|
|
25
24
|
}
|
|
26
|
-
export declare const provider: (...mappers: MapFn<IProvider
|
|
25
|
+
export declare const provider: <Instance>(...mappers: MapFn<IProvider<Instance>>[]) => ClassDecorator;
|
|
27
26
|
export declare const getTransformers: <T>(Target: constructor<T>) => MapFn<IProvider<T>>[];
|
|
28
27
|
export declare const alias: (...aliases: Alias[]) => MapFn<IProvider>;
|
|
29
28
|
export declare const visible: (isVisibleWhen: ChildrenVisibilityPredicate) => MapFn<IProvider>;
|
|
@@ -33,9 +32,9 @@ export declare abstract class ProviderDecorator<T> implements IProvider<T> {
|
|
|
33
32
|
setVisibility(predicate: ChildrenVisibilityPredicate): this;
|
|
34
33
|
isVisible(parent: IContainer, child: Tagged): boolean;
|
|
35
34
|
resolve(container: IContainer, options: ProviderResolveOptions): T;
|
|
35
|
+
protected abstract resolveInstantly(container: IContainer, options: InstantDependencyOptions): T;
|
|
36
36
|
pipe(...mappers: MapFn<IProvider<T>>[]): IProvider<T>;
|
|
37
37
|
matchAliases(predicate: AliasPredicate): boolean;
|
|
38
38
|
addAliases(...aliases: Alias[]): this;
|
|
39
39
|
setArgs(argsFn: ArgsFn): this;
|
|
40
|
-
setLazy(lazy: boolean): this;
|
|
41
40
|
}
|
|
@@ -7,13 +7,11 @@ export declare class Provider<T> implements IProvider<T> {
|
|
|
7
7
|
static fromValue<T>(value: T): IProvider<T>;
|
|
8
8
|
private readonly aliases;
|
|
9
9
|
private argsFn;
|
|
10
|
-
private isLazy;
|
|
11
10
|
private isVisibleWhen;
|
|
12
11
|
constructor(resolveDependency: ResolveDependency<T>);
|
|
13
12
|
pipe(...mappers: MapFn<IProvider<T>>[]): IProvider<T>;
|
|
14
13
|
resolve(container: IContainer, { args, lazy }: ProviderResolveOptions): T;
|
|
15
14
|
setVisibility(predicate: ChildrenVisibilityPredicate): this;
|
|
16
|
-
setLazy(lazy: boolean): this;
|
|
17
15
|
setArgs(argsFn: ArgsFn): this;
|
|
18
16
|
isVisible(parent: Tagged, child: Tagged): boolean;
|
|
19
17
|
matchAliases(predicate: AliasPredicate): boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IContainer } from '../../container/IContainer';
|
|
2
|
-
import { IProvider, ProviderDecorator
|
|
2
|
+
import { InstantDependencyOptions, IProvider, ProviderDecorator } from '../IProvider';
|
|
3
3
|
import { MapFn } from '../../utils';
|
|
4
4
|
import { Cache } from './Cache';
|
|
5
5
|
export declare function singleton<T = unknown>(cacheProvider?: () => Cache<unknown, T>): MapFn<IProvider<T>>;
|
|
@@ -7,5 +7,5 @@ export declare class SingletonProvider<T> extends ProviderDecorator<T> {
|
|
|
7
7
|
private readonly provider;
|
|
8
8
|
private readonly cache;
|
|
9
9
|
constructor(provider: IProvider<T>, cache: Cache<unknown, T>);
|
|
10
|
-
|
|
10
|
+
resolveInstantly(container: IContainer, options: InstantDependencyOptions): T;
|
|
11
11
|
}
|
package/typings/utils.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export declare const pipe: <T>(...mappers: MapFn<T>[]) => MapFn<T>;
|
|
|
4
4
|
export declare function fillEmptyIndexes<T>(baseArr: (T | undefined)[], insertArr: T[]): T[];
|
|
5
5
|
export declare const constant: <T>(value: T) => () => T;
|
|
6
6
|
export declare const isConstructor: (T: unknown) => T is constructor<unknown>;
|
|
7
|
-
export declare function lazyInstance<T>(resolveInstance: () => T): T;
|
|
7
|
+
export declare function lazyInstance<T>(resolveInstance: () => T, isLazy?: boolean): T;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.makeProviderLazy = exports.LazyProvider = void 0;
|
|
4
|
-
const IProvider_1 = require("./IProvider");
|
|
5
|
-
const utils_1 = require("../utils");
|
|
6
|
-
class LazyProvider extends IProvider_1.ProviderDecorator {
|
|
7
|
-
constructor(provider) {
|
|
8
|
-
super(provider);
|
|
9
|
-
this.provider = provider;
|
|
10
|
-
}
|
|
11
|
-
resolve(container, options) {
|
|
12
|
-
return (0, utils_1.lazyInstance)(() => this.provider.resolve(container, options));
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
exports.LazyProvider = LazyProvider;
|
|
16
|
-
const makeProviderLazy = (provider) => new LazyProvider(provider);
|
|
17
|
-
exports.makeProviderLazy = makeProviderLazy;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ProviderDecorator } from './IProvider';
|
|
2
|
-
import { lazyInstance } from '../utils';
|
|
3
|
-
export class LazyProvider extends ProviderDecorator {
|
|
4
|
-
constructor(provider) {
|
|
5
|
-
super(provider);
|
|
6
|
-
this.provider = provider;
|
|
7
|
-
}
|
|
8
|
-
resolve(container, options) {
|
|
9
|
-
return lazyInstance(() => this.provider.resolve(container, options));
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
export const makeProviderLazy = (provider) => new LazyProvider(provider);
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { IProvider, ProviderDecorator, ProviderResolveOptions } from './IProvider';
|
|
2
|
-
import { IContainer } from '../container/IContainer';
|
|
3
|
-
export declare class LazyProvider<Instance> extends ProviderDecorator<Instance> {
|
|
4
|
-
private provider;
|
|
5
|
-
constructor(provider: IProvider<Instance>);
|
|
6
|
-
resolve(container: IContainer, options: ProviderResolveOptions): Instance;
|
|
7
|
-
}
|
|
8
|
-
export declare const makeProviderLazy: <Instance>(provider: IProvider<Instance>) => LazyProvider<Instance>;
|