@codefast/di 0.3.14-canary.0 → 0.3.14-canary.2

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 (66) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +54 -29
  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 -327
  8. package/dist/binding.mjs +19 -324
  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 +44 -128
  14. package/dist/container.mjs +664 -433
  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 +69 -188
  26. package/dist/errors.mjs +92 -219
  27. package/dist/graph-adapters/cytoscape.d.mts +24 -0
  28. package/dist/graph-adapters/cytoscape.mjs +23 -0
  29. package/dist/graph-adapters/dot.d.mts +6 -0
  30. package/dist/graph-adapters/dot.mjs +17 -0
  31. package/dist/graph-adapters/reactflow.d.mts +29 -0
  32. package/dist/graph-adapters/reactflow.mjs +29 -0
  33. package/dist/graph-adapters/types.d.mts +2 -0
  34. package/dist/graph-adapters/types.mjs +1 -0
  35. package/dist/index.d.mts +16 -9
  36. package/dist/index.mjs +8 -5
  37. package/dist/inspector.d.mts +34 -95
  38. package/dist/inspector.mjs +57 -256
  39. package/dist/lifecycle.d.mts +20 -53
  40. package/dist/lifecycle.mjs +129 -99
  41. package/dist/metadata/metadata-keys.d.mts +9 -26
  42. package/dist/metadata/metadata-keys.mjs +7 -28
  43. package/dist/metadata/metadata-reader-token.d.mts +7 -0
  44. package/dist/metadata/metadata-reader-token.mjs +5 -0
  45. package/dist/metadata/metadata-types.d.mts +22 -71
  46. package/dist/metadata/symbol-metadata-reader.d.mts +10 -26
  47. package/dist/metadata/symbol-metadata-reader.mjs +32 -45
  48. package/dist/module.d.mts +30 -84
  49. package/dist/module.mjs +26 -72
  50. package/dist/registry.d.mts +32 -63
  51. package/dist/registry.mjs +131 -82
  52. package/dist/resolve-options.d.mts +18 -0
  53. package/dist/resolve-options.mjs +22 -0
  54. package/dist/resolver.d.mts +67 -190
  55. package/dist/resolver.mjs +715 -424
  56. package/dist/scope.d.mts +19 -102
  57. package/dist/scope.mjs +37 -192
  58. package/dist/token.d.mts +8 -22
  59. package/dist/token.mjs +9 -11
  60. package/dist/types.d.mts +48 -0
  61. package/dist/types.mjs +1 -0
  62. package/package.json +52 -14
  63. package/dist/metadata/param-registry.d.mts +0 -16
  64. package/dist/metadata/param-registry.mjs +0 -31
  65. package/dist/scope-validation.d.mts +0 -21
  66. package/dist/scope-validation.mjs +0 -35
package/dist/scope.d.mts CHANGED
@@ -1,108 +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
- private constructor();
41
- /**
42
- * Creates a root scope manager that owns both the singleton cache and scoped cache.
43
- */
44
- static createRoot(): ScopeManager;
45
- /**
46
- * Shares the parent singleton cache; receives a fresh scoped cache (for child containers).
47
- */
48
- createChildScope(): ScopeManager;
49
- /**
50
- * Whether a singleton/scoped binding currently has a cached instance (always false for transient).
51
- */
52
- isBindingCached(binding: Binding<unknown>): boolean;
53
- /**
54
- * Returns the cached instance for singleton/scoped bindings, or calls `createInstance` on first access.
55
- */
56
- getOrCreate(binding: Binding<unknown>, createInstance: () => unknown): unknown;
57
- /**
58
- * Async variant of {@link getOrCreate}. Deduplicates concurrent creation calls for the same
59
- * binding using an in-flight promise map, preventing double-instantiation under parallel resolves.
60
- */
61
- getOrCreateAsync(binding: Binding<unknown>, createInstance: () => Promise<unknown>): Promise<unknown>;
62
- /**
63
- * Runs synchronous `onDeactivation` hooks for scoped instances owned by this manager.
64
- * Throws if any hook returns a Promise.
65
- */
66
- dispose(): void;
67
- /**
68
- * Runs `onDeactivation` hooks for scoped instances; root also disposes shared singletons.
69
- */
70
- disposeAsync(): Promise<void>;
71
- /**
72
- * Drops a cached singleton/scoped instance for `bindingId` and runs `onDeactivation` synchronously.
73
- */
74
- releaseByBindingId(bindingId: BindingIdentifier): void;
75
- /**
76
- * Drops a cached singleton/scoped instance for `bindingId` and awaits `onDeactivation`.
77
- */
78
- releaseByBindingIdAsync(bindingId: BindingIdentifier): Promise<void>;
79
- /**
80
- * Drops a cached singleton/scoped instance for `binding.id` and runs `onDeactivation` synchronously.
81
- */
82
- releaseBinding(binding: Binding<unknown>): void;
83
- /**
84
- * Drops a cached singleton/scoped instance for `binding.id` and awaits `onDeactivation`.
85
- */
86
- releaseBindingAsync(binding: Binding<unknown>): Promise<void>;
87
- /**
88
- * Removes a single entry from `store`, runs `onDeactivation` synchronously, then calls
89
- * `@preDestroy`. Throws {@link InternalError} if the handler returns a Promise.
90
- */
91
- private releaseFromStore;
92
- /**
93
- * Async counterpart of {@link releaseFromStore}: awaits `onDeactivation` then `@preDestroy`.
94
- */
95
- private releaseFromStoreAsync;
96
- /**
97
- * Iterates all entries in `store`, clears each one, runs `onDeactivation` + `@preDestroy`
98
- * synchronously. Throws {@link InternalError} if any handler returns a Promise.
99
- */
100
- private disposeMap;
101
- /**
102
- * Async counterpart of {@link disposeMap}: clears the store first, then runs all
103
- * deactivation hooks; collects errors and rethrows as `AggregateError` when multiple fail.
104
- */
105
- 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;
106
23
  }
