@codefast/di 0.7.1 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +242 -159
  3. package/dist/ambient/active-container.d.ts +1 -2
  4. package/dist/ambient/active-container.js +1 -2
  5. package/dist/container/binding-builders.d.ts +1 -2
  6. package/dist/container/binding-builders.js +5 -7
  7. package/dist/container/container.d.ts +1 -2
  8. package/dist/container/container.js +4 -6
  9. package/dist/core/binding-scope.d.ts +1 -2
  10. package/dist/core/binding-scope.js +1 -2
  11. package/dist/core/binding.d.ts +16 -4
  12. package/dist/core/binding.js +30 -6
  13. package/dist/core/constraint-requirement.d.ts +1 -2
  14. package/dist/core/constraint-requirement.js +1 -2
  15. package/dist/core/constructor-type.d.ts +1 -2
  16. package/dist/core/constructor-type.js +1 -2
  17. package/dist/core/map-upsert.d.ts +1 -2
  18. package/dist/core/map-upsert.js +1 -2
  19. package/dist/core/module.d.ts +1 -2
  20. package/dist/core/module.js +1 -2
  21. package/dist/core/registry.d.ts +1 -5
  22. package/dist/core/registry.js +15 -63
  23. package/dist/core/tag.d.ts +27 -2
  24. package/dist/core/tag.js +55 -13
  25. package/dist/core/token.d.ts +1 -2
  26. package/dist/core/token.js +1 -2
  27. package/dist/core/types.d.ts +1 -2
  28. package/dist/core/types.js +1 -2
  29. package/dist/decorators/inject.d.ts +1 -2
  30. package/dist/decorators/inject.js +1 -2
  31. package/dist/decorators/injectable.d.ts +1 -2
  32. package/dist/decorators/injectable.js +1 -2
  33. package/dist/decorators/lifecycle-decorators.d.ts +1 -2
  34. package/dist/decorators/lifecycle-decorators.js +1 -2
  35. package/dist/errors/diagnostics.d.ts +1 -2
  36. package/dist/errors/diagnostics.js +1 -2
  37. package/dist/errors/errors.d.ts +1 -2
  38. package/dist/errors/errors.js +29 -5
  39. package/dist/index.d.ts +2 -3
  40. package/dist/index.js +2 -3
  41. package/dist/injection/descriptor.d.ts +1 -2
  42. package/dist/injection/descriptor.js +1 -2
  43. package/dist/injection/resolve-options.d.ts +18 -14
  44. package/dist/injection/resolve-options.js +70 -17
  45. package/dist/introspection/dependency-graph.d.ts +1 -2
  46. package/dist/introspection/dependency-graph.js +23 -11
  47. package/dist/introspection/graph-adapters/cytoscape.d.ts +1 -2
  48. package/dist/introspection/graph-adapters/cytoscape.js +1 -2
  49. package/dist/introspection/graph-adapters/dot.d.ts +1 -2
  50. package/dist/introspection/graph-adapters/dot.js +1 -2
  51. package/dist/introspection/graph-adapters/mermaid.d.ts +1 -2
  52. package/dist/introspection/graph-adapters/mermaid.js +1 -2
  53. package/dist/introspection/graph-adapters/reactflow.d.ts +1 -2
  54. package/dist/introspection/graph-adapters/reactflow.js +1 -2
  55. package/dist/introspection/inspector.d.ts +1 -2
  56. package/dist/introspection/inspector.js +1 -2
  57. package/dist/lifecycle/lifecycle-manager.d.ts +1 -2
  58. package/dist/lifecycle/lifecycle-manager.js +1 -2
  59. package/dist/lifecycle/scope-manager.d.ts +1 -2
  60. package/dist/lifecycle/scope-manager.js +1 -2
  61. package/dist/metadata/metadata-keys.d.ts +1 -2
  62. package/dist/metadata/metadata-keys.js +1 -2
  63. package/dist/metadata/metadata-reader-token.d.ts +1 -2
  64. package/dist/metadata/metadata-reader-token.js +1 -2
  65. package/dist/metadata/metadata-types.d.ts +1 -2
  66. package/dist/metadata/metadata-types.js +1 -2
  67. package/dist/metadata/symbol-metadata-reader.d.ts +1 -2
  68. package/dist/metadata/symbol-metadata-reader.js +1 -2
  69. package/dist/metadata/verifying-metadata-reader.d.ts +1 -2
  70. package/dist/metadata/verifying-metadata-reader.js +1 -2
  71. package/dist/resolution/cache/activation-need.d.ts +1 -2
  72. package/dist/resolution/cache/activation-need.js +1 -2
  73. package/dist/resolution/cache/binding-lookup-cache.d.ts +2 -5
  74. package/dist/resolution/cache/binding-lookup-cache.js +2 -40
  75. package/dist/resolution/cache/class-introspector.d.ts +1 -2
  76. package/dist/resolution/cache/class-introspector.js +1 -2
  77. package/dist/resolution/context.d.ts +1 -2
  78. package/dist/resolution/context.js +1 -2
  79. package/dist/resolution/path/resolution-path.d.ts +1 -2
  80. package/dist/resolution/path/resolution-path.js +1 -2
  81. package/dist/resolution/plan/instantiation-plan.d.ts +5 -14
  82. package/dist/resolution/plan/instantiation-plan.js +10 -29
  83. package/dist/resolution/resolver.d.ts +13 -7
  84. package/dist/resolution/resolver.js +107 -143
  85. package/dist/resolution/select/binding-select.d.ts +5 -7
  86. package/dist/resolution/select/binding-select.js +19 -22
  87. package/dist/resolution/select/constraints.d.ts +1 -2
  88. package/dist/resolution/select/constraints.js +1 -2
  89. package/package.json +6 -58
  90. package/dist/ambient/active-container.d.ts.map +0 -1
  91. package/dist/ambient/active-container.js.map +0 -1
  92. package/dist/container/binding-builders.d.ts.map +0 -1
  93. package/dist/container/binding-builders.js.map +0 -1
  94. package/dist/container/container.d.ts.map +0 -1
  95. package/dist/container/container.js.map +0 -1
  96. package/dist/core/binding-scope.d.ts.map +0 -1
  97. package/dist/core/binding-scope.js.map +0 -1
  98. package/dist/core/binding.d.ts.map +0 -1
  99. package/dist/core/binding.js.map +0 -1
  100. package/dist/core/constraint-requirement.d.ts.map +0 -1
  101. package/dist/core/constraint-requirement.js.map +0 -1
  102. package/dist/core/constructor-type.d.ts.map +0 -1
  103. package/dist/core/constructor-type.js.map +0 -1
  104. package/dist/core/map-upsert.d.ts.map +0 -1
  105. package/dist/core/map-upsert.js.map +0 -1
  106. package/dist/core/module.d.ts.map +0 -1
  107. package/dist/core/module.js.map +0 -1
  108. package/dist/core/registry.d.ts.map +0 -1
  109. package/dist/core/registry.js.map +0 -1
  110. package/dist/core/tag.d.ts.map +0 -1
  111. package/dist/core/tag.js.map +0 -1
  112. package/dist/core/token.d.ts.map +0 -1
  113. package/dist/core/token.js.map +0 -1
  114. package/dist/core/types.d.ts.map +0 -1
  115. package/dist/core/types.js.map +0 -1
  116. package/dist/decorators/inject.d.ts.map +0 -1
  117. package/dist/decorators/inject.js.map +0 -1
  118. package/dist/decorators/injectable.d.ts.map +0 -1
  119. package/dist/decorators/injectable.js.map +0 -1
  120. package/dist/decorators/lifecycle-decorators.d.ts.map +0 -1
  121. package/dist/decorators/lifecycle-decorators.js.map +0 -1
  122. package/dist/errors/diagnostics.d.ts.map +0 -1
  123. package/dist/errors/diagnostics.js.map +0 -1
  124. package/dist/errors/errors.d.ts.map +0 -1
  125. package/dist/errors/errors.js.map +0 -1
  126. package/dist/index.d.ts.map +0 -1
  127. package/dist/index.js.map +0 -1
  128. package/dist/injection/descriptor.d.ts.map +0 -1
  129. package/dist/injection/descriptor.js.map +0 -1
  130. package/dist/injection/resolve-options.d.ts.map +0 -1
  131. package/dist/injection/resolve-options.js.map +0 -1
  132. package/dist/introspection/dependency-graph.d.ts.map +0 -1
  133. package/dist/introspection/dependency-graph.js.map +0 -1
  134. package/dist/introspection/graph-adapters/cytoscape.d.ts.map +0 -1
  135. package/dist/introspection/graph-adapters/cytoscape.js.map +0 -1
  136. package/dist/introspection/graph-adapters/dot.d.ts.map +0 -1
  137. package/dist/introspection/graph-adapters/dot.js.map +0 -1
  138. package/dist/introspection/graph-adapters/mermaid.d.ts.map +0 -1
  139. package/dist/introspection/graph-adapters/mermaid.js.map +0 -1
  140. package/dist/introspection/graph-adapters/reactflow.d.ts.map +0 -1
  141. package/dist/introspection/graph-adapters/reactflow.js.map +0 -1
  142. package/dist/introspection/inspector.d.ts.map +0 -1
  143. package/dist/introspection/inspector.js.map +0 -1
  144. package/dist/lifecycle/lifecycle-manager.d.ts.map +0 -1
  145. package/dist/lifecycle/lifecycle-manager.js.map +0 -1
  146. package/dist/lifecycle/scope-manager.d.ts.map +0 -1
  147. package/dist/lifecycle/scope-manager.js.map +0 -1
  148. package/dist/metadata/metadata-keys.d.ts.map +0 -1
  149. package/dist/metadata/metadata-keys.js.map +0 -1
  150. package/dist/metadata/metadata-reader-token.d.ts.map +0 -1
  151. package/dist/metadata/metadata-reader-token.js.map +0 -1
  152. package/dist/metadata/metadata-types.d.ts.map +0 -1
  153. package/dist/metadata/metadata-types.js.map +0 -1
  154. package/dist/metadata/symbol-metadata-reader.d.ts.map +0 -1
  155. package/dist/metadata/symbol-metadata-reader.js.map +0 -1
  156. package/dist/metadata/verifying-metadata-reader.d.ts.map +0 -1
  157. package/dist/metadata/verifying-metadata-reader.js.map +0 -1
  158. package/dist/resolution/cache/activation-need.d.ts.map +0 -1
  159. package/dist/resolution/cache/activation-need.js.map +0 -1
  160. package/dist/resolution/cache/binding-lookup-cache.d.ts.map +0 -1
  161. package/dist/resolution/cache/binding-lookup-cache.js.map +0 -1
  162. package/dist/resolution/cache/class-introspector.d.ts.map +0 -1
  163. package/dist/resolution/cache/class-introspector.js.map +0 -1
  164. package/dist/resolution/context.d.ts.map +0 -1
  165. package/dist/resolution/context.js.map +0 -1
  166. package/dist/resolution/path/resolution-path.d.ts.map +0 -1
  167. package/dist/resolution/path/resolution-path.js.map +0 -1
  168. package/dist/resolution/plan/instantiation-plan.d.ts.map +0 -1
  169. package/dist/resolution/plan/instantiation-plan.js.map +0 -1
  170. package/dist/resolution/resolver.d.ts.map +0 -1
  171. package/dist/resolution/resolver.js.map +0 -1
  172. package/dist/resolution/select/binding-select.d.ts.map +0 -1
  173. package/dist/resolution/select/binding-select.js.map +0 -1
  174. package/dist/resolution/select/constraints.d.ts.map +0 -1
  175. package/dist/resolution/select/constraints.js.map +0 -1
  176. package/src/ambient/active-container.ts +0 -69
  177. package/src/container/binding-builders.ts +0 -332
  178. package/src/container/container.ts +0 -973
  179. package/src/core/binding-scope.ts +0 -15
  180. package/src/core/binding.ts +0 -477
  181. package/src/core/constraint-requirement.ts +0 -94
  182. package/src/core/constructor-type.ts +0 -18
  183. package/src/core/map-upsert.ts +0 -53
  184. package/src/core/module.ts +0 -117
  185. package/src/core/registry.ts +0 -371
  186. package/src/core/tag.ts +0 -158
  187. package/src/core/token.ts +0 -31
  188. package/src/core/types.ts +0 -149
  189. package/src/decorators/inject.ts +0 -101
  190. package/src/decorators/injectable.ts +0 -134
  191. package/src/decorators/lifecycle-decorators.ts +0 -43
  192. package/src/errors/diagnostics.ts +0 -45
  193. package/src/errors/errors.ts +0 -476
  194. package/src/index.ts +0 -139
  195. package/src/injection/descriptor.ts +0 -218
  196. package/src/injection/resolve-options.ts +0 -144
  197. package/src/introspection/dependency-graph.ts +0 -282
  198. package/src/introspection/graph-adapters/cytoscape.ts +0 -78
  199. package/src/introspection/graph-adapters/dot.ts +0 -32
  200. package/src/introspection/graph-adapters/mermaid.ts +0 -61
  201. package/src/introspection/graph-adapters/reactflow.ts +0 -84
  202. package/src/introspection/inspector.ts +0 -134
  203. package/src/lifecycle/lifecycle-manager.ts +0 -272
  204. package/src/lifecycle/scope-manager.ts +0 -158
  205. package/src/metadata/metadata-keys.ts +0 -28
  206. package/src/metadata/metadata-reader-token.ts +0 -10
  207. package/src/metadata/metadata-types.ts +0 -57
  208. package/src/metadata/symbol-metadata-reader.ts +0 -126
  209. package/src/metadata/verifying-metadata-reader.ts +0 -41
  210. package/src/resolution/cache/activation-need.ts +0 -87
  211. package/src/resolution/cache/binding-lookup-cache.ts +0 -209
  212. package/src/resolution/cache/class-introspector.ts +0 -256
  213. package/src/resolution/context.ts +0 -331
  214. package/src/resolution/path/resolution-path.ts +0 -167
  215. package/src/resolution/plan/instantiation-plan.ts +0 -617
  216. package/src/resolution/resolver.ts +0 -1675
  217. package/src/resolution/select/binding-select.ts +0 -210
  218. package/src/resolution/select/constraints.ts +0 -146
