@fnioc/di 1.0.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 +294 -0
- package/dist/builder.d.ts +81 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +85 -0
- package/dist/builder.js.map +1 -0
- package/dist/errors.d.ts +73 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +139 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/scope.d.ts +180 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +466 -0
- package/dist/scope.js.map +1 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
package/dist/scope.js
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
// The scope chain + the resolution engine — the correctness core of the engine.
|
|
2
|
+
//
|
|
3
|
+
// A Scope is a node in a parent-linked chain. It owns and caches the instances
|
|
4
|
+
// whose lifetime tag matches its name, may hold local override registrations
|
|
5
|
+
// that shadow ancestors, and disposes the instances it owns in reverse
|
|
6
|
+
// construction order when closed.
|
|
7
|
+
//
|
|
8
|
+
// Resolution (§"The critical correctness rule"): on a cache miss the instance
|
|
9
|
+
// is constructed by resolving ITS constructor dependencies relative to the
|
|
10
|
+
// OWNING scope (the matched ancestor), never the scope that triggered the
|
|
11
|
+
// resolve. That is what makes a long-lived service depending on a shorter-lived
|
|
12
|
+
// one fail loudly instead of silently capturing it.
|
|
13
|
+
import { getDeps } from "@fnioc/core";
|
|
14
|
+
import { AsyncDisposalRequiredError, CircularDependencyError, FactoryTargetError, MissingMetadataError, MissingScopeError, NoSatisfiableSignatureError, UnregisteredTokenError, } from "./errors.js";
|
|
15
|
+
/** True when a value implements the native synchronous `Disposable`. */
|
|
16
|
+
function isDisposable(value) {
|
|
17
|
+
return (value != null &&
|
|
18
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
19
|
+
typeof value[Symbol.dispose] ===
|
|
20
|
+
"function");
|
|
21
|
+
}
|
|
22
|
+
/** True when a value implements the native `AsyncDisposable`. */
|
|
23
|
+
function isAsyncDisposable(value) {
|
|
24
|
+
return (value != null &&
|
|
25
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
26
|
+
typeof value[Symbol.asyncDispose] === "function");
|
|
27
|
+
}
|
|
28
|
+
/** True when a value is thenable (a Promise or Promise-like). */
|
|
29
|
+
function isThenable(value) {
|
|
30
|
+
return (value != null &&
|
|
31
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
32
|
+
typeof value.then === "function");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* True when a `DepSlot` is a `FactoryRef` — a factory-injected parameter. A
|
|
36
|
+
* slot is a string token, the `null` hole sentinel, or this object form.
|
|
37
|
+
*/
|
|
38
|
+
function isFactoryRef(slot) {
|
|
39
|
+
return (slot !== null &&
|
|
40
|
+
typeof slot === "object" &&
|
|
41
|
+
typeof slot.factory === "string");
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A node in the scope chain. Created from a `DiBuilder` (the root) or from a
|
|
45
|
+
* parent scope (`.createScope`). Holds the instances it owns and any local
|
|
46
|
+
* override registrations.
|
|
47
|
+
*
|
|
48
|
+
* The generic `Scopes` is the user's scope-name union, threaded so
|
|
49
|
+
* `.createScope` only accepts declared names.
|
|
50
|
+
*/
|
|
51
|
+
export class Scope {
|
|
52
|
+
name;
|
|
53
|
+
parent;
|
|
54
|
+
baseRegistrations;
|
|
55
|
+
/** Local override registrations held at this scope (shadow ancestors). */
|
|
56
|
+
localRegistrations = new Map();
|
|
57
|
+
/** Instances this scope owns and caches, keyed by token. */
|
|
58
|
+
instances = new Map();
|
|
59
|
+
/** Owned instances in construction order — disposed in reverse. */
|
|
60
|
+
ownedOrder = [];
|
|
61
|
+
disposed = false;
|
|
62
|
+
constructor(
|
|
63
|
+
/** This scope's tag name. The root scope's name is its lifetime. */
|
|
64
|
+
name,
|
|
65
|
+
/** The parent scope, or `undefined` for the root. */
|
|
66
|
+
parent,
|
|
67
|
+
/** The builder's base registration map (shared, walked last). */
|
|
68
|
+
baseRegistrations) {
|
|
69
|
+
this.name = name;
|
|
70
|
+
this.parent = parent;
|
|
71
|
+
this.baseRegistrations = baseRegistrations;
|
|
72
|
+
}
|
|
73
|
+
/** Creates a parent-linked child scope with the given (declared) name. */
|
|
74
|
+
createScope(childName) {
|
|
75
|
+
return new Scope(childName, this, this.baseRegistrations);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Registers a scope-local override. Shadows any ancestor or base registration
|
|
79
|
+
* for the same token, for this scope and its descendants only. The override
|
|
80
|
+
* paths (`useFactory` / `useValue`) are also available here so a single scope
|
|
81
|
+
* (e.g. a test scope) can swap an implementation without rebuilding the
|
|
82
|
+
* builder.
|
|
83
|
+
*/
|
|
84
|
+
registerFactory(token, useFactory, tag) {
|
|
85
|
+
this.localRegistrations.set(token, {
|
|
86
|
+
kind: "factory",
|
|
87
|
+
useFactory: useFactory,
|
|
88
|
+
tag,
|
|
89
|
+
});
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
/** Registers a scope-local `useValue` override (see `registerFactory`). */
|
|
93
|
+
registerValue(token, useValue) {
|
|
94
|
+
this.localRegistrations.set(token, { kind: "value", useValue });
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Resolves a token to an instance, walking the parent chain for both the
|
|
99
|
+
* registration and the owning scope. The public entry point starts a fresh
|
|
100
|
+
* cycle-detection stack.
|
|
101
|
+
*/
|
|
102
|
+
resolve(token) {
|
|
103
|
+
return this.resolveWith(token, []);
|
|
104
|
+
}
|
|
105
|
+
// ── Registration lookup ─────────────────────────────────────────────────────
|
|
106
|
+
/**
|
|
107
|
+
* Walks UP the chain (this scope's locals → ancestors' locals → base map),
|
|
108
|
+
* returning the nearest registration for `token`. Child shadows parent.
|
|
109
|
+
*/
|
|
110
|
+
lookup(token) {
|
|
111
|
+
// Aliasing `this` to walk the parent chain iteratively.
|
|
112
|
+
let node = this;
|
|
113
|
+
while (node !== undefined) {
|
|
114
|
+
const local = node.localRegistrations.get(token);
|
|
115
|
+
if (local !== undefined)
|
|
116
|
+
return local;
|
|
117
|
+
node = node.parent;
|
|
118
|
+
}
|
|
119
|
+
return this.baseRegistrations.get(token);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Finds the nearest ancestor scope (inclusive of this one) whose name matches
|
|
123
|
+
* `tag`, walking UP the chain. Returns `undefined` when none matches.
|
|
124
|
+
*/
|
|
125
|
+
findOwner(tag) {
|
|
126
|
+
// Aliasing `this` to walk the parent chain iteratively.
|
|
127
|
+
let node = this;
|
|
128
|
+
while (node !== undefined) {
|
|
129
|
+
if (node.name === tag)
|
|
130
|
+
return node;
|
|
131
|
+
node = node.parent;
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
/** The chain of scope names from this scope up to the root, for diagnostics. */
|
|
136
|
+
chainNames() {
|
|
137
|
+
const names = [];
|
|
138
|
+
// Aliasing `this` to walk the parent chain iteratively.
|
|
139
|
+
let node = this;
|
|
140
|
+
while (node !== undefined) {
|
|
141
|
+
names.push(node.name);
|
|
142
|
+
node = node.parent;
|
|
143
|
+
}
|
|
144
|
+
return names;
|
|
145
|
+
}
|
|
146
|
+
// ── Resolution ──────────────────────────────────────────────────────────────
|
|
147
|
+
/**
|
|
148
|
+
* The internal resolver. `stack` is the active resolution path (for cycle
|
|
149
|
+
* detection); it is shared across the whole `resolve()` call but never across
|
|
150
|
+
* separate calls.
|
|
151
|
+
*/
|
|
152
|
+
resolveWith(token, stack) {
|
|
153
|
+
if (stack.includes(token)) {
|
|
154
|
+
throw new CircularDependencyError([...stack, token]);
|
|
155
|
+
}
|
|
156
|
+
const registration = this.lookup(token);
|
|
157
|
+
if (registration === undefined) {
|
|
158
|
+
throw new UnregisteredTokenError(token);
|
|
159
|
+
}
|
|
160
|
+
// useValue: the instance already exists; ownership/caching is moot.
|
|
161
|
+
if (registration.kind === "value") {
|
|
162
|
+
return registration.useValue;
|
|
163
|
+
}
|
|
164
|
+
// Transient (no tag): never cached. Build relative to THIS scope and return
|
|
165
|
+
// a fresh instance every time.
|
|
166
|
+
if (registration.tag === undefined) {
|
|
167
|
+
stack.push(token);
|
|
168
|
+
try {
|
|
169
|
+
return this.instantiate(token, registration, this, stack);
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
stack.pop();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Tagged: find the owning ancestor scope. No match ⇒ throw (never
|
|
176
|
+
// auto-create — that is the captive-dependency detector).
|
|
177
|
+
const owner = this.findOwner(registration.tag);
|
|
178
|
+
if (owner === undefined) {
|
|
179
|
+
throw new MissingScopeError(token, registration.tag, this.chainNames());
|
|
180
|
+
}
|
|
181
|
+
// Cache hit on the owner ⇒ return the cached instance (or Promise).
|
|
182
|
+
if (owner.instances.has(token)) {
|
|
183
|
+
return owner.instances.get(token);
|
|
184
|
+
}
|
|
185
|
+
// Cache miss ⇒ construct relative to the OWNER, cache on the owner.
|
|
186
|
+
stack.push(token);
|
|
187
|
+
try {
|
|
188
|
+
const instance = owner.instantiate(token, registration, owner, stack);
|
|
189
|
+
owner.instances.set(token, instance);
|
|
190
|
+
owner.ownedOrder.push(instance);
|
|
191
|
+
return instance;
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
stack.pop();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Builds an instance for `registration`. `owningScope` is the scope whose
|
|
199
|
+
* chain the dependencies are resolved against — THE critical rule. For a
|
|
200
|
+
* factory override that is the scope passed to the closure; for a class it is
|
|
201
|
+
* the scope its ctor deps resolve relative to.
|
|
202
|
+
*/
|
|
203
|
+
instantiate(token, registration, owningScope, stack) {
|
|
204
|
+
if (registration.kind === "factory") {
|
|
205
|
+
// The factory resolves its own deps relative to the owning scope, but the
|
|
206
|
+
// closure only sees a `resolve` that continues the active cycle stack.
|
|
207
|
+
const scopeView = {
|
|
208
|
+
resolve: (depToken) => owningScope.resolveWith(depToken, stack),
|
|
209
|
+
};
|
|
210
|
+
return registration.useFactory(scopeView);
|
|
211
|
+
}
|
|
212
|
+
return owningScope.construct(token, registration.ctor, stack);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Constructs a class instance on a DIRECT resolve, resolving its constructor
|
|
216
|
+
* dependencies relative to THIS scope (the owning scope). Performs greedy
|
|
217
|
+
* signature selection over the ctor's DepRecord, then fills each slot:
|
|
218
|
+
*
|
|
219
|
+
* - a string token → resolved through this scope's chain (selection
|
|
220
|
+
* guarantees every string-token slot here is resolvable);
|
|
221
|
+
* - a `FactoryRef` → injected as a callable (see `makeFactory`);
|
|
222
|
+
* - a `null` hole → there is no caller on a direct resolve, so it lands as
|
|
223
|
+
* `undefined`. Holes are meaningfully filled only when the class is a
|
|
224
|
+
* factory target — see `constructPartitioned`.
|
|
225
|
+
*/
|
|
226
|
+
construct(token, ctor, stack) {
|
|
227
|
+
const record = getDeps(ctor);
|
|
228
|
+
// No metadata: a zero-arg ctor is `new`ed directly; a ctor with parameters
|
|
229
|
+
// and no record is a hard error with actionable guidance.
|
|
230
|
+
if (record === undefined || record.signatures.length === 0) {
|
|
231
|
+
if (ctor.length > 0) {
|
|
232
|
+
throw new MissingMetadataError(token, ctor.name);
|
|
233
|
+
}
|
|
234
|
+
return new ctor();
|
|
235
|
+
}
|
|
236
|
+
const signature = this.selectSignature(token, ctor, record.signatures);
|
|
237
|
+
const args = signature.map((slot) => {
|
|
238
|
+
if (isFactoryRef(slot)) {
|
|
239
|
+
// A factory-injected parameter: a callable that builds `slot.factory`'s
|
|
240
|
+
// target on demand, resolving the target's own deps relative to THIS
|
|
241
|
+
// scope (the owner) so §5.4 still holds at call time.
|
|
242
|
+
return this.makeFactory(slot);
|
|
243
|
+
}
|
|
244
|
+
if (slot === null) {
|
|
245
|
+
// A hole with no caller on a direct resolve ⇒ unfilled (`undefined`).
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
248
|
+
// A string token — resolve it through this scope's chain.
|
|
249
|
+
return this.resolveWith(slot, stack);
|
|
250
|
+
});
|
|
251
|
+
return new ctor(...args);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Builds the callable injected for a `FactoryRef` parameter.
|
|
255
|
+
*
|
|
256
|
+
* The target ctor's signature is partitioned at CALL time against the live
|
|
257
|
+
* registration map: each slot that is a registered token is resolved; each
|
|
258
|
+
* slot that is an unregistered token or a `null` hole takes the next
|
|
259
|
+
* caller-supplied argument, positionally. The injected callable therefore
|
|
260
|
+
* exposes only the target's unregistered parameters, in their relative order
|
|
261
|
+
* — no Ramda-style placeholders, no leaked constructor arity.
|
|
262
|
+
*
|
|
263
|
+
* Lifetime semantics:
|
|
264
|
+
* - A ZERO-ARG factory (the target ctor has no holes / unregistered params)
|
|
265
|
+
* routes the build through the normal `resolve` path, so it RESPECTS the
|
|
266
|
+
* target's registered lifetime: a singleton target yields the same
|
|
267
|
+
* instance on every call; a transient target yields a fresh one.
|
|
268
|
+
* - A PARAMETERIZED factory (the target has holes / unregistered params
|
|
269
|
+
* filled per call) constructs a FRESH instance on every call and BYPASSES
|
|
270
|
+
* the instance cache. Caller args differ per call, so caching would be
|
|
271
|
+
* wrong — two calls with different arguments must not collapse to one
|
|
272
|
+
* cached instance.
|
|
273
|
+
*
|
|
274
|
+
* The closure captures `this` as the owning scope. §5.4 holds at call time:
|
|
275
|
+
* the target's deps resolve relative to the scope that owns the
|
|
276
|
+
* factory-holding instance, exactly as a direct resolve would — so a factory
|
|
277
|
+
* captured by a singleton that tries to build a request-scoped target still
|
|
278
|
+
* throws `MissingScopeError` when invoked.
|
|
279
|
+
*/
|
|
280
|
+
makeFactory(ref) {
|
|
281
|
+
const owningScope = this;
|
|
282
|
+
const target = this.lookup(ref.factory);
|
|
283
|
+
if (target === undefined) {
|
|
284
|
+
throw new FactoryTargetError(ref.factory, "unregistered");
|
|
285
|
+
}
|
|
286
|
+
// A factory builds its target with `new` — the target must be a class
|
|
287
|
+
// registration, not a useValue/useFactory override.
|
|
288
|
+
if (target.kind !== "class") {
|
|
289
|
+
throw new FactoryTargetError(ref.factory, "not-a-class");
|
|
290
|
+
}
|
|
291
|
+
const targetCtor = target.ctor;
|
|
292
|
+
const record = getDeps(targetCtor);
|
|
293
|
+
const targetSignature = record === undefined || record.signatures.length === 0
|
|
294
|
+
? undefined
|
|
295
|
+
: owningScope.selectTargetSignature(record.signatures);
|
|
296
|
+
// A target slot is caller-supplied when it is a hole or a string token NOT
|
|
297
|
+
// in the live registration map (a nested FactoryRef is itself injected, not
|
|
298
|
+
// caller-supplied). If the target has any such slot the factory is
|
|
299
|
+
// parameterized; otherwise it is a bare zero-arg factory.
|
|
300
|
+
const parameterized = targetSignature !== undefined &&
|
|
301
|
+
targetSignature.some((slot) => slot === null || (!isFactoryRef(slot) && !owningScope.isResolvable(slot)));
|
|
302
|
+
if (!parameterized) {
|
|
303
|
+
return () => owningScope.resolveWith(ref.factory, []);
|
|
304
|
+
}
|
|
305
|
+
// Parameterized factory: construct a fresh instance each call, partitioning
|
|
306
|
+
// the target signature against the live registration map and threading the
|
|
307
|
+
// caller args into the holes / unregistered slots. A fresh cycle stack per
|
|
308
|
+
// call — the factory runs outside the resolve that created it.
|
|
309
|
+
return (...callArgs) => owningScope.constructPartitioned(ref.factory, targetCtor, targetSignature, callArgs);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Constructs a factory target, partitioning its already-selected signature
|
|
313
|
+
* against the live registration map: a registered token is resolved; an
|
|
314
|
+
* unregistered token or a `null` hole takes the next caller-supplied argument
|
|
315
|
+
* positionally. Always a fresh instance — a parameterized factory bypasses
|
|
316
|
+
* the instance cache (caller args differ per call). Runs on a fresh cycle
|
|
317
|
+
* stack since the factory is invoked outside the original resolve.
|
|
318
|
+
*/
|
|
319
|
+
constructPartitioned(token, ctor, signature, callerArgs) {
|
|
320
|
+
const stack = [];
|
|
321
|
+
let nextCallerArg = 0;
|
|
322
|
+
const args = signature.map((slot) => {
|
|
323
|
+
if (isFactoryRef(slot)) {
|
|
324
|
+
return this.makeFactory(slot);
|
|
325
|
+
}
|
|
326
|
+
// An unregistered token or a hole is caller-supplied: take the next arg.
|
|
327
|
+
if (slot === null || !this.isResolvable(slot)) {
|
|
328
|
+
return callerArgs[nextCallerArg++];
|
|
329
|
+
}
|
|
330
|
+
return this.resolveWith(slot, stack);
|
|
331
|
+
});
|
|
332
|
+
return new ctor(...args);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Greedy signature selection. Scans signatures longest → shortest and returns
|
|
336
|
+
* the first SATISFIABLE one. A slot is satisfiable when it is:
|
|
337
|
+
*
|
|
338
|
+
* - a `null` hole — always satisfiable; filled by a caller arg (a direct
|
|
339
|
+
* resolve supplies nothing, so it lands as `undefined`);
|
|
340
|
+
* - a `FactoryRef` — always satisfiable; injected as a callable. The
|
|
341
|
+
* factory's target need not be resolvable for the slot to count (an
|
|
342
|
+
* unregistered target surfaces a `FactoryTargetError` when the factory is
|
|
343
|
+
* built / called, not here); or
|
|
344
|
+
* - a string token whose registration is resolvable in this (the owning)
|
|
345
|
+
* scope's chain.
|
|
346
|
+
*
|
|
347
|
+
* Only string tokens can be UNsatisfiable. A signature is satisfiable iff
|
|
348
|
+
* every string-token slot is resolvable.
|
|
349
|
+
*
|
|
350
|
+
* - Equal-arity ties break by registration order (the order signatures appear
|
|
351
|
+
* in the DepRecord), which `sort`'s stability preserves.
|
|
352
|
+
* - None satisfiable ⇒ throw naming the unsatisfiable tokens.
|
|
353
|
+
*/
|
|
354
|
+
selectSignature(token, ctor, signatures) {
|
|
355
|
+
// Stable sort by descending length; index keeps equal-arity ties in
|
|
356
|
+
// registration order.
|
|
357
|
+
const ordered = signatures
|
|
358
|
+
.map((sig, index) => ({ sig, index }))
|
|
359
|
+
.sort((a, b) => b.sig.length !== a.sig.length
|
|
360
|
+
? b.sig.length - a.sig.length
|
|
361
|
+
: a.index - b.index);
|
|
362
|
+
const unsatisfiable = new Set();
|
|
363
|
+
for (const { sig } of ordered) {
|
|
364
|
+
let satisfiable = true;
|
|
365
|
+
for (const slot of sig) {
|
|
366
|
+
// A hole or a FactoryRef is always satisfiable — only an unresolvable
|
|
367
|
+
// string token blocks a signature.
|
|
368
|
+
if (slot === null || isFactoryRef(slot))
|
|
369
|
+
continue;
|
|
370
|
+
if (!this.isResolvable(slot)) {
|
|
371
|
+
satisfiable = false;
|
|
372
|
+
unsatisfiable.add(slot);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (satisfiable)
|
|
376
|
+
return sig;
|
|
377
|
+
}
|
|
378
|
+
throw new NoSatisfiableSignatureError(token, ctor.name, [...unsatisfiable]);
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Greedy signature selection for a FACTORY TARGET. Unlike `selectSignature`,
|
|
382
|
+
* there is no resolvability gate: a target's unregistered tokens are not
|
|
383
|
+
* unsatisfiable — they are the factory's caller-supplied parameters. So the
|
|
384
|
+
* choice is purely the longest signature, equal-arity ties broken by
|
|
385
|
+
* registration order (`sort` stability). Always returns a signature (the
|
|
386
|
+
* caller has already checked `signatures.length > 0`).
|
|
387
|
+
*/
|
|
388
|
+
selectTargetSignature(signatures) {
|
|
389
|
+
return signatures
|
|
390
|
+
.map((sig, index) => ({ sig, index }))
|
|
391
|
+
.sort((a, b) => b.sig.length !== a.sig.length
|
|
392
|
+
? b.sig.length - a.sig.length
|
|
393
|
+
: a.index - b.index)[0].sig;
|
|
394
|
+
}
|
|
395
|
+
/** True when `token` has a registration somewhere in this scope's chain. */
|
|
396
|
+
isResolvable(token) {
|
|
397
|
+
return this.lookup(token) !== undefined;
|
|
398
|
+
}
|
|
399
|
+
// ── Disposal ────────────────────────────────────────────────────────────────
|
|
400
|
+
/**
|
|
401
|
+
* Closes this scope synchronously, disposing the instances it owns in REVERSE
|
|
402
|
+
* construction order. Only native `Disposable` instances are disposed.
|
|
403
|
+
*
|
|
404
|
+
* Throws `AsyncDisposalRequiredError` if any owned instance is a Promise
|
|
405
|
+
* (thenable) — a pending Promise cannot be disposed synchronously; the caller
|
|
406
|
+
* must use `disposeAsync()`. Idempotent: a second call is a no-op.
|
|
407
|
+
*/
|
|
408
|
+
dispose() {
|
|
409
|
+
if (this.disposed)
|
|
410
|
+
return;
|
|
411
|
+
for (const instance of this.ownedOrder) {
|
|
412
|
+
if (isThenable(instance)) {
|
|
413
|
+
throw new AsyncDisposalRequiredError();
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
this.disposed = true;
|
|
417
|
+
for (let i = this.ownedOrder.length - 1; i >= 0; i--) {
|
|
418
|
+
const instance = this.ownedOrder[i];
|
|
419
|
+
if (isDisposable(instance)) {
|
|
420
|
+
instance[Symbol.dispose]();
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
this.clear();
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Closes this scope asynchronously. Awaits each owned Promise-valued instance
|
|
427
|
+
* first (so an async factory's result settles before teardown), then disposes
|
|
428
|
+
* owned instances in REVERSE construction order — honoring both
|
|
429
|
+
* `Symbol.asyncDispose` and `Symbol.dispose`. Idempotent.
|
|
430
|
+
*/
|
|
431
|
+
async disposeAsync() {
|
|
432
|
+
if (this.disposed)
|
|
433
|
+
return;
|
|
434
|
+
this.disposed = true;
|
|
435
|
+
// Resolve any Promise-valued instances to their settled values so the
|
|
436
|
+
// disposer sees the real object, not the wrapper.
|
|
437
|
+
const settled = [];
|
|
438
|
+
for (const instance of this.ownedOrder) {
|
|
439
|
+
settled.push(isThenable(instance) ? await instance : instance);
|
|
440
|
+
}
|
|
441
|
+
for (let i = settled.length - 1; i >= 0; i--) {
|
|
442
|
+
const instance = settled[i];
|
|
443
|
+
if (isAsyncDisposable(instance)) {
|
|
444
|
+
await instance[Symbol.asyncDispose]();
|
|
445
|
+
}
|
|
446
|
+
else if (isDisposable(instance)) {
|
|
447
|
+
instance[Symbol.dispose]();
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
this.clear();
|
|
451
|
+
}
|
|
452
|
+
/** Drops owned references after disposal so they can be collected. */
|
|
453
|
+
clear() {
|
|
454
|
+
this.instances.clear();
|
|
455
|
+
this.ownedOrder.length = 0;
|
|
456
|
+
}
|
|
457
|
+
/** Native `using` support — delegates to `dispose()`. */
|
|
458
|
+
[Symbol.dispose]() {
|
|
459
|
+
this.dispose();
|
|
460
|
+
}
|
|
461
|
+
/** Native `await using` support — delegates to `disposeAsync()`. */
|
|
462
|
+
[Symbol.asyncDispose]() {
|
|
463
|
+
return this.disposeAsync();
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Token } from "@fnioc/core";
|
|
2
|
+
/**
|
|
3
|
+
* A concrete, instantiable constructor producing `I`.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately plain `new (...) => I`, NOT `abstract new (...) => I`: the
|
|
6
|
+
* container instantiates the concrete type, and an `abstract` class cannot be
|
|
7
|
+
* `new`ed. Passing an abstract class to `.add()` is therefore a type error —
|
|
8
|
+
* exactly the desired rejection.
|
|
9
|
+
*/
|
|
10
|
+
export type Ctor<I = unknown> = new (...args: never[]) => I;
|
|
11
|
+
/**
|
|
12
|
+
* A factory override: a closure that builds the instance, given the scope it is
|
|
13
|
+
* being resolved into (so the factory can `scope.resolve(...)` its own deps).
|
|
14
|
+
*
|
|
15
|
+
* May be async — it can return a `Promise<T>`. The container never awaits; the
|
|
16
|
+
* Promise flows through the sync resolution channel as a value (§"Async as
|
|
17
|
+
* values"). A consumer that depends on it declares `Promise<T>` and awaits.
|
|
18
|
+
*/
|
|
19
|
+
export type Factory<T = unknown> = (scope: ResolveScope) => T;
|
|
20
|
+
/** A class registration: a token bound to a concrete constructor. */
|
|
21
|
+
export interface ClassRegistration {
|
|
22
|
+
readonly kind: "class";
|
|
23
|
+
readonly ctor: Ctor;
|
|
24
|
+
/**
|
|
25
|
+
* The lifetime tag — the scope name that owns and caches the instance.
|
|
26
|
+
* `undefined` means transient (never cached; a fresh instance per resolve).
|
|
27
|
+
*/
|
|
28
|
+
readonly tag: string | undefined;
|
|
29
|
+
}
|
|
30
|
+
/** A `useFactory` override registration. */
|
|
31
|
+
export interface FactoryRegistration {
|
|
32
|
+
readonly kind: "factory";
|
|
33
|
+
readonly useFactory: Factory;
|
|
34
|
+
readonly tag: string | undefined;
|
|
35
|
+
}
|
|
36
|
+
/** A `useValue` override registration — an already-built instance. */
|
|
37
|
+
export interface ValueRegistration {
|
|
38
|
+
readonly kind: "value";
|
|
39
|
+
readonly useValue: unknown;
|
|
40
|
+
}
|
|
41
|
+
/** Any registration the engine can resolve. */
|
|
42
|
+
export type Registration = ClassRegistration | FactoryRegistration | ValueRegistration;
|
|
43
|
+
/**
|
|
44
|
+
* The resolution surface a factory closure receives. A structural subset of
|
|
45
|
+
* `Scope` exposing only what an override needs — resolving further tokens.
|
|
46
|
+
*/
|
|
47
|
+
export interface ResolveScope {
|
|
48
|
+
resolve<T>(token: Token): T;
|
|
49
|
+
}
|
|
50
|
+
/** The override spec accepted by `.register(token, spec)`. */
|
|
51
|
+
export type OverrideSpec<T> = {
|
|
52
|
+
readonly useFactory: (scope: ResolveScope) => T;
|
|
53
|
+
readonly tag?: string;
|
|
54
|
+
} | {
|
|
55
|
+
readonly useValue: T;
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,MAAM,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAE5D;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,KAAK,EAAE,YAAY,KAAK,CAAC,CAAC;AAE9D,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,4CAA4C;AAC5C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,sEAAsE;AACtE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,+CAA+C;AAC/C,MAAM,MAAM,YAAY,GACpB,iBAAiB,GACjB,mBAAmB,GACnB,iBAAiB,CAAC;AAEtB;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;CAC7B;AAED,8DAA8D;AAC9D,MAAM,MAAM,YAAY,CAAC,CAAC,IACtB;IAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,CAAC,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAA;CAAE,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,8DAA8D"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fnioc/di",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "The ioc runtime engine: DiBuilder, scopes, resolution, captive-dependency protection, factories, and native disposal.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dependency-injection",
|
|
7
|
+
"di",
|
|
8
|
+
"ioc",
|
|
9
|
+
"typescript",
|
|
10
|
+
"scope",
|
|
11
|
+
"container"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/fnioc/ioc.git",
|
|
17
|
+
"directory": "packages/di"
|
|
18
|
+
},
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc -b",
|
|
34
|
+
"test": "bun test",
|
|
35
|
+
"lint": "echo 'lint: typecheck runs in build (tsc -b)' && exit 0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@fnioc/core": "^1.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@fnioc/core": "^1.0.0"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public",
|
|
45
|
+
"provenance": true
|
|
46
|
+
}
|
|
47
|
+
}
|