@codefast/di 0.6.2 → 0.7.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 (149) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +3 -4
  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/container.d.ts +6 -0
  8. package/dist/container/container.d.ts.map +1 -1
  9. package/dist/container/container.js +5 -1
  10. package/dist/container/container.js.map +1 -1
  11. package/dist/core/map-upsert.d.ts +29 -0
  12. package/dist/core/map-upsert.d.ts.map +1 -0
  13. package/dist/core/map-upsert.js +44 -0
  14. package/dist/core/map-upsert.js.map +1 -0
  15. package/dist/core/module.d.ts +16 -0
  16. package/dist/core/module.d.ts.map +1 -1
  17. package/dist/core/module.js +8 -0
  18. package/dist/core/module.js.map +1 -1
  19. package/dist/core/registry.d.ts +2 -0
  20. package/dist/core/registry.d.ts.map +1 -1
  21. package/dist/core/registry.js +10 -4
  22. package/dist/core/registry.js.map +1 -1
  23. package/dist/core/token.d.ts +6 -0
  24. package/dist/core/token.d.ts.map +1 -1
  25. package/dist/core/token.js +4 -0
  26. package/dist/core/token.js.map +1 -1
  27. package/dist/core/types.d.ts +20 -0
  28. package/dist/core/types.d.ts.map +1 -1
  29. package/dist/decorators/inject.d.ts +2 -0
  30. package/dist/decorators/inject.d.ts.map +1 -1
  31. package/dist/decorators/inject.js +2 -0
  32. package/dist/decorators/inject.js.map +1 -1
  33. package/dist/decorators/injectable.d.ts +6 -0
  34. package/dist/decorators/injectable.d.ts.map +1 -1
  35. package/dist/decorators/injectable.js +4 -0
  36. package/dist/decorators/injectable.js.map +1 -1
  37. package/dist/decorators/lifecycle-decorators.d.ts +4 -0
  38. package/dist/decorators/lifecycle-decorators.d.ts.map +1 -1
  39. package/dist/decorators/lifecycle-decorators.js +4 -0
  40. package/dist/decorators/lifecycle-decorators.js.map +1 -1
  41. package/dist/errors/errors.d.ts +34 -0
  42. package/dist/errors/errors.d.ts.map +1 -1
  43. package/dist/errors/errors.js +32 -0
  44. package/dist/errors/errors.js.map +1 -1
  45. package/dist/injection/descriptor.d.ts +12 -0
  46. package/dist/injection/descriptor.d.ts.map +1 -1
  47. package/dist/injection/descriptor.js +8 -0
  48. package/dist/injection/descriptor.js.map +1 -1
  49. package/dist/introspection/dependency-graph.d.ts +6 -0
  50. package/dist/introspection/dependency-graph.d.ts.map +1 -1
  51. package/dist/introspection/dependency-graph.js +2 -0
  52. package/dist/introspection/dependency-graph.js.map +1 -1
  53. package/dist/introspection/graph-adapters/cytoscape.d.ts +8 -0
  54. package/dist/introspection/graph-adapters/cytoscape.d.ts.map +1 -1
  55. package/dist/introspection/graph-adapters/cytoscape.js +2 -0
  56. package/dist/introspection/graph-adapters/cytoscape.js.map +1 -1
  57. package/dist/introspection/graph-adapters/dot.d.ts +2 -0
  58. package/dist/introspection/graph-adapters/dot.d.ts.map +1 -1
  59. package/dist/introspection/graph-adapters/dot.js +2 -0
  60. package/dist/introspection/graph-adapters/dot.js.map +1 -1
  61. package/dist/introspection/graph-adapters/reactflow.d.ts +8 -0
  62. package/dist/introspection/graph-adapters/reactflow.d.ts.map +1 -1
  63. package/dist/introspection/graph-adapters/reactflow.js +2 -0
  64. package/dist/introspection/graph-adapters/reactflow.js.map +1 -1
  65. package/dist/introspection/inspector.d.ts +6 -0
  66. package/dist/introspection/inspector.d.ts.map +1 -1
  67. package/dist/introspection/inspector.js +2 -0
  68. package/dist/introspection/inspector.js.map +1 -1
  69. package/dist/lifecycle/lifecycle-manager.d.ts +2 -0
  70. package/dist/lifecycle/lifecycle-manager.d.ts.map +1 -1
  71. package/dist/lifecycle/lifecycle-manager.js +7 -2
  72. package/dist/lifecycle/lifecycle-manager.js.map +1 -1
  73. package/dist/lifecycle/scope-manager.d.ts +2 -0
  74. package/dist/lifecycle/scope-manager.d.ts.map +1 -1
  75. package/dist/lifecycle/scope-manager.js +2 -0
  76. package/dist/lifecycle/scope-manager.js.map +1 -1
  77. package/dist/metadata/metadata-keys.d.ts +6 -0
  78. package/dist/metadata/metadata-keys.d.ts.map +1 -1
  79. package/dist/metadata/metadata-keys.js +6 -0
  80. package/dist/metadata/metadata-keys.js.map +1 -1
  81. package/dist/metadata/metadata-reader-token.d.ts +2 -0
  82. package/dist/metadata/metadata-reader-token.d.ts.map +1 -1
  83. package/dist/metadata/metadata-reader-token.js +2 -0
  84. package/dist/metadata/metadata-reader-token.js.map +1 -1
  85. package/dist/metadata/metadata-types.d.ts +6 -0
  86. package/dist/metadata/metadata-types.d.ts.map +1 -1
  87. package/dist/metadata/symbol-metadata-reader.d.ts +4 -0
  88. package/dist/metadata/symbol-metadata-reader.d.ts.map +1 -1
  89. package/dist/metadata/symbol-metadata-reader.js +4 -0
  90. package/dist/metadata/symbol-metadata-reader.js.map +1 -1
  91. package/dist/resolution/cache/activation-need.d.ts +2 -0
  92. package/dist/resolution/cache/activation-need.d.ts.map +1 -1
  93. package/dist/resolution/cache/activation-need.js +2 -0
  94. package/dist/resolution/cache/activation-need.js.map +1 -1
  95. package/dist/resolution/cache/binding-lookup-cache.d.ts +2 -0
  96. package/dist/resolution/cache/binding-lookup-cache.d.ts.map +1 -1
  97. package/dist/resolution/cache/binding-lookup-cache.js +7 -4
  98. package/dist/resolution/cache/binding-lookup-cache.js.map +1 -1
  99. package/dist/resolution/cache/class-introspector.d.ts +2 -0
  100. package/dist/resolution/cache/class-introspector.d.ts.map +1 -1
  101. package/dist/resolution/cache/class-introspector.js +2 -0
  102. package/dist/resolution/cache/class-introspector.js.map +1 -1
  103. package/dist/resolution/context.d.ts +6 -0
  104. package/dist/resolution/context.d.ts.map +1 -1
  105. package/dist/resolution/context.js +4 -0
  106. package/dist/resolution/context.js.map +1 -1
  107. package/dist/resolution/plan/instantiation-plan.d.ts +2 -0
  108. package/dist/resolution/plan/instantiation-plan.d.ts.map +1 -1
  109. package/dist/resolution/plan/instantiation-plan.js +2 -0
  110. package/dist/resolution/plan/instantiation-plan.js.map +1 -1
  111. package/dist/resolution/resolver.d.ts +2 -0
  112. package/dist/resolution/resolver.d.ts.map +1 -1
  113. package/dist/resolution/resolver.js +2 -0
  114. package/dist/resolution/resolver.js.map +1 -1
  115. package/dist/resolution/select/constraints.d.ts +16 -0
  116. package/dist/resolution/select/constraints.d.ts.map +1 -1
  117. package/dist/resolution/select/constraints.js +16 -0
  118. package/dist/resolution/select/constraints.js.map +1 -1
  119. package/package.json +18 -6
  120. package/src/ambient/active-container.ts +4 -0
  121. package/src/container/container.ts +11 -3
  122. package/src/core/map-upsert.ts +53 -0
  123. package/src/core/module.ts +16 -0
  124. package/src/core/registry.ts +10 -4
  125. package/src/core/token.ts +6 -0
  126. package/src/core/types.ts +20 -0
  127. package/src/decorators/inject.ts +2 -0
  128. package/src/decorators/injectable.ts +8 -0
  129. package/src/decorators/lifecycle-decorators.ts +4 -0
  130. package/src/errors/errors.ts +34 -0
  131. package/src/injection/descriptor.ts +12 -0
  132. package/src/introspection/dependency-graph.ts +6 -0
  133. package/src/introspection/graph-adapters/cytoscape.ts +8 -0
  134. package/src/introspection/graph-adapters/dot.ts +2 -0
  135. package/src/introspection/graph-adapters/reactflow.ts +8 -0
  136. package/src/introspection/inspector.ts +6 -0
  137. package/src/lifecycle/lifecycle-manager.ts +7 -2
  138. package/src/lifecycle/scope-manager.ts +4 -2
  139. package/src/metadata/metadata-keys.ts +6 -0
  140. package/src/metadata/metadata-reader-token.ts +2 -0
  141. package/src/metadata/metadata-types.ts +6 -0
  142. package/src/metadata/symbol-metadata-reader.ts +6 -2
  143. package/src/resolution/cache/activation-need.ts +2 -0
  144. package/src/resolution/cache/binding-lookup-cache.ts +7 -4
  145. package/src/resolution/cache/class-introspector.ts +8 -3
  146. package/src/resolution/context.ts +6 -0
  147. package/src/resolution/plan/instantiation-plan.ts +2 -0
  148. package/src/resolution/resolver.ts +2 -0
  149. 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 {
@@ -73,7 +75,7 @@ export class SymbolMetadataReader implements MetadataReader {
73
75
  preDestroy: mergeUniqueNames(buckets.map((bucket) => bucket.preDestroy).reverse()),
74
76
  };
75
77
  }