@@ -34,5 +34,4 @@ export function postConstruct() {
34
34
  */
35
35
  export function preDestroy() {
36
36
  return recordLifecycleMethod("preDestroy");
37
- }
38
- //# sourceMappingURL=lifecycle-decorators.js.map
37
+ }
@@ -39,5 +39,4 @@ export interface ResolutionDiagnostics {
39
39
  */
40
40
  export interface DiagnosableContainer {
41
41
  [RESOLUTION_DIAGNOSTICS](): ResolutionDiagnostics;
42
- }
43
- //# sourceMappingURL=diagnostics.d.ts.map
42
+ }
@@ -14,5 +14,4 @@
14
14
  *
15
15
  * @since 0.5.0-canary.8
16
16
  */
17
- export const RESOLUTION_DIAGNOSTICS = Symbol("di:resolution-diagnostics");
18
- //# sourceMappingURL=diagnostics.js.map
17
+ export const RESOLUTION_DIAGNOSTICS = Symbol("di:resolution-diagnostics");
@@ -289,5 +289,4 @@ export declare class AsyncActivationError extends DiError {
289
289
  readonly hookKind: "postConstruct" | "onActivation";
290
290
  readonly methodName: string | undefined;
291
291
  constructor(tokenName: string, hookKind: "postConstruct" | "onActivation", methodName?: string);
292
- }
293
- //# sourceMappingURL=errors.d.ts.map
292
+ }
@@ -1,3 +1,4 @@
1
+ import { slotName } from "#/core/tag";
1
2
  /**
2
3
  * Base class for every error the library throws, each carrying a machine-readable `code`.
3
4
  *
@@ -34,11 +35,35 @@ export class TokenNotBoundError extends DiError {
34
35
  }
35
36
  }
36
37
  // Options carry caller values a tag may hold — a bigint or a circular object must not make the
37
- // diagnostic itself throw and mask the real error.
38
+ // diagnostic itself throw and mask the real error. The reserved criterion renders as `name`.
38
39
  function describeResolveOptions(options) {
39
40
  try {
40
- return (JSON.stringify(options, (_key, value) => (typeof value === "bigint" ? `${String(value)}n` : value)) ??
41
- "undefined");
41
+ let name = options.name;
42
+ const criteria = [];
43
+ const add = (criterion) => {
44
+ if (criterion.key === slotName) {
45
+ name ??= String(criterion.value);
46
+ }
47
+ else {
48
+ criteria.push(`${criterion.key.name}=${String(criterion.value)}`);
49
+ }
50
+ };
51
+ if (options.tag !== undefined) {
52
+ add(options.tag);
53
+ }
54
+ if (options.tags !== undefined) {
55
+ for (const criterion of options.tags) {
56
+ add(criterion);
57
+ }
58
+ }
59
+ const display = {};
60
+ if (name !== undefined) {
61
+ display.name = name;
62
+ }
63
+ if (criteria.length > 0) {
64
+ display.tags = criteria;
65
+ }
66
+ return JSON.stringify(display) ?? "undefined";
42
67
  }
43
68
  catch {
44
69
  return "[unserializable options]";
@@ -377,5 +402,4 @@ export class AsyncActivationError extends DiError {
377
402
  this.hookKind = hookKind;
378
403
  this.methodName = methodName;
379
404
  }
380
- }
381
- //# sourceMappingURL=errors.js.map
405
+ }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export type { ActivationHandler, BindingConstraint, BindingIdentifier, BindingKind, BindingScope, BindingTag, ConstraintContext, Constructor, DependencyKey, DeactivationHandler, ResolutionFrame, ResolveOptions, ResolutionContext, TokenValue, } from "#/core/types";
2
2
  export { token, tokenName } from "#/core/token";
3
3
  export type { Token } from "#/core/token";
4
- export { coversTagKeys, NO_TAG_KEYS, tag, tagKeyMaskOf } from "#/core/tag";
4
+ export { coversTagKeys, NO_TAG_KEYS, slotName, tag, tagKeyMaskOf } from "#/core/tag";
5
5
  export type { TagKey, TagKeyMask } from "#/core/tag";
6
6
  export type { AliasBindingBuilder, BindToBuilder, BindingBuilder, ConstantBindingBuilder, ScopedBindingBuilder, SingletonBindingBuilder, SingletonLifecycleBuilder, SlotConstrainedBuilder, TransientBindingBuilder, } from "#/core/binding";
7
7
  export { Container } from "#/container/container";
@@ -32,5 +32,4 @@ export { toCytoscapeGraph } from "#/introspection/graph-adapters/cytoscape";
32
32
  export type { CytoscapeEdge, CytoscapeElements, CytoscapeNode } from "#/introspection/graph-adapters/cytoscape";
33
33
  export { toReactFlowGraph } from "#/introspection/graph-adapters/reactflow";
34
34
  export type { ReactFlowEdge, ReactFlowGraph, ReactFlowNode } from "#/introspection/graph-adapters/reactflow";
35
- export { toMermaidGraph } from "#/introspection/graph-adapters/mermaid";
36
- //# sourceMappingURL=index.d.ts.map
35
+ export { toMermaidGraph } from "#/introspection/graph-adapters/mermaid";
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Token
2
2
  export { token, tokenName } from "#/core/token";
3
3
  // Tag — the interned slot criteria a `whenTagged` and a resolve both take
4
- export { coversTagKeys, NO_TAG_KEYS, tag, tagKeyMaskOf } from "#/core/tag";
4
+ export { coversTagKeys, NO_TAG_KEYS, slotName, tag, tagKeyMaskOf } from "#/core/tag";
5
5
  // Container
6
6
  export { Container } from "#/container/container";
7
7
  // Ambient container — the context an `@inject` accessor initializer resolves from. `resolution/context`
@@ -30,5 +30,4 @@ export { AmbiguousBindingError, AsyncActivationError, AsyncDeactivationError, As
30
30
  export { toDotGraph } from "#/introspection/graph-adapters/dot";
31
31
  export { toCytoscapeGraph } from "#/introspection/graph-adapters/cytoscape";
32
32
  export { toReactFlowGraph } from "#/introspection/graph-adapters/reactflow";
33
- export { toMermaidGraph } from "#/introspection/graph-adapters/mermaid";
34
- //# sourceMappingURL=index.js.map
33
+ export { toMermaidGraph } from "#/introspection/graph-adapters/mermaid";
@@ -87,5 +87,4 @@ export declare function optional<Value>(token: Token<Value> | Constructor<Value>
87
87
  * @since 0.3.16-canary.0
88
88
  */
