@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/errors.d.mts CHANGED
@@ -1,211 +1,92 @@
1
- import { Binding, BindingIdentifier, BindingScope, ResolveHint } from "./binding.mjs";
1
+ import { BindingIdentifier, BindingScope, ResolveOptions } from "./types.mjs";
2
2
 
3
3
  //#region src/errors.d.ts
4
- /**
5
- * Formats a resolution path array into a human-readable `"A -> B -> C"` string.
6
- */
7
- declare function formatResolutionPath(resolutionPath: readonly string[]): string;
8
- /**
9
- * Base error for all `@codefast/di` failures.
10
- *
11
- * Every concrete subclass exposes a stable, machine-readable {@link DiError.code} property
12
- * (e.g. `"TOKEN_NOT_BOUND"`) so consumers can `switch` on error type without relying
13
- * on `instanceof` across package versions.
14
- */
15
4
  declare abstract class DiError extends Error {
16
- /**
17
- * Machine-readable error code, constant per subclass (e.g. `"TOKEN_NOT_BOUND"`).
18
- */
19
5
  abstract readonly code: string;
20
- constructor(message: string, options?: ErrorOptions);
21
- }
22
- /**
23
- * Raised for internal programming errors — invalid library usage or unexpected state that
24
- * indicates a bug in the caller or the library itself.
25
- *
26
- * Examples: double `to*()` call on a {@link BindingBuilder}, ambiguous binding resolution
27
- * with multiple candidates, or scope mutation on a constant binding.
28
- *
29
- * Code: `"INTERNAL_ERROR"`
30
- */
6
+ constructor(message: string);
7
+ }
31
8
  declare class InternalError extends DiError {
32
9
  readonly code = "INTERNAL_ERROR";
10
+ constructor(message: string);
11
+ }
12
+ declare class TokenNotBoundError extends DiError {
13
+ readonly code = "TOKEN_NOT_BOUND";
14
+ readonly tokenName: string;
15
+ constructor(tokenName: string);
33
16
  }
