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 +38 -40
- package/cjm/DepKey.js +1 -1
- package/cjm/container/Container.js +4 -2
- package/cjm/container/EmptyContainer.js +1 -1
- package/cjm/container/IContainer.js +1 -1
- package/cjm/injector/inject.js +2 -1
- package/cjm/provider/Cache.js +3 -0
- package/cjm/provider/IProvider.js +12 -1
- package/cjm/provider/Provider.js +1 -1
- package/cjm/utils.js +14 -1
- package/esm/DepKey.js +1 -1
- package/esm/container/Container.js +5 -3
- package/esm/container/EmptyContainer.js +1 -1
- package/esm/container/IContainer.js +1 -1
- package/esm/injector/inject.js +2 -2
- package/esm/provider/Cache.js +3 -0
- package/esm/provider/IProvider.js +10 -0
- package/esm/provider/Provider.js +1 -1
- package/esm/utils.js +13 -0
- package/package.json +1 -1
- package/typings/container/AutoMockedContainer.d.ts +1 -1
- package/typings/container/Container.d.ts +5 -1
- package/typings/container/EmptyContainer.d.ts +1 -1
- package/typings/container/IContainer.d.ts +2 -2
- package/typings/injector/IInjector.d.ts +2 -2
- package/typings/injector/inject.d.ts +1 -0
- package/typings/provider/Cache.d.ts +2 -0
- package/typings/provider/IProvider.d.ts +3 -2
- package/typings/utils.d.ts +15 -0
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
|
923
|
+
@register(ITodoRepositoryKey.asKey)
|
|
930
924
|
class TodoRepository implements IRepository {
|
|
931
925
|
name = 'TodoRepository';
|
|
932
926
|
}
|
|
933
927
|
|
|
934
|
-
|
|
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((
|
|
942
|
-
@inject((
|
|
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
|
-
|
|
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
|
|
969
|
+
@register(ITodoRepositoryKey.asKey)
|
|
967
970
|
class TodoRepository implements IRepository {
|
|
968
971
|
name = 'TodoRepository';
|
|
969
972
|
}
|
|
970
973
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
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((
|
|
983
|
-
@inject((
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
@@ -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
|
-
|
|
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
|
|
55
|
+
return this.resolveOneStrategy(this, keyOrAlias, options);
|
|
54
56
|
}
|
|
55
57
|
resolveOneByKey(keyOrAlias, { args = [], child = this, lazy } = {}) {
|
|
56
58
|
this.validateContainer();
|
|
@@ -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.
|
|
12
|
+
return scope.resolveClass(keyOrAlias, options);
|
|
13
13
|
}
|
|
14
14
|
try {
|
|
15
15
|
return scope.resolveOneByKey(keyOrAlias, options);
|
package/cjm/injector/inject.js
CHANGED
|
@@ -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.
|
|
21
|
+
return (scope) => scope.resolveClass(target);
|
|
21
22
|
}
|
|
22
23
|
if ((0, IContainer_1.isDependencyKey)(target)) {
|
|
23
24
|
return (scope) => scope.resolveOne(target);
|
package/cjm/provider/Cache.js
CHANGED
|
@@ -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());
|
package/cjm/provider/Provider.js
CHANGED
|
@@ -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.
|
|
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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_CONTAINER_RESOLVER
|
|
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
|
-
|
|
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
|
|
52
|
+
return this.resolveOneStrategy(this, keyOrAlias, options);
|
|
51
53
|
}
|
|
52
54
|
resolveOneByKey(keyOrAlias, { args = [], child = this, lazy } = {}) {
|
|
53
55
|
this.validateContainer();
|
|
@@ -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.
|
|
8
|
+
return scope.resolveClass(keyOrAlias, options);
|
|
9
9
|
}
|
|
10
10
|
try {
|
|
11
11
|
return scope.resolveOneByKey(keyOrAlias, options);
|
package/esm/injector/inject.js
CHANGED
|
@@ -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.
|
|
16
|
+
return (scope) => scope.resolveClass(target);
|
|
17
17
|
}
|
|
18
18
|
if (isDependencyKey(target)) {
|
|
19
19
|
return (scope) => scope.resolveOne(target);
|
package/esm/provider/Cache.js
CHANGED
|
@@ -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 {
|
package/esm/provider/Provider.js
CHANGED
|
@@ -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.
|
|
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
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
39
|
+
resolveClass<T>(target: constructor<T>, options?: {
|
|
40
40
|
args?: unknown[];
|
|
41
41
|
}): T;
|
|
42
|
-
resolveOne<T>(alias: constructor<T> | DependencyKey, options?:
|
|
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
|
|
2
|
-
import
|
|
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> {
|
package/typings/utils.d.ts
CHANGED
|
@@ -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
|
+
};
|