@codefast/di 0.5.0-canary.7 → 0.5.0-canary.8
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 +68 -0
- package/README.md +3 -1
- package/dist/binding.d.ts +47 -5
- package/dist/binding.d.ts.map +1 -1
- package/dist/binding.js +44 -0
- package/dist/binding.js.map +1 -1
- package/dist/constructor-type.d.ts +4 -5
- package/dist/constructor-type.d.ts.map +1 -1
- package/dist/container/binding-builders.d.ts +32 -11
- package/dist/container/binding-builders.d.ts.map +1 -1
- package/dist/container/binding-builders.js +140 -191
- package/dist/container/binding-builders.js.map +1 -1
- package/dist/container/container.d.ts.map +1 -1
- package/dist/container/container.js +75 -92
- package/dist/container/container.js.map +1 -1
- package/dist/decorators/inject.d.ts +2 -4
- package/dist/decorators/inject.d.ts.map +1 -1
- package/dist/decorators/inject.js.map +1 -1
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +17 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/introspection/inspector.js +1 -1
- package/dist/introspection/inspector.js.map +1 -1
- package/dist/metadata/metadata-keys.d.ts +3 -6
- package/dist/metadata/metadata-keys.d.ts.map +1 -1
- package/dist/metadata/metadata-keys.js +3 -6
- package/dist/metadata/metadata-keys.js.map +1 -1
- package/dist/registry.d.ts +14 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +35 -45
- package/dist/registry.js.map +1 -1
- package/dist/resolution/activation-need.d.ts +25 -0
- package/dist/resolution/activation-need.d.ts.map +1 -0
- package/dist/resolution/activation-need.js +64 -0
- package/dist/resolution/activation-need.js.map +1 -0
- package/dist/resolution/binding-lookup-cache.d.ts +41 -0
- package/dist/resolution/binding-lookup-cache.d.ts.map +1 -0
- package/dist/resolution/binding-lookup-cache.js +102 -0
- package/dist/resolution/binding-lookup-cache.js.map +1 -0
- package/dist/resolution/binding-select.js +1 -4
- package/dist/resolution/binding-select.js.map +1 -1
- package/dist/resolution/class-introspector.d.ts +27 -0
- package/dist/resolution/class-introspector.d.ts.map +1 -0
- package/dist/resolution/class-introspector.js +60 -0
- package/dist/resolution/class-introspector.js.map +1 -0
- package/dist/resolution/diagnostics.d.ts +41 -0
- package/dist/resolution/diagnostics.d.ts.map +1 -0
- package/dist/resolution/diagnostics.js +18 -0
- package/dist/resolution/diagnostics.js.map +1 -0
- package/dist/resolution/environment.d.ts +22 -1
- package/dist/resolution/environment.d.ts.map +1 -1
- package/dist/resolution/environment.js +27 -1
- package/dist/resolution/environment.js.map +1 -1
- package/dist/resolution/instantiation-plan.d.ts +15 -15
- package/dist/resolution/instantiation-plan.d.ts.map +1 -1
- package/dist/resolution/instantiation-plan.js +68 -48
- package/dist/resolution/instantiation-plan.js.map +1 -1
- package/dist/resolution/lifecycle.d.ts +2 -0
- package/dist/resolution/lifecycle.d.ts.map +1 -1
- package/dist/resolution/lifecycle.js +16 -11
- package/dist/resolution/lifecycle.js.map +1 -1
- package/dist/resolution/resolution-path.d.ts +4 -13
- package/dist/resolution/resolution-path.d.ts.map +1 -1
- package/dist/resolution/resolution-path.js +3 -16
- package/dist/resolution/resolution-path.js.map +1 -1
- package/dist/resolution/resolver.d.ts +7 -2
- package/dist/resolution/resolver.d.ts.map +1 -1
- package/dist/resolution/resolver.js +116 -328
- package/dist/resolution/resolver.js.map +1 -1
- package/dist/resolution/scope.d.ts +7 -15
- package/dist/resolution/scope.d.ts.map +1 -1
- package/dist/resolution/scope.js +48 -44
- package/dist/resolution/scope.js.map +1 -1
- package/package.json +7 -97
- package/src/binding.ts +104 -5
- package/src/constructor-type.ts +4 -5
- package/src/container/binding-builders.ts +180 -283
- package/src/container/container.ts +90 -103
- package/src/decorators/inject.ts +3 -5
- package/src/errors.ts +21 -0
- package/src/index.ts +1 -0
- package/src/introspection/inspector.ts +1 -1
- package/src/metadata/metadata-keys.ts +3 -6
- package/src/registry.ts +38 -59
- package/src/resolution/activation-need.ts +81 -0
- package/src/resolution/binding-lookup-cache.ts +132 -0
- package/src/resolution/binding-select.ts +1 -4
- package/src/resolution/class-introspector.ts +74 -0
- package/src/resolution/diagnostics.ts +43 -0
- package/src/resolution/environment.ts +31 -1
- package/src/resolution/instantiation-plan.ts +113 -61
- package/src/resolution/lifecycle.ts +16 -11
- package/src/resolution/resolution-path.ts +5 -20
- package/src/resolution/resolver.ts +142 -371
- package/src/resolution/scope.ts +50 -49
package/src/binding.ts
CHANGED
|
@@ -40,6 +40,13 @@ export function bindingSlotEquals(left: BindingSlot, right: BindingSlot): boolea
|
|
|
40
40
|
return true;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Cached singleton absent — distinguishes "not resolved yet" from a cached `undefined`.
|
|
45
|
+
*
|
|
46
|
+
* @since 0.5.0-canary.8
|
|
47
|
+
*/
|
|
48
|
+
export const NO_INSTANCE: unique symbol = Symbol("di:no-instance");
|
|
49
|
+
|
|
43
50
|
/**
|
|
44
51
|
* @since 0.3.16-canary.0
|
|
45
52
|
*/
|
|
@@ -67,12 +74,10 @@ export function bindingSlotToString(slot: BindingSlot): string {
|
|
|
67
74
|
interface BindingBase<Value> {
|
|
68
75
|
readonly id: BindingIdentifier;
|
|
69
76
|
/**
|
|
70
|
-
* True while this binding's factory is on the sync resolution stack
|
|
71
|
-
* it on enter and clears it on exit, making cycle detection an O(1) field read with no hashing,
|
|
72
|
-
* no path scan, and no side table. Sync resolution is single-threaded, so the flag is exactly
|
|
73
|
-
* path membership; the async lane keeps its own per-path check because chains can interleave.
|
|
77
|
+
* True while this binding's factory is on the sync resolution stack — the sync lane's cycle check.
|
|
74
78
|
*
|
|
75
|
-
* @remarks Resolver-owned bookkeeping
|
|
79
|
+
* @remarks Resolver-owned bookkeeping; callers never set it. See `ARCHITECTURE.md` for why the
|
|
80
|
+
* sync and async lanes detect cycles differently.
|
|
76
81
|
*/
|
|
77
82
|
inFlight?: boolean | undefined;
|
|
78
83
|
/**
|
|
@@ -83,6 +88,13 @@ interface BindingBase<Value> {
|
|
|
83
88
|
* @remarks Resolver-owned bookkeeping — `registry.add` normalizes it, so callers never set it.
|
|
84
89
|
*/
|
|
85
90
|
frame?: ResolutionFrame | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Cached singleton instance, or {@link NO_INSTANCE}.
|
|
93
|
+
*
|
|
94
|
+
* @remarks A binding belongs to exactly one container, so its singleton slot is per-binding —
|
|
95
|
+
* a field read replaces a keyed lookup on the hottest resolve shape there is.
|
|
96
|
+
*/
|
|
97
|
+
instance?: unknown;
|
|
86
98
|
readonly token: Token<Value> | Constructor<Value>;
|
|
87
99
|
readonly slot: BindingSlot;
|
|
88
100
|
readonly predicate?: ((ctx: ConstraintContext) => boolean) | undefined;
|
|
@@ -204,6 +216,93 @@ export function generateBindingId(): BindingIdentifier {
|
|
|
204
216
|
return String(++bindingIdCounter) as BindingIdentifier;
|
|
205
217
|
}
|
|
206
218
|
|
|
219
|
+
// ── Construction ──────────────────────────────────────────────────────────────
|
|
220
|
+
|
|
221
|
+
// Superset of every kind's fields, so one literal can copy any binding shape.
|
|
222
|
+
/** Union of every key any binding kind declares — `keyof` a union would give the intersection. */
|
|
223
|
+
type BindingFieldName = Binding<unknown> extends infer Kind ? (Kind extends unknown ? keyof Kind : never) : never;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Completeness guard for {@link createBinding}'s literal.
|
|
227
|
+
*
|
|
228
|
+
* @remarks The literal is `satisfies` this, so a field added to any binding kind that the literal
|
|
229
|
+
* forgets to write is a compile error rather than a binding silently missing it.
|
|
230
|
+
*/
|
|
231
|
+
type ConstructedBindingFields = Record<BindingFieldName, unknown>;
|
|
232
|
+
|
|
233
|
+
type BindingFieldSuperset = {
|
|
234
|
+
readonly kind: Binding["kind"];
|
|
235
|
+
readonly instance?: unknown;
|
|
236
|
+
readonly scope?: unknown;
|
|
237
|
+
readonly target?: unknown;
|
|
238
|
+
readonly factory?: unknown;
|
|
239
|
+
readonly deps?: unknown;
|
|
240
|
+
readonly value?: unknown;
|
|
241
|
+
readonly onActivation?: unknown;
|
|
242
|
+
readonly onDeactivation?: unknown;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The single construction site for bindings — one literal, one V8 hidden class.
|
|
247
|
+
*
|
|
248
|
+
* @see `ARCHITECTURE.md` — why the field order and the single site are load-bearing.
|
|
249
|
+
*
|
|
250
|
+
* @param source - the kind-specific payload, or an existing binding to re-slot
|
|
251
|
+
* @param id - reuse a caller's id to keep a fluent chain's `id()` stable across refinements
|
|
252
|
+
*
|
|
253
|
+
* @since 0.5.0-canary.8
|
|
254
|
+
*/
|
|
255
|
+
export function createBinding<Value>(
|
|
256
|
+
source: PartialBinding<Value> | Binding<Value>,
|
|
257
|
+
token: Token<Value> | Constructor<Value>,
|
|
258
|
+
slot: BindingSlot,
|
|
259
|
+
predicate: ((ctx: ConstraintContext) => boolean) | undefined,
|
|
260
|
+
id: BindingIdentifier = generateBindingId(),
|
|
261
|
+
): Binding<Value> {
|
|
262
|
+
const fields = source as BindingFieldSuperset;
|
|
263
|
+
return {
|
|
264
|
+
kind: fields.kind,
|
|
265
|
+
id,
|
|
266
|
+
inFlight: false,
|
|
267
|
+
frame: undefined,
|
|
268
|
+
instance: (source as { instance?: unknown }).instance ?? NO_INSTANCE,
|
|
269
|
+
token,
|
|
270
|
+
slot,
|
|
271
|
+
predicate,
|
|
272
|
+
scope: fields.scope,
|
|
273
|
+
target: fields.target,
|
|
274
|
+
factory: fields.factory,
|
|
275
|
+
deps: fields.deps,
|
|
276
|
+
value: fields.value,
|
|
277
|
+
onActivation: fields.onActivation,
|
|
278
|
+
onDeactivation: fields.onDeactivation,
|
|
279
|
+
} satisfies ConstructedBindingFields as Binding<Value>;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Writable view of the only fields a fluent chain may refine after registration.
|
|
284
|
+
*
|
|
285
|
+
* @remarks No registry index is keyed on these, so a builder that owns the registered object
|
|
286
|
+
* can write them directly instead of re-registering. `token`, `slot`, `predicate` and `id`
|
|
287
|
+
* are excluded on purpose — changing those means re-indexing.
|
|
288
|
+
*
|
|
289
|
+
* @since 0.5.0-canary.8
|
|
290
|
+
*/
|
|
291
|
+
export interface RefinableBindingFields<Value> {
|
|
292
|
+
onActivation: ActivationHandler<Value> | undefined;
|
|
293
|
+
onDeactivation: DeactivationHandler<Value> | undefined;
|
|
294
|
+
scope: BindingScope;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Narrows a registered binding to the fields a fluent chain may still refine.
|
|
299
|
+
*
|
|
300
|
+
* @since 0.5.0-canary.8
|
|
301
|
+
*/
|
|
302
|
+
export function refinableFields<Value>(binding: Binding<Value>): RefinableBindingFields<Value> {
|
|
303
|
+
return binding as RefinableBindingFields<Value>;
|
|
304
|
+
}
|
|
305
|
+
|
|
207
306
|
// ── Builder interfaces ────────────────────────────────────────────────────────
|
|
208
307
|
|
|
209
308
|
/**
|
package/src/constructor-type.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A class
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* this alias is the DI “class token” surface only.
|
|
2
|
+
* A class token: newable, producing `Value`.
|
|
3
|
+
*
|
|
4
|
+
* @remarks Rest parameters are `never[]` so classes with typed constructors stay assignable under
|
|
5
|
+
* `strictFunctionTypes`. Construction uses the real shape; this alias is the token surface only.
|
|
7
6
|
*
|
|
8
7
|
* @since 0.3.16-canary.0
|
|
9
8
|
*/
|