89
89
  export declare function injectAll<Value>(token: Token<Value> | Constructor<Value>, options?: InjectOptions): InjectionDescriptor<Array<Value>>;
90
- export {};
91
- //# sourceMappingURL=descriptor.d.ts.map
90
+ export {};
@@ -122,5 +122,4 @@ export function injectAll(token, options) {
122
122
  optional: false,
123
123
  multi: true,
124
124
  }, options);
125
- }
126
- //# sourceMappingURL=descriptor.js.map
125
+ }
@@ -17,22 +17,15 @@ export interface DependencySlot {
17
17
  readonly tags?: ReadonlyArray<BindingTag> | undefined;
18
18
  }
19
19
  /**
20
- * A request whose only criterion is a name — the shape the registry has a direct index for.
20
+ * The lone criterion of a request that carries exactly one, whatever its spelling — the shape the
21
+ * registry has a direct index for.
21
22
  *
22
- * @since 0.5.0-canary.9
23
- */
24
- export declare function isNameOnlyOptions(options: ResolveOptions): options is ResolveOptions & {
25
- name: string;
26
- };
27
- /**
28
- * The lone tag of a request that asks for exactly one, written either way — the shape the registry
29
- * has a direct tag index for.
30
- *
31
- * @remarks Both spellings answer here, so the index is not something one of them silently misses.
23
+ * @remarks Every spelling answers here, so the index is not something one of them silently misses;
24
+ * a name folds to the reserved `slotName` criterion, making the name lane the tag lane.
32
25
  *
33
26
  * @since 0.5.0-canary.9
34
27
  */
