@codefast/di 0.3.14-canary.1 → 0.3.14

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 (65) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +42 -26
  3. package/dist/binding-scope.d.mts +11 -0
  4. package/dist/binding-scope.mjs +19 -0
  5. package/dist/binding-select.d.mts +8 -26
  6. package/dist/binding-select.mjs +56 -49
  7. package/dist/binding.d.mts +107 -335
  8. package/dist/binding.mjs +19 -332
  9. package/dist/constraints.d.mts +11 -29
  10. package/dist/constraints.mjs +32 -36
  11. package/dist/constructor-type.d.mts +17 -0
  12. package/dist/constructor-type.mjs +1 -0
  13. package/dist/container.d.mts +43 -122
  14. package/dist/container.mjs +667 -482
  15. package/dist/decorators/inject.d.mts +19 -50
  16. package/dist/decorators/inject.mjs +131 -93
  17. package/dist/decorators/injectable.d.mts +16 -37
  18. package/dist/decorators/injectable.mjs +47 -66
  19. package/dist/decorators/lifecycle-decorators.d.mts +2 -22
  20. package/dist/decorators/lifecycle-decorators.mjs +81 -37
  21. package/dist/dependency-graph.d.mts +24 -54
  22. package/dist/dependency-graph.mjs +51 -153
  23. package/dist/environment.d.mts +38 -12
  24. package/dist/environment.mjs +82 -16
  25. package/dist/errors.d.mts +70 -189
  26. package/dist/errors.mjs +92 -219
  27. package/dist/graph-adapters/cytoscape.d.mts +21 -7
  28. package/dist/graph-adapters/cytoscape.mjs +18 -35
  29. package/dist/graph-adapters/dot.d.mts +1 -4
  30. package/dist/graph-adapters/dot.mjs +6 -86
  31. package/dist/graph-adapters/reactflow.d.mts +26 -7
  32. package/dist/graph-adapters/reactflow.mjs +21 -72
  33. package/dist/graph-adapters/types.d.mts +2 -91
  34. package/dist/index.d.mts +16 -8
  35. package/dist/index.mjs +8 -5
  36. package/dist/inspector.d.mts +35 -74
  37. package/dist/inspector.mjs +61 -88
  38. package/dist/lifecycle.d.mts +20 -53
  39. package/dist/lifecycle.mjs +129 -99
  40. package/dist/metadata/metadata-keys.d.mts +9 -26
  41. package/dist/metadata/metadata-keys.mjs +7 -28
  42. package/dist/metadata/metadata-reader-token.d.mts +7 -0
  43. package/dist/metadata/metadata-reader-token.mjs +5 -0
  44. package/dist/metadata/metadata-types.d.mts +26 -75
  45. package/dist/metadata/symbol-metadata-reader.d.mts +10 -26
  46. package/dist/metadata/symbol-metadata-reader.mjs +32 -45
  47. package/dist/module.d.mts +30 -96
  48. package/dist/module.mjs +26 -72
  49. package/dist/registry.d.mts +32 -63
  50. package/dist/registry.mjs +131 -82
  51. package/dist/resolve-options.d.mts +18 -0
  52. package/dist/resolve-options.mjs +22 -0
  53. package/dist/resolver.d.mts +67 -190
  54. package/dist/resolver.mjs +715 -424
  55. package/dist/scope.d.mts +19 -106
  56. package/dist/scope.mjs +37 -196
  57. package/dist/token.d.mts +8 -22
  58. package/dist/token.mjs +9 -11
  59. package/dist/types.d.mts +48 -0
  60. package/dist/types.mjs +1 -0
  61. package/package.json +36 -14
  62. package/dist/metadata/param-registry.d.mts +0 -16
  63. package/dist/metadata/param-registry.mjs +0 -31
  64. package/dist/scope-validation.d.mts +0 -21
  65. package/dist/scope-validation.mjs +0 -35
package/dist/resolver.mjs CHANGED
@@ -1,457 +1,748 @@
1
- import { AsyncResolutionError, CircularDependencyError, InternalError, MissingMetadataError, NoMatchingBindingError, ScopeViolationError, TokenNotBoundError } from "./errors.mjs";
2
- import { filterMatchingBindings, registryKeyLabel, selectBindingForRegistry } from "./binding-select.mjs";
3
- import { isPromiseLike, runActivation, runActivationAsync, runPostConstruct, runPostConstructAsync } from "./lifecycle.mjs";
1
+ import { AsyncResolutionError, CircularDependencyError, InternalError, MissingMetadataError, MissingScopeContextError, NoMatchingBindingError, TokenNotBoundError } from "./errors.mjs";
2
+ import { selectAllBindings, selectBinding } from "./binding-select.mjs";
3
+ import { tokenName } from "./token.mjs";
4
+ import { DefaultResolutionContext, buildMaterializationFrame, runWithContainer } from "./environment.mjs";
5
+ import { injectableSlotToResolveOptions } from "./resolve-options.mjs";
4
6
  //#region src/resolver.ts
