ts-ioc-container 29.3.0 → 30.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 (36) hide show
  1. package/README.md +23 -20
  2. package/cjm/by.js +20 -2
  3. package/cjm/container/AutoMockedContainer.js +2 -5
  4. package/cjm/container/Container.js +18 -16
  5. package/cjm/container/EmptyContainer.js +2 -5
  6. package/cjm/index.js +3 -3
  7. package/cjm/injector/ProxyInjector.js +1 -1
  8. package/cjm/metadata.js +2 -4
  9. package/cjm/provider/IProvider.js +0 -5
  10. package/cjm/provider/Provider.js +1 -12
  11. package/cjm/provider/ProviderDecorator.js +0 -7
  12. package/cjm/provider/Registration.js +19 -7
  13. package/cjm/provider/SingletonProvider.js +1 -2
  14. package/esm/by.js +17 -1
  15. package/esm/container/AutoMockedContainer.js +2 -5
  16. package/esm/container/Container.js +19 -17
  17. package/esm/container/EmptyContainer.js +2 -5
  18. package/esm/index.js +1 -2
  19. package/esm/injector/ProxyInjector.js +1 -1
  20. package/esm/metadata.js +2 -4
  21. package/esm/provider/IProvider.js +1 -3
  22. package/esm/provider/Provider.js +1 -12
  23. package/esm/provider/ProviderDecorator.js +0 -7
  24. package/esm/provider/Registration.js +15 -5
  25. package/esm/provider/SingletonProvider.js +1 -2
  26. package/package.json +2 -2
  27. package/typings/by.d.ts +4 -3
  28. package/typings/container/AutoMockedContainer.d.ts +2 -2
  29. package/typings/container/Container.d.ts +6 -5
  30. package/typings/container/EmptyContainer.d.ts +2 -3
  31. package/typings/container/IContainer.d.ts +5 -3
  32. package/typings/index.d.ts +2 -2
  33. package/typings/provider/IProvider.d.ts +1 -8
  34. package/typings/provider/Provider.d.ts +1 -4
  35. package/typings/provider/ProviderDecorator.d.ts +1 -3
  36. package/typings/provider/Registration.d.ts +9 -5
package/README.md CHANGED
@@ -142,9 +142,10 @@ import {
142
142
  Registration as R,
143
143
  by,
144
144
  scope,
145
+ register,
145
146
  } from 'ts-ioc-container';
146
147
 
147
- @key('ILogger')
148
+ @register(key('ILogger'))
148
149
  @provider(singleton(), scope((s) => s.hasTag('child')))
149
150
  class Logger {}
150
151
 
@@ -180,10 +181,10 @@ Sometimes you want to get all instances from container and its scopes. For examp
180
181
 
181
182
  ```typescript
182
183
  import 'reflect-metadata';
183
- import { inject, key, Registration as R, Container, MetadataInjector, by } from 'ts-ioc-container';
184
+ import { inject, key, Registration as R, Container, MetadataInjector, by, register } from 'ts-ioc-container';
184
185
 
185
186
  describe('Instances', function () {
186
- @key('ILogger')
187
+ @register(key('ILogger'))
187
188
  class Logger {}
188
189
 
189
190
  it('should return injected instances', () => {
@@ -403,14 +404,14 @@ Sometimes you need to keep dependency key with class together. For example, you
403
404
 
404
405
  ```typescript
405
406
  import 'reflect-metadata';
406
- import { singleton, Container, provider, MetadataInjector, Registration as R, key, scope } from 'ts-ioc-container';
407
+ import { singleton, Container, provider, MetadataInjector, Registration as R, key, scope, register } from 'ts-ioc-container';
407
408
  import { DependencyMissingKeyError } from '../../lib/errors/DependencyMissingKeyError';
408
409
 