35
- export declare function singleTagOnlyOf(options: ResolveOptions): BindingTag | undefined;
28
+ export declare function singleCriterionOnlyOf(options: ResolveOptions | undefined): BindingTag | undefined;
36
29
  /**
37
30
  * Builds a {@link ResolveOptions} safe for `exactOptionalPropertyTypes`:
38
31
  * omits keys instead of assigning `undefined`.
@@ -50,6 +43,18 @@ export declare function injectionSlotToResolveOptions(injectionSlot: Pick<Depend
50
43
  * @since 0.6.0
51
44
  */
52
45
  export declare function resolveOptionsForSlot(injectionSlot: DependencySlot): ResolveOptions | undefined;
46
+ /**
47
+ * The lone criterion a dependency's fixed criteria fold to, memoized on the slot like its options —
48
+ * `null` means the fold answered "none".
49
+ *
50
+ * @remarks A slot's criteria never change after declaration, so the fold happens once per slot
51
+ * rather than per hop — which is what keeps a named dependency's resolve off the intern map. A
52
+ * lone name whose criterion is not interned yet is left unmemoized: a later `whenNamed` binding
53
+ * mints it, and the next fold must see that.
54
+ *
55
+ * @since 0.8.0
56
+ */
57
+ export declare function singleCriterionForSlot(injectionSlot: DependencySlot): BindingTag | null;
53
58
  /**
54
59
  * Resolve options derived from a binding slot (tags may be empty; omits when nothing to match).
55
60
  *
@@ -62,5 +67,4 @@ export declare function resolveOptionsForSlot(injectionSlot: DependencySlot): Re
62
67
  export declare function bindingSlotToResolveOptions(bindingSlot: {
63
68
  readonly name?: string | undefined;
64
69
  readonly tags?: ReadonlyArray<BindingTag> | undefined;
65
- }): ResolveOptions | undefined;
66
- //# sourceMappingURL=resolve-options.d.ts.map
70
+ }): ResolveOptions | undefined;
@@ -1,31 +1,36 @@
1
+ import { slotName, slotNameCriterionOf } from "#/core/tag";
1
2
  /**
2
- * A request whose only criterion is a name — the shape the registry has a direct index for.
3
+ * The lone criterion of a request that carries exactly one, whatever its spelling — the shape the
4
+ * registry has a direct index for.
3
5
  *
4
- * @since 0.5.0-canary.9
5
- */
6
- export function isNameOnlyOptions(options) {
7
- return (options.name !== undefined && options.tag === undefined && (options.tags === undefined || options.tags.length === 0));
8
- }
9
- /**
10
- * The lone tag of a request that asks for exactly one, written either way — the shape the registry
11
- * has a direct tag index for.
12
- *
13
- * @remarks Both spellings answer here, so the index is not something one of them silently misses.
6
+ * @remarks Every spelling answers here, so the index is not something one of them silently misses;
7
+ * a name folds to the reserved `slotName` criterion, making the name lane the tag lane.
14
8
  *
15
9
  * @since 0.5.0-canary.9
16
10
  */