34
- /**
35
- * Raised when bindings exist for the token but none match the provided name/tag hint.
36
- * Distinguishes from {@link TokenNotBoundError} (no bindings at all).
37
- *
38
- * Thrown when a `{ name }` or `{ tag }` hint is specified but no registered binding satisfies it
39
- * (e.g. `Container.resolve`, `Container.resolveAsync`, `Container.resolveOptional`,
40
- * `Container.resolveAll`, `Container.resolveAllAsync`, and binding selection helpers such as
41
- * {@link selectBindingForRegistry}).
42
- *
43
- * Code: `"NO_MATCHING_BINDING"`
44
- */
45
17
  declare class NoMatchingBindingError extends DiError {
46
18
  readonly code = "NO_MATCHING_BINDING";
47
- /**
48
- * The `Token.name` or `Constructor.name` that was resolved.
49
- */
50
19
  readonly tokenName: string;
51
- /**
52
- * The name/tag hint that failed to match any binding.
53
- */
54
- readonly hint: ResolveHint;
55
- /**
56
- * Label path from the resolution root to the failing token.
57
- */
58
- readonly resolutionPath: readonly string[];
59
- constructor(tokenName: string, hint: ResolveHint, resolutionPath: readonly string[], options?: ErrorOptions);
60
- }
61
- /**
62
- * Raised when no binding exists for the requested token or constructor.
63
- *
64
- * Thrown by `Container.resolve`, `Container.resolveAsync`, and during transitive
65
- * dependency resolution when a required token has never been registered.
66
- *
67
- * Note on optional resolution:
68
- * - Root-level `Container.resolveOptional` returns `undefined` when **that key** has no
69
- * registry entries (it never throws this error for the root key in that case). Missing
70
- * **transitive** dependencies still throw during instantiation.
71
- * - `ResolutionContext.resolveOptional` (used inside factories) catches this error
72
- * internally to return `undefined` for missing dependencies.
73
- *
74
- * Code: `"TOKEN_NOT_BOUND"`
75
- */
76
- declare class TokenNotBoundError extends DiError {
77
- readonly code = "TOKEN_NOT_BOUND";
78
- /**
79
- * The `Token.name` or `Constructor.name` that could not be found.
80
- */
20
+ readonly hint: ResolveOptions;
21
+ readonly availableSlots: string[];
22
+ constructor(tokenName: string, hint: ResolveOptions, availableSlots: string[]);
23
+ }
24
+ declare class AmbiguousBindingError extends DiError {
25
+ readonly code = "AMBIGUOUS_BINDING";
81
26
  readonly tokenName: string;
82
- /**
83
- * Label path from the resolution root to the missing token.
84
- */
85
- readonly resolutionPath: readonly string[];
86
- constructor(tokenName: string, resolutionPath: readonly string[], options?: ErrorOptions);
87
- }
88
- /**
89
- * Raised when a token is encountered a second time on the same resolution call stack,
90
- * indicating a cyclic dependency (A → B → … → A).
91
- *
92
- * Also raised during module loading when `import()` forms a cycle between modules.
93
- *
94
- * Code: `"CIRCULAR_DEPENDENCY"`
95
- */
27
+ readonly candidateIds: readonly BindingIdentifier[];
28
+ constructor(tokenName: string, candidateIds: readonly BindingIdentifier[]);
29
+ }
96
30
  declare class CircularDependencyError extends DiError {
97
31
  readonly code = "CIRCULAR_DEPENDENCY";
98
- /**
99
- * Full label path including the repeated token at the end.
100
- */
101
- readonly resolutionPath: readonly string[];
102
- /**
103
- * Mutable copy of {@link resolutionPath} for consumer convenience.
104
- */
105
32
  readonly cycle: string[];
106
- constructor(resolutionPath: readonly string[], options?: ErrorOptions);
107
- }
108
- /**
109
- * Raised when the container's {@link MetadataReader} is **configured** and reports no
110
- * constructor metadata for a `class` binding whose implementation has `arity > 0`.
111
- *
112
- * If `metadataReader` is `undefined`, the resolver calls `new ImplementationClass()` without
113
- * this check — this error is **not** thrown in that configuration.
114
- *
115
- * Fix: add `@injectable([...deps])` on the class (so `getConstructorMetadata` returns params),
116
- * or omit constructor parameters if you intentionally run without a reader.
117
- *
118
- * Code: `"MISSING_METADATA"`
119
- */
120
- declare class MissingMetadataError extends DiError {
121
- readonly code = "MISSING_METADATA";
122
- /**
123
- * Name of the class that is missing `@injectable()` metadata.
124
- */
125
- readonly className: string;
126
- /**
127
- * Label path from the resolution root to the class binding.
128
- */
129
- readonly resolutionPath: readonly string[];
130
- constructor(className: string, resolutionPath: readonly string[], options?: ErrorOptions);
131
- }
132
- /**
133
- * Raised when the synchronous `Container.load()` is called with an {@link AsyncModule}.
134
- * Use `Container.loadAsync()` or `Container.fromModulesAsync()` instead.
135
- *
136
- * Code: `"ASYNC_MODULE_LOAD"`
137
- */
138
- declare class AsyncModuleLoadError extends DiError {
139
- readonly code = "ASYNC_MODULE_LOAD";
140
- /**
141
- * Name of the async module that was passed to the sync loader.
142
- */
143
- readonly moduleName: string;
144
- constructor(moduleName: string, options?: ErrorOptions);
145
- }
146
- /**
147
- * Raised when synchronous `Container.resolve()` / `Container.resolveAll()` encounters an
148
- * async operation: an `async-dynamic` factory, a `toDynamic` factory that returns a Promise,
149
- * an `onActivation` handler that returns a Promise, or a `@postConstruct` method that
150
- * returns a Promise.
151
- *
152
- * Fix: switch to `Container.resolveAsync()` / `Container.resolveAllAsync()`.
153
- *
154
- * Code: `"ASYNC_RESOLUTION"`
155
- */
33
+ constructor(cycle: string[]);
34
+ }
156
35
  declare class AsyncResolutionError extends DiError {
157
36
  readonly code = "ASYNC_RESOLUTION";
158
- /**
159
- * Token or class name that triggered the async path.
160
- */
161
37
  readonly tokenName: string;
162
- /**
163
- * Label path from the resolution root to the async binding.
164
- */
165
- readonly resolutionPath: readonly string[];
166
- /**
167
- * Human-readable description of why async resolution was required.
168
- */
169
- readonly reason: string;
170
- constructor(tokenName: string, resolutionPath: readonly string[], reason: string, options?: ErrorOptions);
171
- }
172
- /**
173
- * Structured payload passed to the {@link ScopeViolationError} constructor.
174
- * Carries identities and scopes of both the long-lived consumer and the shorter-lived dependency.
175
- */
176
- type ScopeViolationDetails = {
177
- readonly consumerBindingId: BindingIdentifier;
178
- readonly consumerKind: Binding<unknown>["kind"];
38
+ readonly asyncSourceToken: string;
39
+ constructor(tokenName: string, asyncSourceToken: string);
40
+ }
41
+ declare class AsyncDeactivationError extends DiError {
42
+ readonly code = "ASYNC_DEACTIVATION";
43
+ readonly tokenName: string;
44
+ constructor(tokenName: string);
45
+ }
46
+ interface ScopeViolationDetails {
47
+ readonly consumerToken: string;
179
48
  readonly consumerScope: BindingScope;
180
- readonly consumerLabel?: string;
181
- readonly dependencyBindingId: BindingIdentifier;
182
- readonly dependencyKind: Binding<unknown>["kind"];
49
+ readonly dependencyToken: string;
183
50
  readonly dependencyScope: BindingScope;
184
- readonly dependencyLabel?: string;
185
- readonly resolutionPath: readonly string[];
186
- };
187
- /**
188
- * Raised for a **captive dependency**: a singleton consumer resolves (or would resolve) a
189
- * non-constant binding whose lifetime is `scoped` or `transient`. Constant bindings are exempt.
190
- *
191
- * - **Runtime:** each resolution step checks the parent on the materialization stack, so
192
- * violations are detected along the actual construction chain.
193
- * - **`Container.validate()`:** {@link validateScopeRules} walks **direct** static edges from
194
- * {@link listResolvedDependencies} only — it does not recursively expand the whole graph,
195
- * so it may miss violations that appear only deeper in the dependency tree.
196
- *
197
- * Code: `"SCOPE_VIOLATION"`
198
- */
51
+ readonly path: string[];
52
+ }
199
53
  declare class ScopeViolationError extends DiError {
200
54
  readonly code = "SCOPE_VIOLATION";
201
- readonly consumerBindingId: BindingIdentifier;
202
- readonly consumerKind: Binding<unknown>["kind"];
203
- readonly consumerScope: BindingScope;
204
- readonly dependencyBindingId: BindingIdentifier;
205
- readonly dependencyKind: Binding<unknown>["kind"];
206
- readonly dependencyScope: BindingScope;
207
- readonly resolutionPath: readonly string[];
208
- constructor(details: ScopeViolationDetails, options?: ErrorOptions);
55
+ readonly details: ScopeViolationDetails;
56
+ constructor(details: ScopeViolationDetails);
57
+ }
58
+ declare class MissingMetadataError extends DiError {
59
+ readonly code = "MISSING_METADATA";
60
+ readonly targetName: string;
61
+ constructor(targetName: string);
62
+ }
63
+ declare class AsyncModuleLoadError extends DiError {
64
+ readonly code = "ASYNC_MODULE_LOAD";
65
+ readonly moduleName: string;
66
+ constructor(moduleName: string);
67
+ }
68
+ declare class SyncDisposalNotSupportedError extends DiError {
69
+ readonly code = "SYNC_DISPOSAL_NOT_SUPPORTED";
70
+ constructor();
71
+ }
72
+ declare class MissingScopeContextError extends DiError {
73
+ readonly code = "MISSING_SCOPE_CONTEXT";
74
+ readonly tokenName: string;
75
+ constructor(tokenName: string);
76
+ }
77
+ declare class MissingContainerContextError extends DiError {
78
+ readonly code = "MISSING_CONTAINER_CONTEXT";
79
+ readonly targetName: string;
80
+ constructor(targetName: string);
81
+ }
82
+ declare class RebindUnboundTokenError extends DiError {
83
+ readonly code = "REBIND_UNBOUND_TOKEN";
84
+ readonly tokenName: string;
85
+ constructor(tokenName: string);
86
+ }
87
+ declare class DisposedContainerError extends DiError {
88
+ readonly code = "DISPOSED_CONTAINER";
89
+ constructor();
209
90
  }
