ts-ioc-container 46.0.1 → 46.2.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.
- package/README.md +26 -21
- package/cjm/container/EmptyContainer.js +6 -0
- package/cjm/hooks/onConstruct.js +9 -1
- package/cjm/hooks/onDispose.js +11 -1
- package/cjm/index.js +6 -2
- package/cjm/provider/IProvider.js +3 -3
- package/cjm/provider/Provider.js +1 -1
- package/cjm/registration/IRegistration.js +1 -1
- package/cjm/registration/Registration.js +6 -6
- package/esm/container/EmptyContainer.js +6 -0
- package/esm/hooks/onConstruct.js +7 -0
- package/esm/hooks/onDispose.js +9 -0
- package/esm/index.js +3 -2
- package/esm/provider/IProvider.js +3 -3
- package/esm/provider/Provider.js +1 -1
- package/esm/registration/IRegistration.js +1 -1
- package/esm/registration/Registration.js +6 -6
- package/package.json +2 -1
- package/typings/container/EmptyContainer.d.ts +4 -0
- package/typings/container/IContainer.d.ts +4 -0
- package/typings/hooks/onConstruct.d.ts +4 -1
- package/typings/hooks/onDispose.d.ts +4 -1
- package/typings/index.d.ts +4 -4
- package/typings/provider/IProvider.d.ts +4 -4
- package/typings/provider/Provider.d.ts +2 -2
- package/typings/registration/IRegistration.d.ts +3 -3
- package/typings/registration/Registration.d.ts +4 -4
package/README.md
CHANGED
|
@@ -692,7 +692,7 @@ describe('Provider', () => {
|
|
|
692
692
|
|
|
693
693
|
it('allows direct manipulation of visibility predicate', () => {
|
|
694
694
|
const provider = Provider.fromClass(Logger);
|
|
695
|
-
provider.
|
|
695
|
+
provider.setAccessRule(({ invocationScope }) => invocationScope.hasTag('special'));
|
|
696
696
|
const container = new Container({ tags: ['root'] }).register('Logger', provider);
|
|
697
697
|
const specialChild = container.createScope({ tags: ['special'] });
|
|
698
698
|
const regularChild = container.createScope({ tags: ['regular'] });
|
|
@@ -1007,9 +1007,9 @@ describe('ArgsProvider', function () {
|
|
|
1007
1007
|
```
|
|
1008
1008
|
|
|
1009
1009
|
### Visibility
|
|
1010
|
-
Sometimes you want to hide dependency if somebody wants to resolve it from certain scope
|
|
1011
|
-
- `provider(
|
|
1012
|
-
- `Provider.fromClass(Logger).pipe(
|
|
1010
|
+
Sometimes you want to hide dependency if somebody wants to resolve it from certain scope. This uses `ScopeAccessRule` to control access.
|
|
1011
|
+
- `provider(scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope))` - dependency will be accessible only from the scope where it's registered
|
|
1012
|
+
- `Provider.fromClass(Logger).pipe(scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope))`
|
|
1013
1013
|
|
|
1014
1014
|
```typescript
|
|
1015
1015
|
import {
|
|
@@ -1324,7 +1324,7 @@ describe('Registration module', function () {
|
|
|
1324
1324
|
```
|
|
1325
1325
|
|
|
1326
1326
|
### Scope
|
|
1327
|
-
Sometimes you need to register provider only in scope which matches to certain condition and their sub scopes. Especially if you want to register dependency as singleton for some tags, for example `root`
|
|
1327
|
+
Sometimes you need to register provider only in scope which matches to certain condition and their sub scopes. Especially if you want to register dependency as singleton for some tags, for example `root`. This uses `ScopeMatchRule` to determine which scopes should have the provider.
|
|
1328
1328
|
- `@register(scope((container) => container.hasTag('root'))` - register provider only in root scope
|
|
1329
1329
|
- `Registration.fromClass(Logger).when((container) => container.hasTag('root'))`
|
|
1330
1330
|
|
|
@@ -1392,9 +1392,16 @@ Sometimes you need to invoke methods after construct or dispose of class. This i
|
|
|
1392
1392
|
|
|
1393
1393
|
### OnConstruct
|
|
1394
1394
|
```typescript
|
|
1395
|
-
import {
|
|
1395
|
+
import {
|
|
1396
|
+
AddOnConstructHookModule,
|
|
1397
|
+
Container,
|
|
1398
|
+
HookContext,
|
|
1399
|
+
HookFn,
|
|
1400
|
+
inject,
|
|
1401
|
+
onConstruct,
|
|
1402
|
+
Registration as R,
|
|
1403
|
+
} from 'ts-ioc-container';
|
|
1396
1404
|
|
|
1397
|
-
const onConstructHooksRunner = new HooksRunner('onConstruct');
|
|
1398
1405
|
const execute: HookFn = (ctx: HookContext) => {
|
|
1399
1406
|
ctx.invokeMethod({ args: ctx.resolveArgs() });
|
|
1400
1407
|
};
|
|
@@ -1415,9 +1422,7 @@ class Car {
|
|
|
1415
1422
|
describe('onConstruct', function () {
|
|
1416
1423
|
it('should run methods and resolve arguments from container', function () {
|
|
1417
1424
|
const root = new Container()
|
|
1418
|
-
.
|
|
1419
|
-
onConstructHooksRunner.execute(instance, { scope });
|
|
1420
|
-
})
|
|
1425
|
+
.useModule(new AddOnConstructHookModule())
|
|
1421
1426
|
.addRegistration(R.fromValue('bmw').bindTo('engine'));
|
|
1422
1427
|
|
|
1423
1428
|
const car = root.resolve(Car);
|
|
@@ -1431,19 +1436,17 @@ describe('onConstruct', function () {
|
|
|
1431
1436
|
### OnDispose
|
|
1432
1437
|
```typescript
|
|
1433
1438
|
import {
|
|
1439
|
+
AddOnDisposeHookModule,
|
|
1434
1440
|
bindTo,
|
|
1435
1441
|
Container,
|
|
1436
|
-
hook,
|
|
1437
1442
|
type HookFn,
|
|
1438
|
-
HooksRunner,
|
|
1439
1443
|
inject,
|
|
1444
|
+
onDispose,
|
|
1440
1445
|
register,
|
|
1441
1446
|
Registration as R,
|
|
1442
|
-
select,
|
|
1443
1447
|
singleton,
|
|
1444
1448
|
} from 'ts-ioc-container';
|
|
1445
1449
|
|
|
1446
|
-
const onDisposeHookRunner = new HooksRunner('onDispose');
|
|
1447
1450
|
const execute: HookFn = (ctx) => {
|
|
1448
1451
|
ctx.invokeMethod({ args: ctx.resolveArgs() });
|
|
1449
1452
|
};
|
|
@@ -1459,7 +1462,7 @@ class LogsRepo {
|
|
|
1459
1462
|
|
|
1460
1463
|
@register(bindTo('logger'))
|
|
1461
1464
|
class Logger {
|
|
1462
|
-
@
|
|
1465
|
+
@onDispose(({ instance, methodName }) => {
|
|
1463
1466
|
// @ts-ignore
|
|
1464
1467
|
instance[methodName].push('world');
|
|
1465
1468
|
}) // <--- or extract it to @onDispose
|
|
@@ -1471,7 +1474,7 @@ class Logger {
|
|
|
1471
1474
|
this.messages.push(message);
|
|
1472
1475
|
}
|
|
1473
1476
|
|
|
1474
|
-
@
|
|
1477
|
+
@onDispose(execute)
|
|
1475
1478
|
save() {
|
|
1476
1479
|
this.logsRepo.saveLogs(this.messages);
|
|
1477
1480
|
}
|
|
@@ -1479,16 +1482,18 @@ class Logger {
|
|
|
1479
1482
|
|
|
1480
1483
|
describe('onDispose', function () {
|
|
1481
1484
|
it('should invoke hooks on all instances', function () {
|
|
1482
|
-
const container = new Container()
|
|
1485
|
+
const container = new Container()
|
|
1486
|
+
.useModule(new AddOnDisposeHookModule())
|
|
1487
|
+
.addRegistration(R.fromClass(Logger))
|
|
1488
|
+
.addRegistration(R.fromClass(LogsRepo));
|
|
1483
1489
|
|
|
1484
1490
|
const logger = container.resolve<Logger>('logger');
|
|
1485
1491
|
logger.log('Hello');
|
|
1492
|
+
const logsRepo = container.resolve<LogsRepo>('logsRepo');
|
|
1486
1493
|
|
|
1487
|
-
|
|
1488
|
-
onDisposeHookRunner.execute(instance, { scope: container });
|
|
1489
|
-
}
|
|
1494
|
+
container.dispose();
|
|
1490
1495
|
|
|
1491
|
-
expect(
|
|
1496
|
+
expect(logsRepo.savedLogs.join(',')).toBe('Hello,world');
|
|
1492
1497
|
});
|
|
1493
1498
|
});
|
|
1494
1499
|
|
|
@@ -48,5 +48,11 @@ class EmptyContainer {
|
|
|
48
48
|
resolveOneByAlias(alias, options) {
|
|
49
49
|
throw new DependencyNotFoundError_1.DependencyNotFoundError(`Cannot find alias ${alias.toString()}`);
|
|
50
50
|
}
|
|
51
|
+
addOnDisposeHook(...hooks) {
|
|
52
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
53
|
+
}
|
|
54
|
+
addOnConstructHook(...hooks) {
|
|
55
|
+
throw new MethodNotImplementedError_1.MethodNotImplementedError();
|
|
56
|
+
}
|
|
51
57
|
}
|
|
52
58
|
exports.EmptyContainer = EmptyContainer;
|
package/cjm/hooks/onConstruct.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.onConstruct = exports.onConstructHooksRunner = void 0;
|
|
3
|
+
exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = void 0;
|
|
4
4
|
const hook_1 = require("./hook");
|
|
5
5
|
const HooksRunner_1 = require("./HooksRunner");
|
|
6
6
|
exports.onConstructHooksRunner = new HooksRunner_1.HooksRunner('onConstruct');
|
|
7
7
|
const onConstruct = (fn) => (0, hook_1.hook)('onConstruct', fn);
|
|
8
8
|
exports.onConstruct = onConstruct;
|
|
9
|
+
class AddOnConstructHookModule {
|
|
10
|
+
applyTo(container) {
|
|
11
|
+
container.addOnConstructHook((instance, scope) => {
|
|
12
|
+
exports.onConstructHooksRunner.execute(instance, { scope });
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.AddOnConstructHookModule = AddOnConstructHookModule;
|
package/cjm/hooks/onDispose.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.onDispose = exports.onDisposeHooksRunner = void 0;
|
|
3
|
+
exports.AddOnDisposeHookModule = exports.onDispose = exports.onDisposeHooksRunner = void 0;
|
|
4
4
|
const hook_1 = require("./hook");
|
|
5
5
|
const HooksRunner_1 = require("./HooksRunner");
|
|
6
6
|
exports.onDisposeHooksRunner = new HooksRunner_1.HooksRunner('onDispose');
|
|
7
7
|
const onDispose = (fn) => (0, hook_1.hook)('onDispose', fn);
|
|
8
8
|
exports.onDispose = onDispose;
|
|
9
|
+
class AddOnDisposeHookModule {
|
|
10
|
+
applyTo(container) {
|
|
11
|
+
container.addOnDisposeHook((scope) => {
|
|
12
|
+
for (const instance of scope.getInstances()) {
|
|
13
|
+
exports.onDisposeHooksRunner.execute(instance, { scope });
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.AddOnDisposeHookModule = AddOnDisposeHookModule;
|
package/cjm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.Is = exports.select = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = void 0;
|
|
3
|
+
exports.GroupAliasToken = exports.InjectionToken = exports.getParameterMetadata = exports.getMethodMetadata = exports.setMethodMetadata = exports.setParameterMetadata = exports.getClassMetadata = exports.setClassMetadata = exports.HooksRunner = exports.AddOnDisposeHookModule = exports.onDispose = exports.onDisposeHooksRunner = exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = exports.HookContext = exports.hasHooks = exports.hook = exports.getHooks = exports.UnexpectedHookResultError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.DependencyNotFoundError = exports.Registration = exports.bindTo = exports.register = exports.scope = exports.decorate = exports.MultiCache = exports.multiCache = exports.SingletonProvider = exports.singleton = exports.Provider = exports.resolveByArgs = exports.ProviderDecorator = exports.args = exports.argsFn = exports.lazy = exports.scopeAccess = exports.ProxyInjector = exports.SimpleInjector = exports.MetadataInjector = exports.Injector = exports.resolveArgs = exports.inject = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
|
|
4
|
+
exports.Is = exports.select = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = void 0;
|
|
5
5
|
// Containers
|
|
6
6
|
var IContainer_1 = require("./container/IContainer");
|
|
7
7
|
Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
|
|
@@ -13,6 +13,8 @@ Object.defineProperty(exports, "EmptyContainer", { enumerable: true, get: functi
|
|
|
13
13
|
var inject_1 = require("./injector/inject");
|
|
14
14
|
Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return inject_1.inject; } });
|
|
15
15
|
Object.defineProperty(exports, "resolveArgs", { enumerable: true, get: function () { return inject_1.resolveArgs; } });
|
|
16
|
+
var IInjector_1 = require("./injector/IInjector");
|
|
17
|
+
Object.defineProperty(exports, "Injector", { enumerable: true, get: function () { return IInjector_1.Injector; } });
|
|
16
18
|
var MetadataInjector_1 = require("./injector/MetadataInjector");
|
|
17
19
|
Object.defineProperty(exports, "MetadataInjector", { enumerable: true, get: function () { return MetadataInjector_1.MetadataInjector; } });
|
|
18
20
|
var SimpleInjector_1 = require("./injector/SimpleInjector");
|
|
@@ -67,9 +69,11 @@ Object.defineProperty(exports, "injectProp", { enumerable: true, get: function (
|
|
|
67
69
|
var onConstruct_1 = require("./hooks/onConstruct");
|
|
68
70
|
Object.defineProperty(exports, "onConstructHooksRunner", { enumerable: true, get: function () { return onConstruct_1.onConstructHooksRunner; } });
|
|
69
71
|
Object.defineProperty(exports, "onConstruct", { enumerable: true, get: function () { return onConstruct_1.onConstruct; } });
|
|
72
|
+
Object.defineProperty(exports, "AddOnConstructHookModule", { enumerable: true, get: function () { return onConstruct_1.AddOnConstructHookModule; } });
|
|
70
73
|
var onDispose_1 = require("./hooks/onDispose");
|
|
71
74
|
Object.defineProperty(exports, "onDisposeHooksRunner", { enumerable: true, get: function () { return onDispose_1.onDisposeHooksRunner; } });
|
|
72
75
|
Object.defineProperty(exports, "onDispose", { enumerable: true, get: function () { return onDispose_1.onDispose; } });
|
|
76
|
+
Object.defineProperty(exports, "AddOnDisposeHookModule", { enumerable: true, get: function () { return onDispose_1.AddOnDisposeHookModule; } });
|
|
73
77
|
var HooksRunner_1 = require("./hooks/HooksRunner");
|
|
74
78
|
Object.defineProperty(exports, "HooksRunner", { enumerable: true, get: function () { return HooksRunner_1.HooksRunner; } });
|
|
75
79
|
// Metadata
|
|
@@ -18,7 +18,7 @@ const resolveByArgs = (s, ...deps) => deps.map((d) => {
|
|
|
18
18
|
return d;
|
|
19
19
|
});
|
|
20
20
|
exports.resolveByArgs = resolveByArgs;
|
|
21
|
-
const scopeAccess = (
|
|
21
|
+
const scopeAccess = (rule) => (0, ProviderPipe_1.registerPipe)((p) => p.setAccessRule(rule));
|
|
22
22
|
exports.scopeAccess = scopeAccess;
|
|
23
23
|
const lazy = () => (0, ProviderPipe_1.registerPipe)((p) => p.lazy());
|
|
24
24
|
exports.lazy = lazy;
|
|
@@ -27,8 +27,8 @@ class ProviderDecorator {
|
|
|
27
27
|
constructor(decorated) {
|
|
28
28
|
this.decorated = decorated;
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
this.decorated.
|
|
30
|
+
setAccessRule(rule) {
|
|
31
|
+
this.decorated.setAccessRule(rule);
|
|
32
32
|
return this;
|
|
33
33
|
}
|
|
34
34
|
hasAccess(options) {
|
package/cjm/provider/Provider.js
CHANGED
|
@@ -5,7 +5,7 @@ const metadata_1 = require("../metadata");
|
|
|
5
5
|
const ProviderPipe_1 = require("../provider/ProviderPipe");
|
|
6
6
|
const SingleToken_1 = require("../token/SingleToken");
|
|
7
7
|
const BindToken_1 = require("../token/BindToken");
|
|
8
|
-
const scope = (...
|
|
8
|
+
const scope = (...rules) => (r) => r.when(...rules);
|
|
9
9
|
exports.scope = scope;
|
|
10
10
|
const METADATA_KEY = 'registration';
|
|
11
11
|
const getTransformers = (Target) => (0, metadata_1.getClassMetadata)(Target, METADATA_KEY) ?? [];
|
|
@@ -11,7 +11,7 @@ const SingleToken_1 = require("../token/SingleToken");
|
|
|
11
11
|
class Registration {
|
|
12
12
|
createProvider;
|
|
13
13
|
key;
|
|
14
|
-
|
|
14
|
+
scopeRules;
|
|
15
15
|
static fromClass(Target) {
|
|
16
16
|
const transform = (0, utils_1.pipe)(...(0, IRegistration_1.getTransformers)(Target));
|
|
17
17
|
return transform(new Registration(() => Provider_1.Provider.fromClass(Target), Target.name));
|
|
@@ -31,10 +31,10 @@ class Registration {
|
|
|
31
31
|
}
|
|
32
32
|
mappers = [];
|
|
33
33
|
aliases = new Set();
|
|
34
|
-
constructor(createProvider, key,
|
|
34
|
+
constructor(createProvider, key, scopeRules = []) {
|
|
35
35
|
this.createProvider = createProvider;
|
|
36
36
|
this.key = key;
|
|
37
|
-
this.
|
|
37
|
+
this.scopeRules = scopeRules;
|
|
38
38
|
}
|
|
39
39
|
bindToKey(key) {
|
|
40
40
|
this.key = key;
|
|
@@ -50,7 +50,7 @@ class Registration {
|
|
|
50
50
|
return this;
|
|
51
51
|
}
|
|
52
52
|
when(...predicates) {
|
|
53
|
-
this.
|
|
53
|
+
this.scopeRules.push(...predicates);
|
|
54
54
|
return this;
|
|
55
55
|
}
|
|
56
56
|
bindTo(key) {
|
|
@@ -62,10 +62,10 @@ class Registration {
|
|
|
62
62
|
return this;
|
|
63
63
|
}
|
|
64
64
|
matchScope(container) {
|
|
65
|
-
if (this.
|
|
65
|
+
if (this.scopeRules.length === 0) {
|
|
66
66
|
return true;
|
|
67
67
|
}
|
|
68
|
-
const [first, ...rest] = this.
|
|
68
|
+
const [first, ...rest] = this.scopeRules;
|
|
69
69
|
return rest.reduce((prev, curr) => curr(container, prev), first(container));
|
|
70
70
|
}
|
|
71
71
|
applyTo(container) {
|
|
@@ -45,4 +45,10 @@ export class EmptyContainer {
|
|
|
45
45
|
resolveOneByAlias(alias, options) {
|
|
46
46
|
throw new DependencyNotFoundError(`Cannot find alias ${alias.toString()}`);
|
|
47
47
|
}
|
|
48
|
+
addOnDisposeHook(...hooks) {
|
|
49
|
+
throw new MethodNotImplementedError();
|
|
50
|
+
}
|
|
51
|
+
addOnConstructHook(...hooks) {
|
|
52
|
+
throw new MethodNotImplementedError();
|
|
53
|
+
}
|
|
48
54
|
}
|
package/esm/hooks/onConstruct.js
CHANGED
|
@@ -2,3 +2,10 @@ import { hook } from './hook';
|
|
|
2
2
|
import { HooksRunner } from './HooksRunner';
|
|
3
3
|
export const onConstructHooksRunner = new HooksRunner('onConstruct');
|
|
4
4
|
export const onConstruct = (fn) => hook('onConstruct', fn);
|
|
5
|
+
export class AddOnConstructHookModule {
|
|
6
|
+
applyTo(container) {
|
|
7
|
+
container.addOnConstructHook((instance, scope) => {
|
|
8
|
+
onConstructHooksRunner.execute(instance, { scope });
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
}
|
package/esm/hooks/onDispose.js
CHANGED
|
@@ -2,3 +2,12 @@ import { hook } from './hook';
|
|
|
2
2
|
import { HooksRunner } from './HooksRunner';
|
|
3
3
|
export const onDisposeHooksRunner = new HooksRunner('onDispose');
|
|
4
4
|
export const onDispose = (fn) => hook('onDispose', fn);
|
|
5
|
+
export class AddOnDisposeHookModule {
|
|
6
|
+
applyTo(container) {
|
|
7
|
+
container.addOnDisposeHook((scope) => {
|
|
8
|
+
for (const instance of scope.getInstances()) {
|
|
9
|
+
onDisposeHooksRunner.execute(instance, { scope });
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
package/esm/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export { Container } from './container/Container';
|
|
|
4
4
|
export { EmptyContainer } from './container/EmptyContainer';
|
|
5
5
|
// Injectors
|
|
6
6
|
export { inject, resolveArgs } from './injector/inject';
|
|
7
|
+
export { Injector } from './injector/IInjector';
|
|
7
8
|
export { MetadataInjector } from './injector/MetadataInjector';
|
|
8
9
|
export { SimpleInjector } from './injector/SimpleInjector';
|
|
9
10
|
export { ProxyInjector } from './injector/ProxyInjector';
|
|
@@ -26,8 +27,8 @@ export { UnexpectedHookResultError } from './errors/UnexpectedHookResultError';
|
|
|
26
27
|
export { getHooks, hook, hasHooks } from './hooks/hook';
|
|
27
28
|
export { HookContext } from './hooks/HookContext';
|
|
28
29
|
export { injectProp } from './hooks/injectProp';
|
|
29
|
-
export { onConstructHooksRunner, onConstruct } from './hooks/onConstruct';
|
|
30
|
-
export { onDisposeHooksRunner, onDispose } from './hooks/onDispose';
|
|
30
|
+
export { onConstructHooksRunner, onConstruct, AddOnConstructHookModule } from './hooks/onConstruct';
|
|
31
|
+
export { onDisposeHooksRunner, onDispose, AddOnDisposeHookModule } from './hooks/onDispose';
|
|
31
32
|
export { HooksRunner } from './hooks/HooksRunner';
|
|
32
33
|
// Metadata
|
|
33
34
|
export { setClassMetadata, getClassMetadata, setParameterMetadata, setMethodMetadata, getMethodMetadata, getParameterMetadata, } from './metadata';
|
|
@@ -12,15 +12,15 @@ export const resolveByArgs = (s, ...deps) => deps.map((d) => {
|
|
|
12
12
|
}
|
|
13
13
|
return d;
|
|
14
14
|
});
|
|
15
|
-
export const scopeAccess = (
|
|
15
|
+
export const scopeAccess = (rule) => registerPipe((p) => p.setAccessRule(rule));
|
|
16
16
|
export const lazy = () => registerPipe((p) => p.lazy());
|
|
17
17
|
export class ProviderDecorator {
|
|
18
18
|
decorated;
|
|
19
19
|
constructor(decorated) {
|
|
20
20
|
this.decorated = decorated;
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
this.decorated.
|
|
22
|
+
setAccessRule(rule) {
|
|
23
|
+
this.decorated.setAccessRule(rule);
|
|
24
24
|
return this;
|
|
25
25
|
}
|
|
26
26
|
hasAccess(options) {
|
package/esm/provider/Provider.js
CHANGED
|
@@ -2,7 +2,7 @@ import { getClassMetadata, setClassMetadata } from '../metadata';
|
|
|
2
2
|
import { isProviderPipe } from '../provider/ProviderPipe';
|
|
3
3
|
import { SingleToken } from '../token/SingleToken';
|
|
4
4
|
import { isBindToken } from '../token/BindToken';
|
|
5
|
-
export const scope = (...
|
|
5
|
+
export const scope = (...rules) => (r) => r.when(...rules);
|
|
6
6
|
const METADATA_KEY = 'registration';
|
|
7
7
|
export const getTransformers = (Target) => getClassMetadata(Target, METADATA_KEY) ?? [];
|
|
8
8
|
export const register = (...mappers) => setClassMetadata(METADATA_KEY, () => mappers.map((m) => (isProviderPipe(m) ? (r) => m.mapRegistration(r) : m)));
|
|
@@ -8,7 +8,7 @@ import { SingleToken } from '../token/SingleToken';
|
|
|
8
8
|
export class Registration {
|
|
9
9
|
createProvider;
|
|
10
10
|
key;
|
|
11
|
-
|
|
11
|
+
scopeRules;
|
|
12
12
|
static fromClass(Target) {
|
|
13
13
|
const transform = pipe(...getTransformers(Target));
|
|
14
14
|
return transform(new Registration(() => Provider.fromClass(Target), Target.name));
|
|
@@ -28,10 +28,10 @@ export class Registration {
|
|
|
28
28
|
}
|
|
29
29
|
mappers = [];
|
|
30
30
|
aliases = new Set();
|
|
31
|
-
constructor(createProvider, key,
|
|
31
|
+
constructor(createProvider, key, scopeRules = []) {
|
|
32
32
|
this.createProvider = createProvider;
|
|
33
33
|
this.key = key;
|
|
34
|
-
this.
|
|
34
|
+
this.scopeRules = scopeRules;
|
|
35
35
|
}
|
|
36
36
|
bindToKey(key) {
|
|
37
37
|
this.key = key;
|
|
@@ -47,7 +47,7 @@ export class Registration {
|
|
|
47
47
|
return this;
|
|
48
48
|
}
|
|
49
49
|
when(...predicates) {
|
|
50
|
-
this.
|
|
50
|
+
this.scopeRules.push(...predicates);
|
|
51
51
|
return this;
|
|
52
52
|
}
|
|
53
53
|
bindTo(key) {
|
|
@@ -59,10 +59,10 @@ export class Registration {
|
|
|
59
59
|
return this;
|
|
60
60
|
}
|
|
61
61
|
matchScope(container) {
|
|
62
|
-
if (this.
|
|
62
|
+
if (this.scopeRules.length === 0) {
|
|
63
63
|
return true;
|
|
64
64
|
}
|
|
65
|
-
const [first, ...rest] = this.
|
|
65
|
+
const [first, ...rest] = this.scopeRules;
|
|
66
66
|
return rest.reduce((prev, curr) => curr(container, prev), first(container));
|
|
67
67
|
}
|
|
68
68
|
applyTo(container) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-ioc-container",
|
|
3
|
-
"version": "46.0
|
|
3
|
+
"version": "46.2.0",
|
|
4
4
|
"description": "Typescript IoC container",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"format": "prettier --write \"**/*.ts\"",
|
|
52
52
|
"lint": "eslint lib/**/*.ts __tests__/**/*.ts scripts/**/*.ts",
|
|
53
53
|
"lint:fix": "npm run lint --fix",
|
|
54
|
+
"audit": "npm audit",
|
|
54
55
|
"prepare": "husky",
|
|
55
56
|
"release": "npm run build && npm test && npm publish",
|
|
56
57
|
"docs:install": "cd docs && npm install",
|
|
@@ -2,6 +2,8 @@ import { type DependencyKey, type IContainer, type IContainerModule, type Resolv
|
|
|
2
2
|
import { type IProvider } from '../provider/IProvider';
|
|
3
3
|
import { type IRegistration } from '../registration/IRegistration';
|
|
4
4
|
import { constructor, Instance } from '../types';
|
|
5
|
+
import { OnDisposeHook } from '../hooks/onDispose';
|
|
6
|
+
import { OnConstructHook } from '../hooks/onConstruct';
|
|
5
7
|
export declare class EmptyContainer implements IContainer {
|
|
6
8
|
get isDisposed(): boolean;
|
|
7
9
|
addInstance(instance: Instance): void;
|
|
@@ -19,4 +21,6 @@ export declare class EmptyContainer implements IContainer {
|
|
|
19
21
|
resolve<T>(key: constructor<T> | DependencyKey, options?: ResolveOneOptions): T;
|
|
20
22
|
resolveByAlias<T>(alias: DependencyKey, options?: ResolveManyOptions): T[];
|
|
21
23
|
resolveOneByAlias<T>(alias: DependencyKey, options?: ResolveOneOptions): T;
|
|
24
|
+
addOnDisposeHook(...hooks: OnDisposeHook[]): this;
|
|
25
|
+
addOnConstructHook(...hooks: OnConstructHook[]): this;
|
|
22
26
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type IProvider, ProviderOptions } from '../provider/IProvider';
|
|
2
2
|
import { type IRegistration } from '../registration/IRegistration';
|
|
3
3
|
import { constructor, Instance } from '../types';
|
|
4
|
+
import { OnConstructHook } from '../hooks/onConstruct';
|
|
5
|
+
import { OnDisposeHook } from '../hooks/onDispose';
|
|
4
6
|
export type DependencyKey = string | symbol;
|
|
5
7
|
export declare function isDependencyKey(target: unknown): target is DependencyKey;
|
|
6
8
|
export type Tag = string;
|
|
@@ -30,6 +32,8 @@ export type RegisterOptions = {
|
|
|
30
32
|
};
|
|
31
33
|
export interface IContainer extends Tagged {
|
|
32
34
|
readonly isDisposed: boolean;
|
|
35
|
+
addOnConstructHook(...hooks: OnConstructHook[]): this;
|
|
36
|
+
addOnDisposeHook(...hooks: OnDisposeHook[]): this;
|
|
33
37
|
register(key: DependencyKey, value: IProvider, options?: RegisterOptions): this;
|
|
34
38
|
addRegistration(registration: IRegistration): this;
|
|
35
39
|
getRegistrations(): IRegistration[];
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { HookClass, HookFn } from './hook';
|
|
2
|
-
import type { IContainer } from '../container/IContainer';
|
|
2
|
+
import type { IContainer, IContainerModule } from '../container/IContainer';
|
|
3
3
|
import { constructor, Instance } from '../types';
|
|
4
4
|
import { HooksRunner } from './HooksRunner';
|
|
5
5
|
export declare const onConstructHooksRunner: HooksRunner;
|
|
6
6
|
export declare const onConstruct: (fn: HookFn | constructor<HookClass>) => (target: object, propertyKey: string | symbol) => void;
|
|
7
7
|
export type OnConstructHook = (instance: Instance, scope: IContainer) => void;
|
|
8
|
+
export declare class AddOnConstructHookModule implements IContainerModule {
|
|
9
|
+
applyTo(container: IContainer): void;
|
|
10
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { HookClass, HookFn } from './hook';
|
|
2
|
-
import type { IContainer } from '../container/IContainer';
|
|
2
|
+
import type { IContainer, IContainerModule } from '../container/IContainer';
|
|
3
3
|
import { constructor } from '../types';
|
|
4
4
|
import { HooksRunner } from './HooksRunner';
|
|
5
5
|
export declare const onDisposeHooksRunner: HooksRunner;
|
|
6
6
|
export declare const onDispose: (fn: HookFn | constructor<HookClass>) => (target: object, propertyKey: string | symbol) => void;
|
|
7
7
|
export type OnDisposeHook = (scope: IContainer) => void;
|
|
8
|
+
export declare class AddOnDisposeHookModule implements IContainerModule {
|
|
9
|
+
applyTo(container: IContainer): void;
|
|
10
|
+
}
|
package/typings/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { type IContainer, type Resolvable, type IContainerModule, type Dependenc
|
|
|
2
2
|
export { Container } from './container/Container';
|
|
3
3
|
export { EmptyContainer } from './container/EmptyContainer';
|
|
4
4
|
export { inject, resolveArgs } from './injector/inject';
|
|
5
|
-
export { type IInjector, type InjectOptions, type IInjectFnResolver } from './injector/IInjector';
|
|
5
|
+
export { type IInjector, type InjectOptions, type IInjectFnResolver, Injector } from './injector/IInjector';
|
|
6
6
|
export { MetadataInjector } from './injector/MetadataInjector';
|
|
7
7
|
export { SimpleInjector } from './injector/SimpleInjector';
|
|
8
8
|
export { ProxyInjector } from './injector/ProxyInjector';
|
|
@@ -12,7 +12,7 @@ export { singleton, SingletonProvider } from './provider/SingletonProvider';
|
|
|
12
12
|
export { type Cache, multiCache, MultiCache } from './provider/Cache';
|
|
13
13
|
export { decorate, type DecorateFn } from './provider/DecoratorProvider';
|
|
14
14
|
export { type ProviderPipe } from './provider/ProviderPipe';
|
|
15
|
-
export { type IRegistration, type ReturnTypeOfRegistration, scope, register, type
|
|
15
|
+
export { type IRegistration, type ReturnTypeOfRegistration, scope, register, type ScopeMatchRule, bindTo, } from './registration/IRegistration';
|
|
16
16
|
export { Registration } from './registration/Registration';
|
|
17
17
|
export { DependencyNotFoundError } from './errors/DependencyNotFoundError';
|
|
18
18
|
export { DependencyMissingKeyError } from './errors/DependencyMissingKeyError';
|
|
@@ -22,8 +22,8 @@ export { UnexpectedHookResultError } from './errors/UnexpectedHookResultError';
|
|
|
22
22
|
export { getHooks, hook, hasHooks, type HookFn, type HookClass } from './hooks/hook';
|
|
23
23
|
export { HookContext, type IHookContext } from './hooks/HookContext';
|
|
24
24
|
export { injectProp } from './hooks/injectProp';
|
|
25
|
-
export { onConstructHooksRunner, onConstruct } from './hooks/onConstruct';
|
|
26
|
-
export { onDisposeHooksRunner, onDispose } from './hooks/onDispose';
|
|
25
|
+
export { onConstructHooksRunner, onConstruct, AddOnConstructHookModule } from './hooks/onConstruct';
|
|
26
|
+
export { onDisposeHooksRunner, onDispose, AddOnDisposeHookModule } from './hooks/onDispose';
|
|
27
27
|
export type { HooksRunnerContext } from './hooks/HooksRunner';
|
|
28
28
|
export { HooksRunner } from './hooks/HooksRunner';
|
|
29
29
|
export { setClassMetadata, getClassMetadata, setParameterMetadata, setMethodMetadata, getMethodMetadata, getParameterMetadata, } from './metadata';
|
|
@@ -11,7 +11,7 @@ export type ScopeAccessOptions = {
|
|
|
11
11
|
invocationScope: Tagged;
|
|
12
12
|
providerScope: Tagged;
|
|
13
13
|
};
|
|
14
|
-
export type
|
|
14
|
+
export type ScopeAccessRule = (options: ScopeAccessOptions) => boolean;
|
|
15
15
|
export type ArgsFn = (l: IContainer, ...args: unknown[]) => unknown[];
|
|
16
16
|
export interface IMapper {
|
|
17
17
|
mapItem<T>(target: IProvider<T>): IProvider<T>;
|
|
@@ -20,19 +20,19 @@ export interface IProvider<T = any> {
|
|
|
20
20
|
resolve(container: IContainer, options: ProviderOptions): T;
|
|
21
21
|
hasAccess(options: ScopeAccessOptions): boolean;
|
|
22
22
|
pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): IProvider<T>;
|
|
23
|
-
|
|
23
|
+
setAccessRule(hasAccessWhen: ScopeAccessRule): this;
|
|
24
24
|
setArgs(argsFn: ArgsFn): this;
|
|
25
25
|
lazy(): this;
|
|
26
26
|
}
|
|
27
27
|
export declare const args: <T>(...extraArgs: unknown[]) => ProviderPipe<T>;
|
|
28
28
|
export declare const argsFn: <T>(fn: ArgsFn) => ProviderPipe<T>;
|
|
29
29
|
export declare const resolveByArgs: (s: IContainer, ...deps: unknown[]) => any[];
|
|
30
|
-
export declare const scopeAccess: <T>(
|
|
30
|
+
export declare const scopeAccess: <T>(rule: ScopeAccessRule) => ProviderPipe<T>;
|
|
31
31
|
export declare const lazy: <T>() => ProviderPipe<T>;
|
|
32
32
|
export declare abstract class ProviderDecorator<T> implements IProvider<T> {
|
|
33
33
|
private decorated;
|
|
34
34
|
protected constructor(decorated: IProvider<T>);
|
|
35
|
-
|
|
35
|
+
setAccessRule(rule: ScopeAccessRule): this;
|
|
36
36
|
hasAccess(options: ScopeAccessOptions): boolean;
|
|
37
37
|
resolve(container: IContainer, options: ProviderOptions): T;
|
|
38
38
|
pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): IProvider<T>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArgsFn, IProvider, ProviderOptions, ResolveDependency,
|
|
1
|
+
import { ArgsFn, IProvider, ProviderOptions, ResolveDependency, ScopeAccessRule, ScopeAccessOptions } from './IProvider';
|
|
2
2
|
import type { DependencyKey, IContainer } from '../container/IContainer';
|
|
3
3
|
import type { ProviderPipe } from './ProviderPipe';
|
|
4
4
|
import { constructor, MapFn } from '../types';
|
|
@@ -13,7 +13,7 @@ export declare class Provider<T = any> implements IProvider<T> {
|
|
|
13
13
|
constructor(resolveDependency: ResolveDependency<T>);
|
|
14
14
|
pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): IProvider<T>;
|
|
15
15
|
resolve(container: IContainer, { args, lazy }?: ProviderOptions): T;
|
|
16
|
-
|
|
16
|
+
setAccessRule(predicate: ScopeAccessRule): this;
|
|
17
17
|
lazy(): this;
|
|
18
18
|
setArgs(argsFn: ArgsFn): this;
|
|
19
19
|
hasAccess(options: ScopeAccessOptions): boolean;
|
|
@@ -3,16 +3,16 @@ import type { IProvider } from '../provider/IProvider';
|
|
|
3
3
|
import { ProviderPipe } from '../provider/ProviderPipe';
|
|
4
4
|
import { BindToken } from '../token/BindToken';
|
|
5
5
|
import { constructor, MapFn } from '../types';
|
|
6
|
-
export type
|
|
6
|
+
export type ScopeMatchRule = (s: IContainer, prev?: boolean) => boolean;
|
|
7
7
|
export interface IRegistration<T = any> extends IContainerModule {
|
|
8
|
-
when(...predicates:
|
|
8
|
+
when(...predicates: ScopeMatchRule[]): this;
|
|
9
9
|
bindToKey(key: DependencyKey): this;
|
|
10
10
|
bindTo(key: DependencyKey | BindToken): this;
|
|
11
11
|
pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): this;
|
|
12
12
|
bindToAlias(alias: DependencyKey): this;
|
|
13
13
|
}
|
|
14
14
|
export type ReturnTypeOfRegistration<T> = T extends IRegistration<infer R> ? R : never;
|
|
15
|
-
export declare const scope: (...
|
|
15
|
+
export declare const scope: (...rules: ScopeMatchRule[]) => MapFn<IRegistration>;
|
|
16
16
|
export declare const getTransformers: (Target: constructor<unknown>) => MapFn<IRegistration<any>>[];
|
|
17
17
|
export declare const register: (...mappers: Array<MapFn<IRegistration> | ProviderPipe>) => ClassDecorator;
|
|
18
18
|
export declare const bindTo: (...tokens: (DependencyKey | BindToken)[]) => MapFn<IRegistration>;
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { DependencyKey, IContainer } from '../container/IContainer';
|
|
2
2
|
import type { IProvider, ResolveDependency } from '../provider/IProvider';
|
|
3
|
-
import type { IRegistration,
|
|
3
|
+
import type { IRegistration, ScopeMatchRule } from './IRegistration';
|
|
4
4
|
import type { ProviderPipe } from '../provider/ProviderPipe';
|
|
5
5
|
import { BindToken } from '../token/BindToken';
|
|
6
6
|
import { constructor, MapFn } from '../types';
|
|
7
7
|
export declare class Registration<T = any> implements IRegistration<T> {
|
|
8
8
|
private createProvider;
|
|
9
9
|
private key?;
|
|
10
|
-
private
|
|
10
|
+
private scopeRules;
|
|
11
11
|
static fromClass<T>(Target: constructor<T>): IRegistration<any>;
|
|
12
12
|
static fromValue<T>(value: T): IRegistration<any> | Registration<T>;
|
|
13
13
|
static fromFn<T>(fn: ResolveDependency<T>): Registration<T>;
|
|
14
14
|
static fromKey<T>(key: DependencyKey): Registration<T>;
|
|
15
15
|
private mappers;
|
|
16
16
|
private aliases;
|
|
17
|
-
constructor(createProvider: () => IProvider<T>, key?: DependencyKey | undefined,
|
|
17
|
+
constructor(createProvider: () => IProvider<T>, key?: DependencyKey | undefined, scopeRules?: ScopeMatchRule[]);
|
|
18
18
|
bindToKey(key: DependencyKey): this;
|
|
19
19
|
bindToAlias(alias: DependencyKey): this;
|
|
20
20
|
pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): this;
|
|
21
|
-
when(...predicates:
|
|
21
|
+
when(...predicates: ScopeMatchRule[]): this;
|
|
22
22
|
bindTo(key: DependencyKey | BindToken): this;
|
|
23
23
|
private matchScope;
|
|
24
24
|
applyTo(container: IContainer): void;
|