17
- export function singleTagOnlyOf(options) {
18
- if (options.name !== undefined) {
11
+ export function singleCriterionOnlyOf(options) {
12
+ if (options === undefined) {
19
13
  return undefined;
20
14
  }
15
+ if (options.name !== undefined) {
16
+ return loneNameCriterionOf(options);
17
+ }
21
18
  const listed = options.tags;
22
19
  const shorthand = options.tag;
23
20
  if (shorthand !== undefined) {
24
- // Both sources present means the request carries two tags, which no single-tag index can answer.
25
21
  return listed === undefined || listed.length === 0 ? shorthand : undefined;
26
22
  }
27
23
  return listed !== undefined && listed.length === 1 ? listed[0] : undefined;
28
24
  }
25
+ /** The name spelling's half of the fold, kept apart so the common body stays small enough to inline. */
26
+ function loneNameCriterionOf(options) {
27
+ // A name next to any tag means the request carries two criteria, which no single index answers.
28
+ if (options.tag !== undefined || (options.tags !== undefined && options.tags.length > 0)) {
29
+ return undefined;
30
+ }
31
+ // Read, not minted: a request must not retain a name no binding ever declared.
32
+ return slotNameCriterionOf(options.name);
33
+ }
29
34
  /** Shared core: build a ResolveOptions from already-normalised name + tags. */
30
35
  function buildOptions(name, tags) {
31
36
  if (name === undefined && tags === undefined) {
@@ -51,6 +56,8 @@ export function injectionSlotToResolveOptions(injectionSlot) {
51
56
  }
52
57
  /** Where a slot's derived options are memoized, so the same object is handed out every resolve. */
53
58
  const MEMOIZED_RESOLVE_OPTIONS = Symbol("di:resolve-options");
59
+ /** Where a slot's folded lone criterion is memoized — `null` records "computed: none". */
60
+ const MEMOIZED_SINGLE_CRITERION = Symbol("di:single-criterion");
54
61
  /**
55
62
  * The options a dependency resolves with — one object per slot, since a slot's criteria are fixed
56
63
  * when it is declared.
@@ -85,6 +92,41 @@ function memoizeResolveOptions(slot, name, tags) {
85
92
  }
86
93
  return built;
87
94
  }
95
+ /**
96
+ * The lone criterion a dependency's fixed criteria fold to, memoized on the slot like its options —
97
+ * `null` means the fold answered "none".
98
+ *
99
+ * @remarks A slot's criteria never change after declaration, so the fold happens once per slot
100
+ * rather than per hop — which is what keeps a named dependency's resolve off the intern map. A
101
+ * lone name whose criterion is not interned yet is left unmemoized: a later `whenNamed` binding
102
+ * mints it, and the next fold must see that.
103
+ *
104
+ * @since 0.8.0
105
+ */
106
+ export function singleCriterionForSlot(injectionSlot) {
107
+ const slot = injectionSlot;
108
+ const memoized = slot[MEMOIZED_SINGLE_CRITERION];
109
+ if (memoized !== undefined) {
110
+ return memoized;
111
+ }
112
+ const options = resolveOptionsForSlot(injectionSlot);
113
+ const criterion = singleCriterionOnlyOf(options);
114
+ const folded = criterion ?? null;
115
+ if (criterion !== undefined || !isLoneNameOptions(options)) {
116
+ try {
117
+ slot[MEMOIZED_SINGLE_CRITERION] = folded;
118
+ }
119
+ catch {
120
+ // A frozen slot re-folds on every hop rather than throwing.
121
+ }
122
+ }
123
+ return folded;
124
+ }
125
+ /** A slot request whose only criterion is a name — the one shape whose fold can change after a bind. */
126
+ function isLoneNameOptions(options) {
127
+ // Slot-derived options never carry the `tag` shorthand — `buildOptions` folds it into `tags`.
128
+ return (options !== undefined && options.name !== undefined && (options.tags === undefined || options.tags.length === 0));
129
+ }
88
130
  /**
89
131
  * Resolve options derived from a binding slot (tags may be empty; omits when nothing to match).
90
132
  *
@@ -96,6 +138,17 @@ function memoizeResolveOptions(slot, name, tags) {
96
138
  */
97
139
  export function bindingSlotToResolveOptions(bindingSlot) {
98
140
  const tags = bindingSlot.tags;
99
- return buildOptions(bindingSlot.name, tags !== undefined && tags.length > 0 ? tags : undefined);
100
- }
101
- //# sourceMappingURL=resolve-options.js.map
141
+ let name = bindingSlot.name;
142
+ let criteria = tags !== undefined && tags.length > 0 ? tags : undefined;
143
+ if (criteria !== undefined) {
144
+ // A reserved criterion folds into `name` — carried in `tags` it would be said twice or, on a
145
+ // descriptor that spells its name as a tag, not at all.
146
+ const reserved = criteria.find((criterion) => criterion.key === slotName);
147
+ if (reserved !== undefined) {
148
+ name ??= reserved.value;
149
+ const rest = criteria.filter((criterion) => criterion.key !== slotName);
150
+ criteria = rest.length > 0 ? rest : undefined;
151
+ }
152
+ }
153
+ return buildOptions(name, criteria);
154
+ }
@@ -53,5 +53,4 @@ export interface GraphOptions {
53
53
  *
54
54
  * @since 0.3.16-canary.0
55
55
  */
56
- export declare function buildDependencyGraph(registry: BindingRegistry, metadataReader: MetadataReader, options: GraphOptions | undefined, parentRegistry?: BindingRegistry): ContainerGraphJson;
57
- //# sourceMappingURL=dependency-graph.d.ts.map
56
+ export declare function buildDependencyGraph(registry: BindingRegistry, metadataReader: MetadataReader, options: GraphOptions | undefined, parentRegistry?: BindingRegistry): ContainerGraphJson;
@@ -1,4 +1,5 @@
1
1
  import { effectiveBindingScope } from "#/core/binding-scope";
2
+ import { slotName } from "#/core/tag";
2
3
  import { tokenName } from "#/core/token";
3
4
  import { bindingSlotToResolveOptions } from "#/injection/resolve-options";
4
5
  import { matchesSlot } from "#/resolution/select/binding-select";
@@ -26,11 +27,21 @@ function matchingTargets(candidates, ref) {
26
27
  }
27
28
  return candidates.filter((candidate) => matchesSlot(candidate.slot, criterion));
28
29
  }
30
+ /** The name a dependency asks for, whichever spelling carries it. */
31
+ function refSlotName(ref) {
32
+ if (ref.name !== undefined) {
33
+ return ref.name;
34
+ }
35
+ const reserved = ref.tags?.find((criterion) => criterion.key === slotName);
36
+ return reserved === undefined ? undefined : String(reserved.value);
37
+ }
29
38
  function edgeLabel(ref, index) {
30
- const criterion = ref.name !== undefined
31
- ? `name:${ref.name}`
32
- : ref.tags !== undefined && ref.tags.length > 0
33
- ? `tag:${ref.tags[0]?.key.name}=${String(ref.tags[0]?.value)}`
39
+ const name = refSlotName(ref);
40
+ const firstPlainTag = ref.tags?.find((criterion) => criterion.key !== slotName);
41
+ const criterion = name !== undefined
42
+ ? `name:${name}`
43
+ : firstPlainTag !== undefined
44
+ ? `tag:${firstPlainTag.key.name}=${String(firstPlainTag.value)}`
34
45
  : `[${index}]`;
35
46
  return ref.optional ? `${criterion} optional` : criterion;
36
47
  }
@@ -70,27 +81,29 @@ function addDependencyEdges(accumulator, from, ref, index, lookup) {
70
81
  if (!ref.optional) {
71
82
  return;
72
83
  }
84
+ const unboundSlotName = refSlotName(ref);
73
85
  accumulator.edges.push({
74
86
  from,
75
87
  to: unboundNodeIdFor(accumulator, ref.token),
76
88
  label,
77
89
  optional: true,
78
- ...(ref.name !== undefined ? { slotName: ref.name } : {}),
90
+ ...(unboundSlotName !== undefined ? { slotName: unboundSlotName } : {}),
79
91
  });
80
92
  return;
81
93
  }
94
+ const requestedName = refSlotName(ref);
82
95
  for (const target of targets) {
83
96
  // A multi dep with no criterion of its own fans out — each edge names the slot it hits.
84
- const slotName = target.slot.name ?? ref.name;
85
- const perTargetLabel = ref.multi && ref.name === undefined && slotName !== undefined
86
- ? edgeLabel({ ...ref, name: slotName }, index)
97
+ const edgeSlotName = target.slot.name ?? requestedName;
98
+ const perTargetLabel = ref.multi && requestedName === undefined && edgeSlotName !== undefined
99
+ ? edgeLabel({ ...ref, name: edgeSlotName }, index)
87
100
  : label;
88
101
  accumulator.edges.push({
89
102
  from,
90
103
  to: target.id,
91
104
  label: perTargetLabel,
92
105
  optional: ref.optional,
93
- ...(slotName !== undefined ? { slotName } : {}),
106
+ ...(edgeSlotName !== undefined ? { slotName: edgeSlotName } : {}),
94
107
  });
95
108
  }
96
109
  }
@@ -145,5 +158,4 @@ export function buildDependencyGraph(registry, metadataReader, options, parentRe
145
158
  addRegistryBindings(accumulator, parentRegistry, metadataReader, true);
146
159
  }
147
160
  return { nodes: accumulator.nodes, edges: accumulator.edges, includesParent };
148
- }
149
- //# sourceMappingURL=dependency-graph.js.map
161
+ }
@@ -40,5 +40,4 @@ export type CytoscapeElements = ReadonlyArray<CytoscapeNode | CytoscapeEdge>;
40
40
  *
