@codefast/di 0.3.14-canary.1 → 0.3.14
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/CHANGELOG.md +58 -0
- package/README.md +42 -26
- package/dist/binding-scope.d.mts +11 -0
- package/dist/binding-scope.mjs +19 -0
- package/dist/binding-select.d.mts +8 -26
- package/dist/binding-select.mjs +56 -49
- package/dist/binding.d.mts +107 -335
- package/dist/binding.mjs +19 -332
- package/dist/constraints.d.mts +11 -29
- package/dist/constraints.mjs +32 -36
- package/dist/constructor-type.d.mts +17 -0
- package/dist/constructor-type.mjs +1 -0
- package/dist/container.d.mts +43 -122
- package/dist/container.mjs +667 -482
- package/dist/decorators/inject.d.mts +19 -50
- package/dist/decorators/inject.mjs +131 -93
- package/dist/decorators/injectable.d.mts +16 -37
- package/dist/decorators/injectable.mjs +47 -66
- package/dist/decorators/lifecycle-decorators.d.mts +2 -22
- package/dist/decorators/lifecycle-decorators.mjs +81 -37
- package/dist/dependency-graph.d.mts +24 -54
- package/dist/dependency-graph.mjs +51 -153
- package/dist/environment.d.mts +38 -12
- package/dist/environment.mjs +82 -16
- package/dist/errors.d.mts +70 -189
- package/dist/errors.mjs +92 -219
- package/dist/graph-adapters/cytoscape.d.mts +21 -7
- package/dist/graph-adapters/cytoscape.mjs +18 -35
- package/dist/graph-adapters/dot.d.mts +1 -4
- package/dist/graph-adapters/dot.mjs +6 -86
- package/dist/graph-adapters/reactflow.d.mts +26 -7
- package/dist/graph-adapters/reactflow.mjs +21 -72
- package/dist/graph-adapters/types.d.mts +2 -91
- package/dist/index.d.mts +16 -8
- package/dist/index.mjs +8 -5
- package/dist/inspector.d.mts +35 -74
- package/dist/inspector.mjs +61 -88
- package/dist/lifecycle.d.mts +20 -53
- package/dist/lifecycle.mjs +129 -99
- package/dist/metadata/metadata-keys.d.mts +9 -26
- package/dist/metadata/metadata-keys.mjs +7 -28
- package/dist/metadata/metadata-reader-token.d.mts +7 -0
- package/dist/metadata/metadata-reader-token.mjs +5 -0
- package/dist/metadata/metadata-types.d.mts +26 -75
- package/dist/metadata/symbol-metadata-reader.d.mts +10 -26
- package/dist/metadata/symbol-metadata-reader.mjs +32 -45
- package/dist/module.d.mts +30 -96
- package/dist/module.mjs +26 -72
- package/dist/registry.d.mts +32 -63
- package/dist/registry.mjs +131 -82
- package/dist/resolve-options.d.mts +18 -0
- package/dist/resolve-options.mjs +22 -0
- package/dist/resolver.d.mts +67 -190
- package/dist/resolver.mjs +715 -424
- package/dist/scope.d.mts +19 -106
- package/dist/scope.mjs +37 -196
- package/dist/token.d.mts +8 -22
- package/dist/token.mjs +9 -11
- package/dist/types.d.mts +48 -0
- package/dist/types.mjs +1 -0
- package/package.json +36 -14
- package/dist/metadata/param-registry.d.mts +0 -16
- package/dist/metadata/param-registry.mjs +0 -31
- package/dist/scope-validation.d.mts +0 -21
- package/dist/scope-validation.mjs +0 -35
package/dist/scope.d.mts
CHANGED
|
@@ -1,112 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BindingIdentifier } from "./types.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/scope.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Caches singleton and scoped instances, deduplicates concurrent async creation, and runs
|
|
6
|
-
* deactivation hooks (`onDeactivation`, `@preDestroy`) on disposal.
|
|
7
|
-
*
|
|
8
|
-
* A root scope manager owns both singleton and scoped caches. A child scope manager (created
|
|
9
|
-
* via {@link createChildScope}) shares the parent's singleton cache but receives a fresh scoped
|
|
10
|
-
* cache — singletons are shared across the hierarchy, scoped instances are isolated per child.
|
|
11
|
-
*
|
|
12
|
-
* Invariant: `ownsSingletonDisposal` is `true` only for the root. When a child disposes, only
|
|
13
|
-
* its scoped bindings are deactivated; singletons remain alive until the root disposes.
|
|
14
|
-
*/
|
|
15
4
|
declare class ScopeManager {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
private readonly singletonPendingPromises;
|
|
35
|
-
/**
|
|
36
|
-
* In-flight async scoped creation promises (same deduplication role as
|
|
37
|
-
* {@link singletonPendingPromises} but for scoped bindings).
|
|
38
|
-
*/
|
|
39
|
-
private readonly scopedPendingPromises;
|
|
40
|
-
/**
|
|
41
|
-
* Internal constructor for root/child scope managers.
|
|
42
|
-
* Prefer {@link createRoot} and {@link createChildScope}.
|
|
43
|
-
*/
|
|
44
|
-
private constructor();
|
|
45
|
-
/**
|
|
46
|
-
* Creates a root scope manager that owns both the singleton cache and scoped cache.
|
|
47
|
-
*/
|
|
48
|
-
static createRoot(): ScopeManager;
|
|
49
|
-
/**
|
|
50
|
-
* Shares the parent singleton cache; receives a fresh scoped cache (for child containers).
|
|
51
|
-
*/
|
|
52
|
-
createChildScope(): ScopeManager;
|
|
53
|
-
/**
|
|
54
|
-
* Whether a singleton/scoped binding currently has a cached instance (always false for transient).
|
|
55
|
-
*/
|
|
56
|
-
isBindingCached(binding: Binding<unknown>): boolean;
|
|
57
|
-
/**
|
|
58
|
-
* Returns the cached instance for singleton/scoped bindings, or calls `createInstance` on first access.
|
|
59
|
-
*/
|
|
60
|
-
getOrCreate(binding: Binding<unknown>, createInstance: () => unknown): unknown;
|
|
61
|
-
/**
|
|
62
|
-
* Async variant of {@link getOrCreate}. Deduplicates concurrent creation calls for the same
|
|
63
|
-
* binding using an in-flight promise map, preventing double-instantiation under parallel resolves.
|
|
64
|
-
*/
|
|
65
|
-
getOrCreateAsync(binding: Binding<unknown>, createInstance: () => Promise<unknown>): Promise<unknown>;
|
|
66
|
-
/**
|
|
67
|
-
* Runs synchronous `onDeactivation` hooks for scoped instances owned by this manager.
|
|
68
|
-
* Throws if any hook returns a Promise.
|
|
69
|
-
*/
|
|
70
|
-
dispose(): void;
|
|
71
|
-
/**
|
|
72
|
-
* Runs `onDeactivation` hooks for scoped instances; root also disposes shared singletons.
|
|
73
|
-
*/
|
|
74
|
-
disposeAsync(): Promise<void>;
|
|
75
|
-
/**
|
|
76
|
-
* Drops a cached singleton/scoped instance for `bindingId` and runs `onDeactivation` synchronously.
|
|
77
|
-
*/
|
|
78
|
-
releaseByBindingId(bindingId: BindingIdentifier): void;
|
|
79
|
-
/**
|
|
80
|
-
* Drops a cached singleton/scoped instance for `bindingId` and awaits `onDeactivation`.
|
|
81
|
-
*/
|
|
82
|
-
releaseByBindingIdAsync(bindingId: BindingIdentifier): Promise<void>;
|
|
83
|
-
/**
|
|
84
|
-
* Drops a cached singleton/scoped instance for `binding.id` and runs `onDeactivation` synchronously.
|
|
85
|
-
*/
|
|
86
|
-
releaseBinding(binding: Binding<unknown>): void;
|
|
87
|
-
/**
|
|
88
|
-
* Drops a cached singleton/scoped instance for `binding.id` and awaits `onDeactivation`.
|
|
89
|
-
*/
|
|
90
|
-
releaseBindingAsync(binding: Binding<unknown>): Promise<void>;
|
|
91
|
-
/**
|
|
92
|
-
* Removes a single entry from `store`, runs `onDeactivation` synchronously, then calls
|
|
93
|
-
* `@preDestroy`. Throws {@link InternalError} if the handler returns a Promise.
|
|
94
|
-
*/
|
|
95
|
-
private releaseFromStore;
|
|
96
|
-
/**
|
|
97
|
-
* Async counterpart of {@link releaseFromStore}: awaits `onDeactivation` then `@preDestroy`.
|
|
98
|
-
*/
|
|
99
|
-
private releaseFromStoreAsync;
|
|
100
|
-
/**
|
|
101
|
-
* Iterates all entries in `store`, clears each one, runs `onDeactivation` + `@preDestroy`
|
|
102
|
-
* synchronously. Throws {@link InternalError} if any handler returns a Promise.
|
|
103
|
-
*/
|
|
104
|
-
private disposeMap;
|
|
105
|
-
/**
|
|
106
|
-
* Async counterpart of {@link disposeMap}: clears the store first, then runs all
|
|
107
|
-
* deactivation hooks; collects errors and rethrows as `AggregateError` when multiple fail.
|
|
108
|
-
*/
|
|
109
|
-
private disposeMapAsync;
|
|
5
|
+
private readonly _singletons;
|
|
6
|
+
private readonly _inflight;
|
|
7
|
+
private readonly _scoped;
|
|
8
|
+
readonly isChild: boolean;
|
|
9
|
+
constructor(isChild?: boolean);
|
|
10
|
+
hasSingleton(id: BindingIdentifier): boolean;
|
|
11
|
+
getSingleton<Value>(id: BindingIdentifier): Value;
|
|
12
|
+
setSingleton(id: BindingIdentifier, instance: unknown): void;
|
|
13
|
+
deleteSingleton(id: BindingIdentifier): boolean;
|
|
14
|
+
getAllSingletons(): ReadonlyMap<BindingIdentifier, unknown>;
|
|
15
|
+
getInflight(id: BindingIdentifier): Promise<unknown> | undefined;
|
|
16
|
+
setInflight(id: BindingIdentifier, p: Promise<unknown>): void;
|
|
17
|
+
clearInflight(id: BindingIdentifier): void;
|
|
18
|
+
hasScoped(id: BindingIdentifier): boolean;
|
|
19
|
+
getScoped<Value>(id: BindingIdentifier): Value;
|
|
20
|
+
setScoped(id: BindingIdentifier, instance: unknown): void;
|
|
21
|
+
getAllScoped(): ReadonlyMap<BindingIdentifier, unknown>;
|
|
22
|
+
clearAll(): void;
|
|
110
23
|
}
|
|
111
24
|
//#endregion
|
|
112
25
|
export { ScopeManager };
|
package/dist/scope.mjs
CHANGED
|
@@ -1,213 +1,54 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isPromiseLike, runPreDestroy, runPreDestroyAsync } from "./lifecycle.mjs";
|
|
1
|
+
import { MissingScopeContextError } from "./errors.mjs";
|
|
3
2
|
//#region src/scope.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*
|
|
12
|
-
* Invariant: `ownsSingletonDisposal` is `true` only for the root. When a child disposes, only
|
|
13
|
-
* its scoped bindings are deactivated; singletons remain alive until the root disposes.
|
|
14
|
-
*/
|
|
15
|
-
var ScopeManager = class ScopeManager {
|
|
16
|
-
/**
|
|
17
|
-
* Cached singleton instances: `bindingId → { binding, instance }`.
|
|
18
|
-
*/
|
|
19
|
-
singletonCache;
|
|
20
|
-
/**
|
|
21
|
-
* Cached scoped instances for this container level: `bindingId → { binding, instance }`.
|
|
22
|
-
*/
|
|
23
|
-
scopedCache;
|
|
24
|
-
/**
|
|
25
|
-
* True only for the root scope manager. Controls whether {@link dispose} / {@link disposeAsync}
|
|
26
|
-
* also drain the shared singleton cache; child scopes leave singleton disposal to the root.
|
|
27
|
-
*/
|
|
28
|
-
ownsSingletonDisposal;
|
|
29
|
-
/**
|
|
30
|
-
* In-flight async singleton creation promises.
|
|
31
|
-
* Guards against double-instantiation when multiple `resolveAsync` calls for the same
|
|
32
|
-
* singleton binding overlap before the first one settles.
|
|
33
|
-
*/
|
|
34
|
-
singletonPendingPromises;
|
|
35
|
-
/**
|
|
36
|
-
* In-flight async scoped creation promises (same deduplication role as
|
|
37
|
-
* {@link singletonPendingPromises} but for scoped bindings).
|
|
38
|
-
*/
|
|
39
|
-
scopedPendingPromises;
|
|
40
|
-
/**
|
|
41
|
-
* Internal constructor for root/child scope managers.
|
|
42
|
-
* Prefer {@link createRoot} and {@link createChildScope}.
|
|
43
|
-
*/
|
|
44
|
-
constructor(singletonCache, scopedCache, ownsSingletonDisposal, singletonPendingPromises, scopedPendingPromises) {
|
|
45
|
-
this.singletonCache = singletonCache;
|
|
46
|
-
this.scopedCache = scopedCache;
|
|
47
|
-
this.ownsSingletonDisposal = ownsSingletonDisposal;
|
|
48
|
-
this.singletonPendingPromises = singletonPendingPromises;
|
|
49
|
-
this.scopedPendingPromises = scopedPendingPromises;
|
|
3
|
+
var ScopeManager = class {
|
|
4
|
+
_singletons = /* @__PURE__ */ new Map();
|
|
5
|
+
_inflight = /* @__PURE__ */ new Map();
|
|
6
|
+
_scoped = /* @__PURE__ */ new Map();
|
|
7
|
+
isChild;
|
|
8
|
+
constructor(isChild = false) {
|
|
9
|
+
this.isChild = isChild;
|
|
50
10
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
*/
|
|
54
|
-
static createRoot() {
|
|
55
|
-
return new ScopeManager(/* @__PURE__ */ new Map(), /* @__PURE__ */ new Map(), true, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Map());
|
|
11
|
+
hasSingleton(id) {
|
|
12
|
+
return this._singletons.has(id);
|
|
56
13
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
*/
|
|
60
|
-
createChildScope() {
|
|
61
|
-
return new ScopeManager(this.singletonCache, /* @__PURE__ */ new Map(), false, this.singletonPendingPromises, /* @__PURE__ */ new Map());
|
|
14
|
+
getSingleton(id) {
|
|
15
|
+
return this._singletons.get(id);
|
|
62
16
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*/
|
|
66
|
-
isBindingCached(binding) {
|
|
67
|
-
if (binding.scope === "transient") return false;
|
|
68
|
-
return (binding.scope === "singleton" ? this.singletonCache : this.scopedCache).has(binding.id);
|
|
17
|
+
setSingleton(id, instance) {
|
|
18
|
+
this._singletons.set(id, instance);
|
|
69
19
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
*/
|
|
73
|
-
getOrCreate(binding, createInstance) {
|
|
74
|
-
if (binding.scope === "transient") return createInstance();
|
|
75
|
-
const cache = binding.scope === "singleton" ? this.singletonCache : this.scopedCache;
|
|
76
|
-
const cached = cache.get(binding.id);
|
|
77
|
-
if (cached !== void 0) return cached.instance;
|
|
78
|
-
const instance = createInstance();
|
|
79
|
-
cache.set(binding.id, {
|
|
80
|
-
binding,
|
|
81
|
-
instance
|
|
82
|
-
});
|
|
83
|
-
return instance;
|
|
20
|
+
deleteSingleton(id) {
|
|
21
|
+
return this._singletons.delete(id);
|
|
84
22
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
* binding using an in-flight promise map, preventing double-instantiation under parallel resolves.
|
|
88
|
-
*/
|
|
89
|
-
async getOrCreateAsync(binding, createInstance) {
|
|
90
|
-
if (binding.scope === "transient") return createInstance();
|
|
91
|
-
const cache = binding.scope === "singleton" ? this.singletonCache : this.scopedCache;
|
|
92
|
-
const pendingCreationMap = binding.scope === "singleton" ? this.singletonPendingPromises : this.scopedPendingPromises;
|
|
93
|
-
const cached = cache.get(binding.id);
|
|
94
|
-
if (cached !== void 0) return cached.instance;
|
|
95
|
-
let pendingCreation = pendingCreationMap.get(binding.id);
|
|
96
|
-
if (pendingCreation === void 0) {
|
|
97
|
-
pendingCreation = (async () => {
|
|
98
|
-
try {
|
|
99
|
-
const instance = await createInstance();
|
|
100
|
-
cache.set(binding.id, {
|
|
101
|
-
binding,
|
|
102
|
-
instance
|
|
103
|
-
});
|
|
104
|
-
return instance;
|
|
105
|
-
} finally {
|
|
106
|
-
pendingCreationMap.delete(binding.id);
|
|
107
|
-
}
|
|
108
|
-
})();
|
|
109
|
-
pendingCreationMap.set(binding.id, pendingCreation);
|
|
110
|
-
}
|
|
111
|
-
return pendingCreation;
|
|
23
|
+
getAllSingletons() {
|
|
24
|
+
return this._singletons;
|
|
112
25
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
* Throws if any hook returns a Promise.
|
|
116
|
-
*/
|
|
117
|
-
dispose() {
|
|
118
|
-
this.disposeMap(this.scopedCache);
|
|
119
|
-
if (this.ownsSingletonDisposal) this.disposeMap(this.singletonCache);
|
|
26
|
+
getInflight(id) {
|
|
27
|
+
return this._inflight.get(id);
|
|
120
28
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
*/
|
|
124
|
-
async disposeAsync() {
|
|
125
|
-
await this.disposeMapAsync(this.scopedCache);
|
|
126
|
-
if (this.ownsSingletonDisposal) await this.disposeMapAsync(this.singletonCache);
|
|
29
|
+
setInflight(id, p) {
|
|
30
|
+
this._inflight.set(id, p);
|
|
127
31
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
*/
|
|
131
|
-
releaseByBindingId(bindingId) {
|
|
132
|
-
this.releaseFromStore(this.singletonCache, bindingId);
|
|
133
|
-
this.releaseFromStore(this.scopedCache, bindingId);
|
|
32
|
+
clearInflight(id) {
|
|
33
|
+
this._inflight.delete(id);
|
|
134
34
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
*/
|
|
138
|
-
async releaseByBindingIdAsync(bindingId) {
|
|
139
|
-
await this.releaseFromStoreAsync(this.singletonCache, bindingId);
|
|
140
|
-
await this.releaseFromStoreAsync(this.scopedCache, bindingId);
|
|
35
|
+
hasScoped(id) {
|
|
36
|
+
return this._scoped.has(id);
|
|
141
37
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
*/
|
|
145
|
-
releaseBinding(binding) {
|
|
146
|
-
this.releaseByBindingId(binding.id);
|
|
38
|
+
getScoped(id) {
|
|
39
|
+
return this._scoped.get(id);
|
|
147
40
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
async releaseBindingAsync(binding) {
|
|
152
|
-
await this.releaseByBindingIdAsync(binding.id);
|
|
41
|
+
setScoped(id, instance) {
|
|
42
|
+
if (!this.isChild) throw new MissingScopeContextError("(unknown)");
|
|
43
|
+
this._scoped.set(id, instance);
|
|
153
44
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
* `@preDestroy`. Throws {@link InternalError} if the handler returns a Promise.
|
|
157
|
-
*/
|
|
158
|
-
releaseFromStore(store, bindingId) {
|
|
159
|
-
const entry = store.get(bindingId);
|
|
160
|
-
if (entry === void 0) return;
|
|
161
|
-
store.delete(bindingId);
|
|
162
|
-
const handler = entry.binding.onDeactivation;
|
|
163
|
-
if (handler !== void 0) {
|
|
164
|
-
if (isPromiseLike(handler(entry.instance))) throw new InternalError("onDeactivation returned a Promise during synchronous scope release; use releaseBindingAsync() or unloadAsync().");
|
|
165
|
-
}
|
|
166
|
-
if (entry.binding.kind === "class") runPreDestroy(entry.binding.implementationClass, entry.instance);
|
|
45
|
+
getAllScoped() {
|
|
46
|
+
return this._scoped;
|
|
167
47
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const entry = store.get(bindingId);
|
|
173
|
-
if (entry === void 0) return;
|
|
174
|
-
store.delete(bindingId);
|
|
175
|
-
const handler = entry.binding.onDeactivation;
|
|
176
|
-
if (handler !== void 0) await handler(entry.instance);
|
|
177
|
-
if (entry.binding.kind === "class") await runPreDestroyAsync(entry.binding.implementationClass, entry.instance);
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Iterates all entries in `store`, clears each one, runs `onDeactivation` + `@preDestroy`
|
|
181
|
-
* synchronously. Throws {@link InternalError} if any handler returns a Promise.
|
|
182
|
-
*/
|
|
183
|
-
disposeMap(store) {
|
|
184
|
-
const entries = [...store.values()];
|
|
185
|
-
store.clear();
|
|
186
|
-
for (const entry of entries) {
|
|
187
|
-
const handler = entry.binding.onDeactivation;
|
|
188
|
-
if (handler !== void 0) {
|
|
189
|
-
if (isPromiseLike(handler(entry.instance))) throw new InternalError("onDeactivation returned a Promise; use disposeAsync() instead of dispose().");
|
|
190
|
-
}
|
|
191
|
-
if (entry.binding.kind === "class") runPreDestroy(entry.binding.implementationClass, entry.instance);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Async counterpart of {@link disposeMap}: clears the store first, then runs all
|
|
196
|
-
* deactivation hooks; collects errors and rethrows as `AggregateError` when multiple fail.
|
|
197
|
-
*/
|
|
198
|
-
async disposeMapAsync(store) {
|
|
199
|
-
const entries = [...store.values()];
|
|
200
|
-
store.clear();
|
|
201
|
-
const errors = [];
|
|
202
|
-
for (const entry of entries) try {
|
|
203
|
-
const handler = entry.binding.onDeactivation;
|
|
204
|
-
if (handler !== void 0) await handler(entry.instance);
|
|
205
|
-
if (entry.binding.kind === "class") await runPreDestroyAsync(entry.binding.implementationClass, entry.instance);
|
|
206
|
-
} catch (error) {
|
|
207
|
-
errors.push(error);
|
|
208
|
-
}
|
|
209
|
-
if (errors.length === 1) throw errors[0];
|
|
210
|
-
if (errors.length > 1) throw new AggregateError(errors, "disposeAsync: multiple deactivation handlers failed");
|
|
48
|
+
clearAll() {
|
|
49
|
+
this._singletons.clear();
|
|
50
|
+
this._inflight.clear();
|
|
51
|
+
this._scoped.clear();
|
|
211
52
|
}
|
|
212
53
|
};
|
|
213
54
|
//#endregion
|
package/dist/token.d.mts
CHANGED
|
@@ -1,27 +1,13 @@
|
|
|
1
|
+
import { Constructor } from "./constructor-type.mjs";
|
|
2
|
+
|
|
1
3
|
//#region src/token.d.ts
|
|
2
4
|
declare const TOKEN_BRAND: unique symbol;
|
|
3
|
-
|
|
4
|
-
* Opaque injection key branded by `Value` so distinct tokens do not unify in the type system.
|
|
5
|
-
* Registry keys rely on **reference equality** — always reuse the same `token()` result as the key.
|
|
6
|
-
*/
|
|
7
|
-
type Token<Value> = {
|
|
8
|
-
readonly [TOKEN_BRAND]: Value;
|
|
5
|
+
interface Token<Value> {
|
|
9
6
|
readonly name: string;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* Extracts the value type carried by a {@link Token} or the instance type of a {@link Constructor}.
|
|
13
|
-
* Falls through to `never` for types that are neither a token nor a constructor.
|
|
14
|
-
*/
|
|
15
|
-
type TokenValue<Type> = Type extends Token<infer Value> ? Value : Type extends (abstract new (...args: never[]) => infer Value) ? Value : never;
|
|
16
|
-
/**
|
|
17
|
-
* Creates a frozen, type-safe injection token identified by `name`.
|
|
18
|
-
*
|
|
19
|
-
* The returned object is `Object.freeze`-d; `name` is used only for debugging and error
|
|
20
|
-
* messages — binding lookup relies on **reference equality** of the token object.
|
|
21
|
-
* Store the return value in a module-level `const` and import it wherever needed.
|
|
22
|
-
*
|
|
23
|
-
* @param name - Human-readable label (appears in error messages, graph output, and debug snapshots).
|
|
24
|
-
*/
|
|
7
|
+
readonly [TOKEN_BRAND]: Value;
|
|
8
|
+
}
|
|
25
9
|
declare function token<Value>(name: string): Token<Value>;
|
|
10
|
+
declare function tokenName(t: Token<unknown> | Constructor): string;
|
|
11
|
+
declare function isToken(value: unknown): value is Token<unknown>;
|
|
26
12
|
//#endregion
|
|
27
|
-
export { Token,
|
|
13
|
+
export { Token, isToken, token, tokenName };
|
package/dist/token.mjs
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
//#region src/token.ts
|
|
2
|
-
/**
|
|
3
|
-
* Creates a frozen, type-safe injection token identified by `name`.
|
|
4
|
-
*
|
|
5
|
-
* The returned object is `Object.freeze`-d; `name` is used only for debugging and error
|
|
6
|
-
* messages — binding lookup relies on **reference equality** of the token object.
|
|
7
|
-
* Store the return value in a module-level `const` and import it wherever needed.
|
|
8
|
-
*
|
|
9
|
-
* @param name - Human-readable label (appears in error messages, graph output, and debug snapshots).
|
|
10
|
-
*/
|
|
11
2
|
function token(name) {
|
|
12
|
-
return
|
|
3
|
+
return { name };
|
|
4
|
+
}
|
|
5
|
+
function tokenName(t) {
|
|
6
|
+
if (typeof t === "function") return t.name;
|
|
7
|
+
return t.name;
|
|
8
|
+
}
|
|
9
|
+
function isToken(value) {
|
|
10
|
+
return typeof value === "object" && value !== null && "name" in value && typeof value["name"] === "string" && typeof value !== "function";
|
|
13
11
|
}
|
|
14
12
|
//#endregion
|
|
15
|
-
export { token };
|
|
13
|
+
export { isToken, token, tokenName };
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Constructor } from "./constructor-type.mjs";
|
|
2
|
+
import { Token } from "./token.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
/** Token or class constructor used as a binding / injection / resolve key. */
|
|
6
|
+
type DependencyKey = Token<unknown> | Constructor;
|
|
7
|
+
type BindingScope = "singleton" | "transient" | "scoped";
|
|
8
|
+
declare const BINDING_ID_BRAND: unique symbol;
|
|
9
|
+
type BindingIdentifier = string & {
|
|
10
|
+
readonly [BINDING_ID_BRAND]: true;
|
|
11
|
+
};
|
|
12
|
+
type BindingKind = "class" | "dynamic" | "dynamic-async" | "resolved" | "resolved-async" | "constant" | "alias";
|
|
13
|
+
type ActivationHandler<Value> = (ctx: ResolutionContext, instance: Value) => Value | Promise<Value>;
|
|
14
|
+
type DeactivationHandler<Value> = (instance: Value) => void | Promise<void>;
|
|
15
|
+
interface ResolveOptions {
|
|
16
|
+
name?: string;
|
|
17
|
+
tag?: readonly [tag: string, value: unknown];
|
|
18
|
+
tags?: ReadonlyArray<readonly [tag: string, value: unknown]>;
|
|
19
|
+
}
|
|
20
|
+
interface MaterializationFrame {
|
|
21
|
+
readonly tokenName: string;
|
|
22
|
+
readonly scope: BindingScope;
|
|
23
|
+
readonly bindingId: BindingIdentifier;
|
|
24
|
+
readonly kind: BindingKind;
|
|
25
|
+
readonly slot: {
|
|
26
|
+
readonly name: string | undefined;
|
|
27
|
+
readonly tags: ReadonlyArray<readonly [tag: string, value: unknown]>;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
interface ConstraintContext {
|
|
31
|
+
readonly resolutionPath: readonly string[];
|
|
32
|
+
readonly materializationStack: readonly MaterializationFrame[];
|
|
33
|
+
readonly parent: MaterializationFrame | undefined;
|
|
34
|
+
readonly ancestors: readonly MaterializationFrame[];
|
|
35
|
+
readonly currentResolveHint: ResolveOptions | undefined;
|
|
36
|
+
}
|
|
37
|
+
interface ResolutionContext {
|
|
38
|
+
resolve<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value;
|
|
39
|
+
resolveAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value>;
|
|
40
|
+
resolveOptional<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value | undefined;
|
|
41
|
+
resolveOptionalAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value | undefined>;
|
|
42
|
+
resolveAll<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value[];
|
|
43
|
+
resolveAllAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value[]>;
|
|
44
|
+
readonly graph: ConstraintContext;
|
|
45
|
+
}
|
|
46
|
+
type TokenValue<Type> = Type extends Token<infer Value> ? Value : Type extends Constructor<infer Value> ? Value : never;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { ActivationHandler, BindingIdentifier, BindingKind, BindingScope, ConstraintContext, type Constructor, DeactivationHandler, DependencyKey, MaterializationFrame, ResolutionContext, ResolveOptions, TokenValue };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codefast/di",
|
|
3
|
-
"version": "0.3.14
|
|
3
|
+
"version": "0.3.14",
|
|
4
4
|
"description": "Lightweight dependency injection primitives for Codefast",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codefast",
|
|
@@ -28,6 +28,13 @@
|
|
|
28
28
|
"module": "./dist/index.mjs",
|
|
29
29
|
"types": "./dist/index.d.mts",
|
|
30
30
|
"imports": {
|
|
31
|
+
"#/tests/*": [
|
|
32
|
+
"./tests/*",
|
|
33
|
+
"./tests/*.ts",
|
|
34
|
+
"./tests/*.tsx",
|
|
35
|
+
"./tests/*/index.ts",
|
|
36
|
+
"./tests/*/index.tsx"
|
|
37
|
+
],
|
|
31
38
|
"#/*": [
|
|
32
39
|
"./src/*",
|
|
33
40
|
"./src/*.ts",
|
|
@@ -45,6 +52,10 @@
|
|
|
45
52
|
"types": "./dist/binding.d.mts",
|
|
46
53
|
"import": "./dist/binding.mjs"
|
|
47
54
|
},
|
|
55
|
+
"./binding-scope": {
|
|
56
|
+
"types": "./dist/binding-scope.d.mts",
|
|
57
|
+
"import": "./dist/binding-scope.mjs"
|
|
58
|
+
},
|
|
48
59
|
"./binding-select": {
|
|
49
60
|
"types": "./dist/binding-select.d.mts",
|
|
50
61
|
"import": "./dist/binding-select.mjs"
|
|
@@ -53,6 +64,10 @@
|
|
|
53
64
|
"types": "./dist/constraints.d.mts",
|
|
54
65
|
"import": "./dist/constraints.mjs"
|
|
55
66
|
},
|
|
67
|
+
"./constructor-type": {
|
|
68
|
+
"types": "./dist/constructor-type.d.mts",
|
|
69
|
+
"import": "./dist/constructor-type.mjs"
|
|
70
|
+
},
|
|
56
71
|
"./container": {
|
|
57
72
|
"types": "./dist/container.d.mts",
|
|
58
73
|
"import": "./dist/container.mjs"
|
|
@@ -109,14 +124,14 @@
|
|
|
109
124
|
"types": "./dist/metadata/metadata-keys.d.mts",
|
|
110
125
|
"import": "./dist/metadata/metadata-keys.mjs"
|
|
111
126
|
},
|
|
127
|
+
"./metadata/metadata-reader-token": {
|
|
128
|
+
"types": "./dist/metadata/metadata-reader-token.d.mts",
|
|
129
|
+
"import": "./dist/metadata/metadata-reader-token.mjs"
|
|
130
|
+
},
|
|
112
131
|
"./metadata/metadata-types": {
|
|
113
132
|
"types": "./dist/metadata/metadata-types.d.mts",
|
|
114
133
|
"import": "./dist/metadata/metadata-types.mjs"
|
|
115
134
|
},
|
|
116
|
-
"./metadata/param-registry": {
|
|
117
|
-
"types": "./dist/metadata/param-registry.d.mts",
|
|
118
|
-
"import": "./dist/metadata/param-registry.mjs"
|
|
119
|
-
},
|
|
120
135
|
"./metadata/symbol-metadata-reader": {
|
|
121
136
|
"types": "./dist/metadata/symbol-metadata-reader.d.mts",
|
|
122
137
|
"import": "./dist/metadata/symbol-metadata-reader.mjs"
|
|
@@ -129,6 +144,10 @@
|
|
|
129
144
|
"types": "./dist/registry.d.mts",
|
|
130
145
|
"import": "./dist/registry.mjs"
|
|
131
146
|
},
|
|
147
|
+
"./resolve-options": {
|
|
148
|
+
"types": "./dist/resolve-options.d.mts",
|
|
149
|
+
"import": "./dist/resolve-options.mjs"
|
|
150
|
+
},
|
|
132
151
|
"./resolver": {
|
|
133
152
|
"types": "./dist/resolver.d.mts",
|
|
134
153
|
"import": "./dist/resolver.mjs"
|
|
@@ -137,14 +156,14 @@
|
|
|
137
156
|
"types": "./dist/scope.d.mts",
|
|
138
157
|
"import": "./dist/scope.mjs"
|
|
139
158
|
},
|
|
140
|
-
"./scope-validation": {
|
|
141
|
-
"types": "./dist/scope-validation.d.mts",
|
|
142
|
-
"import": "./dist/scope-validation.mjs"
|
|
143
|
-
},
|
|
144
159
|
"./token": {
|
|
145
160
|
"types": "./dist/token.d.mts",
|
|
146
161
|
"import": "./dist/token.mjs"
|
|
147
162
|
},
|
|
163
|
+
"./types": {
|
|
164
|
+
"types": "./dist/types.d.mts",
|
|
165
|
+
"import": "./dist/types.mjs"
|
|
166
|
+
},
|
|
148
167
|
"./package.json": "./package.json"
|
|
149
168
|
},
|
|
150
169
|
"publishConfig": {
|
|
@@ -152,12 +171,13 @@
|
|
|
152
171
|
},
|
|
153
172
|
"devDependencies": {
|
|
154
173
|
"@types/node": "^25.6.0",
|
|
155
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
156
|
-
"@vitest/coverage-v8": "^4.1.
|
|
157
|
-
"
|
|
174
|
+
"@typescript/native-preview": "7.0.0-dev.20260422.1",
|
|
175
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
176
|
+
"expect-type": "^1.3.0",
|
|
177
|
+
"typescript": "^6.0.3",
|
|
158
178
|
"unplugin-swc": "^1.5.9",
|
|
159
|
-
"vitest": "^4.1.
|
|
160
|
-
"@codefast/typescript-config": "0.3.14
|
|
179
|
+
"vitest": "^4.1.5",
|
|
180
|
+
"@codefast/typescript-config": "0.3.14"
|
|
161
181
|
},
|
|
162
182
|
"engines": {
|
|
163
183
|
"node": ">=22.0.0"
|
|
@@ -166,6 +186,8 @@
|
|
|
166
186
|
"build": "tsdown",
|
|
167
187
|
"check-types": "tsgo --noEmit",
|
|
168
188
|
"clean": "rm -rf dist",
|
|
189
|
+
"examples": "for file in examples/*/*.ts; do echo \"=== Running $file ===\"; tsx \"$file\"; echo \"\n\" || exit 1; done",
|
|
190
|
+
"bench": "vitest bench --run",
|
|
169
191
|
"test": "vitest run",
|
|
170
192
|
"test:coverage": "vitest run --coverage",
|
|
171
193
|
"test:watch": "vitest"
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Constructor } from "../binding.mjs";
|
|
2
|
-
import { ParamMetadata } from "./metadata-types.mjs";
|
|
3
|
-
|
|
4
|
-
//#region src/metadata/param-registry.d.ts
|
|
5
|
-
/**
|
|
6
|
-
* Returns the pending `ParamMetadata` map for `implementationClass`, creating it on first access.
|
|
7
|
-
* Used by legacy parameter decorators that fire before the class decorator runs.
|
|
8
|
-
*/
|
|
9
|
-
declare function getOrCreatePendingMap(implementationClass: Constructor<unknown>): Map<number, ParamMetadata>;
|
|
10
|
-
/**
|
|
11
|
-
* Removes and returns the pending map for `implementationClass` (transfer of ownership).
|
|
12
|
-
* Returns `undefined` if no pending entries exist.
|
|
13
|
-
*/
|
|
14
|
-
declare function takePendingMap(implementationClass: Constructor<unknown>): Map<number, ParamMetadata> | undefined;
|
|
15
|
-
//#endregion
|
|
16
|
-
export { getOrCreatePendingMap, takePendingMap };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
//#region src/metadata/param-registry.ts
|
|
2
|
-
/**
|
|
3
|
-
* WeakMap keyed by constructor → pending parameter metadata.
|
|
4
|
-
* Entries are populated by legacy parameter decorators that fire *before* the
|
|
5
|
-
* `@injectable()` class decorator runs, and consumed (via {@link takePendingMap})
|
|
6
|
-
* by the class decorator to merge into the final {@link ConstructorMetadata}.
|
|
7
|
-
*/
|
|
8
|
-
const pendingByConstructor = /* @__PURE__ */ new WeakMap();
|
|
9
|
-
/**
|
|
10
|
-
* Returns the pending `ParamMetadata` map for `implementationClass`, creating it on first access.
|
|
11
|
-
* Used by legacy parameter decorators that fire before the class decorator runs.
|
|
12
|
-
*/
|
|
13
|
-
function getOrCreatePendingMap(implementationClass) {
|
|
14
|
-
let map = pendingByConstructor.get(implementationClass);
|
|
15
|
-
if (!map) {
|
|
16
|
-
map = /* @__PURE__ */ new Map();
|
|
17
|
-
pendingByConstructor.set(implementationClass, map);
|
|
18
|
-
}
|
|
19
|
-
return map;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Removes and returns the pending map for `implementationClass` (transfer of ownership).
|
|
23
|
-
* Returns `undefined` if no pending entries exist.
|
|
24
|
-
*/
|
|
25
|
-
function takePendingMap(implementationClass) {
|
|
26
|
-
const map = pendingByConstructor.get(implementationClass);
|
|
27
|
-
if (map) pendingByConstructor.delete(implementationClass);
|
|
28
|
-
return map;
|
|
29
|
-
}
|
|
30
|
-
//#endregion
|
|
31
|
-
export { getOrCreatePendingMap, takePendingMap };
|