@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.
Files changed (73) hide show
  1. package/CHANGELOG.md +165 -0
  2. package/README.md +6 -5
  3. package/dist/ambient/active-container.d.ts +14 -4
  4. package/dist/ambient/active-container.js +22 -1
  5. package/dist/container/binding-builders.d.ts +35 -13
  6. package/dist/container/binding-builders.js +174 -97
  7. package/dist/container/container.d.ts +10 -10
  8. package/dist/container/container.js +53 -36
  9. package/dist/core/binding-scope.d.ts +2 -2
  10. package/dist/core/binding.d.ts +42 -49
  11. package/dist/core/binding.js +12 -38
  12. package/dist/core/constraint-requirement.d.ts +1 -1
  13. package/dist/core/module.d.ts +3 -3
  14. package/dist/core/registry.d.ts +52 -9
  15. package/dist/core/registry.js +376 -162
  16. package/dist/core/state-epoch.d.ts +16 -0
  17. package/dist/core/state-epoch.js +21 -0
  18. package/dist/core/token.d.ts +1 -1
  19. package/dist/core/types.d.ts +12 -9
  20. package/dist/decorators/inject.d.ts +3 -3
  21. package/dist/decorators/inject.js +5 -5
  22. package/dist/decorators/injectable.d.ts +2 -2
  23. package/dist/decorators/injectable.js +2 -2
  24. package/dist/decorators/lifecycle-decorators.js +2 -2
  25. package/dist/errors/diagnostics.d.ts +2 -0
  26. package/dist/errors/errors.d.ts +29 -3
  27. package/dist/errors/errors.js +34 -2
  28. package/dist/index.d.ts +35 -35
  29. package/dist/index.js +19 -19
  30. package/dist/injection/descriptor.d.ts +9 -7
  31. package/dist/injection/descriptor.js +3 -1
  32. package/dist/injection/resolve-options.d.ts +9 -3
  33. package/dist/injection/resolve-options.js +17 -1
  34. package/dist/introspection/dependency-graph.d.ts +3 -3
  35. package/dist/introspection/dependency-graph.js +15 -10
  36. package/dist/introspection/graph-adapters/cytoscape.d.ts +1 -1
  37. package/dist/introspection/graph-adapters/dot.d.ts +1 -1
  38. package/dist/introspection/graph-adapters/mermaid.d.ts +1 -1
  39. package/dist/introspection/graph-adapters/reactflow.d.ts +1 -1
  40. package/dist/introspection/inspector.d.ts +7 -5
  41. package/dist/introspection/inspector.js +13 -27
  42. package/dist/lifecycle/lifecycle-manager.d.ts +4 -4
  43. package/dist/lifecycle/lifecycle-manager.js +13 -11
  44. package/dist/lifecycle/scope-manager.d.ts +2 -2
  45. package/dist/lifecycle/scope-manager.js +4 -4
  46. package/dist/metadata/metadata-reader-token.d.ts +2 -2
  47. package/dist/metadata/metadata-reader-token.js +1 -1
  48. package/dist/metadata/metadata-types.d.ts +3 -3
  49. package/dist/metadata/symbol-metadata-reader.d.ts +3 -3
  50. package/dist/metadata/symbol-metadata-reader.js +1 -1
  51. package/dist/metadata/verifying-metadata-reader.d.ts +1 -1
  52. package/dist/metadata/verifying-metadata-reader.js +2 -2
  53. package/dist/resolution/cache/activation-need.d.ts +6 -4
  54. package/dist/resolution/cache/activation-need.js +13 -6
  55. package/dist/resolution/cache/binding-lookup-cache.d.ts +39 -6
  56. package/dist/resolution/cache/binding-lookup-cache.js +97 -13
  57. package/dist/resolution/cache/class-introspector.d.ts +6 -6
  58. package/dist/resolution/cache/class-introspector.js +82 -69
  59. package/dist/resolution/context.d.ts +11 -11
  60. package/dist/resolution/context.js +1 -1
  61. package/dist/resolution/path/resolution-path.d.ts +1 -1
  62. package/dist/resolution/path/resolution-path.js +1 -1
  63. package/dist/resolution/plan/instantiation-plan.d.ts +16 -4
  64. package/dist/resolution/plan/instantiation-plan.js +160 -69
  65. package/dist/resolution/plan/plan-codegen.d.ts +100 -0
  66. package/dist/resolution/plan/plan-codegen.js +185 -0
  67. package/dist/resolution/resolver.d.ts +26 -16
  68. package/dist/resolution/resolver.js +401 -147
  69. package/dist/resolution/select/binding-select.d.ts +6 -5
  70. package/dist/resolution/select/binding-select.js +17 -11
  71. package/dist/resolution/select/constraints.d.ts +3 -3
  72. package/dist/resolution/select/constraints.js +4 -4
  73. 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 "#/ambient/active-container";
