@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
@@ -56,5 +56,4 @@ export declare class BindingChain<Value> implements AliasBindingBuilder, Binding
56
56
  onActivation(fn: ActivationHandler<Value>): this;
57
57
  onDeactivation(fn: DeactivationHandler<Value>): this;
58
58
  id(): BindingIdentifier;
59
- }
60
- //# sourceMappingURL=binding-builders.d.ts.map
59
+ }
@@ -1,6 +1,6 @@
1
- import { clearBindingFrame, createBinding, DEFAULT_BINDING_SLOT, refinableFields } from "#/core/binding";
1
+ import { clearBindingFrame, createBinding, createBindingSlot, DEFAULT_BINDING_SLOT, refinableFields, } from "#/core/binding";
2
2
  import { mergingConstraintRequirements } from "#/core/constraint-requirement";
3
- import { tagKeyMaskOf } from "#/core/tag";
3
+ import { slotName } from "#/core/tag";
4
4
  import { tokenName } from "#/core/token";
5
5
  import { ChainNotRegisteredError, SelfBindingRequiresClassError } from "#/errors/errors";
6
6
  import { normalizeToDescriptor } from "#/injection/descriptor";
@@ -14,8 +14,7 @@ function updateSlotTag(slot, criterion) {
14
14
  else {
15
15
  tags[existingIndex] = criterion;
16
16
  }
17
- // Frozen like DEFAULT_BINDING_SLOT's list: frames and snapshots alias a slot's tags.
18
- return { ...slot, tags: Object.freeze(tags), keyMask: tagKeyMaskOf(tags) };
17
+ return createBindingSlot(tags);
19
18
  }
20
19
  /** Record a module's binding id, dropping the id the chain re-slotted away from. */
21
20
  function trackBindingForModule(ids, id, previousId) {
@@ -140,7 +139,7 @@ export class BindingChain {
140
139
  return this.#reslot(binding.slot, composed);
141
140
  }
142
141
  whenNamed(name) {
143
- return this.#reslot({ ...this.#registered().slot, name }, this.#registered().predicate);
142
+ return this.whenTagged(slotName.of(name));
144
143
  }
145
144
  whenTagged(criterion) {
146
145
  const binding = this.#registered();
@@ -226,5 +225,4 @@ export class BindingChain {
226
225
  }
227
226
  }
228
227
  }
229
- }
230
- //# sourceMappingURL=binding-builders.js.map
228
+ }
@@ -74,5 +74,4 @@ export interface ContainerStatic {
74
74
  *
75
75
  * @since 0.3.16-canary.0
76
76
  */
77
- export declare const Container: ContainerStatic;
78
- //# sourceMappingURL=container.d.ts.map
77
+ export declare const Container: ContainerStatic;
@@ -67,9 +67,6 @@ class DefaultContainer {
67
67
  if (this.#moduleRefs !== undefined || this.#moduleBindingIds !== undefined) {
68
68
  builtSubsystems.push("container.moduleTables");
69
69
  }
70
- if (this.#registry.isNamedIndexBuilt) {
71
- builtSubsystems.push("registry.namedIndex");
72
- }
73
70
  if (this.#registry.isTaggedIndexBuilt) {
74
71
  builtSubsystems.push("registry.taggedIndex");
75
72
  }
@@ -516,8 +513,10 @@ class DefaultContainer {
516
513
  !this.#lifecycle.hasActivationHandlers(binding.token)) {
517
514
  continue;
518
515
  }
516
+ // Warm the binding itself — re-selecting by its own criteria could pick a different
517
+ // candidate whose criteria are a subset of them.
519
518
  const slotOptions = bindingSlotToResolveOptions(binding.slot);
520
- await this.resolveAsync(binding.token, slotOptions);
519
+ await this.#resolver.warmBindingAsync(binding, slotOptions);
521
520
  }
522
521
  }
523
522
  }
@@ -744,5 +743,4 @@ export const Container = {
744
743
  await container.loadAsync(...modules);
745
744
  return container;
746
745
  },