210
91
  //#endregion
211
- export { AsyncModuleLoadError, AsyncResolutionError, CircularDependencyError, DiError, InternalError, MissingMetadataError, NoMatchingBindingError, ScopeViolationDetails, ScopeViolationError, TokenNotBoundError, formatResolutionPath };
92
+ export { AmbiguousBindingError, AsyncDeactivationError, AsyncModuleLoadError, AsyncResolutionError, CircularDependencyError, DiError, DisposedContainerError, InternalError, MissingContainerContextError, MissingMetadataError, MissingScopeContextError, NoMatchingBindingError, RebindUnboundTokenError, ScopeViolationDetails, ScopeViolationError, SyncDisposalNotSupportedError, TokenNotBoundError };
package/dist/errors.mjs CHANGED
@@ -1,260 +1,133 @@
1
1
  //#region src/errors.ts
2
- /**
3
- * Formats a resolution path array into a human-readable `"A -> B -> C"` string.
4
- */
5
- function formatResolutionPath(resolutionPath) {
6
- return resolutionPath.length > 0 ? resolutionPath.join(" -> ") : "(empty)";
7
- }
8
- const SCOPE_LABELS = {
9
- singleton: "Singleton",
10
- scoped: "Scoped",
11
- transient: "Transient"
12
- };
13
- /**
14
- * Serializes a {@link ResolveHint} to a debug string; never throws even for exotic values.
15
- */
16
- function safeSerializeHint(hint) {
17
- if (hint === void 0) return "(none)";
18
- try {
19
- const parts = [];
20
- if (hint.name !== void 0) parts.push(`name: ${String(hint.name)}`);
21
- if (hint.tag !== void 0) {
22
- const [tagKey, tagValue] = hint.tag;
23
- parts.push(`tag: [${tagKey}, <${typeof tagValue}>]`);
24
- }
25
- return `{ ${parts.join(", ")} }`;
26
- } catch {
27
- return "(unserializable hint)";
28
- }
29
- }
30
- /**
31
- * Base error for all `@codefast/di` failures.
32
- *
33
- * Every concrete subclass exposes a stable, machine-readable {@link DiError.code} property
34
- * (e.g. `"TOKEN_NOT_BOUND"`) so consumers can `switch` on error type without relying
35
- * on `instanceof` across package versions.
36
- */
37
2
  var DiError = class extends Error {
38
- constructor(message, options) {
39
- super(message, options);
40
- this.name = new.target.name;
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = this.constructor.name;
41
6
  }
42
7
  };
