ts-ioc-container 31.10.0 → 32.0.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.
Files changed (40) hide show
  1. package/README.md +6 -4
  2. package/cjm/by.js +26 -36
  3. package/cjm/container/Container.js +18 -12
  4. package/cjm/index.js +3 -2
  5. package/cjm/injector/MetadataInjector.js +1 -1
  6. package/cjm/injector/ProxyInjector.js +1 -1
  7. package/cjm/injector/SimpleInjector.js +1 -1
  8. package/cjm/provider/DecoratorProvider.js +2 -2
  9. package/cjm/provider/IProvider.js +9 -3
  10. package/cjm/provider/LazyProvider.js +6 -12
  11. package/cjm/provider/Provider.js +11 -3
  12. package/cjm/provider/singleton/SingletonProvider.js +3 -3
  13. package/cjm/utils.js +12 -1
  14. package/esm/by.js +26 -36
  15. package/esm/container/Container.js +18 -12
  16. package/esm/index.js +2 -2
  17. package/esm/injector/MetadataInjector.js +1 -1
  18. package/esm/injector/ProxyInjector.js +1 -1
  19. package/esm/injector/SimpleInjector.js +1 -1
  20. package/esm/provider/DecoratorProvider.js +2 -2
  21. package/esm/provider/IProvider.js +7 -2
  22. package/esm/provider/LazyProvider.js +4 -10
  23. package/esm/provider/Provider.js +12 -4
  24. package/esm/provider/singleton/SingletonProvider.js +3 -3
  25. package/esm/utils.js +10 -0
  26. package/package.json +2 -2
  27. package/typings/by.d.ts +16 -7
  28. package/typings/container/Container.d.ts +4 -3
  29. package/typings/container/IContainer.d.ts +1 -0
  30. package/typings/index.d.ts +2 -2
  31. package/typings/injector/IInjector.d.ts +4 -1
  32. package/typings/injector/MetadataInjector.d.ts +2 -2
  33. package/typings/injector/ProxyInjector.d.ts +2 -2
  34. package/typings/injector/SimpleInjector.d.ts +2 -2
  35. package/typings/provider/DecoratorProvider.d.ts +2 -2
  36. package/typings/provider/IProvider.d.ts +10 -3
  37. package/typings/provider/LazyProvider.d.ts +3 -3
  38. package/typings/provider/Provider.d.ts +4 -2
  39. package/typings/provider/singleton/SingletonProvider.d.ts +2 -2
  40. package/typings/utils.d.ts +1 -0
