@codefast/di 0.10.0 → 0.11.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 +293 -0
- package/README.md +71 -7
- package/dist/ambient/active-container.d.ts +13 -11
- package/dist/ambient/active-container.js +8 -6
- package/dist/container/binding-builders.d.ts +25 -7
- package/dist/container/binding-builders.js +110 -42
- package/dist/container/container.d.ts +8 -8
- package/dist/container/container.js +244 -67
- package/dist/core/binding-declaration.d.ts +120 -0
- package/dist/core/binding-declaration.js +186 -0
- package/dist/core/binding-scope.d.ts +2 -2
- package/dist/core/binding.d.ts +61 -9
- package/dist/core/binding.js +49 -2
- package/dist/core/constraint-requirement.d.ts +1 -1
- package/dist/core/module.d.ts +10 -7
- package/dist/core/module.js +17 -3
- package/dist/core/registry.d.ts +17 -13
- package/dist/core/registry.js +155 -59
- package/dist/core/state-epoch.d.ts +18 -1
- package/dist/core/state-epoch.js +17 -0
- package/dist/core/tag.js +1 -1
- package/dist/core/token.d.ts +1 -1
- package/dist/core/types.d.ts +5 -5
- package/dist/decorators/decorator-metadata.d.ts +9 -0
- package/dist/decorators/decorator-metadata.js +20 -0
- package/dist/decorators/inject.d.ts +3 -3
- package/dist/decorators/inject.js +7 -6
- package/dist/decorators/injectable.d.ts +2 -2
- package/dist/decorators/injectable.js +5 -3
- package/dist/decorators/lifecycle-decorators.js +9 -3
- package/dist/errors/errors.d.ts +85 -14
- package/dist/errors/errors.js +100 -20
- package/dist/index.d.ts +37 -35
- package/dist/index.js +20 -19
- package/dist/injection/descriptor.d.ts +3 -3
- package/dist/injection/descriptor.js +3 -7
- package/dist/injection/resolve-options.d.ts +3 -3
- package/dist/injection/resolve-options.js +7 -5
- package/dist/introspection/dependency-graph.d.ts +10 -5
- package/dist/introspection/dependency-graph.js +51 -28
- 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/graph-adapters/reactflow.js +6 -4
- package/dist/introspection/inspector.d.ts +4 -4
- package/dist/introspection/inspector.js +9 -12
- package/dist/lifecycle/lifecycle-manager.d.ts +4 -4
- package/dist/lifecycle/lifecycle-manager.js +18 -6
- package/dist/lifecycle/scope-manager.d.ts +2 -2
- package/dist/lifecycle/scope-manager.js +31 -13
- 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 +5 -4
- package/dist/metadata/verifying-metadata-reader.js +30 -8
- package/dist/resolution/async-fan-out.d.ts +12 -0
- package/dist/resolution/async-fan-out.js +26 -0
- package/dist/resolution/cache/activation-need.d.ts +4 -5
- package/dist/resolution/cache/activation-need.js +11 -18
- package/dist/resolution/cache/binding-lookup-cache.d.ts +5 -12
- package/dist/resolution/cache/binding-lookup-cache.js +32 -19
- package/dist/resolution/cache/class-introspector.d.ts +16 -5
- package/dist/resolution/cache/class-introspector.js +73 -56
- package/dist/resolution/context.d.ts +17 -25
- package/dist/resolution/context.js +47 -56
- package/dist/resolution/path/resolution-path.d.ts +48 -13
- package/dist/resolution/path/resolution-path.js +90 -39
- package/dist/resolution/plan/instantiation-plan.d.ts +5 -5
- package/dist/resolution/plan/instantiation-plan.js +66 -26
- package/dist/resolution/plan/plan-codegen.d.ts +10 -7
- package/dist/resolution/plan/plan-codegen.js +62 -34
- package/dist/resolution/resolver.d.ts +16 -17
- package/dist/resolution/resolver.js +316 -273
- 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 +14 -2
|
@@ -1,21 +1,9 @@
|
|
|
1
|
-
import { clearBindingFrame,
|
|
2
|
-
import { mergingConstraintRequirements } from "
|
|
3
|
-
import { slotName } from "
|
|
4
|
-
import { tokenName } from "
|
|
5
|
-
import { ChainAlreadyRegisteredError, ChainNotRegisteredError, ManyBindingSlotError, SelfBindingRequiresClassError, } from "
|
|
6
|
-
import { normalizeToDescriptor } from "
|
|
7
|
-
/** One criterion per key: re-tagging the same key replaces it rather than asking for both values. */
|
|
8
|
-
function updateSlotTag(slot, criterion) {
|
|
9
|
-
const tags = [...slot.tags];
|
|
10
|
-
const existingIndex = tags.findIndex((existing) => existing.key === criterion.key);
|
|
11
|
-
if (existingIndex === -1) {
|
|
12
|
-
tags.push(criterion);
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
tags[existingIndex] = criterion;
|
|
16
|
-
}
|
|
17
|
-
return createBindingSlot(tags);
|
|
18
|
-
}
|
|
1
|
+
import { clearBindingFrame, NO_ACTIVATION_STAMP, DEFAULT_BINDING_SLOT, generateBindingId, NO_INSTANCE, UNREGISTERED_ORDER, withSlotCriterion, } 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";
|
|
19
7
|
// ── BindingChain ─────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
20
8
|
/**
|
|
21
9
|
* The one builder behind `bind()` and every `to*()` return type — and the binding it registers.
|
|
@@ -33,6 +21,9 @@ export class BindingChain {
|
|
|
33
21
|
identifier = generateBindingId();
|
|
34
22
|
inFlight = false;
|
|
35
23
|
frame = undefined;
|
|
24
|
+
rootContext = undefined;
|
|
25
|
+
activationStamp = NO_ACTIVATION_STAMP;
|
|
26
|
+
registrationOrder = UNREGISTERED_ORDER;
|
|
36
27
|
instance = NO_INSTANCE;
|
|
37
28
|
token;
|
|
38
29
|
slot = DEFAULT_BINDING_SLOT;
|
|
@@ -76,9 +67,70 @@ export class BindingChain {
|
|
|
76
67
|
this.kind = kind;
|
|
77
68
|
this.scope = scope;
|
|
78
69
|
this.#isRegistered = true;
|
|
79
|
-
|
|
70
|
+
// A fresh registration parks nothing yet and restores nothing: one add, then the version.
|
|
71
|
+
const registration = this.#registration;
|
|
72
|
+
const registry = registration.registry;
|
|
73
|
+
const displaced = registry.add(this.#binding);
|
|
74
|
+
if (displaced !== undefined) {
|
|
75
|
+
if (registration.deactivateDisplaced !== undefined) {
|
|
76
|
+
registration.deactivateDisplaced(displaced);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.#displacedByChain = [displaced];
|
|
80
|
+
registration.onDisplaced?.(displaced);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (registration.moduleBindingIds !== undefined) {
|
|
84
|
+
registration.moduleBindingIds.push(this.identifier);
|
|
85
|
+
}
|
|
86
|
+
this.#versionAfterLastWrite = registry.version;
|
|
80
87
|
return this;
|
|
81
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Registers a declared module's bindings in list order, each a chain of its own that no step
|
|
91
|
+
* will ever refine.
|
|
92
|
+
*
|
|
93
|
+
* @remarks A displaced binding is handled as `to*()` handles it, never parked: nothing refines the
|
|
94
|
+
* chain, so nothing could restore it.
|
|
95
|
+
*/
|
|
96
|
+
static registerDeclared(declarations, registration) {
|
|
97
|
+
const { registry, moduleBindingIds, deactivateDisplaced, onDisplaced } = registration;
|
|
98
|
+
for (let index = 0; index < declarations.length; index += 1) {
|
|
99
|
+
const declaration = declarations[index];
|
|
100
|
+
const binding = BindingChain.#fromDeclaration(declaration, registration);
|
|
101
|
+
const displaced = registry.add(binding);
|
|
102
|
+
if (displaced !== undefined) {
|
|
103
|
+
if (deactivateDisplaced === undefined) {
|
|
104
|
+
onDisplaced?.(displaced);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
deactivateDisplaced(displaced);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
moduleBindingIds?.push(binding.identifier);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A registered chain in the shape a declaration's steps would have left.
|
|
115
|
+
*
|
|
116
|
+
* @remarks Typed `unknown` like the declaration it copies, so the value type is never asserted here.
|
|
117
|
+
*/
|
|
118
|
+
static #fromDeclaration(declaration, registration) {
|
|
119
|
+
const chain = new BindingChain(declaration.token, registration);
|
|
120
|
+
chain.kind = declaration.kind;
|
|
121
|
+
chain.slot = declaration.slot;
|
|
122
|
+
chain.predicate = declaration.predicate;
|
|
123
|
+
chain.isMany = declaration.isMany;
|
|
124
|
+
chain.scope = declaration.scope;
|
|
125
|
+
chain.target = declaration.target;
|
|
126
|
+
chain.factory = declaration.factory;
|
|
127
|
+
chain.deps = declaration.deps;
|
|
128
|
+
chain.value = declaration.value;
|
|
129
|
+
chain.activationHook = declaration.activationHook;
|
|
130
|
+
chain.deactivationHook = declaration.deactivationHook;
|
|
131
|
+
chain.#isRegistered = true;
|
|
132
|
+
return chain.#binding;
|
|
133
|
+
}
|
|
82
134
|
// ── Registration ───────────────────────────────────────────────────────────────────────────────────────────────────
|
|
83
135
|
to(type) {
|
|
84
136
|
this.#requireUnregistered();
|
|
@@ -126,6 +178,24 @@ export class BindingChain {
|
|
|
126
178
|
return this.#register("alias", "transient");
|
|
127
179
|
}
|
|
128
180
|
// ── Refinement ─────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
181
|
+
/**
|
|
182
|
+
* Whether this chain provably still owns the registry's last write with nothing parked.
|
|
183
|
+
*
|
|
184
|
+
* @remarks When it does, a refinement rewrites the live binding in place; otherwise `#reslot`
|
|
185
|
+
* re-checks liveness and restores what the new shape frees.
|
|
186
|
+
*/
|
|
187
|
+
get #isProvablyLive() {
|
|
188
|
+
return this.#registration.registry.version === this.#versionAfterLastWrite && this.#displacedByChain === undefined;
|
|
189
|
+
}
|
|
190
|
+
/** Stamps this chain's last-write version after a mutation it made in place. */
|
|
191
|
+
#recordWrite() {
|
|
192
|
+
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
193
|
+
}
|
|
194
|
+
/** Bumps the registry for an index-neutral mutation (scope, hook) and records this chain's write. */
|
|
195
|
+
#touchAndRecordWrite() {
|
|
196
|
+
this.#registration.registry.touch();
|
|
197
|
+
this.#recordWrite();
|
|
198
|
+
}
|
|
129
199
|
// Slot and predicate are what the registry indexes on, so a re-slot takes the binding out of the
|
|
130
200
|
// registry, rewrites the two fields while it is out, and registers it again — same object, same id.
|
|
131
201
|
#reslot(slot, predicate) {
|
|
@@ -149,8 +219,7 @@ export class BindingChain {
|
|
|
149
219
|
}
|
|
150
220
|
// The frame reports the scope, so a resolve before this call memoized the previous one.
|
|
151
221
|
clearBindingFrame(this.#binding);
|
|
152
|
-
this.#
|
|
153
|
-
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
222
|
+
this.#touchAndRecordWrite();
|
|
154
223
|
return this;
|
|
155
224
|
}
|
|
156
225
|
// SPEC calls a candidate a binding that passes *all* of a chain's predicates, and the chain type
|
|
@@ -162,13 +231,10 @@ export class BindingChain {
|
|
|
162
231
|
const narrowed = previous === undefined
|
|
163
232
|
? predicate
|
|
164
233
|
: 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;
|
|
234
|
+
// The slot is unchanged, so a provably-live binding just takes the predicate in place.
|
|
235
|
+
if (this.#isProvablyLive) {
|
|
236
|
+
this.#registration.registry.setPredicate(this.#binding, narrowed);
|
|
237
|
+
this.#recordWrite();
|
|
172
238
|
return this;
|
|
173
239
|
}
|
|
174
240
|
return this.#reslot(this.slot, narrowed);
|
|
@@ -181,7 +247,7 @@ export class BindingChain {
|
|
|
181
247
|
if (this.isMany) {
|
|
182
248
|
throw new ManyBindingSlotError(tokenName(this.token));
|
|
183
249
|
}
|
|
184
|
-
return this.#reslot(
|
|
250
|
+
return this.#reslot(withSlotCriterion(this.slot, criterion), this.predicate);
|
|
185
251
|
}
|
|
186
252
|
many() {
|
|
187
253
|
this.#requireRegistered();
|
|
@@ -191,14 +257,11 @@ export class BindingChain {
|
|
|
191
257
|
if (this.isMany) {
|
|
192
258
|
return this;
|
|
193
259
|
}
|
|
194
|
-
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (registry.version === this.#versionAfterLastWrite && this.#displacedByChain === undefined) {
|
|
200
|
-
registry.setMany(this.#binding);
|
|
201
|
-
this.#versionAfterLastWrite = registry.version;
|
|
260
|
+
// A provably-live binding takes membership in place; the registry only moves it out of the lone
|
|
261
|
+
// map. Otherwise `#commit` re-checks liveness and restores what the freed slot lets back in.
|
|
262
|
+
if (this.#isProvablyLive) {
|
|
263
|
+
this.#registration.registry.setMany(this.#binding);
|
|
264
|
+
this.#recordWrite();
|
|
202
265
|
return this;
|
|
203
266
|
}
|
|
204
267
|
this.#commit(() => {
|
|
@@ -224,15 +287,13 @@ export class BindingChain {
|
|
|
224
287
|
onActivation(fn) {
|
|
225
288
|
this.#requireRegistered();
|
|
226
289
|
this.activationHook = fn;
|
|
227
|
-
this.#
|
|
228
|
-
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
290
|
+
this.#touchAndRecordWrite();
|
|
229
291
|
return this;
|
|
230
292
|
}
|
|
231
293
|
onDeactivation(fn) {
|
|
232
294
|
this.#requireRegistered();
|
|
233
295
|
this.deactivationHook = fn;
|
|
234
|
-
this.#
|
|
235
|
-
this.#versionAfterLastWrite = this.#registration.registry.version;
|
|
296
|
+
this.#touchAndRecordWrite();
|
|
236
297
|
return this;
|
|
237
298
|
}
|
|
238
299
|
id() {
|
|
@@ -272,7 +333,13 @@ export class BindingChain {
|
|
|
272
333
|
}
|
|
273
334
|
const displaced = registry.add(registered);
|
|
274
335
|
if (displaced !== undefined) {
|
|
275
|
-
(this.#
|
|
336
|
+
if (this.#registration.deactivateDisplaced !== undefined && rewrite === undefined) {
|
|
337
|
+
this.#registration.deactivateDisplaced(displaced);
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
(this.#displacedByChain ??= []).push(displaced);
|
|
341
|
+
this.#registration.onDisplaced?.(displaced);
|
|
342
|
+
}
|
|
276
343
|
}
|
|
277
344
|
if (rewrite !== undefined && this.#displacedByChain !== undefined) {
|
|
278
345
|
this.#restoreNonConflicting(this.#displacedByChain);
|
|
@@ -289,6 +356,7 @@ export class BindingChain {
|
|
|
289
356
|
// the candidate stays parked.
|
|
290
357
|
if (!this.#registration.registry.hasSlotOccupant(candidate)) {
|
|
291
358
|
this.#registration.registry.add(candidate);
|
|
359
|
+
this.#registration.onRestored?.(candidate);
|
|
292
360
|
displaced.splice(index, 1);
|
|
293
361
|
}
|
|
294
362
|
}
|
|
@@ -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
|
*
|