43
- /**
44
- * Raised for internal programming errors — invalid library usage or unexpected state that
45
- * indicates a bug in the caller or the library itself.
46
- *
47
- * Examples: double `to*()` call on a {@link BindingBuilder}, ambiguous binding resolution
48
- * with multiple candidates, or scope mutation on a constant binding.
49
- *
50
- * Code: `"INTERNAL_ERROR"`
51
- */
52
8
  var InternalError = class extends DiError {
53
9
  code = "INTERNAL_ERROR";
10
+ constructor(message) {
11
+ super(message);
12
+ }
13
+ };
14
+ var TokenNotBoundError = class extends DiError {
15
+ code = "TOKEN_NOT_BOUND";
16
+ tokenName;
17
+ constructor(tokenName) {
18
+ super(`No binding found for token '${tokenName}'. Did you forget container.bind(${tokenName})?`);
19
+ this.tokenName = tokenName;
20
+ }
54
21
  };
55
- /**
56
- * Raised when bindings exist for the token but none match the provided name/tag hint.
57
- * Distinguishes from {@link TokenNotBoundError} (no bindings at all).
58
- *
59
- * Thrown when a `{ name }` or `{ tag }` hint is specified but no registered binding satisfies it
60
- * (e.g. `Container.resolve`, `Container.resolveAsync`, `Container.resolveOptional`,
61
- * `Container.resolveAll`, `Container.resolveAllAsync`, and binding selection helpers such as
62
- * {@link selectBindingForRegistry}).
63
- *
64
- * Code: `"NO_MATCHING_BINDING"`
65
- */
66
22
  var NoMatchingBindingError = class extends DiError {
67
23
  code = "NO_MATCHING_BINDING";
68
- /**
69
- * The `Token.name` or `Constructor.name` that was resolved.
70
- */
71
24
  tokenName;
72
- /**
73
- * The name/tag hint that failed to match any binding.
74
- */
75
25
  hint;
76
- /**
77
- * Label path from the resolution root to the failing token.
78
- */
79
- resolutionPath;
80
- constructor(tokenName, hint, resolutionPath, options) {
81
- const pathText = formatResolutionPath(resolutionPath);
82
- const hintText = safeSerializeHint(hint);
83
- super(`No binding matched resolve options ${hintText} for token "${tokenName}" (resolution path: ${pathText})`, options);
26
+ availableSlots;
27
+ constructor(tokenName, hint, availableSlots) {
28
+ const hintStr = JSON.stringify(hint);
29
+ const slotsStr = availableSlots.join(", ");
30
+ super(`No binding for '${tokenName}' matching ${hintStr}. Available slots: [${slotsStr}].`);
84
31
  this.tokenName = tokenName;
85
32
  this.hint = hint;
86
- this.resolutionPath = resolutionPath;
33
+ this.availableSlots = availableSlots;
87
34
  }
88
35
  };
89
- /**
90
- * Raised when no binding exists for the requested token or constructor.
91
- *
92
- * Thrown by `Container.resolve`, `Container.resolveAsync`, and during transitive
93
- * dependency resolution when a required token has never been registered.
94
- *
95
- * Note on optional resolution:
96
- * - Root-level `Container.resolveOptional` returns `undefined` when **that key** has no
97
- * registry entries (it never throws this error for the root key in that case). Missing
98
- * **transitive** dependencies still throw during instantiation.
99
- * - `ResolutionContext.resolveOptional` (used inside factories) catches this error
100
- * internally to return `undefined` for missing dependencies.
101
- *
102
- * Code: `"TOKEN_NOT_BOUND"`
103
- */
104
- var TokenNotBoundError = class extends DiError {
105
- code = "TOKEN_NOT_BOUND";
106
- /**
107
- * The `Token.name` or `Constructor.name` that could not be found.
108
- */
36
+ var AmbiguousBindingError = class extends DiError {
37
+ code = "AMBIGUOUS_BINDING";
109
38
  tokenName;
110
- /**
111
- * Label path from the resolution root to the missing token.
112
- */
113
- resolutionPath;
114
- constructor(tokenName, resolutionPath, options) {
115
- const pathText = formatResolutionPath(resolutionPath);
116
- super(`Token not bound: ${tokenName} (resolution path: ${pathText})`, options);
39
+ candidateIds;
40
+ constructor(tokenName, candidateIds) {
41
+ super(`Multiple bindings for '${tokenName}' matched without a clear winner. Candidates: [${candidateIds.join(", ")}]. Ensure when() predicates are mutually exclusive.`);
117
42
  this.tokenName = tokenName;
118
- this.resolutionPath = resolutionPath;
43
+ this.candidateIds = candidateIds;
119
44
  }
120
45
  };
121
- /**
122
- * Raised when a token is encountered a second time on the same resolution call stack,
123
- * indicating a cyclic dependency (A → B → … → A).
124
- *
125
- * Also raised during module loading when `import()` forms a cycle between modules.
126
- *
127
- * Code: `"CIRCULAR_DEPENDENCY"`
128
- */
129
46
  var CircularDependencyError = class extends DiError {
130
47
  code = "CIRCULAR_DEPENDENCY";
131
- /**
132
- * Full label path including the repeated token at the end.
133
- */
134
- resolutionPath;
135
- /**
136
- * Mutable copy of {@link resolutionPath} for consumer convenience.
137
- */
138
48
  cycle;
139
- constructor(resolutionPath, options) {
140
- const pathText = formatResolutionPath(resolutionPath);
141
- super(`Circular dependency detected: ${pathText}`, options);
142
- this.resolutionPath = resolutionPath;
143
- this.cycle = [...resolutionPath];
49
+ constructor(cycle) {
50
+ super(`Circular dependency detected: ${cycle.join(" → ")}`);
51
+ this.cycle = cycle;
52
+ }
53
+ };
54
+ var AsyncResolutionError = class extends DiError {
55
+ code = "ASYNC_RESOLUTION";
56
+ tokenName;
57
+ asyncSourceToken;
58
+ constructor(tokenName, asyncSourceToken) {
59
+ super(`Token '${tokenName}' requires async resolution because '${asyncSourceToken}' in its dependency chain has an async factory. Use container.resolveAsync(${tokenName}).`);
60
+ this.tokenName = tokenName;
61
+ this.asyncSourceToken = asyncSourceToken;
62
+ }
63
+ };
64
+ var AsyncDeactivationError = class extends DiError {
65
+ code = "ASYNC_DEACTIVATION";
66
+ tokenName;
67
+ constructor(tokenName) {
68
+ super(`Token '${tokenName}' has an async onDeactivation handler. Use unbindAsync() instead.`);
69
+ this.tokenName = tokenName;
70
+ }
71
+ };
72
+ var ScopeViolationError = class extends DiError {
73
+ code = "SCOPE_VIOLATION";
74
+ details;
75
+ constructor(details) {
76
+ super(`Scope violation: '${details.consumerToken}' (${details.consumerScope}) depends on '${details.dependencyToken}' (${details.dependencyScope}). Path: ${details.path.join(" → ")}`);
77
+ this.details = details;
144
78
  }
145
79
  };
146
- /**
147
- * Raised when the container's {@link MetadataReader} is **configured** and reports no
148
- * constructor metadata for a `class` binding whose implementation has `arity > 0`.
149
- *
150
- * If `metadataReader` is `undefined`, the resolver calls `new ImplementationClass()` without
151
- * this check — this error is **not** thrown in that configuration.
152
- *
153
- * Fix: add `@injectable([...deps])` on the class (so `getConstructorMetadata` returns params),
154
- * or omit constructor parameters if you intentionally run without a reader.
155
- *
156
- * Code: `"MISSING_METADATA"`
157
- */
158
80
  var MissingMetadataError = class extends DiError {
159
81
  code = "MISSING_METADATA";
160
- /**
161
- * Name of the class that is missing `@injectable()` metadata.
162
- */
163
- className;
164
- /**
165
- * Label path from the resolution root to the class binding.
166
- */
167
- resolutionPath;
168
- constructor(className, resolutionPath, options) {
169
- const pathText = formatResolutionPath(resolutionPath);
170
- super(`Missing injectable constructor metadata for class "${className}" (resolution path: ${pathText})`, options);
171
- this.className = className;
172
- this.resolutionPath = resolutionPath;
82
+ targetName;
83
+ constructor(targetName) {
84
+ super(`Class '${targetName}' is missing @injectable() decorator. Add @injectable([...deps]) or use toDynamic()/toResolved() instead.`);
85
+ this.targetName = targetName;
173
86
  }
174
87
  };
175
- /**
176
- * Raised when the synchronous `Container.load()` is called with an {@link AsyncModule}.
177
- * Use `Container.loadAsync()` or `Container.fromModulesAsync()` instead.
178
- *
179
- * Code: `"ASYNC_MODULE_LOAD"`
180
- */
181
88
  var AsyncModuleLoadError = class extends DiError {
182
89
  code = "ASYNC_MODULE_LOAD";
183
- /**
184
- * Name of the async module that was passed to the sync loader.
185
- */
186
90
  moduleName;
187
- constructor(moduleName, options) {
188
- super(`Cannot load async module "${moduleName}" synchronously; use loadAsync() or Container.fromModulesAsync().`, options);
91
+ constructor(moduleName) {
92
+ super(`Module '${moduleName}' is async. Use container.loadAsync() instead.`);
189
93
  this.moduleName = moduleName;
190
94
  }
191
95
  };
192
- /**
193
- * Raised when synchronous `Container.resolve()` / `Container.resolveAll()` encounters an
194
- * async operation: an `async-dynamic` factory, a `toDynamic` factory that returns a Promise,
195
- * an `onActivation` handler that returns a Promise, or a `@postConstruct` method that
196
- * returns a Promise.
197
- *
198
- * Fix: switch to `Container.resolveAsync()` / `Container.resolveAllAsync()`.
199
- *
200
- * Code: `"ASYNC_RESOLUTION"`
201
- */
202
- var AsyncResolutionError = class extends DiError {
203
- code = "ASYNC_RESOLUTION";
204
- /**
205
- * Token or class name that triggered the async path.
206
- */
96
+ var SyncDisposalNotSupportedError = class extends DiError {
97
+ code = "SYNC_DISPOSAL_NOT_SUPPORTED";
98
+ constructor() {
99
+ super("Container cannot be disposed synchronously because onDeactivation handlers may be async. Use `await using` or call container.dispose() explicitly.");
100
+ }
101
+ };
102
+ var MissingScopeContextError = class extends DiError {
103
+ code = "MISSING_SCOPE_CONTEXT";
207
104
  tokenName;
208
- /**
209
- * Label path from the resolution root to the async binding.
210
- */
211
- resolutionPath;
212
- /**
213
- * Human-readable description of why async resolution was required.
214
- */
215
- reason;
216
- constructor(tokenName, resolutionPath, reason, options) {
217
- const pathText = formatResolutionPath(resolutionPath);
218
- super(`Cannot resolve "${tokenName}" synchronously: ${reason} (resolution path: ${pathText})`, options);
105
+ constructor(tokenName) {
106
+ super(`Token '${tokenName}' is scoped but was resolved from a container without a child scope context. Use container.createChild() to create a scoped context.`);
219
107
  this.tokenName = tokenName;
220
- this.resolutionPath = resolutionPath;
221
- this.reason = reason;
222
108
  }
223
109
  };
224
- /**
225
- * Raised for a **captive dependency**: a singleton consumer resolves (or would resolve) a
226
- * non-constant binding whose lifetime is `scoped` or `transient`. Constant bindings are exempt.
227
- *
228
- * - **Runtime:** each resolution step checks the parent on the materialization stack, so
229
- * violations are detected along the actual construction chain.
230
- * - **`Container.validate()`:** {@link validateScopeRules} walks **direct** static edges from
231
- * {@link listResolvedDependencies} only — it does not recursively expand the whole graph,
232
- * so it may miss violations that appear only deeper in the dependency tree.
233
- *
234
- * Code: `"SCOPE_VIOLATION"`
235
- */
236
- var ScopeViolationError = class extends DiError {
237
- code = "SCOPE_VIOLATION";
238
- consumerBindingId;
239
- consumerKind;
240
- consumerScope;
241
- dependencyBindingId;
242
- dependencyKind;
243
- dependencyScope;
244
- resolutionPath;
245
- constructor(details, options) {
246
- const pathText = formatResolutionPath(details.resolutionPath);
247
- const consumerLabel = details.consumerLabel ?? String(details.consumerBindingId);
248
- const dependencyLabel = details.dependencyLabel ?? String(details.dependencyBindingId);
249
- super(`Scope Violation: ${SCOPE_LABELS[details.consumerScope]} "${consumerLabel}" cannot depend on ${SCOPE_LABELS[details.dependencyScope]} "${dependencyLabel}" (resolution path: ${pathText})`, options);
250
- this.consumerBindingId = details.consumerBindingId;
251
- this.consumerKind = details.consumerKind;
252
- this.consumerScope = details.consumerScope;
253
- this.dependencyBindingId = details.dependencyBindingId;
254
- this.dependencyKind = details.dependencyKind;
255
- this.dependencyScope = details.dependencyScope;
256
- this.resolutionPath = details.resolutionPath;
110
+ var MissingContainerContextError = class extends DiError {
111
+ code = "MISSING_CONTAINER_CONTEXT";
112
+ targetName;
113
+ constructor(targetName) {
114
+ super(`Class '${targetName}' has @inject accessor fields but was instantiated outside a container context. Resolve it via container.resolve(${targetName}) instead.`);
115
+ this.targetName = targetName;
116
+ }
117
+ };
118
+ var RebindUnboundTokenError = class extends DiError {
119
+ code = "REBIND_UNBOUND_TOKEN";
120
+ tokenName;
121
+ constructor(tokenName) {
122
+ super(`Cannot rebind token '${tokenName}' because it has no own binding in this container. Use container.bind(${tokenName}) to create a new binding instead.`);
123
+ this.tokenName = tokenName;
124
+ }
125
+ };
126
+ var DisposedContainerError = class extends DiError {
127
+ code = "DISPOSED_CONTAINER";
128
+ constructor() {
129
+ super("Cannot perform operations on a disposed container.");
257
130
  }
258
131
  };
259
132
  //#endregion
260
- export { AsyncModuleLoadError, AsyncResolutionError, CircularDependencyError, DiError, InternalError, MissingMetadataError, NoMatchingBindingError, ScopeViolationError, TokenNotBoundError, formatResolutionPath };
133
+ export { AmbiguousBindingError, AsyncDeactivationError, AsyncModuleLoadError, AsyncResolutionError, CircularDependencyError, DiError, DisposedContainerError, InternalError, MissingContainerContextError, MissingMetadataError, MissingScopeContextError, NoMatchingBindingError, RebindUnboundTokenError, ScopeViolationError, SyncDisposalNotSupportedError, TokenNotBoundError };
@@ -0,0 +1,24 @@
1
+ import { ContainerGraphJson } from "../dependency-graph.mjs";
2
+
3
+ //#region src/graph-adapters/cytoscape.d.ts
4
+ interface CytoscapeNode {
5
+ data: {
6
+ id: string;
7
+ label: string;
8
+ kind: string;
9
+ scope: string;
10
+ fromParent: boolean;
11
+ };
12
+ }
13
+ interface CytoscapeEdge {
14
+ data: {
15
+ id: string;
16
+ source: string;
17
+ target: string;
18
+ label?: string;
19
+ };
20
+ }
21
+ type CytoscapeElements = Array<CytoscapeNode | CytoscapeEdge>;
22
+ declare function toCytoscapeGraph(graph: ContainerGraphJson): CytoscapeElements;
23
+ //#endregion
24
+ export { CytoscapeEdge, CytoscapeElements, CytoscapeNode, toCytoscapeGraph };