5
- /**
6
- * Converts a registry key + binding into a {@link MaterializationFrame} for the captive-dependency stack.
7
- */
8
- function bindingToMaterializationFrame(registryKey, binding) {
9
- return {
10
- registryKey,
11
- bindingId: binding.id,
12
- bindingKind: binding.kind,
13
- tags: binding.tags,
14
- scope: binding.scope
15
- };
16
- }
17
- /**
18
- * Stateless graph walker: selects a binding, checks for cycles and scope violations,
19
- * delegates instance caching to `ScopeManager`, and runs lifecycle hooks.
20
- *
21
- * Resolution algorithm (per token):
22
- * 1. Lookup all bindings for the registry key.
23
- * 2. Apply name/tag hint and `when()` constraint filtering.
24
- * 3. Circular-dependency check via a mutable `visiting` set (per call tree).
25
- * 4. Captive-dependency check via the `materializationStack`.
26
- * 5. Scope-cache hit → return cached instance.
27
- * 6. Scope-cache miss → `materialize` → `@postConstruct` → `onActivation` → cache.
28
- *
29
- * Used exclusively by `DefaultContainer`; not part of the public API.
30
- */
7
+ const RESOLUTION_SET_KEY = Symbol("di:resolution-set");
8
+ const RESOLUTION_SET_THRESHOLD = 32;
9
+ const EMPTY_STRING_LIST = [];
10
+ const EMPTY_FRAME_LIST = [];
11
+ const ROOT_CONSTRAINT_CONTEXT = {
12
+ resolutionPath: EMPTY_STRING_LIST,
13
+ materializationStack: EMPTY_FRAME_LIST,
14
+ parent: void 0,
15
+ ancestors: EMPTY_FRAME_LIST,
16
+ currentResolveHint: void 0
17
+ };
31
18
  var DependencyResolver = class {
32
- constructor(deps) {
33
- this.deps = deps;
34
- }
35
- /**
36
- * Entry point for synchronous single-binding resolution.
37
- *
38
- * @throws {@link TokenNotBoundError} — no binding registered for `key`, or a nested dependency is unbound.
39
- * @throws {@link NoMatchingBindingError} — a name/tag `hint` was given for `key` but no binding matched it.
40
- * @throws {@link InternalError} — multiple bindings matched for `key` after applying the hint (ambiguous).
41
- * @throws {@link CircularDependencyError} — `key` or a nested token appears twice on the resolution stack.
42
- * @throws {@link AsyncResolutionError} — an `async-dynamic` binding or async lifecycle/activation on the sync path.
43
- * @throws {@link ScopeViolationError} — captive dependency (singleton → scoped/transient).
44
- * @throws {@link MissingMetadataError} — `class` binding lacks injectable metadata when the reader requires it.
45
- */
46
- resolveRoot(key, hint) {
47
- return this.resolve(key, hint, [], /* @__PURE__ */ new Set(), []);
48
- }
49
- /**
50
- * Entry point for async single-binding resolution. Awaits `async-dynamic` factories
51
- * and async lifecycle hooks that would cause {@link AsyncResolutionError} on the sync path.
52
- *
53
- * @throws {@link TokenNotBoundError} — no binding registered for `key`, or a nested dependency is unbound.
54
- * @throws {@link NoMatchingBindingError} — a name/tag `hint` was given for `key` but no binding matched it.
55
- * @throws {@link InternalError} — multiple bindings matched for `key` after applying the hint (ambiguous).
56
- * @throws {@link CircularDependencyError} — `key` or a nested token appears twice on the resolution stack.
57
- * @throws {@link ScopeViolationError} — captive dependency (singleton → scoped/transient).
58
- * @throws {@link MissingMetadataError} — `class` binding lacks injectable metadata when the reader requires it.
59
- */
60
- resolveAsyncRoot(key, hint) {
61
- return this.resolveAsync(key, hint, [], /* @__PURE__ */ new Set(), []);
62
- }
63
- /**
64
- * Optional resolution for the **requested key only**: returns `undefined` when that key has no
65
- * bindings or every candidate is filtered out **without** a name/tag hint — without throwing
66
- * {@link TokenNotBoundError} for those cases. Instantiating the selected binding still runs the
67
- * normal sync resolution path for nested dependencies; an unregistered transitive dependency
68
- * throws {@link TokenNotBoundError} as usual.
69
- *
70
- * Behavioral rules:
71
- * 1. If the registry key is completely unbound → returns `undefined`.
72
- * 2. If no candidate survives constraint filtering (without a hint) → returns `undefined`.
73
- * 3. If a name/tag hint was provided but no binding matches it → throws {@link NoMatchingBindingError}.
74
- * 4. Still throws on: circular dependencies, async operations on the sync path,
75
- * scope violations, ambiguous multi-binding matches, and {@link TokenNotBoundError} when a
76
- * required nested dependency is unbound.
77
- */
78
- resolveOptionalRoot(key, hint) {
79
- const registryKey = key;
80
- const label = registryKeyLabel(key);
81
- const pathLabels = [label];
82
- const bindings = this.deps.lookup(registryKey);
83
- if (bindings === void 0 || bindings.length === 0) return;
84
- const candidates = filterMatchingBindings(bindings, hint, this.buildConstraintContext(pathLabels, [], hint));
85
- if (candidates.length === 0) {
86
- if (hint !== void 0 && (hint.name !== void 0 || hint.tag !== void 0)) throw new NoMatchingBindingError(label, hint, pathLabels);
87
- return;
88
- }
89
- if (candidates.length !== 1) throw new InternalError(`Ambiguous binding for "${label}": ${String(candidates.length)} candidates matched (resolution path: ${pathLabels.join(" -> ")})`);
90
- const binding = candidates[0];
91
- if (binding === void 0) throw new InternalError(`Internal: expected single binding candidate for "${label}" (resolution path: ${pathLabels.join(" -> ")})`);
92
- this.assertDependencyScopeAllowed(binding, pathLabels, []);
93
- if (binding.kind === "async-dynamic") throw new AsyncResolutionError(label, pathLabels, "encountered async-dynamic factory during synchronous resolution");
94
- const visiting = /* @__PURE__ */ new Set();
95
- visiting.add(registryKey);
19
+ _frameByBindingId = /* @__PURE__ */ new Map();
20
+ _syncResolutionContextPool = [];
21
+ _deepCycleMarks = /* @__PURE__ */ new Map();
22
+ _deepCycleGen = 0;
23
+ _deepActiveLevels = 0;
24
+ _deepSyncCtx;
25
+ _deepSyncCtxPath;
26
+ _deepAsyncCtx;
27
+ _deepAsyncCtxPath;
28
+ _deepAsyncActiveLevels = 0;
29
+ _classHasPostConstruct = /* @__PURE__ */ new WeakMap();
30
+ _classNeedsActiveContainer = /* @__PURE__ */ new WeakMap();
31
+ _classConstructorMetadata = /* @__PURE__ */ new WeakMap();
32
+ _activationNeedByBindingId = /* @__PURE__ */ new Map();
33
+ _activationCacheVersion = -1;
34
+ constructor(_registry, _scope, _lifecycle, _metadataReader, _container, _parent) {
35
+ this._registry = _registry;
36
+ this._scope = _scope;
37
+ this._lifecycle = _lifecycle;
38
+ this._metadataReader = _metadataReader;
39
+ this._container = _container;
40
+ this._parent = _parent;
41
+ }
42
+ _findBinding(token, hint, resolutionPath, materializationStack) {
43
+ if (hint === void 0) {
44
+ const fastDefaultBinding = this._registry.getFastDefault(token);
45
+ if (fastDefaultBinding !== void 0) return {
46
+ binding: fastDefaultBinding,
47
+ owner: this
48
+ };
49
+ }
50
+ if (hint?.name !== void 0 && hint.tag === void 0 && (hint.tags?.length ?? 0) === 0) {
51
+ const namedBinding = this._registry.getSimpleNamed(token, hint.name);
52
+ if (namedBinding !== void 0 && this._matchesBindingFast(namedBinding, hint, resolutionPath, materializationStack)) return {
53
+ binding: namedBinding,
54
+ owner: this
55
+ };
56
+ }
57
+ const bindings = this._registry.getAll(token);
58
+ if (bindings.length > 0) {
59
+ if (bindings.length === 1) {
60
+ const onlyBinding = bindings[0];
61
+ const isDefaultSlot = onlyBinding.slot.name === void 0 && onlyBinding.slot.tags.length === 0;
62
+ if (hint === void 0 && isDefaultSlot && onlyBinding.predicate === void 0) return {
63
+ binding: onlyBinding,
64
+ owner: this
65
+ };
66
+ if (this._matchesBindingFast(onlyBinding, hint, resolutionPath, materializationStack)) return {
67
+ binding: onlyBinding,
68
+ owner: this
69
+ };
70
+ }
71
+ const binding = selectBinding(bindings, hint, this._makeConstraintContext(resolutionPath, materializationStack, hint), this._getTokenName(token));
72
+ if (binding !== void 0) return {
73
+ binding,
74
+ owner: this
75
+ };
76
+ }
77
+ if (this._parent !== void 0) return this._parent._findBinding(token, hint, resolutionPath, materializationStack);
78
+ }
79
+ resolveFromContext(token, resolutionPath, materializationStack) {
80
+ const fastBinding = this._registry.getFastDefault(token);
81
+ if (fastBinding !== void 0) {
82
+ if (fastBinding.kind === "alias") return this.resolveFromContext(fastBinding.target, resolutionPath, materializationStack);
83
+ const scope = fastBinding.scope ?? "transient";
84
+ if (scope === "transient" && fastBinding.kind === "dynamic" && fastBinding.onActivation === void 0 && (this._lifecycle.activationVersion === 0 || !this._lifecycle.hasActivationHandlers(fastBinding.token))) return this._resolveTransientDynamicSyncFromContext(fastBinding, resolutionPath, materializationStack);
85
+ if (scope === "singleton" && this._scope.hasSingleton(fastBinding.id)) return this._scope.getSingleton(fastBinding.id);
86
+ if (scope === "scoped") {
87
+ if (!this._scope.isChild) throw new MissingScopeContextError(this._getTokenName(fastBinding.token));
88
+ if (this._scope.hasScoped(fastBinding.id)) return this._scope.getScoped(fastBinding.id);
89
+ }
90
+ return this._resolveBinding(fastBinding, void 0, resolutionPath, materializationStack);
91
+ }
92
+ return this.resolve(token, void 0, resolutionPath, materializationStack);
93
+ }
94
+ resolve(token, hint, resolutionPath, materializationStack) {
95
+ const found = this._findBinding(token, hint, resolutionPath, materializationStack);
96
+ if (found === void 0) {
97
+ if (this._registry.getAll(token).length > 0) throw new NoMatchingBindingError(this._getTokenName(token), hint ?? {}, this._getAvailableSlots(token));
98
+ throw new TokenNotBoundError(this._getTokenName(token));
99
+ }
100
+ const { binding, owner } = found;
101
+ if (binding.kind === "alias") return this.resolve(binding.target, hint, resolutionPath, materializationStack);
102
+ if ((binding.scope ?? "transient") === "singleton" && owner !== this) return owner._resolveBinding(binding, hint, resolutionPath, materializationStack);
103
+ return this._resolveBinding(binding, hint, resolutionPath, materializationStack);
104
+ }
105
+ _resolveBinding(binding, hint, resolutionPath, materializationStack) {
106
+ if (binding.kind === "constant" && binding.onActivation === void 0 && !this._lifecycle.hasActivationHandlers(binding.token)) return binding.value;
107
+ const scope = binding.scope ?? "transient";
108
+ if (scope === "singleton") {
109
+ if (this._scope.hasSingleton(binding.id)) return this._scope.getSingleton(binding.id);
110
+ }
111
+ if (scope === "scoped") {
112
+ if (!this._scope.isChild) throw new MissingScopeContextError(this._getTokenName(binding.token));
113
+ if (this._scope.hasScoped(binding.id)) return this._scope.getScoped(binding.id);
114
+ }
115
+ const frame = this._getMaterializationFrame(binding);
116
+ const tName = frame.tokenName;
117
+ const pathWithSet = resolutionPath;
118
+ let resolutionSet = pathWithSet[RESOLUTION_SET_KEY];
119
+ if (resolutionSet === void 0 && resolutionPath.length >= RESOLUTION_SET_THRESHOLD) {
120
+ resolutionSet = new Set(resolutionPath);
121
+ pathWithSet[RESOLUTION_SET_KEY] = resolutionSet;
122
+ }
123
+ if (resolutionSet !== void 0 ? resolutionSet.has(tName) : resolutionPath.includes(tName)) throw new CircularDependencyError([...resolutionPath, tName]);
124
+ resolutionPath.push(tName);
125
+ resolutionSet?.add(tName);
126
+ materializationStack.push(frame);
127
+ const needsActivation = this._needsActivation(binding);
128
+ if (!needsActivation && scope === "transient" && binding.kind === "dynamic") {
129
+ const resolutionCtx = this._acquireSyncResolutionContext(resolutionPath, materializationStack, hint);
130
+ try {
131
+ const dynamicResult = binding.factory(resolutionCtx);
132
+ if (dynamicResult instanceof Promise) throw new AsyncResolutionError(tokenName(binding.token), tokenName(binding.token));
133
+ materializationStack.pop();
134
+ resolutionPath.pop();
135
+ resolutionSet?.delete(tName);
136
+ return dynamicResult;
137
+ } catch (error) {
138
+ materializationStack.pop();
139
+ resolutionPath.pop();
140
+ resolutionSet?.delete(tName);
141
+ throw error;
142
+ }
143
+ }
96
144
  try {
97
- return this.instantiateBinding(binding, registryKey, hint, pathLabels, visiting, []);
145
+ const resolutionCtx = needsActivation || this._requiresResolutionContext(binding) ? this._acquireSyncResolutionContext(resolutionPath, materializationStack, hint) : void 0;
146
+ const instance = this._instantiateSync(binding, resolutionCtx, resolutionPath, materializationStack, hint);
147
+ let shouldActivate = needsActivation;
148
+ if (binding.kind === "class" && this._classHasPostConstruct.get(binding.target) === void 0) {
149
+ this._refreshClassPostConstructCache(binding.target);
150
+ this._activationNeedByBindingId.delete(binding.id);
151
+ shouldActivate = this._needsActivation(binding);
152
+ }
153
+ const activated = shouldActivate ? this._lifecycle.runActivationSync(resolutionCtx, binding, instance, this._metadataReader) : instance;
154
+ if (scope === "singleton") this._scope.setSingleton(binding.id, activated);
155
+ else if (scope === "scoped") this._scope.setScoped(binding.id, activated);
156
+ return activated;
98
157
  } finally {
99
- visiting.delete(registryKey);
100
- }
101
- }
102
- /**
103
- * Resolves every matching binding for `key` synchronously into an array.
104
- * Returns an empty array when no bindings exist (does not throw).
105
- *
106
- * @throws {@link AsyncResolutionError} — any candidate is `async-dynamic`.
107
- * @throws {@link NoMatchingBindingError} — hint was specified but no binding matched it.
108
- * @throws {@link TokenNotBoundError} — nested dependency unbound (same as {@link resolveRoot}).
109
- * @throws {@link CircularDependencyError} — cycle while materializing a candidate.
110
- * @throws {@link ScopeViolationError} — captive dependency during materialization.
111
- * @throws {@link MissingMetadataError} — class binding lacks injectable metadata when required.
112
- */
113
- resolveAllRoot(key, hint) {
114
- return this.resolveAll(key, hint, [], /* @__PURE__ */ new Set(), []);
115
- }
116
- /**
117
- * Async counterpart of {@link resolveAllRoot}: resolves every matching binding for `key`,
118
- * awaiting `async-dynamic` factories. Returns an empty array when no bindings exist.
119
- *
120
- * @throws {@link NoMatchingBindingError} — hint was specified but no binding matched it.
121
- * @throws {@link TokenNotBoundError} — nested dependency unbound (same as {@link resolveAsyncRoot}).
122
- * @throws {@link CircularDependencyError} — cycle while materializing a candidate.
123
- * @throws {@link ScopeViolationError} — captive dependency during materialization.
124
- * @throws {@link MissingMetadataError} — class binding lacks injectable metadata when required.
125
- */
126
- async resolveAllAsyncRoot(key, hint) {
127
- return this.resolveAllAsync(key, hint, [], /* @__PURE__ */ new Set(), []);
128
- }
129
- /**
130
- * Context-aware sync `resolveAll`: extends the current resolution path and preserves
131
- * visiting/materialization stacks so nested multi-resolution participates in cycle and
132
- * captive-dependency checks exactly like single-value {@link resolve}.
133
- */
134
- resolveAll(key, hint, pathLabels, visiting, materializationStack) {
135
- const registryKey = key;
136
- const label = registryKeyLabel(key);
137
- const nextPath = [...pathLabels, label];
138
- if (visiting.has(registryKey)) throw new CircularDependencyError(nextPath);
139
- const bindings = this.deps.lookup(registryKey);
140
- if (bindings === void 0 || bindings.length === 0) return [];
141
- const candidates = filterMatchingBindings(bindings, hint, this.buildConstraintContext(nextPath, materializationStack, hint));
142
- if (candidates.length === 0) {
143
- if (hint !== void 0 && (hint.name !== void 0 || hint.tag !== void 0)) throw new NoMatchingBindingError(label, hint, nextPath);
144
- return [];
145
- }
146
- visiting.add(registryKey);
147
- const results = [];
158
+ materializationStack.pop();
159
+ resolutionPath.pop();
160
+ resolutionSet?.delete(tName);
161
+ }
162
+ }
163
+ _instantiateSync(binding, ctx, resolutionPath, materializationStack, hint) {
164
+ switch (binding.kind) {
165
+ case "constant": return binding.value;
166
+ case "dynamic": {
167
+ if (ctx === void 0) throw new InternalError("dynamic binding requires resolution context");
168
+ const r = binding.factory(ctx);
169
+ if (r instanceof Promise) throw new AsyncResolutionError(tokenName(binding.token), tokenName(binding.token));
170
+ return r;
171
+ }
172
+ case "dynamic-async": throw new AsyncResolutionError(tokenName(binding.token), tokenName(binding.token));
173
+ case "class": {
174
+ const deps = this._resolveClassDeps(binding.target, resolutionPath, materializationStack);
175
+ return this._instantiateClass(binding.target, deps);
176
+ }
177
+ case "resolved": {
178
+ const deps = this._resolveDescriptorDeps(binding.deps, resolutionPath, materializationStack, hint);
179
+ const r = binding.factory(...deps);
180
+ if (r instanceof Promise) throw new AsyncResolutionError(tokenName(binding.token), tokenName(binding.token));
181
+ return r;
182
+ }
183
+ case "resolved-async": throw new AsyncResolutionError(tokenName(binding.token), tokenName(binding.token));
184
+ case "alias": throw new InternalError("alias should have been followed before instantiation");
185
+ }
186
+ }
187
+ _resolveClassDeps(target, resolutionPath, materializationStack) {
188
+ const meta = this._getConstructorMetadata(target);
189
+ if (meta === void 0) {
190
+ if (target.length === 0) return [];
191
+ throw new MissingMetadataError(target.name);
192
+ }
193
+ if (meta.params.length === 0) return [];
194
+ if (meta.params.length === 1) {
195
+ const param = meta.params[0];
196
+ const paramHint = injectableSlotToResolveOptions(param);
197
+ if (param.multi) return [this.resolveAll(param.token, paramHint, resolutionPath, materializationStack)];
198
+ if (param.optional) return [this.resolveOptional(param.token, paramHint, resolutionPath, materializationStack)];
199
+ if (paramHint === void 0) return [this.resolveFromContext(param.token, resolutionPath, materializationStack)];
200
+ return [this.resolve(param.token, paramHint, resolutionPath, materializationStack)];
201
+ }
202
+ const deps = new Array(meta.params.length);
203
+ for (let index = 0; index < meta.params.length; index += 1) {
204
+ const param = meta.params[index];
205
+ const paramHint = injectableSlotToResolveOptions(param);
206
+ if (param.multi) {
207
+ deps[index] = this.resolveAll(param.token, paramHint, resolutionPath, materializationStack);
208
+ continue;
209
+ }
210
+ if (param.optional) {
211
+ deps[index] = this.resolveOptional(param.token, paramHint, resolutionPath, materializationStack);
212
+ continue;
213
+ }
214
+ deps[index] = paramHint === void 0 ? this.resolveFromContext(param.token, resolutionPath, materializationStack) : this.resolve(param.token, paramHint, resolutionPath, materializationStack);
215
+ }
216
+ return deps;
217
+ }
218
+ _resolveDescriptorDeps(deps, resolutionPath, materializationStack, _hint) {
219
+ const resolved = new Array(deps.length);
220
+ for (let index = 0; index < deps.length; index += 1) {
221
+ const dep = deps[index];
222
+ const depHint = injectableSlotToResolveOptions(dep);
223
+ if (dep.multi) {
224
+ resolved[index] = this.resolveAll(dep.token, depHint, resolutionPath, materializationStack);
225
+ continue;
226
+ }
227
+ if (dep.optional) {
228
+ resolved[index] = this.resolveOptional(dep.token, depHint, resolutionPath, materializationStack);
229
+ continue;
230
+ }
231
+ resolved[index] = depHint === void 0 ? this.resolveFromContext(dep.token, resolutionPath, materializationStack) : this.resolve(dep.token, depHint, resolutionPath, materializationStack);
232
+ }
233
+ return resolved;
234
+ }
235
+ resolveOptional(token, hint, resolutionPath, materializationStack) {
148
236
  try {
149
- for (const binding of candidates) {
150
- this.assertDependencyScopeAllowed(binding, nextPath, materializationStack);
151
- if (binding.kind === "async-dynamic") throw new AsyncResolutionError(label, nextPath, "encountered async-dynamic factory during synchronous resolveAll");
152
- results.push(this.instantiateBinding(binding, registryKey, hint, nextPath, visiting, materializationStack));
237
+ return this.resolve(token, hint, resolutionPath, materializationStack);
238
+ } catch (e) {
239
+ if (e instanceof TokenNotBoundError || e instanceof NoMatchingBindingError) return;
240
+ throw e;
241
+ }
242
+ }
243
+ resolveAll(token, hint, resolutionPath, materializationStack) {
244
+ if (hint?.name !== void 0 && hint.tag === void 0 && (hint.tags?.length ?? 0) === 0) {
245
+ const namedCandidates = this._getSimpleNamedBindingsFromChain(token, hint.name);
246
+ if (namedCandidates.length === 0) return [];
247
+ const resolved = new Array(namedCandidates.length);
248
+ for (let index = 0; index < namedCandidates.length; index += 1) resolved[index] = this._resolveCandidateSync(namedCandidates[index], hint, resolutionPath, materializationStack);
249
+ return resolved;
250
+ }
251
+ const allBindings = this._getAllBindingsFromChain(token);
252
+ if (allBindings.length === 0) return [];
253
+ const candidates = selectAllBindings(allBindings, hint, this._makeConstraintContext(resolutionPath, materializationStack, hint));
254
+ const resolved = new Array(candidates.length);
255
+ for (let index = 0; index < candidates.length; index += 1) resolved[index] = this._resolveCandidateSync(candidates[index], hint, resolutionPath, materializationStack);
256
+ return resolved;
257
+ }
258
+ resolveAsyncFromContext(token, resolutionPath, materializationStack) {
259
+ const fastBinding = this._registry.getFastDefault(token);
260
+ if (fastBinding !== void 0) {
261
+ if (fastBinding.kind === "alias") return this.resolveAsyncFromContext(fastBinding.target, resolutionPath, materializationStack);
262
+ const scope = fastBinding.scope ?? "transient";
263
+ if (scope === "transient" && (fastBinding.kind === "dynamic" || fastBinding.kind === "dynamic-async") && fastBinding.onActivation === void 0 && (this._lifecycle.activationVersion === 0 || !this._lifecycle.hasActivationHandlers(fastBinding.token))) return this._resolveTransientDynamicAsyncFromContext(fastBinding, resolutionPath, materializationStack);
264
+ if (scope === "singleton" && this._scope.hasSingleton(fastBinding.id)) return Promise.resolve(this._scope.getSingleton(fastBinding.id));
265
+ if (scope === "scoped") {
266
+ if (!this._scope.isChild) return Promise.reject(new MissingScopeContextError(this._getTokenName(fastBinding.token)));
267
+ if (this._scope.hasScoped(fastBinding.id)) return Promise.resolve(this._scope.getScoped(fastBinding.id));
153
268
  }
154
- } finally {
155
- visiting.delete(registryKey);
156
- }
157
- return results;
158
- }
159
- /**
160
- * Async counterpart of {@link resolveAll}: keeps the current path and materialization stack
161
- * so `when()` constraints and scope validation behave consistently for nested multi-resolution.
162
- */
163
- async resolveAllAsync(key, hint, pathLabels, visiting, materializationStack) {
164
- const registryKey = key;
165
- const label = registryKeyLabel(key);
166
- const nextPath = [...pathLabels, label];
167
- if (visiting.has(registryKey)) throw new CircularDependencyError(nextPath);
168
- const bindings = this.deps.lookup(registryKey);
169
- if (bindings === void 0 || bindings.length === 0) return [];
170
- const candidates = filterMatchingBindings(bindings, hint, this.buildConstraintContext(nextPath, materializationStack, hint));
171
- if (candidates.length === 0) {
172
- if (hint !== void 0 && (hint.name !== void 0 || hint.tag !== void 0)) throw new NoMatchingBindingError(label, hint, nextPath);
173
- return [];
174
- }
175
- visiting.add(registryKey);
176
- const results = [];
269
+ return this._resolveBindingAsync(fastBinding, void 0, resolutionPath, materializationStack);
270
+ }
271
+ return this.resolveAsync(token, void 0, resolutionPath, materializationStack);
272
+ }
273
+ async resolveAsync(token, hint, resolutionPath, materializationStack) {
274
+ const found = this._findBinding(token, hint, resolutionPath, materializationStack);
275
+ if (found === void 0) {
276
+ if (this._registry.getAll(token).length > 0) throw new NoMatchingBindingError(this._getTokenName(token), hint ?? {}, this._getAvailableSlots(token));
277
+ throw new TokenNotBoundError(this._getTokenName(token));
278
+ }
279
+ const { binding, owner } = found;
280
+ if (binding.kind === "alias") return this.resolveAsync(binding.target, hint, resolutionPath, materializationStack);
281
+ if ((binding.scope ?? "transient") === "singleton" && owner !== this) return owner._resolveBindingAsync(binding, hint, resolutionPath, materializationStack);
282
+ return this._resolveBindingAsync(binding, hint, resolutionPath, materializationStack);
283
+ }
284
+ async _resolveBindingAsync(binding, hint, resolutionPath, materializationStack) {
285
+ if (binding.kind === "constant" && binding.onActivation === void 0 && !this._lifecycle.hasActivationHandlers(binding.token)) return binding.value;
286
+ const scope = binding.scope ?? "transient";
287
+ if (scope === "singleton") {
288
+ if (this._scope.hasSingleton(binding.id)) return this._scope.getSingleton(binding.id);
289
+ const inflight = this._scope.getInflight(binding.id);
290
+ if (inflight !== void 0) return inflight;
291
+ }
292
+ if (scope === "scoped") {
293
+ if (!this._scope.isChild) throw new MissingScopeContextError(this._getTokenName(binding.token));
294
+ if (this._scope.hasScoped(binding.id)) return this._scope.getScoped(binding.id);
295
+ }
296
+ const frame = this._getMaterializationFrame(binding);
297
+ const tName = frame.tokenName;
298
+ const pathWithSet = resolutionPath;
299
+ let resolutionSet = pathWithSet[RESOLUTION_SET_KEY];
300
+ if (resolutionSet === void 0 && resolutionPath.length >= RESOLUTION_SET_THRESHOLD) {
301
+ resolutionSet = new Set(resolutionPath);
302
+ pathWithSet[RESOLUTION_SET_KEY] = resolutionSet;
303
+ }
304
+ if (resolutionSet !== void 0 ? resolutionSet.has(tName) : resolutionPath.includes(tName)) throw new CircularDependencyError([...resolutionPath, tName]);
305
+ resolutionPath.push(tName);
306
+ resolutionSet?.add(tName);
307
+ materializationStack.push(frame);
308
+ const needsActivation = this._needsActivation(binding);
309
+ if (!needsActivation && scope === "transient" && (binding.kind === "dynamic" || binding.kind === "dynamic-async")) {
310
+ const resolutionCtx = new DefaultResolutionContext(this, resolutionPath, materializationStack, hint);
311
+ try {
312
+ if (binding.kind === "dynamic-async") return await binding.factory(resolutionCtx);
313
+ const dynamicResult = binding.factory(resolutionCtx);
314
+ return dynamicResult instanceof Promise ? await dynamicResult : dynamicResult;
315
+ } finally {
316
+ materializationStack.pop();
317
+ resolutionPath.pop();
318
+ resolutionSet?.delete(tName);
319
+ }
320
+ }
321
+ const resolutionCtx = needsActivation || this._requiresResolutionContext(binding) ? new DefaultResolutionContext(this, resolutionPath, materializationStack, hint) : void 0;
177
322
  try {
178
- for (const binding of candidates) {
179
- this.assertDependencyScopeAllowed(binding, nextPath, materializationStack);
180
- results.push(await this.instantiateBindingAsync(binding, registryKey, hint, nextPath, visiting, materializationStack));
323
+ if (scope === "singleton") {
324
+ const createSingletonPromise = async () => {
325
+ const instance = await this._instantiateAsync(binding, resolutionCtx, resolutionPath, materializationStack, hint);
326
+ let shouldActivate = needsActivation;
327
+ if (binding.kind === "class" && this._classHasPostConstruct.get(binding.target) === void 0) {
328
+ this._refreshClassPostConstructCache(binding.target);
329
+ this._activationNeedByBindingId.delete(binding.id);
330
+ shouldActivate = this._needsActivation(binding);
331
+ }
332
+ const activated = shouldActivate ? await this._lifecycle.runActivation(resolutionCtx, binding, instance, this._metadataReader) : instance;
333
+ this._scope.setSingleton(binding.id, activated);
334
+ this._scope.clearInflight(binding.id);
335
+ return activated;
336
+ };
337
+ const p = createSingletonPromise().catch((err) => {
338
+ this._scope.clearInflight(binding.id);
339
+ throw err;
340
+ });
341
+ this._scope.setInflight(binding.id, p);
342
+ return await p;
343
+ }
344
+ const instance = await this._instantiateAsync(binding, resolutionCtx, resolutionPath, materializationStack, hint);
345
+ let shouldActivate = needsActivation;
346
+ if (binding.kind === "class" && this._classHasPostConstruct.get(binding.target) === void 0) {
347
+ this._refreshClassPostConstructCache(binding.target);
348
+ this._activationNeedByBindingId.delete(binding.id);
349
+ shouldActivate = this._needsActivation(binding);
181
350
  }
351
+ const activated = shouldActivate ? await this._lifecycle.runActivation(resolutionCtx, binding, instance, this._metadataReader) : instance;
352
+ if (scope === "scoped") this._scope.setScoped(binding.id, activated);
353
+ return activated;
182
354
  } finally {
183
- visiting.delete(registryKey);
355
+ materializationStack.pop();
356
+ resolutionPath.pop();
357
+ resolutionSet?.delete(tName);
358
+ }
359
+ }
360
+ async _instantiateAsync(binding, ctx, resolutionPath, materializationStack, hint) {
361
+ switch (binding.kind) {
362
+ case "constant": return binding.value;
363
+ case "dynamic": {
364
+ if (ctx === void 0) throw new InternalError("dynamic binding requires resolution context");
365
+ const r = binding.factory(ctx);
366
+ return r instanceof Promise ? r : Promise.resolve(r);
367
+ }
368
+ case "dynamic-async":
369
+ if (ctx === void 0) throw new InternalError("dynamic-async binding requires resolution context");
370
+ return binding.factory(ctx);
371
+ case "class": {
372
+ const deps = await this._resolveClassDepsAsync(binding.target, resolutionPath, materializationStack);
373
+ return this._instantiateClass(binding.target, deps);
374
+ }
375
+ case "resolved": {
376
+ if (ctx === void 0) throw new InternalError("resolved binding requires resolution context");
377
+ const deps = await this._resolveDescriptorDepsAsync(binding.deps, resolutionPath, materializationStack, hint);
378
+ const r = binding.factory(...deps);
379
+ return r instanceof Promise ? r : Promise.resolve(r);
380
+ }
381
+ case "resolved-async": {
382
+ const deps = await this._resolveDescriptorDepsAsync(binding.deps, resolutionPath, materializationStack, hint);
383
+ return binding.factory(...deps);
384
+ }
385
+ case "alias": throw new InternalError("alias should have been followed before instantiation");
386
+ }
387
+ }
388
+ async _resolveClassDepsAsync(target, resolutionPath, materializationStack) {
389
+ const meta = this._getConstructorMetadata(target);
390
+ if (meta === void 0) {
391
+ if (target.length === 0) return [];
392
+ throw new MissingMetadataError(target.name);
393
+ }
394
+ if (meta.params.length === 0) return [];
395
+ if (meta.params.length === 1) {
396
+ const param = meta.params[0];
397
+ const paramHint = injectableSlotToResolveOptions(param);
398
+ if (param.multi) return [await this.resolveAllAsync(param.token, paramHint, resolutionPath, materializationStack)];
399
+ if (param.optional) return [await this.resolveOptionalAsync(param.token, paramHint, resolutionPath, materializationStack)];
400
+ if (paramHint === void 0) return [await this.resolveAsyncFromContext(param.token, resolutionPath, materializationStack)];
401
+ return [await this.resolveAsync(param.token, paramHint, resolutionPath, materializationStack)];
402
+ }
403
+ const pending = new Array(meta.params.length);
404
+ const shouldCloneContext = meta.params.length > 1;
405
+ for (let index = 0; index < meta.params.length; index += 1) {
406
+ const param = meta.params[index];
407
+ const paramHint = injectableSlotToResolveOptions(param);
408
+ if (param.multi) pending[index] = this.resolveAllAsync(param.token, paramHint, shouldCloneContext ? [...resolutionPath] : resolutionPath, shouldCloneContext ? [...materializationStack] : materializationStack);
409
+ else if (param.optional) pending[index] = this.resolveOptionalAsync(param.token, paramHint, shouldCloneContext ? [...resolutionPath] : resolutionPath, shouldCloneContext ? [...materializationStack] : materializationStack);
410
+ else pending[index] = paramHint === void 0 ? this.resolveAsyncFromContext(param.token, shouldCloneContext ? [...resolutionPath] : resolutionPath, shouldCloneContext ? [...materializationStack] : materializationStack) : this.resolveAsync(param.token, paramHint, shouldCloneContext ? [...resolutionPath] : resolutionPath, shouldCloneContext ? [...materializationStack] : materializationStack);
411
+ }
412
+ return Promise.all(pending);
413
+ }
414
+ async _resolveDescriptorDepsAsync(deps, resolutionPath, materializationStack, _hint) {
415
+ const pending = new Array(deps.length);
416
+ const shouldCloneContext = deps.length > 1;
417
+ for (let index = 0; index < deps.length; index += 1) {
418
+ const dep = deps[index];
419
+ const depHint = injectableSlotToResolveOptions(dep);
420
+ if (dep.multi) pending[index] = this.resolveAllAsync(dep.token, depHint, shouldCloneContext ? [...resolutionPath] : resolutionPath, shouldCloneContext ? [...materializationStack] : materializationStack);
421
+ else if (dep.optional) pending[index] = this.resolveOptionalAsync(dep.token, depHint, shouldCloneContext ? [...resolutionPath] : resolutionPath, shouldCloneContext ? [...materializationStack] : materializationStack);
422
+ else pending[index] = depHint === void 0 ? this.resolveAsyncFromContext(dep.token, shouldCloneContext ? [...resolutionPath] : resolutionPath, shouldCloneContext ? [...materializationStack] : materializationStack) : this.resolveAsync(dep.token, depHint, shouldCloneContext ? [...resolutionPath] : resolutionPath, shouldCloneContext ? [...materializationStack] : materializationStack);
184
423
  }
185
- return results;
424
+ return Promise.all(pending);
186
425
  }
187
- /**
188
- * Assembles the read-only {@link ConstraintContext} snapshot passed to `when()` predicates.
189
- * Extracts the top-of-stack frame as `parent` and the rest as `ancestors`.
190
- */
191
- buildConstraintContext(resolutionPath, materializationStack, currentResolveHint) {
426
+ async resolveOptionalAsync(token, hint, resolutionPath, materializationStack) {
427
+ try {
428
+ return await this.resolveAsync(token, hint, resolutionPath, materializationStack);
429
+ } catch (e) {
430
+ if (e instanceof TokenNotBoundError || e instanceof NoMatchingBindingError) return;
431
+ throw e;
432
+ }
433
+ }
434
+ async resolveAllAsync(token, hint, resolutionPath, materializationStack) {
435
+ if (hint?.name !== void 0 && hint.tag === void 0 && (hint.tags?.length ?? 0) === 0) {
436
+ const namedCandidates = this._getSimpleNamedBindingsFromChain(token, hint.name);
437
+ if (namedCandidates.length === 0) return [];
438
+ const pending = new Array(namedCandidates.length);
439
+ for (let index = 0; index < namedCandidates.length; index += 1) pending[index] = this._resolveCandidateAsync(namedCandidates[index], hint, resolutionPath, materializationStack);
440
+ return Promise.all(pending);
441
+ }
442
+ const allBindings = this._getAllBindingsFromChain(token);
443
+ if (allBindings.length === 0) return [];
444
+ const candidates = selectAllBindings(allBindings, hint, this._makeConstraintContext(resolutionPath, materializationStack, hint));
445
+ const pending = new Array(candidates.length);
446
+ for (let index = 0; index < candidates.length; index += 1) pending[index] = this._resolveCandidateAsync(candidates[index], hint, resolutionPath, materializationStack);
447
+ return Promise.all(pending);
448
+ }
449
+ _getAllBindingsFromChain(token) {
450
+ const ownBindings = this._registry.getAll(token);
451
+ if (this._parent === void 0) return ownBindings;
452
+ const result = [...ownBindings];
453
+ let current = this._parent;
454
+ while (current !== void 0) {
455
+ const own = current._registry.getAll(token);
456
+ if (own.length > 0) result.push(...own);
457
+ current = current._parent;
458
+ }
459
+ return result;
460
+ }
461
+ _getSimpleNamedBindingsFromChain(token, name) {
462
+ const ownBinding = this._registry.getSimpleNamed(token, name);
463
+ if (this._parent === void 0) return ownBinding !== void 0 ? [ownBinding] : [];
464
+ const result = [];
465
+ if (ownBinding !== void 0) result.push(ownBinding);
466
+ let current = this._parent;
467
+ while (current !== void 0) {
468
+ const binding = current._registry.getSimpleNamed(token, name);
469
+ if (binding !== void 0) result.push(binding);
470
+ current = current._parent;
471
+ }
472
+ return result;
473
+ }
474
+ _getAvailableSlots(token) {
475
+ return this._registry.availableSlotStrings(token);
476
+ }
477
+ _makeConstraintContext(resolutionPath, materializationStack, hint) {
478
+ if (hint === void 0 && resolutionPath.length === 0 && materializationStack.length === 0) return ROOT_CONSTRAINT_CONTEXT;
192
479
  return {
193
480
  resolutionPath,
194
481
  materializationStack,
195
- parent: materializationStack.length > 0 ? materializationStack[materializationStack.length - 1] : void 0,
196
- ancestors: materializationStack.slice(0, -1),
197
- currentResolveHint
482
+ parent: materializationStack.at(-1),
483
+ ancestors: materializationStack.length > 1 ? materializationStack.slice(0, -1) : [],
484
+ currentResolveHint: hint
198
485
  };
199
486
  }
200
- /**
201
- * Throws {@link ScopeViolationError} when the immediate consumer on the stack is a singleton
202
- * and the dependency has `"scoped"` or `"transient"` lifetime (captive dependency).
203
- * Constants are exempt — they have no scope cache.
204
- */
205
- assertDependencyScopeAllowed(dependencyBinding, resolutionPath, materializationStack) {
206
- const consumer = materializationStack[materializationStack.length - 1];
207
- if (consumer === void 0) return;
208
- if (consumer.scope !== "singleton") return;
209
- if (dependencyBinding.kind === "constant") return;
210
- if (dependencyBinding.scope === "transient" || dependencyBinding.scope === "scoped") {
211
- const dependencyLabel = resolutionPath[resolutionPath.length - 1];
212
- const consumerLabel = resolutionPath.length >= 2 ? resolutionPath[resolutionPath.length - 2] : void 0;
213
- throw new ScopeViolationError({
214
- consumerBindingId: consumer.bindingId,
215
- consumerKind: consumer.bindingKind,
216
- consumerScope: consumer.scope,
217
- consumerLabel,
218
- dependencyBindingId: dependencyBinding.id,
219
- dependencyKind: dependencyBinding.kind,
220
- dependencyScope: dependencyBinding.scope,
221
- dependencyLabel,
222
- resolutionPath: [...resolutionPath]
223
- });
487
+ _matchesBindingFast(binding, hint, resolutionPath, materializationStack) {
488
+ if (!this._matchesSlotFast(binding.slot, hint)) return false;
489
+ if (binding.predicate === void 0) return true;
490
+ const ctx = this._makeConstraintContext(resolutionPath, materializationStack, hint);
491
+ return binding.predicate(ctx);
492
+ }
493
+ _matchesSlotFast(slot, hint) {
494
+ const hintName = hint?.name;
495
+ const hintTags = hint?.tags;
496
+ const singleHintTag = hint?.tag;
497
+ const hasHintTags = (hintTags?.length ?? 0) > 0 || singleHintTag !== void 0;
498
+ if (slot.name !== void 0) {
499
+ if (hintName === void 0 || slot.name !== hintName) return false;
500
+ } else if (hintName !== void 0) return false;
501
+ if (slot.tags.length > 0) {
502
+ if (!hasHintTags) return false;
503
+ for (const [tagKey, tagValue] of slot.tags) if (!this._matchesHintTag(tagKey, tagValue, hintTags, singleHintTag)) return false;
504
+ } else if (hasHintTags) return false;
505
+ return true;
506
+ }
507
+ _getTokenName(token) {
508
+ return tokenName(token);
509
+ }
510
+ _getConstructorMetadata(target) {
511
+ const cached = this._classConstructorMetadata.get(target);
512
+ if (cached !== void 0) return cached === null ? void 0 : cached;
513
+ const metadata = this._metadataReader.getConstructorMetadata(target);
514
+ this._classConstructorMetadata.set(target, metadata ?? null);
515
+ return metadata;
516
+ }
517
+ _instantiateClass(target, deps) {
518
+ let needsActiveContainer = this._classNeedsActiveContainer.get(target);
519
+ if (needsActiveContainer === void 0) {
520
+ needsActiveContainer = ((this._metadataReader.getAccessorMetadata?.(target))?.length ?? 0) > 0;
521
+ this._classNeedsActiveContainer.set(target, needsActiveContainer);
224
522
  }
523
+ const invokable = target;
524
+ if (!needsActiveContainer) return new invokable(...deps);
525
+ return runWithContainer(this._container, () => new invokable(...deps));
225
526
  }
226
- /**
227
- * Builds a {@link ResolutionContext} for use inside factories and lifecycle hooks.
228
- * The `resolve` / `resolveAsync` / `resolveOptional` closures carry the current path and
229
- * materialization stack forward so nested calls inherit captive-dependency checks.
230
- */
231
- createContext(pathLabels, visiting, materializationStack, currentResolveHint) {
232
- return {
233
- resolve: (token, hint) => this.resolve(token, hint, [...pathLabels], visiting, materializationStack),
234
- resolveAsync: (token, hint) => this.resolveAsync(token, hint, [...pathLabels], visiting, materializationStack),
235
- resolveOptional: (token, hint) => {
236
- try {
237
- return this.resolve(token, hint, [...pathLabels], visiting, materializationStack);
238
- } catch (caughtError) {
239
- if (caughtError instanceof TokenNotBoundError) return;
240
- throw caughtError;
241
- }
242
- },
243
- resolveAll: (token, hint) => this.resolveAll(token, hint, [...pathLabels], visiting, materializationStack),
244
- resolveAllAsync: (token, hint) => this.resolveAllAsync(token, hint, [...pathLabels], visiting, materializationStack),
245
- graph: this.buildConstraintContext(pathLabels, materializationStack, currentResolveHint)
246
- };
527
+ _matchesHintTag(tagKey, tagValue, hintTags, singleHintTag) {
528
+ if (singleHintTag !== void 0 && singleHintTag[0] === tagKey && Object.is(singleHintTag[1], tagValue)) return true;
529
+ if (hintTags === void 0 || hintTags.length === 0) return false;
530
+ for (let index = 0; index < hintTags.length; index += 1) {
531
+ const hintTag = hintTags[index];
532
+ if (hintTag[0] === tagKey && Object.is(hintTag[1], tagValue)) return true;
533
+ }
534
+ return false;
247
535
  }
248
- /**
249
- * Core synchronous resolution: lookup → filter → cycle check → scope check → instantiate.
250
- * Called recursively when a binding's dependencies need resolution.
251
- *
252
- * @param key - Token or constructor being resolved.
253
- * @param hint - Optional name/tag filter for multi-binding selection.
254
- * @param pathLabels - Mutable label path accumulated during graph walk; extended in place.
255
- * @param visiting - Registry keys currently on the call stack; used for circular-dependency detection.
256
- * @param materializationStack - Bindings along the current construction chain; used to block singleton→scoped/transient.
257
- */
258
- resolve(key, hint, pathLabels, visiting, materializationStack) {
259
- const registryKey = key;
260
- const label = registryKeyLabel(key);
261
- const nextPath = [...pathLabels, label];
262
- if (visiting.has(registryKey)) throw new CircularDependencyError(nextPath);
263
- const bindings = this.deps.lookup(registryKey);
264
- if (bindings === void 0 || bindings.length === 0) throw new TokenNotBoundError(label, nextPath);
265
- const binding = selectBindingForRegistry(bindings, hint, label, nextPath, this.buildConstraintContext(nextPath, materializationStack, hint));
266
- this.assertDependencyScopeAllowed(binding, nextPath, materializationStack);
267
- if (binding.kind === "async-dynamic") throw new AsyncResolutionError(label, nextPath, "encountered async-dynamic factory during synchronous resolution");
268
- visiting.add(registryKey);
536
+ _resolveTransientDynamicSyncFromContext(binding, resolutionPath, materializationStack) {
537
+ if (resolutionPath.length < RESOLUTION_SET_THRESHOLD) {
538
+ const frame = this._getMaterializationFrame(binding);
539
+ const tName = frame.tokenName;
540
+ if (resolutionPath.includes(tName)) throw new CircularDependencyError([...resolutionPath, tName]);
541
+ resolutionPath.push(tName);
542
+ materializationStack.push(frame);
543
+ const resolutionCtx = this._acquireSyncResolutionContext(resolutionPath, materializationStack, void 0);
544
+ try {
545
+ const dynamicResult = binding.factory(resolutionCtx);
546
+ if (dynamicResult instanceof Promise) throw new AsyncResolutionError(tName, tName);
547
+ return dynamicResult;
548
+ } finally {
549
+ materializationStack.pop();
550
+ resolutionPath.pop();
551
+ }
552
+ }
553
+ if (this._deepActiveLevels > 0 && this._deepSyncCtxPath !== resolutionPath) return this._resolveTransientDynamicSyncSlow(binding, resolutionPath, materializationStack);
554
+ if (this._deepActiveLevels === 0) {
555
+ const gen = ++this._deepCycleGen;
556
+ for (const stackFrame of materializationStack) this._deepCycleMarks.set(stackFrame.bindingId, gen);
557
+ let ctx = this._deepSyncCtx;
558
+ if (ctx === void 0) {
559
+ ctx = new DefaultResolutionContext(this, resolutionPath, materializationStack, void 0);
560
+ this._deepSyncCtx = ctx;
561
+ } else ctx.reset(this, resolutionPath, materializationStack, void 0);
562
+ this._deepSyncCtxPath = resolutionPath;
563
+ }
564
+ if (this._deepCycleMarks.get(binding.id) === this._deepCycleGen) throw new CircularDependencyError([...resolutionPath, tokenName(binding.token)]);
565
+ this._deepCycleMarks.set(binding.id, this._deepCycleGen);
566
+ this._deepActiveLevels++;
269
567
  try {
270
- return this.instantiateBinding(binding, registryKey, hint, nextPath, visiting, materializationStack);
568
+ const dynamicResult = binding.factory(this._deepSyncCtx);
569
+ if (dynamicResult instanceof Promise) throw new AsyncResolutionError(tokenName(binding.token), tokenName(binding.token));
570
+ return dynamicResult;
271
571
  } finally {
272
- visiting.delete(registryKey);
273
- }
274
- }
275
- /**
276
- * Core async resolution: same pipeline as {@link resolve} but awaits `async-dynamic`
277
- * factories and async lifecycle hooks instead of throwing {@link AsyncResolutionError}.
278
- *
279
- * @param key - Token or constructor being resolved.
280
- * @param hint - Optional name/tag filter for multi-binding selection.
281
- * @param pathLabels - Mutable label path accumulated during graph walk; extended in place.
282
- * @param visiting - Registry keys currently on the call stack; used for circular-dependency detection.
283
- * @param materializationStack - Same captive-dependency chain as {@link resolve}.
284
- */
285
- async resolveAsync(key, hint, pathLabels, visiting, materializationStack) {
286
- const registryKey = key;
287
- const label = registryKeyLabel(key);
288
- const nextPath = [...pathLabels, label];
289
- if (visiting.has(registryKey)) throw new CircularDependencyError(nextPath);
290
- const bindings = this.deps.lookup(registryKey);
291
- if (bindings === void 0 || bindings.length === 0) throw new TokenNotBoundError(label, nextPath);
292
- const binding = selectBindingForRegistry(bindings, hint, label, nextPath, this.buildConstraintContext(nextPath, materializationStack, hint));
293
- this.assertDependencyScopeAllowed(binding, nextPath, materializationStack);
294
- visiting.add(registryKey);
572
+ if (--this._deepActiveLevels === 0) this._deepSyncCtxPath = void 0;
573
+ }
574
+ }
575
+ _resolveTransientDynamicSyncSlow(binding, resolutionPath, materializationStack) {
576
+ const frame = this._getMaterializationFrame(binding);
577
+ const tName = frame.tokenName;
578
+ const pathWithSet = resolutionPath;
579
+ let resolutionSet = pathWithSet[RESOLUTION_SET_KEY];
580
+ if (resolutionSet === void 0) {
581
+ resolutionSet = new Set(resolutionPath);
582
+ pathWithSet[RESOLUTION_SET_KEY] = resolutionSet;
583
+ }
584
+ if (resolutionSet.has(tName)) throw new CircularDependencyError([...resolutionPath, tName]);
585
+ resolutionPath.push(tName);
586
+ resolutionSet.add(tName);
587
+ materializationStack.push(frame);
588
+ const resolutionCtx = this._acquireSyncResolutionContext(resolutionPath, materializationStack, void 0);
295
589
  try {
296
- return await this.instantiateBindingAsync(binding, registryKey, hint, nextPath, visiting, materializationStack);
590
+ const dynamicResult = binding.factory(resolutionCtx);
591
+ if (dynamicResult instanceof Promise) throw new AsyncResolutionError(tName, tName);
592
+ return dynamicResult;
297
593
  } finally {
298
- visiting.delete(registryKey);
299
- }
300
- }
301
- /**
302
- * Handles scope-cache lookup / storage and lifecycle hooks (`@postConstruct`, `onActivation`)
303
- * around a synchronous call to {@link materialize}.
304
- */
305
- instantiateBinding(binding, registryKey, hint, pathLabels, visiting, materializationStack) {
306
- this.assertCaptiveDependencyFromMaterializationStack(binding, pathLabels, materializationStack);
307
- return this.deps.scopeManager.getOrCreate(binding, () => {
308
- const frame = bindingToMaterializationFrame(registryKey, binding);
309
- const extendedStack = [...materializationStack, frame];
310
- const ctx = this.createContext(pathLabels, visiting, extendedStack, hint);
311
- const instance = this.materialize(binding, hint, ctx, pathLabels, visiting, extendedStack);
312
- if (binding.kind === "class") runPostConstruct(binding.implementationClass, instance, pathLabels);
313
- return runActivation(binding, instance, ctx, pathLabels);
314
- });
315
- }
316
- /**
317
- * Async counterpart of {@link instantiateBinding}: delegates to {@link materializeAsync}
318
- * and awaits `@postConstruct` and `onActivation` hooks.
319
- */
320
- async instantiateBindingAsync(binding, registryKey, hint, pathLabels, visiting, materializationStack) {
321
- this.assertCaptiveDependencyFromMaterializationStack(binding, pathLabels, materializationStack);
322
- return this.deps.scopeManager.getOrCreateAsync(binding, async () => {
323
- const frame = bindingToMaterializationFrame(registryKey, binding);
324
- const extendedStack = [...materializationStack, frame];
325
- const ctx = this.createContext(pathLabels, visiting, extendedStack, hint);
326
- const instance = await this.materializeAsync(binding, hint, ctx, pathLabels, visiting, extendedStack);
327
- if (binding.kind === "class") await runPostConstructAsync(binding.implementationClass, instance);
328
- return await runActivationAsync(binding, instance, ctx, pathLabels);
329
- });
330
- }
331
- /**
332
- * Duplicate captive-dependency guard applied at instantiation time (after scope-cache miss),
333
- * checking the top of the materialization stack rather than the raw `ConstraintContext`.
334
- */
335
- assertCaptiveDependencyFromMaterializationStack(dependencyBinding, resolutionPath, materializationStack) {
336
- const parentFrame = materializationStack[materializationStack.length - 1];
337
- if (parentFrame === void 0) return;
338
- if (parentFrame.scope !== "singleton") return;
339
- if (dependencyBinding.kind === "constant") return;
340
- if (dependencyBinding.scope === "scoped" || dependencyBinding.scope === "transient") {
341
- const dependencyLabel = resolutionPath[resolutionPath.length - 1];
342
- const consumerLabel = resolutionPath.length >= 2 ? resolutionPath[resolutionPath.length - 2] : void 0;
343
- throw new ScopeViolationError({
344
- consumerBindingId: parentFrame.bindingId,
345
- consumerKind: parentFrame.bindingKind,
346
- consumerScope: parentFrame.scope,
347
- consumerLabel,
348
- dependencyBindingId: dependencyBinding.id,
349
- dependencyKind: dependencyBinding.kind,
350
- dependencyScope: dependencyBinding.scope,
351
- dependencyLabel,
352
- resolutionPath: [...resolutionPath]
353
- });
594
+ materializationStack.pop();
595
+ resolutionPath.pop();
596
+ resolutionSet.delete(tName);
354
597
  }
355
598
  }
356
- /**
357
- * Synchronously produces the raw instance for a binding **without** touching the scope cache
358
- * or running lifecycle hooks. The caller ({@link instantiateBinding}) wraps this with
359
- * cache logic and post-construction hooks.
360
- *
361
- * Dispatches on `binding.kind`; throws {@link AsyncResolutionError} if the binding is
362
- * `async-dynamic` or if a `dynamic` / `resolved` factory returns a Promise.
363
- */
364
- materialize(binding, hint, ctx, pathLabels, visiting, materializationStack) {
365
- switch (binding.kind) {
366
- case "constant": return binding.value;
367
- case "class": return this.instantiateClassBinding(binding, pathLabels, visiting, materializationStack);
368
- case "dynamic": {
369
- const factoryResult = binding.factory(ctx);
370
- if (isPromiseLike(factoryResult)) throw new AsyncResolutionError(pathLabels[pathLabels.length - 1] ?? "(unknown)", pathLabels, "dynamic factory returned a Promise during synchronous resolution");
371
- return factoryResult;
599
+ _resolveTransientDynamicAsyncFromContext(binding, resolutionPath, materializationStack) {
600
+ if (resolutionPath.length < RESOLUTION_SET_THRESHOLD) {
601
+ const tName = tokenName(binding.token);
602
+ if (resolutionPath.includes(tName)) return Promise.reject(new CircularDependencyError([...resolutionPath, tName]));
603
+ resolutionPath.push(tName);
604
+ let ctx;
605
+ let isOwnerLevel;
606
+ if (this._deepAsyncCtxPath === resolutionPath) {
607
+ ctx = this._deepAsyncCtx;
608
+ isOwnerLevel = true;
609
+ } else if (this._deepAsyncCtxPath === void 0) {
610
+ const existing = this._deepAsyncCtx;
611
+ if (existing === void 0) {
612
+ ctx = new DefaultResolutionContext(this, resolutionPath, materializationStack, void 0);
613
+ this._deepAsyncCtx = ctx;
614
+ } else {
615
+ existing.reset(this, resolutionPath, materializationStack, void 0);
616
+ ctx = existing;
617
+ }
618
+ this._deepAsyncCtxPath = resolutionPath;
619
+ isOwnerLevel = true;
620
+ } else {
621
+ ctx = new DefaultResolutionContext(this, resolutionPath, materializationStack, void 0);
622
+ isOwnerLevel = false;
372
623
  }
373
- case "async-dynamic": throw new AsyncResolutionError(pathLabels[pathLabels.length - 1] ?? "(unknown)", pathLabels, "async-dynamic factory cannot be materialized synchronously");
374
- case "resolved": {
375
- const deps = [];
376
- for (const depToken of binding.dependencyTokens) deps.push(this.resolve(depToken, void 0, pathLabels, visiting, materializationStack));
377
- const resolvedValue = binding.factory(...deps);
378
- if (isPromiseLike(resolvedValue)) throw new AsyncResolutionError(pathLabels[pathLabels.length - 1] ?? "(unknown)", pathLabels, "resolved factory returned a Promise during synchronous resolution");
379
- return resolvedValue;
624
+ if (isOwnerLevel) this._deepAsyncActiveLevels++;
625
+ let factoryPromise;
626
+ try {
627
+ if (binding.kind === "dynamic-async") factoryPromise = binding.factory(ctx);
628
+ else {
629
+ const r = binding.factory(ctx);
630
+ factoryPromise = r instanceof Promise ? r : Promise.resolve(r);
631
+ }
632
+ } catch (err) {
633
+ resolutionPath.pop();
634
+ if (isOwnerLevel && --this._deepAsyncActiveLevels === 0) this._deepAsyncCtxPath = void 0;
635
+ return Promise.reject(err);
380
636
  }
381
- case "alias": return this.resolve(binding.targetToken, hint, pathLabels, visiting, materializationStack);
382
- default: return binding;
637
+ return factoryPromise.then((value) => {
638
+ resolutionPath.pop();
639
+ if (isOwnerLevel && --this._deepAsyncActiveLevels === 0) this._deepAsyncCtxPath = void 0;
640
+ return value;
641
+ }, (err) => {
642
+ resolutionPath.pop();
643
+ if (isOwnerLevel && --this._deepAsyncActiveLevels === 0) this._deepAsyncCtxPath = void 0;
644
+ throw err;
645
+ });
383
646
  }
647
+ return this._resolveTransientDynamicAsyncSlow(binding, resolutionPath, materializationStack);
384
648
  }
385
- /**
386
- * Async counterpart of {@link materialize}; awaits `async-dynamic` factories and
387
- * recursively resolves `resolved`-binding dependencies with {@link resolveAsync}.
388
- */
389
- async materializeAsync(binding, hint, ctx, pathLabels, visiting, materializationStack) {
390
- switch (binding.kind) {
391
- case "constant": return binding.value;
392
- case "class": return this.instantiateClassBindingAsync(binding, pathLabels, visiting, materializationStack);
393
- case "dynamic": return binding.factory(ctx);
394
- case "async-dynamic": return await binding.factory(ctx);
395
- case "resolved": {
396
- const deps = [];
397
- for (const depToken of binding.dependencyTokens) deps.push(await this.resolveAsync(depToken, void 0, pathLabels, visiting, materializationStack));
398
- return binding.factory(...deps);
399
- }
400
- case "alias": return this.resolveAsync(binding.targetToken, hint, pathLabels, visiting, materializationStack);
401
- default: return binding;
402
- }
403
- }
404
- /**
405
- * Reads `@injectable()` constructor metadata and synchronously resolves each parameter,
406
- * then calls `new ImplementationClass(...deps)`. Throws {@link MissingMetadataError} when
407
- * the class has constructor parameters but no metadata.
408
- */
409
- instantiateClassBinding(binding, pathLabels, visiting, materializationStack) {
410
- const reader = this.deps.metadataReader;
411
- const ImplementationClass = binding.implementationClass;
412
- if (reader === void 0) return new ImplementationClass();
413
- const meta = reader.getConstructorMetadata(binding.implementationClass);
414
- if (ImplementationClass.length > 0 && meta === void 0) throw new MissingMetadataError(registryKeyLabel(binding.implementationClass), pathLabels);
415
- if (meta === void 0 || meta.params.length === 0) return new ImplementationClass();
416
- return new ImplementationClass(...meta.params.map((param) => {
417
- const paramHint = param.name !== void 0 ? { name: param.name } : param.tag !== void 0 ? { tag: param.tag } : void 0;
418
- if (param.all === true) return this.resolveAll(param.token, paramHint, pathLabels, visiting, materializationStack);
419
- if (param.optional) try {
420
- return this.resolve(param.token, paramHint, pathLabels, visiting, materializationStack);
421
- } catch (caughtError) {
422
- if (caughtError instanceof TokenNotBoundError) return;
423
- throw caughtError;
424
- }
425
- return this.resolve(param.token, paramHint, pathLabels, visiting, materializationStack);
426
- }));
427
- }
428
- /**
429
- * Async counterpart of {@link instantiateClassBinding}: resolves constructor dependencies
430
- * with {@link resolveAsync} so `async-dynamic` parameters are awaited in order.
431
- */
432
- async instantiateClassBindingAsync(binding, pathLabels, visiting, materializationStack) {
433
- const reader = this.deps.metadataReader;
434
- const ImplementationClass = binding.implementationClass;
435
- if (reader === void 0) return new ImplementationClass();
436
- const meta = reader.getConstructorMetadata(binding.implementationClass);
437
- if (ImplementationClass.length > 0 && meta === void 0) throw new MissingMetadataError(registryKeyLabel(binding.implementationClass), pathLabels);
438
- if (meta === void 0 || meta.params.length === 0) return new ImplementationClass();
439
- const deps = [];
440
- for (const param of meta.params) {
441
- const paramHint = param.name !== void 0 ? { name: param.name } : param.tag !== void 0 ? { tag: param.tag } : void 0;
442
- if (param.all === true) {
443
- deps.push(await this.resolveAllAsync(param.token, paramHint, pathLabels, visiting, materializationStack));
444
- continue;
445
- }
446
- if (param.optional) try {
447
- deps.push(await this.resolveAsync(param.token, paramHint, pathLabels, visiting, materializationStack));
448
- } catch (caughtError) {
449
- if (caughtError instanceof TokenNotBoundError) deps.push(void 0);
450
- else throw caughtError;
451
- }
452
- else deps.push(await this.resolveAsync(param.token, paramHint, pathLabels, visiting, materializationStack));
649
+ async _resolveTransientDynamicAsyncSlow(binding, resolutionPath, materializationStack) {
650
+ const frame = this._getMaterializationFrame(binding);
651
+ const tName = frame.tokenName;
652
+ const pathWithSet = resolutionPath;
653
+ let resolutionSet = pathWithSet[RESOLUTION_SET_KEY];
654
+ if (resolutionSet === void 0) {
655
+ resolutionSet = new Set(resolutionPath);
656
+ pathWithSet[RESOLUTION_SET_KEY] = resolutionSet;
657
+ }
658
+ if (resolutionSet.has(tName)) throw new CircularDependencyError([...resolutionPath, tName]);
659
+ resolutionPath.push(tName);
660
+ resolutionSet.add(tName);
661
+ materializationStack.push(frame);
662
+ const resolutionCtx = new DefaultResolutionContext(this, resolutionPath, materializationStack, void 0);
663
+ try {
664
+ if (binding.kind === "dynamic-async") return await binding.factory(resolutionCtx);
665
+ const dynamicResult = binding.factory(resolutionCtx);
666
+ return dynamicResult instanceof Promise ? await dynamicResult : dynamicResult;
667
+ } finally {
668
+ materializationStack.pop();
669
+ resolutionPath.pop();
670
+ resolutionSet.delete(tName);
671
+ }
672
+ }
673
+ _resolveCandidateSync(binding, hint, resolutionPath, materializationStack) {
674
+ if (binding.kind === "constant" && binding.onActivation === void 0 && !this._lifecycle.hasActivationHandlers(binding.token)) return binding.value;
675
+ if (binding.kind === "alias") return this.resolve(binding.target, hint, resolutionPath, materializationStack);
676
+ const scope = binding.scope ?? "transient";
677
+ if (scope === "singleton" && this._scope.hasSingleton(binding.id)) return this._scope.getSingleton(binding.id);
678
+ if (scope === "scoped") {
679
+ if (!this._scope.isChild) throw new MissingScopeContextError(this._getTokenName(binding.token));
680
+ if (this._scope.hasScoped(binding.id)) return this._scope.getScoped(binding.id);
681
+ }
682
+ return this._resolveBinding(binding, hint, resolutionPath, materializationStack);
683
+ }
684
+ _resolveCandidateAsync(binding, hint, resolutionPath, materializationStack) {
685
+ if (binding.kind === "constant" && binding.onActivation === void 0 && !this._lifecycle.hasActivationHandlers(binding.token)) return Promise.resolve(binding.value);
686
+ const isolatedPath = [...resolutionPath];
687
+ const isolatedStack = [...materializationStack];
688
+ if (binding.kind === "alias") return this.resolveAsync(binding.target, hint, isolatedPath, isolatedStack);
689
+ const scope = binding.scope ?? "transient";
690
+ if (scope === "singleton" && this._scope.hasSingleton(binding.id)) return Promise.resolve(this._scope.getSingleton(binding.id));
691
+ if (scope === "scoped") {
692
+ if (!this._scope.isChild) return Promise.reject(new MissingScopeContextError(this._getTokenName(binding.token)));
693
+ if (this._scope.hasScoped(binding.id)) return Promise.resolve(this._scope.getScoped(binding.id));
694
+ }
695
+ return this._resolveBindingAsync(binding, hint, isolatedPath, isolatedStack);
696
+ }
697
+ _getMaterializationFrame(binding) {
698
+ const existing = this._frameByBindingId.get(binding.id);
699
+ if (existing !== void 0) return existing;
700
+ const scope = binding.scope ?? "transient";
701
+ const frame = buildMaterializationFrame(tokenName(binding.token), scope, binding.id, binding.kind, binding.slot);
702
+ this._frameByBindingId.set(binding.id, frame);
703
+ return frame;
704
+ }
705
+ _needsActivation(binding) {
706
+ const lifecycleVersion = this._lifecycle.activationVersion;
707
+ if (lifecycleVersion === 0 && binding.kind !== "class" && binding.kind !== "alias" && binding.onActivation === void 0) return false;
708
+ if (this._activationCacheVersion !== lifecycleVersion) {
709
+ this._activationNeedByBindingId.clear();
710
+ this._activationCacheVersion = lifecycleVersion;
711
+ }
712
+ const cached = this._activationNeedByBindingId.get(binding.id);
713
+ if (cached !== void 0) return cached;
714
+ if (binding.kind === "class") {
715
+ let hasActivation = this._lifecycle.hasActivationHandlers(binding.token) || binding.onActivation !== void 0;
716
+ const cachedPostConstruct = this._classHasPostConstruct.get(binding.target);
717
+ if (cachedPostConstruct === void 0) hasActivation = true;
718
+ else if (cachedPostConstruct) hasActivation = true;
719
+ this._activationNeedByBindingId.set(binding.id, hasActivation);
720
+ return hasActivation;
721
+ }
722
+ let hasActivation = false;
723
+ if (binding.kind !== "alias" && binding.onActivation !== void 0) hasActivation = true;
724
+ else if (this._lifecycle.hasActivationHandlers(binding.token)) hasActivation = true;
725
+ this._activationNeedByBindingId.set(binding.id, hasActivation);
726
+ return hasActivation;
727
+ }
728
+ _refreshClassPostConstructCache(target) {
729
+ const lifecycle = this._metadataReader.getLifecycleMetadata(target);
730
+ const hasPostConstruct = lifecycle !== void 0 && lifecycle.postConstruct !== void 0 && lifecycle.postConstruct.length > 0;
731
+ this._classHasPostConstruct.set(target, hasPostConstruct);
732
+ }
733
+ _requiresResolutionContext(binding) {
734
+ return binding.kind === "dynamic" || binding.kind === "dynamic-async";
735
+ }
736
+ _acquireSyncResolutionContext(resolutionPath, materializationStack, hint) {
737
+ const depth = materializationStack.length;
738
+ const existing = this._syncResolutionContextPool[depth];
739
+ if (existing !== void 0) {
740
+ existing.reset(this, resolutionPath, materializationStack, hint);
741
+ return existing;
453
742
  }
454
- return new ImplementationClass(...deps);
743
+ const created = new DefaultResolutionContext(this, resolutionPath, materializationStack, hint);
744
+ this._syncResolutionContextPool[depth] = created;
745
+ return created;
455
746
  }
456
747
  };
457
748
  //#endregion