@codefast/di 0.7.0 → 0.8.0

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 (173) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +1 -1
  3. package/dist/ambient/active-container.d.ts +4 -0
  4. package/dist/ambient/active-container.d.ts.map +1 -1
  5. package/dist/ambient/active-container.js +4 -0
  6. package/dist/ambient/active-container.js.map +1 -1
  7. package/dist/container/binding-builders.d.ts.map +1 -1
  8. package/dist/container/binding-builders.js +4 -5
  9. package/dist/container/binding-builders.js.map +1 -1
  10. package/dist/container/container.d.ts +6 -0
  11. package/dist/container/container.d.ts.map +1 -1
  12. package/dist/container/container.js +5 -4
  13. package/dist/container/container.js.map +1 -1
  14. package/dist/core/binding.d.ts +15 -2
  15. package/dist/core/binding.d.ts.map +1 -1
  16. package/dist/core/binding.js +29 -4
  17. package/dist/core/binding.js.map +1 -1
  18. package/dist/core/module.d.ts +16 -0
  19. package/dist/core/module.d.ts.map +1 -1
  20. package/dist/core/module.js +8 -0
  21. package/dist/core/module.js.map +1 -1
  22. package/dist/core/registry.d.ts +2 -3
  23. package/dist/core/registry.d.ts.map +1 -1
  24. package/dist/core/registry.js +16 -61
  25. package/dist/core/registry.js.map +1 -1
  26. package/dist/core/tag.d.ts +26 -0
  27. package/dist/core/tag.d.ts.map +1 -1
  28. package/dist/core/tag.js +54 -11
  29. package/dist/core/tag.js.map +1 -1
  30. package/dist/core/token.d.ts +6 -0
  31. package/dist/core/token.d.ts.map +1 -1
  32. package/dist/core/token.js +4 -0
  33. package/dist/core/token.js.map +1 -1
  34. package/dist/core/types.d.ts +20 -0
  35. package/dist/core/types.d.ts.map +1 -1
  36. package/dist/decorators/inject.d.ts +2 -0
  37. package/dist/decorators/inject.d.ts.map +1 -1
  38. package/dist/decorators/inject.js +2 -0
  39. package/dist/decorators/inject.js.map +1 -1
  40. package/dist/decorators/injectable.d.ts +6 -0
  41. package/dist/decorators/injectable.d.ts.map +1 -1
  42. package/dist/decorators/injectable.js +4 -0
  43. package/dist/decorators/injectable.js.map +1 -1
  44. package/dist/decorators/lifecycle-decorators.d.ts +4 -0
  45. package/dist/decorators/lifecycle-decorators.d.ts.map +1 -1
  46. package/dist/decorators/lifecycle-decorators.js +4 -0
  47. package/dist/decorators/lifecycle-decorators.js.map +1 -1
  48. package/dist/errors/errors.d.ts +34 -0
  49. package/dist/errors/errors.d.ts.map +1 -1
  50. package/dist/errors/errors.js +60 -3
  51. package/dist/errors/errors.js.map +1 -1
  52. package/dist/index.d.ts +1 -1
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +1 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/injection/descriptor.d.ts +12 -0
  57. package/dist/injection/descriptor.d.ts.map +1 -1
  58. package/dist/injection/descriptor.js +8 -0
  59. package/dist/injection/descriptor.js.map +1 -1
  60. package/dist/injection/resolve-options.d.ts +17 -12
  61. package/dist/injection/resolve-options.d.ts.map +1 -1
  62. package/dist/injection/resolve-options.js +69 -15
  63. package/dist/injection/resolve-options.js.map +1 -1
  64. package/dist/introspection/dependency-graph.d.ts +6 -0
  65. package/dist/introspection/dependency-graph.d.ts.map +1 -1
  66. package/dist/introspection/dependency-graph.js +24 -9
  67. package/dist/introspection/dependency-graph.js.map +1 -1
  68. package/dist/introspection/graph-adapters/cytoscape.d.ts +8 -0
  69. package/dist/introspection/graph-adapters/cytoscape.d.ts.map +1 -1
  70. package/dist/introspection/graph-adapters/cytoscape.js +2 -0
  71. package/dist/introspection/graph-adapters/cytoscape.js.map +1 -1
  72. package/dist/introspection/graph-adapters/dot.d.ts +2 -0
  73. package/dist/introspection/graph-adapters/dot.d.ts.map +1 -1
  74. package/dist/introspection/graph-adapters/dot.js +2 -0
  75. package/dist/introspection/graph-adapters/dot.js.map +1 -1
  76. package/dist/introspection/graph-adapters/reactflow.d.ts +8 -0
  77. package/dist/introspection/graph-adapters/reactflow.d.ts.map +1 -1
  78. package/dist/introspection/graph-adapters/reactflow.js +2 -0
  79. package/dist/introspection/graph-adapters/reactflow.js.map +1 -1
  80. package/dist/introspection/inspector.d.ts +6 -0
  81. package/dist/introspection/inspector.d.ts.map +1 -1
  82. package/dist/introspection/inspector.js +2 -0
  83. package/dist/introspection/inspector.js.map +1 -1
  84. package/dist/lifecycle/lifecycle-manager.d.ts +2 -0
  85. package/dist/lifecycle/lifecycle-manager.d.ts.map +1 -1
  86. package/dist/lifecycle/lifecycle-manager.js +2 -0
  87. package/dist/lifecycle/lifecycle-manager.js.map +1 -1
  88. package/dist/lifecycle/scope-manager.d.ts +2 -0
  89. package/dist/lifecycle/scope-manager.d.ts.map +1 -1
  90. package/dist/lifecycle/scope-manager.js +2 -0
  91. package/dist/lifecycle/scope-manager.js.map +1 -1
  92. package/dist/metadata/metadata-keys.d.ts +6 -0
  93. package/dist/metadata/metadata-keys.d.ts.map +1 -1
  94. package/dist/metadata/metadata-keys.js +6 -0
  95. package/dist/metadata/metadata-keys.js.map +1 -1
  96. package/dist/metadata/metadata-reader-token.d.ts +2 -0
  97. package/dist/metadata/metadata-reader-token.d.ts.map +1 -1
  98. package/dist/metadata/metadata-reader-token.js +2 -0
  99. package/dist/metadata/metadata-reader-token.js.map +1 -1
  100. package/dist/metadata/metadata-types.d.ts +6 -0
  101. package/dist/metadata/metadata-types.d.ts.map +1 -1
  102. package/dist/metadata/symbol-metadata-reader.d.ts +4 -0
  103. package/dist/metadata/symbol-metadata-reader.d.ts.map +1 -1
  104. package/dist/metadata/symbol-metadata-reader.js +4 -0
  105. package/dist/metadata/symbol-metadata-reader.js.map +1 -1
  106. package/dist/resolution/cache/activation-need.d.ts +2 -0
  107. package/dist/resolution/cache/activation-need.d.ts.map +1 -1
  108. package/dist/resolution/cache/activation-need.js +2 -0
  109. package/dist/resolution/cache/activation-need.js.map +1 -1
  110. package/dist/resolution/cache/binding-lookup-cache.d.ts +2 -2
  111. package/dist/resolution/cache/binding-lookup-cache.d.ts.map +1 -1
  112. package/dist/resolution/cache/binding-lookup-cache.js +2 -37
  113. package/dist/resolution/cache/binding-lookup-cache.js.map +1 -1
  114. package/dist/resolution/cache/class-introspector.d.ts +2 -0
  115. package/dist/resolution/cache/class-introspector.d.ts.map +1 -1
  116. package/dist/resolution/cache/class-introspector.js +2 -0
  117. package/dist/resolution/cache/class-introspector.js.map +1 -1
  118. package/dist/resolution/context.d.ts +6 -0
  119. package/dist/resolution/context.d.ts.map +1 -1
  120. package/dist/resolution/context.js +4 -0
  121. package/dist/resolution/context.js.map +1 -1
  122. package/dist/resolution/plan/instantiation-plan.d.ts +6 -12
  123. package/dist/resolution/plan/instantiation-plan.d.ts.map +1 -1
  124. package/dist/resolution/plan/instantiation-plan.js +11 -27
  125. package/dist/resolution/plan/instantiation-plan.js.map +1 -1
  126. package/dist/resolution/resolver.d.ts +14 -5
  127. package/dist/resolution/resolver.d.ts.map +1 -1
  128. package/dist/resolution/resolver.js +108 -141
  129. package/dist/resolution/resolver.js.map +1 -1
  130. package/dist/resolution/select/binding-select.d.ts +4 -5
  131. package/dist/resolution/select/binding-select.d.ts.map +1 -1
  132. package/dist/resolution/select/binding-select.js +18 -20
  133. package/dist/resolution/select/binding-select.js.map +1 -1
  134. package/dist/resolution/select/constraints.d.ts +16 -0
  135. package/dist/resolution/select/constraints.d.ts.map +1 -1
  136. package/dist/resolution/select/constraints.js +16 -0
  137. package/dist/resolution/select/constraints.js.map +1 -1
  138. package/package.json +13 -6
  139. package/src/ambient/active-container.ts +4 -0
  140. package/src/container/binding-builders.ts +10 -5
  141. package/src/container/container.ts +9 -4
  142. package/src/core/binding.ts +33 -5
  143. package/src/core/module.ts +16 -0
  144. package/src/core/registry.ts +16 -66
  145. package/src/core/tag.ts +71 -17
  146. package/src/core/token.ts +6 -0
  147. package/src/core/types.ts +20 -0
  148. package/src/decorators/inject.ts +2 -0
  149. package/src/decorators/injectable.ts +8 -0
  150. package/src/decorators/lifecycle-decorators.ts +4 -0
  151. package/src/errors/errors.ts +62 -5
  152. package/src/index.ts +1 -1
  153. package/src/injection/descriptor.ts +12 -0
  154. package/src/injection/resolve-options.ts +75 -18
  155. package/src/introspection/dependency-graph.ts +29 -9
  156. package/src/introspection/graph-adapters/cytoscape.ts +8 -0
  157. package/src/introspection/graph-adapters/dot.ts +2 -0
  158. package/src/introspection/graph-adapters/reactflow.ts +8 -0
  159. package/src/introspection/inspector.ts +6 -0
  160. package/src/lifecycle/lifecycle-manager.ts +2 -0
  161. package/src/lifecycle/scope-manager.ts +2 -0
  162. package/src/metadata/metadata-keys.ts +6 -0
  163. package/src/metadata/metadata-reader-token.ts +2 -0
  164. package/src/metadata/metadata-types.ts +6 -0
  165. package/src/metadata/symbol-metadata-reader.ts +4 -0
  166. package/src/resolution/cache/activation-need.ts +2 -0
  167. package/src/resolution/cache/binding-lookup-cache.ts +2 -40
  168. package/src/resolution/cache/class-introspector.ts +2 -0
  169. package/src/resolution/context.ts +6 -0
  170. package/src/resolution/plan/instantiation-plan.ts +15 -38
  171. package/src/resolution/resolver.ts +122 -141
  172. package/src/resolution/select/binding-select.ts +18 -21
  173. package/src/resolution/select/constraints.ts +16 -0