41
41
  * @since 0.3.16-canary.0
42
42
  */
43
- export declare function toCytoscapeGraph(graph: ContainerGraphJson): CytoscapeElements;
44
- //# sourceMappingURL=cytoscape.d.ts.map
43
+ export declare function toCytoscapeGraph(graph: ContainerGraphJson): CytoscapeElements;
@@ -31,5 +31,4 @@ export function toCytoscapeGraph(graph) {
31
31
  });
32
32
  }
33
33
  return elements;
34
- }
35
- //# sourceMappingURL=cytoscape.js.map
34
+ }
@@ -4,5 +4,4 @@ import type { ContainerGraphJson } from "#/introspection/dependency-graph";
4
4
  *
5
5
  * @since 0.3.16-canary.0
6
6
  */
7
- export declare function toDotGraph(graph: ContainerGraphJson): string;
8
- //# sourceMappingURL=dot.d.ts.map
7
+ export declare function toDotGraph(graph: ContainerGraphJson): string;
@@ -23,5 +23,4 @@ export function toDotGraph(graph) {
23
23
  }
24
24
  lines.push("}");
25
25
  return lines.join("\n");
26
- }
27
- //# sourceMappingURL=dot.js.map
26
+ }
@@ -5,5 +5,4 @@ import type { ContainerGraphJson } from "#/introspection/dependency-graph";
5
5
  *
