@codefast/di 0.3.14-canary.1 → 0.3.14

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 (65) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +42 -26
  3. package/dist/binding-scope.d.mts +11 -0
  4. package/dist/binding-scope.mjs +19 -0
  5. package/dist/binding-select.d.mts +8 -26
  6. package/dist/binding-select.mjs +56 -49
  7. package/dist/binding.d.mts +107 -335
  8. package/dist/binding.mjs +19 -332
  9. package/dist/constraints.d.mts +11 -29
  10. package/dist/constraints.mjs +32 -36
  11. package/dist/constructor-type.d.mts +17 -0
  12. package/dist/constructor-type.mjs +1 -0
  13. package/dist/container.d.mts +43 -122
  14. package/dist/container.mjs +667 -482
  15. package/dist/decorators/inject.d.mts +19 -50
  16. package/dist/decorators/inject.mjs +131 -93
  17. package/dist/decorators/injectable.d.mts +16 -37
  18. package/dist/decorators/injectable.mjs +47 -66
  19. package/dist/decorators/lifecycle-decorators.d.mts +2 -22
  20. package/dist/decorators/lifecycle-decorators.mjs +81 -37
  21. package/dist/dependency-graph.d.mts +24 -54
  22. package/dist/dependency-graph.mjs +51 -153
  23. package/dist/environment.d.mts +38 -12
  24. package/dist/environment.mjs +82 -16
  25. package/dist/errors.d.mts +70 -189
  26. package/dist/errors.mjs +92 -219
  27. package/dist/graph-adapters/cytoscape.d.mts +21 -7
  28. package/dist/graph-adapters/cytoscape.mjs +18 -35
  29. package/dist/graph-adapters/dot.d.mts +1 -4
  30. package/dist/graph-adapters/dot.mjs +6 -86
  31. package/dist/graph-adapters/reactflow.d.mts +26 -7
  32. package/dist/graph-adapters/reactflow.mjs +21 -72
  33. package/dist/graph-adapters/types.d.mts +2 -91
  34. package/dist/index.d.mts +16 -8
  35. package/dist/index.mjs +8 -5
  36. package/dist/inspector.d.mts +35 -74
  37. package/dist/inspector.mjs +61 -88
  38. package/dist/lifecycle.d.mts +20 -53
  39. package/dist/lifecycle.mjs +129 -99
  40. package/dist/metadata/metadata-keys.d.mts +9 -26
  41. package/dist/metadata/metadata-keys.mjs +7 -28
  42. package/dist/metadata/metadata-reader-token.d.mts +7 -0
  43. package/dist/metadata/metadata-reader-token.mjs +5 -0
  44. package/dist/metadata/metadata-types.d.mts +26 -75
  45. package/dist/metadata/symbol-metadata-reader.d.mts +10 -26
  46. package/dist/metadata/symbol-metadata-reader.mjs +32 -45
  47. package/dist/module.d.mts +30 -96
  48. package/dist/module.mjs +26 -72
  49. package/dist/registry.d.mts +32 -63
  50. package/dist/registry.mjs +131 -82
  51. package/dist/resolve-options.d.mts +18 -0
  52. package/dist/resolve-options.mjs +22 -0
  53. package/dist/resolver.d.mts +67 -190
  54. package/dist/resolver.mjs +715 -424
  55. package/dist/scope.d.mts +19 -106
  56. package/dist/scope.mjs +37 -196
  57. package/dist/token.d.mts +8 -22
  58. package/dist/token.mjs +9 -11
  59. package/dist/types.d.mts +48 -0
  60. package/dist/types.mjs +1 -0
  61. package/package.json +36 -14
  62. package/dist/metadata/param-registry.d.mts +0 -16
  63. package/dist/metadata/param-registry.mjs +0 -31
  64. package/dist/scope-validation.d.mts +0 -21
  65. package/dist/scope-validation.mjs +0 -35
package/dist/scope.d.mts CHANGED
@@ -1,112 +1,25 @@
1
- import { Binding, BindingIdentifier } from "./binding.mjs";
1
+ import { BindingIdentifier } from "./types.mjs";
2
2
 
3
3
  //#region src/scope.d.ts
