ts-ioc-container 31.8.0 → 31.9.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 CHANGED
@@ -34,7 +34,9 @@
34
34
  - [Arguments](#arguments) `args`
35
35
  - [Visibility](#visibility) `visible`
36
36
  - [Alias](#alias) `alias`
37
- - [Registration](#registration) `@register(key('someKey'))`
37
+ - [Lazy](#lazy) `lazy`
38
+ - [Registration](#registration) `@register`
39
+ - [Key](#key) `key`
38
40
  - [Scope](#scope) `scope`
39
41
  - [Module](#module)
40
42
  - [Hook](#hook) `@hook`
@@ -806,6 +808,95 @@ describe('alias', () => {
806
808
 
807
809
  ```
808
810
 
811
+ ### Lazy
812
+ Sometimes you want to create dependency only when somebody want to invoke it's method or property. This is what `LazyProvider` is for.
813
+ - `@provider(lazy)`
814
+
815
+ ```typescript
816
+ import { lazy, Container, inject, MetadataInjector, provider, Registration as R, singleton, by } from 'ts-ioc-container';
817
+
818
+ describe('lazy provider', () => {
819
+ @provider(singleton())
820
+ class Flag {
821
+ isSet = false;
822
+
823
+ set() {
824
+ this.isSet = true;
825
+ }
826
+ }
827
+
828
+ @provider(lazy)
829
+ class Service {
830
+ name = 'Service';
831
+
832
+ constructor(@inject(by.key('Flag')) private flag: Flag) {
833
+ this.flag.set();
834
+ }
835
+
836
+ greet() {
837
+ return 'Hello';
838
+ }
839
+ }
840
+
841
+ function createContainer() {
842
+ const container = new Container(new MetadataInjector());
843
+ container.add(R.fromClass(Flag)).add(R.fromClass(Service));
844
+ return container;
845
+ }
846
+
847
+ it('should not create an instance until method is not invoked', () => {
848
+ // Arrange
849
+ const container = createContainer();
850
+
851
+ // Act
852
+ const service = container.resolve<Service>('Service');
853
+ const flag = container.resolve<Flag>('Flag');
854
+
855
+ // Assert
856
+ expect(service.greet()).toBe('Hello');
857
+ expect(flag.isSet).toBe(true);
858
+ });
859
+
860
+ it('should create an instance only when some method/property is invoked', () => {
861
+ // Arrange
862
+ const container = createContainer();
863
+
864
+ // Act
865
+ const service = container.resolve<Service>('Service');
866
+ const flag = container.resolve<Flag>('Flag');
867
+
868
+ // Assert
869
+ expect(flag.isSet).toBe(false);
870
+ });
871
+
872
+ it('should not create instance on every method invoked', () => {
873
+ // Arrange
874
+ const container = createContainer();
875
+
876
+ // Act
877
+ const service = container.resolve<Service>('Service');
878
+
879
+ // Assert
880
+ expect(service.greet()).toBe('Hello');
881
+ expect(service.greet()).toBe('Hello');
882
+ expect(container.getInstances().filter((x) => x instanceof Service).length).toBe(1);
883
+ });
884
+
885
+ it('should create instance when property is invoked', () => {
886
+ // Arrange
887
+ const container = createContainer();
888
+
889
+ // Act
890
+ const service = container.resolve<Service>('Service');
891
+ const flag = container.resolve<Flag>('Flag');
892
+
893
+ // Assert
894
+ expect(service.name).toBe('Service');
895
+ expect(flag.isSet).toBe(true);
896
+ });
897
+ });
898
+
899
+ ```
809
900
 
810
901
  ## Registration
811
902
  Registration is provider factory which registers provider in container.
@@ -815,6 +906,12 @@ Registration is provider factory which registers provider in container.
815
906
  - `Registration.fromValue(Logger)`
816
907
  - `Registration.fromFn((container, ...args) => container.resolve(Logger, {args}))`
817
908
 
909
+ ### Key
910
+ Sometimes you want to register provider with certain key. This is what `key` is for.
911
+
912
+ - by default, key is class name
913
+ - you can assign the same key to different registrations
914
+
818
915
  ```typescript
819
916
  import 'reflect-metadata';
820
917
  import { Container, key, MetadataInjector, provider, register, Registration as R, scope, singleton } from 'ts-ioc-container';
package/cjm/index.js CHANGED
@@ -1,18 +1,23 @@
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.ProxyInjector = exports.SimpleInjector = exports.inject = exports.MetadataInjector = exports.Registration = exports.register = exports.scope = exports.key = exports.AutoMockedContainer = exports.multiCache = exports.MultiCache = exports.SingletonProvider = exports.singleton = exports.Provider = exports.ProviderDecorator = exports.args = exports.argsFn = exports.alias = exports.visible = exports.provider = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
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.lazy = exports.LazyProvider = 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
+ // Containers
4
5
  var IContainer_1 = require("./container/IContainer");
5
6
  Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
6
7
  var Container_1 = require("./container/Container");
7
8
  Object.defineProperty(exports, "Container", { enumerable: true, get: function () { return Container_1.Container; } });
8
9
  var EmptyContainer_1 = require("./container/EmptyContainer");
9
10
  Object.defineProperty(exports, "EmptyContainer", { enumerable: true, get: function () { return EmptyContainer_1.EmptyContainer; } });
10
- var DependencyNotFoundError_1 = require("./errors/DependencyNotFoundError");
11
- Object.defineProperty(exports, "DependencyNotFoundError", { enumerable: true, get: function () { return DependencyNotFoundError_1.DependencyNotFoundError; } });
12
- var MethodNotImplementedError_1 = require("./errors/MethodNotImplementedError");
13
- Object.defineProperty(exports, "MethodNotImplementedError", { enumerable: true, get: function () { return MethodNotImplementedError_1.MethodNotImplementedError; } });
14
- var ContainerDisposedError_1 = require("./errors/ContainerDisposedError");
15
- Object.defineProperty(exports, "ContainerDisposedError", { enumerable: true, get: function () { return ContainerDisposedError_1.ContainerDisposedError; } });
11
+ var AutoMockedContainer_1 = require("./container/AutoMockedContainer");
12
+ Object.defineProperty(exports, "AutoMockedContainer", { enumerable: true, get: function () { return AutoMockedContainer_1.AutoMockedContainer; } });
13
+ var MetadataInjector_1 = require("./injector/MetadataInjector");
14
+ Object.defineProperty(exports, "MetadataInjector", { enumerable: true, get: function () { return MetadataInjector_1.MetadataInjector; } });
15
+ Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return MetadataInjector_1.inject; } });
16
+ var SimpleInjector_1 = require("./injector/SimpleInjector");
17
+ Object.defineProperty(exports, "SimpleInjector", { enumerable: true, get: function () { return SimpleInjector_1.SimpleInjector; } });
18
+ var ProxyInjector_1 = require("./injector/ProxyInjector");
19
+ Object.defineProperty(exports, "ProxyInjector", { enumerable: true, get: function () { return ProxyInjector_1.ProxyInjector; } });
20
+ // Providers
16
21
  var IProvider_1 = require("./provider/IProvider");
17
22
  Object.defineProperty(exports, "provider", { enumerable: true, get: function () { return IProvider_1.provider; } });
18
23
  Object.defineProperty(exports, "visible", { enumerable: true, get: function () { return IProvider_1.visible; } });
@@ -28,21 +33,24 @@ Object.defineProperty(exports, "SingletonProvider", { enumerable: true, get: fun
28
33
  var MultiCache_1 = require("./provider/singleton/MultiCache");
29
34
  Object.defineProperty(exports, "MultiCache", { enumerable: true, get: function () { return MultiCache_1.MultiCache; } });
30
35
  Object.defineProperty(exports, "multiCache", { enumerable: true, get: function () { return MultiCache_1.multiCache; } });
31
- var AutoMockedContainer_1 = require("./container/AutoMockedContainer");
32
- Object.defineProperty(exports, "AutoMockedContainer", { enumerable: true, get: function () { return AutoMockedContainer_1.AutoMockedContainer; } });
36
+ var LazyProvider_1 = require("./provider/LazyProvider");
37
+ Object.defineProperty(exports, "LazyProvider", { enumerable: true, get: function () { return LazyProvider_1.LazyProvider; } });
38
+ Object.defineProperty(exports, "lazy", { enumerable: true, get: function () { return LazyProvider_1.lazy; } });
39
+ // Registrations
33
40
  var IRegistration_1 = require("./registration/IRegistration");
34
41
  Object.defineProperty(exports, "key", { enumerable: true, get: function () { return IRegistration_1.key; } });
35
42
  Object.defineProperty(exports, "scope", { enumerable: true, get: function () { return IRegistration_1.scope; } });
36
43
  Object.defineProperty(exports, "register", { enumerable: true, get: function () { return IRegistration_1.register; } });
37
44
  var Registration_1 = require("./registration/Registration");
38
45
  Object.defineProperty(exports, "Registration", { enumerable: true, get: function () { return Registration_1.Registration; } });
39
- var MetadataInjector_1 = require("./injector/MetadataInjector");
40
- Object.defineProperty(exports, "MetadataInjector", { enumerable: true, get: function () { return MetadataInjector_1.MetadataInjector; } });
41
- Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return MetadataInjector_1.inject; } });
42
- var SimpleInjector_1 = require("./injector/SimpleInjector");
43
- Object.defineProperty(exports, "SimpleInjector", { enumerable: true, get: function () { return SimpleInjector_1.SimpleInjector; } });
44
- var ProxyInjector_1 = require("./injector/ProxyInjector");
45
- Object.defineProperty(exports, "ProxyInjector", { enumerable: true, get: function () { return ProxyInjector_1.ProxyInjector; } });
46
+ // Errors
47
+ var DependencyNotFoundError_1 = require("./errors/DependencyNotFoundError");
48
+ Object.defineProperty(exports, "DependencyNotFoundError", { enumerable: true, get: function () { return DependencyNotFoundError_1.DependencyNotFoundError; } });
49
+ var MethodNotImplementedError_1 = require("./errors/MethodNotImplementedError");
50
+ Object.defineProperty(exports, "MethodNotImplementedError", { enumerable: true, get: function () { return MethodNotImplementedError_1.MethodNotImplementedError; } });
51
+ var ContainerDisposedError_1 = require("./errors/ContainerDisposedError");
52
+ Object.defineProperty(exports, "ContainerDisposedError", { enumerable: true, get: function () { return ContainerDisposedError_1.ContainerDisposedError; } });
53
+ // Others
46
54
  var hook_1 = require("./hook");
47
55
  Object.defineProperty(exports, "getHooks", { enumerable: true, get: function () { return hook_1.getHooks; } });
48
56
  Object.defineProperty(exports, "hook", { enumerable: true, get: function () { return hook_1.hook; } });
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lazy = exports.LazyProvider = void 0;
4
+ const IProvider_1 = require("./IProvider");
5
+ class LazyProvider extends IProvider_1.ProviderDecorator {
6
+ constructor(provider) {
7
+ super(provider);
8
+ this.provider = provider;
9
+ }
10
+ resolve(container, ...args) {
11
+ let instance;
12
+ return new Proxy({}, {
13
+ get: (_, prop) => {
14
+ instance = instance ?? this.provider.resolve(container, ...args);
15
+ // @ts-ignore
16
+ return instance[prop];
17
+ },
18
+ });
19
+ }
20
+ }
21
+ exports.LazyProvider = LazyProvider;
22
+ const lazy = (provider) => new LazyProvider(provider);
23
+ exports.lazy = lazy;
package/esm/index.js CHANGED
@@ -1,19 +1,25 @@
1
+ // Containers
1
2
  export { isDependencyKey, } from './container/IContainer';
2
3
  export { Container } from './container/Container';
3
4
  export { EmptyContainer } from './container/EmptyContainer';
4
- export { DependencyNotFoundError } from './errors/DependencyNotFoundError';
5
- export { MethodNotImplementedError } from './errors/MethodNotImplementedError';
6
- export { ContainerDisposedError } from './errors/ContainerDisposedError';
5
+ export { AutoMockedContainer } from './container/AutoMockedContainer';
6
+ export { MetadataInjector, inject } from './injector/MetadataInjector';
7
+ export { SimpleInjector } from './injector/SimpleInjector';
8
+ export { ProxyInjector } from './injector/ProxyInjector';
9
+ // Providers
7
10
  export { provider, visible, alias, argsFn, args, ProviderDecorator, } from './provider/IProvider';
8
11
  export { Provider } from './provider/Provider';
9
12
  export { singleton, SingletonProvider } from './provider/singleton/SingletonProvider';
10
13
  export { MultiCache, multiCache } from './provider/singleton/MultiCache';
11
- export { AutoMockedContainer } from './container/AutoMockedContainer';
14
+ export { LazyProvider, lazy } from './provider/LazyProvider';
15
+ // Registrations
12
16
  export { key, scope, register } from './registration/IRegistration';
13
17
  export { Registration } from './registration/Registration';
14
- export { MetadataInjector, inject } from './injector/MetadataInjector';
15
- export { SimpleInjector } from './injector/SimpleInjector';
16
- export { ProxyInjector } from './injector/ProxyInjector';
18
+ // Errors
19
+ export { DependencyNotFoundError } from './errors/DependencyNotFoundError';
20
+ export { MethodNotImplementedError } from './errors/MethodNotImplementedError';
21
+ export { ContainerDisposedError } from './errors/ContainerDisposedError';
22
+ // Others
17
23
  export { getHooks, hook, hasHooks } from './hook';
18
24
  export { by, IMemoKey } from './by';
19
25
  export { setMetadata, getMetadata, setParameterMetadata, setMethodMetadata, getMethodMetadata, getParameterMetadata, } from './metadata';
@@ -0,0 +1,18 @@
1
+ import { ProviderDecorator } from './IProvider';
2
+ export class LazyProvider extends ProviderDecorator {
3
+ constructor(provider) {
4
+ super(provider);
5
+ this.provider = provider;
6
+ }
7
+ resolve(container, ...args) {
8
+ let instance;
9
+ return new Proxy({}, {
10
+ get: (_, prop) => {
11
+ instance = instance ?? this.provider.resolve(container, ...args);
12
+ // @ts-ignore
13
+ return instance[prop];
14
+ },
15
+ });
16
+ }
17
+ }
18
+ export const lazy = (provider) => new LazyProvider(provider);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "31.8.0",
3
+ "version": "31.9.0",
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": "fa737f07d8b3f1bf9ab0bd33bbdd00cdcc823293"
62
+ "gitHead": "c0874ed0eb277f524b3aa96ed2a39d626af2ba8b"
63
63
  }
@@ -1,22 +1,23 @@
1
1
  export { IContainer, Resolvable, IContainerModule, isDependencyKey, DependencyKey, InjectionToken, Tag, Tagged, } from './container/IContainer';
2
- export { constructor } from './utils';
3
2
  export { Container } from './container/Container';
4
3
  export { EmptyContainer } from './container/EmptyContainer';
4
+ export { AutoMockedContainer } from './container/AutoMockedContainer';
5
5
  export { IInjector } from './injector/IInjector';
6
- export { DependencyNotFoundError } from './errors/DependencyNotFoundError';
7
- export { MethodNotImplementedError } from './errors/MethodNotImplementedError';
8
- export { ContainerDisposedError } from './errors/ContainerDisposedError';
6
+ export { MetadataInjector, inject } from './injector/MetadataInjector';
7
+ export { SimpleInjector } from './injector/SimpleInjector';
8
+ export { ProxyInjector } from './injector/ProxyInjector';
9
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 { AutoMockedContainer } from './container/AutoMockedContainer';
14
+ export { LazyProvider, lazy } from './provider/LazyProvider';
15
15
  export { key, IRegistration, scope, register } from './registration/IRegistration';
16
16
  export { Registration } from './registration/Registration';
17
- export { MetadataInjector, inject } from './injector/MetadataInjector';
18
- export { SimpleInjector } from './injector/SimpleInjector';
19
- export { ProxyInjector } from './injector/ProxyInjector';
17
+ export { DependencyNotFoundError } from './errors/DependencyNotFoundError';
18
+ export { MethodNotImplementedError } from './errors/MethodNotImplementedError';
19
+ export { ContainerDisposedError } from './errors/ContainerDisposedError';
20
20
  export { getHooks, hook, hasHooks } from './hook';
21
21
  export { by, InstancePredicate, IMemo, IMemoKey } from './by';
22
+ export { constructor } from './utils';
22
23
  export { setMetadata, getMetadata, setParameterMetadata, setMethodMetadata, getMethodMetadata, getParameterMetadata, } from './metadata';
@@ -0,0 +1,8 @@
1
+ import { IProvider, ProviderDecorator } 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, ...args: unknown[]): Instance;
7
+ }
8
+ export declare const lazy: <Instance>(provider: IProvider<Instance>) => LazyProvider<Instance>;