6
6
  * @since 0.6.0
7
7
  */
8
- export declare function toMermaidGraph(graph: ContainerGraphJson): string;
9
- //# sourceMappingURL=mermaid.d.ts.map
8
+ export declare function toMermaidGraph(graph: ContainerGraphJson): string;
@@ -43,5 +43,4 @@ export function toMermaidGraph(graph) {
43
43
  lines.push(` class ${unboundIds.join(",")} unbound;`);
44
44
  }
45
45
  return lines.join("\n");
46
- }
47
- //# sourceMappingURL=mermaid.js.map
46
+ }
@@ -45,5 +45,4 @@ export interface ReactFlowGraph {
45
45
  *
46
46
  * @since 0.5.0-canary.7
47
47
  */
48
- export declare function toReactFlowGraph(graph: ContainerGraphJson): ReactFlowGraph;
49
- //# sourceMappingURL=reactflow.d.ts.map
48
+ export declare function toReactFlowGraph(graph: ContainerGraphJson): ReactFlowGraph;
@@ -35,5 +35,4 @@ export function toReactFlowGraph(graph) {
35
35
  ...(edge.slotName !== undefined ? { slotName: edge.slotName } : {}),
36
36
  }));
37
37
  return { nodes, edges };
38
- }
39
- //# sourceMappingURL=reactflow.js.map
38
+ }
@@ -40,5 +40,4 @@ export declare class Inspector {
40
40
  lookupBindings<Value>(token: Token<Value> | Constructor<Value>): ReadonlyArray<BindingSnapshot>;
41
41
  has(token: Token<unknown> | Constructor, options?: ResolveOptions, parentHas?: () => boolean): boolean;
42
42
  hasOwn(token: Token<unknown> | Constructor, options?: ResolveOptions): boolean;
43
- }
44
- //# sourceMappingURL=inspector.d.ts.map
43
+ }
@@ -79,5 +79,4 @@ export class Inspector {
79
79
  id: binding.id,
80
80
  };
81
81
  }
82
- }
83
- //# sourceMappingURL=inspector.js.map
82
+ }
@@ -25,5 +25,4 @@ export declare class LifecycleManager {
25
25
  runDeactivationSync<Value>(binding: Binding<Value>, instance: Value, metadataReader: MetadataReader): void;
26
26
  /** Whether the deferred activation-hook table has had to be built. */
27
27
  get isActivationTableBuilt(): boolean;
28
- }
29
- //# sourceMappingURL=lifecycle-manager.d.ts.map
28
+ }
@@ -207,5 +207,4 @@ function callHook(instance, methodName) {
207
207
  throw new InvalidMetadataError(className, `lifecycle method '${methodName}' is not a method on the instance`);
208
208
  }
209
209
  return method.call(instance);