package/README.md CHANGED
@@ -99,7 +99,7 @@ describe('Basic usage', function () {
99
99
 
100
100
  it('should inject multiple dependencies', function () {
101
101
  class App {
102
- constructor(@inject(by.keys('ILogger1', 'ILogger2')) public loggers: Logger[]) {}
102
+ constructor(@inject(by.keys(['ILogger1', 'ILogger2'])) public loggers: Logger[]) {}
103
103
  }
104
104
 
105
105
  const container = new Container(new MetadataInjector())
@@ -770,9 +770,9 @@ describe('alias', () => {
770
770
  .add(R.fromClass(FileLogger))
771
771
  .add(R.fromClass(DbLogger));
772
772
 
773
- const result1 = by.alias((aliases) => aliases.has('ILogger'), constant('ILogger'))(container);
773
+ const result1 = by.alias((aliases) => aliases.has('ILogger'), { memoize: constant('ILogger') })(container);
774
774
  const child = container.createScope('child');
775
- const result2 = by.alias((aliases) => aliases.has('ILogger'), constant('ILogger'))(child);
775
+ const result2 = by.alias((aliases) => aliases.has('ILogger'), { memoize: constant('ILogger') })(child);
776
776
  const result3 = by.alias((aliases) => aliases.has('ILogger'))(child);
777
777
 
778
778
  expect(result1).toBeInstanceOf(FileLogger);
@@ -791,7 +791,9 @@ describe('alias', () => {
791
791
  class DbLogger implements ILogger {}
792
792
 
793
793
  class App {
794
- constructor(@inject(by.aliases((it) => it.has('ILogger'), constant('ILogger'))) public loggers: ILogger[]) {}
794
+ constructor(
795
+ @inject(by.aliases((it) => it.has('ILogger'), { memoize: constant('ILogger') })) public loggers: ILogger[],
796
+ ) {}
795
797
  }
796
798
 
797
799
  const container = new Container(new MetadataInjector())
package/cjm/by.js CHANGED
@@ -5,64 +5,54 @@ const all = () => true;
5
5
  exports.all = all;
6
6
  exports.IMemoKey = Symbol('IMemo');
7
7
  exports.by = {
8
- aliases: (predicate, memoize) => (c, ...args) => {
8
+ aliases: (predicate, { memoize, lazy } = {}) => (c, ...args) => {
9
9
  const predicateFn = (aliases) => predicate(aliases, c);
10
10
  const memoKey = memoize?.(c);
11
- if (memoKey) {
12
- const memo = c.resolve(exports.IMemoKey);
13
- const memoized = memo.get(memoKey);
14
- if (memoized) {
15
- return memoized.map((key) => c.resolve(key, { args }));
16
- }
17
- const result = c.resolveManyByAlias(predicateFn, { args });
18
- memo.set(memoKey, Array.from(result.keys()));
19
- return Array.from(result.values());
11
+ if (memoKey === undefined) {
12
+ return Array.from(c.resolveManyByAlias(predicateFn, { args, lazy }).values());
20
13
  }
21
- return Array.from(c.resolveManyByAlias(predicateFn, { args }).values());
14
+ const memo = c.resolve(exports.IMemoKey);
15
+ const memoized = memo.get(memoKey);
16
+ if (memoized) {
17
+ return memoized.map((key) => c.resolve(key, { args, lazy }));
18
+ }
19
+ const result = c.resolveManyByAlias(predicateFn, { args, lazy });
20
+ memo.set(memoKey, Array.from(result.keys()));
21
+ return Array.from(result.values());
22
22
  },
23
23
  /**
24
24
  * Get the instance that matches the given alias or fail
25
25
  * @param predicate
26
26
  * @param memoize
27
27
  */
28
- alias: (predicate, memoize) => (c, ...args) => {
28
+ alias: (predicate, { memoize, lazy } = {}) => (c, ...args) => {
29
29
  const predicateFn = (aliases) => predicate(aliases, c);
30
30
  const memoKey = memoize?.(c);
31
- if (memoKey) {
32
- const memo = c.resolve(exports.IMemoKey);
33
- const memoized = memo.get(memoKey);
34
- if (memoized) {
35
- return c.resolve(memoized[0], { args });
36
- }
37
- const [key, result] = c.resolveOneByAlias(predicateFn, { args });
38
- memo.set(memoKey, [key]);
39
- return result;
31
+ if (memoKey === undefined) {
32
+ return c.resolveOneByAlias(predicateFn, { args, lazy })[1];
33
+ }
34
+ const memo = c.resolve(exports.IMemoKey);
35
+ const memoized = memo.get(memoKey);
36
+ if (memoized) {
37
+ return c.resolve(memoized[0], { args, lazy });
40
38
  }
41
- return c.resolveOneByAlias(predicateFn, { args })[1];
39
+ const [key, result] = c.resolveOneByAlias(predicateFn, { args, lazy });
40
+ memo.set(memoKey, [key]);
41
+ return result;
42
42
  },
43
43
  /**
44
44
  * Get all instances that match the given keys
45
45
  * @param keys
46
+ * @param lazy
46
47
  */
47
- keys: (...keys) => (с, ...args) => keys.map((t) => с.resolve(t, { args })),
48
+ keys: (keys, { lazy } = {}) => (с, ...args) => keys.map((t) => с.resolve(t, { args, lazy })),
48
49
  /**
49
50
  * Get the instance that matches the given key
50
51
  * @param key
51
52
  * @param deps
53
+ * @param lazy
52
54
  */
53
- key: (key, ...deps) => (c, ...args) => c.resolve(key, { args: [...deps, ...args] }),
54
- lazy: {
55
- key: (key, ...deps) => (c, ...args) => {
56
- let instance;
57
- return new Proxy({}, {
58
- get: (_, prop) => {
59
- instance = instance ?? c.resolve(key, { args: [...deps, ...args] });
60
- // @ts-ignore
61
- return instance[prop];
62
- },
63
- });
64
- },
65
- },
55
+ key: (key, { args: deps = [], lazy } = {}) => (c, ...args) => c.resolve(key, { args: [...deps, ...args], lazy }),
66
56
  /**
67
57
  * Get all instances that match the given predicate
68
58
  * @param predicate
@@ -4,6 +4,7 @@ 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");
7
8
  class Container {
8
9
  constructor(injector, options = {}) {
9
10
  this.injector = injector;
@@ -25,17 +26,22 @@ class Container {
25
26
  this.providers.set(key, provider);
26
27
  return this;
27
28
  }
28
- resolve(token, { args = [], child = this } = {}) {
29
+ resolve(token, { args = [], child = this, lazy } = {}) {
29
30
  this.validateContainer();
30
31
  if ((0, IContainer_1.isConstructor)(token)) {
31
- const instance = this.injector.resolve(this, token, ...args);
32
- this.instances.add(instance);
33
- return instance;
32
+ return lazy
33
+ ? (0, utils_1.lazyInstance)(() => this.resolveByInjector(token, { args }))
34
+ : this.resolveByInjector(token, { args });
34
35
  }
35
36
  const provider = this.providers.get(token);
36
37
  return provider?.isVisible(this, child)
37
- ? provider.resolve(this, ...args)
38
- : this.parent.resolve(token, { args, child });
38
+ ? provider.resolve(this, { args, lazy })
39
+ : this.parent.resolve(token, { args, child, lazy });
40
+ }
41
+ resolveByInjector(token, options) {
42
+ const instance = this.injector.resolve(this, token, options);
43
+ this.instances.add(instance);
44
+ return instance;
39
45
  }
40
46
  createScope(...tags) {
41
47
  this.validateContainer();
@@ -73,21 +79,21 @@ class Container {
73
79
  hasDependency(key) {
74
80
  return this.providers.has(key) ?? this.parent.hasDependency(key);
75
81
  }
76
- resolveManyByAlias(predicate, { args = [], child = this } = {}, result = new Map()) {
82
+ resolveManyByAlias(predicate, { args = [], child = this, lazy } = {}, result = new Map()) {
77
83
  for (const [key, provider] of this.providers.entries()) {
78
84
  if (!result.has(key) && provider.matchAliases(predicate) && provider.isVisible(this, child)) {
79
- result.set(key, provider.resolve(this, ...args));
85
+ result.set(key, provider.resolve(this, { args, lazy }));
80
86
  }
81
87
  }
82
- return this.parent.resolveManyByAlias(predicate, { args, child }, result);
88
+ return this.parent.resolveManyByAlias(predicate, { args, child, lazy }, result);
83
89
  }
84
- resolveOneByAlias(predicate, { args = [], child = this } = {}) {
90
+ resolveOneByAlias(predicate, { args = [], child = this, lazy } = {}) {
85
91
  for (const [key, provider] of this.providers.entries()) {
86
92
  if (provider.matchAliases(predicate) && provider.isVisible(this, child)) {
87
- return [key, provider.resolve(this, ...args)];
93
+ return [key, provider.resolve(this, { args, lazy })];
88
94
  }
89
95
  }
90
- return this.parent.resolveOneByAlias(predicate, { args, child });
96
+ return this.parent.resolveOneByAlias(predicate, { args, child, lazy });
91
97
  }
92
98
  /**
93
99
  * @private
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.lazy = 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;
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;
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,6 +24,7 @@ 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; } });
27
28
  Object.defineProperty(exports, "ProviderDecorator", { enumerable: true, get: function () { return IProvider_1.ProviderDecorator; } });
28
29
  var Provider_1 = require("./provider/Provider");
29
30
  Object.defineProperty(exports, "Provider", { enumerable: true, get: function () { return Provider_1.Provider; } });
@@ -34,7 +35,7 @@ var MultiCache_1 = require("./provider/singleton/MultiCache");
34
35
  Object.defineProperty(exports, "MultiCache", { enumerable: true, get: function () { return MultiCache_1.MultiCache; } });
35
36
  Object.defineProperty(exports, "multiCache", { enumerable: true, get: function () { return MultiCache_1.multiCache; } });
36
37
  var LazyProvider_1 = require("./provider/LazyProvider");
37
- Object.defineProperty(exports, "lazy", { enumerable: true, get: function () { return LazyProvider_1.lazy; } });
38
+ Object.defineProperty(exports, "makeProviderLazy", { enumerable: true, get: function () { return LazyProvider_1.makeProviderLazy; } });
38
39
  var DecoratorProvider_1 = require("./provider/DecoratorProvider");
39
40
  Object.defineProperty(exports, "decorate", { enumerable: true, get: function () { return DecoratorProvider_1.decorate; } });
40
41
  // Registrations
@@ -8,7 +8,7 @@ const getInjectFns = (Target) => (0, metadata_1.getParameterMetadata)(METADATA_K
8
8
  const inject = (fn) => (0, metadata_1.setParameterMetadata)(METADATA_KEY, fn);
9
9
  exports.inject = inject;
10
10
  class MetadataInjector {
11
- resolve(container, Target, ...deps) {
11
+ resolve(container, Target, { args: deps }) {
12
12
  const injectionFns = getInjectFns(Target);
13
13
  const args = (0, utils_1.fillEmptyIndexes)(injectionFns, deps.map(utils_1.constant)).map((fn) => fn(container));
14
14
  return new Target(...args);
@@ -8,7 +8,7 @@ function getProp(target, key) {
8
8
  }
9
9
  class ProxyInjector {
10
10
  // eslint-disable-next-line @typescript-eslint/ban-types
11
- resolve(container, Target, ...deps) {
11
+ resolve(container, Target, { args: deps }) {
12
12
  const args = deps.reduce((acc, it) => ({ ...acc, ...it }), {});
13
13
  const proxy = new Proxy({}, {
14
14
  // eslint-disable-next-line @typescript-eslint/ban-types
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SimpleInjector = void 0;
4
4
  class SimpleInjector {
5
- resolve(container, Target, ...deps) {
5
+ resolve(container, Target, { args: deps }) {
6
6
  return new Target(container, ...deps);
7
7
  }
8
8
  }
@@ -8,8 +8,8 @@ class DecoratorProvider extends IProvider_1.ProviderDecorator {
8
8
  this.provider = provider;
9
9
  this.decorateFn = decorateFn;
10
10
  }
11
- resolve(scope, ...args) {
12
- const dependency = this.provider.resolve(scope, ...args);
11
+ resolve(scope, options) {
12
+ const dependency = this.provider.resolve(scope, options);
13
13
  return this.decorateFn(dependency, scope);
14
14
  }
15
15
  }
@@ -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.argsFn = exports.args = void 0;
3
+ exports.ProviderDecorator = exports.visible = exports.alias = exports.getTransformers = exports.provider = exports.lazy = 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,6 +11,8 @@ 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;
14
16
  const METADATA_KEY = 'provider';
15
17
  const provider = (...mappers) => (0, metadata_1.setMetadata)(METADATA_KEY, mappers);
16
18
  exports.provider = provider;
@@ -31,8 +33,8 @@ class ProviderDecorator {
31
33
  isVisible(parent, child) {
32
34
  return this.decorated.isVisible(parent, child);
33
35
  }
34
- resolve(container, ...args) {
35
- return this.decorated.resolve(container, ...args);
36
+ resolve(container, options) {
37
+ return this.decorated.resolve(container, options);
36
38
  }
37
39
  pipe(...mappers) {
38
40
  return (0, utils_1.pipe)(...mappers)(this);
@@ -48,5 +50,9 @@ class ProviderDecorator {
48
50
  this.decorated.setArgs(argsFn);
49
51
  return this;
50
52
  }
53
+ setLazy(lazy) {
54
+ this.decorated.setLazy(lazy);
55
+ return this;
56
+ }
51
57
  }
52
58
  exports.ProviderDecorator = ProviderDecorator;
@@ -1,23 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.lazy = exports.LazyProvider = void 0;
3
+ exports.makeProviderLazy = exports.LazyProvider = void 0;
4
4
  const IProvider_1 = require("./IProvider");
5
+ const utils_1 = require("../utils");
5
6
  class LazyProvider extends IProvider_1.ProviderDecorator {
6
7
  constructor(provider) {
7
8
  super(provider);
8
9
  this.provider = provider;
9
10
  }
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
- });
11
+ resolve(container, options) {
12
+ return (0, utils_1.lazyInstance)(() => this.provider.resolve(container, options));
19
13
  }
20
14
  }
21
15
  exports.LazyProvider = LazyProvider;
22
- const lazy = (provider) => new LazyProvider(provider);
23
- exports.lazy = lazy;
16
+ const makeProviderLazy = (provider) => new LazyProvider(provider);
17
+ exports.makeProviderLazy = makeProviderLazy;
@@ -6,7 +6,7 @@ const utils_1 = require("../utils");
6
6
  class Provider {
7
7
  static fromClass(Target) {
8
8
  const transformers = (0, IProvider_1.getTransformers)(Target);
9
- return new Provider((container, ...args) => container.resolve(Target, { args })).pipe(...transformers);
9
+ return new Provider((container, options) => container.resolve(Target, options)).pipe(...transformers);
10
10
  }
11
11
  static fromValue(value) {
12
12
  const mappers = (0, utils_1.isConstructor)(value) ? (0, IProvider_1.getTransformers)(value) ?? [] : [];
@@ -16,18 +16,26 @@ class Provider {
16
16
  this.resolveDependency = resolveDependency;
17
17
  this.aliases = new Set();
18
18
  this.argsFn = () => [];
19
+ this.isLazy = false;
19
20
  this.isVisibleWhen = () => true;
20
21
  }
21
22
  pipe(...mappers) {
22
23
  return (0, utils_1.pipe)(...mappers)(this);
23
24
  }
24
- resolve(container, ...args) {
25
- return this.resolveDependency(container, ...this.argsFn(container, ...args), ...args);
25
+ resolve(container, { args, lazy }) {
26
+ return this.resolveDependency(container, {
27
+ args: [...this.argsFn(container, ...args), ...args],
28
+ lazy: lazy ?? this.isLazy ?? false,
29
+ });
26
30
  }
27
31
  setVisibility(predicate) {
28
32
  this.isVisibleWhen = predicate;
29
33
  return this;
30
34
  }
35
+ setLazy(lazy) {
36
+ this.isLazy = lazy;
37
+ return this;
38
+ }
31
39
  setArgs(argsFn) {
32
40
  this.argsFn = argsFn;
33
41
  return this;
@@ -13,10 +13,10 @@ class SingletonProvider extends IProvider_1.ProviderDecorator {
13
13
  this.provider = provider;
14
14
  this.cache = cache;
15
15
  }
16
- resolve(container, ...args) {
17
- const key = this.cache.getKey(...args);
16
+ resolve(container, options) {
17
+ const key = this.cache.getKey(...options.args);
18
18
  if (!this.cache.hasValue(key)) {
19
- this.cache.setValue(key, this.provider.resolve(container, ...args));
19
+ this.cache.setValue(key, this.provider.resolve(container, options));
20
20
  }
21
21
  return this.cache.getValue(key);
22
22
  }
package/cjm/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isConstructor = exports.constant = exports.fillEmptyIndexes = exports.pipe = void 0;
3
+ exports.lazyInstance = exports.isConstructor = exports.constant = exports.fillEmptyIndexes = exports.pipe = void 0;
4
4
  const pipe = (...mappers) => (value) => mappers.reduce((acc, current) => current(acc), value);
5
5
  exports.pipe = pipe;
6
6
  function fillEmptyIndexes(baseArr, insertArr) {
@@ -18,3 +18,14 @@ 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) {
22
+ let instance;
23
+ return new Proxy({}, {
24
+ get: (_, prop) => {
25
+ instance = instance ?? resolveInstance();
26
+ // @ts-ignore
27
+ return instance[prop];
28
+ },
29
+ });
30
+ }
31
+ exports.lazyInstance = lazyInstance;
package/esm/by.js CHANGED
@@ -1,64 +1,54 @@
1
1
  export const all = () => true;
2
2
  export const IMemoKey = Symbol('IMemo');
3
3
  export const by = {
4
- aliases: (predicate, memoize) => (c, ...args) => {
4
+ aliases: (predicate, { memoize, lazy } = {}) => (c, ...args) => {
5
5
  const predicateFn = (aliases) => predicate(aliases, c);
6
6
  const memoKey = memoize?.(c);
7
- if (memoKey) {
8
- const memo = c.resolve(IMemoKey);
9
- const memoized = memo.get(memoKey);
10
- if (memoized) {
11
- return memoized.map((key) => c.resolve(key, { args }));
12
- }
13
- const result = c.resolveManyByAlias(predicateFn, { args });
14
- memo.set(memoKey, Array.from(result.keys()));
15
- return Array.from(result.values());
7
+ if (memoKey === undefined) {
8
+ return Array.from(c.resolveManyByAlias(predicateFn, { args, lazy }).values());
16
9
  }
17
- return Array.from(c.resolveManyByAlias(predicateFn, { args }).values());
10
+ const memo = c.resolve(IMemoKey);
11
+ const memoized = memo.get(memoKey);
12
+ if (memoized) {
13
+ return memoized.map((key) => c.resolve(key, { args, lazy }));
14
+ }
15
+ const result = c.resolveManyByAlias(predicateFn, { args, lazy });
16
+ memo.set(memoKey, Array.from(result.keys()));
17
+ return Array.from(result.values());
18
18
  },
19
19
  /**
20
20
  * Get the instance that matches the given alias or fail
21
21
  * @param predicate
22
22
  * @param memoize
23
23
  */
24
- alias: (predicate, memoize) => (c, ...args) => {
24
+ alias: (predicate, { memoize, lazy } = {}) => (c, ...args) => {
25
25
  const predicateFn = (aliases) => predicate(aliases, c);
26
26
  const memoKey = memoize?.(c);
27
- if (memoKey) {
28
- const memo = c.resolve(IMemoKey);
29
- const memoized = memo.get(memoKey);
30
- if (memoized) {
31
- return c.resolve(memoized[0], { args });
32
- }
33
- const [key, result] = c.resolveOneByAlias(predicateFn, { args });
34
- memo.set(memoKey, [key]);
35
- return result;
27
+ if (memoKey === undefined) {
28
+ return c.resolveOneByAlias(predicateFn, { args, lazy })[1];
29
+ }
30
+ const memo = c.resolve(IMemoKey);
31
+ const memoized = memo.get(memoKey);
32
+ if (memoized) {
33
+ return c.resolve(memoized[0], { args, lazy });
36
34
  }
37
- return c.resolveOneByAlias(predicateFn, { args })[1];
35
+ const [key, result] = c.resolveOneByAlias(predicateFn, { args, lazy });
36
+ memo.set(memoKey, [key]);
37
+ return result;
38
38
  },
39
39
  /**
40
40
  * Get all instances that match the given keys
41
41
  * @param keys
42
+ * @param lazy
42
43
  */
43
- keys: (...keys) => (с, ...args) => keys.map((t) => с.resolve(t, { args })),
44
+ keys: (keys, { lazy } = {}) => (с, ...args) => keys.map((t) => с.resolve(t, { args, lazy })),
44
45
  /**
45
46
  * Get the instance that matches the given key
46
47
  * @param key
47
48
  * @param deps
49
+ * @param lazy
48
50
  */
49
- key: (key, ...deps) => (c, ...args) => c.resolve(key, { args: [...deps, ...args] }),
50
- lazy: {
51
- key: (key, ...deps) => (c, ...args) => {
52
- let instance;
53
- return new Proxy({}, {
54
- get: (_, prop) => {
55
- instance = instance ?? c.resolve(key, { args: [...deps, ...args] });
56
- // @ts-ignore
57
- return instance[prop];
58
- },
59
- });
60
- },
61
- },
51
+ key: (key, { args: deps = [], lazy } = {}) => (c, ...args) => c.resolve(key, { args: [...deps, ...args], lazy }),
62
52
  /**
63
53
  * Get all instances that match the given predicate
64
54
  * @param predicate
@@ -1,6 +1,7 @@
1
1
  import { isConstructor, } from './IContainer';
2
2
  import { EmptyContainer } from './EmptyContainer';
3
3
  import { ContainerDisposedError } from '../errors/ContainerDisposedError';
4
+ import { lazyInstance } from '../utils';
4
5
  export class Container {
5
6
  constructor(injector, options = {}) {
6
7
  this.injector = injector;
@@ -22,17 +23,22 @@ export class Container {
22
23
  this.providers.set(key, provider);
23
24
  return this;
24
25
  }
25
- resolve(token, { args = [], child = this } = {}) {
26
+ resolve(token, { args = [], child = this, lazy } = {}) {
26
27
  this.validateContainer();
27
28
  if (isConstructor(token)) {
28
- const instance = this.injector.resolve(this, token, ...args);
29
- this.instances.add(instance);
30
- return instance;
29
+ return lazy
30
+ ? lazyInstance(() => this.resolveByInjector(token, { args }))
31
+ : this.resolveByInjector(token, { args });
31
32
  }
32
33
  const provider = this.providers.get(token);
33
34
  return provider?.isVisible(this, child)
34
- ? provider.resolve(this, ...args)
35
- : this.parent.resolve(token, { args, child });
35
+ ? provider.resolve(this, { args, lazy })
36
+ : this.parent.resolve(token, { args, child, lazy });
37
+ }
38
+ resolveByInjector(token, options) {
39
+ const instance = this.injector.resolve(this, token, options);
40
+ this.instances.add(instance);
41
+ return instance;
36
42
  }
37
43
  createScope(...tags) {
38
44
  this.validateContainer();
@@ -70,21 +76,21 @@ export class Container {
70
76
  hasDependency(key) {
71
77
  return this.providers.has(key) ?? this.parent.hasDependency(key);
72
78
  }
73
- resolveManyByAlias(predicate, { args = [], child = this } = {}, result = new Map()) {
79
+ resolveManyByAlias(predicate, { args = [], child = this, lazy } = {}, result = new Map()) {
74
80
  for (const [key, provider] of this.providers.entries()) {
75
81
  if (!result.has(key) && provider.matchAliases(predicate) && provider.isVisible(this, child)) {
76
- result.set(key, provider.resolve(this, ...args));
82
+ result.set(key, provider.resolve(this, { args, lazy }));
77
83
  }
78
84
  }
79
- return this.parent.resolveManyByAlias(predicate, { args, child }, result);
85
+ return this.parent.resolveManyByAlias(predicate, { args, child, lazy }, result);
80
86
  }
81
- resolveOneByAlias(predicate, { args = [], child = this } = {}) {
87
+ resolveOneByAlias(predicate, { args = [], child = this, lazy } = {}) {
82
88
  for (const [key, provider] of this.providers.entries()) {
83
89
  if (provider.matchAliases(predicate) && provider.isVisible(this, child)) {
84
- return [key, provider.resolve(this, ...args)];
90
+ return [key, provider.resolve(this, { args, lazy })];
85
91
  }
86
92
  }
87
- return this.parent.resolveOneByAlias(predicate, { args, child });
93
+ return this.parent.resolveOneByAlias(predicate, { args, child, lazy });
88
94
  }
89
95
  /**
90
96
  * @private
package/esm/index.js CHANGED
@@ -7,11 +7,11 @@ 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, ProviderDecorator, } from './provider/IProvider';
10
+ export { provider, visible, alias, argsFn, args, lazy, 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 { lazy } from './provider/LazyProvider';
14
+ export { makeProviderLazy } from './provider/LazyProvider';
15
15
  export { decorate } from './provider/DecoratorProvider';
16
16
  // Registrations
17
17
  export { key, scope, register } from './registration/IRegistration';
@@ -4,7 +4,7 @@ const METADATA_KEY = 'inject';
4
4
  const getInjectFns = (Target) => getParameterMetadata(METADATA_KEY, Target);
5
5
  export const inject = (fn) => setParameterMetadata(METADATA_KEY, fn);
6
6
  export class MetadataInjector {
7
- resolve(container, Target, ...deps) {
7
+ resolve(container, Target, { args: deps }) {
8
8
  const injectionFns = getInjectFns(Target);
9
9
  const args = fillEmptyIndexes(injectionFns, deps.map(constant)).map((fn) => fn(container));
10
10
  return new Target(...args);
@@ -5,7 +5,7 @@ function getProp(target, key) {
5
5
  }
6
6
  export class ProxyInjector {
7
7
  // eslint-disable-next-line @typescript-eslint/ban-types
8
- resolve(container, Target, ...deps) {
8
+ resolve(container, Target, { args: deps }) {
9
9
  const args = deps.reduce((acc, it) => ({ ...acc, ...it }), {});
10
10
  const proxy = new Proxy({}, {
11
11
  // eslint-disable-next-line @typescript-eslint/ban-types
@@ -1,5 +1,5 @@
1
1
  export class SimpleInjector {
2
- resolve(container, Target, ...deps) {
2
+ resolve(container, Target, { args: deps }) {
3
3
  return new Target(container, ...deps);
4
4
  }
5
5
  }
@@ -5,8 +5,8 @@ export class DecoratorProvider extends ProviderDecorator {
5
5
  this.provider = provider;
6
6
  this.decorateFn = decorateFn;
7
7
  }
8
- resolve(scope, ...args) {
9
- const dependency = this.provider.resolve(scope, ...args);
8
+ resolve(scope, options) {
9
+ const dependency = this.provider.resolve(scope, options);
10
10
  return this.decorateFn(dependency, scope);
11
11
  }
12
12
  }
@@ -6,6 +6,7 @@ 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);
9
10
  const METADATA_KEY = 'provider';
10
11
  export const provider = (...mappers) => setMetadata(METADATA_KEY, mappers);
11
12
  export const getTransformers = (Target) => getMetadata(Target, METADATA_KEY) ?? [];
@@ -22,8 +23,8 @@ export class ProviderDecorator {
22
23
  isVisible(parent, child) {
23
24
  return this.decorated.isVisible(parent, child);
24
25
  }
25
- resolve(container, ...args) {
26
- return this.decorated.resolve(container, ...args);
26
+ resolve(container, options) {
27
+ return this.decorated.resolve(container, options);
27
28
  }
28
29
  pipe(...mappers) {
29
30
  return pipe(...mappers)(this);
@@ -39,4 +40,8 @@ export class ProviderDecorator {
39
40
  this.decorated.setArgs(argsFn);
40
41
  return this;
41
42
  }
43
+ setLazy(lazy) {
44
+ this.decorated.setLazy(lazy);
45
+ return this;
46
+ }
42
47
  }
@@ -1,18 +1,12 @@
1
1
  import { ProviderDecorator } from './IProvider';
2
+ import { lazyInstance } from '../utils';
2
3
  export class LazyProvider extends ProviderDecorator {
3
4
  constructor(provider) {
4
5
  super(provider);
5
6
  this.provider = provider;
6
7
  }
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
- });
8
+ resolve(container, options) {
9
+ return lazyInstance(() => this.provider.resolve(container, options));
16
10
  }
17
11
  }
18
- export const lazy = (provider) => new LazyProvider(provider);
12
+ export const makeProviderLazy = (provider) => new LazyProvider(provider);
@@ -1,9 +1,9 @@
1
- import { getTransformers } from './IProvider';
1
+ import { getTransformers, } from './IProvider';
2
2
  import { isConstructor, pipe } from '../utils';
3
3
  export class Provider {
4
4
  static fromClass(Target) {
5
5
  const transformers = getTransformers(Target);
6
- return new Provider((container, ...args) => container.resolve(Target, { args })).pipe(...transformers);
6
+ return new Provider((container, options) => container.resolve(Target, options)).pipe(...transformers);
7
7
  }
8
8
  static fromValue(value) {
9
9
  const mappers = isConstructor(value) ? getTransformers(value) ?? [] : [];
@@ -13,18 +13,26 @@ export class Provider {
13
13
  this.resolveDependency = resolveDependency;
14
14
  this.aliases = new Set();
15
15
  this.argsFn = () => [];
16
+ this.isLazy = false;
16
17
  this.isVisibleWhen = () => true;
17
18
  }
18
19
  pipe(...mappers) {
19
20
  return pipe(...mappers)(this);
20
21
  }
21
- resolve(container, ...args) {
22
- return this.resolveDependency(container, ...this.argsFn(container, ...args), ...args);
22
+ resolve(container, { args, lazy }) {
23
+ return this.resolveDependency(container, {
24
+ args: [...this.argsFn(container, ...args), ...args],
25
+ lazy: lazy ?? this.isLazy ?? false,
26
+ });
23
27
  }
24
28
  setVisibility(predicate) {
25
29
  this.isVisibleWhen = predicate;
26
30
  return this;
27
31
  }
32
+ setLazy(lazy) {
33
+ this.isLazy = lazy;
34
+ return this;
35
+ }
28
36
  setArgs(argsFn) {
29
37
  this.argsFn = argsFn;
30
38
  return this;
@@ -9,10 +9,10 @@ export class SingletonProvider extends ProviderDecorator {
9
9
  this.provider = provider;
10
10
  this.cache = cache;
11
11
  }
12
- resolve(container, ...args) {
13
- const key = this.cache.getKey(...args);
12
+ resolve(container, options) {
13
+ const key = this.cache.getKey(...options.args);
14
14
  if (!this.cache.hasValue(key)) {
15
- this.cache.setValue(key, this.provider.resolve(container, ...args));
15
+ this.cache.setValue(key, this.provider.resolve(container, options));
16
16
  }
17
17
  return this.cache.getValue(key);
18
18
  }
package/esm/utils.js CHANGED
@@ -11,3 +11,13 @@ 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) {
15
+ let instance;
16
+ return new Proxy({}, {
17
+ get: (_, prop) => {
18
+ instance = instance ?? resolveInstance();
19
+ // @ts-ignore
20
+ return instance[prop];
21
+ },
22
+ });
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "31.10.0",
3
+ "version": "32.0.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": "af0d6c1a013ba9289fd62f21b9493719d02a330c"
62
+ "gitHead": "4bdbd1e91d3f7ea7b1b671bc2140d193748ce2a1"
63
63
  }
package/typings/by.d.ts CHANGED
@@ -1,30 +1,39 @@
1
1
  import { DependencyKey, IContainer, InjectionToken } from './container/IContainer';
2
+ import { ProviderResolveOptions } from './provider/IProvider';
2
3
  export type InstancePredicate = (dep: unknown) => boolean;
3
4
  export declare const all: InstancePredicate;
4
5
  export type IMemo = Map<string, DependencyKey[]>;
5
6
  export declare const IMemoKey: unique symbol;
6
7
  export declare const by: {
7
- aliases: (predicate: (it: Set<string>, s: IContainer) => boolean, memoize?: ((c: IContainer) => string) | undefined) => (c: IContainer, ...args: unknown[]) => unknown[];
8
+ aliases: (predicate: (it: Set<string>, s: IContainer) => boolean, { memoize, lazy }?: {
9
+ memoize?: ((c: IContainer) => string) | undefined;
10
+ lazy?: boolean | undefined;
11
+ }) => (c: IContainer, ...args: unknown[]) => unknown[];
8
12
  /**
9
13
  * Get the instance that matches the given alias or fail
10
14
  * @param predicate
11
15
  * @param memoize
12
16
  */
13
- alias: (predicate: (it: Set<string>, s: IContainer) => boolean, memoize?: ((c: IContainer) => string) | undefined) => (c: IContainer, ...args: unknown[]) => unknown;
17
+ alias: (predicate: (it: Set<string>, s: IContainer) => boolean, { memoize, lazy }?: {
18
+ memoize?: ((c: IContainer) => string) | undefined;
19
+ lazy?: boolean | undefined;
20
+ }) => (c: IContainer, ...args: unknown[]) => unknown;
14
21
  /**
15
22
  * Get all instances that match the given keys
16
23
  * @param keys
24
+ * @param lazy
17
25
  */
18
- keys: (...keys: InjectionToken[]) => (с: IContainer, ...args: unknown[]) => unknown[];
26
+ keys: (keys: InjectionToken[], { lazy }?: Pick<ProviderResolveOptions, 'lazy'>) => (с: IContainer, ...args: unknown[]) => unknown[];
19
27
  /**
20
28
  * Get the instance that matches the given key
21
29
  * @param key
22
30
  * @param deps
31
+ * @param lazy
23
32
  */
24
- key: <T>(key: InjectionToken<T>, ...deps: unknown[]) => (c: IContainer, ...args: unknown[]) => T;
25
- lazy: {
26
- key: <T_1 extends object>(key: InjectionToken<T_1>, ...deps: unknown[]) => (c: IContainer, ...args: unknown[]) => T_1;
27
- };
33
+ key: <T>(key: InjectionToken<T>, { args: deps, lazy }?: {
34
+ args?: unknown[] | undefined;
35
+ lazy?: boolean | undefined;
36
+ }) => (c: IContainer, ...args: unknown[]) => T;
28
37
  /**
29
38
  * Get all instances that match the given predicate
30
39
  * @param predicate
@@ -17,15 +17,16 @@ export declare class Container implements IContainer {
17
17
  });
18
18
  add(registration: IRegistration): this;
19
19
  register(key: DependencyKey, provider: IProvider): this;
20
- resolve<T>(token: InjectionToken<T>, { args, child }?: ResolveOptions): T;
20
+ resolve<T>(token: InjectionToken<T>, { args, child, lazy }?: ResolveOptions): T;
21
+ private resolveByInjector;
21
22
  createScope(...tags: Tag[]): Container;
22
23
  dispose(): void;
23
24
  getInstances(): unknown[];
24
25
  hasTag(tag: Tag): boolean;
25
26
  use(module: IContainerModule): this;
26
27
  hasDependency(key: DependencyKey): boolean;
27
- resolveManyByAlias(predicate: AliasPredicate, { args, child }?: ResolveOptions, result?: Map<DependencyKey, unknown>): Map<DependencyKey, unknown>;
28
- resolveOneByAlias<T>(predicate: AliasPredicate, { args, child }?: ResolveOptions): [DependencyKey, T];
28
+ resolveManyByAlias(predicate: AliasPredicate, { args, child, lazy }?: ResolveOptions, result?: Map<DependencyKey, unknown>): Map<DependencyKey, unknown>;
29
+ resolveOneByAlias<T>(predicate: AliasPredicate, { args, child, lazy }?: ResolveOptions): [DependencyKey, T];
29
30
  /**
30
31
  * @private
31
32
  */
@@ -9,6 +9,7 @@ export type InjectionToken<T = unknown> = constructor<T> | DependencyKey;
9
9
  export type ResolveOptions = {
10
10
  args?: unknown[];
11
11
  child?: Tagged;
12
+ lazy?: boolean;
12
13
  };
13
14
  export interface Resolvable {
14
15
  resolve<T>(key: InjectionToken<T>, options?: ResolveOptions): T;
@@ -6,12 +6,12 @@ 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, ProviderDecorator, } from './provider/IProvider';
9
+ export { ResolveDependency, IProvider, provider, visible, alias, argsFn, args, ArgsFn, lazy, 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 { lazy } from './provider/LazyProvider';
14
+ export { makeProviderLazy } from './provider/LazyProvider';
15
15
  export { decorate, DecorateFn } from './provider/DecoratorProvider';
16
16
  export { key, IRegistration, scope, register } from './registration/IRegistration';
17
17
  export { Registration } from './registration/Registration';
@@ -1,5 +1,8 @@
1
1
  import { constructor } from '../utils';
2
2
  import { IContainer } from '../container/IContainer';
3
+ export type InjectOptions = {
4
+ args: unknown[];
5
+ };
3
6
  export interface IInjector {
4
- resolve<T>(container: IContainer, value: constructor<T>, ...deps: unknown[]): T;
7
+ resolve<T>(container: IContainer, value: constructor<T>, options: InjectOptions): T;
5
8
  }
@@ -1,9 +1,9 @@
1
- import { IInjector } from './IInjector';
1
+ import { IInjector, InjectOptions } from './IInjector';
2
2
  import { IContainer } from '../container/IContainer';
3
3
  import { constructor } from '../utils';
4
4
  type InjectFn<T = unknown> = (l: IContainer, ...args: unknown[]) => T;
5
5
  export declare const inject: (fn: InjectFn) => ParameterDecorator;
6
6
  export declare class MetadataInjector implements IInjector {
7
- resolve<T>(container: IContainer, Target: constructor<T>, ...deps: unknown[]): T;
7
+ resolve<T>(container: IContainer, Target: constructor<T>, { args: deps }: InjectOptions): T;
8
8
  }
9
9
  export {};
@@ -1,6 +1,6 @@
1
- import { IInjector } from './IInjector';
1
+ import { IInjector, InjectOptions } from './IInjector';
2
2
  import { IContainer } from '../container/IContainer';
3
3
  import { constructor } from '../utils';
4
4
  export declare class ProxyInjector implements IInjector {
5
- resolve<T>(container: IContainer, Target: constructor<T>, ...deps: object[]): T;
5
+ resolve<T>(container: IContainer, Target: constructor<T>, { args: deps }: InjectOptions): T;
6
6
  }
@@ -1,6 +1,6 @@
1
- import { IInjector } from './IInjector';
1
+ import { IInjector, InjectOptions } from './IInjector';
2
2
  import { IContainer } from '../container/IContainer';
3
3
  import { constructor } from '../utils';
4
4
  export declare class SimpleInjector implements IInjector {
5
- resolve<T>(container: IContainer, Target: constructor<T>, ...deps: unknown[]): T;
5
+ resolve<T>(container: IContainer, Target: constructor<T>, { args: deps }: InjectOptions): T;
6
6
  }
@@ -1,10 +1,10 @@
1
1
  import { IContainer } from '../container/IContainer';
2
- import { IProvider, ProviderDecorator } from './IProvider';
2
+ import { IProvider, ProviderDecorator, ProviderResolveOptions } 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, ...args: unknown[]): Instance;
8
+ resolve(scope: IContainer, options: ProviderResolveOptions): Instance;
9
9
  }
10
10
  export declare const decorate: <Instance>(decorateFn: DecorateFn<Instance>) => (provider: IProvider<Instance>) => DecoratorProvider<Instance>;
@@ -1,6 +1,10 @@
1
1
  import { Alias, AliasPredicate, IContainer, Tagged } from '../container/IContainer';
2
2
  import { constructor, MapFn } from '../utils';
3
- export type ResolveDependency<T = unknown> = (container: IContainer, ...args: unknown[]) => T;
3
+ export type ProviderResolveOptions = {
4
+ args: unknown[];
5
+ lazy?: boolean;
6
+ };
7
+ export type ResolveDependency<T = unknown> = (container: IContainer, options: ProviderResolveOptions) => T;
4
8
  export type ChildrenVisibilityPredicate = (options: {
5
9
  child: Tagged;
6
10
  isParent: boolean;
@@ -8,14 +12,16 @@ export type ChildrenVisibilityPredicate = (options: {
8
12
  export type ArgsFn = (l: IContainer, ...args: unknown[]) => unknown[];
9
13
  export declare function args<T = unknown>(...extraArgs: unknown[]): MapFn<IProvider<T>>;
10
14
  export declare function argsFn<T = unknown>(fn: ArgsFn): MapFn<IProvider<T>>;
15
+ export declare const lazy: <T>(provider: IProvider<T>) => IProvider<T>;
11
16
  export interface IProvider<T = unknown> {
12
- resolve(container: IContainer, ...args: unknown[]): T;
17
+ resolve(container: IContainer, options: ProviderResolveOptions): T;
13
18
  isVisible(parent: Tagged, child: Tagged): boolean;
14
19
  pipe(...mappers: MapFn<IProvider<T>>[]): IProvider<T>;
15
20
  setVisibility(isVisibleWhen: ChildrenVisibilityPredicate): this;
16
21
  setArgs(argsFn: ArgsFn): this;
17
22
  matchAliases(predicate: AliasPredicate): boolean;
18
23
  addAliases(...aliases: Alias[]): this;
24
+ setLazy(lazy: boolean): this;
19
25
  }
20
26
  export declare const provider: (...mappers: MapFn<IProvider>[]) => ClassDecorator;
21
27
  export declare const getTransformers: <T>(Target: constructor<T>) => MapFn<IProvider<T>>[];
@@ -26,9 +32,10 @@ export declare abstract class ProviderDecorator<T> implements IProvider<T> {
26
32
  protected constructor(decorated: IProvider<T>);
27
33
  setVisibility(predicate: ChildrenVisibilityPredicate): this;
28
34
  isVisible(parent: IContainer, child: Tagged): boolean;
29
- resolve(container: IContainer, ...args: unknown[]): T;
35
+ resolve(container: IContainer, options: ProviderResolveOptions): T;
30
36
  pipe(...mappers: MapFn<IProvider<T>>[]): IProvider<T>;
31
37
  matchAliases(predicate: AliasPredicate): boolean;
32
38
  addAliases(...aliases: Alias[]): this;
33
39
  setArgs(argsFn: ArgsFn): this;
40
+ setLazy(lazy: boolean): this;
34
41
  }
@@ -1,8 +1,8 @@
1
- import { IProvider, ProviderDecorator } from './IProvider';
1
+ import { IProvider, ProviderDecorator, ProviderResolveOptions } from './IProvider';
2
2
  import { IContainer } from '../container/IContainer';
3
3
  export declare class LazyProvider<Instance> extends ProviderDecorator<Instance> {
4
4
  private provider;
5
5
  constructor(provider: IProvider<Instance>);
6
- resolve(container: IContainer, ...args: unknown[]): Instance;
6
+ resolve(container: IContainer, options: ProviderResolveOptions): Instance;
7
7
  }
8
- export declare const lazy: <Instance>(provider: IProvider<Instance>) => LazyProvider<Instance>;
8
+ export declare const makeProviderLazy: <Instance>(provider: IProvider<Instance>) => LazyProvider<Instance>;
@@ -1,4 +1,4 @@
1
- import { ArgsFn, ChildrenVisibilityPredicate, IProvider, ResolveDependency } from './IProvider';
1
+ import { ArgsFn, ChildrenVisibilityPredicate, IProvider, ProviderResolveOptions, ResolveDependency } from './IProvider';
2
2
  import { Alias, AliasPredicate, IContainer, Tagged } from '../container/IContainer';
3
3
  import { constructor, MapFn } from '../utils';
4
4
  export declare class Provider<T> implements IProvider<T> {
@@ -7,11 +7,13 @@ 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;
10
11
  private isVisibleWhen;
11
12
  constructor(resolveDependency: ResolveDependency<T>);
12
13
  pipe(...mappers: MapFn<IProvider<T>>[]): IProvider<T>;
13
- resolve(container: IContainer, ...args: unknown[]): T;
14
+ resolve(container: IContainer, { args, lazy }: ProviderResolveOptions): T;
14
15
  setVisibility(predicate: ChildrenVisibilityPredicate): this;
16
+ setLazy(lazy: boolean): this;
15
17
  setArgs(argsFn: ArgsFn): this;
16
18
  isVisible(parent: Tagged, child: Tagged): boolean;
17
19
  matchAliases(predicate: AliasPredicate): boolean;
@@ -1,5 +1,5 @@
1
1
  import { IContainer } from '../../container/IContainer';
2
- import { IProvider, ProviderDecorator } from '../IProvider';
2
+ import { IProvider, ProviderDecorator, ProviderResolveOptions } 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, ...args: unknown[]): T;
10
+ resolve(container: IContainer, options: ProviderResolveOptions): T;
11
11
  }
@@ -4,3 +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;