7
- import { InvalidMetadataError } from "#/errors/errors";
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
- const metadata = reader.getConstructorMetadata(target);
35
- if (metadata === undefined) {
36
- return undefined;
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
- const metadata = reader.getLifecycleMetadata(target);
85
- if (metadata === undefined || isVerified(verifiedLifecycleTargets, reader, target)) {
86
- return metadata;
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
- if (!Array.isArray(methods)) {
97
- throw new InvalidMetadataError(target.name, `lifecycle metadata: ${phase} is not an array`);
98
- }
99
- for (const [position, name] of methods.entries()) {
100
- if (typeof name !== "string") {
101
- throw new InvalidMetadataError(target.name, `lifecycle metadata: ${phase}[${String(position)}] is not a string`);
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
- const metadata = reader.getAccessorMetadata?.(target);
115
- if (metadata === undefined || isVerified(verifiedAccessorTargets, reader, target)) {
116
- return metadata;
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 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`);
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
- markVerified(verifiedAccessorTargets, reader, target);
139
- return metadata;
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
- // Unallocated until the container resolves its first class binding — a container bound entirely
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 cached = this.#constructorMetadata?.get(target);
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
- (this.#constructorMetadata ??= new WeakMap()).set(target, metadata ?? null);
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
- let needsActiveContainer = this.#needsActiveContainer?.get(target);
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
- (this.#needsActiveContainer ??= new WeakMap()).set(target, needsActiveContainer);
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
- return runWithAmbientResolution(this.#container, resolution, () => new invokable(...deps));
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 "#/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";
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>): Array<Value>;
20
- resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options: ResolveOptions | undefined, resolutionStack: Array<ResolutionFrame>): Promise<Array<Value>>;
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): Array<Value>;
37
- resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Array<Value>>;
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): Array<Value>;
63
- resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Array<Value>>;
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): Array<Value>;
82
- resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Array<Value>>;
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,4 +1,4 @@
1
- import { UNOWNED_BRANCH } from "#/resolution/path/resolution-path";
1
+ import { UNOWNED_BRANCH } from "#resolution/path/resolution-path";
2
2
  /**
3
3
  * The `ResolutionContext` handed to factories and hooks, backed by the engine's callbacks.
4
4
  *
@@ -1,4 +1,4 @@
1
- import type { BindingIdentifier, ResolutionFrame } from "#/core/types";
1
+ import type { BindingIdentifier, ResolutionFrame } from "#core/types";
2
2
  /**
3
3
  * Where the cycle check switches from a linear frame scan to an attached Set.
4
4
  *
@@ -1,5 +1,5 @@
1
1
  /** Cycle-detection bookkeeping carried on the resolution stack itself. */
2
- import { CircularDependencyError } from "#/errors/errors";
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 "#/core/binding";
8
- import type { Token } from "#/core/token";
9
- import type { Constructor, ResolutionFrame, ResolveOptions } from "#/core/types";
10
- import type { ConstructorMetadata } from "#/metadata/metadata-types";
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;