747
- };
748
- //# sourceMappingURL=container.js.map
746
+ };
@@ -9,5 +9,4 @@ import type { BindingScope } from "#/core/types";
9
9
  *
10
10
  * @since 0.3.16-canary.0
11
11
  */
12
- export declare function effectiveBindingScope(binding: Binding): BindingScope;
13
- //# sourceMappingURL=binding-scope.d.ts.map
12
+ export declare function effectiveBindingScope(binding: Binding): BindingScope;
@@ -9,5 +9,4 @@
9
9
  */
10
10
  export function effectiveBindingScope(binding) {
11
11
  return binding.scope;
12
- }
13
- //# sourceMappingURL=binding-scope.js.map
12
+ }
@@ -3,18 +3,31 @@ import type { Token } from "#/core/token";
3
3
  import type { ActivationHandler, BindingIdentifier, BindingScope, Constructor, DeactivationHandler, ResolutionContext, ResolutionFrame, BindingConstraint } from "#/core/types";
4
4
  import type { InjectableDependency, InjectionDescriptor, ResolvedDependencyValue } from "#/injection/descriptor";
5
5
  /**
6
- * The name-plus-tags coordinate a binding registers under and a request matches against.
6
+ * The criterion set a binding registers under and a request matches against.
7
7
  *
8
8
  * @since 0.3.16-canary.0
9
9
  */
10
10
  export interface BindingSlot {
11
+ /** Derived view of the reserved `slotName` criterion — `undefined` when the slot carries none. */
11
12
  readonly name: string | undefined;
13
+ /** The whole criterion set, the reserved name criterion included. */
12
14
  readonly tags: ReadonlyArray<BindingTag>;
13
15
  /** OR of this slot's tag keys, so the subset test is one word compare. */
14
16
  readonly keyMask: TagKeyMask;
15
17
  }
16
18
  /**
17
- * Returns whether two slots carry the same name and tag set, in any tag order.
19
+ * Builds a slot from its criterion set, deriving the name view and key mask.
20
+ *
21
+ * @remarks The one place the derived `name` is computed — a slot assembled any other way can carry
22
+ * a name criterion the readers of the view never see.
23
+ *
24
+ * @since 0.8.0
25
+ */
26
+ export declare function createBindingSlot(tags: ReadonlyArray<BindingTag>): BindingSlot;
27
+ /**
28
+ * Returns whether two slots carry the same criterion set, in any order.
29
+ *
30
+ * @remarks The derived `name` is not compared — the criterion set alone is the identity.
18
31
  *
19
32
  * @since 0.3.16-canary.0
20
33
  */
@@ -323,5 +336,4 @@ export interface SingletonLifecycleBuilder<Value> {
323
336
  onDeactivation(fn: DeactivationHandler<Value>): this;
324
337
  id(): BindingIdentifier;
325
338
  }
326
- export {};
327
- //# sourceMappingURL=binding.d.ts.map
339
+ export {};
@@ -1,11 +1,32 @@
1
- import { NO_TAG_KEYS } from "#/core/tag";
1
+ import { NO_TAG_KEYS, slotName, tagKeyMaskOf } from "#/core/tag";
2
2
  /**
3
- * Returns whether two slots carry the same name and tag set, in any tag order.
3
+ * Builds a slot from its criterion set, deriving the name view and key mask.
4
+ *
5
+ * @remarks The one place the derived `name` is computed — a slot assembled any other way can carry
6
+ * a name criterion the readers of the view never see.
7
+ *
8
+ * @since 0.8.0
9
+ */
10
+ export function createBindingSlot(tags) {
11
+ let name;
12
+ for (const criterion of tags) {
13
+ if (criterion.key === slotName) {
14
+ name = criterion.value;
15
+ break;
16
+ }
17
+ }
18
+ // Frozen like DEFAULT_BINDING_SLOT's list: frames and snapshots alias a slot's tags.
19
+ return { name, tags: Object.freeze([...tags]), keyMask: tagKeyMaskOf(tags) };
20
+ }
21
+ /**
22
+ * Returns whether two slots carry the same criterion set, in any order.
23
+ *
24
+ * @remarks The derived `name` is not compared — the criterion set alone is the identity.
4
25
  *
5
26
  * @since 0.3.16-canary.0
6
27
  */
