@codefast/di 0.5.0-canary.7 → 0.5.0-canary.9
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 +205 -0
- package/README.md +6 -2
- package/dist/binding.d.ts +85 -24
- package/dist/binding.d.ts.map +1 -1
- package/dist/binding.js +55 -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 +144 -192
- package/dist/container/binding-builders.js.map +1 -1
- package/dist/container/container.d.ts.map +1 -1
- package/dist/container/container.js +141 -201
- 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 +24 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +30 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/introspection/inspector.d.ts +0 -1
- package/dist/introspection/inspector.d.ts.map +1 -1
- package/dist/introspection/inspector.js +3 -8
- 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 +81 -78
- package/dist/registry.js.map +1 -1
- package/dist/resolution/activation-need.d.ts +27 -0
- package/dist/resolution/activation-need.d.ts.map +1 -0
- package/dist/resolution/activation-need.js +68 -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 +118 -0
- package/dist/resolution/binding-lookup-cache.js.map +1 -0
- package/dist/resolution/binding-scope.d.ts +5 -2
- package/dist/resolution/binding-scope.d.ts.map +1 -1
- package/dist/resolution/binding-scope.js +6 -17
- package/dist/resolution/binding-scope.js.map +1 -1
- package/dist/resolution/binding-select.d.ts +8 -1
- package/dist/resolution/binding-select.d.ts.map +1 -1
- package/dist/resolution/binding-select.js +14 -36
- 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 +48 -1
- package/dist/resolution/environment.d.ts.map +1 -1
- package/dist/resolution/environment.js +134 -5
- 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 +69 -49
- 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 +60 -62
- package/dist/resolution/lifecycle.js.map +1 -1
- package/dist/resolution/resolution-path.d.ts +84 -17
- package/dist/resolution/resolution-path.d.ts.map +1 -1
- package/dist/resolution/resolution-path.js +68 -23
- package/dist/resolution/resolution-path.js.map +1 -1
- package/dist/resolution/resolve-options.d.ts +41 -4
- package/dist/resolution/resolve-options.d.ts.map +1 -1
- package/dist/resolution/resolve-options.js +25 -1
- package/dist/resolution/resolve-options.js.map +1 -1
- package/dist/resolution/resolver.d.ts +33 -10
- package/dist/resolution/resolver.d.ts.map +1 -1
- package/dist/resolution/resolver.js +471 -830
- package/dist/resolution/resolver.js.map +1 -1
- package/dist/resolution/scope.d.ts +11 -15
- package/dist/resolution/scope.d.ts.map +1 -1
- package/dist/resolution/scope.js +55 -43
- package/dist/resolution/scope.js.map +1 -1
- package/package.json +10 -106
- package/src/binding.ts +146 -24
- package/src/constructor-type.ts +4 -5
- package/src/container/binding-builders.ts +184 -284
- package/src/container/container.ts +161 -221
- package/src/decorators/inject.ts +3 -5
- package/src/errors.ts +38 -0
- package/src/index.ts +4 -1
- package/src/introspection/inspector.ts +3 -9
- package/src/metadata/metadata-keys.ts +3 -6
- package/src/registry.ts +90 -94
- package/src/resolution/activation-need.ts +85 -0
- package/src/resolution/binding-lookup-cache.ts +148 -0
- package/src/resolution/binding-scope.ts +6 -17
- package/src/resolution/binding-select.ts +15 -39
- package/src/resolution/class-introspector.ts +74 -0
- package/src/resolution/diagnostics.ts +43 -0
- package/src/resolution/environment.ts +181 -5
- package/src/resolution/instantiation-plan.ts +116 -64
- package/src/resolution/lifecycle.ts +69 -62
- package/src/resolution/resolution-path.ts +122 -43
- package/src/resolution/resolve-options.ts +51 -4
- package/src/resolution/resolver.ts +649 -1081
- package/src/resolution/scope.ts +58 -47
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,210 @@
|
|
|
1
1
|
# @codefast/di
|
|
2
2
|
|
|
3
|
+
## 0.5.0-canary.9
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - Detect async cycles from the synchronous factory cascade instead of a settle-scoped path, and escape to a per-branch path only where the cascade cannot see.
|
|
8
|
+
|
|
9
|
+
A factory asks for its dependencies from its **synchronous prefix** — `async ctx => await ctx.resolveAsync(dep)` calls `resolveAsync` before it awaits anything — so an eight-level chain is built inside one synchronous cascade before any of it settles, and the chain of who-is-resolving-whom at the moment of a request is the call stack itself. While that cascade is open the resolver's own arrays are the ancestor chain, pushed on factory-enter and popped when the factory returns its promise rather than when that promise settles. Two cascades cannot interleave, so `binding.inFlight` is exact path membership for async too, exactly as it already was for sync. Every level shares one context; nothing is allocated per level and no level observes its own settlement.
|
|
10
|
+
|
|
11
|
+
This fixes a false `CircularDependencyError`. A diamond — `A` awaiting `B` and `C` in parallel, both needing `D` — rejected with `Circular dependency detected: a → b → d → c → d`, a path in which `b → d → c` is not a dependency edge at all. `D`'s flag is now clear by the time the second sibling asks for it.
|
|
12
|
+
|
|
13
|
+
A request made from a continuation, after an await, has its ancestors on no call stack. It arrives with the cascade empty — an exact test, since a continuation never runs inside one — and escapes to a branch lane whose path is append-only: a level appends while its branch still owns the next slot and copies its own prefix once a sibling has claimed it. Anything the cascade lane does not serve escapes the same way, seeded with a snapshot of the ancestors reached so far, and a subtree that has left the cascade stays off it. A cycle formed entirely from post-await edges is still reported, one level in from the true root, because the ancestors before the first escape were never written down; `resolver-async.test.ts` pins that message.
|
|
14
|
+
|
|
15
|
+
Measured with `BENCH_ISOLATE=1 BENCH_FULL=1`, libraries interleaved with rotating order, 3 trials: against inversify 8.2.3 the suite goes from **42 / 0 / 1** to **43 / 0 / 0** — the async chain row this library had always lost now reads **1.60×** where it read 0.75×, and the async group's geomean goes **1.13× to 1.58×**. Per-level overhead against a floor of eight plain awaited async functions falls from 48.3 ns to **19.5 ns** with the collector idle and **21.3 ns** with a full GC forced every 100 samples — the lane is now within ~7 ns of a build carrying no cycle bookkeeping at all, and it is GC-insensitive again.
|
|
16
|
+
|
|
17
|
+
A paired A/B of the two builds, five passes alternating which side ran first, holds all seventeen measured sync rows at parity (0.99–1.08× medians, no row negative across every pass), including `circular-dependency-3`, which shares the `binding.inFlight` flag the cascade now uses. That A/B is also what caught a regression the suite reported as a win: a materialized async singleton did not match the cascade lane and escaped, snapshotting both cascade arrays on every resolve, for **0.81×** of the previous build across all five passes. The cascade entry now answers a plain constant and a cached singleton itself.
|
|
18
|
+
|
|
19
|
+
`ARCHITECTURE.md` records the two shapes tried before this one, including the one that fixed the same bug and measured worse, and why the sync lane's compiled-plan answer does not port to async.
|
|
20
|
+
|
|
21
|
+
`ResolutionDiagnostics` no longer carries `asyncContextPoolSize`, since there is no async context pool to report.
|
|
22
|
+
|
|
23
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - **Breaking:** `effectiveBindingScope` is no longer exported from the package root. It read a `Binding`,
|
|
24
|
+
which `package.json#exports` deliberately withholds, and no public API ever handed one out — so it was
|
|
25
|
+
exported and impossible to call. Read a binding's scope from `BindingSnapshot.scope`
|
|
26
|
+
(`container.lookupBindings()` / `container.inspect()`) or from `GraphNode.scope`
|
|
27
|
+
(`container.generateDependencyGraph()`), both of which have always carried it.
|
|
28
|
+
|
|
29
|
+
`bindingSlotToResolveOptions` now takes its slot structurally, so the slot on a public
|
|
30
|
+
`BindingSnapshot` — where `name` is an optional property rather than a required one holding
|
|
31
|
+
`undefined` — is accepted. Passing a `BindingSlot`-shaped literal keeps working.
|
|
32
|
+
|
|
33
|
+
A type test now asserts each exported function is callable with values a consumer can actually obtain
|
|
34
|
+
from the package's own exports, which is what neither of these satisfied.
|
|
35
|
+
|
|
36
|
+
### Patch Changes
|
|
37
|
+
|
|
38
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - Make resolving through a container-level `onActivation` hook as cheap as resolving without one.
|
|
39
|
+
|
|
40
|
+
A transient factory binding that carries activation hooks now takes the same `O(1)` `binding.inFlight`
|
|
41
|
+
cycle guard as the unhooked lane — the argument for that guard never mentioned hooks, since a hook
|
|
42
|
+
runs on the call stack the factory did — and `LifecycleManager` keeps a one-entry token→hooks cache
|
|
43
|
+
in front of its map, because a resolve loop asks about the same token every iteration. Together they
|
|
44
|
+
halve what the hook lane costs over the plain one. A hook that re-resolves its own token still
|
|
45
|
+
reports `CircularDependencyError`, and the flag is still released on every exit path.
|
|
46
|
+
|
|
47
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - Fix three defects found by an audit of the resolution engine's memoization:
|
|
48
|
+
|
|
49
|
+
- A `.onActivation()` hook added to a chain **after** its binding's first resolve was silently skipped on every lane that consults the activation-need memo (named resolves and nested dependency resolves) while the default-slot dynamic lane honored it. The memo now reads the binding's own hook fresh on every call, so all lanes give one answer.
|
|
50
|
+
- The activation-need memo is keyed by binding id and was only invalidated by the lifecycle version, so a long-running container that rebinds in a loop grew it without bound (~60 B per rebind). The memo is now also stamped with the registry version, evicting entries whose binding ids a rebind has retired.
|
|
51
|
+
- A `scoped` instance cached in a child container survived `unbind`/`unbindAll`/module unload — the drain released singletons only. Scoped entries are now released with their binding (no deactivation, per SPEC §5.2), and resolution diagnostics expose a `scopedInstanceCount` so the release is pinned structurally.
|
|
52
|
+
|
|
53
|
+
A paired A/B against the previous build over six activation- and dispatch-sensitive rows (three passes, alternating order) held every row within noise of parity.
|
|
54
|
+
|
|
55
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - Stop allocating a throwaway `Map` on every named resolve. The named-lookup memo upserted with
|
|
56
|
+
`getOrInsert(token, new Map())`, whose fallback JavaScript evaluates eagerly — so every call built a
|
|
57
|
+
`Map` for the hit that immediately discarded it. It now uses `Map.prototype.getOrInsertComputed` with a
|
|
58
|
+
module-level factory, which allocates nothing on a hit and no closure per call: **~1.72×** on
|
|
59
|
+
`named-constant-get`, measured paired against the previous build with the order alternated.
|
|
60
|
+
|
|
61
|
+
The bind-time upserts keep the eager form deliberately — a bind is usually a token's first, so the
|
|
62
|
+
fallback is usually the value stored, and the computed form measured slower there.
|
|
63
|
+
|
|
64
|
+
`@codefast/di` now calls `Map.prototype.getOrInsertComputed` as well as `getOrInsert`; both ship in Node
|
|
65
|
+
26+, which the package already required.
|
|
66
|
+
|
|
67
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - Put a one-entry cache in front of `BindingLookupCache`'s options-less token map. Two shapes reach that map and neither can use the registry's direct index: an **alias**, whose terminal binding the index cannot name, and a token owned by a **parent container**, whose entry has to carry the owner. Both are then resolved in a loop over the same token, so the map lookup they repeat deserves an inline cache — the rule this package already applies to `LifecycleManager.activationHandlersFor()`.
|
|
68
|
+
|
|
69
|
+
Paired A/B against the previous build, seven passes alternating which side ran first, medians: `to-alias-redirect` **1.16×** (every pass 1.15–1.18) and `child-depth-2-resolve` **1.23×** (every pass 1.22–1.27), which were the two thinnest wins in the suite outside the lifecycle rows. `rebind-hot-swap` — the row that invalidates the cache on every iteration, so the only place a front cache could be pure overhead — reads 1.17×, after a five-pass run had put it at 0.88× on mixed signs; the tighter run is the one to believe.
|
|
70
|
+
|
|
71
|
+
In the interleaved isolated suite `to-alias-redirect` reads **1.53×** of inversify 8.2.3, up from 1.33×, which is what the paired ratio predicts. `child-depth-2-resolve` reads **1.14×** there against 1.36× before — that row carries both of the report's instability markers (above 30M ops/s, and a per-trial IQR over 5%), its own throughput went _up_, and seven paired passes put it at 1.22–1.27×, so the paired number is the one that describes this change. The suite's aggregate moved from 42/0/1 to 42/1/0 at a slightly lower median on rows this change cannot reach, which is run-to-run drift rather than an effect.
|
|
72
|
+
|
|
73
|
+
`null` is a real answer from that map, meaning "this token's shape needs the full selection path", so absence is tracked by the token slot rather than by the entry, and a registry-version change clears the slot along with the map.
|
|
74
|
+
|
|
75
|
+
Folding alias hops into `registry.getFastDefault()` instead was considered and rejected as unsound: that index is a bare own-registry `Map.get` returning a binding, while an alias's terminal may live in a parent container and its invalidation depends on the whole chain's summed version, neither of which the registry can see.
|
|
76
|
+
|
|
77
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - Remove a type parameter the resolver could never honour. Fifteen private methods took `Binding<Value>`
|
|
78
|
+
and returned `Value`, but every caller supplied `Value` through an unchecked `as Binding<Value>` — so the
|
|
79
|
+
generic documented an intent the compiler never verified. The internal lanes now take the erased
|
|
80
|
+
`Binding` and return `unknown`, and the eight public resolve entry points each cast once, where the
|
|
81
|
+
caller's token is the claim being made. Seventeen casts fewer in the resolver.
|
|
82
|
+
|
|
83
|
+
What made that possible: the binding kinds declare their lifecycle hooks as methods rather than
|
|
84
|
+
function-typed properties, so their parameters compare bivariantly and `Binding<Value>` stays assignable
|
|
85
|
+
to `Binding`. The public `ActivationHandler` and `DeactivationHandler` are unchanged and still checked
|
|
86
|
+
strictly, so a handler you write is verified exactly as before.
|
|
87
|
+
|
|
88
|
+
No behaviour change: the emitted JavaScript is identical apart from one line break.
|
|
89
|
+
|
|
90
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - Collapse the resolver's duplicated logic onto one rule per question, and fix the two places where a
|
|
91
|
+
second copy had drifted.
|
|
92
|
+
|
|
93
|
+
- `resolveAll(token, { name })` now evaluates a `when()` predicate on a named binding, as `resolve`
|
|
94
|
+
always did. The name index answers the slot; the predicate is a further constraint, and the
|
|
95
|
+
fast lane was returning a candidate `resolve` refuses.
|
|
96
|
+
- Refining a binding's scope after its first resolve (`bind(T).toDynamic(f)` … later `.singleton()`)
|
|
97
|
+
now reports the new scope to `when()` predicates that read `ctx.parent.scope`. The resolution
|
|
98
|
+
frame is memoized on the binding and derives from `scope`, so the refinement has to drop it.
|
|
99
|
+
|
|
100
|
+
Internally: slot matching, name-only requests, and the alias walk each exist once; a class's
|
|
101
|
+
constructor params and a `toResolved` factory's descriptors resolve through one routine per lane;
|
|
102
|
+
`scope` is declared by every binding kind, so the engine reads it as a plain field. No public API
|
|
103
|
+
changed. Resolution throughput is unchanged or better across the benchmark suite — `resolveOptional`
|
|
104
|
+
~1.5×, transient class and `toResolved` construction ~1.35–1.44×, constants and named lookups
|
|
105
|
+
~1.3×, with the deep/wide graph rows at parity.
|
|
106
|
+
|
|
107
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - Stop minting two arrays per top-level sync resolve, and stop a pooled resolution context re-storing pointers it already holds.
|
|
108
|
+
|
|
109
|
+
`--prof` over the four thinnest rows put the largest di-attributed cost in a place none of this package's notes mention: `#acquireSyncResolutionContext` and `DefaultResolutionContext.reset()` together take **22%** of ticks on `fan-out-tree-depth-3-breadth-4` and **16%** on `scale-deep-transient-chain-512`, and `reset()` alone takes **10%** on `container-level-activation-hook`. The reason `reset()` is not free is that a pooled context outlives enough resolves to sit in old space, so each of its five field writes is a pointer store with a write barrier — and three of the five write the same resolver and the same two arrays every time.
|
|
110
|
+
|
|
111
|
+
Except they did not, because `container.resolve()` handed every call a fresh `[]` pair. So both halves are needed together: a resolver now keeps one sync `rootPath`/`rootStack` pair, lent to a top-level resolve when `rootStack.length === 0` and otherwise replaced by a fresh pair, and `reset()` compares before storing. Every sync lane pops what it pushes, so an empty stack is an exact "nobody holds this"; a nested `container.resolve()` from inside a factory still starts from an empty path, and if a resolve ever left the pair dirty the only consequence is that later resolves mint their own.
|
|
112
|
+
|
|
113
|
+
Paired A/B against this commit's parent, six passes alternating which side ran first: `constant-resolve` **1.70×**, `container-level-activation-hook` **1.67×**, `realistic-graph-resolve-root` **1.34×**, `fan-out-tree-depth-3-breadth-4` **1.28×**, `scale-deep-transient-chain-512` **1.21×**, `scale-mid-transient-chain-32` 1.16×, `singleton-class-1-dep` 1.13×, `to-alias-redirect` 1.09×, and `dynamic-async-chain-8` 0.99× as the untouched control.
|
|
114
|
+
|
|
115
|
+
`transient-class-1-dep` reads **0.91×**, negative in all six passes, and the mechanism is the same one that wins the other rows: a fresh array is in new space, so pushing a frame onto it needs no write barrier, while the shared pair is in old space and every push pays one. That row pushes a frame and does nothing else, so it is the one shape where the barrier costs more than the two allocations saved. Kept because it is one row at −9% against five between +21% and +70%.
|
|
116
|
+
|
|
117
|
+
`tests/unit/resolution/in-flight-invariants.test.ts` pins the lending rule in both directions — a nested root resolve gets its own pair, and a throwing resolve hands the pair back — and both were checked by breaking the guard.
|
|
118
|
+
|
|
119
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - `toSelf()` on a token that is not a class now throws `SelfBindingRequiresClassError` instead of a bare
|
|
120
|
+
`Error`, so it is catchable as a `DiError` like every other failure this package raises, carries a
|
|
121
|
+
`code` and the token name, and is documented in SPEC.
|
|
122
|
+
|
|
123
|
+
It was the one throw site outside the error taxonomy, and the architecture test could not see it —
|
|
124
|
+
that test only read `export class …Error` declarations. It now also fails on any `throw new Error(…)`
|
|
125
|
+
under `src/`, and on an error class the root barrel forgets to export.
|
|
126
|
+
|
|
127
|
+
- [#677](https://github.com/codefastlabs/codefast/pull/677) [`7fd9ba8`](https://github.com/codefastlabs/codefast/commit/7fd9ba82426493bee6ffd11a512920103a644842) Thanks [@thevuong](https://github.com/thevuong)! - Fix a tag request answering differently depending on how it was spelled. `resolve(T, { tags: [["n", -0]] })`
|
|
128
|
+
matched a binding tagged `["n", 0]` while `resolve(T, { tag: ["n", -0] })` threw `NoMatchingBindingError`
|
|
129
|
+
and `resolveAll` returned `[]` — three answers to one question.
|
|
130
|
+
|
|
131
|
+
The registry indexes tagged bindings in a `Map`, so it answers by SameValueZero, while tag values compare
|
|
132
|
+
by `Object.is` as SPEC §3.5 requires; the two differ on `+0` versus `-0`. The fast path now re-checks the
|
|
133
|
+
index's answer, and only where the index can be wrong — a request whose tag value is not zero was already
|
|
134
|
+
exact. `NaN` was never affected: both rules treat it as equal to itself.
|
|
135
|
+
|
|
136
|
+
- [#676](https://github.com/codefastlabs/codefast/pull/676) [`641e233`](https://github.com/codefastlabs/codefast/commit/641e2338d77fb61be2ca585a5986f34cf32ec746) Thanks [@thevuong](https://github.com/thevuong)! - Collapse the `types` and `default` lanes of `package.json#imports` from fallback arrays to single strings.
|
|
137
|
+
|
|
138
|
+
Node resolves an imports array by taking the first candidate it can parse, without checking that the file exists and without falling through — a specifier whose first candidate is missing throws `ERR_MODULE_NOT_FOUND` rather than trying the second. `./dist/*/index.js` and `./dist/*/index.d.ts` could therefore never be reached, so they read as a safety net that does not exist. The `source` lane keeps its extension candidates, which only `tsc` and Vite read and both probe.
|
|
139
|
+
|
|
140
|
+
## 0.5.0-canary.8
|
|
141
|
+
|
|
142
|
+
### Minor Changes
|
|
143
|
+
|
|
144
|
+
- [#646](https://github.com/codefastlabs/codefast/pull/646) [`0093b99`](https://github.com/codefastlabs/codefast/commit/0093b99ed711ad037b0e98e7343dee89786d328b) Thanks [@thevuong](https://github.com/thevuong)! - Build a container's rarely-used collaborators on first use instead of in its constructor: the inspector, the module ref/binding tables, the scope's in-flight and scoped caches, the registry's named and tagged slot indexes, and the class introspector's metadata caches. A container that only binds and resolves — the common case, and every per-request child container — no longer allocates eleven `Map`s it never reads.
|
|
145
|
+
|
|
146
|
+
A fresh `Container.create()` retains 2.7 KB instead of 4.8 KB (**43% lighter**), and `parent.createChild()` the same, measured by retention against a forced collection. Every deferred collaborator behaves identically whether or not something touched it first, which `tests/unit/container/deferred-subsystems.test.ts` pins by exercising each one as the first thing a fresh container does.
|
|
147
|
+
|
|
148
|
+
It is a throughput win too, on the paths that actually build containers: `Container.create()` is **1.80×** faster (230 ns → 127 ns) and a per-request child container plus a resolve through it — `createChild()` + resolve, the shape a web app runs once per request — is **1.31×** faster. Measured by an interleaved A/B with both builds loaded into one process, 13 trials in alternating order, against a control scenario that resolves from a pre-built container and so cannot benefit; the control sat at 0.997–1.009, and median and best-of agreed on both figures.
|
|
149
|
+
|
|
150
|
+
**Breaking:** `ScopeManager.getAllScoped()` is removed from the `./resolution/scope` subpath. Deferring the scoped cache raised the question of what a bulk reader returns when the cache was never allocated, and this reader had no callers anywhere in the package — so it is gone rather than carrying an empty-map fallback for nobody. `getAllSingletons()` is unaffected; its cache is still eager.
|
|
151
|
+
|
|
152
|
+
What it does **not** do is close the `realistic-graph-cold-resolve` loss against tsyringe, and the arithmetic says why: 103 ns off container construction is 2.5% of that row's 4.06 µs iteration, so the row moves ~1.5% — measured, and inside the noise floor. That row's gap is GC-attributable (the two libraries are at mutator parity; di only loses once a forced collection is in the loop), so a 13.7% allocation cut was never going to carry it.
|
|
153
|
+
|
|
154
|
+
- [#646](https://github.com/codefastlabs/codefast/pull/646) [`de80bad`](https://github.com/codefastlabs/codefast/commit/de80bad63f14afda1bd64a6d247852b24aac8e16) Thanks [@thevuong](https://github.com/thevuong)! - Publish an intentional export surface: 13 subpaths instead of 36. The engine's collaborators — `resolution/*`, `registry`, `container/*`, `binding`, `constructor-type`, and the `metadata` internals — are no longer entry points. They carry the invariants documented in ARCHITECTURE.md, and publishing them meant every internal refactor was technically a breaking change. Everything a consumer needs stays reachable from the root export, which already re-exports the builder interfaces, `Constructor`, `MetadataReader`, `effectiveBindingScope`, and the resolve-options helpers.
|
|
155
|
+
|
|
156
|
+
**This also repairs a silent break.** The surface was generated from `dist/`, so reorganising `src/` into `container/`, `resolution/` and `introspection/` renamed twelve already-published entry points — `./inspector` → `./introspection/inspector`, `./dependency-graph` → `./introspection/dependency-graph`, `./graph-adapters/*` → `./introspection/graph-adapters/*`, `./container` → `./container/container`, and the whole flat `./resolver`/`./scope`/`./lifecycle`/`./environment`/`./constraints`/`./binding-select`/`./binding-scope`/`./resolve-options` set — with no changeset saying so. The consumer-facing ones (`./inspector`, `./dependency-graph`, `./graph-adapters/*`) are back at the specifiers they shipped under; `examples/tanstack-start` imports two of them and would have broken on its next upgrade.
|
|
157
|
+
|
|
158
|
+
**Breaking:** the internal subpaths listed above are gone. Import from the package root instead.
|
|
159
|
+
|
|
160
|
+
- [#646](https://github.com/codefastlabs/codefast/pull/646) [`4ba70d1`](https://github.com/codefastlabs/codefast/commit/4ba70d1724e19580ee93ee392e413c23e669f310) Thanks [@thevuong](https://github.com/thevuong)! - Keep a singleton's instance on its binding instead of in a per-container table. A binding belongs to exactly one container, so its singleton slot is per-binding — which turns every cached-singleton read from a keyed `Map` lookup into a field read, on the most common resolve shape there is. The scope manager keeps only a lazily-created list of the bindings that have materialized, so disposal and `inspect()` can still enumerate them, and the singleton `Map` is gone entirely.
|
|
161
|
+
|
|
162
|
+
In the suite, `realistic-graph-resolve-root` — a transient controller over eight cached singletons — went from 10.66M to **12.19M** hz/op, and the `realistic` group geomean from 2.24× to **2.54×** of InversifyJS. That row carries a 2.9% IQR, so it is one of the numbers here worth reading precisely. `singleton-class-1-dep` and cold container build both moved up as well, on rows whose IQR is too wide to attribute confidently.
|
|
163
|
+
|
|
164
|
+
An interleaved A/B against the previous build, both in one process with a control that cannot benefit, put the same row between 1.09× and 1.40× across four runs — never slower, median and best-of agreeing inside each run, but with a spread that depends on what else the process had run. The suite's figure is the one to cite; the A/B established the direction. A trap worth recording: the control first read 0.88×, which was an artifact of timing an 11 ns call one at a time — batched the way the harness does it, the same control reads 1.02× with a 4% spread.
|
|
165
|
+
|
|
166
|
+
**Breaking:** `ScopeManager`'s singleton API takes a `Binding` rather than a `BindingIdentifier`, and `hasSingleton`/`getSingleton`/`peekSingleton`/`setSingleton(id, …)`/`getAllSingletons` are replaced by `setSingleton(binding, …)`, `deleteSingleton(binding)` and `cachedSingletons()`. The `SINGLETON_MISS` sentinel is gone; `NO_INSTANCE` on the binding replaces it. None of this is a published entry point any more, so it is internal — but a fork reaching into `./resolution/scope` would notice. `InstantiationPlanDependencyEntry` also drops its `ownerScope` field, which a compiled thunk no longer needs.
|
|
167
|
+
|
|
168
|
+
### Patch Changes
|
|
169
|
+
|
|
170
|
+
- [#646](https://github.com/codefastlabs/codefast/pull/646) [`d27b76f`](https://github.com/codefastlabs/codefast/commit/d27b76fb14200ae5226ec2a05b77d44ab91b016c) Thanks [@thevuong](https://github.com/thevuong)! - Thread an async chain's resolution context through the call and pool it, instead of parking chain identity on the resolver. `ctx.resolveAsync()` now hands the callee the context it used, so an inner level reuses it when the owner matches — which removes the resolver's path-identity heuristic, its shared settle callback and its active-level counter, and makes two concurrent chains correct by construction rather than by a fallback branch.
|
|
171
|
+
|
|
172
|
+
The contexts are pooled, and that is load-bearing rather than an allocation micro-optimization: a per-chain context survives its chain's microtask hops, so under a collecting profile a freshly allocated one is promoted out of the nursery and then collected the expensive way. An ablation that allocated per chain cost **2.5×** on `dynamic-async-chain-8` under a forced GC every 100 samples, which is the reason for the shape.
|
|
173
|
+
|
|
174
|
+
It does **not** close that row. An earlier draft of this changeset claimed it went from 0.98× to 1.18× of InversifyJS; that figure came from a probe running both library builds in one process, which this harness's README warns is worth ~30% on async chains, and from a 3-trial suite run on a loaded machine. At 5 trials on a quiet machine the row is **0.87×** with a 0.6% / 0.3% IQR — among the tightest numbers in the suite. The mechanism above is real; the win over inversify was not.
|
|
175
|
+
|
|
176
|
+
A competing hypothesis was tested and rejected: a forced full GC costs the two libraries the same (1.35 ms / 9.76 MB live for di, 1.41 ms / 9.89 MB for inversify), so the cost was never the collection but what di re-established afterwards.
|
|
177
|
+
|
|
178
|
+
- [#646](https://github.com/codefastlabs/codefast/pull/646) [`864d213`](https://github.com/codefastlabs/codefast/commit/864d213a4253346dae5799ebba06fc2726e933d2) Thanks [@thevuong](https://github.com/thevuong)! - Fold the fluent chain's registry committer into the chain itself. `bind()` now allocates a `BindingEntry` that carries only the `to*()` calls, and `to*()` a `BindingChain` that commits to the registry directly — one object per bind less than the entry/chain/committer trio, and one `Map` lookup less per binding registered by a module.
|
|
179
|
+
|
|
180
|
+
The two classes now share a `BindingRegistration` describing where the chain registers, built once per container rather than once per `bind()`. Threading that instead of a loose `(registry, moduleBindingIds, moduleRef)` triple makes the module invariant type-enforced — the id list is present exactly when the chain belongs to a module load — which removes both non-null assertions from the commit path, and drops the constructors from 4 and 5 positional parameters to 2 and 3.
|
|
181
|
+
|
|
182
|
+
`BindingCommitter` is gone and `BindingEntry`'s constructor now takes `(token, registration)`. Neither is a published entry point any more, so this is internal.
|
|
183
|
+
|
|
184
|
+
This is a simplification, **not** a throughput win: removing only the committer measured no change above noise. The chain stays two objects because `tests/unit/container/bind-to-builder-order.test.ts` requires `bind()`'s result to lack `when*()` at runtime — that is the test's own guarantee, stricter than SPEC §2.4, which only claims compiler enforcement. The measured ceiling for removing every builder object is ~19% on `realistic-graph-cold-resolve` under a forced GC — recorded in ARCHITECTURE so the lead is not re-tried blind.
|
|
185
|
+
|
|
186
|
+
- [#646](https://github.com/codefastlabs/codefast/pull/646) [`d27b76f`](https://github.com/codefastlabs/codefast/commit/d27b76fb14200ae5226ec2a05b77d44ab91b016c) Thanks [@thevuong](https://github.com/thevuong)! - Compile instantiation plans around dependencies the compiler cannot see through, instead of refusing to compile the graph at all. A factory, a scoped binding, an activation hook, a class past the depth limit, or a multi/optional/named parameter now compiles to an _escape_ — a re-entry into the runtime resolver seeded with exactly the ancestors the interpreted path would have pushed at that point, dispatched through exactly the resolve the interpreter would have called. Cycle detection, constraint contexts and error paths are therefore identical to never having compiled, and only the opaque dependency pays the runtime price while its siblings and ancestors stay compiled.
|
|
187
|
+
|
|
188
|
+
Previously a single `toDynamic` dependency anywhere in a class graph dropped the whole graph to the interpreted path — a 13.9× cliff on a shape applications write constantly (a factory-provided config injected into a class tree). That graph is now ~2× faster, and the first-materialization path of a singleton dependency inside a plan gained cycle detection it did not have.
|
|
189
|
+
|
|
190
|
+
- [#646](https://github.com/codefastlabs/codefast/pull/646) [`d27b76f`](https://github.com/codefastlabs/codefast/commit/d27b76fb14200ae5226ec2a05b77d44ab91b016c) Thanks [@thevuong](https://github.com/thevuong)! - Split the resolver's self-contained caches into named collaborators — `BindingLookupCache` (the chain-versioned options-less lookup memo), `ClassIntrospector` (per-class metadata, `@postConstruct` discovery, accessor injection, instantiation) and `ActivationNeedCache` (per-binding activation need, versioned on the lifecycle manager). The engine class keeps the sync and async pipelines, which genuinely need the same private state on every hop, and `ARCHITECTURE.md` now records the layering, the invariants each hot path depends on, and the rule that separates a legitimate threshold (choosing an implementation) from the kind that was removed (choosing a semantics).
|
|
191
|
+
|
|
192
|
+
New subpaths `@codefast/di/resolution/{activation-need,binding-lookup-cache,class-introspector}`; `@codefast/di/resolution/class-plan` is now `@codefast/di/resolution/instantiation-plan`, correcting an export map that had been stale since the module was renamed.
|
|
193
|
+
|
|
194
|
+
- [#646](https://github.com/codefastlabs/codefast/pull/646) [`a720c62`](https://github.com/codefastlabs/codefast/commit/a720c6297d041ffd2d0bba2e6146af894007a367) Thanks [@thevuong](https://github.com/thevuong)! - Collapse the fluent binding chain into one object. A single `BindingChain` is now the `BindToBuilder` that `bind()` returns and the kind-specific builder that `to*()` returns, so a `bind()` allocates one builder instead of two.
|
|
195
|
+
|
|
196
|
+
The `to*()`-before-`when*()` ordering stays enforced, as a type-level guarantee — which is what SPEC §2.4 actually claims. `bind()` is typed `BindToBuilder`, so a refinement before `to*()` does not compile; `tests/types/container-api.test.ts` pins that. For a caller without types, or one who casts past them, every refinement now throws the new **`ChainNotRegisteredError`** naming the token and pointing at `to*()`, rather than silently doing nothing. `whenDefault()` asserts registration for that reason alone, since it otherwise has nothing to do.
|
|
197
|
+
|
|
198
|
+
The previous revision kept two objects because a unit test asserted the refinement methods were _absent from the object_ `bind()` returns — a stricter reading than the spec, and one that pinned an implementation detail. That test now asserts the contract instead: every refinement throws before `to*()`, nothing is registered when it does, and the chain still works normally afterwards.
|
|
199
|
+
|
|
200
|
+
This is an API simplification, **not** a throughput win: going from four builder objects per bind to three measured no change above noise, and a fluent API cannot go below one, so the ~19% ceiling recorded in ARCHITECTURE for removing all of them is unreachable rather than pending.
|
|
201
|
+
|
|
202
|
+
- [#646](https://github.com/codefastlabs/codefast/pull/646) [`1241f82`](https://github.com/codefastlabs/codefast/commit/1241f82bdb40613667c781111f2ce20409ddfd89) Thanks [@thevuong](https://github.com/thevuong)! - Register a fluent binding chain once instead of once per refinement. `bind(T).toDynamic(f).singleton()` used to insert a binding, remove it, and insert a replacement — two registry mutations, two version bumps, and a full index churn per binding. The chain now registers on its `to*()` call and refines that same registered object in place; only `when*()` re-slots, and it re-registers under the chain's original id, so `id()` stays valid for the whole chain instead of the intermediate ids being dead. Binding construction also funnels through a single `createBinding()` literal, which is what guarantees the one V8 hidden class the resolver's hot property reads depend on — so the registry stores what it is handed rather than re-copying it.
|
|
203
|
+
|
|
204
|
+
Cold container build (build, bind 10 nodes, resolve the root) went from the suite's only loss to a win against every competitor: 0.76× → 3.0× of InversifyJS, 0.43× → 1.9× of Awilix, 0.22× → 1.07× of tsyringe.
|
|
205
|
+
|
|
206
|
+
The builder's `CommitFn` type is replaced by a `BindingCommitter` interface (`commit` plus `refine`, the latter for in-place refinements the registry indexes do not care about), and `createBinding` / `refinableFields` are new exports from `@codefast/di/binding`.
|
|
207
|
+
|
|
3
208
|
## 0.5.0-canary.7
|
|
4
209
|
|
|
5
210
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -16,7 +16,9 @@ Lightweight, type-safe dependency injection for modern TypeScript — built on T
|
|
|
16
16
|
|
|
17
17
|
## Requirements
|
|
18
18
|
|
|
19
|
-
- **Node.js 26 or later — required.** The container uses the native `Map.prototype.getOrInsert`
|
|
19
|
+
- **Node.js 26 or later — required.** The container uses the native `Map.prototype.getOrInsert` and
|
|
20
|
+
`Map.prototype.getOrInsertComputed` (ES2025), which ship in Node 26+. On older Node versions the
|
|
21
|
+
package throws at runtime.
|
|
20
22
|
- **TypeScript 5.2+** with native Stage 3 decorators — leave `experimentalDecorators` **off** (it is off by default).
|
|
21
23
|
|
|
22
24
|
## Installation
|
|
@@ -245,7 +247,9 @@ The root entry re-exports the full public API — prefer it (`import { Container
|
|
|
245
247
|
|
|
246
248
|
## Benchmarks
|
|
247
249
|
|
|
248
|
-
A head-to-head benchmark suite lives in the monorepo: [benchmarks/di-inversify](https://github.com/codefastlabs/codefast/tree/main/benchmarks/di-inversify). It compares `@codefast/di` against **InversifyJS 8** on the full scenario set, plus **Awilix** and **tsyringe** on a shared core subset. Each library runs in its canonical mode, in isolated subprocesses, reported as per-trial medians with interquartile range — designed so the results are re-runnable rather than taken on faith.
|
|
250
|
+
A head-to-head benchmark suite lives in the monorepo: [benchmarks/di-inversify](https://github.com/codefastlabs/codefast/tree/main/benchmarks/di-inversify). It compares `@codefast/di` against **InversifyJS 8** on the full scenario set, plus **Awilix** and **tsyringe** on a shared core subset. Each library runs in its canonical mode, in isolated subprocesses, reported as per-trial medians with interquartile range — designed so the results are re-runnable rather than taken on faith.
|
|
251
|
+
|
|
252
|
+
Against InversifyJS — the only one of the three that covers a comparable feature surface — `@codefast/di` currently wins **all 43 comparable scenarios** in both profiles, at a median of 1.86×–2.21× and a geometric mean of 2.38×–2.76×. Against the two deliberately leaner containers it wins the shared core subset as well, with one exception: cold container build against tsyringe under the forced-GC profile. See [RESULTS.md](https://github.com/codefastlabs/codefast/blob/main/benchmarks/di-inversify/RESULTS.md) for the full tables, the caveats, and the losses that earlier revisions reported — or run `pnpm bench` in that package to reproduce them on your machine.
|
|
249
253
|
|
|
250
254
|
## Contributing
|
|
251
255
|
|
package/dist/binding.d.ts
CHANGED
|
@@ -12,6 +12,12 @@ export interface BindingSlot {
|
|
|
12
12
|
* @since 0.3.16-canary.0
|
|
13
13
|
*/
|
|
14
14
|
export declare function bindingSlotEquals(left: BindingSlot, right: BindingSlot): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Cached singleton absent — distinguishes "not resolved yet" from a cached `undefined`.
|
|
17
|
+
*
|
|
18
|
+
* @since 0.5.0-canary.8
|
|
19
|
+
*/
|
|
20
|
+
export declare const NO_INSTANCE: unique symbol;
|
|
15
21
|
/**
|
|
16
22
|
* @since 0.3.16-canary.0
|
|
17
23
|
*/
|
|
@@ -26,14 +32,14 @@ export declare function bindingSlotToString(slot: BindingSlot): string;
|
|
|
26
32
|
interface BindingBase<Value> {
|
|
27
33
|
readonly id: BindingIdentifier;
|
|
28
34
|
/**
|
|
29
|
-
* True while this binding's factory is on the
|
|
30
|
-
* it on enter and clears it on exit, making cycle detection an O(1) field read with no hashing,
|
|
31
|
-
* no path scan, and no side table. Sync resolution is single-threaded, so the flag is exactly
|
|
32
|
-
* path membership; the async lane keeps its own per-path check because chains can interleave.
|
|
35
|
+
* True while this binding's factory is executing on the current synchronous call stack.
|
|
33
36
|
*
|
|
34
|
-
* @remarks
|
|
37
|
+
* @remarks Both cycle guards that can use an `O(1)` flag read this — the sync transient-dynamic
|
|
38
|
+
* lane and the async cascade lane — because synchronous code does not interleave, so the flag *is*
|
|
39
|
+
* exact path membership. Not optional: `createBinding` always sets it, and a field that may be
|
|
40
|
+
* absent is a field that can cost the shared hidden class. Resolver-owned; callers never set it.
|
|
35
41
|
*/
|
|
36
|
-
inFlight
|
|
42
|
+
inFlight: boolean;
|
|
37
43
|
/**
|
|
38
44
|
* Memoized resolution frame for this binding. Its contents derive only from immutable binding
|
|
39
45
|
* fields, so it is computed once on first resolve and reused instead of a per-resolver Map
|
|
@@ -42,72 +48,80 @@ interface BindingBase<Value> {
|
|
|
42
48
|
* @remarks Resolver-owned bookkeeping — `registry.add` normalizes it, so callers never set it.
|
|
43
49
|
*/
|
|
44
50
|
frame?: ResolutionFrame | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Cached singleton instance, or {@link NO_INSTANCE}.
|
|
53
|
+
*
|
|
54
|
+
* @remarks A binding belongs to exactly one container, so its singleton slot is per-binding —
|
|
55
|
+
* a field read replaces a keyed lookup on the hottest resolve shape there is.
|
|
56
|
+
*/
|
|
57
|
+
instance?: unknown;
|
|
45
58
|
readonly token: Token<Value> | Constructor<Value>;
|
|
46
59
|
readonly slot: BindingSlot;
|
|
47
60
|
readonly predicate?: ((ctx: ConstraintContext) => boolean) | undefined;
|
|
48
61
|
}
|
|
49
62
|
type BindingBaseKeys = keyof BindingBase<unknown>;
|
|
63
|
+
/**
|
|
64
|
+
* The lifecycle hooks every kind but `alias` may carry.
|
|
65
|
+
*
|
|
66
|
+
* @remarks Declared as **methods**, not function-typed properties, so their parameters compare
|
|
67
|
+
* bivariantly and `Binding<Value>` stays assignable to `Binding`. The engine erases the value type at
|
|
68
|
+
* every lane boundary regardless; the public `ActivationHandler` / `DeactivationHandler` keep strict
|
|
69
|
+
* checking, which is where a user's handler is actually verified. Not `readonly`: a fluent chain
|
|
70
|
+
* refines both in place — see {@link RefinableBindingFields}.
|
|
71
|
+
*/
|
|
72
|
+
interface BindingLifecycleHooks<Value> {
|
|
73
|
+
onActivation?(ctx: ResolutionContext, instance: Value): Value | Promise<Value>;
|
|
74
|
+
onDeactivation?(instance: Value): void | Promise<void>;
|
|
75
|
+
}
|
|
50
76
|
/**
|
|
51
77
|
* @since 0.3.16-canary.0
|
|
52
78
|
*/
|
|
53
|
-
export interface ClassBinding<Value> extends BindingBase<Value> {
|
|
79
|
+
export interface ClassBinding<Value> extends BindingBase<Value>, BindingLifecycleHooks<Value> {
|
|
54
80
|
readonly kind: "class";
|
|
55
81
|
readonly target: Constructor<Value>;
|
|
56
82
|
readonly scope: BindingScope;
|
|
57
|
-
readonly onActivation?: ActivationHandler<Value> | undefined;
|
|
58
|
-
readonly onDeactivation?: DeactivationHandler<Value> | undefined;
|
|
59
83
|
}
|
|
60
84
|
/**
|
|
61
85
|
* @since 0.3.16-canary.0
|
|
62
86
|
*/
|
|
63
|
-
export interface DynamicBinding<Value> extends BindingBase<Value> {
|
|
87
|
+
export interface DynamicBinding<Value> extends BindingBase<Value>, BindingLifecycleHooks<Value> {
|
|
64
88
|
readonly kind: "dynamic";
|
|
65
89
|
readonly factory: (ctx: ResolutionContext) => Value;
|
|
66
90
|
readonly scope: BindingScope;
|
|
67
|
-
readonly onActivation?: ActivationHandler<Value> | undefined;
|
|
68
|
-
readonly onDeactivation?: DeactivationHandler<Value> | undefined;
|
|
69
91
|
}
|
|
70
92
|
/**
|
|
71
93
|
* @since 0.3.16-canary.0
|
|
72
94
|
*/
|
|
73
|
-
export interface DynamicAsyncBinding<Value> extends BindingBase<Value> {
|
|
95
|
+
export interface DynamicAsyncBinding<Value> extends BindingBase<Value>, BindingLifecycleHooks<Value> {
|
|
74
96
|
readonly kind: "dynamic-async";
|
|
75
97
|
readonly factory: (ctx: ResolutionContext) => Promise<Value>;
|
|
76
98
|
readonly scope: BindingScope;
|
|
77
|
-
readonly onActivation?: ActivationHandler<Value> | undefined;
|
|
78
|
-
readonly onDeactivation?: DeactivationHandler<Value> | undefined;
|
|
79
99
|
}
|
|
80
100
|
/**
|
|
81
101
|
* @since 0.3.16-canary.0
|
|
82
102
|
*/
|
|
83
|
-
export interface ResolvedBinding<Value> extends BindingBase<Value> {
|
|
103
|
+
export interface ResolvedBinding<Value> extends BindingBase<Value>, BindingLifecycleHooks<Value> {
|
|
84
104
|
readonly kind: "resolved";
|
|
85
105
|
readonly factory: (...args: Array<unknown>) => Value;
|
|
86
106
|
readonly deps: ReadonlyArray<InjectionDescriptor>;
|
|
87
107
|
readonly scope: BindingScope;
|
|
88
|
-
readonly onActivation?: ActivationHandler<Value> | undefined;
|
|
89
|
-
readonly onDeactivation?: DeactivationHandler<Value> | undefined;
|
|
90
108
|
}
|
|
91
109
|
/**
|
|
92
110
|
* @since 0.3.16-canary.0
|
|
93
111
|
*/
|
|
94
|
-
export interface ResolvedAsyncBinding<Value> extends BindingBase<Value> {
|
|
112
|
+
export interface ResolvedAsyncBinding<Value> extends BindingBase<Value>, BindingLifecycleHooks<Value> {
|
|
95
113
|
readonly kind: "resolved-async";
|
|
96
114
|
readonly factory: (...args: Array<unknown>) => Promise<Value>;
|
|
97
115
|
readonly deps: ReadonlyArray<InjectionDescriptor>;
|
|
98
116
|
readonly scope: BindingScope;
|
|
99
|
-
readonly onActivation?: ActivationHandler<Value> | undefined;
|
|
100
|
-
readonly onDeactivation?: DeactivationHandler<Value> | undefined;
|
|
101
117
|
}
|
|
102
118
|
/**
|
|
103
119
|
* @since 0.3.16-canary.0
|
|
104
120
|
*/
|
|
105
|
-
export interface ConstantBinding<Value> extends BindingBase<Value> {
|
|
121
|
+
export interface ConstantBinding<Value> extends BindingBase<Value>, BindingLifecycleHooks<Value> {
|
|
106
122
|
readonly kind: "constant";
|
|
107
123
|
readonly value: Value;
|
|
108
124
|
readonly scope: "singleton";
|
|
109
|
-
readonly onActivation?: ActivationHandler<Value> | undefined;
|
|
110
|
-
readonly onDeactivation?: DeactivationHandler<Value> | undefined;
|
|
111
125
|
}
|
|
112
126
|
/**
|
|
113
127
|
* @since 0.3.16-canary.0
|
|
@@ -115,6 +129,13 @@ export interface ConstantBinding<Value> extends BindingBase<Value> {
|
|
|
115
129
|
export interface AliasBinding<Value> extends BindingBase<Value> {
|
|
116
130
|
readonly kind: "alias";
|
|
117
131
|
readonly target: Token<Value> | Constructor<Value>;
|
|
132
|
+
/**
|
|
133
|
+
* Always `transient` — an alias defers scoping to the binding it points at.
|
|
134
|
+
*
|
|
135
|
+
* @remarks Declared so `scope` is present on every kind, which is what lets the engine read it
|
|
136
|
+
* as a plain field instead of testing for the one kind that lacks it.
|
|
137
|
+
*/
|
|
138
|
+
readonly scope: "transient";
|
|
118
139
|
}
|
|
119
140
|
/**
|
|
120
141
|
* @since 0.3.16-canary.0
|
|
@@ -130,6 +151,46 @@ export type PartialBinding<Value> = Omit<ClassBinding<Value>, BindingBaseKeys> |
|
|
|
130
151
|
* @since 0.3.16-canary.0
|
|
131
152
|
*/
|
|
132
153
|
export declare function generateBindingId(): BindingIdentifier;
|
|
154
|
+
/**
|
|
155
|
+
* The single construction site for bindings — one literal, one V8 hidden class.
|
|
156
|
+
*
|
|
157
|
+
* @see `ARCHITECTURE.md` — why the field order and the single site are load-bearing.
|
|
158
|
+
*
|
|
159
|
+
* @param source - the kind-specific payload, or an existing binding to re-slot
|
|
160
|
+
* @param id - reuse a caller's id to keep a fluent chain's `id()` stable across refinements
|
|
161
|
+
*
|
|
162
|
+
* @since 0.5.0-canary.8
|
|
163
|
+
*/
|
|
164
|
+
export declare function createBinding<Value>(source: PartialBinding<Value> | Binding<Value>, token: Token<Value> | Constructor<Value>, slot: BindingSlot, predicate: ((ctx: ConstraintContext) => boolean) | undefined, id?: BindingIdentifier): Binding<Value>;
|
|
165
|
+
/**
|
|
166
|
+
* Writable view of the only fields a fluent chain may refine after registration.
|
|
167
|
+
*
|
|
168
|
+
* @remarks No registry index is keyed on these, so a builder that owns the registered object
|
|
169
|
+
* can write them directly instead of re-registering. `token`, `slot`, `predicate` and `id`
|
|
170
|
+
* are excluded on purpose — changing those means re-indexing.
|
|
171
|
+
*
|
|
172
|
+
* @since 0.5.0-canary.8
|
|
173
|
+
*/
|
|
174
|
+
export interface RefinableBindingFields<Value> {
|
|
175
|
+
onActivation: ActivationHandler<Value> | undefined;
|
|
176
|
+
onDeactivation: DeactivationHandler<Value> | undefined;
|
|
177
|
+
scope: BindingScope;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Narrows a registered binding to the fields a fluent chain may still refine.
|
|
181
|
+
*
|
|
182
|
+
* @since 0.5.0-canary.8
|
|
183
|
+
*/
|
|
184
|
+
export declare function refinableFields<Value>(binding: Binding<Value>): RefinableBindingFields<Value>;
|
|
185
|
+
/**
|
|
186
|
+
* Drops the memoized resolution frame, for a refinement that changes what the frame reports.
|
|
187
|
+
*
|
|
188
|
+
* @remarks `scope` is the only field a chain writes in place that the frame derives from — a
|
|
189
|
+
* re-slot builds a fresh binding, whose frame starts empty anyway.
|
|
190
|
+
*
|
|
191
|
+
* @since 0.5.0-canary.9
|
|
192
|
+
*/
|
|
193
|
+
export declare function clearBindingFrame<Value>(binding: Binding<Value>): void;
|
|
133
194
|
/**
|
|
134
195
|
* Common slot-constraint + id methods shared by all concrete binding builders.
|
|
135
196
|
*
|
package/dist/binding.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC9G,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAIjB;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAahF;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;CAAsD,CAAC;AAExF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAY7D;AAID,UAAU,WAAW,CAAC,KAAK;IACzB,QAAQ,CAAC,EAAE,EAAE,iBAAiB,CAAC;IAC/B;;;;;;;OAOG;IACH,QAAQ,
|
|
1
|
+
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"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"}
|
package/dist/binding.js
CHANGED
|
@@ -15,6 +15,12 @@ export function bindingSlotEquals(left, right) {
|
|
|
15
15
|
}
|
|
16
16
|
return true;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Cached singleton absent — distinguishes "not resolved yet" from a cached `undefined`.
|
|
20
|
+
*
|
|
21
|
+
* @since 0.5.0-canary.8
|
|
22
|
+
*/
|
|
23
|
+
export const NO_INSTANCE = Symbol("di:no-instance");
|
|
18
24
|
/**
|
|
19
25
|
* @since 0.3.16-canary.0
|
|
20
26
|
*/
|
|
@@ -43,4 +49,53 @@ let bindingIdCounter = 0;
|
|
|
43
49
|
export function generateBindingId() {
|
|
44
50
|
return String(++bindingIdCounter);
|
|
45
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The single construction site for bindings — one literal, one V8 hidden class.
|
|
54
|
+
*
|
|
55
|
+
* @see `ARCHITECTURE.md` — why the field order and the single site are load-bearing.
|
|
56
|
+
*
|
|
57
|
+
* @param source - the kind-specific payload, or an existing binding to re-slot
|
|
58
|
+
* @param id - reuse a caller's id to keep a fluent chain's `id()` stable across refinements
|
|
59
|
+
*
|
|
60
|
+
* @since 0.5.0-canary.8
|
|
61
|
+
*/
|
|
62
|
+
export function createBinding(source, token, slot, predicate, id = generateBindingId()) {
|
|
63
|
+
const fields = source;
|
|
64
|
+
return {
|
|
65
|
+
kind: fields.kind,
|
|
66
|
+
id,
|
|
67
|
+
inFlight: false,
|
|
68
|
+
frame: undefined,
|
|
69
|
+
instance: source.instance ?? NO_INSTANCE,
|
|
70
|
+
token,
|
|
71
|
+
slot,
|
|
72
|
+
predicate,
|
|
73
|
+
scope: fields.scope,
|
|
74
|
+
target: fields.target,
|
|
75
|
+
factory: fields.factory,
|
|
76
|
+
deps: fields.deps,
|
|
77
|
+
value: fields.value,
|
|
78
|
+
onActivation: fields.onActivation,
|
|
79
|
+
onDeactivation: fields.onDeactivation,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Narrows a registered binding to the fields a fluent chain may still refine.
|
|
84
|
+
*
|
|
85
|
+
* @since 0.5.0-canary.8
|
|
86
|
+
*/
|
|
87
|
+
export function refinableFields(binding) {
|
|
88
|
+
return binding;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Drops the memoized resolution frame, for a refinement that changes what the frame reports.
|
|
92
|
+
*
|
|
93
|
+
* @remarks `scope` is the only field a chain writes in place that the frame derives from — a
|
|
94
|
+
* re-slot builds a fresh binding, whose frame starts empty anyway.
|
|
95
|
+
*
|
|
96
|
+
* @since 0.5.0-canary.9
|
|
97
|
+
*/
|
|
98
|
+
export function clearBindingFrame(binding) {
|
|
99
|
+
binding.frame = undefined;
|
|
100
|
+
}
|
|
46
101
|
//# sourceMappingURL=binding.js.map
|
package/dist/binding.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AAwBA;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAiB,EAAE,KAAkB;IACrE,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,QAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YACzG,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAwB,CAAC;AAExF;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAiB;IACnD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAClC,CAAC;IACD,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;
|
|
1
|
+
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constructor-type.d.ts","sourceRoot":"","sources":["../src/constructor-type.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"constructor-type.d.ts","sourceRoot":"","sources":["../src/constructor-type.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,CAAC,KAAK,GAAG,OAAO,IAAI,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC;AAEhF;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC"}
|