210
- }
211
- //# sourceMappingURL=lifecycle-manager.js.map
210
+ }
@@ -46,5 +46,4 @@ export declare class ScopeManager {
46
46
  *
47
47
  * @since 0.6.0
48
48
  */
49
- export declare const SCOPED_MISS: unique symbol;
50
- //# sourceMappingURL=scope-manager.d.ts.map
49
+ export declare const SCOPED_MISS: unique symbol;
@@ -133,5 +133,4 @@ const EMPTY_BINDINGS = [];
133
133
  *
134
134
  * @since 0.6.0
135
135
  */
136
- export const SCOPED_MISS = Symbol("di:scoped-miss");
137
- //# sourceMappingURL=scope-manager.js.map
136
+ export const SCOPED_MISS = Symbol("di:scoped-miss");
@@ -24,5 +24,4 @@ export declare const INJECT_ACCESSOR_KEY: unique symbol;
24
24
  *
25
25
  * @since 0.3.16-canary.0
26
26
  */
27
- export declare const METADATA_SYMBOL: symbol;
28
- //# sourceMappingURL=metadata-keys.d.ts.map
27
+ export declare const METADATA_SYMBOL: symbol;
@@ -24,5 +24,4 @@ export const INJECT_ACCESSOR_KEY = Symbol("di:inject-accessor");
24
24
  *
25
25
  * @since 0.3.16-canary.0
26
26
  */
27
- export const METADATA_SYMBOL = Symbol.metadata ?? Symbol.for("Symbol.metadata");
28
- //# sourceMappingURL=metadata-keys.js.map
27
+ export const METADATA_SYMBOL = Symbol.metadata ?? Symbol.for("Symbol.metadata");
@@ -5,5 +5,4 @@ import type { MetadataReader } from "#/metadata/metadata-types";
5
5
  *
6
6
  * @since 0.3.16-canary.0
7
7
  */
8
- export declare const MetadataReaderToken: Token<MetadataReader>;
9
- //# sourceMappingURL=metadata-reader-token.d.ts.map
8
+ export declare const MetadataReaderToken: Token<MetadataReader>;
@@ -4,5 +4,4 @@ import { token } from "#/core/token";
4
4
  *
5
5
  * @since 0.3.16-canary.0
6
6
  */
7
- export const MetadataReaderToken = token("MetadataReader");
8
- //# sourceMappingURL=metadata-reader-token.js.map
7
+ export const MetadataReaderToken = token("MetadataReader");
@@ -50,5 +50,4 @@ export interface MetadataReader {
50
50
  readonly key: string | symbol;
51
51
  readonly descriptor: InjectionDescriptor;
52
52
  }> | undefined;
53
- }
54
- //# sourceMappingURL=metadata-types.d.ts.map
53
+ }
@@ -1,2 +1 @@
1
- export {};
2
- //# sourceMappingURL=metadata-types.js.map
1
+ export {};
@@ -33,5 +33,4 @@ export declare class SymbolMetadataReader implements MetadataReader {
33
33
  * @since 0.3.16-canary.0
34
34
  */
35
35
  export declare const defaultMetadataReader: SymbolMetadataReader;
36
- export {};
37
- //# sourceMappingURL=symbol-metadata-reader.d.ts.map
36
+ export {};
@@ -114,5 +114,4 @@ function mergeUniqueNames(lists) {
114
114
  *
115
115
  * @since 0.3.16-canary.0
116
116
  */
117
- export const defaultMetadataReader = new SymbolMetadataReader();
118
- //# sourceMappingURL=symbol-metadata-reader.js.map
117
+ export const defaultMetadataReader = new SymbolMetadataReader();
@@ -12,5 +12,4 @@ import type { MetadataReader } from "#/metadata/metadata-types";
12
12
  *
13
13
  * @since 0.6.0
14
14
  */
15
- export declare function verifyingMetadataReader(reader: MetadataReader): MetadataReader;
16
- //# sourceMappingURL=verifying-metadata-reader.d.ts.map
15
+ export declare function verifyingMetadataReader(reader: MetadataReader): MetadataReader;
@@ -28,5 +28,4 @@ export function verifyingMetadataReader(reader) {
28
28
  };
29
29
  verifyingReaders.add(verifying);
30
30
  return verifying;
31
- }
32
- //# sourceMappingURL=verifying-metadata-reader.js.map
31
+ }
@@ -25,5 +25,4 @@ export declare class ActivationNeedCache {
25
25
  * conservative `true`.
26
26
  */
27
27
  refreshAfterFirstInstantiation<Value>(binding: Binding<Value>, needsActivation: boolean): boolean;
28
- }
29
- //# sourceMappingURL=activation-need.d.ts.map
28
+ }
@@ -66,5 +66,4 @@ export class ActivationNeedCache {
66
66
  #nonClassNeedsActivation(binding) {
67
67
  return this.#lifecycle.hasActivationHandlers(binding.token);
68
68
  }
69
- }
70
- //# sourceMappingURL=activation-need.js.map
69
+ }
@@ -28,7 +28,7 @@ export interface DefaultLookupEntry<Owner> {
28
28
  */
29
29
  export declare const ALIAS_HOP_LIMIT = 32;
30
30
  /**
31
- * A version-stamped cache of binding lookups by token, name, and tag across the container chain.
31
+ * A version-stamped cache of binding lookups by token and criterion across the container chain.
32
32
  *
33
33
  * @since 0.5.0-canary.9
34
34
  */
@@ -39,9 +39,6 @@ export declare class BindingLookupCache<Owner> {
39
39
  chainVersion(): number;
40
40
  /** `null` when the token's shape needs the full selection path. */
41
41
  defaultEntry(token: Token<unknown> | Constructor): DefaultLookupEntry<Owner> | null;
42
- /** `null` when the name's shape needs the full selection path. */
43
- namedEntry(token: Token<unknown> | Constructor, name: string): DefaultLookupEntry<Owner> | null;
44
42
  /** `null` when the tag's shape needs the full selection path. */
45
43
  taggedEntry(token: Token<unknown> | Constructor, tag: BindingTag): DefaultLookupEntry<Owner> | null;
46
- }
47
- //# sourceMappingURL=binding-lookup-cache.d.ts.map
44
+ }