7
28
  export function bindingSlotEquals(left, right) {
8
- if (left.name !== right.name || left.keyMask !== right.keyMask || left.tags.length !== right.tags.length) {
29
+ if (left.keyMask !== right.keyMask || left.tags.length !== right.tags.length) {
9
30
  return false;
10
31
  }
11
32
  for (const criterion of left.tags) {
@@ -37,7 +58,7 @@ export const DEFAULT_BINDING_SLOT = { name: undefined, tags: Object.freeze([]),
37
58
  * @since 0.3.16-canary.0
38
59
  */
39
60
  export function bindingSlotToString(slot) {
40
- if (slot.name === undefined && slot.tags.length === 0) {
61
+ if (slot.tags.length === 0) {
41
62
  return "default";
42
63
  }
43
64
  const parts = [];
@@ -45,6 +66,10 @@ export function bindingSlotToString(slot) {
45
66
  parts.push(`name:${slot.name}`);
46
67
  }
47
68
  for (const criterion of slot.tags) {
69
+ // The reserved criterion already printed as the `name:` part.
70
+ if (criterion.key === slotName) {
71
+ continue;
72
+ }
48
73
  parts.push(`tag:${criterion.key.name}=${String(criterion.value)}`);
49
74
  }
50
75
  return parts.join(",");
@@ -112,5 +137,4 @@ export function refinableFields(binding) {
112
137
  */
113
138
  export function clearBindingFrame(binding) {
114
139
  binding.frame = undefined;
115
- }
116
- //# sourceMappingURL=binding.js.map
140
+ }
@@ -49,5 +49,4 @@ export declare function constraintRequirementsOf(predicate: BindingConstraint):
49
49
  *
50
50
  * @since 0.6.1
51
51
  */
52
- export declare function mergingConstraintRequirements(composite: BindingConstraint, left: BindingConstraint, right: BindingConstraint): BindingConstraint;
53
- //# sourceMappingURL=constraint-requirement.d.ts.map
52
+ export declare function mergingConstraintRequirements(composite: BindingConstraint, left: BindingConstraint, right: BindingConstraint): BindingConstraint;
@@ -58,5 +58,4 @@ export function mergingConstraintRequirements(composite, left, right) {
58
58
  enumerable: false,
59
59
  });
60
60
  return composite;
61
- }
62
- //# sourceMappingURL=constraint-requirement.js.map
61
+ }
@@ -14,5 +14,4 @@ export type Constructor<out Value = unknown> = new (...args: Array<never>) => Va
14
14
  *
15
15
  * @since 0.3.16-canary.0
16
16
  */
17
- export type ConstructorInvocation = new (...args: Array<unknown>) => unknown;
18
- //# sourceMappingURL=constructor-type.d.ts.map
17
+ export type ConstructorInvocation = new (...args: Array<unknown>) => unknown;
@@ -1,2 +1 @@
1
- export {};
2
- //# sourceMappingURL=constructor-type.js.map
1
+ export {};
@@ -25,5 +25,4 @@ export declare function getOrInsert<Key, Value extends {} | null>(map: Map<Key,
25
25
  *
26
26
  * @since 0.7.0
27
27
  */
28
- export declare function getOrInsertComputed<Key, Value extends {} | null>(map: Map<Key, Value>, key: NoInfer<Key>, create: (key: NoInfer<Key>) => NoInfer<Value>): Value;
29
- //# sourceMappingURL=map-upsert.d.ts.map
28
+ export declare function getOrInsertComputed<Key, Value extends {} | null>(map: Map<Key, Value>, key: NoInfer<Key>, create: (key: NoInfer<Key>) => NoInfer<Value>): Value;
@@ -40,5 +40,4 @@ export function getOrInsertComputed(map, key, create) {
40
40
  const created = create(key);
41
41
  map.set(key, created);
42
42
  return created;
43
- }
44
- //# sourceMappingURL=map-upsert.js.map
43
+ }
@@ -79,5 +79,4 @@ export declare const Module: {
79
79
  * @since 0.3.16-canary.0
80
80
  */
81
81
  export declare function isSyncModule(module: SyncModule | AsyncModule): module is SyncModule;
82
- export {};
83
- //# sourceMappingURL=module.d.ts.map
82
+ export {};
@@ -58,5 +58,4 @@ export const Module = {
58
58
  */
59
59
  export function isSyncModule(module) {
60
60
  return module[SYNC_MODULE_BRAND] === true;
61
- }
62
- //# sourceMappingURL=module.js.map
61
+ }
@@ -41,7 +41,6 @@ export declare class BindingRegistry {
41
41
  clear(): ReadonlyArray<Binding>;
42
42
  /** Whether a slot-based binding currently occupies `binding`'s slot, so adding it would displace. */
43
43
  hasSlotOccupant(binding: Binding): boolean;
44
- getSimpleNamed(token: Token<unknown> | Constructor, name: string): Binding | undefined;
45
44
  /**
46
45
  * The binding indexed under one criterion.
47
46
  *
@@ -59,9 +58,6 @@ export declare class BindingRegistry {
59
58
  getFastDefault(token: Token<unknown> | Constructor): Binding | undefined;
60
59
  /** Summarize available slot strings for a token (for error messages). */
61
60
  availableSlotStrings(token: Token<unknown> | Constructor): Array<string>;
62
- /** Whether the deferred named-slot index has had to be built. */
63
- get isNamedIndexBuilt(): boolean;
64
61
  /** Whether the deferred tagged-slot index has had to be built. */
65
62
  get isTaggedIndexBuilt(): boolean;
66
- }
67
- //# sourceMappingURL=registry.d.ts.map
63
+ }
@@ -12,15 +12,13 @@ export class BindingRegistry {
12
12
  #bindings = new Map();
13
13
  // Fast lookup by binding ID
14
14
  #byId = new Map();
15
- // Fast lookup for slot { name, tags: [] } — unallocated until a named binding is registered.
16
- #simpleNamed;
17
15
  // Fast path for one default slot binding with no predicate
18
16
  #fastDefault = new Map();
19
- // Fast lookup for a slot carrying exactly one tag — keyed by the interned criterion itself, so
20
- // the (key, value) pair is one hash rather than two. Unallocated until a tagged binding lands.
17
+ // Fast lookup for a slot carrying exactly one criterion (a lone name folds here too) — keyed by
18
+ // the interned criterion itself, so the pair is one hash. Unallocated until such a slot lands.
21
19
  #simpleTagged;
22
- // Name-less slots with two or more tags, bucketed by their FIRST criterion. A matching slot's
23
- // every tag is in the request, so walking the request's buckets finds each candidate exactly once.
20
+ // Slots with two or more criteria, bucketed by their FIRST criterion. A matching slot's every
21
+ // criterion is in the request, so walking the request's buckets finds each candidate exactly once.
24
22
  #multiTagged;
25
23
  // Set on the first constant registered and never cleared. Teardown only needs the negative answer
26
24
  // to be exact, and that is what lets a container holding no constant skip its sweep entirely.
@@ -67,7 +65,6 @@ export class BindingRegistry {
67
65
  if (existingIndex !== -1) {
68
66
  displacedBinding = bindingsForToken[existingIndex];
69
67
  this.#byId.delete(displacedBinding.id);
70
- this.#deindexSimpleNamedBinding(key, displacedBinding);
71
68
  this.#deindexSimpleTaggedBinding(key, displacedBinding);
72
69
  this.#deindexMultiTaggedBinding(key, displacedBinding);
73
70
  }
@@ -79,7 +76,6 @@ export class BindingRegistry {
79
76
  }
80
77
  this.#bindings.set(key, nextBindings);
81
78
  this.#byId.set(binding.id, binding);
82
- this.#indexSimpleNamedBinding(key, binding);
83
79
  this.#indexSimpleTaggedBinding(key, binding);
84
80
  this.#indexMultiTaggedBinding(key, binding);
85
81
  this.#refreshFastDefaultForToken(key);
@@ -91,7 +87,6 @@ export class BindingRegistry {
91
87
  const key = token;
92
88
  const bindingsForToken = this.#bindings.get(key) ?? [];
93
89
  this.#bindings.delete(key);
94
- this.#simpleNamed?.delete(key);
95
90
  this.#simpleTagged?.delete(key);
96
91
  this.#multiTagged?.delete(key);
97
92
  this.#fastDefault.delete(key);
@@ -114,12 +109,10 @@ export class BindingRegistry {
114
109
  const bindingIndex = bindingsForToken.findIndex((candidate) => candidate.id === id);
115
110
  // Copy-on-write, like `add`: a walk holding the current array must not lose its place.
116
111
  const remaining = bindingIndex === -1 ? bindingsForToken : bindingsForToken.toSpliced(bindingIndex, 1);
117
- this.#deindexSimpleNamedBinding(key, binding);
118
112
  this.#deindexSimpleTaggedBinding(key, binding);
119
113
  this.#deindexMultiTaggedBinding(key, binding);
120
114
  if (remaining.length === 0) {
121
115
  this.#bindings.delete(key);
122
- this.#simpleNamed?.delete(key);
123
116
  this.#simpleTagged?.delete(key);
124
117
  this.#multiTagged?.delete(key);
125
118
  this.#fastDefault.delete(key);
@@ -159,7 +152,6 @@ export class BindingRegistry {
159
152
  const all = this.allBindings();
160
153
  this.#bindings.clear();
161
154
  this.#byId.clear();
162
- this.#simpleNamed?.clear();
163
155
  this.#simpleTagged?.clear();
164
156
  this.#multiTagged?.clear();
165
157
  this.#fastDefault.clear();
@@ -176,9 +168,6 @@ export class BindingRegistry {
176
168
  }
177
169
  return candidates.some((candidate) => !isPurePredicateBinding(candidate) && bindingSlotEquals(candidate.slot, binding.slot));
178
170
  }
179
- getSimpleNamed(token, name) {
180
- return this.#simpleNamed?.get(token)?.get(name);
181
- }
182
171
  /**
183
172
  * The binding indexed under one criterion.
184
173
  *
@@ -255,31 +244,6 @@ export class BindingRegistry {
255
244
  bucket.splice(bindingIndex, 1);
256
245
  }
257
246
  }
258
- #indexSimpleNamedBinding(tokenKey, binding) {
259
- const name = simpleNameOf(binding);
260
- if (name === undefined) {
261
- return;
262
- }
263
- this.#simpleNamed ??= new Map();
264
- const bindingsByName = getOrInsert(this.#simpleNamed, tokenKey, new Map());
265
- bindingsByName.set(name, binding);
266
- }
267
- #deindexSimpleNamedBinding(tokenKey, binding) {
268
- const name = simpleNameOf(binding);
269
- if (name === undefined) {
270
- return;
271
- }
272
- const bindingsByName = this.#simpleNamed?.get(tokenKey);
273
- if (bindingsByName === undefined) {
274
- return;
275
- }
276
- if (bindingsByName.get(name)?.id === binding.id) {
277
- bindingsByName.delete(name);
278
- if (bindingsByName.size === 0) {
279
- this.#simpleNamed.delete(tokenKey);
280
- }
281
- }
282
- }
283
247
  #refreshFastDefaultForToken(tokenKey) {
284
248
  const bindingsForToken = this.#bindings.get(tokenKey);
285
249
  const onlyBinding = bindingsForToken?.length === 1 ? bindingsForToken[0] : undefined;
@@ -289,43 +253,31 @@ export class BindingRegistry {
289
253
  }
290
254
  this.#fastDefault.delete(tokenKey);
291
255
  }
292
- /** Whether the deferred named-slot index has had to be built. */
293
- get isNamedIndexBuilt() {
294
- return this.#simpleNamed !== undefined;
295
- }
296
256
  /** Whether the deferred tagged-slot index has had to be built. */
297
257
  get isTaggedIndexBuilt() {
298
258
  return this.#simpleTagged !== undefined;
299
259
  }
300
260
  }
301
- /** The name a binding is indexed under, or `undefined` when its slot is more than a plain name. */
302
- function simpleNameOf(binding) {
303
- const { name, tags } = binding.slot;
304
- return name !== undefined && tags.length === 0 ? name : undefined;
305
- }
306
261
  /**
307
- * The tag a binding is indexed under, or `undefined` when its slot is more than one plain tag.
262
+ * The criterion a binding is indexed under, or `undefined` when its slot carries more than one.
308
263
  *
309
- * @remarks Carries predicate-bearing bindings too, exactly as the name index does: every lane that
310
- * reads this index already re-checks what it finds, so an indexed hit was never unconditional.
264
+ * @remarks Carries predicate-bearing bindings too: every lane that reads this index already
265
+ * re-checks what it finds, so an indexed hit was never unconditional.
311
266
  */
312
267
  function simpleTagOf(binding) {
313
- const { name, tags } = binding.slot;
314
- return name === undefined && tags.length === 1 ? tags[0] : undefined;
268
+ const { tags } = binding.slot;
269
+ return tags.length === 1 ? tags[0] : undefined;
315
270
  }
316
- /** The first criterion a multi-tag slot is bucketed under, or `undefined` for any other shape. */
271
+ /** The first criterion a multi-criterion slot is bucketed under, or `undefined` for any other shape. */
317
272
  function multiTagFirstOf(binding) {
318
- const { name, tags } = binding.slot;
319
- return name === undefined && tags.length >= 2 ? tags[0] : undefined;
273
+ const { tags } = binding.slot;
274
+ return tags.length >= 2 ? tags[0] : undefined;
320
275
  }
321
276
  /** A binding nothing has to be matched against: the default slot, no predicate. */
322
277
  function isDefaultSlotBinding(binding) {
323
- const { name, tags } = binding.slot;
324
- return name === undefined && tags.length === 0 && binding.predicate === undefined;
278
+ return binding.slot.tags.length === 0 && binding.predicate === undefined;
325
279
  }
326
280
  /** A predicate with no slot constraint: last-wins does not apply to it. */
327
281
  function isPurePredicateBinding(binding) {
328
- const { name, tags } = binding.slot;
329
- return binding.predicate !== undefined && name === undefined && tags.length === 0;
330
- }
331
- //# sourceMappingURL=registry.js.map
282
+ return binding.predicate !== undefined && binding.slot.tags.length === 0;
283
+ }
@@ -47,6 +47,14 @@ export interface TagKey<Value = unknown> {
47
47
  readonly mask: TagKeyMask;
48
48
  /** The criterion for one value, interned: the same value always yields the same object. */
49
49
  of(value: Value): BindingTag<Value>;
50
+ /**
51
+ * The interned criterion for a value, or `undefined` when none was ever minted.
52
+ *
53
+ * @remarks Reading without minting is what keeps a request-side value from being retained for
54
+ * the process lifetime: a value no binding ever declared has no criterion, so a lookup can
55
+ * answer "no match" without inserting one.
56
+ */
57
+ peek(value: Value): BindingTag<Value> | undefined;
50
58
  }
51
59
  /**
52
60
  * Declares a tag key, whose `of()` builds the criteria a `whenTagged` and a resolve both take.
@@ -64,6 +72,24 @@ export interface TagKey<Value = unknown> {
64
72
  * @since 0.6.0
65
73
  */
66
74
  export declare function tag<Value = unknown>(name: string): TagKey<Value>;
75
+ /**
76
+ * The reserved key a slot's name is a criterion of.
77
+ *
78
+ * @remarks `whenNamed(n)` and a request's `name` are sugar for `slotName.of(n)`, so one selection
79
+ * model serves both spellings — a name takes part in key masks, indexes and specificity like any
80
+ * criterion. What reserves the key is its identity; diagnostics render its criteria as `name:<value>`.
81
+ *
82
+ * @since 0.8.0
83
+ */
84
+ export declare const slotName: TagKey<string>;
85
+ /**
86
+ * The reserved criterion for a name, or `undefined` while no binding has declared it.
87
+ *
88
+ * @remarks Reads without minting, so a request-side name no binding declared is never retained.
89
+ *
90
+ * @since 0.8.0
91
+ */
92
+ export declare function slotNameCriterionOf(name: string): BindingTag<string> | undefined;
67
93
  /**
68
94
  * The key set a list of criteria covers.
69
95
  *
@@ -76,5 +102,4 @@ export declare function tagKeyMaskOf(tags: ReadonlyArray<BindingTag>): TagKeyMas
76
102
  * @since 0.6.0
77
103
  */
78
104
  export declare function coversTagKeys(requestMask: TagKeyMask, slotMask: TagKeyMask): boolean;
79
- export {};
80
- //# sourceMappingURL=tag.d.ts.map
105
+ export {};
package/dist/core/tag.js CHANGED
@@ -49,6 +49,22 @@ export function tag(name) {
49
49
  // split and `NaN` hits itself, with no `internKeyFor` detour.
50
50
  let lastValue;
51
51
  let lastPair;
52
+ // The miss paths live outside `of()`/`peek()` so the hot wrappers stay small enough to inline.
53
+ const internPair = (value) => {
54
+ const cacheKey = internKeyFor(value);
55
+ const existing = interned.get(cacheKey);
56
+ if (existing !== undefined) {
57
+ lastValue = value;
58
+ lastPair = existing;
59
+ return existing;
60
+ }
61
+ const pair = { key, value, mask };
62
+ interned.set(cacheKey, pair);
63
+ lastValue = value;
64
+ lastPair = pair;
65
+ return pair;
66
+ };
67
+ const peekInterned = (value) => interned.get(internKeyFor(value));
52
68
  const key = {
53
69
  name,
54
70
  id,
@@ -57,22 +73,49 @@ export function tag(name) {
57
73
  if (lastPair !== undefined && Object.is(value, lastValue)) {
58
74
  return lastPair;
59
75
  }
60
- const cacheKey = internKeyFor(value);
61
- const existing = interned.get(cacheKey);
62
- if (existing !== undefined) {
63
- lastValue = value;
64
- lastPair = existing;
65
- return existing;
76
+ return internPair(value);
77
+ },
78
+ peek(value) {
79
+ if (lastPair !== undefined && Object.is(value, lastValue)) {
80
+ return lastPair;
66
81
  }
67
- const pair = { key, value, mask };
68
- interned.set(cacheKey, pair);
69
- lastValue = value;
70
- lastPair = pair;
71
- return pair;
82
+ return peekInterned(value);
72
83
  },
73
84
  };
74
85
  return key;
75
86
  }
87
+ /**
88
+ * The reserved key a slot's name is a criterion of.
89
+ *
90
+ * @remarks `whenNamed(n)` and a request's `name` are sugar for `slotName.of(n)`, so one selection
91
+ * model serves both spellings — a name takes part in key masks, indexes and specificity like any
92
+ * criterion. What reserves the key is its identity; diagnostics render its criteria as `name:<value>`.
93
+ *
94
+ * @since 0.8.0
95
+ */
96
+ export const slotName = tag("di:name");
97
+ // One-entry front for the reserved key's read: a name's criterion never changes once minted, so a
98
+ // hit is sound forever, and a miss is never cached so a later `whenNamed` bind is still seen.
99
+ let lastPeekedName;
100
+ let lastPeekedCriterion;
101
+ /**
102
+ * The reserved criterion for a name, or `undefined` while no binding has declared it.
103
+ *
104
+ * @remarks Reads without minting, so a request-side name no binding declared is never retained.
105
+ *
106
+ * @since 0.8.0
107
+ */
108
+ export function slotNameCriterionOf(name) {
109
+ if (name === lastPeekedName) {
110
+ return lastPeekedCriterion;
111
+ }
112
+ const criterion = slotName.peek(name);
113
+ if (criterion !== undefined) {
114
+ lastPeekedName = name;
115
+ lastPeekedCriterion = criterion;
116
+ }
117
+ return criterion;
118
+ }
76
119
  /**
77
120
  * The key set a list of criteria covers.
78
121
  *
@@ -92,5 +135,4 @@ export function tagKeyMaskOf(tags) {
92
135
  */
93
136
  export function coversTagKeys(requestMask, slotMask) {
94
137
  return (requestMask & slotMask) === slotMask;
95
- }
96
- //# sourceMappingURL=tag.js.map
138
+ }
@@ -21,5 +21,4 @@ export declare function token<Value>(name: string): Token<Value>;
21
21
  * @since 0.3.16-canary.0
22
22
  */
23
23
  export declare function tokenName(dependency: Token<unknown> | Constructor): string;
24
- export {};
25
- //# sourceMappingURL=token.d.ts.map
24
+ export {};
@@ -13,5 +13,4 @@ export function token(name) {
13
13
  */
14
14
  export function tokenName(dependency) {
15
15
  return dependency.name;
16
- }
17
- //# sourceMappingURL=token.js.map
16
+ }
@@ -112,5 +112,4 @@ export interface ResolutionContext {
112
112
  *
113
113
  * @since 0.3.16-canary.0
114
114
  */
115
- export type TokenValue<Type> = Type extends Token<infer Value> ? Value : Type extends Constructor<infer Value> ? Value : never;
116
- //# sourceMappingURL=types.d.ts.map
115
+ export type TokenValue<Type> = Type extends Token<infer Value> ? Value : Type extends Constructor<infer Value> ? Value : never;
@@ -1,2 +1 @@
1
- export {};
2
- //# sourceMappingURL=types.js.map
1
+ export {};
@@ -9,5 +9,4 @@ type ClassAccessorDecorator<This, Value> = (target: ClassAccessorDecoratorTarget
9
9
  * @since 0.3.16-canary.0
10
10
  */
11
11
  export declare function inject<Value>(token: Token<Value> | Constructor<Value>, options?: InjectOptions): InjectionDescriptor<Value> & ClassAccessorDecorator<unknown, Value>;
12
- export {};
13
- //# sourceMappingURL=inject.d.ts.map
12
+ export {};
@@ -73,5 +73,4 @@ export function inject(token, options) {
73
73
  }
74
74
  Object.defineProperties(decoratorFn, props);
75
75
  return decoratorFn;
76
- }
77
- //# sourceMappingURL=inject.js.map
76
+ }
@@ -54,5 +54,4 @@ export declare function injectable(): (target: unknown, context: ClassDecoratorC
54
54
  * @since 0.3.16-canary.0
55
55
  */
56
56
  export declare function injectable<const Deps extends ReadonlyArray<InjectableDependency>>(deps: Deps, options?: InjectableOptions): <Target extends abstract new (...args: InjectedParameters<Deps>) => unknown>(target: Target & (number extends Deps["length"] ? unknown : Deps["length"] extends ConstructorParameters<Target>["length"] ? unknown : never), context: ClassDecoratorContext) => void;
57
- export type { InjectableDependency };
58
- //# sourceMappingURL=injectable.d.ts.map
57
+ export type { InjectableDependency };
@@ -52,5 +52,4 @@ export function injectable(deps, options) {
52
52
  options.autoRegister.register(target, scope);
53
53
  }
54
54
  };
55
- }
56
- //# sourceMappingURL=injectable.js.map
55
+ }
@@ -11,5 +11,4 @@ export declare function postConstruct(): MethodDecorator;
11
11
  * @since 0.3.16-canary.0
12
12
  */
13
13
  export declare function preDestroy(): MethodDecorator;
14
- export {};
15
- //# sourceMappingURL=lifecycle-decorators.d.ts.map
14
+ export {};