@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
package/src/core/types.ts DELETED
@@ -1,149 +0,0 @@
1
- import type { Constructor } from "#/core/constructor-type";
2
- import type { BindingTag, TagKeyMask } from "#/core/tag";
3
- import type { Token } from "#/core/token";
4
-
5
- // Re-export for consumers that import from `#/types`
6
- export type { Constructor } from "#/core/constructor-type";
7
- export type { BindingTag, TagKey, TagKeyMask } from "#/core/tag";
8
-
9
- /**
10
- * Token or class constructor used as a binding / injection / resolve key.
11
- *
12
- * @since 0.3.16-canary.0
13
- */
14
- export type DependencyKey = Token<unknown> | Constructor;
15
-
16
- // ── BindingScope ─────────────────────────────────────────────────────────────────────────────────────────────────────
17
-
18
- /**
19
- * The lifetime a binding's instances are cached under.
20
- *
21
- * @since 0.3.16-canary.0
22
- */
23
- export type BindingScope = "singleton" | "transient" | "scoped";
24
-
25
- // ── BindingIdentifier ────────────────────────────────────────────────────────────────────────────────────────────────
26
-
27
- declare const BINDING_ID_BRAND: unique symbol;
28
- /**
29
- * A branded string that uniquely identifies one binding.
30
- *
31
- * @since 0.3.16-canary.0
32
- */
33
- export type BindingIdentifier = string & { readonly [BINDING_ID_BRAND]: true };
34
-
35
- // ── BindingKind ──────────────────────────────────────────────────────────────────────────────────────────────────────
36
-
37
- /**
38
- * The strategy a binding produces values with, set by the `to*()` call that created it.
39
- *
40
- * @since 0.3.16-canary.0
41
- */
42
- export type BindingKind = "class" | "dynamic" | "dynamic-async" | "resolved" | "resolved-async" | "constant" | "alias";
43
-
44
- // ── Handlers ─────────────────────────────────────────────────────────────────────────────────────────────────────────
45
-
46
- /**
47
- * A hook that runs after an instance is created and returns the instance to hand out.
48
- *
49
- * @since 0.3.16-canary.0
50
- */
51
- export type ActivationHandler<Value> = (ctx: ResolutionContext, instance: Value) => Value | Promise<Value>;
52
-
53
- /**
54
- * A hook that runs when a cached instance is released from its scope.
55
- *
56
- * @since 0.3.16-canary.0
57
- */
58
- export type DeactivationHandler<Value> = (instance: Value) => void | Promise<void>;
59
-
60
- // ── ResolveOptions ───────────────────────────────────────────────────────────────────────────────────────────────────
61
-
62
- /**
63
- * Slot-selection criteria — a name and tags — that narrow which binding a resolve call matches.
64
- *
65
- * @since 0.3.16-canary.0
66
- */
67
- export interface ResolveOptions {
68
- name?: string | undefined;
69
- /**
70
- * Single-tag shorthand, equivalent to listing the one pair in `tags`.
71
- *
72
- * @remarks Reaches the same tagged index, so choosing it costs nothing. `InjectOptions` accepts it
73
- * too and folds it into `tags`. Only `tags` expresses a request for more than one tag.
74
- */
75
- tag?: BindingTag | undefined;
76
- tags?: ReadonlyArray<BindingTag> | undefined;
77
- }
78
-
79
- // ── ResolutionFrame ──────────────────────────────────────────────────────────────────────────────────────────────────
80
-
81
- /**
82
- * One entry of the resolution stack: the token, scope, binding, and slot being resolved.
83
- *
84
- * @since 0.3.16-canary.0
85
- */
86
- export interface ResolutionFrame {
87
- readonly tokenName: string;
88
- readonly scope: BindingScope;
89
- readonly bindingId: BindingIdentifier;
90
- readonly kind: BindingKind;
91
- readonly slot: {
92
- readonly name: string | undefined;
93
- readonly tags: ReadonlyArray<BindingTag>;
94
- readonly keyMask: TagKeyMask;
95
- };
96
- }
97
-
98
- // ── ConstraintContext ────────────────────────────────────────────────────────────────────────────────────────────────
99
-
100
- /**
101
- * The resolution-time view — path, stack, parent, and ancestors — a `BindingConstraint` inspects.
102
- *
103
- * @since 0.3.16-canary.0
104
- */
105
- export interface ConstraintContext {
106
- readonly resolutionPath: ReadonlyArray<string>;
107
- readonly resolutionStack: ReadonlyArray<ResolutionFrame>;
108
- readonly parent: ResolutionFrame | undefined;
109
- readonly ancestors: ReadonlyArray<ResolutionFrame>;
110
- /** Readonly because one frozen object answers every resolve of a slot — a write would throw. */
111
- readonly currentResolveOptions: Readonly<ResolveOptions> | undefined;
112
- }
113
-
114
- /**
115
- * The predicate `when()` selects a binding by, and the shape every `when*` helper returns.
116
- *
117
- * @since 0.6.0
118
- */
119
- export type BindingConstraint = (ctx: ConstraintContext) => boolean;
120
-
121
- // ── ResolutionContext ────────────────────────────────────────────────────────────────────────────────────────────────
122
-
123
- /**
124
- * The container view a dynamic factory or activation handler resolves further dependencies through.
125
- *
126
- * @since 0.3.16-canary.0
127
- */
128
- export interface ResolutionContext {
129
- resolve<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value;
130
- resolveAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Value>;
131
- resolveOptional<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Value | undefined;
132
- resolveOptionalAsync<Value>(
133
- token: Token<Value> | Constructor<Value>,
134
- options?: ResolveOptions,
135
- ): Promise<Value | undefined>;
136
- resolveAll<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Array<Value>;
137
- resolveAllAsync<Value>(token: Token<Value> | Constructor<Value>, options?: ResolveOptions): Promise<Array<Value>>;
138
- readonly graph: ConstraintContext;
139
- }
140
-
141
- // ── TokenValue ───────────────────────────────────────────────────────────────────────────────────────────────────────
142
-
143
- /**
144
- * The value type a token or class constructor resolves to.
145
- *
146
- * @since 0.3.16-canary.0
147
- */
148
- export type TokenValue<Type> =
149
- Type extends Token<infer Value> ? Value : Type extends Constructor<infer Value> ? Value : never;
@@ -1,101 +0,0 @@
1
- import { getActiveContainer, getAmbientResolution } from "#/ambient/active-container";
2
- /** `@inject` — the accessor-decorator channel, resolving from the ambient container. */
3
- import type { Token } from "#/core/token";
4
- import type { Constructor } from "#/core/types";
5
- import { MissingContainerContextError, StaticMemberDecoratorError } from "#/errors/errors";
6
- import type { InjectionDescriptor, InjectOptions } from "#/injection/descriptor";
7
- import { buildInjectionDescriptor } from "#/injection/descriptor";
8
- import { injectionSlotToResolveOptions } from "#/injection/resolve-options";
9
- import { INJECT_ACCESSOR_KEY } from "#/metadata/metadata-keys";
10
-
11
- /**
12
- * The name of the class being constructed, or `undefined` when there is none to report.
13
- *
14
- * @remarks Two ways there is none: an anonymous class expression has an empty `name`, and an
15
- * instance whose prototype chain answers no `constructor` has nothing to read. Narrowed rather than
16
- * asserted — the value arrives as `unknown` and the platform makes no promise about it.
17
- */
18
- function classNameOf(instance: unknown): string | undefined {
19
- if (typeof instance !== "object" || instance === null) {
20
- return undefined;
21
- }
22
- const constructor: unknown = Reflect.get(instance, "constructor");
23
- if (typeof constructor !== "function" || constructor.name === "") {
24
- return undefined;
25
- }
26
-
27
- return constructor.name;
28
- }
29
-
30
- // ── inject() — dual-role ─────────────────────────────────────────────────────────────────────────────────────────────
31
-
32
- type ClassAccessorDecorator<This, Value> = (
33
- target: ClassAccessorDecoratorTarget<This, Value>,
34
- context: ClassAccessorDecoratorContext<This, Value>,
35
- ) => ClassAccessorDecoratorResult<This, Value> | void;
36
-
37
- /**
38
- * Creates a dual-role value: an injection descriptor that also works as a class accessor decorator.
39
- *
40
- * @since 0.3.16-canary.0
41
- */
42
- export function inject<Value>(
43
- token: Token<Value> | Constructor<Value>,
44
- options?: InjectOptions,
45
- ): InjectionDescriptor<Value> & ClassAccessorDecorator<unknown, Value> {
46
- const descriptor = buildInjectionDescriptor(token, options);
47
- // Derived from the descriptor, not from `options`: the descriptor is where the tag shorthand has
48
- // already been folded. Built once here rather than per constructed instance.
49
- const resolveOptions = injectionSlotToResolveOptions(descriptor);
50
-
51
- const decoratorFn = (
52
- _target: ClassAccessorDecoratorTarget<unknown, Value>,
53
- context: ClassAccessorDecoratorContext<unknown, Value>,
54
- ): ClassAccessorDecoratorResult<unknown, Value> => {
55
- if (context.static) {
56
- throw new StaticMemberDecoratorError("inject", String(context.name));
57
- }
58
- const meta = context.metadata as Record<string | symbol, unknown>;
59
- // Own bucket only: the metadata record inherits the base class's, and pushing into an inherited
60
- // array would register this accessor on the base class instead.
61
- if (!Object.hasOwn(meta, INJECT_ACCESSOR_KEY) || !Array.isArray(meta[INJECT_ACCESSOR_KEY])) {
62
- meta[INJECT_ACCESSOR_KEY] = [];
63
- }
64
- (meta[INJECT_ACCESSOR_KEY] as Array<{ key: string | symbol; descriptor: InjectionDescriptor }>).push({
65
- key: context.name,
66
- descriptor,
67
- });
68
-
69
- context.addInitializer(function (this: unknown) {
70
- // Prefer the engine's path-continuing resolver: it keeps this accessor's dependencies on the
71
- // live resolution path, so a cycle through an accessor is detected instead of recursing.
72
- const ambient = getAmbientResolution();
73
- if (ambient !== undefined) {
74
- const value = descriptor.optional
75
- ? ambient.resolveOptional(token, resolveOptions)
76
- : ambient.resolve(token, resolveOptions);
77
- context.access.set(this, value as Value);
78
- return;
79
- }
80
- const container = getActiveContainer();
81
- if (container === undefined) {
82
- throw new MissingContainerContextError(classNameOf(this), context.name);
83
- }
84
- const value = descriptor.optional
85
- ? container.resolveOptional(token, resolveOptions)
86
- : container.resolve(token, resolveOptions);
87
- context.access.set(this, value as Value);
88
- });
89
-
90
- return {};
91
- };
92
-
93
- // Use defineProperties to handle read-only `name` property of functions
94
- const props: PropertyDescriptorMap = {};
95
- for (const key of Object.keys(descriptor) as Array<keyof typeof descriptor>) {
96
- props[key] = { value: descriptor[key], writable: true, enumerable: true, configurable: true };
97
- }
98
- Object.defineProperties(decoratorFn, props);
99
-
100
- return decoratorFn as InjectionDescriptor<Value> & ClassAccessorDecorator<unknown, Value>;
101
- }
@@ -1,134 +0,0 @@
1
- import type { BindingScope, Constructor } from "#/core/types";
2
- import type { InjectableDependency, ResolvedDependencyValue } from "#/injection/descriptor";
3
- import { normalizeToDescriptor } from "#/injection/descriptor";
4
- import { INJECTABLE_KEY } from "#/metadata/metadata-keys";
5
- import type { ParamMetadata } from "#/metadata/metadata-types";
6
-
7
- // ── AutoRegisterRegistry ─────────────────────────────────────────────────────────────────────────────────────────────
8
-
9
- /**
10
- * The collector `@injectable` registers a class into, for a container to bind later.
11
- *
12
- * @since 0.3.16-canary.0
13
- */
14
- export interface AutoRegisterRegistry {
15
- register(target: Constructor, scope: BindingScope): void;
16
- entries(): ReadonlyArray<{ target: Constructor; scope: BindingScope }>;
17
- }
18
-
19
- /**
20
- * Creates an empty auto-register registry.
21
- *
22
- * @since 0.3.16-canary.0
23
- */
24
- export function createAutoRegisterRegistry(): AutoRegisterRegistry {
25
- const registeredEntries: Array<{ target: Constructor; scope: BindingScope }> = [];
26
- return {
27
- register(target: Constructor, scope: BindingScope): void {
28
- registeredEntries.push({ target, scope });
29
- },
30
- entries(): ReadonlyArray<{ target: Constructor; scope: BindingScope }> {
31
- return registeredEntries;
32
- },
33
- };
34
- }
35
-
36
- // ── InjectableOptions ────────────────────────────────────────────────────────────────────────────────────────────────
37
-
38
- /**
39
- * Auto-registration options `@injectable` accepts alongside its deps list.
40
- *
41
- * @since 0.3.16-canary.0
42
- */
43
- export interface InjectableOptions {
44
- autoRegister?: AutoRegisterRegistry | undefined;
45
- scope?: BindingScope | undefined;
46
- }
47
-
48
- // ── @injectable() ────────────────────────────────────────────────────────────────────────────────────────────────────
49
-
50
- /**
51
- * The parameters a constructor is handed, given what its `deps` declare.
52
- *
53
- * @remarks Reuses the same reading a `toResolved` factory gets, so `injectAll` arrives as an array
54
- * and `optional` as possibly undefined in both places.
55
- */
56
- type InjectedParameters<Deps extends ReadonlyArray<InjectableDependency>> = {
57
- -readonly [Index in keyof Deps]: ResolvedDependencyValue<Deps[Index]>;
58
- };
59
-
60
- /**
61
- * Declare a class injectable, and what its constructor is to be handed.
62
- *
63
- * @since 0.3.16-canary.0
64
- */
65
- export function injectable(): (target: unknown, context: ClassDecoratorContext) => void;
66
-
67
- /**
68
- * @remarks Declaring dependencies constrains the class: the decorator only accepts one whose
69
- * constructor takes exactly what `deps` resolve to, in that order — including arity, so a literal
70
- * deps list longer than the constructor is a compile error rather than a resolved-and-discarded
71
- * value. Optional trailing parameters admit every arity they declare, and a rest parameter admits
72
- * any list. A deps *array* — one whose length the compiler cannot know — skips the arity check,
73
- * which is also the deliberate spelling for declaring more dependencies than the constructor
74
- * takes, e.g. for the dependency graph's edges.
75
- *
76
- * @since 0.3.16-canary.0
77
- */
78
- export function injectable<const Deps extends ReadonlyArray<InjectableDependency>>(
79
- deps: Deps,
80
- options?: InjectableOptions,
81
- ): <Target extends abstract new (...args: InjectedParameters<Deps>) => unknown>(
82
- target: Target &
83
- (number extends Deps["length"]
84
- ? unknown
85
- : Deps["length"] extends ConstructorParameters<Target>["length"]
86
- ? unknown
87
- : never),
88
- context: ClassDecoratorContext,
89
- ) => void;
90
-
91
- /**
92
- * Writes the declared dependencies into the class's metadata and optionally auto-registers it.
93
- *
94
- * @since 0.6.0
95
- */
96
- export function injectable(
97
- deps?: ReadonlyArray<InjectableDependency>,
98
- options?: InjectableOptions,
99
- ): (target: never, context: ClassDecoratorContext) => void {
100
- return function (target: never, context: ClassDecoratorContext): void {
101
- const parameterMetadataList: Array<ParamMetadata> = (deps ?? []).map((dependency, index) => {
102
- const descriptor = normalizeToDescriptor(dependency);
103
- const baseParameterMetadata: Pick<ParamMetadata, "index" | "token" | "optional" | "multi"> = {
104
- index,
105
- token: descriptor.token,
106
- optional: descriptor.optional,
107
- multi: descriptor.multi,
108
- };
109
- if (descriptor.name !== undefined && descriptor.tags !== undefined) {
110
- return { ...baseParameterMetadata, name: descriptor.name, tags: descriptor.tags };
111
- }
112
- if (descriptor.name !== undefined) {
113
- return { ...baseParameterMetadata, name: descriptor.name };
114
- }
115
- if (descriptor.tags !== undefined) {
116
- return { ...baseParameterMetadata, tags: descriptor.tags };
117
- }
118
- return baseParameterMetadata;
119
- });
120
-
121
- // Field decorators run before the class decorator — accessor @inject entries are
122
- // already on context.metadata by the time this runs.
123
- (context.metadata as Record<string | symbol, unknown>)[INJECTABLE_KEY] = {
124
- params: parameterMetadataList,
125
- };
126
-
127
- if (options?.autoRegister !== undefined) {
128
- const scope: BindingScope = options.scope ?? "transient";
129
- options.autoRegister.register(target as Constructor, scope);
130
- }
131
- };
132
- }
133
-
134
- export type { InjectableDependency };
@@ -1,43 +0,0 @@
1
- import { StaticMemberDecoratorError } from "#/errors/errors";
2
- import { LIFECYCLE_KEY } from "#/metadata/metadata-keys";
3
- import type { MutableLifecycleMetadata } from "#/metadata/metadata-types";
4
-
5
- type MethodDecorator = (target: unknown, context: ClassMethodDecoratorContext) => void;
6
-
7
- /** Records the decorated method under one lifecycle phase; both decorators differ only in that phase. */
8
- function recordLifecycleMethod(phase: "postConstruct" | "preDestroy"): MethodDecorator {
9
- return function (target: unknown, context: ClassMethodDecoratorContext): void {
10
- if (context.static) {
11
- throw new StaticMemberDecoratorError(phase, String(context.name));
12
- }
13
- const meta = context.metadata as Record<string | symbol, unknown>;
14
- // Own bucket only: `context.metadata` inherits the base class's record, and writing through an
15
- // inherited bucket would register this hook on the base class instead.
16
- if (!Object.hasOwn(meta, LIFECYCLE_KEY)) {
17
- meta[LIFECYCLE_KEY] = { postConstruct: [], preDestroy: [] };
18
- }
19
- const lifecycle = meta[LIFECYCLE_KEY] as MutableLifecycleMetadata;
20
- const methodName = String(context.name);
21
- if (!lifecycle[phase].includes(methodName)) {
22
- lifecycle[phase].push(methodName);
23
- }
24
- };
25
- }
26
-
27
- /**
28
- * Marks an instance method to run after the container constructs and wires the instance.
29
- *
30
- * @since 0.3.16-canary.0
31
- */
32
- export function postConstruct(): MethodDecorator {
33
- return recordLifecycleMethod("postConstruct");
34
- }
35
-
36
- /**
37
- * Marks an instance method to run when the instance's container or scope is disposed.
38
- *
39
- * @since 0.3.16-canary.0
40
- */
41
- export function preDestroy(): MethodDecorator {
42
- return recordLifecycleMethod("preDestroy");
43
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * Internal seam letting tests assert that an optimization is *active*, not merely that the result
3
- * is correct.
4
- *
5
- * @remarks Timing belongs in the benchmark, which needs a quiet machine and twenty minutes; these
6
- * are structural counts, so CI can hold the invariants that make the benchmark fast. Reached
7
- * through a symbol from a module the package does not publish, so it is not public API.
8
- */
9
-
10
- /**
11
- * Key for the diagnostics accessor on a container.
12
- *
13
- * @remarks A symbol rather than a method name, so it cannot collide with the public surface or be
14
- * reached by anyone who has not imported this module.
15
- *
16
- * @since 0.5.0-canary.8
17
- */
18
- export const RESOLUTION_DIAGNOSTICS: unique symbol = Symbol("di:resolution-diagnostics");
19
-
20
- /**
21
- * Structural facts about a container's resolution caches.
22
- *
23
- * @since 0.5.0-canary.8
24
- */
25
- export interface ResolutionDiagnostics {
26
- /** Bindings with a compiled instantiation plan. */
27
- readonly compiledPlanCount: number;
28
- /** Bindings with a compiled async instantiation plan. */
29
- readonly compiledAsyncPlanCount: number;
30
- /** Contexts held by the depth-indexed sync pool. */
31
- readonly syncContextPoolSize: number;
32
- /** Scoped instances currently cached by this container's scope manager. */
33
- readonly scopedInstanceCount: number;
34
- /** Deferred collaborators this container has had to build. */
35
- readonly builtSubsystems: ReadonlyArray<string>;
36
- }
37
-
38
- /**
39
- * A container that can report on its resolution caches.
40
- *
41
- * @since 0.5.0-canary.8
42
- */
43
- export interface DiagnosableContainer {
44
- [RESOLUTION_DIAGNOSTICS](): ResolutionDiagnostics;
45
- }