@codefast/di 0.8.0 → 0.8.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 +13 -0
- package/README.md +242 -159
- package/dist/ambient/active-container.d.ts +1 -2
- package/dist/ambient/active-container.js +1 -2
- package/dist/container/binding-builders.d.ts +1 -2
- package/dist/container/binding-builders.js +1 -2
- package/dist/container/container.d.ts +1 -2
- package/dist/container/container.js +1 -2
- package/dist/core/binding-scope.d.ts +1 -2
- package/dist/core/binding-scope.js +1 -2
- package/dist/core/binding.d.ts +1 -2
- package/dist/core/binding.js +1 -2
- package/dist/core/constraint-requirement.d.ts +1 -2
- package/dist/core/constraint-requirement.js +1 -2
- package/dist/core/constructor-type.d.ts +1 -2
- package/dist/core/constructor-type.js +1 -2
- package/dist/core/map-upsert.d.ts +1 -2
- package/dist/core/map-upsert.js +1 -2
- package/dist/core/module.d.ts +1 -2
- package/dist/core/module.js +1 -2
- package/dist/core/registry.d.ts +1 -2
- package/dist/core/registry.js +1 -2
- package/dist/core/tag.d.ts +1 -2
- package/dist/core/tag.js +1 -2
- package/dist/core/token.d.ts +1 -2
- package/dist/core/token.js +1 -2
- package/dist/core/types.d.ts +1 -2
- package/dist/core/types.js +1 -2
- package/dist/decorators/inject.d.ts +1 -2
- package/dist/decorators/inject.js +1 -2
- package/dist/decorators/injectable.d.ts +1 -2
- package/dist/decorators/injectable.js +1 -2
- package/dist/decorators/lifecycle-decorators.d.ts +1 -2
- package/dist/decorators/lifecycle-decorators.js +1 -2
- package/dist/errors/diagnostics.d.ts +1 -2
- package/dist/errors/diagnostics.js +1 -2
- package/dist/errors/errors.d.ts +1 -2
- package/dist/errors/errors.js +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/injection/descriptor.d.ts +1 -2
- package/dist/injection/descriptor.js +1 -2
- package/dist/injection/resolve-options.d.ts +1 -2
- package/dist/injection/resolve-options.js +1 -2
- package/dist/introspection/dependency-graph.d.ts +1 -2
- package/dist/introspection/dependency-graph.js +1 -2
- package/dist/introspection/graph-adapters/cytoscape.d.ts +1 -2
- package/dist/introspection/graph-adapters/cytoscape.js +1 -2
- package/dist/introspection/graph-adapters/dot.d.ts +1 -2
- package/dist/introspection/graph-adapters/dot.js +1 -2
- package/dist/introspection/graph-adapters/mermaid.d.ts +1 -2
- package/dist/introspection/graph-adapters/mermaid.js +1 -2
- package/dist/introspection/graph-adapters/reactflow.d.ts +1 -2
- package/dist/introspection/graph-adapters/reactflow.js +1 -2
- package/dist/introspection/inspector.d.ts +1 -2
- package/dist/introspection/inspector.js +1 -2
- package/dist/lifecycle/lifecycle-manager.d.ts +1 -2
- package/dist/lifecycle/lifecycle-manager.js +1 -2
- package/dist/lifecycle/scope-manager.d.ts +1 -2
- package/dist/lifecycle/scope-manager.js +1 -2
- package/dist/metadata/metadata-keys.d.ts +1 -2
- package/dist/metadata/metadata-keys.js +1 -2
- package/dist/metadata/metadata-reader-token.d.ts +1 -2
- package/dist/metadata/metadata-reader-token.js +1 -2
- package/dist/metadata/metadata-types.d.ts +1 -2
- package/dist/metadata/metadata-types.js +1 -2
- package/dist/metadata/symbol-metadata-reader.d.ts +1 -2
- package/dist/metadata/symbol-metadata-reader.js +1 -2
- package/dist/metadata/verifying-metadata-reader.d.ts +1 -2
- package/dist/metadata/verifying-metadata-reader.js +1 -2
- package/dist/resolution/cache/activation-need.d.ts +1 -2
- package/dist/resolution/cache/activation-need.js +1 -2
- package/dist/resolution/cache/binding-lookup-cache.d.ts +1 -2
- package/dist/resolution/cache/binding-lookup-cache.js +1 -2
- package/dist/resolution/cache/class-introspector.d.ts +1 -2
- package/dist/resolution/cache/class-introspector.js +1 -2
- package/dist/resolution/context.d.ts +1 -2
- package/dist/resolution/context.js +1 -2
- package/dist/resolution/path/resolution-path.d.ts +1 -2
- package/dist/resolution/path/resolution-path.js +1 -2
- package/dist/resolution/plan/instantiation-plan.d.ts +1 -2
- package/dist/resolution/plan/instantiation-plan.js +1 -2
- package/dist/resolution/resolver.d.ts +1 -2
- package/dist/resolution/resolver.js +1 -2
- package/dist/resolution/select/binding-select.d.ts +1 -2
- package/dist/resolution/select/binding-select.js +1 -2
- package/dist/resolution/select/constraints.d.ts +1 -2
- package/dist/resolution/select/constraints.js +1 -2
- package/package.json +6 -58
- package/dist/ambient/active-container.d.ts.map +0 -1
- package/dist/ambient/active-container.js.map +0 -1
- package/dist/container/binding-builders.d.ts.map +0 -1
- package/dist/container/binding-builders.js.map +0 -1
- package/dist/container/container.d.ts.map +0 -1
- package/dist/container/container.js.map +0 -1
- package/dist/core/binding-scope.d.ts.map +0 -1
- package/dist/core/binding-scope.js.map +0 -1
- package/dist/core/binding.d.ts.map +0 -1
- package/dist/core/binding.js.map +0 -1
- package/dist/core/constraint-requirement.d.ts.map +0 -1
- package/dist/core/constraint-requirement.js.map +0 -1
- package/dist/core/constructor-type.d.ts.map +0 -1
- package/dist/core/constructor-type.js.map +0 -1
- package/dist/core/map-upsert.d.ts.map +0 -1
- package/dist/core/map-upsert.js.map +0 -1
- package/dist/core/module.d.ts.map +0 -1
- package/dist/core/module.js.map +0 -1
- package/dist/core/registry.d.ts.map +0 -1
- package/dist/core/registry.js.map +0 -1
- package/dist/core/tag.d.ts.map +0 -1
- package/dist/core/tag.js.map +0 -1
- package/dist/core/token.d.ts.map +0 -1
- package/dist/core/token.js.map +0 -1
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/types.js.map +0 -1
- package/dist/decorators/inject.d.ts.map +0 -1
- package/dist/decorators/inject.js.map +0 -1
- package/dist/decorators/injectable.d.ts.map +0 -1
- package/dist/decorators/injectable.js.map +0 -1
- package/dist/decorators/lifecycle-decorators.d.ts.map +0 -1
- package/dist/decorators/lifecycle-decorators.js.map +0 -1
- package/dist/errors/diagnostics.d.ts.map +0 -1
- package/dist/errors/diagnostics.js.map +0 -1
- package/dist/errors/errors.d.ts.map +0 -1
- package/dist/errors/errors.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/injection/descriptor.d.ts.map +0 -1
- package/dist/injection/descriptor.js.map +0 -1
- package/dist/injection/resolve-options.d.ts.map +0 -1
- package/dist/injection/resolve-options.js.map +0 -1
- package/dist/introspection/dependency-graph.d.ts.map +0 -1
- package/dist/introspection/dependency-graph.js.map +0 -1
- package/dist/introspection/graph-adapters/cytoscape.d.ts.map +0 -1
- package/dist/introspection/graph-adapters/cytoscape.js.map +0 -1
- package/dist/introspection/graph-adapters/dot.d.ts.map +0 -1
- package/dist/introspection/graph-adapters/dot.js.map +0 -1
- package/dist/introspection/graph-adapters/mermaid.d.ts.map +0 -1
- package/dist/introspection/graph-adapters/mermaid.js.map +0 -1
- package/dist/introspection/graph-adapters/reactflow.d.ts.map +0 -1
- package/dist/introspection/graph-adapters/reactflow.js.map +0 -1
- package/dist/introspection/inspector.d.ts.map +0 -1
- package/dist/introspection/inspector.js.map +0 -1
- package/dist/lifecycle/lifecycle-manager.d.ts.map +0 -1
- package/dist/lifecycle/lifecycle-manager.js.map +0 -1
- package/dist/lifecycle/scope-manager.d.ts.map +0 -1
- package/dist/lifecycle/scope-manager.js.map +0 -1
- package/dist/metadata/metadata-keys.d.ts.map +0 -1
- package/dist/metadata/metadata-keys.js.map +0 -1
- package/dist/metadata/metadata-reader-token.d.ts.map +0 -1
- package/dist/metadata/metadata-reader-token.js.map +0 -1
- package/dist/metadata/metadata-types.d.ts.map +0 -1
- package/dist/metadata/metadata-types.js.map +0 -1
- package/dist/metadata/symbol-metadata-reader.d.ts.map +0 -1
- package/dist/metadata/symbol-metadata-reader.js.map +0 -1
- package/dist/metadata/verifying-metadata-reader.d.ts.map +0 -1
- package/dist/metadata/verifying-metadata-reader.js.map +0 -1
- package/dist/resolution/cache/activation-need.d.ts.map +0 -1
- package/dist/resolution/cache/activation-need.js.map +0 -1
- package/dist/resolution/cache/binding-lookup-cache.d.ts.map +0 -1
- package/dist/resolution/cache/binding-lookup-cache.js.map +0 -1
- package/dist/resolution/cache/class-introspector.d.ts.map +0 -1
- package/dist/resolution/cache/class-introspector.js.map +0 -1
- package/dist/resolution/context.d.ts.map +0 -1
- package/dist/resolution/context.js.map +0 -1
- package/dist/resolution/path/resolution-path.d.ts.map +0 -1
- package/dist/resolution/path/resolution-path.js.map +0 -1
- package/dist/resolution/plan/instantiation-plan.d.ts.map +0 -1
- package/dist/resolution/plan/instantiation-plan.js.map +0 -1
- package/dist/resolution/resolver.d.ts.map +0 -1
- package/dist/resolution/resolver.js.map +0 -1
- package/dist/resolution/select/binding-select.d.ts.map +0 -1
- package/dist/resolution/select/binding-select.js.map +0 -1
- package/dist/resolution/select/constraints.d.ts.map +0 -1
- package/dist/resolution/select/constraints.js.map +0 -1
- package/src/ambient/active-container.ts +0 -69
- package/src/container/binding-builders.ts +0 -337
- package/src/container/container.ts +0 -972
- package/src/core/binding-scope.ts +0 -15
- package/src/core/binding.ts +0 -505
- package/src/core/constraint-requirement.ts +0 -94
- package/src/core/constructor-type.ts +0 -18
- package/src/core/map-upsert.ts +0 -53
- package/src/core/module.ts +0 -117
- package/src/core/registry.ts +0 -319
- package/src/core/tag.ts +0 -212
- package/src/core/token.ts +0 -31
- package/src/core/types.ts +0 -149
- package/src/decorators/inject.ts +0 -101
- package/src/decorators/injectable.ts +0 -134
- package/src/decorators/lifecycle-decorators.ts +0 -43
- package/src/errors/diagnostics.ts +0 -45
- package/src/errors/errors.ts +0 -499
- package/src/index.ts +0 -139
- package/src/injection/descriptor.ts +0 -218
- package/src/injection/resolve-options.ts +0 -201
- package/src/introspection/dependency-graph.ts +0 -296
- package/src/introspection/graph-adapters/cytoscape.ts +0 -78
- package/src/introspection/graph-adapters/dot.ts +0 -32
- package/src/introspection/graph-adapters/mermaid.ts +0 -61
- package/src/introspection/graph-adapters/reactflow.ts +0 -84
- package/src/introspection/inspector.ts +0 -134
- package/src/lifecycle/lifecycle-manager.ts +0 -272
- package/src/lifecycle/scope-manager.ts +0 -158
- package/src/metadata/metadata-keys.ts +0 -28
- package/src/metadata/metadata-reader-token.ts +0 -10
- package/src/metadata/metadata-types.ts +0 -57
- package/src/metadata/symbol-metadata-reader.ts +0 -126
- package/src/metadata/verifying-metadata-reader.ts +0 -41
- package/src/resolution/cache/activation-need.ts +0 -87
- package/src/resolution/cache/binding-lookup-cache.ts +0 -169
- package/src/resolution/cache/class-introspector.ts +0 -256
- package/src/resolution/context.ts +0 -331
- package/src/resolution/path/resolution-path.ts +0 -167
- package/src/resolution/plan/instantiation-plan.ts +0 -592
- package/src/resolution/resolver.ts +0 -1654
- package/src/resolution/select/binding-select.ts +0 -207
- package/src/resolution/select/constraints.ts +0 -146
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
/** The `ResolutionContext` a factory is handed, and the callbacks the resolver answers it with. */
|
|
2
|
-
import type { Token } from "#/core/token";
|
|
3
|
-
import type {
|
|
4
|
-
BindingIdentifier,
|
|
5
|
-
BindingKind,
|
|
6
|
-
BindingScope,
|
|
7
|
-
ConstraintContext,
|
|
8
|
-
Constructor,
|
|
9
|
-
ResolutionFrame,
|
|
10
|
-
ResolutionContext,
|
|
11
|
-
ResolveOptions,
|
|
12
|
-
} from "#/core/types";
|
|
13
|
-
import type { BranchDepth, OwnedBranchStack } from "#/resolution/path/resolution-path";
|
|
14
|
-
import { UNOWNED_BRANCH } from "#/resolution/path/resolution-path";
|
|
15
|
-
|
|
16
|
-
// ── ResolutionContext implementation ─────────────────────────────────────────────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* The engine surface a resolution context calls back into to resolve further dependencies.
|
|
20
|
-
*
|
|
21
|
-
* @since 0.3.16-canary.0
|
|
22
|
-
*/
|
|
23
|
-
export interface ResolverCallbacks {
|
|
24
|
-
resolveFromContext<Value>(token: Token<Value> | Constructor<Value>, resolutionStack: Array<ResolutionFrame>): Value;
|
|
25
|
-
resolve<Value>(
|
|
26
|
-
token: Token<Value> | Constructor<Value>,
|
|
27
|
-
options: ResolveOptions | undefined,
|
|
28
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
29
|
-
): Value;
|
|
30
|
-
resolveAsyncFromContext<Value>(
|
|
31
|
-
token: Token<Value> | Constructor<Value>,
|
|
32
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
33
|
-
branchDepth: BranchDepth,
|
|
34
|
-
): Promise<Value>;
|
|
35
|
-
/** Not one of the eight `Value`-naming entry points: its caller is, and casts once. */
|
|
36
|
-
resolveAsyncFromCascade(token: Token<unknown> | Constructor): Promise<unknown>;
|
|
37
|
-
resolveAsync<Value>(
|
|
38
|
-
token: Token<Value> | Constructor<Value>,
|
|
39
|
-
options: ResolveOptions | undefined,
|
|
40
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
41
|
-
): Promise<Value>;
|
|
42
|
-
resolveOptional<Value>(
|
|
43
|
-
token: Token<Value> | Constructor<Value>,
|
|
44
|
-
options: ResolveOptions | undefined,
|
|
45
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
46
|
-
): Value | undefined;
|
|
47
|
-
resolveOptionalAsync<Value>(
|
|
48
|
-
token: Token<Value> | Constructor<Value>,
|
|
49
|
-
options: ResolveOptions | undefined,
|
|
50
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
51
|
-
): Promise<Value | undefined>;
|
|
52
|
-
resolveAll<Value>(
|
|
53
|
-
token: Token<Value> | Constructor<Value>,
|
|
54
|
-
options: ResolveOptions | undefined,
|
|
55
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
56
|
-
): Array<Value>;
|
|
57
|
-
resolveAllAsync<Value>(
|
|
58
|
-
token: Token<Value> | Constructor<Value>,
|
|
59
|
-
options: ResolveOptions | undefined,
|
|
60
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
61
|
-
): Promise<Array<Value>>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* The `ResolutionContext` handed to factories and hooks, backed by the engine's callbacks.
|
|
66
|
-
*
|
|
67
|
-
* @since 0.3.16-canary.0
|
|
68
|
-
*/
|
|
69
|
-
export class DefaultResolutionContext implements ResolutionContext {
|
|
70
|
-
#resolver: ResolverCallbacks;
|
|
71
|
-
#resolutionStack: Array<ResolutionFrame>;
|
|
72
|
-
#currentOptions: ResolveOptions | undefined;
|
|
73
|
-
|
|
74
|
-
constructor(
|
|
75
|
-
resolver: ResolverCallbacks,
|
|
76
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
77
|
-
currentOptions: ResolveOptions | undefined,
|
|
78
|
-
) {
|
|
79
|
-
this.#resolver = resolver;
|
|
80
|
-
this.#resolutionStack = resolutionStack;
|
|
81
|
-
this.#currentOptions = currentOptions;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
#graph: ConstraintContext | undefined;
|
|
85
|
-
|
|
86
|
-
get graph(): ConstraintContext {
|
|
87
|
-
if (this.#graph === undefined) {
|
|
88
|
-
this.#graph = new DefaultConstraintContext(this.#resolutionStack, this.#currentOptions);
|
|
89
|
-
}
|
|
90
|
-
return this.#graph;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
reset(
|
|
94
|
-
resolver: ResolverCallbacks,
|
|
95
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
96
|
-
currentOptions: ResolveOptions | undefined,
|
|
97
|
-
): void {
|
|
98
|
-
// Compared before storing: a pooled context lives long enough to be in old space, so storing a
|
|
99
|
-
// pointer costs a write barrier, and a sync resolve hands every depth the same stack.
|
|
100
|
-
if (this.#resolver !== resolver) {
|
|
101
|
-
this.#resolver = resolver;
|
|
102
|
-
}
|
|
103
|
-
if (this.#resolutionStack !== resolutionStack) {
|
|
104
|
-
this.#resolutionStack = resolutionStack;
|
|
105
|
-
}
|
|
106
|
-
this.#currentOptions = currentOptions;
|
|
107
|
-
if (this.#graph !== undefined) {
|
|
108
|
-
this.#graph = undefined;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
resolve<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value {
|
|
113
|
-
if (options === undefined) {
|
|
114
|
-
return this.#resolver.resolveFromContext(token, this.#resolutionStack);
|
|
115
|
-
}
|
|
116
|
-
return this.#resolver.resolve(token, options, this.#resolutionStack);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
resolveAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value> {
|
|
120
|
-
if (options === undefined) {
|
|
121
|
-
// UNOWNED_BRANCH: this frame's array is a sync stack it will pop, so the lane must copy it.
|
|
122
|
-
return this.#resolver.resolveAsyncFromContext(token, this.#resolutionStack, UNOWNED_BRANCH);
|
|
123
|
-
}
|
|
124
|
-
return this.#resolver.resolveAsync(token, options, this.#resolutionStack);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
resolveOptional<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value | undefined {
|
|
128
|
-
return this.#resolver.resolveOptional(token, options, this.#resolutionStack);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
resolveOptionalAsync<Value>(
|
|
132
|
-
token: Token<Value> | Constructor<Value>,
|
|
133
|
-
options?: ResolveOptions,
|
|
134
|
-
): Promise<Value | undefined> {
|
|
135
|
-
return this.#resolver.resolveOptionalAsync(token, options, this.#resolutionStack);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Array<Value> {
|
|
139
|
-
return this.#resolver.resolveAll(token, options, this.#resolutionStack);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Array<Value>> {
|
|
143
|
-
return this.#resolver.resolveAllAsync(token, options, this.#resolutionStack);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* One async level's resolution context, which is also its branch of the resolution stack.
|
|
149
|
-
*
|
|
150
|
-
* @remarks Separate from {@link DefaultResolutionContext} so the sync lane's pooled context keeps
|
|
151
|
-
* reading its stack as a plain field: only an async branch has a prefix to take, because an async
|
|
152
|
-
* level owns its branch of the stack.
|
|
153
|
-
*
|
|
154
|
-
* @since 0.5.0-canary.9
|
|
155
|
-
*/
|
|
156
|
-
export class AsyncLevelContext implements ResolutionContext {
|
|
157
|
-
readonly #resolver: ResolverCallbacks;
|
|
158
|
-
readonly #resolutionStack: OwnedBranchStack;
|
|
159
|
-
readonly #currentOptions: ResolveOptions | undefined;
|
|
160
|
-
readonly #branchDepth: BranchDepth;
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* @param resolver - the engine callbacks every request on this level goes through
|
|
164
|
-
* @param resolutionStack - this level's own branch; the depth is read off it rather than passed,
|
|
165
|
-
* so the two cannot disagree about where this level sits
|
|
166
|
-
* @param currentOptions - the options of the request that opened this level, if any
|
|
167
|
-
*/
|
|
168
|
-
constructor(
|
|
169
|
-
resolver: ResolverCallbacks,
|
|
170
|
-
resolutionStack: OwnedBranchStack,
|
|
171
|
-
currentOptions: ResolveOptions | undefined,
|
|
172
|
-
) {
|
|
173
|
-
this.#resolver = resolver;
|
|
174
|
-
this.#resolutionStack = resolutionStack;
|
|
175
|
-
this.#currentOptions = currentOptions;
|
|
176
|
-
this.#branchDepth = resolutionStack.length as BranchDepth;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
#graph: ConstraintContext | undefined;
|
|
180
|
-
#exactStackCache: Array<ResolutionFrame> | undefined;
|
|
181
|
-
|
|
182
|
-
get graph(): ConstraintContext {
|
|
183
|
-
if (this.#graph === undefined) {
|
|
184
|
-
this.#graph = new DefaultConstraintContext(this.#exactStack(), this.#currentOptions);
|
|
185
|
-
}
|
|
186
|
-
return this.#graph;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// The stack is append-only and a descendant may already have grown it past this level, so every
|
|
190
|
-
// caller but the async lane is handed this branch's prefix. It is fixed for the level's lifetime.
|
|
191
|
-
#exactStack(): Array<ResolutionFrame> {
|
|
192
|
-
return (this.#exactStackCache ??= this.#resolutionStack.slice(0, this.#branchDepth));
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
resolve<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value {
|
|
196
|
-
if (options === undefined) {
|
|
197
|
-
return this.#resolver.resolveFromContext(token, this.#exactStack());
|
|
198
|
-
}
|
|
199
|
-
return this.#resolver.resolve(token, options, this.#exactStack());
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
resolveAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value> {
|
|
203
|
-
if (options === undefined) {
|
|
204
|
-
// The hot lane: the resolver reads this branch by depth, so nothing is materialized.
|
|
205
|
-
return this.#resolver.resolveAsyncFromContext(token, this.#resolutionStack, this.#branchDepth);
|
|
206
|
-
}
|
|
207
|
-
return this.#resolver.resolveAsync(token, options, this.#exactStack());
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
resolveOptional<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value | undefined {
|
|
211
|
-
return this.#resolver.resolveOptional(token, options, this.#exactStack());
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
resolveOptionalAsync<Value>(
|
|
215
|
-
token: Token<Value> | Constructor<Value>,
|
|
216
|
-
options?: ResolveOptions,
|
|
217
|
-
): Promise<Value | undefined> {
|
|
218
|
-
return this.#resolver.resolveOptionalAsync(token, options, this.#exactStack());
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Array<Value> {
|
|
222
|
-
return this.#resolver.resolveAll(token, options, this.#exactStack());
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Array<Value>> {
|
|
226
|
-
return this.#resolver.resolveAllAsync(token, options, this.#exactStack());
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* The one context every level of an open synchronous factory cascade shares.
|
|
232
|
-
*
|
|
233
|
-
* @remarks It carries no per-level state at all: while the cascade is open, the resolver's stack
|
|
234
|
-
* *is* this level's ancestor chain, so nothing has to be allocated per level.
|
|
235
|
-
*
|
|
236
|
-
* @since 0.5.0-canary.9
|
|
237
|
-
*/
|
|
238
|
-
export class AsyncCascadeContext implements ResolutionContext {
|
|
239
|
-
readonly #resolver: ResolverCallbacks;
|
|
240
|
-
readonly #cascadeStack: Array<ResolutionFrame>;
|
|
241
|
-
|
|
242
|
-
constructor(resolver: ResolverCallbacks, cascadeStack: Array<ResolutionFrame>) {
|
|
243
|
-
this.#resolver = resolver;
|
|
244
|
-
this.#cascadeStack = cascadeStack;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
get graph(): ConstraintContext {
|
|
248
|
-
// Not memoized: this context outlives every level, so a cached graph would describe whichever
|
|
249
|
-
// level asked first. The cascade stack is only this level's ancestors while it is open.
|
|
250
|
-
return new DefaultConstraintContext(this.#cascadeStack, undefined);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
resolve<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value {
|
|
254
|
-
if (options === undefined) {
|
|
255
|
-
return this.#resolver.resolveFromContext(token, this.#cascadeStack);
|
|
256
|
-
}
|
|
257
|
-
return this.#resolver.resolve(token, options, this.#cascadeStack);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
resolveAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value> {
|
|
261
|
-
if (options === undefined) {
|
|
262
|
-
return this.#resolver.resolveAsyncFromCascade(token) as Promise<Value>;
|
|
263
|
-
}
|
|
264
|
-
return this.#resolver.resolveAsync(token, options, [...this.#cascadeStack]);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
resolveOptional<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value | undefined {
|
|
268
|
-
return this.#resolver.resolveOptional(token, options, this.#cascadeStack);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
resolveOptionalAsync<Value>(
|
|
272
|
-
token: Token<Value> | Constructor<Value>,
|
|
273
|
-
options?: ResolveOptions,
|
|
274
|
-
): Promise<Value | undefined> {
|
|
275
|
-
return this.#resolver.resolveOptionalAsync(token, options, [...this.#cascadeStack]);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Array<Value> {
|
|
279
|
-
return this.#resolver.resolveAll(token, options, this.#cascadeStack);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Array<Value>> {
|
|
283
|
-
return this.#resolver.resolveAllAsync(token, options, [...this.#cascadeStack]);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
class DefaultConstraintContext implements ConstraintContext {
|
|
288
|
-
readonly resolutionStack: ReadonlyArray<ResolutionFrame>;
|
|
289
|
-
readonly parent: ResolutionFrame | undefined;
|
|
290
|
-
readonly currentResolveOptions: Readonly<ResolveOptions> | undefined;
|
|
291
|
-
|
|
292
|
-
constructor(resolutionStack: ReadonlyArray<ResolutionFrame>, currentResolveOptions: ResolveOptions | undefined) {
|
|
293
|
-
this.resolutionStack = resolutionStack;
|
|
294
|
-
this.parent = resolutionStack.at(-1);
|
|
295
|
-
this.currentResolveOptions = currentResolveOptions;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Derived per read, never cached: the stack this context aliases may be live, and the names must
|
|
299
|
-
// report it as it stands — exactly as the dedicated name array did.
|
|
300
|
-
get resolutionPath(): ReadonlyArray<string> {
|
|
301
|
-
const names = new Array<string>(this.resolutionStack.length);
|
|
302
|
-
for (let index = 0; index < this.resolutionStack.length; index += 1) {
|
|
303
|
-
names[index] = this.resolutionStack[index]!.tokenName;
|
|
304
|
-
}
|
|
305
|
-
return names;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
#ancestors: ReadonlyArray<ResolutionFrame> | undefined;
|
|
309
|
-
|
|
310
|
-
get ancestors(): ReadonlyArray<ResolutionFrame> {
|
|
311
|
-
if (this.#ancestors === undefined) {
|
|
312
|
-
this.#ancestors = this.resolutionStack.length > 1 ? this.resolutionStack.slice(0, -1) : [];
|
|
313
|
-
}
|
|
314
|
-
return this.#ancestors;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Creates the resolution-stack frame for one in-flight resolve.
|
|
320
|
-
*
|
|
321
|
-
* @since 0.3.16-canary.0
|
|
322
|
-
*/
|
|
323
|
-
export function buildResolutionFrame(
|
|
324
|
-
tokenName: string,
|
|
325
|
-
scope: BindingScope,
|
|
326
|
-
bindingId: BindingIdentifier,
|
|
327
|
-
kind: BindingKind,
|
|
328
|
-
slot: ResolutionFrame["slot"],
|
|
329
|
-
): ResolutionFrame {
|
|
330
|
-
return { tokenName, scope, bindingId, kind, slot };
|
|
331
|
-
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import type { BindingIdentifier, ResolutionFrame } from "#/core/types";
|
|
2
|
-
/** Cycle-detection bookkeeping carried on the resolution stack itself. */
|
|
3
|
-
import { CircularDependencyError } from "#/errors/errors";
|
|
4
|
-
|
|
5
|
-
const RESOLUTION_SET_KEY: unique symbol = Symbol("di:resolution-set");
|
|
6
|
-
/**
|
|
7
|
-
* Where the cycle check switches from a linear frame scan to an attached Set.
|
|
8
|
-
*
|
|
9
|
-
* @remarks Measured rather than guessed: below this depth the linear scan wins, above it the Set does.
|
|
10
|
-
*
|
|
11
|
-
* @since 0.5.0-canary.7
|
|
12
|
-
*/
|
|
13
|
-
export const RESOLUTION_SET_THRESHOLD = 32;
|
|
14
|
-
type ResolutionStackWithSet = Array<ResolutionFrame> & { [RESOLUTION_SET_KEY]?: Set<BindingIdentifier> | undefined };
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* The token names along a stack plus the frame that closed the cycle — built only to throw.
|
|
18
|
-
*
|
|
19
|
-
* @since 0.6.0
|
|
20
|
-
*/
|
|
21
|
-
export function cycleNamesOf(resolutionStack: ReadonlyArray<ResolutionFrame>, closingName: string): Array<string> {
|
|
22
|
-
const names = new Array<string>(resolutionStack.length + 1);
|
|
23
|
-
for (let index = 0; index < resolutionStack.length; index += 1) {
|
|
24
|
-
names[index] = resolutionStack[index]!.tokenName;
|
|
25
|
-
}
|
|
26
|
-
names[resolutionStack.length] = closingName;
|
|
27
|
-
return names;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Marks a level as in-flight on this stack, throwing if its binding is already an ancestor.
|
|
32
|
-
*
|
|
33
|
-
* @remarks The check keys on binding identity — two distinct tokens may share a display name — and
|
|
34
|
-
* the names an error prints are derived from the frames at the throw site. Unmark by popping the
|
|
35
|
-
* stack plus `set?.delete(frame.bindingId)`. Sync only — the async lane never removes an entry, so
|
|
36
|
-
* it extends a branch instead; see {@link extendResolutionBranch}.
|
|
37
|
-
*
|
|
38
|
-
* @returns the membership set once the stack is deep enough to carry one, else `undefined`.
|
|
39
|
-
*
|
|
40
|
-
* @since 0.5.0-canary.7
|
|
41
|
-
*/
|
|
42
|
-
export function enterResolutionPath(
|
|
43
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
44
|
-
frame: ResolutionFrame,
|
|
45
|
-
): Set<BindingIdentifier> | undefined {
|
|
46
|
-
const stackWithSet = resolutionStack as ResolutionStackWithSet;
|
|
47
|
-
let resolutionSet = stackWithSet[RESOLUTION_SET_KEY];
|
|
48
|
-
// A live set mirrors the stack exactly, so a size that disagrees means it is holding ids of
|
|
49
|
-
// frames that unwound: the ones already on the stack when it attached were handed no set to
|
|
50
|
-
// delete from. Dropped rather than repaired, because the next deep frame rebuilds it.
|
|
51
|
-
if (resolutionSet !== undefined && resolutionSet.size !== resolutionStack.length) {
|
|
52
|
-
resolutionSet = undefined;
|
|
53
|
-
stackWithSet[RESOLUTION_SET_KEY] = undefined;
|
|
54
|
-
}
|
|
55
|
-
if (resolutionSet === undefined && resolutionStack.length >= RESOLUTION_SET_THRESHOLD) {
|
|
56
|
-
resolutionSet = new Set<BindingIdentifier>();
|
|
57
|
-
for (let index = 0; index < resolutionStack.length; index += 1) {
|
|
58
|
-
resolutionSet.add(resolutionStack[index]!.bindingId);
|
|
59
|
-
}
|
|
60
|
-
stackWithSet[RESOLUTION_SET_KEY] = resolutionSet;
|
|
61
|
-
}
|
|
62
|
-
if (resolutionSet === undefined) {
|
|
63
|
-
for (let index = 0; index < resolutionStack.length; index += 1) {
|
|
64
|
-
if (resolutionStack[index]!.bindingId === frame.bindingId) {
|
|
65
|
-
throw new CircularDependencyError(cycleNamesOf(resolutionStack, frame.tokenName));
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
} else if (resolutionSet.has(frame.bindingId)) {
|
|
69
|
-
throw new CircularDependencyError(cycleNamesOf(resolutionStack, frame.tokenName));
|
|
70
|
-
}
|
|
71
|
-
resolutionStack.push(frame);
|
|
72
|
-
resolutionSet?.add(frame.bindingId);
|
|
73
|
-
return resolutionSet;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
declare const BRANCH_BRAND: unique symbol;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* A resolution stack one async branch owns, so appending to it cannot disturb another branch.
|
|
80
|
-
*
|
|
81
|
-
* @remarks Only {@link extendResolutionBranch} mints one. That is what makes "may this lane append
|
|
82
|
-
* to this array" a question the compiler answers instead of a rule in a doc — a sync frame's stack,
|
|
83
|
-
* which that frame will pop, is a plain `Array<ResolutionFrame>` and cannot reach a level that owns
|
|
84
|
-
* its own.
|
|
85
|
-
*
|
|
86
|
-
* @since 0.5.0-canary.9
|
|
87
|
-
*/
|
|
88
|
-
export type OwnedBranchStack = Array<ResolutionFrame> & { readonly [BRANCH_BRAND]: true };
|
|
89
|
-
|
|
90
|
-
declare const BRANCH_DEPTH_BRAND: unique symbol;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* How many leading entries of a stack belong to one async branch.
|
|
94
|
-
*
|
|
95
|
-
* @remarks Branded so a bare number cannot be passed: a depth from anywhere but this branch silently
|
|
96
|
-
* re-parents a level.
|
|
97
|
-
*
|
|
98
|
-
* @since 0.5.0-canary.9
|
|
99
|
-
*/
|
|
100
|
-
export type OwnedBranchDepth = number & { readonly [BRANCH_DEPTH_BRAND]: true };
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* A stack no async branch owns yet, so its first extension must copy rather than append.
|
|
104
|
-
*
|
|
105
|
-
* @since 0.5.0-canary.9
|
|
106
|
-
*/
|
|
107
|
-
export const UNOWNED_BRANCH = -1;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* How far into a stack one extension may reach: this branch's own depth, or nobody's.
|
|
111
|
-
*
|
|
112
|
-
* @remarks A union rather than a sentinel hidden inside the branded number, so the two cases are
|
|
113
|
-
* visible at every signature that takes one and `=== UNOWNED_BRANCH` narrows to the owned case.
|
|
114
|
-
*
|
|
115
|
-
* @since 0.5.0-canary.9
|
|
116
|
-
*/
|
|
117
|
-
export type BranchDepth = OwnedBranchDepth | typeof UNOWNED_BRANCH;
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* The depth a chain's first level extends from, over an array its caller just minted.
|
|
121
|
-
*
|
|
122
|
-
* @since 0.5.0-canary.9
|
|
123
|
-
*/
|
|
124
|
-
export const ROOT_BRANCH = 0 as OwnedBranchDepth;
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* A branch's own depth: the length its stack had when this level took it.
|
|
128
|
-
*
|
|
129
|
-
* @since 0.5.0-canary.9
|
|
130
|
-
*/
|
|
131
|
-
export function branchDepthOf(branch: OwnedBranchStack): OwnedBranchDepth {
|
|
132
|
-
return branch.length as OwnedBranchDepth;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Extends one branch of an append-only stack, throwing if the binding is already an ancestor.
|
|
137
|
-
*
|
|
138
|
-
* @remarks The check compares binding ids on the frames; the names an error prints are derived at
|
|
139
|
-
* the throw site. Appends in place while this branch still owns the next slot, and copies its own
|
|
140
|
-
* prefix once a sibling has claimed it. Nothing is ever removed, so no async level has to observe
|
|
141
|
-
* its own settlement to unwind.
|
|
142
|
-
*
|
|
143
|
-
* @since 0.5.0-canary.9
|
|
144
|
-
*/
|
|
145
|
-
export function extendResolutionBranch(
|
|
146
|
-
resolutionStack: Array<ResolutionFrame>,
|
|
147
|
-
branchDepth: BranchDepth,
|
|
148
|
-
frame: ResolutionFrame,
|
|
149
|
-
): OwnedBranchStack {
|
|
150
|
-
const depth = branchDepth === UNOWNED_BRANCH ? resolutionStack.length : branchDepth;
|
|
151
|
-
for (let index = 0; index < depth; index += 1) {
|
|
152
|
-
if (resolutionStack[index]!.bindingId === frame.bindingId) {
|
|
153
|
-
throw new CircularDependencyError(cycleNamesOf(resolutionStack.slice(0, depth), frame.tokenName));
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// An unowned array belongs to a sync frame that will pop it, or carries a membership Set this
|
|
157
|
-
// lane cannot keep true; copying is what makes the branch's own appends safe.
|
|
158
|
-
if (branchDepth === resolutionStack.length) {
|
|
159
|
-
// The sole mint: appending in place needs a depth that came from a branch already owned, or
|
|
160
|
-
// ROOT_BRANCH over an array its caller minted for this chain alone.
|
|
161
|
-
resolutionStack.push(frame);
|
|
162
|
-
return resolutionStack as OwnedBranchStack;
|
|
163
|
-
}
|
|
164
|
-
const branch = resolutionStack.slice(0, depth);
|
|
165
|
-
branch.push(frame);
|
|
166
|
-
return branch as OwnedBranchStack;
|
|
167
|
-
}
|