ts-ioc-container 55.5.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 +120 -8
- package/cjm/container/AliasMap.js +0 -1
- package/cjm/container/Container.js +0 -5
- package/cjm/hooks/HookContext.js +0 -3
- package/cjm/hooks/hook.js +0 -5
- package/cjm/hooks/onConstructAsync.js +28 -0
- package/cjm/hooks/onContainerDisposed.js +18 -0
- package/cjm/index.js +10 -14
- package/cjm/injector/IInjector.js +0 -1
- package/cjm/utils/fp.js +0 -3
- package/cjm/utils/proxy.js +0 -1
- package/esm/container/AliasMap.js +0 -1
- package/esm/container/Container.js +7 -12
- package/esm/container/EmptyContainer.js +3 -3
- package/esm/errors/CannonSingletonApplyTwiceError.js +1 -1
- package/esm/errors/ContainerDisposedError.js +1 -1
- package/esm/errors/ContainerNotFoundError.js +1 -1
- package/esm/errors/DependencyMissingKeyError.js +1 -1
- package/esm/errors/DependencyNotFoundError.js +1 -1
- package/esm/errors/MethodNotImplementedError.js +1 -1
- package/esm/errors/ProviderDisposedError.js +1 -1
- package/esm/errors/UnexpectedHookResultError.js +1 -1
- package/esm/errors/UnsupportedTokenTypeError.js +1 -1
- package/esm/hooks/HookContext.js +2 -5
- package/esm/hooks/HooksRunner.js +4 -4
- package/esm/hooks/hook.js +2 -7
- package/esm/hooks/injectProp.js +1 -1
- package/esm/hooks/onConstruct.js +2 -2
- package/esm/hooks/onConstructAsync.js +23 -0
- package/esm/hooks/onContainerDisposed.js +13 -0
- package/esm/index.js +44 -51
- package/esm/injector/IInjector.js +1 -2
- package/esm/injector/MetadataInjector.js +4 -4
- package/esm/injector/ProxyInjector.js +1 -1
- package/esm/injector/SimpleInjector.js +1 -1
- package/esm/metadata/class.js +1 -1
- package/esm/metadata/method.js +1 -1
- package/esm/metadata/parameter.js +1 -1
- package/esm/package.json +3 -0
- package/esm/provider/Provider.js +2 -2
- package/esm/registration/IRegistration.js +3 -3
- package/esm/registration/Registration.js +8 -8
- package/esm/select.js +4 -4
- package/esm/token/BindToken.js +1 -1
- package/esm/token/ClassToken.js +1 -1
- package/esm/token/ConstantToken.js +2 -2
- package/esm/token/FunctionToken.js +1 -1
- package/esm/token/GroupAliasToken.js +1 -1
- package/esm/token/GroupInstanceToken.js +2 -2
- package/esm/token/InjectionToken.js +1 -1
- package/esm/token/SingleAliasToken.js +1 -1
- package/esm/token/SingleToken.js +1 -1
- package/esm/token/toToken.js +8 -8
- package/esm/utils/fp.js +0 -3
- package/esm/utils/proxy.js +0 -1
- package/package.json +25 -11
- package/typings/ExecutionContext.d.ts +1 -1
- package/typings/container/AliasMap.d.ts +1 -1
- package/typings/container/Container.d.ts +7 -7
- package/typings/container/EmptyContainer.d.ts +6 -6
- package/typings/container/IContainer.d.ts +5 -5
- package/typings/errors/CannonSingletonApplyTwiceError.d.ts +1 -1
- package/typings/errors/ContainerDisposedError.d.ts +1 -1
- package/typings/errors/ContainerNotFoundError.d.ts +1 -1
- package/typings/errors/DependencyMissingKeyError.d.ts +1 -1
- package/typings/errors/DependencyNotFoundError.d.ts +1 -1
- package/typings/errors/MethodNotImplementedError.d.ts +1 -1
- package/typings/errors/ProviderDisposedError.d.ts +1 -1
- package/typings/errors/UnexpectedHookResultError.d.ts +1 -1
- package/typings/errors/UnsupportedTokenTypeError.d.ts +1 -1
- package/typings/hooks/HookContext.d.ts +2 -2
- package/typings/hooks/HooksRunner.d.ts +2 -2
- package/typings/hooks/hook.d.ts +4 -4
- package/typings/hooks/injectProp.d.ts +4 -4
- package/typings/hooks/onConstruct.d.ts +5 -5
- package/typings/hooks/onConstructAsync.d.ts +12 -0
- package/typings/hooks/onContainerDisposed.d.ts +10 -0
- package/typings/index.d.ts +46 -45
- package/typings/injector/IInjector.d.ts +3 -3
- package/typings/injector/MetadataInjector.d.ts +6 -6
- package/typings/injector/ProxyInjector.d.ts +3 -3
- package/typings/injector/SimpleInjector.d.ts +3 -3
- package/typings/provider/IProvider.d.ts +2 -2
- package/typings/provider/Provider.d.ts +3 -3
- package/typings/registration/IRegistration.d.ts +5 -5
- package/typings/registration/Registration.d.ts +6 -6
- package/typings/select.d.ts +5 -5
- package/typings/token/BindToken.d.ts +1 -1
- package/typings/token/ClassToken.d.ts +4 -4
- package/typings/token/ConstantToken.d.ts +2 -2
- package/typings/token/FunctionToken.d.ts +4 -4
- package/typings/token/GroupAliasToken.d.ts +5 -5
- package/typings/token/GroupInstanceToken.d.ts +3 -3
- package/typings/token/InjectionToken.d.ts +2 -2
- package/typings/token/SingleAliasToken.d.ts +5 -5
- package/typings/token/SingleToken.d.ts +4 -4
- package/typings/token/toToken.d.ts +4 -4
- package/cjm/hooks/onDispose.js +0 -18
- package/esm/hooks/onDispose.js +0 -13
- package/typings/hooks/onDispose.d.ts +0 -10
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ provider pipelines, aliases, and custom injector strategies.
|
|
|
19
19
|
- clean API for classes, keys, tokens, aliases, and scopes
|
|
20
20
|
- no global container object; pass containers and scopes explicitly
|
|
21
21
|
- supports tagged application, request, transaction, page, and widget scopes
|
|
22
|
-
- decorator support with `@register`, `@inject`, `@onConstruct`, and `@
|
|
22
|
+
- decorator support with `@register`, `@inject`, `@onConstruct`, and `@onContainerDisposed`
|
|
23
23
|
- can [inject properties](#inject-property)
|
|
24
24
|
- can inject [lazy dependencies](#lazy)
|
|
25
25
|
- composable provider and registration pipelines
|
|
@@ -27,6 +27,7 @@ provider pipelines, aliases, and custom injector strategies.
|
|
|
27
27
|
## Content
|
|
28
28
|
|
|
29
29
|
- [Setup](#setup)
|
|
30
|
+
- [Environment support](#environment-support)
|
|
30
31
|
- [Quickstart](#quickstart)
|
|
31
32
|
- [Cheatsheet](#cheatsheet)
|
|
32
33
|
- [Container](#container)
|
|
@@ -52,7 +53,8 @@ provider pipelines, aliases, and custom injector strategies.
|
|
|
52
53
|
- [Module](#module)
|
|
53
54
|
- [Hook](#hook) `@hook`
|
|
54
55
|
- [OnConstruct](#onconstruct) `@onConstruct`
|
|
55
|
-
- [
|
|
56
|
+
- [OnConstructAsync](#onconstructasync) `@onConstructAsync`
|
|
57
|
+
- [OnContainerDisposed](#oncontainerdisposed) `@onContainerDisposed`
|
|
56
58
|
- [Inject Property](#inject-property)
|
|
57
59
|
- [Inject Method](#inject-method)
|
|
58
60
|
- [Mock](#mock)
|
|
@@ -85,6 +87,28 @@ And `tsconfig.json` should have next options:
|
|
|
85
87
|
}
|
|
86
88
|
```
|
|
87
89
|
|
|
90
|
+
## Environment support
|
|
91
|
+
|
|
92
|
+
`ts-ioc-container` ships both CommonJS and ES module builds (selected
|
|
93
|
+
automatically via the package `exports` map) plus TypeScript declarations, so it
|
|
94
|
+
runs anywhere modern JavaScript does. The package is `sideEffects`-free, so
|
|
95
|
+
bundlers tree-shake unused exports.
|
|
96
|
+
|
|
97
|
+
| Environment | Supported | Module format | Notes |
|
|
98
|
+
| --- | :---: | --- | --- |
|
|
99
|
+
| Node.js (ESM, `import`) | ✅ | ESM | Node.js 18+; resolved via the `import` condition. |
|
|
100
|
+
| Node.js (CommonJS, `require`) | ✅ | CJS | Node.js 18+; resolved via the `require` condition. |
|
|
101
|
+
| Browser / Web (via bundlers) | ✅ | ESM | webpack, Vite, Rollup, esbuild, Parcel; tree-shakeable. |
|
|
102
|
+
| TypeScript | ✅ | CJS + ESM | Types shipped for both; needs `experimentalDecorators` for the metadata injector. |
|
|
103
|
+
| Deno | ✅ | ESM | Use the `npm:ts-ioc-container` specifier. |
|
|
104
|
+
| Bun | ✅ | CJS + ESM | Runs the native ESM/CJS builds directly. |
|
|
105
|
+
|
|
106
|
+
> [!NOTE]
|
|
107
|
+
> The default `MetadataInjector` (and the `@inject` / `@onConstruct` /
|
|
108
|
+
> `@onContainerDisposed` decorators) rely on `reflect-metadata`. It is declared as an
|
|
109
|
+
> optional peer dependency — install it and import it once at your entrypoint.
|
|
110
|
+
> `SimpleInjector` and `ProxyInjector` do not need it.
|
|
111
|
+
|
|
88
112
|
## Quickstart
|
|
89
113
|
|
|
90
114
|
```typescript
|
|
@@ -426,7 +450,7 @@ describe('Instances', function () {
|
|
|
426
450
|
Sometimes you want to dispose a container or scope. For example, when a request, page, widget, or other local lifecycle ends.
|
|
427
451
|
|
|
428
452
|
- container can be disposed
|
|
429
|
-
- when container is disposed then it runs its `
|
|
453
|
+
- when container is disposed then it runs its `onContainerDisposed` hooks, unregisters its providers, removes its local instances, and detaches from its parent
|
|
430
454
|
|
|
431
455
|
> [!IMPORTANT]
|
|
432
456
|
> Dispose is local to the container being disposed. Child scopes are not disposed automatically; dispose them explicitly when their own lifecycle ends.
|
|
@@ -445,7 +469,7 @@ import { bindTo, Container, ContainerDisposedError, register, Registration as R,
|
|
|
445
469
|
* - Cache entries cleared
|
|
446
470
|
*
|
|
447
471
|
* The container.dispose() method:
|
|
448
|
-
* 1. Executes all
|
|
472
|
+
* 1. Executes all onContainerDisposed hooks
|
|
449
473
|
* 2. Clears all instances and registrations
|
|
450
474
|
* 3. Detaches from parent scope
|
|
451
475
|
* 4. Prevents further resolution
|
|
@@ -2561,7 +2585,95 @@ describe('onConstruct', function () {
|
|
|
2561
2585
|
|
|
2562
2586
|
```
|
|
2563
2587
|
|
|
2564
|
-
###
|
|
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
|
+
|
|
2676
|
+
### OnContainerDisposed
|
|
2565
2677
|
|
|
2566
2678
|
```typescript
|
|
2567
2679
|
import 'reflect-metadata';
|
|
@@ -2571,7 +2683,7 @@ import {
|
|
|
2571
2683
|
Container,
|
|
2572
2684
|
type HookFn,
|
|
2573
2685
|
inject,
|
|
2574
|
-
|
|
2686
|
+
onContainerDisposed,
|
|
2575
2687
|
register,
|
|
2576
2688
|
Registration as R,
|
|
2577
2689
|
singleton,
|
|
@@ -2600,13 +2712,13 @@ class Logger {
|
|
|
2600
2712
|
this.messages.push(message);
|
|
2601
2713
|
}
|
|
2602
2714
|
|
|
2603
|
-
@
|
|
2715
|
+
@onContainerDisposed(execute)
|
|
2604
2716
|
save() {
|
|
2605
2717
|
this.logsRepo.saveLogs(this.messages);
|
|
2606
2718
|
}
|
|
2607
2719
|
}
|
|
2608
2720
|
|
|
2609
|
-
describe('
|
|
2721
|
+
describe('onContainerDisposed', function () {
|
|
2610
2722
|
it('should invoke hooks on all instances when container is disposed', function () {
|
|
2611
2723
|
const container = new Container()
|
|
2612
2724
|
.useModule(new AddOnDisposeHookModule())
|
|
@@ -83,15 +83,12 @@ class Container {
|
|
|
83
83
|
dispose() {
|
|
84
84
|
this.validateContainer();
|
|
85
85
|
this.isDisposed = true;
|
|
86
|
-
// Execute onDispose hooks
|
|
87
86
|
while (this.onDisposeHookList.length) {
|
|
88
87
|
const onDispose = this.onDisposeHookList.shift();
|
|
89
88
|
onDispose(this);
|
|
90
89
|
}
|
|
91
|
-
// Detach from parent
|
|
92
90
|
this.parent.removeScope(this);
|
|
93
91
|
this.parent = new EmptyContainer_1.EmptyContainer();
|
|
94
|
-
// Reset the state
|
|
95
92
|
for (const [_, provider] of this.providers) {
|
|
96
93
|
provider.dispose();
|
|
97
94
|
}
|
|
@@ -99,7 +96,6 @@ class Container {
|
|
|
99
96
|
this.aliases.destroy();
|
|
100
97
|
this.instances = [];
|
|
101
98
|
this.registrations = [];
|
|
102
|
-
// Clear hooks
|
|
103
99
|
this.onConstructHookList.splice(0, this.onConstructHookList.length);
|
|
104
100
|
}
|
|
105
101
|
addRegistration(registration) {
|
|
@@ -123,7 +119,6 @@ class Container {
|
|
|
123
119
|
}
|
|
124
120
|
addInstance(instance) {
|
|
125
121
|
this.instances.push(instance);
|
|
126
|
-
// Execute onConstruct hooks
|
|
127
122
|
for (const onConstruct of this.onConstructHookList) {
|
|
128
123
|
onConstruct(instance, this);
|
|
129
124
|
}
|
package/cjm/hooks/HookContext.js
CHANGED
|
@@ -19,15 +19,12 @@ class HookContext {
|
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
invokeMethod({ args = this.resolveArgs() } = {}) {
|
|
22
|
-
// @ts-ignore
|
|
23
22
|
return this.instance[this.methodName](...args);
|
|
24
23
|
}
|
|
25
24
|
setProperty(fn) {
|
|
26
|
-
// @ts-ignore
|
|
27
25
|
this.instance[this.methodName] = fn.resolve(this.scope);
|
|
28
26
|
}
|
|
29
27
|
getProperty() {
|
|
30
|
-
// @ts-ignore
|
|
31
28
|
return this.instance[this.methodName];
|
|
32
29
|
}
|
|
33
30
|
setInitialArgs(...args) {
|
package/cjm/hooks/hook.js
CHANGED
|
@@ -13,7 +13,6 @@ exports.toHookFn = toHookFn;
|
|
|
13
13
|
const getReflectionTarget = (target) => {
|
|
14
14
|
return (0, proxy_1.isProxy)(target) ? (0, proxy_1.getProxyTarget)(target) : target;
|
|
15
15
|
};
|
|
16
|
-
// Walk the constructor's prototype chain (most-derived first) collecting each class.
|
|
17
16
|
const getConstructorChain = (ctor) => {
|
|
18
17
|
const chain = [];
|
|
19
18
|
let current = ctor;
|
|
@@ -23,9 +22,6 @@ const getConstructorChain = (ctor) => {
|
|
|
23
22
|
}
|
|
24
23
|
return chain;
|
|
25
24
|
};
|
|
26
|
-
// Get hooks metadata, merging hooks declared on parent (extended-from) classes.
|
|
27
|
-
// Hooks are collected from base to derived so a derived class's hooks for the same
|
|
28
|
-
// method name take precedence over (replace) the parent's.
|
|
29
25
|
function getHooks(target, key) {
|
|
30
26
|
const reflectionTarget = getReflectionTarget(target);
|
|
31
27
|
const merged = new Map();
|
|
@@ -43,7 +39,6 @@ function hasHooks(target, key) {
|
|
|
43
39
|
const reflectionTarget = getReflectionTarget(target);
|
|
44
40
|
return getConstructorChain(reflectionTarget.constructor).some((ctor) => Reflect.hasOwnMetadata(key, ctor));
|
|
45
41
|
}
|
|
46
|
-
// Hook decorator
|
|
47
42
|
const hook = (key, ...fns) => (target, propertyKey) => {
|
|
48
43
|
const hooks = Reflect.hasOwnMetadata(key, target.constructor)
|
|
49
44
|
? Reflect.getOwnMetadata(key, target.constructor)
|
|
@@ -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;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AddOnDisposeHookModule = exports.onContainerDisposed = exports.onContainerDisposedHooksRunner = void 0;
|
|
4
|
+
const hook_1 = require("./hook");
|
|
5
|
+
const HooksRunner_1 = require("./HooksRunner");
|
|
6
|
+
exports.onContainerDisposedHooksRunner = new HooksRunner_1.HooksRunner('onContainerDisposed');
|
|
7
|
+
const onContainerDisposed = (...fns) => (0, hook_1.hook)('onContainerDisposed', ...fns);
|
|
8
|
+
exports.onContainerDisposed = onContainerDisposed;
|
|
9
|
+
class AddOnDisposeHookModule {
|
|
10
|
+
applyTo(container) {
|
|
11
|
+
container.addOnDisposeHook((scope) => {
|
|
12
|
+
for (const instance of scope.getInstances()) {
|
|
13
|
+
exports.onContainerDisposedHooksRunner.execute(instance, { scope });
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.AddOnDisposeHookModule = AddOnDisposeHookModule;
|
package/cjm/index.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
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;
|
|
5
|
-
// Containers
|
|
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;
|
|
6
5
|
var IContainer_1 = require("./container/IContainer");
|
|
7
6
|
Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
|
|
8
7
|
var Container_1 = require("./container/Container");
|
|
9
8
|
Object.defineProperty(exports, "Container", { enumerable: true, get: function () { return Container_1.Container; } });
|
|
10
9
|
var EmptyContainer_1 = require("./container/EmptyContainer");
|
|
11
10
|
Object.defineProperty(exports, "EmptyContainer", { enumerable: true, get: function () { return EmptyContainer_1.EmptyContainer; } });
|
|
12
|
-
// Injectors
|
|
13
11
|
var IInjector_1 = require("./injector/IInjector");
|
|
14
12
|
Object.defineProperty(exports, "Injector", { enumerable: true, get: function () { return IInjector_1.Injector; } });
|
|
15
13
|
var MetadataInjector_1 = require("./injector/MetadataInjector");
|
|
@@ -24,7 +22,6 @@ var ProxyInjector_1 = require("./injector/ProxyInjector");
|
|
|
24
22
|
Object.defineProperty(exports, "ProxyInjector", { enumerable: true, get: function () { return ProxyInjector_1.ProxyInjector; } });
|
|
25
23
|
var Provider_1 = require("./provider/Provider");
|
|
26
24
|
Object.defineProperty(exports, "Provider", { enumerable: true, get: function () { return Provider_1.Provider; } });
|
|
27
|
-
// Registrations
|
|
28
25
|
var IRegistration_1 = require("./registration/IRegistration");
|
|
29
26
|
Object.defineProperty(exports, "register", { enumerable: true, get: function () { return IRegistration_1.register; } });
|
|
30
27
|
Object.defineProperty(exports, "bindTo", { enumerable: true, get: function () { return IRegistration_1.bindTo; } });
|
|
@@ -37,7 +34,6 @@ Object.defineProperty(exports, "appendArgs", { enumerable: true, get: function (
|
|
|
37
34
|
Object.defineProperty(exports, "appendArgsFn", { enumerable: true, get: function () { return IRegistration_1.appendArgsFn; } });
|
|
38
35
|
var Registration_1 = require("./registration/Registration");
|
|
39
36
|
Object.defineProperty(exports, "Registration", { enumerable: true, get: function () { return Registration_1.Registration; } });
|
|
40
|
-
// Errors
|
|
41
37
|
var DependencyNotFoundError_1 = require("./errors/DependencyNotFoundError");
|
|
42
38
|
Object.defineProperty(exports, "DependencyNotFoundError", { enumerable: true, get: function () { return DependencyNotFoundError_1.DependencyNotFoundError; } });
|
|
43
39
|
var ContainerNotFoundError_1 = require("./errors/ContainerNotFoundError");
|
|
@@ -54,7 +50,6 @@ var UnexpectedHookResultError_1 = require("./errors/UnexpectedHookResultError");
|
|
|
54
50
|
Object.defineProperty(exports, "UnexpectedHookResultError", { enumerable: true, get: function () { return UnexpectedHookResultError_1.UnexpectedHookResultError; } });
|
|
55
51
|
var CannonSingletonApplyTwiceError_1 = require("./errors/CannonSingletonApplyTwiceError");
|
|
56
52
|
Object.defineProperty(exports, "CannonSingletonApplyTwiceError", { enumerable: true, get: function () { return CannonSingletonApplyTwiceError_1.CannonSingletonApplyTwiceError; } });
|
|
57
|
-
// Hooks
|
|
58
53
|
var hook_1 = require("./hooks/hook");
|
|
59
54
|
Object.defineProperty(exports, "getHooks", { enumerable: true, get: function () { return hook_1.getHooks; } });
|
|
60
55
|
Object.defineProperty(exports, "hook", { enumerable: true, get: function () { return hook_1.hook; } });
|
|
@@ -69,13 +64,16 @@ var onConstruct_1 = require("./hooks/onConstruct");
|
|
|
69
64
|
Object.defineProperty(exports, "onConstructHooksRunner", { enumerable: true, get: function () { return onConstruct_1.onConstructHooksRunner; } });
|
|
70
65
|
Object.defineProperty(exports, "onConstruct", { enumerable: true, get: function () { return onConstruct_1.onConstruct; } });
|
|
71
66
|
Object.defineProperty(exports, "AddOnConstructHookModule", { enumerable: true, get: function () { return onConstruct_1.AddOnConstructHookModule; } });
|
|
72
|
-
var
|
|
73
|
-
Object.defineProperty(exports, "
|
|
74
|
-
Object.defineProperty(exports, "
|
|
75
|
-
Object.defineProperty(exports, "
|
|
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; } });
|
|
71
|
+
var onContainerDisposed_1 = require("./hooks/onContainerDisposed");
|
|
72
|
+
Object.defineProperty(exports, "onContainerDisposedHooksRunner", { enumerable: true, get: function () { return onContainerDisposed_1.onContainerDisposedHooksRunner; } });
|
|
73
|
+
Object.defineProperty(exports, "onContainerDisposed", { enumerable: true, get: function () { return onContainerDisposed_1.onContainerDisposed; } });
|
|
74
|
+
Object.defineProperty(exports, "AddOnDisposeHookModule", { enumerable: true, get: function () { return onContainerDisposed_1.AddOnDisposeHookModule; } });
|
|
76
75
|
var HooksRunner_1 = require("./hooks/HooksRunner");
|
|
77
76
|
Object.defineProperty(exports, "HooksRunner", { enumerable: true, get: function () { return HooksRunner_1.HooksRunner; } });
|
|
78
|
-
// Tokens
|
|
79
77
|
var InjectionToken_1 = require("./token/InjectionToken");
|
|
80
78
|
Object.defineProperty(exports, "InjectionToken", { enumerable: true, get: function () { return InjectionToken_1.InjectionToken; } });
|
|
81
79
|
var GroupAliasToken_1 = require("./token/GroupAliasToken");
|
|
@@ -94,7 +92,6 @@ var ConstantToken_1 = require("./token/ConstantToken");
|
|
|
94
92
|
Object.defineProperty(exports, "ConstantToken", { enumerable: true, get: function () { return ConstantToken_1.ConstantToken; } });
|
|
95
93
|
var GroupInstanceToken_1 = require("./token/GroupInstanceToken");
|
|
96
94
|
Object.defineProperty(exports, "GroupInstanceToken", { enumerable: true, get: function () { return GroupInstanceToken_1.GroupInstanceToken; } });
|
|
97
|
-
// Metadata
|
|
98
95
|
var class_1 = require("./metadata/class");
|
|
99
96
|
Object.defineProperty(exports, "addClassMeta", { enumerable: true, get: function () { return class_1.addClassMeta; } });
|
|
100
97
|
Object.defineProperty(exports, "getClassMeta", { enumerable: true, get: function () { return class_1.getClassMeta; } });
|
|
@@ -127,7 +124,6 @@ var shallowCache_1 = require("./utils/shallowCache");
|
|
|
127
124
|
Object.defineProperty(exports, "shallowCache", { enumerable: true, get: function () { return shallowCache_1.shallowCache; } });
|
|
128
125
|
var once_1 = require("./utils/once");
|
|
129
126
|
Object.defineProperty(exports, "once", { enumerable: true, get: function () { return once_1.once; } });
|
|
130
|
-
// Utils
|
|
131
127
|
var select_1 = require("./select");
|
|
132
128
|
Object.defineProperty(exports, "select", { enumerable: true, get: function () { return select_1.select; } });
|
|
133
129
|
var fp_1 = require("./utils/fp");
|
|
@@ -4,7 +4,6 @@ exports.Injector = void 0;
|
|
|
4
4
|
const proxy_1 = require("../utils/proxy");
|
|
5
5
|
class Injector {
|
|
6
6
|
resolve(scope, Target, { args, lazy } = {}) {
|
|
7
|
-
// @ts-ignore
|
|
8
7
|
return (0, proxy_1.toLazyIf)(() => {
|
|
9
8
|
const instance = this.createInstance(scope, Target, { args });
|
|
10
9
|
scope.addInstance(instance);
|
package/cjm/utils/fp.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.pipe = pipe;
|
|
4
|
-
// Implementation
|
|
5
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
4
|
function pipe(...mappers) {
|
|
7
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
5
|
return (value) => mappers.reduce((acc, current) => current(acc), value);
|
|
9
6
|
}
|
package/cjm/utils/proxy.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { EmptyContainer } from './EmptyContainer';
|
|
2
|
-
import { ContainerDisposedError } from '../errors/ContainerDisposedError';
|
|
3
|
-
import { MetadataInjector } from '../injector/MetadataInjector';
|
|
4
|
-
import { AliasMap } from './AliasMap';
|
|
5
|
-
import { DependencyNotFoundError } from '../errors/DependencyNotFoundError';
|
|
6
|
-
import { Is } from '../utils/basic';
|
|
7
|
-
import { Filter as F } from '../utils/array';
|
|
1
|
+
import { EmptyContainer } from './EmptyContainer.js';
|
|
2
|
+
import { ContainerDisposedError } from '../errors/ContainerDisposedError.js';
|
|
3
|
+
import { MetadataInjector } from '../injector/MetadataInjector.js';
|
|
4
|
+
import { AliasMap } from './AliasMap.js';
|
|
5
|
+
import { DependencyNotFoundError } from '../errors/DependencyNotFoundError.js';
|
|
6
|
+
import { Is } from '../utils/basic.js';
|
|
7
|
+
import { Filter as F } from '../utils/array.js';
|
|
8
8
|
export class Container {
|
|
9
9
|
isDisposed = false;
|
|
10
10
|
parent;
|
|
@@ -80,15 +80,12 @@ export class Container {
|
|
|
80
80
|
dispose() {
|
|
81
81
|
this.validateContainer();
|
|
82
82
|
this.isDisposed = true;
|
|
83
|
-
// Execute onDispose hooks
|
|
84
83
|
while (this.onDisposeHookList.length) {
|
|
85
84
|
const onDispose = this.onDisposeHookList.shift();
|
|
86
85
|
onDispose(this);
|
|
87
86
|
}
|
|
88
|
-
// Detach from parent
|
|
89
87
|
this.parent.removeScope(this);
|
|
90
88
|
this.parent = new EmptyContainer();
|
|
91
|
-
// Reset the state
|
|
92
89
|
for (const [_, provider] of this.providers) {
|
|
93
90
|
provider.dispose();
|
|
94
91
|
}
|
|
@@ -96,7 +93,6 @@ export class Container {
|
|
|
96
93
|
this.aliases.destroy();
|
|
97
94
|
this.instances = [];
|
|
98
95
|
this.registrations = [];
|
|
99
|
-
// Clear hooks
|
|
100
96
|
this.onConstructHookList.splice(0, this.onConstructHookList.length);
|
|
101
97
|
}
|
|
102
98
|
addRegistration(registration) {
|
|
@@ -120,7 +116,6 @@ export class Container {
|
|
|
120
116
|
}
|
|
121
117
|
addInstance(instance) {
|
|
122
118
|
this.instances.push(instance);
|
|
123
|
-
// Execute onConstruct hooks
|
|
124
119
|
for (const onConstruct of this.onConstructHookList) {
|
|
125
120
|
onConstruct(instance, this);
|
|
126
121
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { MethodNotImplementedError } from '../errors/MethodNotImplementedError';
|
|
2
|
-
import { DependencyNotFoundError } from '../errors/DependencyNotFoundError';
|
|
3
|
-
import { ContainerNotFoundError } from '../errors/ContainerNotFoundError';
|
|
1
|
+
import { MethodNotImplementedError } from '../errors/MethodNotImplementedError.js';
|
|
2
|
+
import { DependencyNotFoundError } from '../errors/DependencyNotFoundError.js';
|
|
3
|
+
import { ContainerNotFoundError } from '../errors/ContainerNotFoundError.js';
|
|
4
4
|
export class EmptyContainer {
|
|
5
5
|
get isDisposed() {
|
|
6
6
|
throw new MethodNotImplementedError();
|
package/esm/hooks/HookContext.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getProxyTarget, isProxy } from '../utils/proxy';
|
|
2
|
-
import { resolveArgs } from '../injector/MetadataInjector';
|
|
1
|
+
import { getProxyTarget, isProxy } from '../utils/proxy.js';
|
|
2
|
+
import { resolveArgs } from '../injector/MetadataInjector.js';
|
|
3
3
|
export class HookContext {
|
|
4
4
|
scope;
|
|
5
5
|
methodName;
|
|
@@ -16,15 +16,12 @@ export class HookContext {
|
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
invokeMethod({ args = this.resolveArgs() } = {}) {
|
|
19
|
-
// @ts-ignore
|
|
20
19
|
return this.instance[this.methodName](...args);
|
|
21
20
|
}
|
|
22
21
|
setProperty(fn) {
|
|
23
|
-
// @ts-ignore
|
|
24
22
|
this.instance[this.methodName] = fn.resolve(this.scope);
|
|
25
23
|
}
|
|
26
24
|
getProperty() {
|
|
27
|
-
// @ts-ignore
|
|
28
25
|
return this.instance[this.methodName];
|
|
29
26
|
}
|
|
30
27
|
setInitialArgs(...args) {
|
package/esm/hooks/HooksRunner.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createHookContext } from './HookContext';
|
|
2
|
-
import { getHooks, hasHooks, toHookFn } from './hook';
|
|
3
|
-
import { UnexpectedHookResultError } from '../errors/UnexpectedHookResultError';
|
|
4
|
-
import { promisify } from '../utils/promise';
|
|
1
|
+
import { createHookContext } from './HookContext.js';
|
|
2
|
+
import { getHooks, hasHooks, toHookFn } from './hook.js';
|
|
3
|
+
import { UnexpectedHookResultError } from '../errors/UnexpectedHookResultError.js';
|
|
4
|
+
import { promisify } from '../utils/promise.js';
|
|
5
5
|
export class HooksRunner {
|
|
6
6
|
key;
|
|
7
7
|
constructor(key) {
|
package/esm/hooks/hook.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Is } from '../utils/basic';
|
|
2
|
-
import { getProxyTarget, isProxy } from '../utils/proxy';
|
|
1
|
+
import { Is } from '../utils/basic.js';
|
|
2
|
+
import { getProxyTarget, isProxy } from '../utils/proxy.js';
|
|
3
3
|
const isHookClassConstructor = (execute) => {
|
|
4
4
|
return Is.constructor(execute) && execute.prototype.execute;
|
|
5
5
|
};
|
|
@@ -7,7 +7,6 @@ export const toHookFn = (execute) => isHookClassConstructor(execute) ? (context)
|
|
|
7
7
|
const getReflectionTarget = (target) => {
|
|
8
8
|
return isProxy(target) ? getProxyTarget(target) : target;
|
|
9
9
|
};
|
|
10
|
-
// Walk the constructor's prototype chain (most-derived first) collecting each class.
|
|
11
10
|
const getConstructorChain = (ctor) => {
|
|
12
11
|
const chain = [];
|
|
13
12
|
let current = ctor;
|
|
@@ -17,9 +16,6 @@ const getConstructorChain = (ctor) => {
|
|
|
17
16
|
}
|
|
18
17
|
return chain;
|
|
19
18
|
};
|
|
20
|
-
// Get hooks metadata, merging hooks declared on parent (extended-from) classes.
|
|
21
|
-
// Hooks are collected from base to derived so a derived class's hooks for the same
|
|
22
|
-
// method name take precedence over (replace) the parent's.
|
|
23
19
|
export function getHooks(target, key) {
|
|
24
20
|
const reflectionTarget = getReflectionTarget(target);
|
|
25
21
|
const merged = new Map();
|
|
@@ -37,7 +33,6 @@ export function hasHooks(target, key) {
|
|
|
37
33
|
const reflectionTarget = getReflectionTarget(target);
|
|
38
34
|
return getConstructorChain(reflectionTarget.constructor).some((ctor) => Reflect.hasOwnMetadata(key, ctor));
|
|
39
35
|
}
|
|
40
|
-
// Hook decorator
|
|
41
36
|
export const hook = (key, ...fns) => (target, propertyKey) => {
|
|
42
37
|
const hooks = Reflect.hasOwnMetadata(key, target.constructor)
|
|
43
38
|
? Reflect.getOwnMetadata(key, target.constructor)
|