@codefast/di 0.5.0-canary.7 → 0.5.0-canary.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +205 -0
- package/README.md +6 -2
- package/dist/binding.d.ts +85 -24
- package/dist/binding.d.ts.map +1 -1
- package/dist/binding.js +55 -0
- package/dist/binding.js.map +1 -1
- package/dist/constructor-type.d.ts +4 -5
- package/dist/constructor-type.d.ts.map +1 -1
- package/dist/container/binding-builders.d.ts +32 -11
- package/dist/container/binding-builders.d.ts.map +1 -1
- package/dist/container/binding-builders.js +144 -192
- package/dist/container/binding-builders.js.map +1 -1
- package/dist/container/container.d.ts.map +1 -1
- package/dist/container/container.js +141 -201
- package/dist/container/container.js.map +1 -1
- package/dist/decorators/inject.d.ts +2 -4
- package/dist/decorators/inject.d.ts.map +1 -1
- package/dist/decorators/inject.js.map +1 -1
- package/dist/errors.d.ts +24 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +30 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/introspection/inspector.d.ts +0 -1
- package/dist/introspection/inspector.d.ts.map +1 -1
- package/dist/introspection/inspector.js +3 -8
- package/dist/introspection/inspector.js.map +1 -1
- package/dist/metadata/metadata-keys.d.ts +3 -6
- package/dist/metadata/metadata-keys.d.ts.map +1 -1
- package/dist/metadata/metadata-keys.js +3 -6
- package/dist/metadata/metadata-keys.js.map +1 -1
- package/dist/registry.d.ts +14 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +81 -78
- package/dist/registry.js.map +1 -1
- package/dist/resolution/activation-need.d.ts +27 -0
- package/dist/resolution/activation-need.d.ts.map +1 -0
- package/dist/resolution/activation-need.js +68 -0
- package/dist/resolution/activation-need.js.map +1 -0
- package/dist/resolution/binding-lookup-cache.d.ts +41 -0
- package/dist/resolution/binding-lookup-cache.d.ts.map +1 -0
- package/dist/resolution/binding-lookup-cache.js +118 -0
- package/dist/resolution/binding-lookup-cache.js.map +1 -0
- package/dist/resolution/binding-scope.d.ts +5 -2
- package/dist/resolution/binding-scope.d.ts.map +1 -1
- package/dist/resolution/binding-scope.js +6 -17
- package/dist/resolution/binding-scope.js.map +1 -1
- package/dist/resolution/binding-select.d.ts +8 -1
- package/dist/resolution/binding-select.d.ts.map +1 -1
- package/dist/resolution/binding-select.js +14 -36
- package/dist/resolution/binding-select.js.map +1 -1
- package/dist/resolution/class-introspector.d.ts +27 -0
- package/dist/resolution/class-introspector.d.ts.map +1 -0
- package/dist/resolution/class-introspector.js +60 -0
- package/dist/resolution/class-introspector.js.map +1 -0
- package/dist/resolution/diagnostics.d.ts +41 -0
- package/dist/resolution/diagnostics.d.ts.map +1 -0
- package/dist/resolution/diagnostics.js +18 -0
- package/dist/resolution/diagnostics.js.map +1 -0
- package/dist/resolution/environment.d.ts +48 -1
- package/dist/resolution/environment.d.ts.map +1 -1
- package/dist/resolution/environment.js +134 -5
- package/dist/resolution/environment.js.map +1 -1
- package/dist/resolution/instantiation-plan.d.ts +15 -15
- package/dist/resolution/instantiation-plan.d.ts.map +1 -1
- package/dist/resolution/instantiation-plan.js +69 -49
- package/dist/resolution/instantiation-plan.js.map +1 -1
- package/dist/resolution/lifecycle.d.ts +2 -0
- package/dist/resolution/lifecycle.d.ts.map +1 -1
- package/dist/resolution/lifecycle.js +60 -62
- package/dist/resolution/lifecycle.js.map +1 -1
- package/dist/resolution/resolution-path.d.ts +84 -17
- package/dist/resolution/resolution-path.d.ts.map +1 -1
- package/dist/resolution/resolution-path.js +68 -23
- package/dist/resolution/resolution-path.js.map +1 -1
- package/dist/resolution/resolve-options.d.ts +41 -4
- package/dist/resolution/resolve-options.d.ts.map +1 -1
- package/dist/resolution/resolve-options.js +25 -1
- package/dist/resolution/resolve-options.js.map +1 -1
- package/dist/resolution/resolver.d.ts +33 -10
- package/dist/resolution/resolver.d.ts.map +1 -1
- package/dist/resolution/resolver.js +471 -830
- package/dist/resolution/resolver.js.map +1 -1
- package/dist/resolution/scope.d.ts +11 -15
- package/dist/resolution/scope.d.ts.map +1 -1
- package/dist/resolution/scope.js +55 -43
- package/dist/resolution/scope.js.map +1 -1
- package/package.json +10 -106
- package/src/binding.ts +146 -24
- package/src/constructor-type.ts +4 -5
- package/src/container/binding-builders.ts +184 -284
- package/src/container/container.ts +161 -221
- package/src/decorators/inject.ts +3 -5
- package/src/errors.ts +38 -0
- package/src/index.ts +4 -1
- package/src/introspection/inspector.ts +3 -9
- package/src/metadata/metadata-keys.ts +3 -6
- package/src/registry.ts +90 -94
- package/src/resolution/activation-need.ts +85 -0
- package/src/resolution/binding-lookup-cache.ts +148 -0
- package/src/resolution/binding-scope.ts +6 -17
- package/src/resolution/binding-select.ts +15 -39
- package/src/resolution/class-introspector.ts +74 -0
- package/src/resolution/diagnostics.ts +43 -0
- package/src/resolution/environment.ts +181 -5
- package/src/resolution/instantiation-plan.ts +116 -64
- package/src/resolution/lifecycle.ts +69 -62
- package/src/resolution/resolution-path.ts +122 -43
- package/src/resolution/resolve-options.ts +51 -4
- package/src/resolution/resolver.ts +649 -1081
- package/src/resolution/scope.ts +58 -47
package/src/resolution/scope.ts
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
|
+
import type { Binding } from "#/binding";
|
|
2
|
+
import { NO_INSTANCE } from "#/binding";
|
|
1
3
|
import { MissingScopeContextError } from "#/errors";
|
|
2
4
|
import type { BindingIdentifier } from "#/types";
|
|
3
5
|
|
|
4
|
-
/**
|
|
5
|
-
* Sentinel returned by {@link ScopeManager.peekSingleton} when nothing is cached —
|
|
6
|
-
* lets hot paths read the cache with a single Map.get even for `undefined` values.
|
|
7
|
-
*
|
|
8
|
-
* @since 0.5.0-canary.7
|
|
9
|
-
*/
|
|
10
|
-
export const SINGLETON_MISS: unique symbol = Symbol("di:singleton-miss");
|
|
11
|
-
|
|
12
6
|
/**
|
|
13
7
|
* @since 0.3.16-canary.0
|
|
14
8
|
*/
|
|
15
9
|
export class ScopeManager {
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
// Instances live on their binding (see ARCHITECTURE.md); this list only lets disposal and
|
|
11
|
+
// `inspect()` enumerate them.
|
|
12
|
+
#singletonBindings: Array<Binding<unknown>> | undefined;
|
|
13
|
+
// In-flight promises for async singleton creation — only an async resolve ever needs it.
|
|
14
|
+
#inflight: Map<BindingIdentifier, Promise<unknown>> | undefined;
|
|
15
|
+
// Scoped cache — only a child container resolving a `scoped` binding ever needs it.
|
|
16
|
+
#scoped: Map<BindingIdentifier, unknown> | undefined;
|
|
22
17
|
|
|
23
18
|
readonly isChild: boolean;
|
|
24
19
|
|
|
@@ -26,69 +21,85 @@ export class ScopeManager {
|
|
|
26
21
|
this.isChild = isChild;
|
|
27
22
|
}
|
|
28
23
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
getSingleton<Value>(id: BindingIdentifier): Value {
|
|
34
|
-
return this.#singletons.get(id) as Value;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** Cached value, or {@link SINGLETON_MISS} — one Map.get on the hot path. */
|
|
38
|
-
peekSingleton(id: BindingIdentifier): unknown {
|
|
39
|
-
const value = this.#singletons.get(id);
|
|
40
|
-
if (value === undefined && !this.#singletons.has(id)) {
|
|
41
|
-
return SINGLETON_MISS;
|
|
24
|
+
setSingleton<const Value>(binding: Binding<Value>, instance: unknown): void {
|
|
25
|
+
if (binding.instance === NO_INSTANCE) {
|
|
26
|
+
(this.#singletonBindings ??= []).push(binding as Binding<unknown>);
|
|
42
27
|
}
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
setSingleton(id: BindingIdentifier, instance: unknown): void {
|
|
47
|
-
this.#singletons.set(id, instance);
|
|
28
|
+
binding.instance = instance;
|
|
48
29
|
}
|
|
49
30
|
|
|
50
|
-
|
|
51
|
-
|
|
31
|
+
/** Every binding in this container holding a cached singleton. */
|
|
32
|
+
cachedSingletons(): ReadonlyArray<Binding<unknown>> {
|
|
33
|
+
return this.#singletonBindings ?? EMPTY_BINDINGS;
|
|
52
34
|
}
|
|
53
35
|
|
|
54
|
-
|
|
55
|
-
|
|
36
|
+
deleteSingleton<const Value>(binding: Binding<Value>): boolean {
|
|
37
|
+
if (binding.instance === NO_INSTANCE) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
binding.instance = NO_INSTANCE;
|
|
41
|
+
const tracked = this.#singletonBindings;
|
|
42
|
+
if (tracked !== undefined) {
|
|
43
|
+
const index = tracked.indexOf(binding as Binding<unknown>);
|
|
44
|
+
if (index !== -1) {
|
|
45
|
+
tracked.splice(index, 1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
56
49
|
}
|
|
57
50
|
|
|
58
51
|
getInflight(id: BindingIdentifier): Promise<unknown> | undefined {
|
|
59
|
-
return this.#inflight
|
|
52
|
+
return this.#inflight?.get(id);
|
|
60
53
|
}
|
|
61
54
|
|
|
62
55
|
setInflight(id: BindingIdentifier, p: Promise<unknown>): void {
|
|
63
|
-
this.#inflight.set(id, p);
|
|
56
|
+
(this.#inflight ??= new Map()).set(id, p);
|
|
64
57
|
}
|
|
65
58
|
|
|
66
59
|
clearInflight(id: BindingIdentifier): void {
|
|
67
|
-
this.#inflight
|
|
60
|
+
this.#inflight?.delete(id);
|
|
68
61
|
}
|
|
69
62
|
|
|
70
63
|
hasScoped(id: BindingIdentifier): boolean {
|
|
71
|
-
return this.#scoped.has(id);
|
|
64
|
+
return this.#scoped !== undefined && this.#scoped.has(id);
|
|
72
65
|
}
|
|
73
66
|
|
|
74
67
|
getScoped<Value>(id: BindingIdentifier): Value {
|
|
75
|
-
return this.#scoped
|
|
68
|
+
return this.#scoped?.get(id) as Value;
|
|
76
69
|
}
|
|
77
70
|
|
|
78
71
|
setScoped(id: BindingIdentifier, instance: unknown): void {
|
|
79
72
|
if (!this.isChild) {
|
|
80
73
|
throw new MissingScopeContextError("(unknown)");
|
|
81
74
|
}
|
|
82
|
-
this.#scoped.set(id, instance);
|
|
75
|
+
(this.#scoped ??= new Map()).set(id, instance);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Releases a removed binding's scoped instance — no deactivation, per SPEC §5.2. */
|
|
79
|
+
deleteScoped(id: BindingIdentifier): void {
|
|
80
|
+
this.#scoped?.delete(id);
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
/** Scoped instances currently cached — a structural count for diagnostics. */
|
|
84
|
+
get scopedCount(): number {
|
|
85
|
+
return this.#scoped?.size ?? 0;
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
clearAll(): void {
|
|
90
|
-
this.#
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
const tracked = this.#singletonBindings;
|
|
90
|
+
if (tracked !== undefined) {
|
|
91
|
+
for (const binding of tracked) {
|
|
92
|
+
binding.instance = NO_INSTANCE;
|
|
93
|
+
}
|
|
94
|
+
tracked.length = 0;
|
|
95
|
+
}
|
|
96
|
+
this.#inflight?.clear();
|
|
97
|
+
this.#scoped?.clear();
|
|
98
|
+
}
|
|
99
|
+
/** Whether the deferred table behind `#scoped` has had to be built. */
|
|
100
|
+
get isBuilt(): boolean {
|
|
101
|
+
return this.#scoped !== undefined;
|
|
93
102
|
}
|
|
94
103
|
}
|
|
104
|
+
|
|
105
|
+
const EMPTY_BINDINGS: ReadonlyArray<Binding<unknown>> = [];
|