ts-ioc-container 32.10.0 → 32.11.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 +23 -19
- package/cjm/hooks/HookContext.js +27 -0
- package/cjm/hooks/hook.js +10 -6
- package/cjm/index.js +8 -6
- package/cjm/injector/MetadataInjector.js +4 -21
- package/cjm/injector/inject.js +16 -0
- package/cjm/utils.js +5 -1
- package/esm/hooks/{ExecutionContext.js → HookContext.js} +6 -4
- package/esm/hooks/hook.js +8 -4
- package/esm/index.js +5 -3
- package/esm/injector/MetadataInjector.js +3 -17
- package/esm/injector/inject.js +11 -0
- package/esm/utils.js +3 -0
- package/package.json +2 -2
- package/typings/by.d.ts +2 -2
- package/typings/container/AutoMockedContainer.d.ts +1 -1
- package/typings/container/Container.d.ts +1 -1
- package/typings/container/EmptyContainer.d.ts +1 -1
- package/typings/container/IContainer.d.ts +1 -1
- package/typings/hooks/HookContext.d.ts +25 -0
- package/typings/hooks/hook.d.ts +20 -13
- package/typings/index.d.ts +5 -4
- package/typings/injector/MetadataInjector.d.ts +1 -5
- package/typings/injector/inject.d.ts +5 -0
- package/typings/utils.d.ts +5 -1
- package/cjm/hooks/ExecutionContext.js +0 -23
- package/typings/hooks/ExecutionContext.d.ts +0 -13
package/README.md
CHANGED
|
@@ -785,7 +785,7 @@ import {
|
|
|
785
785
|
Registration as R,
|
|
786
786
|
scope,
|
|
787
787
|
} from 'ts-ioc-container';
|
|
788
|
-
import { constant } from '../../lib/utils
|
|
788
|
+
import { constant } from '../../lib/utils';
|
|
789
789
|
|
|
790
790
|
describe('alias', () => {
|
|
791
791
|
const IMiddlewareKey = 'IMiddleware';
|
|
@@ -1145,23 +1145,23 @@ import 'reflect-metadata';
|
|
|
1145
1145
|
import {
|
|
1146
1146
|
constructor,
|
|
1147
1147
|
Container,
|
|
1148
|
-
key,
|
|
1149
1148
|
hook,
|
|
1150
1149
|
IContainer,
|
|
1151
1150
|
IInjector,
|
|
1151
|
+
InjectOptions,
|
|
1152
|
+
key,
|
|
1152
1153
|
MetadataInjector,
|
|
1153
|
-
Registration as R,
|
|
1154
1154
|
register,
|
|
1155
|
-
|
|
1155
|
+
Registration as R,
|
|
1156
|
+
runHooks,
|
|
1156
1157
|
} from 'ts-ioc-container';
|
|
1157
|
-
import { InjectOptions } from '../lib/injector/IInjector.ts';
|
|
1158
1158
|
|
|
1159
1159
|
class MyInjector implements IInjector {
|
|
1160
1160
|
private injector = new MetadataInjector();
|
|
1161
1161
|
|
|
1162
1162
|
resolve<T>(container: IContainer, value: constructor<T>, options: InjectOptions): T {
|
|
1163
1163
|
const instance = this.injector.resolve(container, value, options);
|
|
1164
|
-
|
|
1164
|
+
void runHooks(instance as object, 'onConstruct', { scope: container, handleError: jest.fn() });
|
|
1165
1165
|
return instance;
|
|
1166
1166
|
}
|
|
1167
1167
|
}
|
|
@@ -1170,7 +1170,9 @@ class MyInjector implements IInjector {
|
|
|
1170
1170
|
class Logger {
|
|
1171
1171
|
isReady = false;
|
|
1172
1172
|
|
|
1173
|
-
@hook('onConstruct', (context) =>
|
|
1173
|
+
@hook('onConstruct', (context) => {
|
|
1174
|
+
context.invokeMethod({ args: [] });
|
|
1175
|
+
}) // <--- or extract it to @onConstruct
|
|
1174
1176
|
initialize() {
|
|
1175
1177
|
this.isReady = true;
|
|
1176
1178
|
}
|
|
@@ -1196,17 +1198,17 @@ describe('onConstruct', function () {
|
|
|
1196
1198
|
```typescript
|
|
1197
1199
|
import 'reflect-metadata';
|
|
1198
1200
|
import {
|
|
1199
|
-
singleton,
|
|
1200
1201
|
by,
|
|
1201
1202
|
Container,
|
|
1202
|
-
key,
|
|
1203
1203
|
hook,
|
|
1204
1204
|
inject,
|
|
1205
|
-
|
|
1206
|
-
Registration as R,
|
|
1205
|
+
key,
|
|
1207
1206
|
MetadataInjector,
|
|
1207
|
+
provider,
|
|
1208
1208
|
register,
|
|
1209
|
-
|
|
1209
|
+
Registration as R,
|
|
1210
|
+
runHooks,
|
|
1211
|
+
singleton,
|
|
1210
1212
|
} from 'ts-ioc-container';
|
|
1211
1213
|
|
|
1212
1214
|
@register(key('logsRepo'))
|
|
@@ -1237,7 +1239,9 @@ class Logger {
|
|
|
1237
1239
|
return this.messages.length;
|
|
1238
1240
|
}
|
|
1239
1241
|
|
|
1240
|
-
@hook('onDispose', (c) =>
|
|
1242
|
+
@hook('onDispose', (c) => {
|
|
1243
|
+
c.invokeMethod({ args: [] });
|
|
1244
|
+
}) // <--- or extract it to @onDispose
|
|
1241
1245
|
async save(): Promise<void> {
|
|
1242
1246
|
this.logsRepo.saveLogs(this.messages);
|
|
1243
1247
|
}
|
|
@@ -1251,7 +1255,7 @@ describe('onDispose', function () {
|
|
|
1251
1255
|
logger.log('Hello');
|
|
1252
1256
|
|
|
1253
1257
|
for (const instance of container.getInstances()) {
|
|
1254
|
-
|
|
1258
|
+
void runHooks(instance as object, 'onDispose', { scope: container, handleError: jest.fn() });
|
|
1255
1259
|
}
|
|
1256
1260
|
|
|
1257
1261
|
expect(container.resolve<LogsRepo>('logsRepo').savedLogs.join(',')).toBe('Hello,world');
|
|
@@ -1263,7 +1267,7 @@ describe('onDispose', function () {
|
|
|
1263
1267
|
### Inject property
|
|
1264
1268
|
|
|
1265
1269
|
```typescript
|
|
1266
|
-
import { by, Container,
|
|
1270
|
+
import { by, Container, hook, injectProp, MetadataInjector, Registration, runHooks } from 'ts-ioc-container';
|
|
1267
1271
|
|
|
1268
1272
|
describe('inject property', () => {
|
|
1269
1273
|
it('should inject property', () => {
|
|
@@ -1275,7 +1279,7 @@ describe('inject property', () => {
|
|
|
1275
1279
|
|
|
1276
1280
|
const container = new Container(new MetadataInjector()).add(Registration.fromValue(expected).to('greeting'));
|
|
1277
1281
|
const app = container.resolve(App);
|
|
1278
|
-
|
|
1282
|
+
runHooks(app as object, 'onInit', { scope: container, handleError: jest.fn() });
|
|
1279
1283
|
|
|
1280
1284
|
expect(app.greeting).toBe(expected);
|
|
1281
1285
|
});
|
|
@@ -1286,7 +1290,7 @@ describe('inject property', () => {
|
|
|
1286
1290
|
### Inject method
|
|
1287
1291
|
|
|
1288
1292
|
```typescript
|
|
1289
|
-
import { by, Container,
|
|
1293
|
+
import { by, Container, runHooks, hook, inject, invokeExecution, MetadataInjector, Registration } from 'ts-ioc-container';
|
|
1290
1294
|
|
|
1291
1295
|
describe('inject method', () => {
|
|
1292
1296
|
const sleep = (number: number) => new Promise((resolve) => setTimeout(resolve, number));
|
|
@@ -1304,7 +1308,7 @@ describe('inject method', () => {
|
|
|
1304
1308
|
|
|
1305
1309
|
const container = new Container(new MetadataInjector()).add(Registration.fromValue(expected).to('greeting'));
|
|
1306
1310
|
const app = container.resolve(App);
|
|
1307
|
-
await
|
|
1311
|
+
await runHooks(app, 'onInit', { scope: container, handleError: jest.fn() });
|
|
1308
1312
|
|
|
1309
1313
|
expect(app.greeting).toBe(expected);
|
|
1310
1314
|
});
|
|
@@ -1324,7 +1328,7 @@ describe('inject method', () => {
|
|
|
1324
1328
|
.add(Registration.fromFn(() => sleep(25).then(() => 'world')).to('person'));
|
|
1325
1329
|
|
|
1326
1330
|
const app = container.resolve(App);
|
|
1327
|
-
await
|
|
1331
|
+
await runHooks(app, 'onInit', { scope: container, handleError: jest.fn() });
|
|
1328
1332
|
|
|
1329
1333
|
expect(app.greeting).toBe('Hello,world');
|
|
1330
1334
|
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hookMetaKey = exports.createHookContext = exports.HookContext = void 0;
|
|
4
|
+
const inject_1 = require("../injector/inject");
|
|
5
|
+
class HookContext {
|
|
6
|
+
constructor(instance, scope, methodName) {
|
|
7
|
+
this.instance = instance;
|
|
8
|
+
this.scope = scope;
|
|
9
|
+
this.methodName = methodName;
|
|
10
|
+
}
|
|
11
|
+
resolveArgs(...args) {
|
|
12
|
+
return (0, inject_1.resolveArgs)(this.instance.constructor, this.methodName)(this.scope, ...args);
|
|
13
|
+
}
|
|
14
|
+
invokeMethod({ args = this.resolveArgs() }) {
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
return this.instance[this.methodName](...args);
|
|
17
|
+
}
|
|
18
|
+
injectProperty(fn) {
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
this.instance[this.methodName] = fn(this.scope);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.HookContext = HookContext;
|
|
24
|
+
const createHookContext = (Target, scope, methodName = 'constructor') => new HookContext(Target, scope, methodName);
|
|
25
|
+
exports.createHookContext = createHookContext;
|
|
26
|
+
const hookMetaKey = (methodName = 'constructor') => `inject:${methodName}`;
|
|
27
|
+
exports.hookMetaKey = hookMetaKey;
|
package/cjm/hooks/hook.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.invokeExecution = exports.injectProp = exports.
|
|
4
|
-
const
|
|
3
|
+
exports.executeHooks = exports.invokeExecution = exports.injectProp = exports.runHooks = exports.hasHooks = exports.getHooks = exports.hook = void 0;
|
|
4
|
+
const HookContext_1 = require("./HookContext");
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
6
|
const hook = (key, ...fns) => (target, propertyKey) => {
|
|
7
7
|
const hooks = Reflect.hasMetadata(key, target.constructor)
|
|
@@ -19,13 +19,12 @@ function hasHooks(target, key) {
|
|
|
19
19
|
return Reflect.hasMetadata(key, target.constructor);
|
|
20
20
|
}
|
|
21
21
|
exports.hasHooks = hasHooks;
|
|
22
|
-
const
|
|
22
|
+
const runHooks = (target, key, { scope, createContext = HookContext_1.createHookContext, handleError, }) => {
|
|
23
23
|
const hooks = Array.from(getHooks(target, key).entries());
|
|
24
|
-
const createContext = (methodName) => decorateContext(new ExecutionContext_1.ExecutionContext(target, methodName, scope));
|
|
25
24
|
const runExecution = (execute, context) => (0, utils_1.promisify)(execute(context)).catch((e) => handleError(e, scope));
|
|
26
|
-
return Promise.all(hooks.flatMap(([methodName, executions]) => executions.map((execute) => runExecution(execute, createContext(methodName)))));
|
|
25
|
+
return Promise.all(hooks.flatMap(([methodName, executions]) => executions.map((execute) => runExecution(execute, createContext(target, scope, methodName)))));
|
|
27
26
|
};
|
|
28
|
-
exports.
|
|
27
|
+
exports.runHooks = runHooks;
|
|
29
28
|
const injectProp = (fn) => (context) => context.injectProperty(fn);
|
|
30
29
|
exports.injectProp = injectProp;
|
|
31
30
|
const invokeExecution = ({ handleResult }) => async (context) => {
|
|
@@ -33,3 +32,8 @@ const invokeExecution = ({ handleResult }) => async (context) => {
|
|
|
33
32
|
return handleResult(context.invokeMethod({ args }), context);
|
|
34
33
|
};
|
|
35
34
|
exports.invokeExecution = invokeExecution;
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Use `runHooks` instead
|
|
37
|
+
* @TODO: Remove in v33
|
|
38
|
+
*/
|
|
39
|
+
exports.executeHooks = exports.runHooks;
|
package/cjm/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getParameterMetadata = exports.getMethodMetadata = exports.setMethodMetadata = exports.setParameterMetadata = exports.getMetadata = exports.setMetadata = exports.byAliases = exports.byAlias = exports.IMemoKey = exports.by = exports.
|
|
3
|
+
exports.getParameterMetadata = exports.getMethodMetadata = exports.setMethodMetadata = exports.setParameterMetadata = exports.getMetadata = exports.setMetadata = exports.byAliases = exports.byAlias = exports.IMemoKey = exports.by = exports.HookContext = exports.invokeExecution = exports.injectProp = exports.runHooks = exports.executeHooks = exports.hasHooks = exports.hook = exports.getHooks = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.Registration = exports.register = exports.scope = exports.key = exports.decorate = exports.multiCache = exports.MultiCache = exports.SingletonProvider = exports.singleton = exports.Provider = exports.ProviderDecorator = exports.args = exports.argsFn = exports.alias = exports.visible = exports.provider = exports.ProxyInjector = exports.SimpleInjector = exports.MetadataInjector = exports.resolveArgs = exports.inject = exports.AutoMockedContainer = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
|
|
4
4
|
// Containers
|
|
5
5
|
var IContainer_1 = require("./container/IContainer");
|
|
6
6
|
Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
|
|
@@ -10,11 +10,12 @@ var EmptyContainer_1 = require("./container/EmptyContainer");
|
|
|
10
10
|
Object.defineProperty(exports, "EmptyContainer", { enumerable: true, get: function () { return EmptyContainer_1.EmptyContainer; } });
|
|
11
11
|
var AutoMockedContainer_1 = require("./container/AutoMockedContainer");
|
|
12
12
|
Object.defineProperty(exports, "AutoMockedContainer", { enumerable: true, get: function () { return AutoMockedContainer_1.AutoMockedContainer; } });
|
|
13
|
+
// Injectors
|
|
14
|
+
var inject_1 = require("./injector/inject");
|
|
15
|
+
Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return inject_1.inject; } });
|
|
16
|
+
Object.defineProperty(exports, "resolveArgs", { enumerable: true, get: function () { return inject_1.resolveArgs; } });
|
|
13
17
|
var MetadataInjector_1 = require("./injector/MetadataInjector");
|
|
14
18
|
Object.defineProperty(exports, "MetadataInjector", { enumerable: true, get: function () { return MetadataInjector_1.MetadataInjector; } });
|
|
15
|
-
Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return MetadataInjector_1.inject; } });
|
|
16
|
-
Object.defineProperty(exports, "resolveArgs", { enumerable: true, get: function () { return MetadataInjector_1.resolveArgs; } });
|
|
17
|
-
Object.defineProperty(exports, "getInjectFns", { enumerable: true, get: function () { return MetadataInjector_1.getInjectFns; } });
|
|
18
19
|
var SimpleInjector_1 = require("./injector/SimpleInjector");
|
|
19
20
|
Object.defineProperty(exports, "SimpleInjector", { enumerable: true, get: function () { return SimpleInjector_1.SimpleInjector; } });
|
|
20
21
|
var ProxyInjector_1 = require("./injector/ProxyInjector");
|
|
@@ -57,10 +58,11 @@ Object.defineProperty(exports, "getHooks", { enumerable: true, get: function ()
|
|
|
57
58
|
Object.defineProperty(exports, "hook", { enumerable: true, get: function () { return hook_1.hook; } });
|
|
58
59
|
Object.defineProperty(exports, "hasHooks", { enumerable: true, get: function () { return hook_1.hasHooks; } });
|
|
59
60
|
Object.defineProperty(exports, "executeHooks", { enumerable: true, get: function () { return hook_1.executeHooks; } });
|
|
61
|
+
Object.defineProperty(exports, "runHooks", { enumerable: true, get: function () { return hook_1.runHooks; } });
|
|
60
62
|
Object.defineProperty(exports, "injectProp", { enumerable: true, get: function () { return hook_1.injectProp; } });
|
|
61
63
|
Object.defineProperty(exports, "invokeExecution", { enumerable: true, get: function () { return hook_1.invokeExecution; } });
|
|
62
|
-
var
|
|
63
|
-
Object.defineProperty(exports, "
|
|
64
|
+
var HookContext_1 = require("./hooks/HookContext");
|
|
65
|
+
Object.defineProperty(exports, "HookContext", { enumerable: true, get: function () { return HookContext_1.HookContext; } });
|
|
64
66
|
// Others
|
|
65
67
|
var by_1 = require("./by");
|
|
66
68
|
Object.defineProperty(exports, "by", { enumerable: true, get: function () { return by_1.by; } });
|
|
@@ -1,27 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MetadataInjector =
|
|
4
|
-
const
|
|
5
|
-
const metadata_1 = require("../metadata");
|
|
6
|
-
const METADATA_KEY = 'inject';
|
|
7
|
-
const getInjectFns = (Target, methodName) => (0, metadata_1.getParameterMetadata)(metaKey(methodName), Target);
|
|
8
|
-
exports.getInjectFns = getInjectFns;
|
|
9
|
-
const metaKey = (methodName = 'constructor') => `${METADATA_KEY}:${methodName}`;
|
|
10
|
-
function isInstance(target) {
|
|
11
|
-
return Object.prototype.hasOwnProperty.call(target, 'constructor');
|
|
12
|
-
}
|
|
13
|
-
const inject = (fn) => (target, propertyKey, parameterIndex) => {
|
|
14
|
-
(0, metadata_1.setParameterMetadata)(metaKey(propertyKey), fn)(isInstance(target) ? target.constructor : target, propertyKey, parameterIndex);
|
|
15
|
-
};
|
|
16
|
-
exports.inject = inject;
|
|
17
|
-
const resolveArgs = (Target, methodName) => {
|
|
18
|
-
const argsFns = (0, exports.getInjectFns)(Target, methodName);
|
|
19
|
-
return (scope, ...deps) => (0, utils_1.fillEmptyIndexes)(argsFns, deps.map(utils_1.constant)).map((fn) => fn(scope));
|
|
20
|
-
};
|
|
21
|
-
exports.resolveArgs = resolveArgs;
|
|
3
|
+
exports.MetadataInjector = void 0;
|
|
4
|
+
const inject_1 = require("./inject");
|
|
22
5
|
class MetadataInjector {
|
|
23
|
-
resolve(
|
|
24
|
-
const args = (0,
|
|
6
|
+
resolve(scope, Target, { args: deps }) {
|
|
7
|
+
const args = (0, inject_1.resolveArgs)(Target)(scope, ...deps);
|
|
25
8
|
return new Target(...args);
|
|
26
9
|
}
|
|
27
10
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveArgs = exports.inject = void 0;
|
|
4
|
+
const metadata_1 = require("../metadata");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const HookContext_1 = require("../hooks/HookContext");
|
|
7
|
+
const inject = (fn) => (target, propertyKey, parameterIndex) => {
|
|
8
|
+
(0, metadata_1.setParameterMetadata)((0, HookContext_1.hookMetaKey)(propertyKey), fn)((0, utils_1.isInstance)(target) ? target.constructor : target, propertyKey, parameterIndex);
|
|
9
|
+
};
|
|
10
|
+
exports.inject = inject;
|
|
11
|
+
const resolveArgs = (Target, methodName) => {
|
|
12
|
+
const argsFns = getInjectFns(Target, methodName);
|
|
13
|
+
return (scope, ...deps) => (0, utils_1.fillEmptyIndexes)(argsFns, deps.map(utils_1.constant)).map((fn) => fn(scope));
|
|
14
|
+
};
|
|
15
|
+
exports.resolveArgs = resolveArgs;
|
|
16
|
+
const getInjectFns = (Target, methodName) => (0, metadata_1.getParameterMetadata)((0, HookContext_1.hookMetaKey)(methodName), Target);
|
package/cjm/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.promisify = exports.lazyProxy = exports.isConstructor = exports.constant = exports.fillEmptyIndexes = exports.pipe = void 0;
|
|
3
|
+
exports.isInstance = exports.promisify = exports.lazyProxy = exports.isConstructor = exports.constant = exports.fillEmptyIndexes = exports.pipe = void 0;
|
|
4
4
|
const pipe = (...mappers) => (value) => mappers.reduce((acc, current) => current(acc), value);
|
|
5
5
|
exports.pipe = pipe;
|
|
6
6
|
function fillEmptyIndexes(baseArr, insertArr) {
|
|
@@ -31,3 +31,7 @@ function lazyProxy(resolveInstance) {
|
|
|
31
31
|
exports.lazyProxy = lazyProxy;
|
|
32
32
|
const promisify = (arg) => (arg instanceof Promise ? arg : Promise.resolve(arg));
|
|
33
33
|
exports.promisify = promisify;
|
|
34
|
+
function isInstance(target) {
|
|
35
|
+
return Object.prototype.hasOwnProperty.call(target, 'constructor');
|
|
36
|
+
}
|
|
37
|
+
exports.isInstance = isInstance;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { resolveArgs } from '../injector/
|
|
2
|
-
export class
|
|
3
|
-
constructor(instance,
|
|
1
|
+
import { resolveArgs } from '../injector/inject';
|
|
2
|
+
export class HookContext {
|
|
3
|
+
constructor(instance, scope, methodName) {
|
|
4
4
|
this.instance = instance;
|
|
5
|
-
this.methodName = methodName;
|
|
6
5
|
this.scope = scope;
|
|
6
|
+
this.methodName = methodName;
|
|
7
7
|
}
|
|
8
8
|
resolveArgs(...args) {
|
|
9
9
|
return resolveArgs(this.instance.constructor, this.methodName)(this.scope, ...args);
|
|
@@ -17,3 +17,5 @@ export class ExecutionContext {
|
|
|
17
17
|
this.instance[this.methodName] = fn(this.scope);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
export const createHookContext = (Target, scope, methodName = 'constructor') => new HookContext(Target, scope, methodName);
|
|
21
|
+
export const hookMetaKey = (methodName = 'constructor') => `inject:${methodName}`;
|
package/esm/hooks/hook.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHookContext } from './HookContext';
|
|
2
2
|
import { promisify } from '../utils';
|
|
3
3
|
export const hook = (key, ...fns) => (target, propertyKey) => {
|
|
4
4
|
const hooks = Reflect.hasMetadata(key, target.constructor)
|
|
@@ -13,14 +13,18 @@ export function getHooks(target, key) {
|
|
|
13
13
|
export function hasHooks(target, key) {
|
|
14
14
|
return Reflect.hasMetadata(key, target.constructor);
|
|
15
15
|
}
|
|
16
|
-
export const
|
|
16
|
+
export const runHooks = (target, key, { scope, createContext = createHookContext, handleError, }) => {
|
|
17
17
|
const hooks = Array.from(getHooks(target, key).entries());
|
|
18
|
-
const createContext = (methodName) => decorateContext(new ExecutionContext(target, methodName, scope));
|
|
19
18
|
const runExecution = (execute, context) => promisify(execute(context)).catch((e) => handleError(e, scope));
|
|
20
|
-
return Promise.all(hooks.flatMap(([methodName, executions]) => executions.map((execute) => runExecution(execute, createContext(methodName)))));
|
|
19
|
+
return Promise.all(hooks.flatMap(([methodName, executions]) => executions.map((execute) => runExecution(execute, createContext(target, scope, methodName)))));
|
|
21
20
|
};
|
|
22
21
|
export const injectProp = (fn) => (context) => context.injectProperty(fn);
|
|
23
22
|
export const invokeExecution = ({ handleResult }) => async (context) => {
|
|
24
23
|
const args = await Promise.all(context.resolveArgs().map(promisify));
|
|
25
24
|
return handleResult(context.invokeMethod({ args }), context);
|
|
26
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated Use `runHooks` instead
|
|
28
|
+
* @TODO: Remove in v33
|
|
29
|
+
*/
|
|
30
|
+
export const executeHooks = runHooks;
|
package/esm/index.js
CHANGED
|
@@ -3,7 +3,9 @@ export { isDependencyKey, } from './container/IContainer';
|
|
|
3
3
|
export { Container } from './container/Container';
|
|
4
4
|
export { EmptyContainer } from './container/EmptyContainer';
|
|
5
5
|
export { AutoMockedContainer } from './container/AutoMockedContainer';
|
|
6
|
-
|
|
6
|
+
// Injectors
|
|
7
|
+
export { inject, resolveArgs } from './injector/inject';
|
|
8
|
+
export { MetadataInjector } from './injector/MetadataInjector';
|
|
7
9
|
export { SimpleInjector } from './injector/SimpleInjector';
|
|
8
10
|
export { ProxyInjector } from './injector/ProxyInjector';
|
|
9
11
|
// Providers
|
|
@@ -20,8 +22,8 @@ export { DependencyNotFoundError } from './errors/DependencyNotFoundError';
|
|
|
20
22
|
export { MethodNotImplementedError } from './errors/MethodNotImplementedError';
|
|
21
23
|
export { ContainerDisposedError } from './errors/ContainerDisposedError';
|
|
22
24
|
// Hooks
|
|
23
|
-
export { getHooks, hook, hasHooks, executeHooks, injectProp, invokeExecution } from './hooks/hook';
|
|
24
|
-
export {
|
|
25
|
+
export { getHooks, hook, hasHooks, executeHooks, runHooks, injectProp, invokeExecution } from './hooks/hook';
|
|
26
|
+
export { HookContext } from './hooks/HookContext';
|
|
25
27
|
// Others
|
|
26
28
|
export { by, IMemoKey, byAlias, byAliases } from './by';
|
|
27
29
|
export { setMetadata, getMetadata, setParameterMetadata, setMethodMetadata, getMethodMetadata, getParameterMetadata, } from './metadata';
|
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { setParameterMetadata, getParameterMetadata } from '../metadata';
|
|
3
|
-
const METADATA_KEY = 'inject';
|
|
4
|
-
export const getInjectFns = (Target, methodName) => getParameterMetadata(metaKey(methodName), Target);
|
|
5
|
-
const metaKey = (methodName = 'constructor') => `${METADATA_KEY}:${methodName}`;
|
|
6
|
-
function isInstance(target) {
|
|
7
|
-
return Object.prototype.hasOwnProperty.call(target, 'constructor');
|
|
8
|
-
}
|
|
9
|
-
export const inject = (fn) => (target, propertyKey, parameterIndex) => {
|
|
10
|
-
setParameterMetadata(metaKey(propertyKey), fn)(isInstance(target) ? target.constructor : target, propertyKey, parameterIndex);
|
|
11
|
-
};
|
|
12
|
-
export const resolveArgs = (Target, methodName) => {
|
|
13
|
-
const argsFns = getInjectFns(Target, methodName);
|
|
14
|
-
return (scope, ...deps) => fillEmptyIndexes(argsFns, deps.map(constant)).map((fn) => fn(scope));
|
|
15
|
-
};
|
|
1
|
+
import { resolveArgs } from './inject';
|
|
16
2
|
export class MetadataInjector {
|
|
17
|
-
resolve(
|
|
18
|
-
const args = resolveArgs(Target)(
|
|
3
|
+
resolve(scope, Target, { args: deps }) {
|
|
4
|
+
const args = resolveArgs(Target)(scope, ...deps);
|
|
19
5
|
return new Target(...args);
|
|
20
6
|
}
|
|
21
7
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getParameterMetadata, setParameterMetadata } from '../metadata';
|
|
2
|
+
import { constant, fillEmptyIndexes, isInstance } from '../utils';
|
|
3
|
+
import { hookMetaKey } from '../hooks/HookContext';
|
|
4
|
+
export const inject = (fn) => (target, propertyKey, parameterIndex) => {
|
|
5
|
+
setParameterMetadata(hookMetaKey(propertyKey), fn)(isInstance(target) ? target.constructor : target, propertyKey, parameterIndex);
|
|
6
|
+
};
|
|
7
|
+
export const resolveArgs = (Target, methodName) => {
|
|
8
|
+
const argsFns = getInjectFns(Target, methodName);
|
|
9
|
+
return (scope, ...deps) => fillEmptyIndexes(argsFns, deps.map(constant)).map((fn) => fn(scope));
|
|
10
|
+
};
|
|
11
|
+
const getInjectFns = (Target, methodName) => getParameterMetadata(hookMetaKey(methodName), Target);
|
package/esm/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-ioc-container",
|
|
3
|
-
"version": "32.
|
|
3
|
+
"version": "32.11.0",
|
|
4
4
|
"description": "Typescript IoC container",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"ts-node": "^10.9.1",
|
|
60
60
|
"typescript": "5.4.3"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "75d723a20c55049f12bbc0cebe816edf4b4b30a1"
|
|
63
63
|
}
|
package/typings/by.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DependencyKey, IContainer, InjectionToken } from './container/IContainer';
|
|
2
2
|
import { ProviderResolveOptions } from './provider/IProvider';
|
|
3
|
-
import { InjectFn } from './
|
|
3
|
+
import { InjectFn } from './hooks/HookContext';
|
|
4
4
|
export type InstancePredicate = (dep: unknown) => boolean;
|
|
5
5
|
export declare const all: InstancePredicate;
|
|
6
6
|
export type IMemo = Map<string, DependencyKey[]>;
|
|
@@ -18,7 +18,7 @@ export declare const by: {
|
|
|
18
18
|
args?: unknown[] | undefined;
|
|
19
19
|
lazy?: boolean | undefined;
|
|
20
20
|
}) => (c: IContainer, ...args: unknown[]) => T;
|
|
21
|
-
instances: (predicate?: InstancePredicate) => (l: IContainer) =>
|
|
21
|
+
instances: (predicate?: InstancePredicate) => (l: IContainer) => object[];
|
|
22
22
|
scope: {
|
|
23
23
|
current: (container: IContainer) => IContainer;
|
|
24
24
|
create: (...tags: string[]) => (l: IContainer) => IContainer;
|
|
@@ -7,7 +7,7 @@ export declare abstract class AutoMockedContainer implements IContainer {
|
|
|
7
7
|
abstract resolve<T>(key: InjectionToken<T>, options?: ResolveOptions): T;
|
|
8
8
|
dispose(): void;
|
|
9
9
|
register(): this;
|
|
10
|
-
getInstances():
|
|
10
|
+
getInstances(): object[];
|
|
11
11
|
removeScope(): void;
|
|
12
12
|
use(): this;
|
|
13
13
|
getRegistrations(): never[];
|
|
@@ -20,7 +20,7 @@ export declare class Container implements IContainer {
|
|
|
20
20
|
resolve<T>(token: InjectionToken<T>, { args, child, lazy }?: ResolveOptions): T;
|
|
21
21
|
createScope(...tags: Tag[]): Container;
|
|
22
22
|
dispose(): void;
|
|
23
|
-
getInstances():
|
|
23
|
+
getInstances(): object[];
|
|
24
24
|
hasTag(tag: Tag): boolean;
|
|
25
25
|
use(module: IContainerModule): this;
|
|
26
26
|
hasDependency(key: DependencyKey): boolean;
|
|
@@ -10,7 +10,7 @@ export declare class EmptyContainer implements IContainer {
|
|
|
10
10
|
register(key: DependencyKey, value: IProvider): this;
|
|
11
11
|
resolve<T>(key: InjectionToken<T>, options: ResolveOptions): T;
|
|
12
12
|
getRegistrations(): never[];
|
|
13
|
-
getInstances():
|
|
13
|
+
getInstances(): object[];
|
|
14
14
|
removeScope(): void;
|
|
15
15
|
use(module: IContainerModule): this;
|
|
16
16
|
add(registration: IRegistration): this;
|
|
@@ -28,7 +28,7 @@ export interface IContainer extends Resolvable, Tagged {
|
|
|
28
28
|
register(key: DependencyKey, value: IProvider): this;
|
|
29
29
|
add(registration: IRegistration): this;
|
|
30
30
|
removeScope(child: IContainer): void;
|
|
31
|
-
getInstances():
|
|
31
|
+
getInstances(): object[];
|
|
32
32
|
dispose(): void;
|
|
33
33
|
use(module: IContainerModule): this;
|
|
34
34
|
getRegistrations(): IRegistration[];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { IContainer } from '../container/IContainer';
|
|
2
|
+
export type InjectFn<T = unknown> = (l: IContainer) => T;
|
|
3
|
+
export interface IHookContext {
|
|
4
|
+
instance: object;
|
|
5
|
+
scope: IContainer;
|
|
6
|
+
methodName?: string;
|
|
7
|
+
resolveArgs(...args: unknown[]): unknown[];
|
|
8
|
+
invokeMethod({ args }: {
|
|
9
|
+
args?: unknown[];
|
|
10
|
+
}): unknown;
|
|
11
|
+
injectProperty(fn: InjectFn): void;
|
|
12
|
+
}
|
|
13
|
+
export declare class HookContext implements IHookContext {
|
|
14
|
+
instance: object;
|
|
15
|
+
scope: IContainer;
|
|
16
|
+
methodName?: string | undefined;
|
|
17
|
+
constructor(instance: object, scope: IContainer, methodName?: string | undefined);
|
|
18
|
+
resolveArgs(...args: unknown[]): unknown[];
|
|
19
|
+
invokeMethod({ args }: {
|
|
20
|
+
args?: unknown[];
|
|
21
|
+
}): unknown;
|
|
22
|
+
injectProperty(fn: InjectFn): void;
|
|
23
|
+
}
|
|
24
|
+
export declare const createHookContext: (Target: object, scope: IContainer, methodName?: string) => IHookContext;
|
|
25
|
+
export declare const hookMetaKey: (methodName?: string) => string;
|
package/typings/hooks/hook.d.ts
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { IContainer } from '../container/IContainer';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export declare const hook: (key: string | symbol, ...fns: HookList) => (target: object, propertyKey: string | symbol) => void;
|
|
8
|
-
export declare function getHooks(target: object, key: string | symbol): Hooks;
|
|
2
|
+
import { createHookContext, IHookContext, InjectFn } from './HookContext';
|
|
3
|
+
export type Hook<T extends IHookContext = IHookContext> = (context: T) => void | Promise<void>;
|
|
4
|
+
type HooksOfClass = Map<string, Hook[]>;
|
|
5
|
+
export declare const hook: (key: string | symbol, ...fns: Hook[]) => (target: object, propertyKey: string | symbol) => void;
|
|
6
|
+
export declare function getHooks(target: object, key: string | symbol): HooksOfClass;
|
|
9
7
|
export declare function hasHooks(target: object, key: string | symbol): boolean;
|
|
10
|
-
export declare const
|
|
8
|
+
export declare const runHooks: (target: object, key: string | symbol, { scope, createContext, handleError, }: {
|
|
11
9
|
scope: IContainer;
|
|
12
|
-
|
|
10
|
+
createContext?: ((Target: object, scope: IContainer, methodName?: string) => IHookContext) | undefined;
|
|
13
11
|
handleError: (e: Error, s: IContainer) => void;
|
|
14
|
-
}) => Promise<
|
|
15
|
-
export declare const injectProp: (fn: InjectFn) =>
|
|
16
|
-
type HandleResult = (result: unknown, context:
|
|
12
|
+
}) => Promise<void[]>;
|
|
13
|
+
export declare const injectProp: (fn: InjectFn) => Hook;
|
|
14
|
+
type HandleResult = (result: unknown, context: IHookContext) => void | Promise<void>;
|
|
17
15
|
export declare const invokeExecution: ({ handleResult }: {
|
|
18
16
|
handleResult: HandleResult;
|
|
19
|
-
}) =>
|
|
17
|
+
}) => Hook;
|
|
18
|
+
/**
|
|
19
|
+
* @deprecated Use `runHooks` instead
|
|
20
|
+
* @TODO: Remove in v33
|
|
21
|
+
*/
|
|
22
|
+
export declare const executeHooks: (target: object, key: string | symbol, { scope, createContext, handleError, }: {
|
|
23
|
+
scope: IContainer;
|
|
24
|
+
createContext?: ((Target: object, scope: IContainer, methodName?: string) => IHookContext) | undefined;
|
|
25
|
+
handleError: (e: Error, s: IContainer) => void;
|
|
26
|
+
}) => Promise<void[]>;
|
|
20
27
|
export {};
|
package/typings/index.d.ts
CHANGED
|
@@ -2,8 +2,9 @@ export { IContainer, Resolvable, IContainerModule, isDependencyKey, DependencyKe
|
|
|
2
2
|
export { Container } from './container/Container';
|
|
3
3
|
export { EmptyContainer } from './container/EmptyContainer';
|
|
4
4
|
export { AutoMockedContainer } from './container/AutoMockedContainer';
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
5
|
+
export { inject, resolveArgs } from './injector/inject';
|
|
6
|
+
export { IInjector, InjectOptions } from './injector/IInjector';
|
|
7
|
+
export { MetadataInjector } from './injector/MetadataInjector';
|
|
7
8
|
export { SimpleInjector } from './injector/SimpleInjector';
|
|
8
9
|
export { ProxyInjector } from './injector/ProxyInjector';
|
|
9
10
|
export { ResolveDependency, IProvider, provider, visible, alias, argsFn, args, ArgsFn, ProviderDecorator, ProviderResolveOptions, } from './provider/IProvider';
|
|
@@ -17,8 +18,8 @@ export { Registration } from './registration/Registration';
|
|
|
17
18
|
export { DependencyNotFoundError } from './errors/DependencyNotFoundError';
|
|
18
19
|
export { MethodNotImplementedError } from './errors/MethodNotImplementedError';
|
|
19
20
|
export { ContainerDisposedError } from './errors/ContainerDisposedError';
|
|
20
|
-
export { getHooks, hook, hasHooks,
|
|
21
|
-
export {
|
|
21
|
+
export { getHooks, hook, hasHooks, Hook, executeHooks, runHooks, injectProp, invokeExecution } from './hooks/hook';
|
|
22
|
+
export { HookContext, InjectFn } from './hooks/HookContext';
|
|
22
23
|
export { by, InstancePredicate, IMemo, IMemoKey, byAlias, byAliases } from './by';
|
|
23
24
|
export { constructor } from './utils';
|
|
24
25
|
export { setMetadata, getMetadata, setParameterMetadata, setMethodMetadata, getMethodMetadata, getParameterMetadata, } from './metadata';
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { IInjector, InjectOptions } from './IInjector';
|
|
2
2
|
import { IContainer } from '../container/IContainer';
|
|
3
3
|
import { constructor } from '../utils';
|
|
4
|
-
export type InjectFn<T = unknown> = (l: IContainer) => T;
|
|
5
|
-
export declare const getInjectFns: (Target: constructor<unknown>, methodName?: string) => InjectFn<unknown>[];
|
|
6
|
-
export declare const inject: (fn: InjectFn) => ParameterDecorator;
|
|
7
|
-
export declare const resolveArgs: (Target: constructor<unknown>, methodName?: string) => (scope: IContainer, ...deps: unknown[]) => unknown[];
|
|
8
4
|
export declare class MetadataInjector implements IInjector {
|
|
9
|
-
resolve<T>(
|
|
5
|
+
resolve<T>(scope: IContainer, Target: constructor<T>, { args: deps }: InjectOptions): T;
|
|
10
6
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { constructor } from '../utils';
|
|
2
|
+
import { IContainer } from '../container/IContainer';
|
|
3
|
+
import { InjectFn } from '../hooks/HookContext';
|
|
4
|
+
export declare const inject: (fn: InjectFn) => ParameterDecorator;
|
|
5
|
+
export declare const resolveArgs: (Target: constructor<unknown>, methodName?: string) => (scope: IContainer, ...deps: unknown[]) => unknown[];
|
package/typings/utils.d.ts
CHANGED
|
@@ -5,4 +5,8 @@ export declare function fillEmptyIndexes<T>(baseArr: (T | undefined)[], insertAr
|
|
|
5
5
|
export declare const constant: <T>(value: T) => () => T;
|
|
6
6
|
export declare const isConstructor: (T: unknown) => T is constructor<unknown>;
|
|
7
7
|
export declare function lazyProxy<T>(resolveInstance: () => T): T;
|
|
8
|
-
export declare const promisify: (arg:
|
|
8
|
+
export declare const promisify: <T>(arg: T | Promise<T>) => Promise<T>;
|
|
9
|
+
export interface InstanceOfClass<T = unknown> {
|
|
10
|
+
new (...args: unknown[]): T;
|
|
11
|
+
}
|
|
12
|
+
export declare function isInstance(target: object): target is InstanceOfClass<unknown>;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ExecutionContext = void 0;
|
|
4
|
-
const MetadataInjector_1 = require("../injector/MetadataInjector");
|
|
5
|
-
class ExecutionContext {
|
|
6
|
-
constructor(instance, methodName, scope) {
|
|
7
|
-
this.instance = instance;
|
|
8
|
-
this.methodName = methodName;
|
|
9
|
-
this.scope = scope;
|
|
10
|
-
}
|
|
11
|
-
resolveArgs(...args) {
|
|
12
|
-
return (0, MetadataInjector_1.resolveArgs)(this.instance.constructor, this.methodName)(this.scope, ...args);
|
|
13
|
-
}
|
|
14
|
-
invokeMethod({ args = this.resolveArgs() }) {
|
|
15
|
-
// @ts-ignore
|
|
16
|
-
return this.instance[this.methodName](...args);
|
|
17
|
-
}
|
|
18
|
-
injectProperty(fn) {
|
|
19
|
-
// @ts-ignore
|
|
20
|
-
this.instance[this.methodName] = fn(this.scope);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
exports.ExecutionContext = ExecutionContext;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { InjectFn } from '../injector/MetadataInjector';
|
|
2
|
-
import { IContainer } from '../container/IContainer';
|
|
3
|
-
export declare class ExecutionContext {
|
|
4
|
-
instance: object;
|
|
5
|
-
methodName: string;
|
|
6
|
-
scope: IContainer;
|
|
7
|
-
constructor(instance: object, methodName: string, scope: IContainer);
|
|
8
|
-
resolveArgs(...args: unknown[]): unknown[];
|
|
9
|
-
invokeMethod({ args }: {
|
|
10
|
-
args: unknown[];
|
|
11
|
-
}): unknown;
|
|
12
|
-
injectProperty(fn: InjectFn): void;
|
|
13
|
-
}
|