107
24
  //#endregion
108
25
  export { ScopeManager };
package/dist/scope.mjs CHANGED
@@ -1,209 +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
- constructor(singletonCache, scopedCache, ownsSingletonDisposal, singletonPendingPromises, scopedPendingPromises) {
41
- this.singletonCache = singletonCache;
42
- this.scopedCache = scopedCache;
43
- this.ownsSingletonDisposal = ownsSingletonDisposal;
44
- this.singletonPendingPromises = singletonPendingPromises;
45
- 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;
46
10
  }
47
- /**
48
- * Creates a root scope manager that owns both the singleton cache and scoped cache.
49
- */
50
- static createRoot() {
51
- 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);
52
13
  }
53
- /**
54
- * Shares the parent singleton cache; receives a fresh scoped cache (for child containers).
55
- */
56
- createChildScope() {
57
- return new ScopeManager(this.singletonCache, /* @__PURE__ */ new Map(), false, this.singletonPendingPromises, /* @__PURE__ */ new Map());
14
+ getSingleton(id) {
15
+ return this._singletons.get(id);
58
16
  }
59
- /**
60
- * Whether a singleton/scoped binding currently has a cached instance (always false for transient).
61
- */
62
- isBindingCached(binding) {
63
- if (binding.scope === "transient") return false;
64
- return (binding.scope === "singleton" ? this.singletonCache : this.scopedCache).has(binding.id);
17
+ setSingleton(id, instance) {
18
+ this._singletons.set(id, instance);
65
19
  }
66
- /**
67
- * Returns the cached instance for singleton/scoped bindings, or calls `createInstance` on first access.
68
- */
69
- getOrCreate(binding, createInstance) {
70
- if (binding.scope === "transient") return createInstance();
71
- const cache = binding.scope === "singleton" ? this.singletonCache : this.scopedCache;
72
- const cached = cache.get(binding.id);
73
- if (cached !== void 0) return cached.instance;
74
- const instance = createInstance();
75
- cache.set(binding.id, {
76
- binding,
77
- instance
78
- });
79
- return instance;
20
+ deleteSingleton(id) {
21
+ return this._singletons.delete(id);
80
22
  }
81
- /**
82
- * Async variant of {@link getOrCreate}. Deduplicates concurrent creation calls for the same
83
- * binding using an in-flight promise map, preventing double-instantiation under parallel resolves.
84
- */
85
- async getOrCreateAsync(binding, createInstance) {
86
- if (binding.scope === "transient") return createInstance();
87
- const cache = binding.scope === "singleton" ? this.singletonCache : this.scopedCache;
88
- const pendingCreationMap = binding.scope === "singleton" ? this.singletonPendingPromises : this.scopedPendingPromises;
89
- const cached = cache.get(binding.id);
90
- if (cached !== void 0) return cached.instance;
91
- let pendingCreation = pendingCreationMap.get(binding.id);
92
- if (pendingCreation === void 0) {
93
- pendingCreation = (async () => {
94
- try {
95
- const instance = await createInstance();
96
- cache.set(binding.id, {
97
- binding,
98
- instance
99
- });
100
- return instance;
101
- } finally {
102
- pendingCreationMap.delete(binding.id);
103
- }
104
- })();
105
- pendingCreationMap.set(binding.id, pendingCreation);
106
- }
107
- return pendingCreation;
23
+ getAllSingletons() {
24
+ return this._singletons;
108
25
  }
109
- /**
110
- * Runs synchronous `onDeactivation` hooks for scoped instances owned by this manager.
111
- * Throws if any hook returns a Promise.
112
- */
113
- dispose() {
114
- this.disposeMap(this.scopedCache);
115
- if (this.ownsSingletonDisposal) this.disposeMap(this.singletonCache);
26
+ getInflight(id) {
27
+ return this._inflight.get(id);
116
28
  }
117
- /**
118
- * Runs `onDeactivation` hooks for scoped instances; root also disposes shared singletons.
119
- */
120
- async disposeAsync() {
121
- await this.disposeMapAsync(this.scopedCache);
122
- if (this.ownsSingletonDisposal) await this.disposeMapAsync(this.singletonCache);
29
+ setInflight(id, p) {
30
+ this._inflight.set(id, p);
123
31
  }
124
- /**
125
- * Drops a cached singleton/scoped instance for `bindingId` and runs `onDeactivation` synchronously.
126
- */
127
- releaseByBindingId(bindingId) {
128
- this.releaseFromStore(this.singletonCache, bindingId);
129
- this.releaseFromStore(this.scopedCache, bindingId);
32
+ clearInflight(id) {
33
+ this._inflight.delete(id);
130
34
  }
131
- /**
132
- * Drops a cached singleton/scoped instance for `bindingId` and awaits `onDeactivation`.
133
- */
134
- async releaseByBindingIdAsync(bindingId) {
135
- await this.releaseFromStoreAsync(this.singletonCache, bindingId);
136
- await this.releaseFromStoreAsync(this.scopedCache, bindingId);
35
+ hasScoped(id) {
36
+ return this._scoped.has(id);
137
37
  }
138
- /**
139
- * Drops a cached singleton/scoped instance for `binding.id` and runs `onDeactivation` synchronously.
140
- */
141
- releaseBinding(binding) {
142
- this.releaseByBindingId(binding.id);
38
+ getScoped(id) {
39
+ return this._scoped.get(id);
143
40
  }
144
- /**
145
- * Drops a cached singleton/scoped instance for `binding.id` and awaits `onDeactivation`.
146
- */
147
- async releaseBindingAsync(binding) {
148
- await this.releaseByBindingIdAsync(binding.id);
41
+ setScoped(id, instance) {
42
+ if (!this.isChild) throw new MissingScopeContextError("(unknown)");
43
+ this._scoped.set(id, instance);
149
44
  }
150
- /**
151
- * Removes a single entry from `store`, runs `onDeactivation` synchronously, then calls
152
- * `@preDestroy`. Throws {@link InternalError} if the handler returns a Promise.
153
- */
154
- releaseFromStore(store, bindingId) {
155
- const entry = store.get(bindingId);
156
- if (entry === void 0) return;
157
- store.delete(bindingId);
158
- const handler = entry.binding.onDeactivation;
159
- if (handler !== void 0) {
160
- if (isPromiseLike(handler(entry.instance))) throw new InternalError("onDeactivation returned a Promise during synchronous scope release; use releaseBindingAsync() or unloadAsync().");
161
- }
162
- if (entry.binding.kind === "class") runPreDestroy(entry.binding.implementationClass, entry.instance);
45
+ getAllScoped() {
46
+ return this._scoped;
163
47
  }
164
- /**
165
- * Async counterpart of {@link releaseFromStore}: awaits `onDeactivation` then `@preDestroy`.
166
- */
167
- async releaseFromStoreAsync(store, bindingId) {
168
- const entry = store.get(bindingId);
169
- if (entry === void 0) return;
170
- store.delete(bindingId);
171
- const handler = entry.binding.onDeactivation;
172
- if (handler !== void 0) await handler(entry.instance);
173
- if (entry.binding.kind === "class") await runPreDestroyAsync(entry.binding.implementationClass, entry.instance);
174
- }
175
- /**
176
- * Iterates all entries in `store`, clears each one, runs `onDeactivation` + `@preDestroy`
177
- * synchronously. Throws {@link InternalError} if any handler returns a Promise.
178
- */
179
- disposeMap(store) {
180
- const entries = [...store.values()];
181
- store.clear();
182
- for (const entry of entries) {
183
- const handler = entry.binding.onDeactivation;
184
- if (handler !== void 0) {
185
- if (isPromiseLike(handler(entry.instance))) throw new InternalError("onDeactivation returned a Promise; use disposeAsync() instead of dispose().");
186
- }
187
- if (entry.binding.kind === "class") runPreDestroy(entry.binding.implementationClass, entry.instance);
188
- }
189
- }
190
- /**
191
- * Async counterpart of {@link disposeMap}: clears the store first, then runs all
192
- * deactivation hooks; collects errors and rethrows as `AggregateError` when multiple fail.
193
- */
194
- async disposeMapAsync(store) {
195
- const entries = [...store.values()];
196
- store.clear();
197
- const errors = [];
198
- for (const entry of entries) try {
199
- const handler = entry.binding.onDeactivation;
200
- if (handler !== void 0) await handler(entry.instance);
201
- if (entry.binding.kind === "class") await runPreDestroyAsync(entry.binding.implementationClass, entry.instance);
202
- } catch (error) {
203
- errors.push(error);
204
- }
205
- if (errors.length === 1) throw errors[0];
206
- 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();
207
52
  }
208
53
  };
209
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.0",
3
+ "version": "0.3.14-canary.2",
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"
@@ -81,6 +96,22 @@
81
96
  "types": "./dist/errors.d.mts",
82
97
  "import": "./dist/errors.mjs"
83
98
  },
99
+ "./graph-adapters/cytoscape": {
100
+ "types": "./dist/graph-adapters/cytoscape.d.mts",
101
+ "import": "./dist/graph-adapters/cytoscape.mjs"
102
+ },
103
+ "./graph-adapters/dot": {
104
+ "types": "./dist/graph-adapters/dot.d.mts",
105
+ "import": "./dist/graph-adapters/dot.mjs"
106
+ },
107
+ "./graph-adapters/reactflow": {
108
+ "types": "./dist/graph-adapters/reactflow.d.mts",
109
+ "import": "./dist/graph-adapters/reactflow.mjs"
110
+ },
111
+ "./graph-adapters/types": {
112
+ "types": "./dist/graph-adapters/types.d.mts",
113
+ "import": "./dist/graph-adapters/types.mjs"
114
+ },
84
115
  "./inspector": {
85
116
  "types": "./dist/inspector.d.mts",
86
117
  "import": "./dist/inspector.mjs"
@@ -93,14 +124,14 @@
93
124
  "types": "./dist/metadata/metadata-keys.d.mts",
94
125
  "import": "./dist/metadata/metadata-keys.mjs"
95
126
  },
127
+ "./metadata/metadata-reader-token": {
128
+ "types": "./dist/metadata/metadata-reader-token.d.mts",
129
+ "import": "./dist/metadata/metadata-reader-token.mjs"
130
+ },
96
131
  "./metadata/metadata-types": {
97
132
  "types": "./dist/metadata/metadata-types.d.mts",
98
133
  "import": "./dist/metadata/metadata-types.mjs"
99
134
  },
100
- "./metadata/param-registry": {
101
- "types": "./dist/metadata/param-registry.d.mts",
102
- "import": "./dist/metadata/param-registry.mjs"
103
- },
104
135
  "./metadata/symbol-metadata-reader": {
105
136
  "types": "./dist/metadata/symbol-metadata-reader.d.mts",
106
137
  "import": "./dist/metadata/symbol-metadata-reader.mjs"
@@ -113,6 +144,10 @@
113
144
  "types": "./dist/registry.d.mts",
114
145
  "import": "./dist/registry.mjs"
115
146
  },
147
+ "./resolve-options": {
148
+ "types": "./dist/resolve-options.d.mts",
149
+ "import": "./dist/resolve-options.mjs"
150
+ },
116
151
  "./resolver": {
117
152
  "types": "./dist/resolver.d.mts",
118
153
  "import": "./dist/resolver.mjs"
@@ -121,14 +156,14 @@
121
156
  "types": "./dist/scope.d.mts",
122
157
  "import": "./dist/scope.mjs"
123
158
  },
124
- "./scope-validation": {
125
- "types": "./dist/scope-validation.d.mts",
126
- "import": "./dist/scope-validation.mjs"
127
- },
128
159
  "./token": {
129
160
  "types": "./dist/token.d.mts",
130
161
  "import": "./dist/token.mjs"
131
162
  },
163
+ "./types": {
164
+ "types": "./dist/types.d.mts",
165
+ "import": "./dist/types.mjs"
166
+ },
132
167
  "./package.json": "./package.json"
133
168
  },
134
169
  "publishConfig": {
@@ -136,12 +171,13 @@
136
171
  },
137
172
  "devDependencies": {
138
173
  "@types/node": "^25.6.0",
139
- "@typescript/native-preview": "7.0.0-dev.20260411.1",
140
- "@vitest/coverage-v8": "^4.1.4",
141
- "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",
142
178
  "unplugin-swc": "^1.5.9",
143
- "vitest": "^4.1.4",
144
- "@codefast/typescript-config": "0.3.14-canary.0"
179
+ "vitest": "^4.1.5",
180
+ "@codefast/typescript-config": "0.3.14-canary.2"
145
181
  },
146
182
  "engines": {
147
183
  "node": ">=22.0.0"
@@ -150,6 +186,8 @@
150
186
  "build": "tsdown",
151
187
  "check-types": "tsgo --noEmit",
152
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",
153
191
  "test": "vitest run",
154
192
  "test:coverage": "vitest run --coverage",
155
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 };