409
410
  describe('Registration module', function () {
410
411
  const createContainer = () => new Container(new MetadataInjector(), { tags: ['root'] });
411
412
 
412
413
  it('should register class', function () {
413
- @key('ILogger')
414
+ @register(key('ILogger'))
414
415
  @provider(singleton(), scope((s) => s.hasTag('root')))
415
416
  class Logger {}
416
417
 
@@ -498,9 +499,9 @@ Sometimes you need to create only one instance of dependency per scope. For exam
498
499
 
499
500
  ```typescript
500
501
  import 'reflect-metadata';
501
- import { singleton, Container, key, provider, MetadataInjector, Registration as R } from 'ts-ioc-container';
502
+ import { singleton, Container, key, provider, MetadataInjector, Registration as R, register } from 'ts-ioc-container';
502
503
 
503
- @key('logger')
504
+ @register(key('logger'))
504
505
  @provider(singleton())
505
506
  class Logger {}
506
507
 
@@ -538,9 +539,9 @@ Sometimes you need to resolve provider only from scope which matches to certain
538
539
 
539
540
  ```typescript
540
541
  import 'reflect-metadata';
541
- import { singleton, Container, key, provider, MetadataInjector, Registration as R, scope } from 'ts-ioc-container';
542
+ import { singleton, Container, key, provider, MetadataInjector, Registration as R, scope, register } from 'ts-ioc-container';
542
543
 
543
- @key('ILogger')
544
+ @register(key('ILogger'))
544
545
  @provider(singleton(), scope((s) => s.hasTag('root'))) // the same as .pipe(singleton(), scope((s) => s.hasTag('root')))
545
546
  class Logger {}
546
547
  describe('ScopeProvider', function () {
@@ -559,9 +560,9 @@ Sometimes you want to bind some arguments to provider. This is what `ArgsProvide
559
560
 
560
561
  ```typescript
561
562
  import 'reflect-metadata';
562
- import { Container, key, argsFn, args, MetadataInjector, Registration as R } from 'ts-ioc-container';
563
+ import { Container, key, argsFn, args, MetadataInjector, Registration as R, register } from 'ts-ioc-container';
563
564
 
564
- @key('logger')
565
+ @register(key('logger'))
565
566
  class Logger {
566
567
  constructor(
567
568
  public name: string,
@@ -608,11 +609,11 @@ Sometimes you want to register the same provider with different keys. This is wh
608
609
 
609
610
  ```typescript
610
611
  import 'reflect-metadata';
611
- import { alias, by, Container, inject, provider, MetadataInjector, Registration as R } from 'ts-ioc-container';
612
+ import { by, Container, inject, MetadataInjector, Registration as R, register, alias } from 'ts-ioc-container';
612
613
 
613
614
  describe('alias', () => {
614
615
  const IMiddlewareKey = 'IMiddleware';
615
- const middleware = provider(alias(IMiddlewareKey));
616
+ const middleware = register(alias(IMiddlewareKey));
616
617
 
617
618
  interface IMiddleware {
618
619
  applyTo(application: IApplication): void;
@@ -640,7 +641,7 @@ describe('alias', () => {
640
641
  it('should resolve by some alias', () => {
641
642
  class App implements IApplication {
642
643
  private appliedMiddleware: Set<string> = new Set();
643
- constructor(@inject(by.provider((d) => d.hasAlias(IMiddlewareKey))) public middleware: IMiddleware[]) {}
644
+ constructor(@inject(by.aliases((it) => it.includes(IMiddlewareKey))) public middleware: IMiddleware[]) {}
644
645
 
645
646
  markMiddlewareAsApplied(name: string): void {
646
647
  this.appliedMiddleware.add(name);
@@ -680,12 +681,12 @@ Sometimes you want to encapsulate registration logic in separate module. This is
680
681
 
681
682
  ```typescript
682
683
  import 'reflect-metadata';
683
- import { IContainerModule, Registration as R, IContainer, key, Container, MetadataInjector } from 'ts-ioc-container';
684
+ import { IContainerModule, Registration as R, IContainer, key, Container, MetadataInjector, register } from 'ts-ioc-container';
684
685
 
685
- @key('ILogger')
686
+ @register(key('ILogger'))
686
687
  class Logger {}
687
688
 
688
- @key('ILogger')
689
+ @register(key('ILogger'))
689
690
  class TestLogger {}
690
691
 
691
692
  class Production implements IContainerModule {
@@ -736,6 +737,7 @@ import {
736
737
  IInjector,
737
738
  MetadataInjector,
738
739
  Registration as R,
740
+ register,
739
741
  } from 'ts-ioc-container';
740
742
 
741
743
  class MyInjector implements IInjector {
@@ -752,7 +754,7 @@ class MyInjector implements IInjector {
752
754
  }
753
755
  }
754
756
 
755
- @key('logger')
757
+ @register(key('logger'))
756
758
  class Logger {
757
759
  isReady = false;
758
760
 
@@ -792,9 +794,10 @@ import {
792
794
  provider,
793
795
  Registration as R,
794
796
  MetadataInjector,
797
+ register,
795
798
  } from 'ts-ioc-container';
796
799
 
797
- @key('logsRepo')
800
+ @register(key('logsRepo'))
798
801
  @provider(singleton())
799
802
  class LogsRepo {
800
803
  savedLogs: string[] = [];
@@ -804,7 +807,7 @@ class LogsRepo {
804
807
  }
805
808
  }
806
809
 
807
- @key('logger')
810
+ @register(key('logger'))
808
811
  class Logger {
809
812
  private messages: string[] = [];
810
813
 
package/cjm/by.js CHANGED
@@ -1,10 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.by = exports.all = void 0;
3
+ exports.by = exports.resolveSilently = exports.isPresent = exports.all = void 0;
4
+ const DependencyNotFoundError_1 = require("./errors/DependencyNotFoundError");
4
5
  const all = () => true;
5
6
  exports.all = all;
7
+ const isPresent = (value) => value !== null && value !== undefined;
8
+ exports.isPresent = isPresent;
9
+ const resolveSilently = (c, ...args) => (key) => {
10
+ try {
11
+ return c.resolve(key, ...args);
12
+ }
13
+ catch (e) {
14
+ if (e instanceof DependencyNotFoundError_1.DependencyNotFoundError) {
15
+ return undefined;
16
+ }
17
+ throw e;
18
+ }
19
+ };
20
+ exports.resolveSilently = resolveSilently;
6
21
  exports.by = {
7
- provider: (predicate) => (c, ...args) => c.getTokensByProvider(predicate).map((t) => c.resolve(t, ...args)),
22
+ aliases: (predicate) => (c, ...args) => c
23
+ .getKeysByAlias(predicate)
24
+ .map((0, exports.resolveSilently)(c, ...args))
25
+ .filter(exports.isPresent),
8
26
  /**
9
27
  * Get all instances that match the given keys
10
28
  * @param keys
@@ -3,15 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AutoMockedContainer = void 0;
4
4
  const index_1 = require("../index");
5
5
  class AutoMockedContainer {
6
- constructor() {
7
- this.tags = [];
6
+ getKeysByAlias(alias) {
7
+ return [];
8
8
  }
9
9
  hasDependency(key) {
10
10
  return false;
11
11
  }
12
- getTokensByProvider() {
13
- return [];
14
- }
15
12
  createScope() {
16
13
  throw new index_1.MethodNotImplementedError();
17
14
  }
@@ -6,18 +6,21 @@ const EmptyContainer_1 = require("./EmptyContainer");
6
6
  const ContainerDisposedError_1 = require("../errors/ContainerDisposedError");
7
7
  class Container {
8
8
  constructor(injector, options = {}) {
9
- var _a, _b;
10
9
  this.injector = injector;
11
10
  this.providers = new Map();
11
+ this.aliases = new Map();
12
12
  this.isDisposed = false;
13
13
  this.scopes = new Set();
14
14
  this.instances = new Set();
15
- this.parent = (_a = options.parent) !== null && _a !== void 0 ? _a : new EmptyContainer_1.EmptyContainer();
16
- this.tags = new Set((_b = options.tags) !== null && _b !== void 0 ? _b : []);
15
+ this.parent = options.parent ?? new EmptyContainer_1.EmptyContainer();
16
+ this.tags = new Set(options.tags ?? []);
17
17
  }
18
- register(key, provider) {
18
+ register(key, provider, aliases) {
19
19
  this.validateContainer();
20
20
  this.providers.set(key, provider);
21
+ if (aliases && aliases.length > 0) {
22
+ this.aliases.set(key, aliases);
23
+ }
21
24
  return this;
22
25
  }
23
26
  resolve(token, ...args) {
@@ -28,16 +31,7 @@ class Container {
28
31
  return instance;
29
32
  }
30
33
  const provider = this.providers.get(token);
31
- return (provider === null || provider === void 0 ? void 0 : provider.isValid(this)) ? provider.resolve(this, ...args) : this.parent.resolve(token, ...args);
32
- }
33
- getTokensByProvider(predicate) {
34
- const keys = new Set(this.parent.getTokensByProvider(predicate));
35
- for (const [key, provider] of this.providers) {
36
- if (predicate(provider)) {
37
- keys.add(key);
38
- }
39
- }
40
- return Array.from(keys);
34
+ return provider?.isValid(this) ? provider.resolve(this, ...args) : this.parent.resolve(token, ...args);
41
35
  }
42
36
  createScope(...tags) {
43
37
  this.validateContainer();
@@ -74,8 +68,16 @@ class Container {
74
68
  return this;
75
69
  }
76
70
  hasDependency(key) {
77
- var _a;
78
- return (_a = this.providers.has(key)) !== null && _a !== void 0 ? _a : this.parent.hasDependency(key);
71
+ return this.providers.has(key) ?? this.parent.hasDependency(key);
72
+ }
73
+ getKeysByAlias(predicate) {
74
+ const result = new Set(this.parent.getKeysByAlias(predicate));
75
+ for (const [key, aliases] of this.aliases.entries()) {
76
+ if (predicate(aliases)) {
77
+ result.add(key);
78
+ }
79
+ }
80
+ return Array.from(result);
79
81
  }
80
82
  /**
81
83
  * @private
@@ -4,15 +4,12 @@ exports.EmptyContainer = void 0;
4
4
  const MethodNotImplementedError_1 = require("../errors/MethodNotImplementedError");
5
5
  const DependencyNotFoundError_1 = require("../errors/DependencyNotFoundError");
6
6
  class EmptyContainer {
7
- constructor() {
8
- this.tags = [];
7
+ getKeysByAlias(alias) {
8
+ return [];
9
9
  }
10
10
  hasDependency(key) {
11
11
  return false;
12
12
  }
13
- getTokensByProvider() {
14
- return [];
15
- }
16
13
  hasTag() {
17
14
  throw new MethodNotImplementedError_1.MethodNotImplementedError();
18
15
  }
package/cjm/index.js CHANGED
@@ -1,14 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setParameterMetadata = exports.getMetadata = exports.setMetadata = exports.by = exports.hook = exports.getHooks = exports.ProxyInjector = exports.SimpleInjector = exports.inject = exports.MetadataInjector = exports.Registration = exports.key = exports.AutoMockedContainer = exports.ScopeProvider = exports.scope = exports.SingletonProvider = exports.singleton = exports.ArgsProvider = exports.args = exports.argsFn = exports.provider = exports.Provider = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.alias = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
3
+ exports.setParameterMetadata = exports.getMetadata = exports.setMetadata = exports.by = exports.hook = exports.getHooks = exports.ProxyInjector = exports.SimpleInjector = exports.inject = exports.MetadataInjector = exports.alias = exports.register = exports.Registration = exports.key = exports.AutoMockedContainer = exports.ScopeProvider = exports.scope = exports.SingletonProvider = exports.singleton = exports.ArgsProvider = exports.args = exports.argsFn = exports.provider = exports.Provider = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
4
4
  var IContainer_1 = require("./container/IContainer");
5
5
  Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
6
6
  var Container_1 = require("./container/Container");
7
7
  Object.defineProperty(exports, "Container", { enumerable: true, get: function () { return Container_1.Container; } });
8
8
  var EmptyContainer_1 = require("./container/EmptyContainer");
9
9
  Object.defineProperty(exports, "EmptyContainer", { enumerable: true, get: function () { return EmptyContainer_1.EmptyContainer; } });
10
- var IProvider_1 = require("./provider/IProvider");
11
- Object.defineProperty(exports, "alias", { enumerable: true, get: function () { return IProvider_1.alias; } });
12
10
  var DependencyNotFoundError_1 = require("./errors/DependencyNotFoundError");
13
11
  Object.defineProperty(exports, "DependencyNotFoundError", { enumerable: true, get: function () { return DependencyNotFoundError_1.DependencyNotFoundError; } });
14
12
  var MethodNotImplementedError_1 = require("./errors/MethodNotImplementedError");
@@ -33,6 +31,8 @@ Object.defineProperty(exports, "AutoMockedContainer", { enumerable: true, get: f
33
31
  var Registration_1 = require("./provider/Registration");
34
32
  Object.defineProperty(exports, "key", { enumerable: true, get: function () { return Registration_1.key; } });
35
33
  Object.defineProperty(exports, "Registration", { enumerable: true, get: function () { return Registration_1.Registration; } });
34
+ Object.defineProperty(exports, "register", { enumerable: true, get: function () { return Registration_1.register; } });
35
+ Object.defineProperty(exports, "alias", { enumerable: true, get: function () { return Registration_1.alias; } });
36
36
  var MetadataInjector_1 = require("./injector/MetadataInjector");
37
37
  Object.defineProperty(exports, "MetadataInjector", { enumerable: true, get: function () { return MetadataInjector_1.MetadataInjector; } });
38
38
  Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return MetadataInjector_1.inject; } });
@@ -9,7 +9,7 @@ function getProp(target, key) {
9
9
  class ProxyInjector {
10
10
  // eslint-disable-next-line @typescript-eslint/ban-types
11
11
  resolve(container, Target, ...deps) {
12
- const args = deps.reduce((acc, it) => (Object.assign(Object.assign({}, acc), it)), {});
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
15
15
  get(target, prop) {
package/cjm/metadata.js CHANGED
@@ -11,14 +11,12 @@ function getMetadata(target, key) {
11
11
  }
12
12
  exports.getMetadata = getMetadata;
13
13
  const setParameterMetadata = (key, value) => (target, propertyKey, parameterIndex) => {
14
- var _a;
15
- const metadata = (_a = Reflect.getOwnMetadata(key, target)) !== null && _a !== void 0 ? _a : [];
14
+ const metadata = Reflect.getOwnMetadata(key, target) ?? [];
16
15
  metadata[parameterIndex] = value;
17
16
  Reflect.defineMetadata(key, metadata, target);
18
17
  };
19
18
  exports.setParameterMetadata = setParameterMetadata;
20
19
  const getParameterMetadata = (key, target) => {
21
- var _a;
22
- return (_a = Reflect.getOwnMetadata(key, target)) !== null && _a !== void 0 ? _a : [];
20
+ return Reflect.getOwnMetadata(key, target) ?? [];
23
21
  };
24
22
  exports.getParameterMetadata = getParameterMetadata;
@@ -1,7 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.alias = void 0;
4
- function alias(...tokens) {
5
- return (provider) => provider.addAliases(...tokens);
6
- }
7
- exports.alias = alias;
@@ -8,8 +8,7 @@ const provider = (...mappers) => (0, metadata_1.setMetadata)(PROVIDER_KEY, mappe
8
8
  exports.provider = provider;
9
9
  class Provider {
10
10
  static fromClass(Target) {
11
- var _a;
12
- const mappers = (_a = (0, metadata_1.getMetadata)(Target, PROVIDER_KEY)) !== null && _a !== void 0 ? _a : [];
11
+ const mappers = (0, metadata_1.getMetadata)(Target, PROVIDER_KEY) ?? [];
13
12
  return new Provider((container, ...args) => container.resolve(Target, ...args)).pipe(...mappers);
14
13
  }
15
14
  static fromValue(value) {
@@ -17,20 +16,10 @@ class Provider {
17
16
  }
18
17
  constructor(resolveDependency) {
19
18
  this.resolveDependency = resolveDependency;
20
- this.aliases = new Set();
21
19
  }
22
20
  pipe(...mappers) {
23
21
  return (0, utils_1.pipe)(...mappers)(this);
24
22
  }
25
- addAliases(...aliases) {
26
- for (const alias of aliases) {
27
- this.aliases.add(alias);
28
- }
29
- return this;
30
- }
31
- hasAlias(alias) {
32
- return this.aliases.has(alias);
33
- }
34
23
  clone() {
35
24
  return new Provider(this.resolveDependency);
36
25
  }
@@ -6,13 +6,6 @@ class ProviderDecorator {
6
6
  constructor(decorated) {
7
7
  this.decorated = decorated;
8
8
  }
9
- addAliases(...aliases) {
10
- this.decorated.addAliases(...aliases);
11
- return this;
12
- }
13
- hasAlias(alias) {
14
- return this.decorated.hasAlias(alias);
15
- }
16
9
  isValid(container) {
17
10
  return this.decorated.isValid(container);
18
11
  }
@@ -1,16 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Registration = exports.key = void 0;
3
+ exports.alias = exports.key = exports.register = exports.Registration = void 0;
4
+ const utils_1 = require("../utils");
4
5
  const metadata_1 = require("../metadata");
5
6
  const Provider_1 = require("./Provider");
6
7
  const DependencyMissingKeyError_1 = require("../errors/DependencyMissingKeyError");
7
8
  const DEPENDENCY_KEY = 'DEPENDENCY_KEY';
8
- const key = (value) => (0, metadata_1.setMetadata)(DEPENDENCY_KEY, value);
9
- exports.key = key;
10
9
  class Registration {
11
10
  static fromClass(Target) {
12
- const dependencyKey = (0, metadata_1.getMetadata)(Target, DEPENDENCY_KEY);
13
- return new Registration(Provider_1.Provider.fromClass(Target), dependencyKey !== null && dependencyKey !== void 0 ? dependencyKey : Target.name);
11
+ const transform = (0, utils_1.pipe)(...((0, metadata_1.getMetadata)(Target, DEPENDENCY_KEY) ?? []));
12
+ return transform(new Registration(Provider_1.Provider.fromClass(Target), Target.name));
14
13
  }
15
14
  static fromValue(value) {
16
15
  return new Registration(Provider_1.Provider.fromValue(value));
@@ -18,14 +17,21 @@ class Registration {
18
17
  static fromFn(fn) {
19
18
  return new Registration(new Provider_1.Provider(fn));
20
19
  }
21
- constructor(provider, key) {
20
+ constructor(provider, key, aliases = []) {
22
21
  this.provider = provider;
23
22
  this.key = key;
23
+ this.aliases = aliases;
24
24
  }
25
25
  to(key) {
26
26
  this.key = key;
27
27
  return this;
28
28
  }
29
+ addAliases(...aliases) {
30
+ for (const alias of aliases) {
31
+ this.aliases.push(alias);
32
+ }
33
+ return this;
34
+ }
29
35
  pipe(...mappers) {
30
36
  this.provider = this.provider.pipe(...mappers);
31
37
  return this;
@@ -34,7 +40,13 @@ class Registration {
34
40
  if (!this.key) {
35
41
  throw new DependencyMissingKeyError_1.DependencyMissingKeyError('No key provided for registration');
36
42
  }
37
- container.register(this.key, this.provider);
43
+ container.register(this.key, this.provider, this.aliases);
38
44
  }
39
45
  }
40
46
  exports.Registration = Registration;
47
+ const register = (...mappers) => (0, metadata_1.setMetadata)(DEPENDENCY_KEY, mappers);
48
+ exports.register = register;
49
+ const key = (key) => (r) => r.to(key);
50
+ exports.key = key;
51
+ const alias = (...aliases) => (r) => r.addAliases(...aliases);
52
+ exports.alias = alias;
@@ -15,8 +15,7 @@ class SingletonProvider extends ProviderDecorator_1.ProviderDecorator {
15
15
  return new SingletonProvider(this.provider.clone());
16
16
  }
17
17
  resolve(container, ...args) {
18
- var _a;
19
- this.instance = (_a = this.instance) !== null && _a !== void 0 ? _a : { value: this.provider.resolve(container, ...args) };
18
+ this.instance = this.instance ?? { value: this.provider.resolve(container, ...args) };
20
19
  return this.instance.value;
21
20
  }
22
21
  }
package/esm/by.js CHANGED
@@ -1,6 +1,22 @@
1
+ import { DependencyNotFoundError } from './errors/DependencyNotFoundError';
1
2
  export const all = () => true;
3
+ export const isPresent = (value) => value !== null && value !== undefined;
4
+ export const resolveSilently = (c, ...args) => (key) => {
5
+ try {
6
+ return c.resolve(key, ...args);
7
+ }
8
+ catch (e) {
9
+ if (e instanceof DependencyNotFoundError) {
10
+ return undefined;
11
+ }
12
+ throw e;
13
+ }
14
+ };
2
15
  export const by = {
3
- provider: (predicate) => (c, ...args) => c.getTokensByProvider(predicate).map((t) => c.resolve(t, ...args)),
16
+ aliases: (predicate) => (c, ...args) => c
17
+ .getKeysByAlias(predicate)
18
+ .map(resolveSilently(c, ...args))
19
+ .filter(isPresent),
4
20
  /**
5
21
  * Get all instances that match the given keys
6
22
  * @param keys
@@ -1,14 +1,11 @@
1
1
  import { MethodNotImplementedError } from '../index';
2
2
  export class AutoMockedContainer {
3
- constructor() {
4
- this.tags = [];
3
+ getKeysByAlias(alias) {
4
+ return [];
5
5
  }
6
6
  hasDependency(key) {
7
7
  return false;
8
8
  }
9
- getTokensByProvider() {
10
- return [];
11
- }
12
9
  createScope() {
13
10
  throw new MethodNotImplementedError();
14
11
  }
@@ -1,20 +1,23 @@
1
- import { isConstructor } from './IContainer';
1
+ import { isConstructor, } from './IContainer';
2
2
  import { EmptyContainer } from './EmptyContainer';
3
3
  import { ContainerDisposedError } from '../errors/ContainerDisposedError';
4
4
  export class Container {
5
5
  constructor(injector, options = {}) {
6
- var _a, _b;
7
6
  this.injector = injector;
8
7
  this.providers = new Map();
8
+ this.aliases = new Map();
9
9
  this.isDisposed = false;
10
10
  this.scopes = new Set();
11
11
  this.instances = new Set();
12
- this.parent = (_a = options.parent) !== null && _a !== void 0 ? _a : new EmptyContainer();
13
- this.tags = new Set((_b = options.tags) !== null && _b !== void 0 ? _b : []);
12
+ this.parent = options.parent ?? new EmptyContainer();
13
+ this.tags = new Set(options.tags ?? []);
14
14
  }
15
- register(key, provider) {
15
+ register(key, provider, aliases) {
16
16
  this.validateContainer();
17
17
  this.providers.set(key, provider);
18
+ if (aliases && aliases.length > 0) {
19
+ this.aliases.set(key, aliases);
20
+ }
18
21
  return this;
19
22
  }
20
23
  resolve(token, ...args) {
@@ -25,16 +28,7 @@ export class Container {
25
28
  return instance;
26
29
  }
27
30
  const provider = this.providers.get(token);
28
- return (provider === null || provider === void 0 ? void 0 : provider.isValid(this)) ? provider.resolve(this, ...args) : this.parent.resolve(token, ...args);
29
- }
30
- getTokensByProvider(predicate) {
31
- const keys = new Set(this.parent.getTokensByProvider(predicate));
32
- for (const [key, provider] of this.providers) {
33
- if (predicate(provider)) {
34
- keys.add(key);
35
- }
36
- }
37
- return Array.from(keys);
31
+ return provider?.isValid(this) ? provider.resolve(this, ...args) : this.parent.resolve(token, ...args);
38
32
  }
39
33
  createScope(...tags) {
40
34
  this.validateContainer();
@@ -71,8 +65,16 @@ export class Container {
71
65
  return this;
72
66
  }
73
67
  hasDependency(key) {
74
- var _a;
75
- return (_a = this.providers.has(key)) !== null && _a !== void 0 ? _a : this.parent.hasDependency(key);
68
+ return this.providers.has(key) ?? this.parent.hasDependency(key);
69
+ }
70
+ getKeysByAlias(predicate) {
71
+ const result = new Set(this.parent.getKeysByAlias(predicate));
72
+ for (const [key, aliases] of this.aliases.entries()) {
73
+ if (predicate(aliases)) {
74
+ result.add(key);
75
+ }
76
+ }
77
+ return Array.from(result);
76
78
  }
77
79
  /**
78
80
  * @private
@@ -1,15 +1,12 @@
1
1
  import { MethodNotImplementedError } from '../errors/MethodNotImplementedError';
2
2
  import { DependencyNotFoundError } from '../errors/DependencyNotFoundError';
3
3
  export class EmptyContainer {
4
- constructor() {
5
- this.tags = [];
4
+ getKeysByAlias(alias) {
5
+ return [];
6
6
  }
7
7
  hasDependency(key) {
8
8
  return false;
9
9
  }
10
- getTokensByProvider() {
11
- return [];
12
- }
13
10
  hasTag() {
14
11
  throw new MethodNotImplementedError();
15
12
  }
package/esm/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  export { isDependencyKey, } from './container/IContainer';
2
2
  export { Container } from './container/Container';
3
3
  export { EmptyContainer } from './container/EmptyContainer';
4
- export { alias } from './provider/IProvider';
5
4
  export { DependencyNotFoundError } from './errors/DependencyNotFoundError';
6
5
  export { MethodNotImplementedError } from './errors/MethodNotImplementedError';
7
6
  export { ContainerDisposedError } from './errors/ContainerDisposedError';
@@ -10,7 +9,7 @@ export { argsFn, args, ArgsProvider } from './provider/ArgsProvider';
10
9
  export { singleton, SingletonProvider } from './provider/SingletonProvider';
11
10
  export { scope, ScopeProvider } from './provider/ScopeProvider';
12
11
  export { AutoMockedContainer } from './container/AutoMockedContainer';
13
- export { key, Registration } from './provider/Registration';
12
+ export { key, Registration, register, alias } from './provider/Registration';
14
13
  export { MetadataInjector, inject } from './injector/MetadataInjector';
15
14
  export { SimpleInjector } from './injector/SimpleInjector';
16
15
  export { ProxyInjector } from './injector/ProxyInjector';
@@ -6,7 +6,7 @@ function getProp(target, key) {
6
6
  export class ProxyInjector {
7
7
  // eslint-disable-next-line @typescript-eslint/ban-types
8
8
  resolve(container, Target, ...deps) {
9
- const args = deps.reduce((acc, it) => (Object.assign(Object.assign({}, acc), it)), {});
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
12
12
  get(target, prop) {
package/esm/metadata.js CHANGED
@@ -6,12 +6,10 @@ export function getMetadata(target, key) {
6
6
  return Reflect.getOwnMetadata(key, target);
7
7
  }
8
8
  export const setParameterMetadata = (key, value) => (target, propertyKey, parameterIndex) => {
9
- var _a;
10
- const metadata = (_a = Reflect.getOwnMetadata(key, target)) !== null && _a !== void 0 ? _a : [];
9
+ const metadata = Reflect.getOwnMetadata(key, target) ?? [];
11
10
  metadata[parameterIndex] = value;
12
11
  Reflect.defineMetadata(key, metadata, target);
13
12
  };
14
13
  export const getParameterMetadata = (key, target) => {
15
- var _a;
16
- return (_a = Reflect.getOwnMetadata(key, target)) !== null && _a !== void 0 ? _a : [];
14
+ return Reflect.getOwnMetadata(key, target) ?? [];
17
15
  };
@@ -1,3 +1 @@
1
- export function alias(...tokens) {
2
- return (provider) => provider.addAliases(...tokens);
3
- }
1
+ export {};
@@ -4,8 +4,7 @@ const PROVIDER_KEY = 'provider';
4
4
  export const provider = (...mappers) => setMetadata(PROVIDER_KEY, mappers);
5
5
  export class Provider {
6
6
  static fromClass(Target) {
7
- var _a;
8
- const mappers = (_a = getMetadata(Target, PROVIDER_KEY)) !== null && _a !== void 0 ? _a : [];
7
+ const mappers = getMetadata(Target, PROVIDER_KEY) ?? [];
9
8
  return new Provider((container, ...args) => container.resolve(Target, ...args)).pipe(...mappers);
10
9
  }
11
10
  static fromValue(value) {
@@ -13,20 +12,10 @@ export class Provider {
13
12
  }
14
13
  constructor(resolveDependency) {
15
14
  this.resolveDependency = resolveDependency;
16
- this.aliases = new Set();
17
15
  }
18
16
  pipe(...mappers) {
19
17
  return pipe(...mappers)(this);
20
18
  }
21
- addAliases(...aliases) {
22
- for (const alias of aliases) {
23
- this.aliases.add(alias);
24
- }
25
- return this;
26
- }
27
- hasAlias(alias) {
28
- return this.aliases.has(alias);
29
- }
30
19
  clone() {
31
20
  return new Provider(this.resolveDependency);
32
21
  }
@@ -3,13 +3,6 @@ export class ProviderDecorator {
3
3
  constructor(decorated) {
4
4
  this.decorated = decorated;
5
5
  }
6
- addAliases(...aliases) {
7
- this.decorated.addAliases(...aliases);
8
- return this;
9
- }
10
- hasAlias(alias) {
11
- return this.decorated.hasAlias(alias);
12
- }
13
6
  isValid(container) {
14
7
  return this.decorated.isValid(container);
15
8
  }
@@ -1,12 +1,12 @@
1
+ import { pipe } from '../utils';
1
2
  import { getMetadata, setMetadata } from '../metadata';
2
3
  import { Provider } from './Provider';
3
4
  import { DependencyMissingKeyError } from '../errors/DependencyMissingKeyError';
4
5
  const DEPENDENCY_KEY = 'DEPENDENCY_KEY';
5
- export const key = (value) => setMetadata(DEPENDENCY_KEY, value);
6
6
  export class Registration {
7
7
  static fromClass(Target) {
8
- const dependencyKey = getMetadata(Target, DEPENDENCY_KEY);
9
- return new Registration(Provider.fromClass(Target), dependencyKey !== null && dependencyKey !== void 0 ? dependencyKey : Target.name);
8
+ const transform = pipe(...(getMetadata(Target, DEPENDENCY_KEY) ?? []));
9
+ return transform(new Registration(Provider.fromClass(Target), Target.name));
10
10
  }
11
11
  static fromValue(value) {
12
12
  return new Registration(Provider.fromValue(value));
@@ -14,14 +14,21 @@ export class Registration {
14
14
  static fromFn(fn) {
15
15
  return new Registration(new Provider(fn));
16
16
  }
17
- constructor(provider, key) {
17
+ constructor(provider, key, aliases = []) {
18
18
  this.provider = provider;
19
19
  this.key = key;
20
+ this.aliases = aliases;
20
21
  }
21
22
  to(key) {
22
23
  this.key = key;
23
24
  return this;
24
25
  }
26
+ addAliases(...aliases) {
27
+ for (const alias of aliases) {
28
+ this.aliases.push(alias);
29
+ }
30
+ return this;
31
+ }
25
32
  pipe(...mappers) {
26
33
  this.provider = this.provider.pipe(...mappers);
27
34
  return this;
@@ -30,6 +37,9 @@ export class Registration {
30
37
  if (!this.key) {
31
38
  throw new DependencyMissingKeyError('No key provided for registration');
32
39
  }
33
- container.register(this.key, this.provider);
40
+ container.register(this.key, this.provider, this.aliases);
34
41
  }
35
42
  }
43
+ export const register = (...mappers) => setMetadata(DEPENDENCY_KEY, mappers);
44
+ export const key = (key) => (r) => r.to(key);
45
+ export const alias = (...aliases) => (r) => r.addAliases(...aliases);
@@ -11,8 +11,7 @@ export class SingletonProvider extends ProviderDecorator {
11
11
  return new SingletonProvider(this.provider.clone());
12
12
  }
13
13
  resolve(container, ...args) {
14
- var _a;
15
- this.instance = (_a = this.instance) !== null && _a !== void 0 ? _a : { value: this.provider.resolve(container, ...args) };
14
+ this.instance = this.instance ?? { value: this.provider.resolve(container, ...args) };
16
15
  return this.instance.value;
17
16
  }
18
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "29.3.0",
3
+ "version": "30.0.0",
4
4
  "description": "Typescript IoC container",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -60,5 +60,5 @@
60
60
  "ts-node": "^10.9.1",
61
61
  "typescript": "5.4.3"
62
62
  },
63
- "gitHead": "0533f30b75ac9adb189e7e67ce181aac87ea95cb"
63
+ "gitHead": "454ff1ea7e43f331cf36f64973d1373d9d87f8a4"
64
64
  }
package/typings/by.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { IContainer, InjectionToken } from './container/IContainer';
2
- import { Aliased } from './provider/IProvider';
1
+ import { AliasPredicate, DependencyKey, IContainer, InjectionToken } from './container/IContainer';
3
2
  export type InstancePredicate = (dep: unknown) => boolean;
4
3
  export declare const all: InstancePredicate;
4
+ export declare const isPresent: <T>(value: T | null | undefined) => value is T;
5
+ export declare const resolveSilently: (c: IContainer, ...args: unknown[]) => (key: DependencyKey) => unknown;
5
6
  export declare const by: {
6
- provider: (predicate: (provider: Aliased) => boolean) => (c: IContainer, ...args: unknown[]) => unknown[];
7
+ aliases: (predicate: AliasPredicate) => (c: IContainer, ...args: unknown[]) => unknown[];
7
8
  /**
8
9
  * Get all instances that match the given keys
9
10
  * @param keys
@@ -1,8 +1,8 @@
1
1
  import { IContainer, InjectionToken, IProvider, DependencyKey } from '../index';
2
+ import { AliasPredicate } from './IContainer';
2
3
  export declare abstract class AutoMockedContainer implements IContainer {
3
- tags: string[];
4
+ getKeysByAlias(alias: AliasPredicate): DependencyKey[];
4
5
  hasDependency(key: string): boolean;
5
- getTokensByProvider(): DependencyKey[];
6
6
  createScope(): IContainer;
7
7
  abstract resolve<T>(key: InjectionToken<T>): T;
8
8
  dispose(): void;
@@ -1,9 +1,10 @@
1
- import { DependencyKey, IContainer, IContainerModule, InjectionToken, Tag } from './IContainer';
1
+ import { Alias, AliasPredicate, DependencyKey, IContainer, IContainerModule, InjectionToken, Tag } from './IContainer';
2
2
  import { IInjector } from '../injector/IInjector';
3
- import { IProvider, ProviderPredicate } from '../provider/IProvider';
3
+ import { IProvider } from '../provider/IProvider';
4
4
  export declare class Container implements IContainer {
5
5
  private readonly injector;
6
- readonly providers: Map<DependencyKey, IProvider<unknown>>;
6
+ private readonly providers;
7
+ private readonly aliases;
7
8
  private tags;
8
9
  private isDisposed;
9
10
  private parent;
@@ -13,15 +14,15 @@ export declare class Container implements IContainer {
13
14
  parent?: IContainer;
14
15
  tags?: Tag[];
15
16
  });
16
- register(key: DependencyKey, provider: IProvider): this;
17
+ register(key: DependencyKey, provider: IProvider, aliases?: Alias[]): this;
17
18
  resolve<T>(token: InjectionToken<T>, ...args: unknown[]): T;
18
- getTokensByProvider(predicate: ProviderPredicate): DependencyKey[];
19
19
  createScope(...tags: Tag[]): Container;
20
20
  dispose(): void;
21
21
  getInstances(): unknown[];
22
22
  hasTag(tag: Tag): boolean;
23
23
  use(...modules: IContainerModule[]): this;
24
24
  hasDependency(key: DependencyKey): boolean;
25
+ getKeysByAlias(predicate: AliasPredicate): DependencyKey[];
25
26
  /**
26
27
  * @private
27
28
  */
@@ -1,9 +1,8 @@
1
- import { DependencyKey, IContainer, IContainerModule, InjectionToken } from './IContainer';
1
+ import { AliasPredicate, DependencyKey, IContainer, IContainerModule, InjectionToken } from './IContainer';
2
2
  import { IProvider } from '../provider/IProvider';
3
3
  export declare class EmptyContainer implements IContainer {
4
- tags: string[];
4
+ getKeysByAlias(alias: AliasPredicate): DependencyKey[];
5
5
  hasDependency(key: string): boolean;
6
- getTokensByProvider(): DependencyKey[];
7
6
  hasTag(): boolean;
8
7
  createScope(): IContainer;
9
8
  dispose(): void;
@@ -1,4 +1,4 @@
1
- import { IProvider, ProviderPredicate } from '../provider/IProvider';
1
+ import { IProvider } from '../provider/IProvider';
2
2
  import { constructor } from '../utils';
3
3
  export type Tag = string;
4
4
  export type DependencyKey = string | symbol;
@@ -14,14 +14,16 @@ export interface IContainerModule {
14
14
  export interface Tagged {
15
15
  hasTag(tag: Tag): boolean;
16
16
  }
17
+ export type Alias = string;
18
+ export type AliasPredicate = (aliases: Alias[]) => boolean;
17
19
  export interface IContainer extends Resolvable, Tagged {
18
20
  createScope(...tags: Tag[]): IContainer;
19
- register(key: DependencyKey, value: IProvider): this;
21
+ register(key: DependencyKey, value: IProvider, aliases?: Alias[]): this;
20
22
  removeScope(child: IContainer): void;
21
23
  getInstances(): unknown[];
22
24
  dispose(): void;
23
25
  use(...modules: IContainerModule[]): this;
24
26
  getAllProviders(): Map<DependencyKey, IProvider>;
25
- getTokensByProvider(predicate: ProviderPredicate): DependencyKey[];
26
27
  hasDependency(key: DependencyKey): boolean;
28
+ getKeysByAlias(alias: AliasPredicate): DependencyKey[];
27
29
  }
@@ -2,7 +2,7 @@ export { IContainer, Resolvable, IContainerModule, isDependencyKey, DependencyKe
2
2
  export { constructor } from './utils';
3
3
  export { Container } from './container/Container';
4
4
  export { EmptyContainer } from './container/EmptyContainer';
5
- export { ResolveDependency, IProvider, alias } from './provider/IProvider';
5
+ export { ResolveDependency, IProvider } from './provider/IProvider';
6
6
  export { IInjector } from './injector/IInjector';
7
7
  export { DependencyNotFoundError } from './errors/DependencyNotFoundError';
8
8
  export { MethodNotImplementedError } from './errors/MethodNotImplementedError';
@@ -12,7 +12,7 @@ export { ArgsFn, argsFn, args, ArgsProvider } from './provider/ArgsProvider';
12
12
  export { singleton, SingletonProvider } from './provider/SingletonProvider';
13
13
  export { scope, ScopeProvider } from './provider/ScopeProvider';
14
14
  export { AutoMockedContainer } from './container/AutoMockedContainer';
15
- export { key, Registration } from './provider/Registration';
15
+ export { key, Registration, register, alias } from './provider/Registration';
16
16
  export { MetadataInjector, inject } from './injector/MetadataInjector';
17
17
  export { SimpleInjector } from './injector/SimpleInjector';
18
18
  export { ProxyInjector } from './injector/ProxyInjector';
@@ -1,16 +1,9 @@
1
1
  import { Resolvable, Tagged } from '../container/IContainer';
2
2
  import { MapFn } from '../utils';
3
3
  export type ResolveDependency<T = unknown> = (container: Resolvable, ...args: unknown[]) => T;
4
- export type Alias = string;
5
- export interface Aliased {
6
- hasAlias(alias: Alias): boolean;
7
- }
8
- export interface IProvider<T = unknown> extends Aliased {
4
+ export interface IProvider<T = unknown> {
9
5
  clone(): IProvider<T>;
10
6
  resolve(container: Resolvable, ...args: unknown[]): T;
11
7
  isValid(container: Tagged): boolean;
12
8
  pipe(...mappers: MapFn<IProvider<T>>[]): IProvider<T>;
13
- addAliases(...aliases: Alias[]): this;
14
9
  }
15
- export type ProviderPredicate = (provider: IProvider) => boolean;
16
- export declare function alias<T = unknown>(...tokens: Alias[]): MapFn<IProvider<T>>;
@@ -1,4 +1,4 @@
1
- import { Alias, IProvider, ResolveDependency } from './IProvider';
1
+ import { IProvider, ResolveDependency } from './IProvider';
2
2
  import { Resolvable } from '../container/IContainer';
3
3
  import { constructor, MapFn } from '../utils';
4
4
  export declare const provider: (...mappers: MapFn<IProvider>[]) => ClassDecorator;
@@ -6,11 +6,8 @@ export declare class Provider<T> implements IProvider<T> {
6
6
  private readonly resolveDependency;
7
7
  static fromClass<T>(Target: constructor<T>): IProvider<T>;
8
8
  static fromValue<T>(value: T): Provider<T>;
9
- private aliases;
10
9
  constructor(resolveDependency: ResolveDependency<T>);
11
10
  pipe(...mappers: MapFn<IProvider<T>>[]): IProvider<T>;
12
- addAliases(...aliases: Alias[]): this;
13
- hasAlias(alias: Alias): boolean;
14
11
  clone(): Provider<T>;
15
12
  resolve(container: Resolvable, ...args: unknown[]): T;
16
13
  isValid(): boolean;
@@ -1,11 +1,9 @@
1
1
  import { Resolvable, Tagged } from '../container/IContainer';
2
- import { Alias, IProvider } from './IProvider';
2
+ import { IProvider } from './IProvider';
3
3
  import { MapFn } from '../utils';
4
4
  export declare abstract class ProviderDecorator<T> implements IProvider<T> {
5
5
  private decorated;
6
6
  protected constructor(decorated: IProvider<T>);
7
- addAliases(...aliases: Alias[]): this;
8
- hasAlias(alias: Alias): boolean;
9
7
  abstract clone(): IProvider<T>;
10
8
  isValid(container: Tagged): boolean;
11
9
  resolve(container: Resolvable, ...args: any[]): T;
@@ -1,15 +1,19 @@
1
- import { DependencyKey, IContainer, IContainerModule } from '../container/IContainer';
1
+ import { Alias, DependencyKey, IContainer, IContainerModule } from '../container/IContainer';
2
2
  import { constructor, MapFn } from '../utils';
3
3
  import { IProvider, ResolveDependency } from './IProvider';
4
- export declare const key: (value: DependencyKey) => ClassDecorator;
5
- export declare class Registration<T> implements IContainerModule {
4
+ export declare class Registration<T = unknown> implements IContainerModule {
6
5
  private provider;
7
6
  private key?;
8
- static fromClass<T>(Target: constructor<T>): Registration<T>;
7
+ private aliases;
8
+ static fromClass<T>(Target: constructor<T>): Registration<unknown>;
9
9
  static fromValue<T>(value: T): Registration<T>;
10
10
  static fromFn<T>(fn: ResolveDependency<T>): Registration<T>;
11
- constructor(provider: IProvider<T>, key?: DependencyKey | undefined);
11
+ constructor(provider: IProvider<T>, key?: DependencyKey | undefined, aliases?: string[]);
12
12
  to(key: DependencyKey): this;
13
+ addAliases(...aliases: Alias[]): this;
13
14
  pipe(...mappers: MapFn<IProvider<T>>[]): this;
14
15
  applyTo(container: IContainer): void;
15
16
  }
17
+ export declare const register: (...mappers: MapFn<Registration>[]) => ClassDecorator;
18
+ export declare const key: (key: DependencyKey) => MapFn<Registration>;
19
+ export declare const alias: (...aliases: Alias[]) => MapFn<Registration>;