@@ -6,6 +6,8 @@ import type { ConstructorMetadata, LifecycleMetadata, MetadataReader } from "#/m
6
6
  type AccessorEntry = { readonly key: string | symbol; readonly descriptor: InjectionDescriptor };
7
7
 
8
8
  /**
9
+ * The default `MetadataReader`, reading decorator metadata stored under `Symbol.metadata`.
10
+ *
9
11
  * @since 0.3.16-canary.0
10
12
  */
11
13
  export class SymbolMetadataReader implements MetadataReader {
@@ -117,6 +119,8 @@ function mergeUniqueNames(lists: Array<ReadonlyArray<string>>): Array<string> {
117
119
  }
118
120
 
119
121
  /**
122
+ * The shared reader a container falls back to when given no custom `MetadataReader`.
123
+ *
120
124
  * @since 0.3.16-canary.0
121
125
  */
122
126
  export const defaultMetadataReader: SymbolMetadataReader = new SymbolMetadataReader();
@@ -11,6 +11,8 @@ import type { LifecycleManager } from "#/lifecycle/lifecycle-manager";
11
11
  import type { ClassIntrospector } from "#/resolution/cache/class-introspector";
12
12
 
13
13
  /**
14
+ * A per-binding cache of whether activation work — hooks or `@postConstruct` — is needed on resolve.
15
+ *
14
16
  * @since 0.5.0-canary.8
15
17
  */
16
18
  export class ActivationNeedCache {
@@ -31,14 +31,11 @@ export interface DefaultLookupEntry<Owner> {
31
31
  */
32
32
  export const ALIAS_HOP_LIMIT = 32;
33
33
 
34
- /**
35
- * @since 0.5.0-canary.8
36
- */
37
- const newNameToEntryMap = <Owner>(): Map<string, DefaultLookupEntry<Owner> | null> => new Map();
38
-
39
34
  const newTagToEntryMap = <Owner>(): Map<BindingTag, DefaultLookupEntry<Owner> | null> => new Map();
40
35
 
41
36
  /**
37
+ * A version-stamped cache of binding lookups by token and criterion across the container chain.
38
+ *
42
39
  * @since 0.5.0-canary.9
43
40
  */
44
41
  export class BindingLookupCache<Owner> {
@@ -49,8 +46,6 @@ export class BindingLookupCache<Owner> {
49
46
  // is tracked by the token slot rather than by the entry.
50
47
  #lastToken: Token<unknown> | Constructor | undefined;
51
48
  #lastEntry: DefaultLookupEntry<Owner> | null = null;
52
- readonly #byTokenAndName = new Map<Token<unknown> | Constructor, Map<string, DefaultLookupEntry<Owner> | null>>();
53
- #namedVersion = -1;
54
49
  readonly #byTokenAndTag = new Map<Token<unknown> | Constructor, Map<BindingTag, DefaultLookupEntry<Owner> | null>>();
55
50
  #taggedVersion = -1;
56
51
  // One entry in front of the tag map, and the map is not written until a second distinct request
@@ -99,24 +94,6 @@ export class BindingLookupCache<Owner> {
99
94
  return entry;
100
95
  }
101
96
 
102
- /** `null` when the name's shape needs the full selection path. */
103
- namedEntry(token: Token<unknown> | Constructor, name: string): DefaultLookupEntry<Owner> | null {
104
- const version = this.chainVersion();
105
- if (version !== this.#namedVersion) {
106
- this.#byTokenAndName.clear();
107
- this.#namedVersion = version;
108
- }
109
- // Computed, not eager: this runs on every named resolve, and the eager form would allocate a
110
- // Map per call only to discard it on the hit that follows.
111
- const byName = getOrInsertComputed(this.#byTokenAndName, token, newNameToEntryMap);
112
- let entry = byName.get(name);
113
- if (entry === undefined) {
114
- entry = this.#findNamedInChain(token, name);
115
- byName.set(name, entry);
116
- }
117
- return entry;
118
- }
119
-
120
97
  /** `null` when the tag's shape needs the full selection path. */
121
98
  taggedEntry(token: Token<unknown> | Constructor, tag: BindingTag): DefaultLookupEntry<Owner> | null {
122
99
  const version = this.chainVersion();
@@ -175,21 +152,6 @@ export class BindingLookupCache<Owner> {
175
152
  return this.#parent === undefined ? null : this.#parent.#findDefaultInChain(token);
176
153
  }
177
154
 
178
- #findNamedInChain(token: Token<unknown> | Constructor, name: string): DefaultLookupEntry<Owner> | null {
179
- const named = this.#registry.getSimpleNamed(token, name);
180
- if (named !== undefined) {
181
- // Predicates need a live context; aliases carry options through the full path.
182
- if (named.predicate !== undefined || named.kind === "alias") {
183
- return null;
184
- }
185
- return { binding: named, owner: this.#owner };
186
- }
187
- if (this.#registry.has(token)) {
188
- return null;
189
- }
190
- return this.#parent === undefined ? null : this.#parent.#findNamedInChain(token, name);
191
- }
192
-
193
155
  #findTaggedInChain(token: Token<unknown> | Constructor, tag: BindingTag): DefaultLookupEntry<Owner> | null {
194
156
  const tagged = this.#registry.getSimpleTagged(token, tag);
195
157
  if (tagged !== undefined) {
@@ -188,6 +188,8 @@ export function verifyAccessorMetadata(
188
188
  }
189
189
 
190
190
  /**
191
+ * A per-class cache of constructor metadata and the activation facts derived from it.
192
+ *
191
193
  * @since 0.5.0-canary.8
192
194
  */
193
195
  export class ClassIntrospector {
@@ -16,6 +16,8 @@ import { UNOWNED_BRANCH } from "#/resolution/path/resolution-path";
16
16
  // ── ResolutionContext implementation ─────────────────────────────────────────────────────────────────────────────────
17
17
 
18
18
  /**
19
+ * The engine surface a resolution context calls back into to resolve further dependencies.
20
+ *
19
21
  * @since 0.3.16-canary.0
20
22
  */
21
23
  export interface ResolverCallbacks {
@@ -60,6 +62,8 @@ export interface ResolverCallbacks {
60
62
  }
61
63
 
62
64
  /**
65
+ * The `ResolutionContext` handed to factories and hooks, backed by the engine's callbacks.
66
+ *
63
67
  * @since 0.3.16-canary.0
64
68
  */
65
69
  export class DefaultResolutionContext implements ResolutionContext {
@@ -312,6 +316,8 @@ class DefaultConstraintContext implements ConstraintContext {
312
316
  }
313
317
 
314
318
  /**
319
+ * Creates the resolution-stack frame for one in-flight resolve.
320
+ *
315
321
  * @since 0.3.16-canary.0
316
322
  */
317
323
  export function buildResolutionFrame(
@@ -12,7 +12,7 @@ import { tokenName } from "#/core/token";
12
12
  import type { Constructor, ResolutionFrame, ResolveOptions } from "#/core/types";
13
13
  import { AsyncResolutionError } from "#/errors/errors";
14
14
  import type { DependencySlot } from "#/injection/resolve-options";
15
- import { injectionSlotToResolveOptions, isNameOnlyOptions } from "#/injection/resolve-options";
15
+ import { injectionSlotToResolveOptions } from "#/injection/resolve-options";
16
16
  import type { ConstructorMetadata } from "#/metadata/metadata-types";
17
17
 
18
18
  // Past this depth a dependency escapes to the runtime path rather than inlining further —
@@ -115,22 +115,13 @@ export interface InstantiationPlanHost {
115
115
  /** Options-less lookup with alias hops folded; `null` when the fast lane can't answer. */
116
116
  lookupDependencyEntry(token: Token<unknown> | Constructor): InstantiationPlanDependencyEntry | null;
117
117
  /**
118
- * A name-only lookup a plan may bake in, or `null` when the answer is not the compiler's to make.
118
+ * A single-criterion lookup a plan may bake in, or `null` when the answer is not the compiler's
119
+ * to make.
119
120
  *
120
- * @remarks Selection for a named request is an index hit *and* a predicate, and a predicate reads
121
+ * @remarks Selection for such a request is an index hit *and* a predicate, and a predicate reads
121
122
  * the resolution path — so only a candidate carrying none of one can be decided ahead of time.
122
123
  */
123
- lookupPathIndependentNamedEntry(
124
- token: Token<unknown> | Constructor,
125
- options: ResolveOptions & { name: string },
126
- ): InstantiationPlanDependencyEntry | null;
127
- /**
128
- * The named lookup's single-tag twin, or `null` under the same rule.
129
- *
130
- * @remarks Optional so a host predating it stays a valid host — a compiler given none simply
131
- * escapes the dependency, which is exactly the pre-settlement behavior.
132
- */
133
- lookupPathIndependentTaggedEntry?(
124
+ lookupPathIndependentEntry(
134
125
  token: Token<unknown> | Constructor,
135
126
  options: ResolveOptions,
136
127
  ): InstantiationPlanDependencyEntry | null;
@@ -161,6 +152,8 @@ export interface InstantiationPlanHost {
161
152
  export type EscapeArity = "all" | "optional" | "single";
162
153
 
163
154
  /**
155
+ * The compiler that flattens a class or resolved binding's dependencies into an instantiation plan.
156
+ *
164
157
  * @since 0.3.16-canary.1
165
158
  */
166
159
  export class InstantiationPlanCompiler {
@@ -263,19 +256,11 @@ export class InstantiationPlanCompiler {
263
256
  return this.#compileEscapeThunk(token, ancestors, "optional", options);
264
257
  }
265
258
  if (options !== undefined) {
266
- // A name the registry can settle without reading a path is a dependency like any other: it
267
- // escapes only because it carries a criterion, not because anything about it is opaque.
268
- if (isNameOnlyOptions(options)) {
269
- const named = this.#host.lookupPathIndependentNamedEntry(token, options);
270
- if (named !== null) {
271
- return this.#compileDepThunk(named, compileStack, depth, ancestors, options);
272
- }
273
- } else {
274
- // The host owns the whole single-tag decision, including whether the options qualify.
275
- const tagged = this.#host.lookupPathIndependentTaggedEntry?.(token, options);
276
- if (tagged !== null && tagged !== undefined) {
277
- return this.#compileDepThunk(tagged, compileStack, depth, ancestors, options);
278
- }
259
+ // A criterion the registry can settle without reading a path is a dependency like any other:
260
+ // it escapes only because the host cannot decide it ahead of time.
261
+ const indexed = this.#host.lookupPathIndependentEntry(token, options);
262
+ if (indexed !== null) {
263
+ return this.#compileDepThunk(indexed, compileStack, depth, ancestors, options);
279
264
  }
280
265
  return this.#compileEscapeThunk(token, ancestors, "single", options);
281
266
  }
@@ -539,17 +524,9 @@ export class InstantiationPlanCompiler {
539
524
  return this.#compileAsyncEscapeThunk(token, ancestors, "optional", options);
540
525
  }
541
526
  if (options !== undefined) {
542
- if (isNameOnlyOptions(options)) {
543
- const named = this.#host.lookupPathIndependentNamedEntry(token, options);
544
- if (named !== null) {
545
- return this.#compileAsyncDepThunk(named, compileStack, depth, ancestors, options);
546
- }
547
- } else {
548
- // The host owns the whole single-tag decision, including whether the options qualify.
549
- const tagged = this.#host.lookupPathIndependentTaggedEntry?.(token, options);
550
- if (tagged !== null && tagged !== undefined) {
551
- return this.#compileAsyncDepThunk(tagged, compileStack, depth, ancestors, options);
552
- }
527
+ const indexed = this.#host.lookupPathIndependentEntry(token, options);
528
+ if (indexed !== null) {
529
+ return this.#compileAsyncDepThunk(indexed, compileStack, depth, ancestors, options);
553
530
  }
554
531
  return this.#compileAsyncEscapeThunk(token, ancestors, "single", options);
555
532
  }