@codefast/di 0.10.0 → 0.10.1
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 +28 -0
- package/README.md +3 -2
- package/dist/ambient/active-container.d.ts +6 -9
- package/dist/ambient/active-container.js +2 -5
- package/dist/container/binding-builders.d.ts +7 -7
- package/dist/container/binding-builders.js +36 -27
- package/dist/container/container.d.ts +8 -8
- package/dist/container/container.js +20 -20
- package/dist/core/binding-scope.d.ts +2 -2
- package/dist/core/binding.d.ts +6 -6
- package/dist/core/binding.js +1 -1
- package/dist/core/constraint-requirement.d.ts +1 -1
- package/dist/core/module.d.ts +3 -3
- package/dist/core/registry.d.ts +6 -6
- package/dist/core/registry.js +36 -24
- package/dist/core/token.d.ts +1 -1
- package/dist/core/types.d.ts +5 -5
- package/dist/decorators/inject.d.ts +3 -3
- package/dist/decorators/inject.js +5 -5
- package/dist/decorators/injectable.d.ts +2 -2
- package/dist/decorators/injectable.js +2 -2
- package/dist/decorators/lifecycle-decorators.js +2 -2
- package/dist/errors/errors.d.ts +8 -11
- package/dist/errors/errors.js +7 -10
- package/dist/index.d.ts +35 -35
- package/dist/index.js +19 -19
- package/dist/injection/descriptor.d.ts +3 -3
- package/dist/injection/resolve-options.d.ts +3 -3
- package/dist/injection/resolve-options.js +1 -1
- package/dist/introspection/dependency-graph.d.ts +3 -3
- package/dist/introspection/dependency-graph.js +5 -5
- package/dist/introspection/graph-adapters/cytoscape.d.ts +1 -1
- package/dist/introspection/graph-adapters/dot.d.ts +1 -1
- package/dist/introspection/graph-adapters/mermaid.d.ts +1 -1
- package/dist/introspection/graph-adapters/reactflow.d.ts +1 -1
- package/dist/introspection/inspector.d.ts +4 -4
- package/dist/introspection/inspector.js +3 -3
- package/dist/lifecycle/lifecycle-manager.d.ts +4 -4
- package/dist/lifecycle/lifecycle-manager.js +4 -4
- package/dist/lifecycle/scope-manager.d.ts +2 -2
- package/dist/lifecycle/scope-manager.js +3 -3
- package/dist/metadata/metadata-reader-token.d.ts +2 -2
- package/dist/metadata/metadata-reader-token.js +1 -1
- package/dist/metadata/metadata-types.d.ts +3 -3
- package/dist/metadata/symbol-metadata-reader.d.ts +3 -3
- package/dist/metadata/symbol-metadata-reader.js +1 -1
- package/dist/metadata/verifying-metadata-reader.d.ts +1 -1
- package/dist/metadata/verifying-metadata-reader.js +2 -2
- package/dist/resolution/cache/activation-need.d.ts +4 -4
- package/dist/resolution/cache/binding-lookup-cache.d.ts +5 -5
- package/dist/resolution/cache/binding-lookup-cache.js +2 -2
- package/dist/resolution/cache/class-introspector.d.ts +5 -5
- package/dist/resolution/cache/class-introspector.js +55 -56
- package/dist/resolution/context.d.ts +3 -3
- package/dist/resolution/context.js +1 -1
- package/dist/resolution/path/resolution-path.d.ts +1 -1
- package/dist/resolution/path/resolution-path.js +1 -1
- package/dist/resolution/plan/instantiation-plan.d.ts +5 -5
- package/dist/resolution/plan/instantiation-plan.js +5 -5
- package/dist/resolution/plan/plan-codegen.d.ts +3 -3
- package/dist/resolution/plan/plan-codegen.js +2 -2
- package/dist/resolution/resolver.d.ts +12 -12
- package/dist/resolution/resolver.js +33 -20
- package/dist/resolution/select/binding-select.d.ts +6 -5
- package/dist/resolution/select/binding-select.js +5 -4
- package/dist/resolution/select/constraints.d.ts +3 -3
- package/dist/resolution/select/constraints.js +4 -4
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @codefast/di
|
|
2
2
|
|
|
3
|
+
## 0.10.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#892](https://github.com/codefastlabs/codefast/pull/892) [`4c97c5b`](https://github.com/codefastlabs/codefast/commit/4c97c5b8c2314f25ee9df7eac5a4b5dd723d6d90) Thanks [@thevuong](https://github.com/thevuong)! - Lower the monorepo's Node floor from 24 to 22.12, so the packages install and run on the active Node 22 LTS line.
|
|
8
|
+
|
|
9
|
+
`engines.node` becomes `>=22.12.0` across every package — the floor the shared toolchain (oxlint, Vite, Vitest, TanStack
|
|
10
|
+
Start) already requires. Development stays on the latest Node (`.node-version`) for speed, and a CI matrix exercises the
|
|
11
|
+
floor and the active LTS directly, so the floor is a contract CI proves rather than one everyone has to run.
|
|
12
|
+
`@types/node` is pinned to the floor's major (`^22`), with a workspace override holding the whole tree there so a dev
|
|
13
|
+
tool's `@types/node: "*"` peer can no longer pull a newer major and mask an API the floor lacks. The floor stays
|
|
14
|
+
mechanical, not advisory: `@codefast/di` keeps its own `Map` upsert helpers rather than the ES2025
|
|
15
|
+
`Map.prototype.getOrInsert` (which would raise the floor to 26) and its `lib` stays `ES2024`. `@codefast/cli`'s mirror
|
|
16
|
+
step now calls the `node:path` functions directly instead of aliasing them, which the floor's types correctly flag as
|
|
17
|
+
unbound methods.
|
|
18
|
+
|
|
19
|
+
The shared `@codefast/typescript-config` presets pin `lib` and `target` to `ES2024` (was `ESNext`) so the compiler's
|
|
20
|
+
ECMAScript surface matches the Node floor: an ES2025 builtin such as `Map.prototype.getOrInsert` now fails to type-check
|
|
21
|
+
rather than compiling and crashing on Node 22.12. `@codefast/di` and `@codefast/di-testing` already pinned `lib` and are
|
|
22
|
+
unchanged.
|
|
23
|
+
|
|
24
|
+
Internal subpath imports move from a `#/` prefix to a bare `#` (`#core/token`, not `#/core/token`), and the
|
|
25
|
+
`package.json#imports` keys become `#*`/`#tests/*`/`#examples/*` to match. Node's native ESM resolver rejects a
|
|
26
|
+
`#/`-prefixed specifier with `ERR_INVALID_MODULE_SPECIFIER` on the whole Node 22 line (and on Node 24 before 24.14), and
|
|
27
|
+
each package ships those specifiers verbatim inside its published `dist/*.js` for a consumer's Node to resolve — so this
|
|
28
|
+
rename is what actually lets the packages import on the new floor. Purely internal: a consumer's own import paths are
|
|
29
|
+
unchanged.
|
|
30
|
+
|
|
3
31
|
## 0.10.0
|
|
4
32
|
|
|
5
33
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ its keep as the dependency graph grows.
|
|
|
35
35
|
pnpm add @codefast/di
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
`@codefast/di` requires Node.js
|
|
38
|
+
`@codefast/di` requires Node.js 22.12 or later and TypeScript 5.9 or later, with native Stage 3 decorators. Leave
|
|
39
39
|
`experimentalDecorators` off — it's off by default. The package is published on 0.x and versioned on its own track:
|
|
40
40
|
breaking changes ship as minor versions, so pin the minor version when you need stability.
|
|
41
41
|
|
|
@@ -224,7 +224,8 @@ predicates ship from the root entry:
|
|
|
224
224
|
| `whenParentTaggedAll(criteria)` | the parent's slot carries all criteria in the array |
|
|
225
225
|
| `whenAnyAncestorTaggedAll(criteria)` | some ancestor's slot carries all criteria in the array |
|
|
226
226
|
|
|
227
|
-
For the exact matching and most-specific-wins rules, see
|
|
227
|
+
For the exact matching and most-specific-wins rules, see
|
|
228
|
+
[`SPEC.md` → Slots and last-wins](./SPEC.md#slots-and-last-wins--the-exact-definition).
|
|
228
229
|
|
|
229
230
|
## Decorators
|
|
230
231
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** The container an `@inject` accessor initializer resolves from when it has no other handle. */
|
|
2
|
-
import type { Container } from "
|
|
3
|
-
import type { ConstructorInvocation } from "
|
|
4
|
-
import type { Token } from "
|
|
5
|
-
import type { Constructor, ResolveOptions } from "
|
|
2
|
+
import type { Container } from "#container/container";
|
|
3
|
+
import type { ConstructorInvocation } from "#core/constructor-type";
|
|
4
|
+
import type { Token } from "#core/token";
|
|
5
|
+
import type { Constructor, ResolveOptions } from "#core/types";
|
|
6
6
|
/**
|
|
7
7
|
* Path-continuing resolution the engine installs while constructing a class with `@inject` accessors.
|
|
8
8
|
*
|
|
@@ -27,11 +27,6 @@ export declare function runWithContainer<Result>(container: Container, fn: () =>
|
|
|
27
27
|
* @since 0.6.0
|
|
28
28
|
*/
|
|
29
29
|
export declare function runWithAmbientResolution<Result>(container: Container, resolution: AmbientResolution | undefined, fn: () => Result): Result;
|
|
30
|
-
/**
|
|
31
|
-
* Returns the ambient container for the construction in flight, if one is installed.
|
|
32
|
-
*
|
|
33
|
-
* @since 0.3.16-canary.0
|
|
34
|
-
*/
|
|
35
30
|
/**
|
|
36
31
|
* Constructs `target` with `container` and `resolution` ambient for the duration of its constructor.
|
|
37
32
|
*
|
|
@@ -42,6 +37,8 @@ export declare function runWithAmbientResolution<Result>(container: Container, r
|
|
|
42
37
|
*/
|
|
43
38
|
export declare function constructWithAmbientResolution(container: Container, resolution: AmbientResolution, target: ConstructorInvocation, deps: ReadonlyArray<unknown>): unknown;
|
|
44
39
|
/**
|
|
40
|
+
* Returns the ambient container for the construction in flight, if one is installed.
|
|
41
|
+
*
|
|
45
42
|
* @since 0.10.0
|
|
46
43
|
*/
|
|
47
44
|
export declare function getActiveContainer(): Container | undefined;
|
|
@@ -26,11 +26,6 @@ export function runWithAmbientResolution(container, resolution, fn) {
|
|
|
26
26
|
activeResolution = previousResolution;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Returns the ambient container for the construction in flight, if one is installed.
|
|
31
|
-
*
|
|
32
|
-
* @since 0.3.16-canary.0
|
|
33
|
-
*/
|
|
34
29
|
/**
|
|
35
30
|
* Constructs `target` with `container` and `resolution` ambient for the duration of its constructor.
|
|
36
31
|
*
|
|
@@ -53,6 +48,8 @@ export function constructWithAmbientResolution(container, resolution, target, de
|
|
|
53
48
|
}
|
|
54
49
|
}
|
|
55
50
|
/**
|
|
51
|
+
* Returns the ambient container for the construction in flight, if one is installed.
|
|
52
|
+
*
|
|
56
53
|
* @since 0.10.0
|
|
57
54
|
*/
|
|
58
55
|
export function getActiveContainer() {
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
* binding in the process shares one hidden class; the return type of each step is what pins the
|
|
7
7
|
* chain's order, so no runtime check has to.
|
|
8
8
|
*/
|
|
9
|
-
import type { AliasBindingBuilder, BindingBuilder, BindingSlot, BindToBuilder, ConstantBindingBuilder, ScopedBindingBuilder, SingletonBindingBuilder, SingletonLifecycleBuilder, TransientBindingBuilder } from "
|
|
10
|
-
import type { BindingRegistry } from "
|
|
11
|
-
import type { BindingTag } from "
|
|
12
|
-
import type { Token } from "
|
|
13
|
-
import type { ActivationHandler, BindingConstraint, BindingIdentifier, BindingKind, BindingScope, Constructor, DeactivationHandler, ResolutionContext, ResolutionFrame } from "
|
|
14
|
-
import type { InjectableDependency, InjectionDescriptor, ResolvedDependencyValue } from "
|
|
15
|
-
import type { ScopeManager } from "
|
|
9
|
+
import type { AliasBindingBuilder, BindingBuilder, BindingSlot, BindToBuilder, ConstantBindingBuilder, ScopedBindingBuilder, SingletonBindingBuilder, SingletonLifecycleBuilder, TransientBindingBuilder } from "#core/binding";
|
|
10
|
+
import type { BindingRegistry } from "#core/registry";
|
|
11
|
+
import type { BindingTag } from "#core/tag";
|
|
12
|
+
import type { Token } from "#core/token";
|
|
13
|
+
import type { ActivationHandler, BindingConstraint, BindingIdentifier, BindingKind, BindingScope, Constructor, DeactivationHandler, ResolutionContext, ResolutionFrame } from "#core/types";
|
|
14
|
+
import type { InjectableDependency, InjectionDescriptor, ResolvedDependencyValue } from "#injection/descriptor";
|
|
15
|
+
import type { ScopeManager } from "#lifecycle/scope-manager";
|
|
16
16
|
/**
|
|
17
17
|
* Where a chain registers, and on whose behalf.
|
|
18
18
|
*
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { clearBindingFrame, createBindingSlot, DEFAULT_BINDING_SLOT, generateBindingId, NO_INSTANCE, } from "
|
|
2
|
-
import { mergingConstraintRequirements } from "
|
|
3
|
-
import { slotName } from "
|
|
4
|
-
import { tokenName } from "
|
|
5
|
-
import { ChainAlreadyRegisteredError, ChainNotRegisteredError, ManyBindingSlotError, SelfBindingRequiresClassError, } from "
|
|
6
|
-
import { normalizeToDescriptor } from "
|
|
1
|
+
import { clearBindingFrame, createBindingSlot, DEFAULT_BINDING_SLOT, generateBindingId, NO_INSTANCE, } from "#core/binding";
|
|
2
|
+
import { mergingConstraintRequirements } from "#core/constraint-requirement";
|
|
3
|
+
import { slotName } from "#core/tag";
|
|
4
|
+
import { tokenName } from "#core/token";
|
|
5
|
+
import { ChainAlreadyRegisteredError, ChainNotRegisteredError, ManyBindingSlotError, SelfBindingRequiresClassError, } from "#errors/errors";
|
|
6
|
+
import { normalizeToDescriptor } from "#injection/descriptor";
|
|
7
7
|
/** One criterion per key: re-tagging the same key replaces it rather than asking for both values. */
|
|
8
8
|
function updateSlotTag(slot, criterion) {
|
|
9
9
|
const tags = [...slot.tags];
|
|
@@ -126,6 +126,24 @@ export class BindingChain {
|
|
|
126
126
|
return this.#register("alias", "transient");
|
|
127
127
|
}
|
|
128
128
|
// ── Refinement ─────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
129
|
+
/**
|
|
130
|
+
* Whether this chain provably still owns the registry's last write with nothing parked.
|
|
131
|
+
*
|
|
132
|
+
* @remarks When it does, a refinement rewrites the live binding in place; otherwise `#reslot`
|
|
133
|
+
* re-checks liveness and restores what the new shape frees.
|
|
134
|
+
*/
|
|
135
|
+
get #isProvablyLive() {
|
|
136
|
+
return this.#registration.registry.version === this.#versionAfterLastWrite && this.#displacedByChain === undefined;
|
|
137
|
+
}
|
|
138
|
+
/** Stamps this chain's last-write version after a mutation it made in place. */
|
|
139
|
+
#recordWrite() {
|
|
140
|
+
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
141
|
+
}
|
|
142
|
+
/** Bumps the registry for an index-neutral mutation (scope, hook) and records this chain's write. */
|
|
143
|
+
#touchAndRecordWrite() {
|
|
144
|
+
this.#registration.registry.touch();
|
|
145
|
+
this.#recordWrite();
|
|
146
|
+
}
|
|
129
147
|
// Slot and predicate are what the registry indexes on, so a re-slot takes the binding out of the
|
|
130
148
|
// registry, rewrites the two fields while it is out, and registers it again — same object, same id.
|
|
131
149
|
#reslot(slot, predicate) {
|
|
@@ -149,8 +167,7 @@ export class BindingChain {
|
|
|
149
167
|
}
|
|
150
168
|
// The frame reports the scope, so a resolve before this call memoized the previous one.
|
|
151
169
|
clearBindingFrame(this.#binding);
|
|
152
|
-
this.#
|
|
153
|
-
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
170
|
+
this.#touchAndRecordWrite();
|
|
154
171
|
return this;
|
|
155
172
|
}
|
|
156
173
|
// SPEC calls a candidate a binding that passes *all* of a chain's predicates, and the chain type
|
|
@@ -162,13 +179,10 @@ export class BindingChain {
|
|
|
162
179
|
const narrowed = previous === undefined
|
|
163
180
|
? predicate
|
|
164
181
|
: mergingConstraintRequirements((ctx) => previous(ctx) && predicate(ctx), previous, predicate);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (registry.version === this.#versionAfterLastWrite && this.#displacedByChain === undefined) {
|
|
170
|
-
registry.setPredicate(this.#binding, narrowed);
|
|
171
|
-
this.#versionAfterLastWrite = registry.version;
|
|
182
|
+
// The slot is unchanged, so a provably-live binding just takes the predicate in place.
|
|
183
|
+
if (this.#isProvablyLive) {
|
|
184
|
+
this.#registration.registry.setPredicate(this.#binding, narrowed);
|
|
185
|
+
this.#recordWrite();
|
|
172
186
|
return this;
|
|
173
187
|
}
|
|
174
188
|
return this.#reslot(this.slot, narrowed);
|
|
@@ -191,14 +205,11 @@ export class BindingChain {
|
|
|
191
205
|
if (this.isMany) {
|
|
192
206
|
return this;
|
|
193
207
|
}
|
|
194
|
-
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (registry.version === this.#versionAfterLastWrite && this.#displacedByChain === undefined) {
|
|
200
|
-
registry.setMany(this.#binding);
|
|
201
|
-
this.#versionAfterLastWrite = registry.version;
|
|
208
|
+
// A provably-live binding takes membership in place; the registry only moves it out of the lone
|
|
209
|
+
// map. Otherwise `#commit` re-checks liveness and restores what the freed slot lets back in.
|
|
210
|
+
if (this.#isProvablyLive) {
|
|
211
|
+
this.#registration.registry.setMany(this.#binding);
|
|
212
|
+
this.#recordWrite();
|
|
202
213
|
return this;
|
|
203
214
|
}
|
|
204
215
|
this.#commit(() => {
|
|
@@ -224,15 +235,13 @@ export class BindingChain {
|
|
|
224
235
|
onActivation(fn) {
|
|
225
236
|
this.#requireRegistered();
|
|
226
237
|
this.activationHook = fn;
|
|
227
|
-
this.#
|
|
228
|
-
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
238
|
+
this.#touchAndRecordWrite();
|
|
229
239
|
return this;
|
|
230
240
|
}
|
|
231
241
|
onDeactivation(fn) {
|
|
232
242
|
this.#requireRegistered();
|
|
233
243
|
this.deactivationHook = fn;
|
|
234
|
-
this.#
|
|
235
|
-
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
244
|
+
this.#touchAndRecordWrite();
|
|
236
245
|
return this;
|
|
237
246
|
}
|
|
238
247
|
id() {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { BindToBuilder } from "
|
|
2
|
-
import type { AsyncModule, SyncModule } from "
|
|
3
|
-
import type { Token } from "
|
|
4
|
-
import type { ActivationHandler, BindingIdentifier, Constructor, DeactivationHandler, ResolveOptions } from "
|
|
5
|
-
import type { AutoRegisterRegistry } from "
|
|
6
|
-
import type { ContainerGraphJson, GraphOptions } from "
|
|
7
|
-
import type { BindingSnapshot, ContainerSnapshot } from "
|
|
8
|
-
import type { MetadataReader } from "
|
|
1
|
+
import type { BindToBuilder } from "#core/binding";
|
|
2
|
+
import type { AsyncModule, SyncModule } from "#core/module";
|
|
3
|
+
import type { Token } from "#core/token";
|
|
4
|
+
import type { ActivationHandler, BindingIdentifier, Constructor, DeactivationHandler, ResolveOptions } from "#core/types";
|
|
5
|
+
import type { AutoRegisterRegistry } from "#decorators/injectable";
|
|
6
|
+
import type { ContainerGraphJson, GraphOptions } from "#introspection/dependency-graph";
|
|
7
|
+
import type { BindingSnapshot, ContainerSnapshot } from "#introspection/inspector";
|
|
8
|
+
import type { MetadataReader } from "#metadata/metadata-types";
|
|
9
9
|
/**
|
|
10
10
|
* The public surface: binding, resolving, modules, lifecycle hooks, child scopes, and disposal.
|
|
11
11
|
*
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { BindingChain } from "
|
|
2
|
-
import { NO_INSTANCE } from "
|
|
3
|
-
import { effectiveBindingScope } from "
|
|
4
|
-
import { constraintRequirementsOf } from "
|
|
5
|
-
import { getOrInsert, getOrInsertComputed } from "
|
|
6
|
-
import { isSyncModule, MODULE_SETUP } from "
|
|
7
|
-
import { BindingRegistry } from "
|
|
8
|
-
import { tokenName } from "
|
|
9
|
-
import { RESOLUTION_DIAGNOSTICS } from "
|
|
10
|
-
import { AsyncModuleLoadError, CircularDependencyError, DisposedContainerError, InternalError, RebindUnboundTokenError, ScopeViolationError, SyncDisposalNotSupportedError, UnreachableConstraintError, UnreachableLifecycleHookError, } from "
|
|
11
|
-
import { injectionSlotToResolveOptions, bindingSlotToResolveOptions } from "
|
|
12
|
-
import { buildDependencyGraph } from "
|
|
13
|
-
import { Inspector } from "
|
|
14
|
-
import { LifecycleManager } from "
|
|
15
|
-
import { ScopeManager } from "
|
|
16
|
-
import { MetadataReaderToken } from "
|
|
17
|
-
import { defaultMetadataReader } from "
|
|
18
|
-
import { verifyingMetadataReader } from "
|
|
19
|
-
import { ROOT_BRANCH } from "
|
|
20
|
-
import { DependencyResolver } from "
|
|
1
|
+
import { BindingChain } from "#container/binding-builders";
|
|
2
|
+
import { NO_INSTANCE } from "#core/binding";
|
|
3
|
+
import { effectiveBindingScope } from "#core/binding-scope";
|
|
4
|
+
import { constraintRequirementsOf } from "#core/constraint-requirement";
|
|
5
|
+
import { getOrInsert, getOrInsertComputed } from "#core/map-upsert";
|
|
6
|
+
import { isSyncModule, MODULE_SETUP } from "#core/module";
|
|
7
|
+
import { BindingRegistry } from "#core/registry";
|
|
8
|
+
import { tokenName } from "#core/token";
|
|
9
|
+
import { RESOLUTION_DIAGNOSTICS } from "#errors/diagnostics";
|
|
10
|
+
import { AsyncModuleLoadError, CircularDependencyError, DisposedContainerError, InternalError, RebindUnboundTokenError, ScopeViolationError, SyncDisposalNotSupportedError, UnreachableConstraintError, UnreachableLifecycleHookError, } from "#errors/errors";
|
|
11
|
+
import { injectionSlotToResolveOptions, bindingSlotToResolveOptions } from "#injection/resolve-options";
|
|
12
|
+
import { buildDependencyGraph } from "#introspection/dependency-graph";
|
|
13
|
+
import { Inspector } from "#introspection/inspector";
|
|
14
|
+
import { LifecycleManager } from "#lifecycle/lifecycle-manager";
|
|
15
|
+
import { ScopeManager } from "#lifecycle/scope-manager";
|
|
16
|
+
import { MetadataReaderToken } from "#metadata/metadata-reader-token";
|
|
17
|
+
import { defaultMetadataReader } from "#metadata/symbol-metadata-reader";
|
|
18
|
+
import { verifyingMetadataReader } from "#metadata/verifying-metadata-reader";
|
|
19
|
+
import { ROOT_BRANCH } from "#resolution/path/resolution-path";
|
|
20
|
+
import { DependencyResolver } from "#resolution/resolver";
|
|
21
21
|
/** Whether a requirement's name is declared — on its token when it names one, on any token otherwise. */
|
|
22
22
|
function isSlotNameDeclared(declared, requirement) {
|
|
23
23
|
if (requirement.tokenName !== undefined) {
|
package/dist/core/binding.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { BindingTag, TagKeyMask } from "
|
|
2
|
-
import type { Token } from "
|
|
3
|
-
import type { ActivationHandler, BindingIdentifier, BindingScope, Constructor, DeactivationHandler, ResolutionContext, ResolutionFrame, BindingConstraint } from "
|
|
4
|
-
import type { InjectableDependency, InjectionDescriptor, ResolvedDependencyValue } from "
|
|
1
|
+
import type { BindingTag, TagKeyMask } from "#core/tag";
|
|
2
|
+
import type { Token } from "#core/token";
|
|
3
|
+
import type { ActivationHandler, BindingIdentifier, BindingScope, Constructor, DeactivationHandler, ResolutionContext, ResolutionFrame, BindingConstraint } from "#core/types";
|
|
4
|
+
import type { InjectableDependency, InjectionDescriptor, ResolvedDependencyValue } from "#injection/descriptor";
|
|
5
5
|
/**
|
|
6
6
|
* The criterion set a binding registers under and a request matches against.
|
|
7
7
|
*
|
|
@@ -61,8 +61,8 @@ interface BindingBase<Value> {
|
|
|
61
61
|
*
|
|
62
62
|
* @remarks Both cycle guards that can use an `O(1)` flag read this — the sync transient-dynamic
|
|
63
63
|
* lane and the async cascade lane — because synchronous code does not interleave, so the flag *is*
|
|
64
|
-
* exact path membership. Not optional:
|
|
65
|
-
* absent is a field that can cost the shared hidden class. Resolver-owned; callers never set it.
|
|
64
|
+
* exact path membership. Not optional: the binding builder always initializes it, and a field that
|
|
65
|
+
* may be absent is a field that can cost the shared hidden class. Resolver-owned; callers never set it.
|
|
66
66
|
*/
|
|
67
67
|
inFlight: boolean;
|
|
68
68
|
/**
|
package/dist/core/binding.js
CHANGED
package/dist/core/module.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { BindToBuilder } from "
|
|
2
|
-
import type { Token } from "
|
|
3
|
-
import type { Constructor } from "
|
|
1
|
+
import type { BindToBuilder } from "#core/binding";
|
|
2
|
+
import type { Token } from "#core/token";
|
|
3
|
+
import type { Constructor } from "#core/types";
|
|
4
4
|
declare const SYNC_MODULE_BRAND: unique symbol;
|
|
5
5
|
declare const ASYNC_MODULE_BRAND: unique symbol;
|
|
6
6
|
/**
|
package/dist/core/registry.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Binding } from "
|
|
2
|
-
import type { BindingTag } from "
|
|
3
|
-
import type { Token } from "
|
|
4
|
-
import type { BindingConstraint, BindingIdentifier, Constructor } from "
|
|
1
|
+
import type { Binding } from "#core/binding";
|
|
2
|
+
import type { BindingTag } from "#core/tag";
|
|
3
|
+
import type { Token } from "#core/token";
|
|
4
|
+
import type { BindingConstraint, BindingIdentifier, Constructor } from "#core/types";
|
|
5
5
|
/**
|
|
6
6
|
* One container's binding store, indexed by token, binding id, and slot for fast lookup.
|
|
7
7
|
*
|
|
@@ -27,8 +27,8 @@ export declare class BindingRegistry {
|
|
|
27
27
|
/**
|
|
28
28
|
* Adds or replaces a binding using slot-aware last-wins. Returns the displaced binding, if any.
|
|
29
29
|
*
|
|
30
|
-
* @remarks The binding is stored by reference — it must come from
|
|
31
|
-
* what guarantees the single hidden class the resolver's hot reads depend on.
|
|
30
|
+
* @remarks The binding is stored by reference — it must come from the one binding builder, which
|
|
31
|
+
* is what guarantees the single hidden class the resolver's hot reads depend on.
|
|
32
32
|
*/
|
|
33
33
|
add(binding: Binding): Binding | undefined;
|
|
34
34
|
/** Remove all bindings for a token. Returns removed bindings. */
|
package/dist/core/registry.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { bindingSlotEquals, bindingSlotToString, writableMembership, writablePredicate } from "
|
|
2
|
-
import { getOrInsert } from "
|
|
3
|
-
import { advanceStateEpoch } from "
|
|
1
|
+
import { bindingSlotEquals, bindingSlotToString, writableMembership, writablePredicate } from "#core/binding";
|
|
2
|
+
import { getOrInsert } from "#core/map-upsert";
|
|
3
|
+
import { advanceStateEpoch } from "#core/state-epoch";
|
|
4
4
|
const NO_BINDINGS = Object.freeze([]);
|
|
5
5
|
/** One construction site, so every record shares a hidden class. */
|
|
6
6
|
function createTokenRecord(bindings) {
|
|
@@ -69,8 +69,8 @@ export class BindingRegistry {
|
|
|
69
69
|
/**
|
|
70
70
|
* Adds or replaces a binding using slot-aware last-wins. Returns the displaced binding, if any.
|
|
71
71
|
*
|
|
72
|
-
* @remarks The binding is stored by reference — it must come from
|
|
73
|
-
* what guarantees the single hidden class the resolver's hot reads depend on.
|
|
72
|
+
* @remarks The binding is stored by reference — it must come from the one binding builder, which
|
|
73
|
+
* is what guarantees the single hidden class the resolver's hot reads depend on.
|
|
74
74
|
*/
|
|
75
75
|
add(binding) {
|
|
76
76
|
this.#bump();
|
|
@@ -299,19 +299,14 @@ export class BindingRegistry {
|
|
|
299
299
|
*/
|
|
300
300
|
setMany(binding) {
|
|
301
301
|
this.#bump();
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
this.#lone.delete(key);
|
|
306
|
-
this.#createRecord(key, [binding]);
|
|
302
|
+
// Set before any (re)indexing so `#indexSlot` sees a member and leaves it out of every slot.
|
|
303
|
+
writableMembership(binding).isMany = true;
|
|
304
|
+
if (this.#promoteLoneToRecord(binding.token, binding)) {
|
|
307
305
|
return;
|
|
308
306
|
}
|
|
309
|
-
// A default occupant that becomes a member frees its slot, so drop the stale index entry.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
record.defaultOccupant = undefined;
|
|
313
|
-
}
|
|
314
|
-
writableMembership(binding).isMany = true;
|
|
307
|
+
// A default occupant that becomes a member frees its slot, so drop the stale index entry. A
|
|
308
|
+
// member cannot collapse a record back to lone, so this path does not settle.
|
|
309
|
+
this.#clearDefaultOccupant(binding.token, binding);
|
|
315
310
|
}
|
|
316
311
|
/**
|
|
317
312
|
* Adds a predicate to a live binding in place.
|
|
@@ -322,21 +317,38 @@ export class BindingRegistry {
|
|
|
322
317
|
*/
|
|
323
318
|
setPredicate(binding, predicate) {
|
|
324
319
|
this.#bump();
|
|
320
|
+
// Set before any (re)indexing: a predicate-only binding holds no default slot.
|
|
325
321
|
writablePredicate(binding).predicate = predicate;
|
|
326
|
-
|
|
327
|
-
if (this.#lone.get(key) === binding) {
|
|
328
|
-
this.#lone.delete(key);
|
|
329
|
-
this.#createRecord(key, [binding]);
|
|
322
|
+
if (this.#promoteLoneToRecord(binding.token, binding)) {
|
|
330
323
|
return;
|
|
331
324
|
}
|
|
325
|
+
// The binding may have vacated the default slot, and a narrowed record can collapse back to lone.
|
|
326
|
+
const record = this.#clearDefaultOccupant(binding.token, binding);
|
|
327
|
+
if (record !== undefined) {
|
|
328
|
+
this.#settle(binding.token, record);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Moves a binding still holding the lone seat into a fresh one-binding record, returning whether it did.
|
|
333
|
+
*
|
|
334
|
+
* @remarks Its field (`isMany` or `predicate`) is written before this call, so the founding
|
|
335
|
+
* `#indexSlot` files it under the slot it now holds.
|
|
336
|
+
*/
|
|
337
|
+
#promoteLoneToRecord(key, binding) {
|
|
338
|
+
if (this.#lone.get(key) !== binding) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
this.#lone.delete(key);
|
|
342
|
+
this.#createRecord(key, [binding]);
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
/** Clears the default-slot index entry a binding has vacated, returning its record if one exists. */
|
|
346
|
+
#clearDefaultOccupant(key, binding) {
|
|
332
347
|
const record = this.#records?.get(key);
|
|
333
|
-
// The binding is now predicate-only, so it no longer holds the default slot it may have held.
|
|
334
348
|
if (record?.defaultOccupant === binding) {
|
|
335
349
|
record.defaultOccupant = undefined;
|
|
336
350
|
}
|
|
337
|
-
|
|
338
|
-
this.#settle(key, record);
|
|
339
|
-
}
|
|
351
|
+
return record;
|
|
340
352
|
}
|
|
341
353
|
/** Summarize available slot strings for a token (for error messages). */
|
|
342
354
|
availableSlotStrings(token) {
|
package/dist/core/token.d.ts
CHANGED
package/dist/core/types.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Constructor } from "
|
|
2
|
-
import type { BindingTag, TagKeyMask } from "
|
|
3
|
-
import type { Token } from "
|
|
4
|
-
export type { Constructor } from "
|
|
5
|
-
export type { BindingTag, TagKey, TagKeyMask } from "
|
|
1
|
+
import type { Constructor } from "#core/constructor-type";
|
|
2
|
+
import type { BindingTag, TagKeyMask } from "#core/tag";
|
|
3
|
+
import type { Token } from "#core/token";
|
|
4
|
+
export type { Constructor } from "#core/constructor-type";
|
|
5
|
+
export type { BindingTag, TagKey, TagKeyMask } from "#core/tag";
|
|
6
6
|
/**
|
|
7
7
|
* Token or class constructor used as a binding / injection / resolve key.
|
|
8
8
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** `@inject` — the accessor-decorator channel, resolving from the ambient container. */
|
|
2
|
-
import type { Token } from "
|
|
3
|
-
import type { Constructor } from "
|
|
4
|
-
import type { InjectionDescriptor, InjectOptions } from "
|
|
2
|
+
import type { Token } from "#core/token";
|
|
3
|
+
import type { Constructor } from "#core/types";
|
|
4
|
+
import type { InjectionDescriptor, InjectOptions } from "#injection/descriptor";
|
|
5
5
|
type ClassAccessorDecorator<This, Value> = (target: ClassAccessorDecoratorTarget<This, Value>, context: ClassAccessorDecoratorContext<This, Value>) => ClassAccessorDecoratorResult<This, Value> | void;
|
|
6
6
|
/**
|
|
7
7
|
* Creates a dual-role value: an injection descriptor that also works as a class accessor decorator.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { getActiveContainer, getAmbientResolution } from "
|
|
2
|
-
import { MissingContainerContextError, StaticMemberDecoratorError } from "
|
|
3
|
-
import { buildInjectionDescriptor } from "
|
|
4
|
-
import { injectionSlotToResolveOptions } from "
|
|
5
|
-
import { INJECT_ACCESSOR_KEY } from "
|
|
1
|
+
import { getActiveContainer, getAmbientResolution } from "#ambient/active-container";
|
|
2
|
+
import { MissingContainerContextError, StaticMemberDecoratorError } from "#errors/errors";
|
|
3
|
+
import { buildInjectionDescriptor } from "#injection/descriptor";
|
|
4
|
+
import { injectionSlotToResolveOptions } from "#injection/resolve-options";
|
|
5
|
+
import { INJECT_ACCESSOR_KEY } from "#metadata/metadata-keys";
|
|
6
6
|
/**
|
|
7
7
|
* The name of the class being constructed, or `undefined` when there is none to report.
|
|
8
8
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { BindingScope, Constructor } from "
|
|
2
|
-
import type { InjectableDependency, ResolvedDependencyValue } from "
|
|
1
|
+
import type { BindingScope, Constructor } from "#core/types";
|
|
2
|
+
import type { InjectableDependency, ResolvedDependencyValue } from "#injection/descriptor";
|
|
3
3
|
/**
|
|
4
4
|
* The collector `@injectable` registers a class into, for a container to bind later.
|
|
5
5
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { normalizeToDescriptor } from "
|
|
2
|
-
import { INJECTABLE_KEY } from "
|
|
1
|
+
import { normalizeToDescriptor } from "#injection/descriptor";
|
|
2
|
+
import { INJECTABLE_KEY } from "#metadata/metadata-keys";
|
|
3
3
|
/**
|
|
4
4
|
* Creates an empty auto-register registry.
|
|
5
5
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { StaticMemberDecoratorError } from "
|
|
2
|
-
import { LIFECYCLE_KEY } from "
|
|
1
|
+
import { StaticMemberDecoratorError } from "#errors/errors";
|
|
2
|
+
import { LIFECYCLE_KEY } from "#metadata/metadata-keys";
|
|
3
3
|
/** Records the decorated method under one lifecycle phase; both decorators differ only in that phase. */
|
|
4
4
|
function recordLifecycleMethod(phase) {
|
|
5
5
|
return function (target, context) {
|
package/dist/errors/errors.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ConstraintRequirement } from "
|
|
2
|
-
import type { BindingIdentifier, BindingScope, ResolveOptions } from "
|
|
1
|
+
import type { ConstraintRequirement } from "#core/constraint-requirement";
|
|
2
|
+
import type { BindingIdentifier, BindingScope, ResolveOptions } from "#core/types";
|
|
3
3
|
/**
|
|
4
4
|
* Base class for every error the library throws, each carrying a machine-readable `code`.
|
|
5
5
|
*
|
|
@@ -223,15 +223,6 @@ export declare class MissingContainerContextError extends DiError {
|
|
|
223
223
|
readonly accessorName: string | symbol;
|
|
224
224
|
constructor(className: string | undefined, accessorName: string | symbol);
|
|
225
225
|
}
|
|
226
|
-
/**
|
|
227
|
-
* A fluent chain was refined before a `to*()` call gave it a binding to refine.
|
|
228
|
-
*
|
|
229
|
-
* @remarks The builder types make this unreachable from TypeScript — `bind()` returns
|
|
230
|
-
* `BindToBuilder`, which exposes only `to*()`. It exists for JavaScript callers and for anyone who
|
|
231
|
-
* casts past the types, so the misuse fails loudly instead of mutating nothing.
|
|
232
|
-
*
|
|
233
|
-
* @since 0.5.0-canary.8
|
|
234
|
-
*/
|
|
235
226
|
/**
|
|
236
227
|
* A second `to*()` on a chain that already registered its binding.
|
|
237
228
|
*
|
|
@@ -259,6 +250,12 @@ export declare class ManyBindingSlotError extends DiError {
|
|
|
259
250
|
constructor(tokenName: string);
|
|
260
251
|
}
|
|
261
252
|
/**
|
|
253
|
+
* A fluent chain was refined before a `to*()` call gave it a binding to refine.
|
|
254
|
+
*
|
|
255
|
+
* @remarks The builder types make this unreachable from TypeScript — `bind()` returns
|
|
256
|
+
* `BindToBuilder`, which exposes only `to*()`. It exists for JavaScript callers and for anyone who
|
|
257
|
+
* casts past the types, so the misuse fails loudly instead of mutating nothing.
|
|
258
|
+
*
|
|
262
259
|
* @since 0.10.0
|
|
263
260
|
*/
|
|
264
261
|
export declare class ChainNotRegisteredError extends DiError {
|