ts-ioc-container 32.0.0 → 32.0.2

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
@@ -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
- - [Lazy](#lazy) `lazy`
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
- ### Lazy
814
- Sometimes you want to create dependency only when somebody want to invoke it's method or property. This is what `LazyProvider` is for.
815
- - `@provider(lazy)`
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 { lazy, Container, inject, MetadataInjector, provider, Registration as R, singleton, by } from 'ts-ioc-container';
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 Flag {
823
- isSet = false;
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
- constructor(@inject(by.key('Flag')) private flag: Flag) {
835
- this.flag.set();
934
+ log(message: string) {
935
+ this.logs.push(message);
836
936
  }
837
937
 
838
- greet() {
839
- return 'Hello';
938
+ printLogs() {
939
+ return this.logs.join(',');
840
940
  }
841
941
  }
842
942
 
843
- function createContainer() {
844
- const container = new Container(new MetadataInjector());
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
- it('should not create an instance until method is not invoked', () => {
850
- // Arrange
851
- const container = createContainer();
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
- // Assert
858
- expect(flag.isSet).toBe(false);
859
- });
952
+ class LogRepository implements IRepository {
953
+ constructor(
954
+ private repository: IRepository,
955
+ @inject(by.key('Logger')) private logger: Logger,
956
+ ) {}
860
957
 
861
- it('should create an instance only when some method/property is invoked', () => {
862
- // Arrange
863
- const container = createContainer();
958
+ async save(item: Todo): Promise<void> {
959
+ this.logger.log(item.id);
960
+ return this.repository.save(item);
961
+ }
962
+ }
864
963
 
865
- // Act
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
- // Assert
870
- expect(service.greet()).toBe('Hello');
871
- expect(flag.isSet).toBe(true);
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
- it('should not create instance on every method invoked', () => {
875
- // Arrange
876
- const container = createContainer();
974
+ class App {
975
+ constructor(@inject(by.key('IRepository')) public repository: IRepository) {}
877
976
 
878
- // Act
879
- const service = container.resolve<Service>('Service');
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
- // Assert
882
- expect(service.greet()).toBe('Hello');
883
- expect(service.greet()).toBe('Hello');
884
- expect(container.getInstances().filter((x) => x instanceof Service).length).toBe(1);
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 create instance when property is invoked', () => {
989
+ it('should decorate repo by logger middleware', async () => {
888
990
  // Arrange
889
991
  const container = createContainer();
890
992
 
891
993
  // Act
892
- const service = container.resolve<Service>('Service');
893
- const flag = container.resolve<Flag>('Flag');
994
+ const app = container.resolve(App);
995
+ const logger = container.resolve<Logger>('Logger');
996
+ await app.run();
894
997
 
895
998
  // Assert
896
- expect(service.name).toBe('Service');
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
- return lazy
33
- ? (0, utils_1.lazyInstance)(() => this.resolveByInjector(token, { args }))
34
- : this.resolveByInjector(token, { args });
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.makeProviderLazy = exports.multiCache = exports.MultiCache = exports.SingletonProvider = exports.singleton = exports.Provider = exports.ProviderDecorator = exports.lazy = 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;
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
- resolve(scope, options) {
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.lazy = exports.argsFn = exports.args = void 0;
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.decorated.resolve(container, options);
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;
@@ -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
- resolve(container, options) {
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
- return lazy
30
- ? lazyInstance(() => this.resolveByInjector(token, { args }))
31
- : this.resolveByInjector(token, { args });
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, lazy, ProviderDecorator, } from './provider/IProvider';
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
- resolve(scope, options) {
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.decorated.resolve(container, options);
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
  }
@@ -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
- resolve(container, options) {
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.0",
3
+ "version": "32.0.2",
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": "4bdbd1e91d3f7ea7b1b671bc2140d193748ce2a1"
62
+ "gitHead": "e8102530801f72d298f83a13791649c091c13f9a"
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[];
@@ -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, lazy, ProviderDecorator, } from './provider/IProvider';
9
+ export { ResolveDependency, IProvider, provider, visible, alias, argsFn, args, ArgsFn, ProviderDecorator, InstantDependencyOptions, ProviderResolveOptions, } 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, ProviderResolveOptions } from './IProvider';
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
- resolve(scope: IContainer, options: ProviderResolveOptions): Instance;
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>[]) => ClassDecorator;
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, ProviderResolveOptions } from '../IProvider';
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
- resolve(container: IContainer, options: ProviderResolveOptions): T;
10
+ resolveInstantly(container: IContainer, options: InstantDependencyOptions): T;
11
11
  }
@@ -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>;