ts-ioc-container 41.1.0 → 41.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -84,7 +84,6 @@ And `tsconfig.json` should have next options:
84
84
  ### Basic usage
85
85
 
86
86
  ```typescript
87
- import 'reflect-metadata';
88
87
  import { type IContainer, by, Container, inject, Registration as R } from 'ts-ioc-container';
89
88
 
90
89
  describe('Basic usage', function () {
@@ -125,7 +124,6 @@ Sometimes you need to create a scope of container. For example, when you want to
125
124
  - NOTICE: when you create a scope then we clone ONLY tags-matched providers.
126
125
 
127
126
  ```typescript
128
- import 'reflect-metadata';
129
127
  import {
130
128
  asKey,
131
129
  by,
@@ -173,7 +171,6 @@ Sometimes you want to get all instances from container and its scopes. For examp
173
171
  - you can get instances from container and scope which were created by injector
174
172
 
175
173
  ```typescript
176
- import 'reflect-metadata';
177
174
  import { asKey, by, Container, inject, register, Registration as R } from 'ts-ioc-container';
178
175
 
179
176
  describe('Instances', function () {
@@ -243,7 +240,6 @@ Sometimes you want to dispose container and all its scopes. For example, when yo
243
240
  - when container is disposed then it unregisters all providers and remove all instances
244
241
 
245
242
  ```typescript
246
- import 'reflect-metadata';
247
243
  import { by, Container, ContainerDisposedError, Registration as R } from 'ts-ioc-container';
248
244
 
249
245
  class Logger {}
@@ -369,7 +365,6 @@ This type of injector uses `@inject` decorator to mark where dependencies should
369
365
  Also you can [inject property.](#inject-property)
370
366
 
371
367
  ```typescript
372
- import 'reflect-metadata';
373
368
  import { Container, inject, Registration as R } from 'ts-ioc-container';
374
369
 
375
370
  class Logger {
@@ -404,7 +399,6 @@ describe('Reflection Injector', function () {
404
399
  This type of injector just passes container to constructor with others arguments.
405
400
 
406
401
  ```typescript
407
- import 'reflect-metadata';
408
402
  import { Container, type IContainer, Registration as R, SimpleInjector } from 'ts-ioc-container';
409
403
 
410
404
  describe('SimpleInjector', function () {
@@ -444,7 +438,6 @@ describe('SimpleInjector', function () {
444
438
  This type of injector injects dependencies as dictionary `Record<string, unknown>`.
445
439
 
446
440
  ```typescript
447
- import 'reflect-metadata';
448
441
  import { Container, ProxyInjector, args, Registration as R } from 'ts-ioc-container';
449
442
 
450
443
  describe('ProxyInjector', function () {
@@ -522,7 +515,6 @@ describe('ProxyInjector', function () {
522
515
  mockContainer.addRegistration(R.fromClass(Service).bindToKey('service'));
523
516
 
524
517
  const app = mockContainer.resolveOne(App);
525
- console.log('App loggers:', app.loggers);
526
518
  expect(app.loggers).toBeInstanceOf(Array);
527
519
  expect(app.loggers.length).toBe(1);
528
520
  expect(app.loggers[0]).toBe(mockLogger);
@@ -542,7 +534,6 @@ Provider is dependency factory which creates dependency.
542
534
  - `new Provider((container, ...args) => container.resolve(Logger, {args}))`
543
535
 
544
536
  ```typescript
545
- import 'reflect-metadata';
546
537
  import {
547
538
  args,
548
539
  argsFn,
@@ -752,7 +743,7 @@ describe('Provider', () => {
752
743
  }
753
744
 
754
745
  const root = new Container({ tags: ['root'] }).addRegistration(R.fromClass(Logger));
755
- const main = root.resolveByClass(Main);
746
+ const main = root.resolveClass(Main);
756
747
 
757
748
  expect(isLoggerCreated).toBe(false);
758
749
 
@@ -780,7 +771,7 @@ describe('Provider', () => {
780
771
  }
781
772
 
782
773
  const root = new Container({ tags: ['root'] }).addRegistration(R.fromClass(Logger));
783
- const main = root.resolveByClass(Main);
774
+ const main = root.resolveClass(Main);
784
775
 
785
776
  expect(main.getChannel()).toBe('file');
786
777
  });
@@ -809,7 +800,7 @@ describe('Provider', () => {
809
800
  .addRegistration(R.fromValue('file').bindToKey('channel'))
810
801
  .addRegistration(R.fromClass(Logger));
811
802
 
812
- const main = root.resolveByClass(Main);
803
+ const main = root.resolveClass(Main);
813
804
 
814
805
  expect(main.getChannel()).toBe('file');
815
806
  });
@@ -824,7 +815,6 @@ Sometimes you need to create only one instance of dependency per scope. For exam
824
815
  - NOTICE: if you create a scope 'A' of container 'root' then Logger of A !== Logger of root.
825
816
 
826
817
  ```typescript
827
- import 'reflect-metadata';
828
818
  import { asKey, Container, register, Registration as R, singleton } from 'ts-ioc-container';
829
819
 
830
820
  @register(asKey('logger'), singleton())
@@ -866,19 +856,20 @@ Sometimes you want to bind some arguments to provider. This is what `ArgsProvide
866
856
  - NOTICE: args from this provider has higher priority than args from `resolve` method.
867
857
 
868
858
  ```typescript
869
- import 'reflect-metadata';
870
859
  import {
871
860
  args,
872
861
  argsFn,
873
862
  asKey,
863
+ by,
874
864
  Container,
875
- type DependencyKey,
865
+ depKey,
876
866
  inject,
877
867
  MultiCache,
878
868
  register,
879
869
  Registration as R,
880
870
  singleton,
881
871
  } from 'ts-ioc-container';
872
+ import { resolveByArgs } from '../lib/provider/IProvider';
882
873
 
883
874
  @register(asKey('logger'))
884
875
  class Logger {
@@ -894,7 +885,7 @@ describe('ArgsProvider', function () {
894
885
  }
895
886
 
896
887
  it('can assign argument function to provider', function () {
897
- const root = createContainer().addRegistration(R.fromClass(Logger).pipe(argsFn((container, ...args) => ['name'])));
888
+ const root = createContainer().addRegistration(R.fromClass(Logger).pipe(argsFn(() => ['name'])));
898
889
 
899
890
  const logger = root.createScope().resolveOne<Logger>('logger');
900
891
  expect(logger.name).toBe('name');
@@ -921,25 +912,34 @@ describe('ArgsProvider', function () {
921
912
  name: string;
922
913
  }
923
914
 
924
- @register(asKey('UserRepository'))
915
+ const IUserRepositoryKey = depKey<IRepository>('IUserRepository');
916
+ const ITodoRepositoryKey = depKey<IRepository>('ITodoRepository');
917
+
918
+ @register(IUserRepositoryKey.asKey)
925
919
  class UserRepository implements IRepository {
926
920
  name = 'UserRepository';
927
921
  }
928
922
 
929
- @register(asKey('TodoRepository'))
923
+ @register(ITodoRepositoryKey.asKey)
930
924
  class TodoRepository implements IRepository {
931
925
  name = 'TodoRepository';
932
926
  }
933
927
 
934
- @register(asKey('EntityManager'), argsFn((container, token) => [container.resolveOne(token as DependencyKey)]))
928
+ interface IEntityManager {
929
+ repository: IRepository;
930
+ }
931
+
932
+ const IEntityManagerKey = depKey<IEntityManager>('IEntityManager');
933
+
934
+ @register(IEntityManagerKey.asKey, argsFn(resolveByArgs))
935
935
  class EntityManager {
936
936
  constructor(public repository: IRepository) {}
937
937
  }
938
938
 
939
939
  class Main {
940
940
  constructor(
941
- @inject((s) => s.resolveOne('EntityManager', { args: ['UserRepository'] })) public userEntities: EntityManager,
942
- @inject((s) => s.resolveOne('EntityManager', { args: ['TodoRepository'] })) public todoEntities: EntityManager,
941
+ @inject(by.one(IEntityManagerKey).args(IUserRepositoryKey)) public userEntities: EntityManager,
942
+ @inject(by.one(IEntityManagerKey).args(ITodoRepositoryKey)) public todoEntities: EntityManager,
943
943
  ) {}
944
944
  }
945
945
 
@@ -958,29 +958,34 @@ describe('ArgsProvider', function () {
958
958
  name: string;
959
959
  }
960
960
 
961
- @register(asKey('UserRepository'))
961
+ const IUserRepositoryKey = depKey<IRepository>('IUserRepository');
962
+ const ITodoRepositoryKey = depKey<IRepository>('ITodoRepository');
963
+
964
+ @register(IUserRepositoryKey.asKey)
962
965
  class UserRepository implements IRepository {
963
966
  name = 'UserRepository';
964
967
  }
965
968
 
966
- @register(asKey('TodoRepository'))
969
+ @register(ITodoRepositoryKey.asKey)
967
970
  class TodoRepository implements IRepository {
968
971
  name = 'TodoRepository';
969
972
  }
970
973
 
971
- @register(
972
- asKey('EntityManager'),
973
- argsFn((container, token) => [container.resolveOne(token as DependencyKey)]),
974
- singleton(() => new MultiCache((...args: unknown[]) => args[0] as DependencyKey)),
975
- )
974
+ interface IEntityManager {
975
+ repository: IRepository;
976
+ }
977
+
978
+ const IEntityManagerKey = depKey<IEntityManager>('IEntityManager');
979
+
980
+ @register(IEntityManagerKey.asKey, argsFn(resolveByArgs), singleton(MultiCache.fromFirstArg))
976
981
  class EntityManager {
977
982
  constructor(public repository: IRepository) {}
978
983
  }
979
984
 
980
985
  class Main {
981
986
  constructor(
982
- @inject((s) => s.resolveOne('EntityManager', { args: ['UserRepository'] })) public userEntities: EntityManager,
983
- @inject((s) => s.resolveOne('EntityManager', { args: ['TodoRepository'] })) public todoEntities: EntityManager,
987
+ @inject(by.one(IEntityManagerKey).args(IUserRepositoryKey)) public userEntities: EntityManager,
988
+ @inject(by.one(IEntityManagerKey).args(ITodoRepositoryKey)) public todoEntities: EntityManager,
984
989
  ) {}
985
990
  }
986
991
 
@@ -990,11 +995,11 @@ describe('ArgsProvider', function () {
990
995
  .addRegistration(R.fromClass(TodoRepository));
991
996
  const main = root.resolveOne(Main);
992
997
 
993
- const userRepository = root.resolveOne<EntityManager>('EntityManager', { args: ['UserRepository'] }).repository;
998
+ const userRepository = IEntityManagerKey.resolve(root, { args: [IUserRepositoryKey] }).repository;
994
999
  expect(userRepository).toBeInstanceOf(UserRepository);
995
1000
  expect(main.userEntities.repository).toBe(userRepository);
996
1001
 
997
- const todoRepository = root.resolveOne<EntityManager>('EntityManager', { args: ['TodoRepository'] }).repository;
1002
+ const todoRepository = IEntityManagerKey.resolve(root, { args: [ITodoRepositoryKey] }).repository;
998
1003
  expect(todoRepository).toBeInstanceOf(TodoRepository);
999
1004
  expect(main.todoEntities.repository).toBe(todoRepository);
1000
1005
  });
@@ -1008,7 +1013,6 @@ Sometimes you want to hide dependency if somebody wants to resolve it from certa
1008
1013
  - `Provider.fromClass(Logger).pipe(visible(({ isParent, child }) => isParent || child.hasTag('root')))`
1009
1014
 
1010
1015
  ```typescript
1011
- import 'reflect-metadata';
1012
1016
  import {
1013
1017
  asKey,
1014
1018
  Container,
@@ -1048,7 +1052,6 @@ Alias is needed to group keys
1048
1052
  - `Provider.fromClass(Logger).pipe(alias('logger'))`
1049
1053
 
1050
1054
  ```typescript
1051
- import 'reflect-metadata';
1052
1055
  import { asAlias, by, Container, DependencyNotFoundError, inject, register, Registration as R, scope } from 'ts-ioc-container';
1053
1056
 
1054
1057
  describe('alias', () => {
@@ -1272,7 +1275,6 @@ Sometimes you want to register provider with certain key. This is what `key` is
1272
1275
  - you can assign the same key to different registrations
1273
1276
 
1274
1277
  ```typescript
1275
- import 'reflect-metadata';
1276
1278
  import { asAlias, asKey, Container, register, Registration as R, scope, singleton } from 'ts-ioc-container';
1277
1279
  import { DependencyMissingKeyError } from '../../lib/errors/DependencyMissingKeyError';
1278
1280
 
@@ -1333,7 +1335,6 @@ Sometimes you need to register provider only in scope which matches to certain c
1333
1335
  - `Registration.fromClass(Logger).when((container) => container.hasTag('root'))`
1334
1336
 
1335
1337
  ```typescript
1336
- import 'reflect-metadata';
1337
1338
  import { singleton, Container, Registration as R, scope, register, asKey } from 'ts-ioc-container';
1338
1339
 
1339
1340
  @register(asKey('ILogger'), scope((s) => s.hasTag('root')), singleton())
@@ -1352,7 +1353,6 @@ describe('ScopeProvider', function () {
1352
1353
  Sometimes you want to encapsulate registration logic in separate module. This is what `IContainerModule` is for.
1353
1354
 
1354
1355
  ```typescript
1355
- import 'reflect-metadata';
1356
1356
  import { asKey, Container, type IContainer, type IContainerModule, register, Registration as R } from 'ts-ioc-container';
1357
1357
 
1358
1358
  @register(asKey('ILogger'))
@@ -1398,7 +1398,6 @@ Sometimes you need to invoke methods after construct or dispose of class. This i
1398
1398
 
1399
1399
  ### OnConstruct
1400
1400
  ```typescript
1401
- import 'reflect-metadata';
1402
1401
  import {
1403
1402
  asKey,
1404
1403
  type constructor,
@@ -1453,7 +1452,6 @@ describe('onConstruct', function () {
1453
1452
 
1454
1453
  ### OnDispose
1455
1454
  ```typescript
1456
- import 'reflect-metadata';
1457
1455
  import { asKey, by, Container, hook, inject, register, Registration as R, runHooks, singleton } from 'ts-ioc-container';
1458
1456
 
1459
1457
  @register(asKey('logsRepo'), singleton())
@@ -1552,7 +1550,7 @@ export class MoqContainer extends AutoMockedContainer {
1552
1550
  return this.mocks.get(key) as IMock<T>;
1553
1551
  }
1554
1552
 
1555
- resolveByClass<T>(target: any, options?: { args?: unknown[] }): T {
1553
+ resolveClass<T>(target: any, options?: { args?: unknown[] }): T {
1556
1554
  throw new Error('Method not implemented.');
1557
1555
  }
1558
1556
 
package/cjm/DepKey.js CHANGED
@@ -26,7 +26,7 @@ const depKey = (key) => {
26
26
  }
27
27
  return registration;
28
28
  },
29
- resolve: (s) => s.resolveOne(key),
29
+ resolve: (s, options) => s.resolveOne(key, options),
30
30
  pipe(...values) {
31
31
  mappers.push(...values);
32
32
  return this;
@@ -20,12 +20,14 @@ class Container {
20
20
  onConstruct;
21
21
  onDispose;
22
22
  injector;
23
+ resolveOneStrategy;
23
24
  constructor(options = {}) {
24
25
  this.injector = options.injector ?? new MetadataInjector_1.MetadataInjector();
25
26
  this.parent = options.parent ?? new EmptyContainer_1.EmptyContainer();
26
27
  this.tags = new Set(options.tags ?? []);
27
28
  this.onConstruct = options.onConstruct ?? (() => { });
28
29
  this.onDispose = options.onDispose ?? (() => { });
30
+ this.resolveOneStrategy = options.resolveOneStrategy ?? IContainer_1.DEFAULT_CONTAINER_RESOLVER;
29
31
  }
30
32
  register(key, provider, { aliases = [] } = {}) {
31
33
  this.validateContainer();
@@ -42,7 +44,7 @@ class Container {
42
44
  getRegistrations() {
43
45
  return [...this.parent.getRegistrations(), ...this.registrations];
44
46
  }
45
- resolveByClass(token, { args = [] } = {}) {
47
+ resolveClass(token, { args = [] } = {}) {
46
48
  this.validateContainer();
47
49
  const instance = this.injector.resolve(this, token, { args });
48
50
  this.instances.add(instance);
@@ -50,7 +52,7 @@ class Container {
50
52
  return instance;
51
53
  }
52
54
  resolveOne(keyOrAlias, options) {
53
- return (0, IContainer_1.DEFAULT_CONTAINER_RESOLVER)(this, keyOrAlias, options);
55
+ return this.resolveOneStrategy(this, keyOrAlias, options);
54
56
  }
55
57
  resolveOneByKey(keyOrAlias, { args = [], child = this, lazy } = {}) {
56
58
  this.validateContainer();
@@ -10,7 +10,7 @@ class EmptyContainer {
10
10
  getParent() {
11
11
  return undefined;
12
12
  }
13
- resolveByClass(token, options) {
13
+ resolveClass(token, options) {
14
14
  throw new MethodNotImplementedError_1.MethodNotImplementedError();
15
15
  }
16
16
  getScopes() {
@@ -9,7 +9,7 @@ function isDependencyKey(token) {
9
9
  }
10
10
  const DEFAULT_CONTAINER_RESOLVER = (scope, keyOrAlias, options) => {
11
11
  if ((0, utils_1.isConstructor)(keyOrAlias)) {
12
- return scope.resolveByClass(keyOrAlias, options);
12
+ return scope.resolveClass(keyOrAlias, options);
13
13
  }
14
14
  try {
15
15
  return scope.resolveOneByKey(keyOrAlias, options);
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveArgs = exports.toInjectFn = exports.inject = void 0;
4
+ exports.isInjectBuilder = isInjectBuilder;
4
5
  const metadata_1 = require("../metadata");
5
6
  const utils_1 = require("../utils");
6
7
  const IContainer_1 = require("../container/IContainer");
@@ -17,7 +18,7 @@ const toInjectFn = (target) => {
17
18
  return (s) => target.resolve(s);
18
19
  }
19
20
  if ((0, utils_1.isConstructor)(target)) {
20
- return (scope) => scope.resolveByClass(target);
21
+ return (scope) => scope.resolveClass(target);
21
22
  }
22
23
  if ((0, IContainer_1.isDependencyKey)(target)) {
23
24
  return (scope) => scope.resolveOne(target);
@@ -4,6 +4,9 @@ exports.SingleCache = exports.multiCache = exports.MultiCache = void 0;
4
4
  class MultiCache {
5
5
  getKey;
6
6
  instances = new Map();
7
+ static fromFirstArg() {
8
+ return new MultiCache((key) => key);
9
+ }
7
10
  constructor(getKey = () => '1') {
8
11
  this.getKey = getKey;
9
12
  }
@@ -1,11 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ProviderDecorator = exports.lazy = exports.scopeAccess = exports.argsFn = exports.args = void 0;
3
+ exports.ProviderDecorator = exports.lazy = exports.scopeAccess = exports.resolveByArgs = exports.argsFn = exports.args = void 0;
4
+ const utils_1 = require("../utils");
4
5
  const ProviderPipe_1 = require("./ProviderPipe");
5
6
  const args = (...extraArgs) => (0, ProviderPipe_1.registerPipe)((p) => p.setArgs(() => extraArgs));
6
7
  exports.args = args;
7
8
  const argsFn = (fn) => (0, ProviderPipe_1.registerPipe)((p) => p.setArgs(fn));
8
9
  exports.argsFn = argsFn;
10
+ const resolveByArgs = (s, ...deps) => deps.map((d) => {
11
+ if (utils_1.Is.injectBuilder(d)) {
12
+ return d.resolve(s);
13
+ }
14
+ if (utils_1.Is.constructor(d)) {
15
+ return s.resolveClass(d);
16
+ }
17
+ return d;
18
+ });
19
+ exports.resolveByArgs = resolveByArgs;
9
20
  const scopeAccess = (predicate) => (0, ProviderPipe_1.registerPipe)((p) => p.setAccessPredicate(predicate));
10
21
  exports.scopeAccess = scopeAccess;
11
22
  const lazy = () => (0, ProviderPipe_1.registerPipe)((p) => p.lazy());
@@ -6,7 +6,7 @@ const ProviderPipe_1 = require("./ProviderPipe");
6
6
  class Provider {
7
7
  resolveDependency;
8
8
  static fromClass(Target) {
9
- return new Provider((container, options) => container.resolveByClass(Target, options));
9
+ return new Provider((container, options) => container.resolveClass(Target, options));
10
10
  }
11
11
  static fromValue(value) {
12
12
  return new Provider(() => value);
package/cjm/utils.js CHANGED
@@ -1,11 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Filter = exports.List = exports.promisify = exports.constant = exports.pipe = exports.isConstructor = void 0;
3
+ exports.Is = exports.Filter = exports.List = exports.promisify = exports.constant = exports.pipe = exports.isConstructor = void 0;
4
4
  exports.isInstance = isInstance;
5
5
  exports.fillEmptyIndexes = fillEmptyIndexes;
6
6
  exports.lazyProxy = lazyProxy;
7
+ /**
8
+ * @deprecated Use Is.constructor instead
9
+ */
7
10
  const isConstructor = (T) => typeof T === 'function' && !!T.prototype;
8
11
  exports.isConstructor = isConstructor;
12
+ /**
13
+ * @deprecated Use Is.instance instead
14
+ */
9
15
  function isInstance(target) {
10
16
  return Object.prototype.hasOwnProperty.call(target, 'constructor');
11
17
  }
@@ -44,3 +50,10 @@ exports.Filter = {
44
50
  return (v) => !excludeSet.has(v);
45
51
  },
46
52
  };
53
+ exports.Is = {
54
+ object: (target) => target !== null && typeof target === 'object',
55
+ instance: (target) => Object.prototype.hasOwnProperty.call(target, 'constructor'),
56
+ constructor: (target) => typeof target === 'function' && !!target.prototype,
57
+ dependencyKey: (target) => ['string', 'symbol'].includes(typeof target),
58
+ injectBuilder: (target) => exports.Is.object(target) && 'resolve' in target && typeof target['resolve'] === 'function',
59
+ };
package/esm/DepKey.js CHANGED
@@ -22,7 +22,7 @@ export const depKey = (key) => {
22
22
  }
23
23
  return registration;
24
24
  },
25
- resolve: (s) => s.resolveOne(key),
25
+ resolve: (s, options) => s.resolveOne(key, options),
26
26
  pipe(...values) {
27
27
  mappers.push(...values);
28
28
  return this;
@@ -1,4 +1,4 @@
1
- import { DEFAULT_CONTAINER_RESOLVER as resolveOne, } from './IContainer';
1
+ import { DEFAULT_CONTAINER_RESOLVER, } from './IContainer';
2
2
  import { EmptyContainer } from './EmptyContainer';
3
3
  import { ContainerDisposedError } from '../errors/ContainerDisposedError';
4
4
  import { MetadataInjector } from '../injector/MetadataInjector';
@@ -17,12 +17,14 @@ export class Container {
17
17
  onConstruct;
18
18
  onDispose;
19
19
  injector;
20
+ resolveOneStrategy;
20
21
  constructor(options = {}) {
21
22
  this.injector = options.injector ?? new MetadataInjector();
22
23
  this.parent = options.parent ?? new EmptyContainer();
23
24
  this.tags = new Set(options.tags ?? []);
24
25
  this.onConstruct = options.onConstruct ?? (() => { });
25
26
  this.onDispose = options.onDispose ?? (() => { });
27
+ this.resolveOneStrategy = options.resolveOneStrategy ?? DEFAULT_CONTAINER_RESOLVER;
26
28
  }
27
29
  register(key, provider, { aliases = [] } = {}) {
28
30
  this.validateContainer();
@@ -39,7 +41,7 @@ export class Container {
39
41
  getRegistrations() {
40
42
  return [...this.parent.getRegistrations(), ...this.registrations];
41
43
  }
42
- resolveByClass(token, { args = [] } = {}) {
44
+ resolveClass(token, { args = [] } = {}) {
43
45
  this.validateContainer();
44
46
  const instance = this.injector.resolve(this, token, { args });
45
47
  this.instances.add(instance);
@@ -47,7 +49,7 @@ export class Container {
47
49
  return instance;
48
50
  }
49
51
  resolveOne(keyOrAlias, options) {
50
- return resolveOne(this, keyOrAlias, options);
52
+ return this.resolveOneStrategy(this, keyOrAlias, options);
51
53
  }
52
54
  resolveOneByKey(keyOrAlias, { args = [], child = this, lazy } = {}) {
53
55
  this.validateContainer();
@@ -7,7 +7,7 @@ export class EmptyContainer {
7
7
  getParent() {
8
8
  return undefined;
9
9
  }
10
- resolveByClass(token, options) {
10
+ resolveClass(token, options) {
11
11
  throw new MethodNotImplementedError();
12
12
  }
13
13
  getScopes() {
@@ -5,7 +5,7 @@ export function isDependencyKey(token) {
5
5
  }
6
6
  export const DEFAULT_CONTAINER_RESOLVER = (scope, keyOrAlias, options) => {
7
7
  if (isConstructor(keyOrAlias)) {
8
- return scope.resolveByClass(keyOrAlias, options);
8
+ return scope.resolveClass(keyOrAlias, options);
9
9
  }
10
10
  try {
11
11
  return scope.resolveOneByKey(keyOrAlias, options);
@@ -5,7 +5,7 @@ import { hookMetaKey } from '../hooks/HookContext';
5
5
  export const inject = (fn) => (target, propertyKey, parameterIndex) => {
6
6
  setParameterMetadata(hookMetaKey(propertyKey), toInjectFn(fn))(isInstance(target) ? target.constructor : target, propertyKey, parameterIndex);
7
7
  };
8
- function isInjectBuilder(fn) {
8
+ export function isInjectBuilder(fn) {
9
9
  return 'resolve' in fn && typeof fn['resolve'] === 'function';
10
10
  }
11
11
  export const toInjectFn = (target) => {
@@ -13,7 +13,7 @@ export const toInjectFn = (target) => {
13
13
  return (s) => target.resolve(s);
14
14
  }
15
15
  if (isConstructor(target)) {
16
- return (scope) => scope.resolveByClass(target);
16
+ return (scope) => scope.resolveClass(target);
17
17
  }
18
18
  if (isDependencyKey(target)) {
19
19
  return (scope) => scope.resolveOne(target);
@@ -1,6 +1,9 @@
1
1
  export class MultiCache {
2
2
  getKey;
3
3
  instances = new Map();
4
+ static fromFirstArg() {
5
+ return new MultiCache((key) => key);
6
+ }
4
7
  constructor(getKey = () => '1') {
5
8
  this.getKey = getKey;
6
9
  }
@@ -1,6 +1,16 @@
1
+ import { Is } from '../utils';
1
2
  import { isProviderPipe, registerPipe } from './ProviderPipe';
2
3
  export const args = (...extraArgs) => registerPipe((p) => p.setArgs(() => extraArgs));
3
4
  export const argsFn = (fn) => registerPipe((p) => p.setArgs(fn));
5
+ export const resolveByArgs = (s, ...deps) => deps.map((d) => {
6
+ if (Is.injectBuilder(d)) {
7
+ return d.resolve(s);
8
+ }
9
+ if (Is.constructor(d)) {
10
+ return s.resolveClass(d);
11
+ }
12
+ return d;
13
+ });
4
14
  export const scopeAccess = (predicate) => registerPipe((p) => p.setAccessPredicate(predicate));
5
15
  export const lazy = () => registerPipe((p) => p.lazy());
6
16
  export class ProviderDecorator {
@@ -3,7 +3,7 @@ import { isProviderPipe } from './ProviderPipe';
3
3
  export class Provider {
4
4
  resolveDependency;
5
5
  static fromClass(Target) {
6
- return new Provider((container, options) => container.resolveByClass(Target, options));
6
+ return new Provider((container, options) => container.resolveClass(Target, options));
7
7
  }
8
8
  static fromValue(value) {
9
9
  return new Provider(() => value);
package/esm/utils.js CHANGED
@@ -1,4 +1,10 @@
1
+ /**
2
+ * @deprecated Use Is.constructor instead
3
+ */
1
4
  export const isConstructor = (T) => typeof T === 'function' && !!T.prototype;
5
+ /**
6
+ * @deprecated Use Is.instance instead
7
+ */
2
8
  export function isInstance(target) {
3
9
  return Object.prototype.hasOwnProperty.call(target, 'constructor');
4
10
  }
@@ -34,3 +40,10 @@ export const Filter = {
34
40
  return (v) => !excludeSet.has(v);
35
41
  },
36
42
  };
43
+ export const Is = {
44
+ object: (target) => target !== null && typeof target === 'object',
45
+ instance: (target) => Object.prototype.hasOwnProperty.call(target, 'constructor'),
46
+ constructor: (target) => typeof target === 'function' && !!target.prototype,
47
+ dependencyKey: (target) => ['string', 'symbol'].includes(typeof target),
48
+ injectBuilder: (target) => Is.object(target) && 'resolve' in target && typeof target['resolve'] === 'function',
49
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "41.1.0",
3
+ "version": "41.1.2",
4
4
  "description": "Typescript IoC container",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -15,7 +15,7 @@ export declare abstract class AutoMockedContainer implements IContainer {
15
15
  getRegistrations(): never[];
16
16
  addRegistration(registration: IRegistration): this;
17
17
  abstract resolveMany<T>(alias: DependencyKey, options?: ResolveManyOptions): T[];
18
- abstract resolveByClass<T>(target: constructor<T>, options?: {
18
+ abstract resolveClass<T>(target: constructor<T>, options?: {
19
19
  args?: unknown[];
20
20
  }): T;
21
21
  abstract resolveOneByKey<T>(keyOrAlias: DependencyKey, options?: ResolveOneOptions): T;
@@ -3,6 +3,7 @@ import { type IInjector } from '../injector/IInjector';
3
3
  import { type IProvider } from '../provider/IProvider';
4
4
  import { type IRegistration } from '../registration/IRegistration';
5
5
  import { type constructor } from '../utils';
6
+ type ResolveOneStrategy = <T>(scope: IContainer, keyOrAlias: constructor<T> | DependencyKey, options?: ResolveOneOptions) => T;
6
7
  export declare class Container implements IContainer {
7
8
  isDisposed: boolean;
8
9
  private parent;
@@ -15,17 +16,19 @@ export declare class Container implements IContainer {
15
16
  private readonly onConstruct;
16
17
  private readonly onDispose;
17
18
  private readonly injector;
19
+ private readonly resolveOneStrategy;
18
20
  constructor(options?: {
19
21
  injector?: IInjector;
20
22
  parent?: IContainer;
21
23
  tags?: Tag[];
22
24
  onConstruct?: (instance: Instance, scope: IContainer) => void;
23
25
  onDispose?: (scope: IContainer) => void;
26
+ resolveOneStrategy?: ResolveOneStrategy;
24
27
  });
25
28
  register(key: DependencyKey, provider: IProvider, { aliases }?: RegisterOptions): this;
26
29
  addRegistration(registration: IRegistration): this;
27
30
  getRegistrations(): IRegistration[];
28
- resolveByClass<T>(token: constructor<T>, { args }?: {
31
+ resolveClass<T>(token: constructor<T>, { args }?: {
29
32
  args?: unknown[];
30
33
  }): T;
31
34
  resolveOne<T>(keyOrAlias: constructor<T> | DependencyKey, options?: ResolveOneOptions): T;
@@ -47,3 +50,4 @@ export declare class Container implements IContainer {
47
50
  private validateContainer;
48
51
  private findProviderByKeyOrFail;
49
52
  }
53
+ export {};
@@ -5,7 +5,7 @@ import { type constructor } from '../utils';
5
5
  export declare class EmptyContainer implements IContainer {
6
6
  get isDisposed(): boolean;
7
7
  getParent(): undefined;
8
- resolveByClass<T>(token: constructor<T>, options?: {
8
+ resolveClass<T>(token: constructor<T>, options?: {
9
9
  args?: [];
10
10
  }): T;
11
11
  getScopes(): never[];
@@ -36,10 +36,10 @@ export interface IContainer extends Tagged {
36
36
  register(key: DependencyKey, value: IProvider, options?: RegisterOptions): this;
37
37
  addRegistration(registration: IRegistration): this;
38
38
  getRegistrations(): IRegistration[];
39
- resolveByClass<T>(target: constructor<T>, options?: {
39
+ resolveClass<T>(target: constructor<T>, options?: {
40
40
  args?: unknown[];
41
41
  }): T;
42
- resolveOne<T>(alias: constructor<T> | DependencyKey, options?: ResolveManyOptions): T;
42
+ resolveOne<T>(alias: constructor<T> | DependencyKey, options?: ResolveOneOptions): T;
43
43
  resolveOneByKey<T>(key: DependencyKey, options?: ResolveOneOptions): T;
44
44
  resolveOneByAlias<T>(key: DependencyKey, options?: ResolveOneOptions): T;
45
45
  resolveMany<T>(alias: DependencyKey, options?: ResolveManyOptions): T[];
@@ -1,5 +1,5 @@
1
1
  import { type constructor } from '../utils';
2
- import { type IContainer } from '../container/IContainer';
2
+ import { type IContainer, ResolveOneOptions } from '../container/IContainer';
3
3
  export type InjectOptions = {
4
4
  args: unknown[];
5
5
  };
@@ -7,5 +7,5 @@ export interface IInjector {
7
7
  resolve<T>(container: IContainer, value: constructor<T>, options: InjectOptions): T;
8
8
  }
9
9
  export interface IInjectFnResolver<T> {
10
- resolve(s: IContainer): T;
10
+ resolve(s: IContainer, options?: ResolveOneOptions): T;
11
11
  }
@@ -3,5 +3,6 @@ import { DependencyKey, type IContainer } from '../container/IContainer';
3
3
  import { type InjectFn } from '../hooks/HookContext';
4
4
  import { type IInjectFnResolver } from './IInjector';
5
5
  export declare const inject: <T>(fn: InjectFn<T> | IInjectFnResolver<T> | DependencyKey | constructor<T>) => ParameterDecorator;
6
+ export declare function isInjectBuilder<T>(fn: object): fn is IInjectFnResolver<T>;
6
7
  export declare const toInjectFn: <T>(target: InjectFn<T> | IInjectFnResolver<T> | DependencyKey | constructor<T>) => InjectFn<T>;
7
8
  export declare const resolveArgs: (Target: constructor<unknown>, methodName?: string) => (scope: IContainer, ...deps: unknown[]) => unknown[];
@@ -1,3 +1,4 @@
1
+ import type { DependencyKey } from '../container/IContainer';
1
2
  export interface Cache<K, V> {
2
3
  getKey(...args: unknown[]): K;
3
4
  hasValue(key: K): boolean;
@@ -7,6 +8,7 @@ export interface Cache<K, V> {
7
8
  export declare class MultiCache<K, V> implements Cache<K, V> {
8
9
  readonly getKey: (...args: unknown[]) => K;
9
10
  private instances;
11
+ static fromFirstArg(): MultiCache<DependencyKey, unknown>;
10
12
  constructor(getKey?: (...args: unknown[]) => K);
11
13
  hasValue(token: K): boolean;
12
14
  getValue(token: K): V;
@@ -1,5 +1,5 @@
1
- import type { IContainer, Tagged } from '../container/IContainer';
2
- import type { MapFn } from '../utils';
1
+ import { IContainer, Tagged } from '../container/IContainer';
2
+ import { MapFn } from '../utils';
3
3
  import { ProviderPipe } from './ProviderPipe';
4
4
  export type ProviderResolveOptions = {
5
5
  args: unknown[];
@@ -25,6 +25,7 @@ export interface IProvider<T = any> {
25
25
  }
26
26
  export declare const args: <T>(...extraArgs: unknown[]) => ProviderPipe<T>;
27
27
  export declare const argsFn: <T>(fn: ArgsFn) => ProviderPipe<T>;
28
+ export declare const resolveByArgs: (s: IContainer, ...deps: unknown[]) => unknown[];
28
29
  export declare const scopeAccess: <T>(predicate: ScopeAccessFn) => ProviderPipe<T>;
29
30
  export declare const lazy: <T>() => ProviderPipe<T>;
30
31
  export declare abstract class ProviderDecorator<T> implements IProvider<T> {
@@ -1,8 +1,16 @@
1
+ import { DependencyKey } from './container/IContainer';
2
+ import { IInjectFnResolver } from './injector/IInjector';
1
3
  export type constructor<T> = new (...args: any[]) => T;
4
+ /**
5
+ * @deprecated Use Is.constructor instead
6
+ */
2
7
  export declare const isConstructor: (T: unknown) => T is constructor<unknown>;
3
8
  export interface InstanceOfClass<T = unknown> {
4
9
  new (...args: unknown[]): T;
5
10
  }
11
+ /**
12
+ * @deprecated Use Is.instance instead
13
+ */
6
14
  export declare function isInstance(target: object): target is InstanceOfClass;
7
15
  export type MapFn<T> = (value: T) => T;
8
16
  export declare const pipe: <T>(...mappers: MapFn<T>[]) => MapFn<T>;
@@ -16,3 +24,10 @@ export declare const List: {
16
24
  export declare const Filter: {
17
25
  exclude: <T>(arr: Set<T> | T[]) => (v: T) => boolean;
18
26
  };
27
+ export declare const Is: {
28
+ object: (target: unknown) => target is object;
29
+ instance: (target: unknown) => target is InstanceOfClass;
30
+ constructor: (target: unknown) => target is constructor<unknown>;
31
+ dependencyKey: (target: unknown) => target is DependencyKey;
32
+ injectBuilder: (target: unknown) => target is IInjectFnResolver<unknown>;
33
+ };