4
- /**
5
- * Caches singleton and scoped instances, deduplicates concurrent async creation, and runs
6
- * deactivation hooks (`onDeactivation`, `@preDestroy`) on disposal.
7
- *
8
- * A root scope manager owns both singleton and scoped caches. A child scope manager (created
9
- * via {@link createChildScope}) shares the parent's singleton cache but receives a fresh scoped
10
- * cache — singletons are shared across the hierarchy, scoped instances are isolated per child.
11
- *
12
- * Invariant: `ownsSingletonDisposal` is `true` only for the root. When a child disposes, only
13
- * its scoped bindings are deactivated; singletons remain alive until the root disposes.
14
- */
15
4
  declare class ScopeManager {
16
- /**
17
- * Cached singleton instances: `bindingId → { binding, instance }`.
18
- */
19
- private readonly singletonCache;
20
- /**
21
- * Cached scoped instances for this container level: `bindingId → { binding, instance }`.
22
- */
23
- private readonly scopedCache;
24
- /**
25
- * True only for the root scope manager. Controls whether {@link dispose} / {@link disposeAsync}
26
- * also drain the shared singleton cache; child scopes leave singleton disposal to the root.
27
- */
28
- private readonly ownsSingletonDisposal;
29
- /**
30
- * In-flight async singleton creation promises.
31
- * Guards against double-instantiation when multiple `resolveAsync` calls for the same
32
- * singleton binding overlap before the first one settles.
33
- */
34
- private readonly singletonPendingPromises;
35
- /**
36
- * In-flight async scoped creation promises (same deduplication role as
37
- * {@link singletonPendingPromises} but for scoped bindings).
38
- */
39
- private readonly scopedPendingPromises;
40
- /**
41
- * Internal constructor for root/child scope managers.
42
- * Prefer {@link createRoot} and {@link createChildScope}.
43
- */
44
- private constructor();
45
- /**
46
- * Creates a root scope manager that owns both the singleton cache and scoped cache.
47
- */
48
- static createRoot(): ScopeManager;
49
- /**
50
- * Shares the parent singleton cache; receives a fresh scoped cache (for child containers).
51
- */
52
- createChildScope(): ScopeManager;
53
- /**
54
- * Whether a singleton/scoped binding currently has a cached instance (always false for transient).
55
- */
56
- isBindingCached(binding: Binding<unknown>): boolean;
57
- /**
58
- * Returns the cached instance for singleton/scoped bindings, or calls `createInstance` on first access.
59
- */
60
- getOrCreate(binding: Binding<unknown>, createInstance: () => unknown): unknown;
61
- /**
62
- * Async variant of {@link getOrCreate}. Deduplicates concurrent creation calls for the same
63
- * binding using an in-flight promise map, preventing double-instantiation under parallel resolves.
64
- */
65
- getOrCreateAsync(binding: Binding<unknown>, createInstance: () => Promise<unknown>): Promise<unknown>;
66
- /**
67
- * Runs synchronous `onDeactivation` hooks for scoped instances owned by this manager.
68
- * Throws if any hook returns a Promise.
69
- */
70
- dispose(): void;
71
- /**
72
- * Runs `onDeactivation` hooks for scoped instances; root also disposes shared singletons.
73
- */
74
- disposeAsync(): Promise<void>;
75
- /**
76
- * Drops a cached singleton/scoped instance for `bindingId` and runs `onDeactivation` synchronously.
77
- */
78
- releaseByBindingId(bindingId: BindingIdentifier): void;
79
- /**
80
- * Drops a cached singleton/scoped instance for `bindingId` and awaits `onDeactivation`.
81
- */
82
- releaseByBindingIdAsync(bindingId: BindingIdentifier): Promise<void>;
83
- /**
84
- * Drops a cached singleton/scoped instance for `binding.id` and runs `onDeactivation` synchronously.
85
- */
86
- releaseBinding(binding: Binding<unknown>): void;
87
- /**
88
- * Drops a cached singleton/scoped instance for `binding.id` and awaits `onDeactivation`.
89
- */
90
- releaseBindingAsync(binding: Binding<unknown>): Promise<void>;
91
- /**
92
- * Removes a single entry from `store`, runs `onDeactivation` synchronously, then calls
93
- * `@preDestroy`. Throws {@link InternalError} if the handler returns a Promise.
94
- */
95
- private releaseFromStore;
96
- /**
97
- * Async counterpart of {@link releaseFromStore}: awaits `onDeactivation` then `@preDestroy`.
98
- */
99
- private releaseFromStoreAsync;
100
- /**
101
- * Iterates all entries in `store`, clears each one, runs `onDeactivation` + `@preDestroy`
102
- * synchronously. Throws {@link InternalError} if any handler returns a Promise.
103
- */
104
- private disposeMap;
105
- /**
106
- * Async counterpart of {@link disposeMap}: clears the store first, then runs all
107
- * deactivation hooks; collects errors and rethrows as `AggregateError` when multiple fail.
108
- */
109
- private disposeMapAsync;
5
+ private readonly _singletons;
6
+ private readonly _inflight;
7
+ private readonly _scoped;
8
+ readonly isChild: boolean;
9
+ constructor(isChild?: boolean);
10
+ hasSingleton(id: BindingIdentifier): boolean;
11
+ getSingleton<Value>(id: BindingIdentifier): Value;
12
+ setSingleton(id: BindingIdentifier, instance: unknown): void;
13
+ deleteSingleton(id: BindingIdentifier): boolean;
14
+ getAllSingletons(): ReadonlyMap<BindingIdentifier, unknown>;
15
+ getInflight(id: BindingIdentifier): Promise<unknown> | undefined;
16
+ setInflight(id: BindingIdentifier, p: Promise<unknown>): void;
17
+ clearInflight(id: BindingIdentifier): void;
18
+ hasScoped(id: BindingIdentifier): boolean;
19
+ getScoped<Value>(id: BindingIdentifier): Value;
20
+ setScoped(id: BindingIdentifier, instance: unknown): void;
21
+ getAllScoped(): ReadonlyMap<BindingIdentifier, unknown>;
22
+ clearAll(): void;
110
23
  }
