@codefast/di 0.9.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +165 -0
- package/README.md +6 -5
- package/dist/ambient/active-container.d.ts +14 -4
- package/dist/ambient/active-container.js +22 -1
- package/dist/container/binding-builders.d.ts +35 -13
- package/dist/container/binding-builders.js +174 -97
- package/dist/container/container.d.ts +10 -10
- package/dist/container/container.js +53 -36
- package/dist/core/binding-scope.d.ts +2 -2
- package/dist/core/binding.d.ts +42 -49
- package/dist/core/binding.js +12 -38
- package/dist/core/constraint-requirement.d.ts +1 -1
- package/dist/core/module.d.ts +3 -3
- package/dist/core/registry.d.ts +52 -9
- package/dist/core/registry.js +376 -162
- package/dist/core/state-epoch.d.ts +16 -0
- package/dist/core/state-epoch.js +21 -0
- package/dist/core/token.d.ts +1 -1
- package/dist/core/types.d.ts +12 -9
- package/dist/decorators/inject.d.ts +3 -3
- package/dist/decorators/inject.js +5 -5
- package/dist/decorators/injectable.d.ts +2 -2
- package/dist/decorators/injectable.js +2 -2
- package/dist/decorators/lifecycle-decorators.js +2 -2
- package/dist/errors/diagnostics.d.ts +2 -0
- package/dist/errors/errors.d.ts +29 -3
- package/dist/errors/errors.js +34 -2
- package/dist/index.d.ts +35 -35
- package/dist/index.js +19 -19
- package/dist/injection/descriptor.d.ts +9 -7
- package/dist/injection/descriptor.js +3 -1
- package/dist/injection/resolve-options.d.ts +9 -3
- package/dist/injection/resolve-options.js +17 -1
- package/dist/introspection/dependency-graph.d.ts +3 -3
- package/dist/introspection/dependency-graph.js +15 -10
- package/dist/introspection/graph-adapters/cytoscape.d.ts +1 -1
- package/dist/introspection/graph-adapters/dot.d.ts +1 -1
- package/dist/introspection/graph-adapters/mermaid.d.ts +1 -1
- package/dist/introspection/graph-adapters/reactflow.d.ts +1 -1
- package/dist/introspection/inspector.d.ts +7 -5
- package/dist/introspection/inspector.js +13 -27
- package/dist/lifecycle/lifecycle-manager.d.ts +4 -4
- package/dist/lifecycle/lifecycle-manager.js +13 -11
- package/dist/lifecycle/scope-manager.d.ts +2 -2
- package/dist/lifecycle/scope-manager.js +4 -4
- package/dist/metadata/metadata-reader-token.d.ts +2 -2
- package/dist/metadata/metadata-reader-token.js +1 -1
- package/dist/metadata/metadata-types.d.ts +3 -3
- package/dist/metadata/symbol-metadata-reader.d.ts +3 -3
- package/dist/metadata/symbol-metadata-reader.js +1 -1
- package/dist/metadata/verifying-metadata-reader.d.ts +1 -1
- package/dist/metadata/verifying-metadata-reader.js +2 -2
- package/dist/resolution/cache/activation-need.d.ts +6 -4
- package/dist/resolution/cache/activation-need.js +13 -6
- package/dist/resolution/cache/binding-lookup-cache.d.ts +39 -6
- package/dist/resolution/cache/binding-lookup-cache.js +97 -13
- package/dist/resolution/cache/class-introspector.d.ts +6 -6
- package/dist/resolution/cache/class-introspector.js +82 -69
- package/dist/resolution/context.d.ts +11 -11
- package/dist/resolution/context.js +1 -1
- package/dist/resolution/path/resolution-path.d.ts +1 -1
- package/dist/resolution/path/resolution-path.js +1 -1
- package/dist/resolution/plan/instantiation-plan.d.ts +16 -4
- package/dist/resolution/plan/instantiation-plan.js +160 -69
- package/dist/resolution/plan/plan-codegen.d.ts +100 -0
- package/dist/resolution/plan/plan-codegen.js +185 -0
- package/dist/resolution/resolver.d.ts +26 -16
- package/dist/resolution/resolver.js +401 -147
- package/dist/resolution/select/binding-select.d.ts +6 -5
- package/dist/resolution/select/binding-select.js +17 -11
- package/dist/resolution/select/constraints.d.ts +3 -3
- package/dist/resolution/select/constraints.js +4 -4
- package/package.json +11 -3
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @remarks Metadata cannot change once a class is defined, so nothing here needs version stamping.
|
|
5
5
|
*/
|
|
6
|
-
import { runWithAmbientResolution } from "
|
|
7
|
-
import { InvalidMetadataError } from "
|
|
6
|
+
import { constructWithAmbientResolution, runWithAmbientResolution } from "#ambient/active-container";
|
|
7
|
+
import { InvalidMetadataError } from "#errors/errors";
|
|
8
8
|
// Verified pairs, not verified classes: two readers may disagree about the same class, and a reader
|
|
9
9
|
// that goes out of scope takes its record with it.
|
|
10
10
|
const verifiedTargets = new WeakMap();
|
|
@@ -21,6 +21,20 @@ function markVerified(cache, reader, target) {
|
|
|
21
21
|
}
|
|
22
22
|
verified.add(target);
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Runs `validate` against a reader's metadata the first time this process sees the pair, then remembers it.
|
|
26
|
+
*
|
|
27
|
+
* @remarks An absent metadata answer needs no check; a verified pair is returned untouched, so the
|
|
28
|
+
* shape assertion runs once per `(reader, target)` rather than per container.
|
|
29
|
+
*/
|
|
30
|
+
function verifyOnce(cache, reader, target, metadata, validate) {
|
|
31
|
+
if (metadata === undefined || isVerified(cache, reader, target)) {
|
|
32
|
+
return metadata;
|
|
33
|
+
}
|
|
34
|
+
validate(metadata);
|
|
35
|
+
markVerified(cache, reader, target);
|
|
36
|
+
return metadata;
|
|
37
|
+
}
|
|
24
38
|
/**
|
|
25
39
|
* A reader's constructor metadata for a class, verified the first time this process asks.
|
|
26
40
|
*
|
|
@@ -31,16 +45,9 @@ function markVerified(cache, reader, target) {
|
|
|
31
45
|
* @since 0.6.0
|
|
32
46
|
*/
|
|
33
47
|
export function verifyConstructorMetadata(reader, target) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
if (isVerified(verifiedTargets, reader, target)) {
|
|
39
|
-
return metadata;
|
|
40
|
-
}
|
|
41
|
-
assertConstructorMetadata(metadata, target);
|
|
42
|
-
markVerified(verifiedTargets, reader, target);
|
|
43
|
-
return metadata;
|
|
48
|
+
return verifyOnce(verifiedTargets, reader, target, reader.getConstructorMetadata(target), (metadata) => {
|
|
49
|
+
assertConstructorMetadata(metadata, target);
|
|
50
|
+
});
|
|
44
51
|
}
|
|
45
52
|
/**
|
|
46
53
|
* Verifies what a reader claims about a class, since a `MetadataReader` is a public seam.
|
|
@@ -81,29 +88,25 @@ export function assertConstructorMetadata(metadata, target) {
|
|
|
81
88
|
* @since 0.6.0
|
|
82
89
|
*/
|
|
83
90
|
export function verifyLifecycleMetadata(reader, target) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
if (typeof metadata !== "object" || metadata === null) {
|
|
89
|
-
throw new InvalidMetadataError(target.name, `lifecycle metadata: expected an object, received ${typeof metadata}`);
|
|
90
|
-
}
|
|
91
|
-
for (const phase of ["postConstruct", "preDestroy"]) {
|
|
92
|
-
const methods = Reflect.get(metadata, phase);
|
|
93
|
-
if (methods === undefined) {
|
|
94
|
-
continue;
|
|
91
|
+
return verifyOnce(verifiedLifecycleTargets, reader, target, reader.getLifecycleMetadata(target), (metadata) => {
|
|
92
|
+
if (typeof metadata !== "object" || metadata === null) {
|
|
93
|
+
throw new InvalidMetadataError(target.name, `lifecycle metadata: expected an object, received ${typeof metadata}`);
|
|
95
94
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
for (const phase of ["postConstruct", "preDestroy"]) {
|
|
96
|
+
const methods = Reflect.get(metadata, phase);
|
|
97
|
+
if (methods === undefined) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (!Array.isArray(methods)) {
|
|
101
|
+
throw new InvalidMetadataError(target.name, `lifecycle metadata: ${phase} is not an array`);
|
|
102
|
+
}
|
|
103
|
+
for (const [position, name] of methods.entries()) {
|
|
104
|
+
if (typeof name !== "string") {
|
|
105
|
+
throw new InvalidMetadataError(target.name, `lifecycle metadata: ${phase}[${String(position)}] is not a string`);
|
|
106
|
+
}
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
|
-
}
|
|
105
|
-
markVerified(verifiedLifecycleTargets, reader, target);
|
|
106
|
-
return metadata;
|
|
109
|
+
});
|
|
107
110
|
}
|
|
108
111
|
/**
|
|
109
112
|
* A reader's accessor metadata for a class, verified the first time this process asks.
|
|
@@ -111,32 +114,37 @@ export function verifyLifecycleMetadata(reader, target) {
|
|
|
111
114
|
* @since 0.6.0
|
|
112
115
|
*/
|
|
113
116
|
export function verifyAccessorMetadata(reader, target) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
if (!Array.isArray(metadata)) {
|
|
119
|
-
throw new InvalidMetadataError(target.name, "accessor metadata: expected an array");
|
|
120
|
-
}
|
|
121
|
-
for (const [position, entry] of metadata.entries()) {
|
|
122
|
-
if (typeof entry !== "object" || entry === null) {
|
|
123
|
-
throw new InvalidMetadataError(target.name, `accessor metadata: [${String(position)}] is not an object`);
|
|
124
|
-
}
|
|
125
|
-
const key = Reflect.get(entry, "key");
|
|
126
|
-
if (typeof key !== "string" && typeof key !== "symbol") {
|
|
127
|
-
throw new InvalidMetadataError(target.name, `accessor metadata: [${String(position)}].key is not a string or symbol`);
|
|
117
|
+
return verifyOnce(verifiedAccessorTargets, reader, target, reader.getAccessorMetadata?.(target), (metadata) => {
|
|
118
|
+
if (!Array.isArray(metadata)) {
|
|
119
|
+
throw new InvalidMetadataError(target.name, "accessor metadata: expected an array");
|
|
128
120
|
}
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
121
|
+
for (const [position, entry] of metadata.entries()) {
|
|
122
|
+
if (typeof entry !== "object" || entry === null) {
|
|
123
|
+
throw new InvalidMetadataError(target.name, `accessor metadata: [${String(position)}] is not an object`);
|
|
124
|
+
}
|
|
125
|
+
const key = Reflect.get(entry, "key");
|
|
126
|
+
if (typeof key !== "string" && typeof key !== "symbol") {
|
|
127
|
+
throw new InvalidMetadataError(target.name, `accessor metadata: [${String(position)}].key is not a string or symbol`);
|
|
128
|
+
}
|
|
129
|
+
const descriptor = Reflect.get(entry, "descriptor");
|
|
130
|
+
if (typeof descriptor !== "object" || descriptor === null) {
|
|
131
|
+
throw new InvalidMetadataError(target.name, `accessor metadata: [${String(position)}].descriptor is not an object`);
|
|
132
|
+
}
|
|
133
|
+
const dependency = Reflect.get(descriptor, "token");
|
|
134
|
+
if (typeof dependency !== "object" && typeof dependency !== "function") {
|
|
135
|
+
throw new InvalidMetadataError(target.name, `accessor metadata: [${String(position)}].descriptor.token is not a token or a class`);
|
|
136
|
+
}
|
|
136
137
|
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const cachesByReader = new WeakMap();
|
|
141
|
+
function cachesFor(reader) {
|
|
142
|
+
let caches = cachesByReader.get(reader);
|
|
143
|
+
if (caches === undefined) {
|
|
144
|
+
caches = { constructorMetadata: undefined, hasPostConstruct: undefined, needsActiveContainer: undefined };
|
|
145
|
+
cachesByReader.set(reader, caches);
|
|
146
|
+
}
|
|
147
|
+
return caches;
|
|
140
148
|
}
|
|
141
149
|
/**
|
|
142
150
|
* A per-class cache of constructor metadata and the activation facts derived from it.
|
|
@@ -144,24 +152,25 @@ export function verifyAccessorMetadata(reader, target) {
|
|
|
144
152
|
* @since 0.5.0-canary.8
|
|
145
153
|
*/
|
|
146
154
|
export class ClassIntrospector {
|
|
147
|
-
|
|
148
|
-
// to constants, factories or aliases never introspects one.
|
|
149
|
-
#constructorMetadata;
|
|
150
|
-
#hasPostConstruct;
|
|
151
|
-
#needsActiveContainer;
|
|
155
|
+
#caches;
|
|
152
156
|
#reader;
|
|
153
157
|
#container;
|
|
154
|
-
constructor(reader, container) {
|
|
158
|
+
constructor(reader, container, inherited) {
|
|
159
|
+
this.#caches = inherited !== undefined && inherited.#reader === reader ? inherited.#caches : undefined;
|
|
155
160
|
this.#reader = reader;
|
|
156
161
|
this.#container = container;
|
|
157
162
|
}
|
|
163
|
+
#shared() {
|
|
164
|
+
return (this.#caches ??= cachesFor(this.#reader));
|
|
165
|
+
}
|
|
158
166
|
constructorMetadata(target) {
|
|
159
|
-
const
|
|
167
|
+
const caches = this.#shared();
|
|
168
|
+
const cached = caches.constructorMetadata?.get(target);
|
|
160
169
|
if (cached !== undefined) {
|
|
161
170
|
return cached === null ? undefined : cached;
|
|
162
171
|
}
|
|
163
172
|
const metadata = this.#reader.getConstructorMetadata(target);
|
|
164
|
-
(
|
|
173
|
+
(caches.constructorMetadata ??= new WeakMap()).set(target, metadata ?? null);
|
|
165
174
|
return metadata;
|
|
166
175
|
}
|
|
167
176
|
/**
|
|
@@ -170,18 +179,19 @@ export class ClassIntrospector {
|
|
|
170
179
|
* @remarks Callers treat unknown as "assume it does", so the first activation settles it.
|
|
171
180
|
*/
|
|
172
181
|
knownPostConstruct(target) {
|
|
173
|
-
return this.#hasPostConstruct?.get(target);
|
|
182
|
+
return this.#shared().hasPostConstruct?.get(target);
|
|
174
183
|
}
|
|
175
184
|
discoverPostConstruct(target) {
|
|
176
185
|
const lifecycle = this.#reader.getLifecycleMetadata(target);
|
|
177
|
-
(this.#hasPostConstruct ??= new WeakMap()).set(target, lifecycle !== undefined && lifecycle.postConstruct !== undefined && lifecycle.postConstruct.length > 0);
|
|
186
|
+
(this.#shared().hasPostConstruct ??= new WeakMap()).set(target, lifecycle !== undefined && lifecycle.postConstruct !== undefined && lifecycle.postConstruct.length > 0);
|
|
178
187
|
}
|
|
179
188
|
/** True when the class has accessor injection, which reads the container during construction. */
|
|
180
189
|
needsActiveContainer(target) {
|
|
181
|
-
|
|
190
|
+
const caches = this.#shared();
|
|
191
|
+
let needsActiveContainer = caches.needsActiveContainer?.get(target);
|
|
182
192
|
if (needsActiveContainer === undefined) {
|
|
183
193
|
needsActiveContainer = (this.#reader.getAccessorMetadata?.(target)?.length ?? 0) > 0;
|
|
184
|
-
(
|
|
194
|
+
(caches.needsActiveContainer ??= new WeakMap()).set(target, needsActiveContainer);
|
|
185
195
|
}
|
|
186
196
|
return needsActiveContainer;
|
|
187
197
|
}
|
|
@@ -190,6 +200,9 @@ export class ClassIntrospector {
|
|
|
190
200
|
if (!this.needsActiveContainer(target)) {
|
|
191
201
|
return new invokable(...deps);
|
|
192
202
|
}
|
|
193
|
-
|
|
203
|
+
if (resolution === undefined) {
|
|
204
|
+
return runWithAmbientResolution(this.#container, undefined, () => new invokable(...deps));
|
|
205
|
+
}
|
|
206
|
+
return constructWithAmbientResolution(this.#container, resolution, invokable, deps);
|
|
194
207
|
}
|
|
195
208
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The `ResolutionContext` a factory is handed, and the callbacks the resolver answers it with. */
|
|
2
|
-
import type { Token } from "
|
|
3
|
-
import type { BindingIdentifier, BindingKind, BindingScope, ConstraintContext, Constructor, ResolutionFrame, ResolutionContext, ResolveOptions } from "
|
|
4
|
-
import type { BranchDepth, OwnedBranchStack } from "
|
|
2
|
+
import type { Token } from "#core/token";
|
|
3
|
+
import type { BindingIdentifier, BindingKind, BindingScope, ConstraintContext, Constructor, ResolutionFrame, ResolutionContext, ResolveOptions } from "#core/types";
|
|
4
|
+
import type { BranchDepth, OwnedBranchStack } from "#resolution/path/resolution-path";
|
|
5
5
|
/**
|
|
6
6
|
* The engine surface a resolution context calls back into to resolve further dependencies.
|
|
7
7
|
*
|
|
@@ -16,8 +16,8 @@ export interface ResolverCallbacks {
|
|
|
16
16
|
resolveAsync<Value>(token: Token<Value> | Constructor<Value>, options: ResolveOptions | undefined, resolutionStack: Array<ResolutionFrame>): Promise<Value>;
|
|
17
17
|
resolveOptional<Value>(token: Token<Value> | Constructor<Value>, options: ResolveOptions | undefined, resolutionStack: Array<ResolutionFrame>): Value | undefined;
|
|
18
18
|
resolveOptionalAsync<Value>(token: Token<Value> | Constructor<Value>, options: ResolveOptions | undefined, resolutionStack: Array<ResolutionFrame>): Promise<Value | undefined>;
|
|
19
|
-
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options: ResolveOptions | undefined, resolutionStack: Array<ResolutionFrame>):
|
|
20
|
-
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options: ResolveOptions | undefined, resolutionStack: Array<ResolutionFrame>): Promise<
|
|
19
|
+
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options: ResolveOptions | undefined, resolutionStack: Array<ResolutionFrame>): ReadonlyArray<Value>;
|
|
20
|
+
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options: ResolveOptions | undefined, resolutionStack: Array<ResolutionFrame>): Promise<ReadonlyArray<Value>>;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* The `ResolutionContext` handed to factories and hooks, backed by the engine's callbacks.
|
|
@@ -33,8 +33,8 @@ export declare class DefaultResolutionContext implements ResolutionContext {
|
|
|
33
33
|
resolveAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value>;
|
|
34
34
|
resolveOptional<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value | undefined;
|
|
35
35
|
resolveOptionalAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value | undefined>;
|
|
36
|
-
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions):
|
|
37
|
-
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<
|
|
36
|
+
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): ReadonlyArray<Value>;
|
|
37
|
+
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<ReadonlyArray<Value>>;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
40
|
* One async level's resolution context, which is also its branch of the resolution stack.
|
|
@@ -59,8 +59,8 @@ export declare class AsyncLevelContext implements ResolutionContext {
|
|
|
59
59
|
resolveAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value>;
|
|
60
60
|
resolveOptional<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value | undefined;
|
|
61
61
|
resolveOptionalAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value | undefined>;
|
|
62
|
-
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions):
|
|
63
|
-
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<
|
|
62
|
+
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): ReadonlyArray<Value>;
|
|
63
|
+
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<ReadonlyArray<Value>>;
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
66
|
* The one context every level of an open synchronous factory cascade shares.
|
|
@@ -78,8 +78,8 @@ export declare class AsyncCascadeContext implements ResolutionContext {
|
|
|
78
78
|
resolveAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value>;
|
|
79
79
|
resolveOptional<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value | undefined;
|
|
80
80
|
resolveOptionalAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value | undefined>;
|
|
81
|
-
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions):
|
|
82
|
-
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<
|
|
81
|
+
resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): ReadonlyArray<Value>;
|
|
82
|
+
resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<ReadonlyArray<Value>>;
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
85
|
* Creates the resolution-stack frame for one in-flight resolve.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Cycle-detection bookkeeping carried on the resolution stack itself. */
|
|
2
|
-
import { CircularDependencyError } from "
|
|
2
|
+
import { CircularDependencyError } from "#errors/errors";
|
|
3
3
|
const RESOLUTION_SET_KEY = Symbol("di:resolution-set");
|
|
4
4
|
/**
|
|
5
5
|
* Where the cycle check switches from a linear frame scan to an attached Set.
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* @remarks A dependency the compiler cannot inline escapes to a resolver callback instead; the
|
|
5
5
|
* closure must stay callable for it, which is what bounds what may be inlined.
|
|
6
6
|
*/
|
|
7
|
-
import type { Binding } from "
|
|
8
|
-
import type {
|
|
9
|
-
import type {
|
|
10
|
-
import type {
|
|
7
|
+
import type { Binding } from "#core/binding";
|
|
8
|
+
import type { ConstructorInvocation } from "#core/constructor-type";
|
|
9
|
+
import type { Token } from "#core/token";
|
|
10
|
+
import type { Constructor, ResolutionFrame, ResolveOptions } from "#core/types";
|
|
11
|
+
import type { ConstructorMetadata } from "#metadata/metadata-types";
|
|
11
12
|
/**
|
|
12
13
|
* Compilation asked to retry later (class lifecycle metadata not discovered yet).
|
|
13
14
|
*
|
|
@@ -41,6 +42,11 @@ export interface InstantiationPlanHost {
|
|
|
41
42
|
/** Cached postConstruct presence — `undefined` until a runtime resolve discovers it. */
|
|
42
43
|
knownPostConstruct(target: Constructor): boolean | undefined;
|
|
43
44
|
needsActiveContainer(target: Constructor): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Constructs a class whose accessors resolve during construction, with the container ambient and
|
|
47
|
+
* the binding's frame on the path so an accessor that cycles back is still caught.
|
|
48
|
+
*/
|
|
49
|
+
constructWithAccessors(binding: Binding, target: ConstructorInvocation, deps: Array<unknown>): unknown;
|
|
44
50
|
getConstructorMetadata(target: Constructor): ConstructorMetadata | undefined;
|
|
45
51
|
/** Options-less lookup with alias hops folded; `null` when the fast lane can't answer. */
|
|
46
52
|
lookupDependencyEntry(token: Token<unknown> | Constructor): InstantiationPlanDependencyEntry | null;
|
|
@@ -54,6 +60,10 @@ export interface InstantiationPlanHost {
|
|
|
54
60
|
lookupPathIndependentEntry(token: Token<unknown> | Constructor, options: ResolveOptions): InstantiationPlanDependencyEntry | null;
|
|
55
61
|
/** The frame the interpreted path pushes for this binding, so escapes can replay it. */
|
|
56
62
|
getResolutionFrame(binding: Binding): ResolutionFrame;
|
|
63
|
+
/** Swaps a plan the host still holds for its successor; a plan the host has since dropped stays dropped. */
|
|
64
|
+
replacePlan(binding: Binding, current: () => unknown, next: () => unknown): void;
|
|
65
|
+
/** The async counterpart of {@link InstantiationPlanHost.replacePlan}, over the async plan map. */
|
|
66
|
+
replaceAsyncPlan(binding: Binding, current: () => unknown, next: () => unknown): void;
|
|
57
67
|
/** Runtime resolve for an escaped dependency, seeded with the ancestor frames above it. */
|
|
58
68
|
resolveEscaped(token: Token<unknown> | Constructor, options: ResolveOptions | undefined, arity: EscapeArity, resolutionStack: Array<ResolutionFrame>): unknown;
|
|
59
69
|
/** The async counterpart of {@link InstantiationPlanHost.resolveEscaped}, replaying the async dispatch. */
|
|
@@ -74,6 +84,8 @@ export type EscapeArity = "all" | "optional" | "single";
|
|
|
74
84
|
export declare class InstantiationPlanCompiler {
|
|
75
85
|
#private;
|
|
76
86
|
constructor(host: InstantiationPlanHost);
|
|
87
|
+
/** Plans this compiler has generated as functions of their own. */
|
|
88
|
+
get generatedPlanCount(): number;
|
|
77
89
|
compile(binding: Binding & {
|
|
78
90
|
kind: "class" | "resolved";
|
|
79
91
|
}): InstantiationPlanCompileResult;
|