76
- (this.#lifecycleByClass ??= new WeakMap()).set(target, merged);
78
+ (this.#lifecycleByClass ??= new WeakMap<Constructor, LifecycleMetadata | null>()).set(target, merged);
77
79
  return merged ?? undefined;
78
80
  }
79
81
 
@@ -96,7 +98,7 @@ export class SymbolMetadataReader implements MetadataReader {
96
98
  } else {
97
99
  merged = buckets.flat();
98
100
  }
99
- (this.#accessorsByClass ??= new WeakMap()).set(target, merged);
101
+ (this.#accessorsByClass ??= new WeakMap<Constructor, ReadonlyArray<AccessorEntry> | null>()).set(target, merged);
100
102
  return merged ?? undefined;
101
103
  }
102
104
  }
@@ -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 {
@@ -5,6 +5,7 @@
5
5
  * the container hierarchy again.
6
6
  */
7
7
  import type { Binding } from "#/core/binding";
8
+ import { getOrInsertComputed } from "#/core/map-upsert";
8
9
  import type { BindingRegistry } from "#/core/registry";
9
10
  import type { BindingTag } from "#/core/tag";
10
11
  import type { Token } from "#/core/token";
@@ -38,6 +39,8 @@ const newNameToEntryMap = <Owner>(): Map<string, DefaultLookupEntry<Owner> | nul
38
39
  const newTagToEntryMap = <Owner>(): Map<BindingTag, DefaultLookupEntry<Owner> | null> => new Map();
39
40
 
40
41
  /**
42
+ * A version-stamped cache of binding lookups by token, name, and tag across the container chain.
43
+ *
41
44
  * @since 0.5.0-canary.9
42
45
  */
43
46
  export class BindingLookupCache<Owner> {
@@ -105,9 +108,9 @@ export class BindingLookupCache<Owner> {
105
108
  this.#byTokenAndName.clear();
106
109
  this.#namedVersion = version;
107
110
  }
108
- // Computed, not eager: this runs on every named resolve, and `getOrInsert(token, new Map())`
109
- // would allocate a Map per call only to discard it on the hit that follows.
110
- const byName = this.#byTokenAndName.getOrInsertComputed(token, newNameToEntryMap);
111
+ // Computed, not eager: this runs on every named resolve, and the eager form would allocate a
112
+ // Map per call only to discard it on the hit that follows.
113
+ const byName = getOrInsertComputed(this.#byTokenAndName, token, newNameToEntryMap);
111
114
  let entry = byName.get(name);
112
115
  if (entry === undefined) {
113
116
  entry = this.#findNamedInChain(token, name);
@@ -134,7 +137,7 @@ export class BindingLookupCache<Owner> {
134
137
  } else {
135
138
  // Keyed by the criterion object itself: criteria are interned, so identity is the slot
136
139
  // contract's own `Object.is` — the same exactness the registry's tagged index relies on.
137
- const byTag = this.#byTokenAndTag.getOrInsertComputed(token, newTagToEntryMap);
140
+ const byTag = getOrInsertComputed(this.#byTokenAndTag, token, newTagToEntryMap);
138
141
  entry = byTag.get(tag);
139
142
  if (entry === undefined) {
140
143
  entry = this.#findTaggedInChain(token, tag);
@@ -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 {
@@ -210,7 +212,10 @@ export class ClassIntrospector {
210
212
  return cached === null ? undefined : cached;
211
213
  }
212
214
  const metadata = this.#reader.getConstructorMetadata(target);
213
- (this.#constructorMetadata ??= new WeakMap()).set(target, metadata ?? null);
215
+ (this.#constructorMetadata ??= new WeakMap<Constructor, ConstructorMetadata | null>()).set(
216
+ target,
217
+ metadata ?? null,
218
+ );
214
219
  return metadata;
215
220
  }
216
221
 
@@ -225,7 +230,7 @@ export class ClassIntrospector {
225
230
 
226
231
  discoverPostConstruct(target: Constructor): void {
227
232
  const lifecycle = this.#reader.getLifecycleMetadata(target);
228
- (this.#hasPostConstruct ??= new WeakMap()).set(
233
+ (this.#hasPostConstruct ??= new WeakMap<Constructor, boolean>()).set(
229
234
  target,
230
235
  lifecycle !== undefined && lifecycle.postConstruct !== undefined && lifecycle.postConstruct.length > 0,
231
236
  );
@@ -236,7 +241,7 @@ export class ClassIntrospector {
236
241
  let needsActiveContainer = this.#needsActiveContainer?.get(target);
237
242
  if (needsActiveContainer === undefined) {
238
243
  needsActiveContainer = (this.#reader.getAccessorMetadata?.(target)?.length ?? 0) > 0;
239
- (this.#needsActiveContainer ??= new WeakMap()).set(target, needsActiveContainer);
244
+ (this.#needsActiveContainer ??= new WeakMap<Constructor, boolean>()).set(target, needsActiveContainer);
240
245
  }
241
246
  return needsActiveContainer;
242
247
  }
@@ -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(
@@ -161,6 +161,8 @@ export interface InstantiationPlanHost {
161
161
  export type EscapeArity = "all" | "optional" | "single";
162
162
 
163
163
  /**
164
+ * The compiler that flattens a class or resolved binding's dependencies into an instantiation plan.
165
+ *
164
166
  * @since 0.3.16-canary.1
165
167
  */
166
168
  export class InstantiationPlanCompiler {
@@ -71,6 +71,8 @@ const ROOT_CONSTRAINT_CONTEXT = {
71
71
  };
72
72
 
73
73
  /**
74
+ * The resolution engine driving binding selection, instantiation, scoping, and lifecycle hooks.
75
+ *
74
76
  * @since 0.3.16-canary.0
75
77
  */
76
78
  export class DependencyResolver implements ResolverCallbacks {
@@ -7,6 +7,8 @@ import type { BindingConstraint, Constructor } from "#/core/types";
7
7
  import { EmptyTagCriteriaError } from "#/errors/errors";
8
8
 
9
9
  /**
10
+ * Matches when the direct parent frame resolves the given token.
11
+ *
10
12
  * @since 0.3.16-canary.0
11
13
  */
12
14
  export function whenParentIs(token: Token<unknown> | Constructor): BindingConstraint {
@@ -16,6 +18,8 @@ export function whenParentIs(token: Token<unknown> | Constructor): BindingConstr
16
18
  }
17
19
 
18
20
  /**
21
+ * Matches when there is no direct parent frame, or it resolves a different token.
22
+ *
19
23
  * @since 0.3.16-canary.0
20
24
  */
21
25
  export function whenNoParentIs(token: Token<unknown> | Constructor): BindingConstraint {
@@ -25,6 +29,8 @@ export function whenNoParentIs(token: Token<unknown> | Constructor): BindingCons
25
29
  }
26
30
 
27
31
  /**
32
+ * Matches when at least one ancestor frame resolves the given token.
33
+ *
28
34
  * @since 0.3.16-canary.0
29
35
  */
30
36
  export function whenAnyAncestorIs(token: Token<unknown> | Constructor): BindingConstraint {
@@ -34,6 +40,8 @@ export function whenAnyAncestorIs(token: Token<unknown> | Constructor): BindingC
34
40
  }
35
41
 
36
42
  /**
43
+ * Matches when no ancestor frame resolves the given token.
44
+ *
37
45
  * @since 0.3.16-canary.0
38
46
  */
39
47
  export function whenNoAncestorIs(token: Token<unknown> | Constructor): BindingConstraint {
@@ -43,6 +51,8 @@ export function whenNoAncestorIs(token: Token<unknown> | Constructor): BindingCo
43
51
  }
44
52
 
45
53
  /**
54
+ * Matches when the direct parent slot carries the given name.
55
+ *
46
56
  * @since 0.3.16-canary.0
47
57
  */
48
58
  export function whenParentNamed(name: string): BindingConstraint {
@@ -54,6 +64,8 @@ export function whenParentNamed(name: string): BindingConstraint {
54
64
  }
55
65
 
56
66
  /**
67
+ * Matches when at least one ancestor slot carries the given name.
68
+ *
57
69
  * @since 0.3.16-canary.0
58
70
  */
59
71
  export function whenAnyAncestorNamed(name: string): BindingConstraint {
@@ -65,6 +77,8 @@ export function whenAnyAncestorNamed(name: string): BindingConstraint {
65
77
  }
66
78
 
67
79
  /**
80
+ * Matches when the direct parent slot carries the given tag pair.
81
+ *
68
82
  * @since 0.3.16-canary.0
69
83
  */
70
84
  export function whenParentTagged(criterion: BindingTag): BindingConstraint {
@@ -73,6 +87,8 @@ export function whenParentTagged(criterion: BindingTag): BindingConstraint {
73
87
  }
74
88
 
75
89
  /**
90
+ * Matches when at least one ancestor slot carries the given tag pair.
91
+ *
76
92
  * @since 0.3.16-canary.0
77
93
  */
78
94
  export function whenAnyAncestorTagged(criterion: BindingTag): BindingConstraint {