111
24
  //#endregion
112
25
  export { ScopeManager };
package/dist/scope.mjs CHANGED
@@ -1,213 +1,54 @@
1
- import { InternalError } from "./errors.mjs";
2
- import { isPromiseLike, runPreDestroy, runPreDestroyAsync } from "./lifecycle.mjs";
1
+ import { MissingScopeContextError } from "./errors.mjs";
3
2
  //#region src/scope.ts
4
- /**
5
- * Caches singleton and scoped instances, deduplicates concurrent async creation, and runs
6
- * deactivation hooks (`onDeactivation`, `@preDestroy`) on disposal.
7
- *
8
- * A root scope manager owns both singleton and scoped caches. A child scope manager (created
9
- * via {@link createChildScope}) shares the parent's singleton cache but receives a fresh scoped
10
- * cache — singletons are shared across the hierarchy, scoped instances are isolated per child.
11
- *
12
- * Invariant: `ownsSingletonDisposal` is `true` only for the root. When a child disposes, only
13
- * its scoped bindings are deactivated; singletons remain alive until the root disposes.
14
- */
15
- var ScopeManager = class ScopeManager {
16
- /**
17
- * Cached singleton instances: `bindingId → { binding, instance }`.
18
- */
19
- singletonCache;
20
- /**
21
- * Cached scoped instances for this container level: `bindingId → { binding, instance }`.
22
- */
23
- scopedCache;
24
- /**
25
- * True only for the root scope manager. Controls whether {@link dispose} / {@link disposeAsync}
26
- * also drain the shared singleton cache; child scopes leave singleton disposal to the root.
27
- */
28
- ownsSingletonDisposal;
29
- /**
30
- * In-flight async singleton creation promises.
31
- * Guards against double-instantiation when multiple `resolveAsync` calls for the same
32
- * singleton binding overlap before the first one settles.
33
- */
34
- singletonPendingPromises;
35
- /**
36
- * In-flight async scoped creation promises (same deduplication role as
37
- * {@link singletonPendingPromises} but for scoped bindings).
38
- */
39
- scopedPendingPromises;
40
- /**
41
- * Internal constructor for root/child scope managers.
42
- * Prefer {@link createRoot} and {@link createChildScope}.
43
- */
44
- constructor(singletonCache, scopedCache, ownsSingletonDisposal, singletonPendingPromises, scopedPendingPromises) {
45
- this.singletonCache = singletonCache;
46
- this.scopedCache = scopedCache;
47
- this.ownsSingletonDisposal = ownsSingletonDisposal;
48
- this.singletonPendingPromises = singletonPendingPromises;
49
- this.scopedPendingPromises = scopedPendingPromises;
3
+ var ScopeManager = class {
4
+ _singletons = /* @__PURE__ */ new Map();
5
+ _inflight = /* @__PURE__ */ new Map();
6
+ _scoped = /* @__PURE__ */ new Map();
7
+ isChild;
8
+ constructor(isChild = false) {
9
+ this.isChild = isChild;
50
10
  }
51
- /**
52
- * Creates a root scope manager that owns both the singleton cache and scoped cache.
53
- */
54
- static createRoot() {
55
- return new ScopeManager(/* @__PURE__ */ new Map(), /* @__PURE__ */ new Map(), true, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Map());
11
+ hasSingleton(id) {
12
+ return this._singletons.has(id);
56
13
  }
57
- /**
58
- * Shares the parent singleton cache; receives a fresh scoped cache (for child containers).
59
- */
60
- createChildScope() {
61
- return new ScopeManager(this.singletonCache, /* @__PURE__ */ new Map(), false, this.singletonPendingPromises, /* @__PURE__ */ new Map());
14
+ getSingleton(id) {
15
+ return this._singletons.get(id);
62
16
  }
63
- /**
64
- * Whether a singleton/scoped binding currently has a cached instance (always false for transient).
65
- */
66
- isBindingCached(binding) {
67
- if (binding.scope === "transient") return false;
68
- return (binding.scope === "singleton" ? this.singletonCache : this.scopedCache).has(binding.id);
17
+ setSingleton(id, instance) {
18
+ this._singletons.set(id, instance);
69
19
  }
70
- /**
71
- * Returns the cached instance for singleton/scoped bindings, or calls `createInstance` on first access.
72
- */
73
- getOrCreate(binding, createInstance) {
74
- if (binding.scope === "transient") return createInstance();
75
- const cache = binding.scope === "singleton" ? this.singletonCache : this.scopedCache;
76
- const cached = cache.get(binding.id);
77
- if (cached !== void 0) return cached.instance;
78
- const instance = createInstance();
79
- cache.set(binding.id, {
80
- binding,
81
- instance
82
- });
83
- return instance;
20
+ deleteSingleton(id) {
21
+ return this._singletons.delete(id);
84
22
  }
85
- /**
86
- * Async variant of {@link getOrCreate}. Deduplicates concurrent creation calls for the same
87
- * binding using an in-flight promise map, preventing double-instantiation under parallel resolves.
88
- */
89
- async getOrCreateAsync(binding, createInstance) {
90
- if (binding.scope === "transient") return createInstance();
91
- const cache = binding.scope === "singleton" ? this.singletonCache : this.scopedCache;
92
- const pendingCreationMap = binding.scope === "singleton" ? this.singletonPendingPromises : this.scopedPendingPromises;
93
- const cached = cache.get(binding.id);
94
- if (cached !== void 0) return cached.instance;
95
- let pendingCreation = pendingCreationMap.get(binding.id);
96
- if (pendingCreation === void 0) {
97
- pendingCreation = (async () => {
98
- try {
99
- const instance = await createInstance();
100
- cache.set(binding.id, {
101
- binding,
102
- instance
103
- });
104
- return instance;
105
- } finally {
106
- pendingCreationMap.delete(binding.id);
107
- }
108
- })();
109
- pendingCreationMap.set(binding.id, pendingCreation);
110
- }
111
- return pendingCreation;
23
+ getAllSingletons() {
24
+ return this._singletons;
112
25
  }
113
- /**
114
- * Runs synchronous `onDeactivation` hooks for scoped instances owned by this manager.
115
- * Throws if any hook returns a Promise.
116
- */
117
- dispose() {
118
- this.disposeMap(this.scopedCache);
119
- if (this.ownsSingletonDisposal) this.disposeMap(this.singletonCache);
26
+ getInflight(id) {
27
+ return this._inflight.get(id);
120
28
  }
121
- /**
122
- * Runs `onDeactivation` hooks for scoped instances; root also disposes shared singletons.
123
- */
124
- async disposeAsync() {
125
- await this.disposeMapAsync(this.scopedCache);
126
- if (this.ownsSingletonDisposal) await this.disposeMapAsync(this.singletonCache);
29
+ setInflight(id, p) {
30
+ this._inflight.set(id, p);
127
31
  }
128
- /**
129
- * Drops a cached singleton/scoped instance for `bindingId` and runs `onDeactivation` synchronously.
130
- */
131
- releaseByBindingId(bindingId) {
132
- this.releaseFromStore(this.singletonCache, bindingId);
133
- this.releaseFromStore(this.scopedCache, bindingId);
32
+ clearInflight(id) {
33
+ this._inflight.delete(id);
134
34
  }
135
- /**
136
- * Drops a cached singleton/scoped instance for `bindingId` and awaits `onDeactivation`.
137
- */
138
- async releaseByBindingIdAsync(bindingId) {
139
- await this.releaseFromStoreAsync(this.singletonCache, bindingId);
140
- await this.releaseFromStoreAsync(this.scopedCache, bindingId);
35
+ hasScoped(id) {
36
+ return this._scoped.has(id);
141
37
  }
142
- /**
143
- * Drops a cached singleton/scoped instance for `binding.id` and runs `onDeactivation` synchronously.
144
- */
145
- releaseBinding(binding) {
146
- this.releaseByBindingId(binding.id);
38
+ getScoped(id) {
39
+ return this._scoped.get(id);
147
40
  }
148
- /**
149
- * Drops a cached singleton/scoped instance for `binding.id` and awaits `onDeactivation`.
150
- */
151
- async releaseBindingAsync(binding) {
152
- await this.releaseByBindingIdAsync(binding.id);
41
+ setScoped(id, instance) {
42
+ if (!this.isChild) throw new MissingScopeContextError("(unknown)");
43
+ this._scoped.set(id, instance);
153
44
  }
154
- /**
155
- * Removes a single entry from `store`, runs `onDeactivation` synchronously, then calls
156
- * `@preDestroy`. Throws {@link InternalError} if the handler returns a Promise.
157
- */
158
- releaseFromStore(store, bindingId) {
159
- const entry = store.get(bindingId);
160
- if (entry === void 0) return;
161
- store.delete(bindingId);
162
- const handler = entry.binding.onDeactivation;
163
- if (handler !== void 0) {
164
- if (isPromiseLike(handler(entry.instance))) throw new InternalError("onDeactivation returned a Promise during synchronous scope release; use releaseBindingAsync() or unloadAsync().");
165
- }
166
- if (entry.binding.kind === "class") runPreDestroy(entry.binding.implementationClass, entry.instance);
45
+ getAllScoped() {
46
+ return this._scoped;
167
47
  }
168
- /**
169
- * Async counterpart of {@link releaseFromStore}: awaits `onDeactivation` then `@preDestroy`.
170
- */
171
- async releaseFromStoreAsync(store, bindingId) {
172
- const entry = store.get(bindingId);
173
- if (entry === void 0) return;
174
- store.delete(bindingId);
175
- const handler = entry.binding.onDeactivation;
176
- if (handler !== void 0) await handler(entry.instance);
177
- if (entry.binding.kind === "class") await runPreDestroyAsync(entry.binding.implementationClass, entry.instance);
178
- }
179
- /**
180
- * Iterates all entries in `store`, clears each one, runs `onDeactivation` + `@preDestroy`
181
- * synchronously. Throws {@link InternalError} if any handler returns a Promise.
182
- */
183
- disposeMap(store) {
184
- const entries = [...store.values()];
185
- store.clear();
186
- for (const entry of entries) {
187
- const handler = entry.binding.onDeactivation;
188
- if (handler !== void 0) {
189
- if (isPromiseLike(handler(entry.instance))) throw new InternalError("onDeactivation returned a Promise; use disposeAsync() instead of dispose().");
190
- }
191
- if (entry.binding.kind === "class") runPreDestroy(entry.binding.implementationClass, entry.instance);
192
- }
193
- }
194
- /**
195
- * Async counterpart of {@link disposeMap}: clears the store first, then runs all
196
- * deactivation hooks; collects errors and rethrows as `AggregateError` when multiple fail.
197
- */
198
- async disposeMapAsync(store) {
199
- const entries = [...store.values()];
200
- store.clear();
201
- const errors = [];
202
- for (const entry of entries) try {
203
- const handler = entry.binding.onDeactivation;
204
- if (handler !== void 0) await handler(entry.instance);
205
- if (entry.binding.kind === "class") await runPreDestroyAsync(entry.binding.implementationClass, entry.instance);
206
- } catch (error) {
207
- errors.push(error);
208
- }
209
- if (errors.length === 1) throw errors[0];
210
- if (errors.length > 1) throw new AggregateError(errors, "disposeAsync: multiple deactivation handlers failed");
48
+ clearAll() {
49
+ this._singletons.clear();
50
+ this._inflight.clear();
51
+ this._scoped.clear();
211
52
  }
212
53
  };
213
54
  //#endregion
package/dist/token.d.mts CHANGED
@@ -1,27 +1,13 @@
1
+ import { Constructor } from "./constructor-type.mjs";
2
+
1
3
  //#region src/token.d.ts
2
4
  declare const TOKEN_BRAND: unique symbol;
3
- /**
4
- * Opaque injection key branded by `Value` so distinct tokens do not unify in the type system.
5
- * Registry keys rely on **reference equality** — always reuse the same `token()` result as the key.
6
- */
7
- type Token<Value> = {
8
- readonly [TOKEN_BRAND]: Value;
5
+ interface Token<Value> {
9
6
  readonly name: string;
10
- };
11
- /**
12
- * Extracts the value type carried by a {@link Token} or the instance type of a {@link Constructor}.
13
- * Falls through to `never` for types that are neither a token nor a constructor.
14
- */
15
- type TokenValue<Type> = Type extends Token<infer Value> ? Value : Type extends (abstract new (...args: never[]) => infer Value) ? Value : never;
16
- /**
17
- * Creates a frozen, type-safe injection token identified by `name`.
18
- *
19
- * The returned object is `Object.freeze`-d; `name` is used only for debugging and error
20
- * messages — binding lookup relies on **reference equality** of the token object.
21
- * Store the return value in a module-level `const` and import it wherever needed.
22
- *
23
- * @param name - Human-readable label (appears in error messages, graph output, and debug snapshots).
24
- */
7
+ readonly [TOKEN_BRAND]: Value;
8
+ }
25
9
  declare function token<Value>(name: string): Token<Value>;
10
+ declare function tokenName(t: Token<unknown> | Constructor): string;
11
+ declare function isToken(value: unknown): value is Token<unknown>;
26
12
  //#endregion
27
- export { Token, TokenValue, token };
13
+ export { Token, isToken, token, tokenName };
package/dist/token.mjs CHANGED
@@ -1,15 +1,13 @@
1
1
  //#region src/token.ts
2
- /**
3
- * Creates a frozen, type-safe injection token identified by `name`.
4
- *
5
- * The returned object is `Object.freeze`-d; `name` is used only for debugging and error
6
- * messages — binding lookup relies on **reference equality** of the token object.
7
- * Store the return value in a module-level `const` and import it wherever needed.
8
- *
9
- * @param name - Human-readable label (appears in error messages, graph output, and debug snapshots).
10
- */
11
2
  function token(name) {
12
- return Object.freeze({ name });
3
+ return { name };
4
+ }
5
+ function tokenName(t) {
6
+ if (typeof t === "function") return t.name;
7
+ return t.name;
8
+ }
9
+ function isToken(value) {
10
+ return typeof value === "object" && value !== null && "name" in value && typeof value["name"] === "string" && typeof value !== "function";
13
11
  }
14
12
  //#endregion
15
- export { token };
13
+ export { isToken, token, tokenName };
@@ -0,0 +1,48 @@
1
+ import { Constructor } from "./constructor-type.mjs";
2
+ import { Token } from "./token.mjs";
3
+
4
+ //#region src/types.d.ts
5
+ /** Token or class constructor used as a binding / injection / resolve key. */
6
+ type DependencyKey = Token<unknown> | Constructor;
7
+ type BindingScope = "singleton" | "transient" | "scoped";
8
+ declare const BINDING_ID_BRAND: unique symbol;
9
+ type BindingIdentifier = string & {
10
+ readonly [BINDING_ID_BRAND]: true;
11
+ };
12
+ type BindingKind = "class" | "dynamic" | "dynamic-async" | "resolved" | "resolved-async" | "constant" | "alias";
13
+ type ActivationHandler<Value> = (ctx: ResolutionContext, instance: Value) => Value | Promise<Value>;
14
+ type DeactivationHandler<Value> = (instance: Value) => void | Promise<void>;
15
+ interface ResolveOptions {
16
+ name?: string;
17
+ tag?: readonly [tag: string, value: unknown];
18
+ tags?: ReadonlyArray<readonly [tag: string, value: unknown]>;
19
+ }
20
+ interface MaterializationFrame {
21
+ readonly tokenName: string;
22
+ readonly scope: BindingScope;
23
+ readonly bindingId: BindingIdentifier;
24
+ readonly kind: BindingKind;
25
+ readonly slot: {
26
+ readonly name: string | undefined;
27
+ readonly tags: ReadonlyArray<readonly [tag: string, value: unknown]>;
28
+ };
29
+ }
30
+ interface ConstraintContext {
31
+ readonly resolutionPath: readonly string[];
32
+ readonly materializationStack: readonly MaterializationFrame[];
33
+ readonly parent: MaterializationFrame | undefined;
34
+ readonly ancestors: readonly MaterializationFrame[];
35
+ readonly currentResolveHint: ResolveOptions | undefined;
36
+ }
37
+ interface ResolutionContext {
38
+ resolve<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value;
39
+ resolveAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value>;
40
+ resolveOptional<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value | undefined;
41
+ resolveOptionalAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value | undefined>;
42
+ resolveAll<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value[];
43
+ resolveAllAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value[]>;
44
+ readonly graph: ConstraintContext;
45
+ }
46
+ type TokenValue<Type> = Type extends Token<infer Value> ? Value : Type extends Constructor<infer Value> ? Value : never;
47
+ //#endregion
48
+ export { ActivationHandler, BindingIdentifier, BindingKind, BindingScope, ConstraintContext, type Constructor, DeactivationHandler, DependencyKey, MaterializationFrame, ResolutionContext, ResolveOptions, TokenValue };
package/dist/types.mjs ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codefast/di",
3
- "version": "0.3.14-canary.1",
3
+ "version": "0.3.14",
4
4
  "description": "Lightweight dependency injection primitives for Codefast",
5
5
  "keywords": [
6
6
  "codefast",
@@ -28,6 +28,13 @@
28
28
  "module": "./dist/index.mjs",
29
29
  "types": "./dist/index.d.mts",
30
30
  "imports": {
31
+ "#/tests/*": [
32
+ "./tests/*",
33
+ "./tests/*.ts",
34
+ "./tests/*.tsx",
35
+ "./tests/*/index.ts",
36
+ "./tests/*/index.tsx"
37
+ ],
31
38
  "#/*": [
32
39
  "./src/*",
33
40
  "./src/*.ts",
@@ -45,6 +52,10 @@
45
52
  "types": "./dist/binding.d.mts",
46
53
  "import": "./dist/binding.mjs"
47
54
  },
55
+ "./binding-scope": {
56
+ "types": "./dist/binding-scope.d.mts",
57
+ "import": "./dist/binding-scope.mjs"
58
+ },
48
59
  "./binding-select": {
49
60
  "types": "./dist/binding-select.d.mts",
50
61
  "import": "./dist/binding-select.mjs"
@@ -53,6 +64,10 @@
53
64
  "types": "./dist/constraints.d.mts",
54
65
  "import": "./dist/constraints.mjs"
55
66
  },
67
+ "./constructor-type": {
68
+ "types": "./dist/constructor-type.d.mts",
69
+ "import": "./dist/constructor-type.mjs"
70
+ },
56
71
  "./container": {
57
72
  "types": "./dist/container.d.mts",
58
73
  "import": "./dist/container.mjs"
@@ -109,14 +124,14 @@
109
124
  "types": "./dist/metadata/metadata-keys.d.mts",
110
125
  "import": "./dist/metadata/metadata-keys.mjs"
111
126
  },
127
+ "./metadata/metadata-reader-token": {
128
+ "types": "./dist/metadata/metadata-reader-token.d.mts",
129
+ "import": "./dist/metadata/metadata-reader-token.mjs"
130
+ },
112
131
  "./metadata/metadata-types": {
113
132
  "types": "./dist/metadata/metadata-types.d.mts",
114
133
  "import": "./dist/metadata/metadata-types.mjs"
115
134
  },
116
- "./metadata/param-registry": {
117
- "types": "./dist/metadata/param-registry.d.mts",
118
- "import": "./dist/metadata/param-registry.mjs"
119
- },
120
135
  "./metadata/symbol-metadata-reader": {
121
136
  "types": "./dist/metadata/symbol-metadata-reader.d.mts",
122
137
  "import": "./dist/metadata/symbol-metadata-reader.mjs"
@@ -129,6 +144,10 @@
129
144
  "types": "./dist/registry.d.mts",
130
145
  "import": "./dist/registry.mjs"
131
146
  },
147
+ "./resolve-options": {
148
+ "types": "./dist/resolve-options.d.mts",
149
+ "import": "./dist/resolve-options.mjs"
150
+ },
132
151
  "./resolver": {
133
152
  "types": "./dist/resolver.d.mts",
134
153
  "import": "./dist/resolver.mjs"
@@ -137,14 +156,14 @@
137
156
  "types": "./dist/scope.d.mts",
138
157
  "import": "./dist/scope.mjs"
139
158
  },
140
- "./scope-validation": {
141
- "types": "./dist/scope-validation.d.mts",
142
- "import": "./dist/scope-validation.mjs"
143
- },
144
159
  "./token": {
145
160
  "types": "./dist/token.d.mts",
146
161
  "import": "./dist/token.mjs"
147
162
  },
163
+ "./types": {
164
+ "types": "./dist/types.d.mts",
165
+ "import": "./dist/types.mjs"
166
+ },
148
167
  "./package.json": "./package.json"
149
168
  },
150
169
  "publishConfig": {
@@ -152,12 +171,13 @@
152
171
  },
153
172
  "devDependencies": {
154
173
  "@types/node": "^25.6.0",
155
- "@typescript/native-preview": "7.0.0-dev.20260411.1",
156
- "@vitest/coverage-v8": "^4.1.4",
157
- "typescript": "^6.0.2",
174
+ "@typescript/native-preview": "7.0.0-dev.20260422.1",
175
+ "@vitest/coverage-v8": "^4.1.5",
176
+ "expect-type": "^1.3.0",
177
+ "typescript": "^6.0.3",
158
178
  "unplugin-swc": "^1.5.9",
159
- "vitest": "^4.1.4",
160
- "@codefast/typescript-config": "0.3.14-canary.1"
179
+ "vitest": "^4.1.5",
180
+ "@codefast/typescript-config": "0.3.14"
161
181
  },
162
182
  "engines": {
163
183
  "node": ">=22.0.0"
@@ -166,6 +186,8 @@
166
186
  "build": "tsdown",
167
187
  "check-types": "tsgo --noEmit",
168
188
  "clean": "rm -rf dist",
189
+ "examples": "for file in examples/*/*.ts; do echo \"=== Running $file ===\"; tsx \"$file\"; echo \"\n\" || exit 1; done",
190
+ "bench": "vitest bench --run",
169
191
  "test": "vitest run",
170
192
  "test:coverage": "vitest run --coverage",
171
193
  "test:watch": "vitest"
@@ -1,16 +0,0 @@
1
- import { Constructor } from "../binding.mjs";
2
- import { ParamMetadata } from "./metadata-types.mjs";
3
-
4
- //#region src/metadata/param-registry.d.ts
5
- /**
6
- * Returns the pending `ParamMetadata` map for `implementationClass`, creating it on first access.
7
- * Used by legacy parameter decorators that fire before the class decorator runs.
8
- */
9
- declare function getOrCreatePendingMap(implementationClass: Constructor<unknown>): Map<number, ParamMetadata>;
10
- /**
11
- * Removes and returns the pending map for `implementationClass` (transfer of ownership).
12
- * Returns `undefined` if no pending entries exist.
13
- */
14
- declare function takePendingMap(implementationClass: Constructor<unknown>): Map<number, ParamMetadata> | undefined;
15
- //#endregion
16
- export { getOrCreatePendingMap, takePendingMap };
@@ -1,31 +0,0 @@
1
- //#region src/metadata/param-registry.ts
2
- /**
3
- * WeakMap keyed by constructor → pending parameter metadata.
4
- * Entries are populated by legacy parameter decorators that fire *before* the
5
- * `@injectable()` class decorator runs, and consumed (via {@link takePendingMap})
6
- * by the class decorator to merge into the final {@link ConstructorMetadata}.
7
- */
8
- const pendingByConstructor = /* @__PURE__ */ new WeakMap();
9
- /**
10
- * Returns the pending `ParamMetadata` map for `implementationClass`, creating it on first access.
11
- * Used by legacy parameter decorators that fire before the class decorator runs.
12
- */
13
- function getOrCreatePendingMap(implementationClass) {
14
- let map = pendingByConstructor.get(implementationClass);
15
- if (!map) {
16
- map = /* @__PURE__ */ new Map();
17
- pendingByConstructor.set(implementationClass, map);
18
- }
19
- return map;
20
- }
21
- /**
22
- * Removes and returns the pending map for `implementationClass` (transfer of ownership).
23
- * Returns `undefined` if no pending entries exist.
24
- */
25
- function takePendingMap(implementationClass) {
26
- const map = pendingByConstructor.get(implementationClass);
27
- if (map) pendingByConstructor.delete(implementationClass);
28
- return map;
29
- }
30
- //#endregion
31
- export { getOrCreatePendingMap, takePendingMap };