ts-ioc-container 55.6.0 → 55.7.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 +89 -0
- package/cjm/hooks/onConstructAsync.js +28 -0
- package/cjm/index.js +6 -2
- package/esm/hooks/onConstructAsync.js +23 -0
- package/esm/index.js +1 -0
- package/package.json +1 -1
- package/typings/hooks/onConstructAsync.d.ts +12 -0
- package/typings/index.d.ts +1 -0
package/README.md
CHANGED
|
@@ -53,6 +53,7 @@ provider pipelines, aliases, and custom injector strategies.
|
|
|
53
53
|
- [Module](#module)
|
|
54
54
|
- [Hook](#hook) `@hook`
|
|
55
55
|
- [OnConstruct](#onconstruct) `@onConstruct`
|
|
56
|
+
- [OnConstructAsync](#onconstructasync) `@onConstructAsync`
|
|
56
57
|
- [OnContainerDisposed](#oncontainerdisposed) `@onContainerDisposed`
|
|
57
58
|
- [Inject Property](#inject-property)
|
|
58
59
|
- [Inject Method](#inject-method)
|
|
@@ -2584,6 +2585,94 @@ describe('onConstruct', function () {
|
|
|
2584
2585
|
|
|
2585
2586
|
```
|
|
2586
2587
|
|
|
2588
|
+
### OnConstructAsync
|
|
2589
|
+
|
|
2590
|
+
`@onConstructAsync` runs promise-returning initialization. Resolution stays
|
|
2591
|
+
synchronous: `AddOnConstructAsyncHookModule` starts the hooks when the instance
|
|
2592
|
+
is created and they settle afterwards, so `resolve` returns before they finish.
|
|
2593
|
+
|
|
2594
|
+
```typescript
|
|
2595
|
+
import 'reflect-metadata';
|
|
2596
|
+
import {
|
|
2597
|
+
AddOnConstructAsyncHookModule,
|
|
2598
|
+
Container,
|
|
2599
|
+
type ExecutionContext,
|
|
2600
|
+
type HookFn,
|
|
2601
|
+
inject,
|
|
2602
|
+
onConstructAsync,
|
|
2603
|
+
Registration as R,
|
|
2604
|
+
} from 'ts-ioc-container';
|
|
2605
|
+
|
|
2606
|
+
const execute: HookFn = async (ctx) => {
|
|
2607
|
+
await ctx.invokeMethod({ args: ctx.resolveArgs() });
|
|
2608
|
+
};
|
|
2609
|
+
|
|
2610
|
+
describe('onConstructAsync', function () {
|
|
2611
|
+
it('should run an async initialization method after the instance is created', async function () {
|
|
2612
|
+
class DatabaseConnection {
|
|
2613
|
+
isConnected = false;
|
|
2614
|
+
connectionString = '';
|
|
2615
|
+
readonly ready: Promise<void>;
|
|
2616
|
+
|
|
2617
|
+
private markReady!: () => void;
|
|
2618
|
+
|
|
2619
|
+
constructor() {
|
|
2620
|
+
this.ready = new Promise((resolve) => {
|
|
2621
|
+
this.markReady = resolve;
|
|
2622
|
+
});
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
@onConstructAsync(execute)
|
|
2626
|
+
async connect(@inject('ConnectionString') connectionString: string) {
|
|
2627
|
+
await Promise.resolve();
|
|
2628
|
+
this.connectionString = connectionString;
|
|
2629
|
+
this.isConnected = true;
|
|
2630
|
+
this.markReady();
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
const container = new Container()
|
|
2635
|
+
.useModule(new AddOnConstructAsyncHookModule())
|
|
2636
|
+
.addRegistration(R.fromValue('postgres://localhost:5432').bindTo('ConnectionString'));
|
|
2637
|
+
|
|
2638
|
+
const db = container.resolve(DatabaseConnection);
|
|
2639
|
+
|
|
2640
|
+
// resolution does not wait for async hooks
|
|
2641
|
+
expect(db.isConnected).toBe(false);
|
|
2642
|
+
|
|
2643
|
+
await db.ready;
|
|
2644
|
+
|
|
2645
|
+
expect(db.isConnected).toBe(true);
|
|
2646
|
+
expect(db.connectionString).toBe('postgres://localhost:5432');
|
|
2647
|
+
});
|
|
2648
|
+
|
|
2649
|
+
it('should forward rejected hooks to the onException handler with the execution context', async function () {
|
|
2650
|
+
const failure = new Error('boom');
|
|
2651
|
+
|
|
2652
|
+
class BrokenService {
|
|
2653
|
+
@onConstructAsync(() => Promise.reject(failure))
|
|
2654
|
+
init() {}
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
let captured: { ex: unknown; context: ExecutionContext } | undefined;
|
|
2658
|
+
const container = new Container().useModule(
|
|
2659
|
+
new AddOnConstructAsyncHookModule((ex, context) => {
|
|
2660
|
+
captured = { ex, context };
|
|
2661
|
+
}),
|
|
2662
|
+
);
|
|
2663
|
+
|
|
2664
|
+
const child = container.createScope();
|
|
2665
|
+
child.resolve(BrokenService);
|
|
2666
|
+
|
|
2667
|
+
await vi.waitFor(() => expect(captured).toBeDefined());
|
|
2668
|
+
|
|
2669
|
+
expect(captured?.ex).toBe(failure);
|
|
2670
|
+
expect(captured?.context.scope).toBe(child);
|
|
2671
|
+
});
|
|
2672
|
+
});
|
|
2673
|
+
|
|
2674
|
+
```
|
|
2675
|
+
|
|
2587
2676
|
### OnContainerDisposed
|
|
2588
2677
|
|
|
2589
2678
|
```typescript
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AddOnConstructAsyncHookModule = exports.onConstructAsync = exports.onConstructAsyncHooksRunner = void 0;
|
|
4
|
+
const hook_1 = require("./hook");
|
|
5
|
+
const HooksRunner_1 = require("./HooksRunner");
|
|
6
|
+
exports.onConstructAsyncHooksRunner = new HooksRunner_1.HooksRunner('onConstructAsync');
|
|
7
|
+
const onConstructAsync = (...fns) => (0, hook_1.hook)('onConstructAsync', ...fns);
|
|
8
|
+
exports.onConstructAsync = onConstructAsync;
|
|
9
|
+
class AddOnConstructAsyncHookModule {
|
|
10
|
+
onException;
|
|
11
|
+
constructor(onException) {
|
|
12
|
+
this.onException = onException;
|
|
13
|
+
}
|
|
14
|
+
applyTo(container) {
|
|
15
|
+
container.addOnConstructHook((instance, scope) => {
|
|
16
|
+
if (!exports.onConstructAsyncHooksRunner.hasHooks(instance)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
exports.onConstructAsyncHooksRunner.executeAsync(instance, { scope }).catch((ex) => {
|
|
20
|
+
if (!this.onException) {
|
|
21
|
+
throw ex;
|
|
22
|
+
}
|
|
23
|
+
this.onException(ex, { scope });
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.AddOnConstructAsyncHookModule = AddOnConstructAsyncHookModule;
|
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.resolveConstructor = exports.Is = exports.pipe = exports.select = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.getClassMeta = exports.addClassMeta = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = void 0;
|
|
3
|
+
exports.toGroupAlias = exports.GroupAliasToken = exports.InjectionToken = exports.HooksRunner = exports.AddOnDisposeHookModule = exports.onContainerDisposed = exports.onContainerDisposedHooksRunner = exports.AddOnConstructAsyncHookModule = exports.onConstructAsync = exports.onConstructAsyncHooksRunner = exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = exports.createHookContext = exports.createHookContextFactory = exports.HookContext = exports.hasHooks = exports.hook = exports.getHooks = exports.CannonSingletonApplyTwiceError = exports.UnexpectedHookResultError = exports.ProviderDisposedError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.ContainerNotFoundError = exports.DependencyNotFoundError = exports.Registration = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.argsFn = exports.args = exports.inject = exports.MetadataInjector = exports.Injector = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
|
|
4
|
+
exports.resolveConstructor = exports.Is = exports.pipe = exports.select = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.getClassMeta = exports.addClassMeta = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = void 0;
|
|
5
5
|
var IContainer_1 = require("./container/IContainer");
|
|
6
6
|
Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
|
|
7
7
|
var Container_1 = require("./container/Container");
|
|
@@ -64,6 +64,10 @@ var onConstruct_1 = require("./hooks/onConstruct");
|
|
|
64
64
|
Object.defineProperty(exports, "onConstructHooksRunner", { enumerable: true, get: function () { return onConstruct_1.onConstructHooksRunner; } });
|
|
65
65
|
Object.defineProperty(exports, "onConstruct", { enumerable: true, get: function () { return onConstruct_1.onConstruct; } });
|
|
66
66
|
Object.defineProperty(exports, "AddOnConstructHookModule", { enumerable: true, get: function () { return onConstruct_1.AddOnConstructHookModule; } });
|
|
67
|
+
var onConstructAsync_1 = require("./hooks/onConstructAsync");
|
|
68
|
+
Object.defineProperty(exports, "onConstructAsyncHooksRunner", { enumerable: true, get: function () { return onConstructAsync_1.onConstructAsyncHooksRunner; } });
|
|
69
|
+
Object.defineProperty(exports, "onConstructAsync", { enumerable: true, get: function () { return onConstructAsync_1.onConstructAsync; } });
|
|
70
|
+
Object.defineProperty(exports, "AddOnConstructAsyncHookModule", { enumerable: true, get: function () { return onConstructAsync_1.AddOnConstructAsyncHookModule; } });
|
|
67
71
|
var onContainerDisposed_1 = require("./hooks/onContainerDisposed");
|
|
68
72
|
Object.defineProperty(exports, "onContainerDisposedHooksRunner", { enumerable: true, get: function () { return onContainerDisposed_1.onContainerDisposedHooksRunner; } });
|
|
69
73
|
Object.defineProperty(exports, "onContainerDisposed", { enumerable: true, get: function () { return onContainerDisposed_1.onContainerDisposed; } });
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { hook } from './hook.js';
|
|
2
|
+
import { HooksRunner } from './HooksRunner.js';
|
|
3
|
+
export const onConstructAsyncHooksRunner = new HooksRunner('onConstructAsync');
|
|
4
|
+
export const onConstructAsync = (...fns) => hook('onConstructAsync', ...fns);
|
|
5
|
+
export class AddOnConstructAsyncHookModule {
|
|
6
|
+
onException;
|
|
7
|
+
constructor(onException) {
|
|
8
|
+
this.onException = onException;
|
|
9
|
+
}
|
|
10
|
+
applyTo(container) {
|
|
11
|
+
container.addOnConstructHook((instance, scope) => {
|
|
12
|
+
if (!onConstructAsyncHooksRunner.hasHooks(instance)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
onConstructAsyncHooksRunner.executeAsync(instance, { scope }).catch((ex) => {
|
|
16
|
+
if (!this.onException) {
|
|
17
|
+
throw ex;
|
|
18
|
+
}
|
|
19
|
+
this.onException(ex, { scope });
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
package/esm/index.js
CHANGED
|
@@ -20,6 +20,7 @@ export { getHooks, hook, hasHooks } from './hooks/hook.js';
|
|
|
20
20
|
export { HookContext, createHookContextFactory, createHookContext } from './hooks/HookContext.js';
|
|
21
21
|
export { injectProp } from './hooks/injectProp.js';
|
|
22
22
|
export { onConstructHooksRunner, onConstruct, AddOnConstructHookModule, } from './hooks/onConstruct.js';
|
|
23
|
+
export { onConstructAsyncHooksRunner, onConstructAsync, AddOnConstructAsyncHookModule } from './hooks/onConstructAsync.js';
|
|
23
24
|
export { onContainerDisposedHooksRunner, onContainerDisposed, AddOnDisposeHookModule, } from './hooks/onContainerDisposed.js';
|
|
24
25
|
export { HooksRunner } from './hooks/HooksRunner.js';
|
|
25
26
|
export { InjectionToken } from './token/InjectionToken.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-ioc-container",
|
|
3
|
-
"version": "55.
|
|
3
|
+
"version": "55.7.0",
|
|
4
4
|
"description": "Fast, lightweight TypeScript dependency injection container with a clean API, scoped lifecycles, decorators, tokens, hooks, lazy injection, customizable providers, and no global container objects.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HookClass, HookFn } from './hook.js';
|
|
2
|
+
import type { IContainer, IContainerModule } from '../container/IContainer.js';
|
|
3
|
+
import { constructor } from '../utils/basic.js';
|
|
4
|
+
import { HooksRunner } from './HooksRunner.js';
|
|
5
|
+
import type { OnExceptionHandler } from './onConstruct.js';
|
|
6
|
+
export declare const onConstructAsyncHooksRunner: HooksRunner;
|
|
7
|
+
export declare const onConstructAsync: (...fns: (HookFn | constructor<HookClass>)[]) => (target: object, propertyKey: string | symbol) => void;
|
|
8
|
+
export declare class AddOnConstructAsyncHookModule implements IContainerModule {
|
|
9
|
+
private readonly onException?;
|
|
10
|
+
constructor(onException?: OnExceptionHandler | undefined);
|
|
11
|
+
applyTo(container: IContainer): void;
|
|
12
|
+
}
|
package/typings/index.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export { getHooks, hook, hasHooks, type HookFn, type HookClass, type InjectFn, t
|
|
|
21
21
|
export { HookContext, createHookContextFactory, createHookContext, type IHookContext } from './hooks/HookContext.js';
|
|
22
22
|
export { injectProp } from './hooks/injectProp.js';
|
|
23
23
|
export { onConstructHooksRunner, onConstruct, AddOnConstructHookModule, type OnExceptionHandler, } from './hooks/onConstruct.js';
|
|
24
|
+
export { onConstructAsyncHooksRunner, onConstructAsync, AddOnConstructAsyncHookModule } from './hooks/onConstructAsync.js';
|
|
24
25
|
export { onContainerDisposedHooksRunner, onContainerDisposed, AddOnDisposeHookModule, } from './hooks/onContainerDisposed.js';
|
|
25
26
|
export { HooksRunner, type HooksRunnerContext, type MapHookContext } from './hooks/HooksRunner.js';
|
|
26
27
|
export { InjectionToken } from './token/InjectionToken.js';
|