@codefast/di 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +615 -0
- package/README.md +119 -30
- package/dist/ambient/active-container.d.ts +37 -0
- package/dist/ambient/active-container.d.ts.map +1 -0
- package/dist/ambient/active-container.js +41 -0
- package/dist/ambient/active-container.js.map +1 -0
- package/dist/container/binding-builders.d.ts +12 -8
- package/dist/container/binding-builders.d.ts.map +1 -1
- package/dist/container/binding-builders.js +56 -31
- package/dist/container/binding-builders.js.map +1 -1
- package/dist/container/container.d.ts +33 -19
- package/dist/container/container.d.ts.map +1 -1
- package/dist/container/container.js +279 -118
- package/dist/container/container.js.map +1 -1
- package/dist/{resolution → core}/binding-scope.d.ts +2 -2
- package/dist/core/binding-scope.d.ts.map +1 -0
- package/dist/core/binding-scope.js.map +1 -0
- package/dist/{binding.d.ts → core/binding.d.ts} +70 -15
- package/dist/core/binding.d.ts.map +1 -0
- package/dist/{binding.js → core/binding.js} +27 -12
- package/dist/core/binding.js.map +1 -0
- package/dist/core/constraint-requirement.d.ts +38 -0
- package/dist/core/constraint-requirement.d.ts.map +1 -0
- package/dist/core/constraint-requirement.js +28 -0
- package/dist/core/constraint-requirement.js.map +1 -0
- package/dist/{constructor-type.d.ts → core/constructor-type.d.ts} +1 -1
- package/dist/core/constructor-type.d.ts.map +1 -0
- package/dist/core/constructor-type.js.map +1 -0
- package/dist/{module.d.ts → core/module.d.ts} +5 -5
- package/dist/core/module.d.ts.map +1 -0
- package/dist/{module.js → core/module.js} +4 -4
- package/dist/core/module.js.map +1 -0
- package/dist/{registry.d.ts → core/registry.d.ts} +27 -7
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/{registry.js → core/registry.js} +125 -52
- package/dist/core/registry.js.map +1 -0
- package/dist/core/tag.d.ts +80 -0
- package/dist/core/tag.d.ts.map +1 -0
- package/dist/core/tag.js +84 -0
- package/dist/core/tag.js.map +1 -0
- package/dist/{token.d.ts → core/token.d.ts} +2 -6
- package/dist/core/token.d.ts.map +1 -0
- package/dist/core/token.js +13 -0
- package/dist/core/token.js.map +1 -0
- package/dist/{types.d.ts → core/types.d.ts} +27 -21
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js.map +1 -0
- package/dist/decorators/inject.d.ts +5 -49
- package/dist/decorators/inject.d.ts.map +1 -1
- package/dist/decorators/inject.js +34 -104
- package/dist/decorators/inject.js.map +1 -1
- package/dist/decorators/injectable.d.ts +25 -5
- package/dist/decorators/injectable.d.ts.map +1 -1
- package/dist/decorators/injectable.js +2 -3
- package/dist/decorators/injectable.js.map +1 -1
- package/dist/decorators/lifecycle-decorators.d.ts +4 -2
- package/dist/decorators/lifecycle-decorators.d.ts.map +1 -1
- package/dist/decorators/lifecycle-decorators.js +19 -25
- package/dist/decorators/lifecycle-decorators.js.map +1 -1
- package/dist/{resolution → errors}/diagnostics.d.ts +2 -0
- package/dist/errors/diagnostics.d.ts.map +1 -0
- package/dist/errors/diagnostics.js.map +1 -0
- package/dist/{errors.d.ts → errors/errors.d.ts} +89 -4
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/{errors.js → errors/errors.js} +129 -7
- package/dist/errors/errors.js.map +1 -0
- package/dist/index.d.ts +21 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/injection/descriptor.d.ts +79 -0
- package/dist/injection/descriptor.d.ts.map +1 -0
- package/dist/injection/descriptor.js +118 -0
- package/dist/injection/descriptor.js.map +1 -0
- package/dist/{resolution → injection}/resolve-options.d.ts +21 -11
- package/dist/injection/resolve-options.d.ts.map +1 -0
- package/dist/injection/resolve-options.js +101 -0
- package/dist/injection/resolve-options.js.map +1 -0
- package/dist/introspection/dependency-graph.d.ts +16 -5
- package/dist/introspection/dependency-graph.d.ts.map +1 -1
- package/dist/introspection/dependency-graph.js +138 -57
- package/dist/introspection/dependency-graph.js.map +1 -1
- package/dist/introspection/graph-adapters/cytoscape.d.ts +6 -3
- package/dist/introspection/graph-adapters/cytoscape.d.ts.map +1 -1
- package/dist/introspection/graph-adapters/cytoscape.js +3 -0
- package/dist/introspection/graph-adapters/cytoscape.js.map +1 -1
- package/dist/introspection/graph-adapters/dot.d.ts.map +1 -1
- package/dist/introspection/graph-adapters/dot.js +12 -5
- package/dist/introspection/graph-adapters/dot.js.map +1 -1
- package/dist/introspection/graph-adapters/mermaid.d.ts +9 -0
- package/dist/introspection/graph-adapters/mermaid.d.ts.map +1 -0
- package/dist/introspection/graph-adapters/mermaid.js +47 -0
- package/dist/introspection/graph-adapters/mermaid.js.map +1 -0
- package/dist/introspection/graph-adapters/reactflow.d.ts +6 -3
- package/dist/introspection/graph-adapters/reactflow.d.ts.map +1 -1
- package/dist/introspection/graph-adapters/reactflow.js +5 -1
- package/dist/introspection/graph-adapters/reactflow.js.map +1 -1
- package/dist/introspection/inspector.d.ts +4 -4
- package/dist/introspection/inspector.d.ts.map +1 -1
- package/dist/introspection/inspector.js +10 -6
- package/dist/introspection/inspector.js.map +1 -1
- package/dist/lifecycle/lifecycle-manager.d.ts +27 -0
- package/dist/lifecycle/lifecycle-manager.d.ts.map +1 -0
- package/dist/{resolution/lifecycle.js → lifecycle/lifecycle-manager.js} +39 -9
- package/dist/lifecycle/lifecycle-manager.js.map +1 -0
- package/dist/lifecycle/scope-manager.d.ts +48 -0
- package/dist/lifecycle/scope-manager.d.ts.map +1 -0
- package/dist/lifecycle/scope-manager.js +135 -0
- package/dist/lifecycle/scope-manager.js.map +1 -0
- package/dist/metadata/metadata-reader-token.d.ts +1 -1
- package/dist/metadata/metadata-reader-token.d.ts.map +1 -1
- package/dist/metadata/metadata-reader-token.js +1 -1
- package/dist/metadata/metadata-reader-token.js.map +1 -1
- package/dist/metadata/metadata-types.d.ts +9 -9
- package/dist/metadata/metadata-types.d.ts.map +1 -1
- package/dist/metadata/symbol-metadata-reader.d.ts +19 -6
- package/dist/metadata/symbol-metadata-reader.d.ts.map +1 -1
- package/dist/metadata/symbol-metadata-reader.js +89 -9
- package/dist/metadata/symbol-metadata-reader.js.map +1 -1
- package/dist/metadata/verifying-metadata-reader.d.ts +16 -0
- package/dist/metadata/verifying-metadata-reader.d.ts.map +1 -0
- package/dist/metadata/verifying-metadata-reader.js +32 -0
- package/dist/metadata/verifying-metadata-reader.js.map +1 -0
- package/dist/resolution/{activation-need.d.ts → cache/activation-need.d.ts} +5 -5
- package/dist/resolution/cache/activation-need.d.ts.map +1 -0
- package/dist/resolution/cache/activation-need.js.map +1 -0
- package/dist/resolution/{binding-lookup-cache.d.ts → cache/binding-lookup-cache.d.ts} +6 -5
- package/dist/resolution/cache/binding-lookup-cache.d.ts.map +1 -0
- package/dist/resolution/cache/binding-lookup-cache.js.map +1 -0
- package/dist/resolution/cache/class-introspector.d.ts +66 -0
- package/dist/resolution/cache/class-introspector.d.ts.map +1 -0
- package/dist/resolution/cache/class-introspector.js +194 -0
- package/dist/resolution/cache/class-introspector.js.map +1 -0
- package/dist/resolution/context.d.ts +84 -0
- package/dist/resolution/context.d.ts.map +1 -0
- package/dist/resolution/{environment.js → context.js} +54 -80
- package/dist/resolution/context.js.map +1 -0
- package/dist/resolution/path/resolution-path.d.ts +94 -0
- package/dist/resolution/path/resolution-path.d.ts.map +1 -0
- package/dist/resolution/path/resolution-path.js +117 -0
- package/dist/resolution/path/resolution-path.js.map +1 -0
- package/dist/resolution/{instantiation-plan.d.ts → plan/instantiation-plan.d.ts} +30 -7
- package/dist/resolution/plan/instantiation-plan.d.ts.map +1 -0
- package/dist/resolution/plan/instantiation-plan.js +390 -0
- package/dist/resolution/plan/instantiation-plan.js.map +1 -0
- package/dist/resolution/resolver.d.ts +28 -28
- package/dist/resolution/resolver.d.ts.map +1 -1
- package/dist/resolution/resolver.js +552 -239
- package/dist/resolution/resolver.js.map +1 -1
- package/dist/resolution/select/binding-select.d.ts +34 -0
- package/dist/resolution/select/binding-select.d.ts.map +1 -0
- package/dist/resolution/select/binding-select.js +175 -0
- package/dist/resolution/select/binding-select.js.map +1 -0
- package/dist/resolution/{constraints.d.ts → select/constraints.d.ts} +13 -12
- package/dist/resolution/select/constraints.d.ts.map +1 -0
- package/dist/resolution/{constraints.js → select/constraints.js} +33 -22
- package/dist/resolution/select/constraints.js.map +1 -0
- package/package.json +160 -20
- package/src/ambient/active-container.ts +65 -0
- package/src/container/binding-builders.ts +72 -44
- package/src/container/container.ts +355 -170
- package/src/{resolution → core}/binding-scope.ts +2 -2
- package/src/{binding.ts → core/binding.ts} +101 -39
- package/src/core/constraint-requirement.ts +51 -0
- package/src/{constructor-type.ts → core/constructor-type.ts} +1 -1
- package/src/{module.ts → core/module.ts} +10 -10
- package/src/core/registry.ts +365 -0
- package/src/core/tag.ts +144 -0
- package/src/{token.ts → core/token.ts} +2 -14
- package/src/{types.ts → core/types.ts} +37 -34
- package/src/decorators/inject.ts +39 -175
- package/src/decorators/injectable.ts +40 -10
- package/src/decorators/lifecycle-decorators.ts +22 -34
- package/src/{resolution → errors}/diagnostics.ts +2 -0
- package/src/{errors.ts → errors/errors.ts} +152 -8
- package/src/index.ts +43 -15
- package/src/injection/descriptor.ts +206 -0
- package/src/injection/resolve-options.ts +144 -0
- package/src/introspection/dependency-graph.ts +223 -63
- package/src/introspection/graph-adapters/cytoscape.ts +9 -3
- package/src/introspection/graph-adapters/dot.ts +13 -5
- package/src/introspection/graph-adapters/mermaid.ts +61 -0
- package/src/introspection/graph-adapters/reactflow.ts +11 -4
- package/src/introspection/inspector.ts +16 -12
- package/src/{resolution/lifecycle.ts → lifecycle/lifecycle-manager.ts} +68 -32
- package/src/lifecycle/scope-manager.ts +156 -0
- package/src/metadata/metadata-reader-token.ts +2 -2
- package/src/metadata/metadata-types.ts +9 -9
- package/src/metadata/symbol-metadata-reader.ts +95 -18
- package/src/metadata/verifying-metadata-reader.ts +41 -0
- package/src/resolution/{activation-need.ts → cache/activation-need.ts} +8 -8
- package/src/resolution/{binding-lookup-cache.ts → cache/binding-lookup-cache.ts} +6 -5
- package/src/resolution/cache/class-introspector.ts +251 -0
- package/src/resolution/{environment.ts → context.ts} +84 -145
- package/src/resolution/path/resolution-path.ts +167 -0
- package/src/resolution/plan/instantiation-plan.ts +579 -0
- package/src/resolution/resolver.ts +635 -313
- package/src/resolution/select/binding-select.ts +210 -0
- package/src/resolution/select/constraints.ts +130 -0
- package/dist/binding.d.ts.map +0 -1
- package/dist/binding.js.map +0 -1
- package/dist/constructor-type.d.ts.map +0 -1
- package/dist/constructor-type.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/module.d.ts.map +0 -1
- package/dist/module.js.map +0 -1
- package/dist/registry.d.ts.map +0 -1
- package/dist/registry.js.map +0 -1
- package/dist/resolution/activation-need.d.ts.map +0 -1
- package/dist/resolution/activation-need.js.map +0 -1
- package/dist/resolution/binding-lookup-cache.d.ts.map +0 -1
- package/dist/resolution/binding-lookup-cache.js.map +0 -1
- package/dist/resolution/binding-scope.d.ts.map +0 -1
- package/dist/resolution/binding-scope.js.map +0 -1
- package/dist/resolution/binding-select.d.ts +0 -23
- package/dist/resolution/binding-select.d.ts.map +0 -1
- package/dist/resolution/binding-select.js +0 -121
- package/dist/resolution/binding-select.js.map +0 -1
- package/dist/resolution/class-introspector.d.ts +0 -27
- package/dist/resolution/class-introspector.d.ts.map +0 -1
- package/dist/resolution/class-introspector.js +0 -60
- package/dist/resolution/class-introspector.js.map +0 -1
- package/dist/resolution/constraints.d.ts.map +0 -1
- package/dist/resolution/constraints.js.map +0 -1
- package/dist/resolution/diagnostics.d.ts.map +0 -1
- package/dist/resolution/diagnostics.js.map +0 -1
- package/dist/resolution/environment.d.ts +0 -94
- package/dist/resolution/environment.d.ts.map +0 -1
- package/dist/resolution/environment.js.map +0 -1
- package/dist/resolution/instantiation-plan.d.ts.map +0 -1
- package/dist/resolution/instantiation-plan.js +0 -183
- package/dist/resolution/instantiation-plan.js.map +0 -1
- package/dist/resolution/lifecycle.d.ts +0 -23
- package/dist/resolution/lifecycle.d.ts.map +0 -1
- package/dist/resolution/lifecycle.js.map +0 -1
- package/dist/resolution/resolution-path.d.ts +0 -98
- package/dist/resolution/resolution-path.d.ts.map +0 -1
- package/dist/resolution/resolution-path.js +0 -98
- package/dist/resolution/resolution-path.js.map +0 -1
- package/dist/resolution/resolve-options.d.ts.map +0 -1
- package/dist/resolution/resolve-options.js +0 -56
- package/dist/resolution/resolve-options.js.map +0 -1
- package/dist/resolution/scope.d.ts +0 -28
- package/dist/resolution/scope.d.ts.map +0 -1
- package/dist/resolution/scope.js +0 -88
- package/dist/resolution/scope.js.map +0 -1
- package/dist/token.d.ts.map +0 -1
- package/dist/token.js +0 -22
- package/dist/token.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/src/registry.ts +0 -282
- package/src/resolution/binding-select.ts +0 -154
- package/src/resolution/class-introspector.ts +0 -74
- package/src/resolution/constraints.ts +0 -121
- package/src/resolution/instantiation-plan.ts +0 -292
- package/src/resolution/resolution-path.ts +0 -156
- package/src/resolution/resolve-options.ts +0 -89
- package/src/resolution/scope.ts +0 -105
- /package/dist/{resolution → core}/binding-scope.js +0 -0
- /package/dist/{constructor-type.js → core/constructor-type.js} +0 -0
- /package/dist/{types.js → core/types.js} +0 -0
- /package/dist/{resolution → errors}/diagnostics.js +0 -0
- /package/dist/resolution/{activation-need.js → cache/activation-need.js} +0 -0
- /package/dist/resolution/{binding-lookup-cache.js → cache/binding-lookup-cache.js} +0 -0
package/README.md
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
# @codefast/di
|
|
2
2
|
|
|
3
|
-
Lightweight, type-safe dependency injection for modern TypeScript — built on TC39 Stage 3 decorators, with no
|
|
3
|
+
Lightweight, type-safe dependency injection for modern TypeScript — built on TC39 Stage 3 decorators, with no
|
|
4
|
+
`reflect-metadata` and no `experimentalDecorators`.
|
|
4
5
|
|
|
5
6
|
[](https://www.npmjs.com/package/@codefast/di)
|
|
6
7
|
[](https://github.com/codefastlabs/codefast/blob/main/LICENSE)
|
|
7
8
|
|
|
8
|
-
- **Typed tokens.** `Token<Value>` flows through every `bind → resolve` path; `resolve()` returns the type you
|
|
9
|
-
|
|
10
|
-
- **
|
|
11
|
-
|
|
9
|
+
- **Typed tokens.** `Token<Value>` flows through every `bind → resolve` path; `resolve()` returns the type you
|
|
10
|
+
registered.
|
|
11
|
+
- **Native Stage 3 decorators.** `@injectable`, `inject`, `optional`, `@postConstruct`, `@preDestroy` — no runtime
|
|
12
|
+
reflection tricks.
|
|
13
|
+
- **Fluent bindings.** Constants, classes, sync/async factories, aliases, named/tagged/predicate constraints, lifecycle
|
|
14
|
+
hooks.
|
|
15
|
+
- **Scopes with validation.** `singleton` / `scoped` / `transient`, plus `validate()` to catch captive dependencies
|
|
16
|
+
early.
|
|
12
17
|
- **Modules.** Bundle bindings into reusable units; load, unload, and compose them across containers.
|
|
13
18
|
- **Async-aware.** Async factories, deduped async singleton construction, and `await using` disposal.
|
|
14
19
|
|
|
15
|
-
>
|
|
20
|
+
> Published on `0.x`, deliberately and with no 1.0 planned — breaking changes ship as minor versions, which is what
|
|
21
|
+
> keeps them cheap. Pin the minor if you need stability.
|
|
16
22
|
|
|
17
23
|
## Requirements
|
|
18
24
|
|
|
19
25
|
- **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
|
-
|
|
26
|
+
`Map.prototype.getOrInsertComputed` (ES2025), which ship in Node 26+. On older Node versions the package throws at
|
|
27
|
+
runtime.
|
|
22
28
|
- **TypeScript 5.2+** with native Stage 3 decorators — leave `experimentalDecorators` **off** (it is off by default).
|
|
23
29
|
|
|
24
30
|
## Installation
|
|
@@ -63,7 +69,8 @@ container.rebind(LoggerToken).toConstantValue({
|
|
|
63
69
|
});
|
|
64
70
|
```
|
|
65
71
|
|
|
66
|
-
`@injectable([...])` lists constructor dependencies in parameter order — no parameter-type reflection, so it works in
|
|
72
|
+
`@injectable([...])` lists constructor dependencies in parameter order — no parameter-type reflection, so it works in
|
|
73
|
+
any ESM runtime that supports Stage 3 decorators.
|
|
67
74
|
|
|
68
75
|
## Tokens
|
|
69
76
|
|
|
@@ -75,7 +82,8 @@ import { token } from "@codefast/di";
|
|
|
75
82
|
const DbToken = token<Database>("Database");
|
|
76
83
|
```
|
|
77
84
|
|
|
78
|
-
A class constructor can also be a key directly: `container.bind(UserService).toSelf()` then
|
|
85
|
+
A class constructor can also be a key directly: `container.bind(UserService).toSelf()` then
|
|
86
|
+
`container.resolve(UserService)`.
|
|
79
87
|
|
|
80
88
|
## Bindings
|
|
81
89
|
|
|
@@ -120,21 +128,48 @@ container.bind(RequestContextToken).toSelf().scoped();
|
|
|
120
128
|
|
|
121
129
|
### Constraints
|
|
122
130
|
|
|
123
|
-
Multiple bindings can share one token; a constraint picks the winner at resolution time.
|
|
131
|
+
Multiple bindings can share one token; a constraint picks the winner at resolution time. Named slots take a plain
|
|
132
|
+
string; tagged slots take a **criterion** minted from a tag key.
|
|
124
133
|
|
|
125
134
|
```typescript
|
|
135
|
+
import { tag } from "@codefast/di";
|
|
136
|
+
|
|
137
|
+
const Provider = tag<"s3" | "gcs">("provider");
|
|
138
|
+
|
|
126
139
|
container.bind(LoggerToken).toConstantValue(fileLogger).whenNamed("file");
|
|
127
|
-
container.bind(StorageToken).to(S3Storage).whenTagged("
|
|
140
|
+
container.bind(StorageToken).to(S3Storage).whenTagged(Provider.of("s3"));
|
|
128
141
|
|
|
129
142
|
container.resolve(LoggerToken, { name: "file" });
|
|
130
|
-
container.resolve(StorageToken, { tag:
|
|
143
|
+
container.resolve(StorageToken, { tag: Provider.of("s3") });
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`tag<Value>(name)` declares the key once and types both ends: a key declared `tag<"s3" | "gcs">` refuses any other
|
|
147
|
+
value, so a bind site and a resolve site cannot drift apart silently. `key.of(value)` interns, so the same value always
|
|
148
|
+
yields the same criterion — which is what lets lookup compare by identity. Build a criterion by hand and it matches
|
|
149
|
+
nothing.
|
|
150
|
+
|
|
151
|
+
`{ tag: criterion }` and `{ tags: [criterion] }` are the same request and take the same lookup path, on `resolve` and on
|
|
152
|
+
`inject` / `optional` / `injectAll` alike. Reach for `tags` when a slot carries more than one tag:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const Env = tag<"prod" | "dev">("env");
|
|
156
|
+
const Tier = tag<"premium" | "basic">("tier");
|
|
157
|
+
|
|
158
|
+
container.bind(LoggerToken).toConstantValue(auditLogger).whenTagged(Env.of("prod")).whenTagged(Tier.of("premium"));
|
|
159
|
+
|
|
160
|
+
container.resolve(LoggerToken, { tags: [Env.of("prod"), Tier.of("premium")] });
|
|
131
161
|
```
|
|
132
162
|
|
|
133
|
-
|
|
163
|
+
A request matches a slot when it carries **every** tag that slot declares — adding tags to a request makes it match more
|
|
164
|
+
slots, not fewer. When several match, the slot declaring more of them wins.
|
|
165
|
+
|
|
166
|
+
For graph-aware selection, pass a predicate to `.when(...)` — helpers like `whenParentIs`, `whenAnyAncestorNamed`, and
|
|
167
|
+
`whenParentTagged` ship from the root entry (`import { whenParentIs } from "@codefast/di"`).
|
|
134
168
|
|
|
135
169
|
## Decorators
|
|
136
170
|
|
|
137
|
-
All decorators use TC39 Stage 3 syntax. `inject()` wraps a dependency with resolve options, `optional()` resolves to
|
|
171
|
+
All decorators use TC39 Stage 3 syntax. `inject()` wraps a dependency with resolve options, `optional()` resolves to
|
|
172
|
+
`undefined` when unbound, and `injectAll()` collects every matching binding into an array.
|
|
138
173
|
|
|
139
174
|
```typescript
|
|
140
175
|
import { inject, injectable, optional, postConstruct, preDestroy } from "@codefast/di";
|
|
@@ -167,6 +202,23 @@ class Controller {
|
|
|
167
202
|
}
|
|
168
203
|
```
|
|
169
204
|
|
|
205
|
+
An accessor resolves from the container that is constructing the instance. When something else owns the `new` — a
|
|
206
|
+
router, an ORM, a test helper — open that context yourself with `runWithContainer(container, () => new Controller())`;
|
|
207
|
+
otherwise the accessor throws `MissingContainerContextError`.
|
|
208
|
+
|
|
209
|
+
Classes you cannot decorate (a dependency's class, generated code, plain JavaScript) are wired by supplying their
|
|
210
|
+
metadata yourself:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const container = Container.create({ metadataReader: myReader });
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
A `MetadataReader` reports constructor parameters, lifecycle method names, and `@inject` accessors; delegate misses to
|
|
217
|
+
`defaultMetadataReader` so decorated classes keep working. The reader is read while the container is constructed, so the
|
|
218
|
+
option — not a later `MetadataReaderToken` binding — is what resolution sees. See
|
|
219
|
+
[examples/19-custom-metadata-reader](https://github.com/codefastlabs/codefast/tree/main/packages/di/examples/19-custom-metadata-reader)
|
|
220
|
+
and the MetadataReader section of [SPEC.md](https://github.com/codefastlabs/codefast/blob/main/packages/di/SPEC.md).
|
|
221
|
+
|
|
170
222
|
## Container
|
|
171
223
|
|
|
172
224
|
```typescript
|
|
@@ -179,11 +231,13 @@ container.resolveAll(HandlerToken); // every matching binding
|
|
|
179
231
|
const db = await container.resolveAsync(DbToken); // required for async bindings
|
|
180
232
|
```
|
|
181
233
|
|
|
182
|
-
Mixing an async binding into a sync `resolve()` throws `AsyncResolutionError` — use `resolveAsync` / `resolveAllAsync` /
|
|
234
|
+
Mixing an async binding into a sync `resolve()` throws `AsyncResolutionError` — use `resolveAsync` / `resolveAllAsync` /
|
|
235
|
+
`resolveOptionalAsync` whenever the chain contains async work.
|
|
183
236
|
|
|
184
237
|
### Child containers
|
|
185
238
|
|
|
186
|
-
Children fall through to the parent's bindings and share its singleton cache, while `scoped` bindings get one instance
|
|
239
|
+
Children fall through to the parent's bindings and share its singleton cache, while `scoped` bindings get one instance
|
|
240
|
+
per child — ideal for per-request wiring.
|
|
187
241
|
|
|
188
242
|
```typescript
|
|
189
243
|
const requestContainer = container.createChild();
|
|
@@ -193,7 +247,8 @@ await requestContainer.dispose(); // releases scoped instances owned by this chi
|
|
|
193
247
|
|
|
194
248
|
### Validation
|
|
195
249
|
|
|
196
|
-
`validate()` fails fast on captive dependencies — for example a `singleton` depending on a `scoped` or `transient`
|
|
250
|
+
`validate()` fails fast on captive dependencies — for example a `singleton` depending on a `scoped` or `transient`
|
|
251
|
+
binding.
|
|
197
252
|
|
|
198
253
|
```typescript
|
|
199
254
|
container.validate(); // throws ScopeViolationError on the first violation
|
|
@@ -230,31 +285,65 @@ const AppModule = Module.create("App", (api) => {
|
|
|
230
285
|
const container = Container.fromModules(AppModule);
|
|
231
286
|
```
|
|
232
287
|
|
|
233
|
-
`Module.createAsync` supports awaiting during setup (remote config, connections); load those with
|
|
288
|
+
`Module.createAsync` supports awaiting during setup (remote config, connections); load those with
|
|
289
|
+
`Container.fromModulesAsync` or `container.loadAsync`. Modules are ref-counted: re-loading is a no-op and `unload` only
|
|
290
|
+
removes bindings once the count reaches zero.
|
|
234
291
|
|
|
235
292
|
## Errors
|
|
236
293
|
|
|
237
|
-
Every error extends `DiError` and carries a stable `code` — `TokenNotBoundError` (`"TOKEN_NOT_BOUND"`),
|
|
294
|
+
Every error extends `DiError` and carries a stable `code` — `TokenNotBoundError` (`"TOKEN_NOT_BOUND"`),
|
|
295
|
+
`CircularDependencyError`, `ScopeViolationError`, `AsyncResolutionError`, `AmbiguousBindingError`, and friends. Import
|
|
296
|
+
them from the root or from `@codefast/di/errors/errors`.
|
|
238
297
|
|
|
239
298
|
## Subpath exports
|
|
240
299
|
|
|
241
|
-
The root entry re-exports the full public API — prefer it
|
|
242
|
-
|
|
243
|
-
-
|
|
244
|
-
|
|
245
|
-
- **
|
|
300
|
+
The root entry re-exports the full public API — prefer it
|
|
301
|
+
(`import { Container, token, toReactFlowGraph } from "@codefast/di"`). Every module is also published as a
|
|
302
|
+
tree-shakeable subpath mirroring the source layout:
|
|
303
|
+
|
|
304
|
+
- **Model** under `/core/*` — `@codefast/di/core/token`, `/core/types`, `/core/binding`, `/core/tag`, `/core/registry`,
|
|
305
|
+
`/core/module`
|
|
306
|
+
- **Errors** under `/errors/*` — `@codefast/di/errors/errors`, `/errors/diagnostics`
|
|
307
|
+
- **Runtime** under `/container/*`, `/injection/*`, `/lifecycle/*` and `/resolution/*` — e.g.
|
|
308
|
+
`@codefast/di/resolution/select/constraints`
|
|
309
|
+
- **Introspection** ships at flat specifiers, without the directory prefix — `@codefast/di/inspector`,
|
|
310
|
+
`/dependency-graph`, and the graph adapters (`@codefast/di/graph-adapters/{dot,cytoscape,mermaid,reactflow}`) for
|
|
311
|
+
visualizing `container.generateDependencyGraph()` output
|
|
246
312
|
- **Decorators & metadata** under `/decorators/*` and `/metadata/*`
|
|
247
313
|
|
|
248
314
|
## Benchmarks
|
|
249
315
|
|
|
250
|
-
A head-to-head benchmark suite lives in the monorepo:
|
|
251
|
-
|
|
252
|
-
|
|
316
|
+
A head-to-head benchmark suite lives in the monorepo:
|
|
317
|
+
[benchmarks/di-inversify](https://github.com/codefastlabs/codefast/tree/main/benchmarks/di-inversify). It compares
|
|
318
|
+
`@codefast/di` against **InversifyJS 8** on the full scenario set, plus **Awilix** and **tsyringe** on a shared core
|
|
319
|
+
subset. Each library runs in its canonical mode, in isolated subprocesses, reported as per-trial medians with
|
|
320
|
+
interquartile range — designed so the results are re-runnable rather than taken on faith.
|
|
321
|
+
|
|
322
|
+
Against InversifyJS — the only one of the three that covers a comparable feature surface — `@codefast/di` currently wins
|
|
323
|
+
**all 44 comparable scenarios** in both profiles, at a median of 2.21×–2.39× and a geometric mean of 2.68×–2.90×.
|
|
324
|
+
Against the two deliberately leaner containers it wins the shared core subset as well, with one exception:
|
|
325
|
+
`realistic-graph-cold-resolve` against tsyringe, which reads parity in the default profile and a loss under the
|
|
326
|
+
forced-GC one. See [RESULTS.md](https://github.com/codefastlabs/codefast/blob/main/benchmarks/di-inversify/RESULTS.md)
|
|
327
|
+
for the full tables, the caveats, and the losses that earlier revisions reported — or run `pnpm bench` in that package
|
|
328
|
+
to reproduce them on your machine.
|
|
329
|
+
|
|
330
|
+
## Learning how it works
|
|
331
|
+
|
|
332
|
+
Curious how the engine is built, or want to learn from it?
|
|
333
|
+
[LEARNING.md](https://github.com/codefastlabs/codefast/blob/main/packages/di/LEARNING.md) is a guided read of the real
|
|
334
|
+
architectural patterns, design patterns, algorithms, TypeScript techniques, and performance work in this codebase — a
|
|
335
|
+
tour of one `resolve()` call, then a catalogue by topic, each pointing at the code. For the exact behavioural contract
|
|
336
|
+
see [SPEC.md](https://github.com/codefastlabs/codefast/blob/main/packages/di/SPEC.md); for the invariants the engine
|
|
337
|
+
depends on see [ARCHITECTURE.md](https://github.com/codefastlabs/codefast/blob/main/packages/di/ARCHITECTURE.md).
|
|
253
338
|
|
|
254
339
|
## Contributing
|
|
255
340
|
|
|
256
|
-
Changing this package's source?
|
|
341
|
+
Changing this package's source?
|
|
342
|
+
[CONTRIBUTING.md](https://github.com/codefastlabs/codefast/blob/main/packages/di/CONTRIBUTING.md) is the full workflow —
|
|
343
|
+
build, exports mirror, tests, the mandatory perf-guard for resolver changes, and the release gate.
|
|
257
344
|
|
|
258
345
|
## License
|
|
259
346
|
|
|
260
|
-
[MIT](https://github.com/codefastlabs/codefast/blob/main/LICENSE) — part of the
|
|
347
|
+
[MIT](https://github.com/codefastlabs/codefast/blob/main/LICENSE) — part of the
|
|
348
|
+
[codefast monorepo](https://github.com/codefastlabs/codefast). See
|
|
349
|
+
[CHANGELOG.md](https://github.com/codefastlabs/codefast/blob/main/packages/di/CHANGELOG.md) for release history.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** The container an `@inject` accessor initializer resolves from when it has no other handle. */
|
|
2
|
+
import type { Container } from "#/container/container";
|
|
3
|
+
import type { Token } from "#/core/token";
|
|
4
|
+
import type { Constructor, ResolveOptions } from "#/core/types";
|
|
5
|
+
/**
|
|
6
|
+
* Path-continuing resolution the engine installs while constructing a class with `@inject` accessors.
|
|
7
|
+
*
|
|
8
|
+
* @remarks Resolving through this keeps an accessor's dependencies on the live resolution path, so a
|
|
9
|
+
* cycle through an accessor surfaces as `CircularDependencyError` instead of unbounded recursion.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.6.0
|
|
12
|
+
*/
|
|
13
|
+
export interface AmbientResolution {
|
|
14
|
+
resolve<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value;
|
|
15
|
+
resolveOptional<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value | undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @since 0.3.16-canary.0
|
|
19
|
+
*/
|
|
20
|
+
export declare function runWithContainer<Result>(container: Container, fn: () => Result): Result;
|
|
21
|
+
/**
|
|
22
|
+
* Engine-internal variant of {@link runWithContainer} that also installs a path-continuing resolver.
|
|
23
|
+
*
|
|
24
|
+
* @since 0.6.0
|
|
25
|
+
*/
|
|
26
|
+
export declare function runWithAmbientResolution<Result>(container: Container, resolution: AmbientResolution | undefined, fn: () => Result): Result;
|
|
27
|
+
/**
|
|
28
|
+
* @since 0.3.16-canary.0
|
|
29
|
+
*/
|
|
30
|
+
export declare function getActiveContainer(): Container | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* The path-continuing resolution for the construction in flight, when the engine installed one.
|
|
33
|
+
*
|
|
34
|
+
* @since 0.6.0
|
|
35
|
+
*/
|
|
36
|
+
export declare function getAmbientResolution(): AmbientResolution | undefined;
|
|
37
|
+
//# sourceMappingURL=active-container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"active-container.d.ts","sourceRoot":"","sources":["../../src/ambient/active-container.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEhE;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,KAAK,CAAC;IAC1F,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,KAAK,GAAG,SAAS,CAAC;CAC/G;AAKD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,MAAM,GAAG,MAAM,CAEvF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAC7C,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,iBAAiB,GAAG,SAAS,EACzC,EAAE,EAAE,MAAM,MAAM,GACf,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,SAAS,GAAG,SAAS,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,GAAG,SAAS,CAEpE"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
let activeContainer;
|
|
2
|
+
let activeResolution;
|
|
3
|
+
/**
|
|
4
|
+
* @since 0.3.16-canary.0
|
|
5
|
+
*/
|
|
6
|
+
export function runWithContainer(container, fn) {
|
|
7
|
+
return runWithAmbientResolution(container, undefined, fn);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Engine-internal variant of {@link runWithContainer} that also installs a path-continuing resolver.
|
|
11
|
+
*
|
|
12
|
+
* @since 0.6.0
|
|
13
|
+
*/
|
|
14
|
+
export function runWithAmbientResolution(container, resolution, fn) {
|
|
15
|
+
const previousContainer = activeContainer;
|
|
16
|
+
const previousResolution = activeResolution;
|
|
17
|
+
activeContainer = container;
|
|
18
|
+
activeResolution = resolution;
|
|
19
|
+
try {
|
|
20
|
+
return fn();
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
activeContainer = previousContainer;
|
|
24
|
+
activeResolution = previousResolution;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* @since 0.3.16-canary.0
|
|
29
|
+
*/
|
|
30
|
+
export function getActiveContainer() {
|
|
31
|
+
return activeContainer;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The path-continuing resolution for the construction in flight, when the engine installed one.
|
|
35
|
+
*
|
|
36
|
+
* @since 0.6.0
|
|
37
|
+
*/
|
|
38
|
+
export function getAmbientResolution() {
|
|
39
|
+
return activeResolution;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=active-container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"active-container.js","sourceRoot":"","sources":["../../src/ambient/active-container.ts"],"names":[],"mappings":"AAkBA,IAAI,eAAsC,CAAC;AAC3C,IAAI,gBAA+C,CAAC;AAEpD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAS,SAAoB,EAAE,EAAgB;IAC7E,OAAO,wBAAwB,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAAoB,EACpB,UAAyC,EACzC,EAAgB;IAEhB,MAAM,iBAAiB,GAAG,eAAe,CAAC;IAC1C,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;IAC5C,eAAe,GAAG,SAAS,CAAC;IAC5B,gBAAgB,GAAG,UAAU,CAAC;IAC9B,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;YAAS,CAAC;QACT,eAAe,GAAG,iBAAiB,CAAC;QACpC,gBAAgB,GAAG,kBAAkB,CAAC;IACxC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,gBAAgB,CAAC;AAC1B,CAAC"}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The fluent chain `bind()` returns: it registers the binding and refines it in place.
|
|
3
3
|
*
|
|
4
|
-
* @
|
|
4
|
+
* @remarks One object plays every role in the chain; the return type of each step is what pins the
|
|
5
|
+
* order, so no runtime check has to.
|
|
5
6
|
*/
|
|
6
|
-
import type { AliasBindingBuilder, BindingBuilder, BindToBuilder, ConstantBindingBuilder, ScopedBindingBuilder, SingletonBindingBuilder, SingletonLifecycleBuilder, TransientBindingBuilder } from "#/binding";
|
|
7
|
-
import type {
|
|
8
|
-
import type {
|
|
9
|
-
import type { Token } from "#/token";
|
|
10
|
-
import type { ActivationHandler,
|
|
7
|
+
import type { AliasBindingBuilder, BindingBuilder, BindToBuilder, ConstantBindingBuilder, ScopedBindingBuilder, SingletonBindingBuilder, SingletonLifecycleBuilder, TransientBindingBuilder } from "#/core/binding";
|
|
8
|
+
import type { BindingRegistry } from "#/core/registry";
|
|
9
|
+
import type { BindingTag } from "#/core/tag";
|
|
10
|
+
import type { Token } from "#/core/token";
|
|
11
|
+
import type { ActivationHandler, BindingConstraint, BindingIdentifier, Constructor, DeactivationHandler, ResolutionContext } from "#/core/types";
|
|
12
|
+
import type { InjectableDependency, ResolvedDependencyValue } from "#/injection/descriptor";
|
|
13
|
+
import type { ScopeManager } from "#/lifecycle/scope-manager";
|
|
11
14
|
/**
|
|
12
15
|
* Where a chain registers, and on whose behalf.
|
|
13
16
|
*
|
|
@@ -18,6 +21,7 @@ import type { ActivationHandler, BindingIdentifier, ConstraintContext, Construct
|
|
|
18
21
|
*/
|
|
19
22
|
export interface BindingRegistration {
|
|
20
23
|
readonly registry: BindingRegistry;
|
|
24
|
+
readonly scope: ScopeManager;
|
|
21
25
|
readonly moduleBindingIds: Array<BindingIdentifier> | undefined;
|
|
22
26
|
}
|
|
23
27
|
/**
|
|
@@ -42,9 +46,9 @@ export declare class BindingChain<Value> implements AliasBindingBuilder, Binding
|
|
|
42
46
|
[K in keyof Deps]: ResolvedDependencyValue<NoInfer<Deps>[K]>;
|
|
43
47
|
}) => Promise<Value>, deps: Deps): BindingBuilder<Value>;
|
|
44
48
|
toAlias(target: Token<Value> | Constructor<Value>): AliasBindingBuilder;
|
|
45
|
-
when(predicate:
|
|
49
|
+
when(predicate: BindingConstraint): this;
|
|
46
50
|
whenNamed(name: string): this;
|
|
47
|
-
whenTagged(
|
|
51
|
+
whenTagged(criterion: BindingTag): this;
|
|
48
52
|
whenDefault(): this;
|
|
49
53
|
singleton(): SingletonBindingBuilder<Value>;
|
|
50
54
|
transient(): TransientBindingBuilder<Value>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding-builders.d.ts","sourceRoot":"","sources":["../../src/container/binding-builders.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"binding-builders.d.ts","sourceRoot":"","sources":["../../src/container/binding-builders.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,26 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { clearBindingFrame, createBinding, DEFAULT_BINDING_SLOT, refinableFields } from "#/core/binding";
|
|
2
|
+
import { tagKeyMaskOf } from "#/core/tag";
|
|
3
|
+
import { tokenName } from "#/core/token";
|
|
4
|
+
import { ChainNotRegisteredError, SelfBindingRequiresClassError } from "#/errors/errors";
|
|
5
|
+
import { normalizeToDescriptor } from "#/injection/descriptor";
|
|
6
|
+
/** One criterion per key: re-tagging the same key replaces it rather than asking for both values. */
|
|
7
|
+
function updateSlotTag(slot, criterion) {
|
|
6
8
|
const tags = [...slot.tags];
|
|
7
|
-
const existingIndex = tags.findIndex((
|
|
9
|
+
const existingIndex = tags.findIndex((existing) => existing.key === criterion.key);
|
|
8
10
|
if (existingIndex === -1) {
|
|
9
|
-
tags.push(
|
|
11
|
+
tags.push(criterion);
|
|
10
12
|
}
|
|
11
13
|
else {
|
|
12
|
-
tags[existingIndex] =
|
|
14
|
+
tags[existingIndex] = criterion;
|
|
13
15
|
}
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
// True when re-adding `restored` would immediately be displaced again by `current`
|
|
17
|
-
// (both slot-based with equal slots) — in that case the replacement was legitimate.
|
|
18
|
-
function displacesRestoredBinding(current, restored) {
|
|
19
|
-
const currentIsPurePredicate = current.predicate !== undefined && current.slot.name === undefined && current.slot.tags.length === 0;
|
|
20
|
-
if (currentIsPurePredicate) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
return bindingSlotEquals(current.slot, restored.slot);
|
|
16
|
+
// Frozen like DEFAULT_BINDING_SLOT's list: frames and snapshots alias a slot's tags.
|
|
17
|
+
return { ...slot, tags: Object.freeze(tags), keyMask: tagKeyMaskOf(tags) };
|
|
24
18
|
}
|
|
25
19
|
/** Record a module's binding id, dropping the id the chain re-slotted away from. */
|
|
26
20
|
function trackBindingForModule(ids, id, previousId) {
|
|
@@ -32,7 +26,7 @@ function trackBindingForModule(ids, id, previousId) {
|
|
|
32
26
|
}
|
|
33
27
|
ids.push(id);
|
|
34
28
|
}
|
|
35
|
-
// ── BindingChain
|
|
29
|
+
// ── BindingChain ─────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
36
30
|
/**
|
|
37
31
|
* The one builder behind `bind()` and every `to*()` return type. Each interface exposes only the
|
|
38
32
|
* calls that are legal at that point in the chain; the runtime object is shared because every
|
|
@@ -45,6 +39,8 @@ export class BindingChain {
|
|
|
45
39
|
#binding;
|
|
46
40
|
// Allocated only by a chain that actually displaces something — most never do.
|
|
47
41
|
#displacedByChain;
|
|
42
|
+
// Registry version after this chain's last write — a mismatch means someone else wrote in between.
|
|
43
|
+
#versionAfterLastWrite = -1;
|
|
48
44
|
#token;
|
|
49
45
|
#registration;
|
|
50
46
|
constructor(token, registration) {
|
|
@@ -66,7 +62,7 @@ export class BindingChain {
|
|
|
66
62
|
this.#commit(this.#binding, undefined);
|
|
67
63
|
return this;
|
|
68
64
|
}
|
|
69
|
-
// ── Registration
|
|
65
|
+
// ── Registration ───────────────────────────────────────────────────────────────────────────────────────────────────
|
|
70
66
|
to(type) {
|
|
71
67
|
return this.#register({ kind: "class", target: type, scope: "transient" });
|
|
72
68
|
}
|
|
@@ -104,32 +100,45 @@ export class BindingChain {
|
|
|
104
100
|
toAlias(target) {
|
|
105
101
|
return this.#register({ kind: "alias", scope: "transient", target });
|
|
106
102
|
}
|
|
107
|
-
// ── Refinement
|
|
103
|
+
// ── Refinement ─────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
108
104
|
// Slot and predicate are what the registry indexes on, so a re-slot rebuilds the binding and
|
|
109
105
|
// re-registers it — under the original id, keeping `id()` stable for the whole chain.
|
|
110
106
|
#reslot(slot, predicate) {
|
|
111
107
|
const previous = this.#registered();
|
|
112
108
|
this.#binding = createBinding(previous, previous.token, slot, predicate, previous.id);
|
|
113
109
|
this.#commit(this.#binding, previous.id);
|
|
110
|
+
// The tracked-singleton list holds object references, and the re-slot just replaced the object.
|
|
111
|
+
this.#registration.scope.replaceSingleton(previous, this.#binding);
|
|
114
112
|
return this;
|
|
115
113
|
}
|
|
116
114
|
#withScope(scope) {
|
|
117
115
|
const binding = this.#registered();
|
|
118
|
-
|
|
116
|
+
if (binding.scope !== scope) {
|
|
117
|
+
// An instance cached under the old scope must not survive the change — a later flip back
|
|
118
|
+
// to that scope would resurrect it.
|
|
119
|
+
this.#registration.scope.deleteSingleton(binding);
|
|
120
|
+
this.#registration.scope.deleteScoped(binding.id);
|
|
121
|
+
refinableFields(binding).scope = scope;
|
|
122
|
+
}
|
|
119
123
|
// The frame reports the scope, so a resolve before this call memoized the previous one.
|
|
120
124
|
clearBindingFrame(binding);
|
|
121
125
|
this.#registration.registry.touch();
|
|
126
|
+
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
122
127
|
return this;
|
|
123
128
|
}
|
|
129
|
+
// SPEC calls a candidate a binding that passes *all* of a chain's predicates, and the chain type
|
|
130
|
+
// reads as refinement, so a second `when()` narrows rather than replaces.
|
|
124
131
|
when(predicate) {
|
|
125
|
-
|
|
132
|
+
const binding = this.#registered();
|
|
133
|
+
const previous = binding.predicate;
|
|
134
|
+
return this.#reslot(binding.slot, previous === undefined ? predicate : (ctx) => previous(ctx) && predicate(ctx));
|
|
126
135
|
}
|
|
127
136
|
whenNamed(name) {
|
|
128
137
|
return this.#reslot({ ...this.#registered().slot, name }, this.#registered().predicate);
|
|
129
138
|
}
|
|
130
|
-
whenTagged(
|
|
139
|
+
whenTagged(criterion) {
|
|
131
140
|
const binding = this.#registered();
|
|
132
|
-
return this.#reslot(updateSlotTag(binding.slot,
|
|
141
|
+
return this.#reslot(updateSlotTag(binding.slot, criterion), binding.predicate);
|
|
133
142
|
}
|
|
134
143
|
whenDefault() {
|
|
135
144
|
// The default slot is what a fresh registration already has, so there is nothing to re-slot —
|
|
@@ -149,19 +158,21 @@ export class BindingChain {
|
|
|
149
158
|
onActivation(fn) {
|
|
150
159
|
refinableFields(this.#registered()).onActivation = fn;
|
|
151
160
|
this.#registration.registry.touch();
|
|
161
|
+
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
152
162
|
return this;
|
|
153
163
|
}
|
|
154
164
|
onDeactivation(fn) {
|
|
155
165
|
refinableFields(this.#registered()).onDeactivation = fn;
|
|
156
166
|
this.#registration.registry.touch();
|
|
167
|
+
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
157
168
|
return this;
|
|
158
169
|
}
|
|
159
170
|
id() {
|
|
160
171
|
return this.#registered().id;
|
|
161
172
|
}
|
|
162
|
-
// ── Registry
|
|
173
|
+
// ── Registry ───────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
163
174
|
/**
|
|
164
|
-
*
|
|
175
|
+
* Registers `binding`, first removing `previousId` when the chain is re-slotting.
|
|
165
176
|
*
|
|
166
177
|
* @remarks A `when*()` that follows `to*()` re-slots an already-live binding and can displace one
|
|
167
178
|
* the final shape would never conflict with. Those stay parked in `#displacedByChain` until the
|
|
@@ -173,23 +184,37 @@ export class BindingChain {
|
|
|
173
184
|
// chain's `Binding<Value>` is erased once, here, rather than at each call site.
|
|
174
185
|
const registered = binding;
|
|
175
186
|
if (previousId !== undefined) {
|
|
176
|
-
registry
|
|
187
|
+
// A registry someone else wrote since this chain's last write invalidates the parked
|
|
188
|
+
// snapshot: restoring it could undo an unbind or shadow a newer binding.
|
|
189
|
+
if (registry.version !== this.#versionAfterLastWrite) {
|
|
190
|
+
this.#displacedByChain = undefined;
|
|
191
|
+
}
|
|
192
|
+
if (registry.removeById(previousId) === undefined) {
|
|
193
|
+
// The chain's binding is no longer live (unbound or displaced) — a refinement must not
|
|
194
|
+
// resurrect it, so the chain goes inert against the registry.
|
|
195
|
+
this.#displacedByChain = undefined;
|
|
196
|
+
this.#versionAfterLastWrite = registry.version;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
177
199
|
}
|
|
178
200
|
const displaced = registry.add(registered);
|
|
179
201
|
if (displaced !== undefined) {
|
|
180
202
|
(this.#displacedByChain ??= []).push(displaced);
|
|
181
203
|
}
|
|
182
204
|
if (previousId !== undefined && this.#displacedByChain !== undefined) {
|
|
183
|
-
this.#restoreNonConflicting(
|
|
205
|
+
this.#restoreNonConflicting(this.#displacedByChain);
|
|
184
206
|
}
|
|
185
207
|
if (moduleBindingIds !== undefined) {
|
|
186
208
|
trackBindingForModule(moduleBindingIds, registered.id, previousId);
|
|
187
209
|
}
|
|
210
|
+
this.#versionAfterLastWrite = registry.version;
|
|
188
211
|
}
|
|
189
|
-
#restoreNonConflicting(
|
|
212
|
+
#restoreNonConflicting(displaced) {
|
|
190
213
|
for (let index = displaced.length - 1; index >= 0; index -= 1) {
|
|
191
214
|
const candidate = displaced[index];
|
|
192
|
-
|
|
215
|
+
// A restore must never displace: a slot that has been re-occupied keeps its occupant, and
|
|
216
|
+
// the candidate stays parked.
|
|
217
|
+
if (!this.#registration.registry.hasSlotOccupant(candidate)) {
|
|
193
218
|
this.#registration.registry.add(candidate);
|
|
194
219
|
displaced.splice(index, 1);
|
|
195
220
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding-builders.js","sourceRoot":"","sources":["../../src/container/binding-builders.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"binding-builders.js","sourceRoot":"","sources":["../../src/container/binding-builders.ts"],"names":[],"mappings":"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"}
|