@codefast/di 0.3.14-canary.1 → 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 (65) hide show
  1. package/CHANGELOG.md +18 -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/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
- */
33
+ constructor(cycle: string[]);
34
+ }
35
+ declare class AsyncResolutionError extends DiError {
36
+ readonly code = "ASYNC_RESOLUTION";
37
+ readonly tokenName: string;
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;
48
+ readonly consumerScope: BindingScope;
49
+ readonly dependencyToken: string;
50
+ readonly dependencyScope: BindingScope;
51
+ readonly path: string[];
52
+ }
53
+ declare class ScopeViolationError extends DiError {
54
+ readonly code = "SCOPE_VIOLATION";
55
+ readonly details: ScopeViolationDetails;
56
+ constructor(details: ScopeViolationDetails);
57
+ }
120
58
  declare class MissingMetadataError extends DiError {
121
59
  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
- */
60
+ readonly targetName: string;
61
+ constructor(targetName: string);
62
+ }
138
63
  declare class AsyncModuleLoadError extends DiError {
139
64
  readonly code = "ASYNC_MODULE_LOAD";
140
- /**
141
- * Name of the async module that was passed to the sync loader.
142
- */
143
65
  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
- */
156
- declare class AsyncResolutionError extends DiError {
157
- readonly code = "ASYNC_RESOLUTION";
158
- /**
159
- * Token or class name that triggered the async path.
160
- */
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";
161
74
  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
- /** Binding id of the long-lived consumer (typically singleton). */readonly consumerBindingId: BindingIdentifier; /** Binding strategy kind of the consumer. */
178
- readonly consumerKind: Binding<unknown>["kind"]; /** Scope of the consumer binding. */
179
- readonly consumerScope: BindingScope; /** Optional display label for consumer in error messages. */
180
- readonly consumerLabel?: string; /** Binding id of the shorter-lived dependency. */
181
- readonly dependencyBindingId: BindingIdentifier; /** Binding strategy kind of the dependency. */
182
- readonly dependencyKind: Binding<unknown>["kind"]; /** Scope of the dependency binding. */
183
- readonly dependencyScope: BindingScope; /** Optional display label for dependency in error messages. */
184
- readonly dependencyLabel?: string; /** Resolution path captured at the violation point. */
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
- */
199
- declare class ScopeViolationError extends DiError {
200
- 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);
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 };
@@ -1,10 +1,24 @@
1
- import { ContainerGraphJson } from "../inspector.mjs";
2
- import { CytoscapeGraphJson } from "./types.mjs";
1
+ import { ContainerGraphJson } from "../dependency-graph.mjs";
3
2
 
4
3
  //#region src/graph-adapters/cytoscape.d.ts
5
- /**
6
- * Converts the canonical container graph JSON into Cytoscape elements format.
7
- */
8
- declare function toCytoscapeGraph(graph: ContainerGraphJson): CytoscapeGraphJson;
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;
9
23
  //#endregion
10
- export { toCytoscapeGraph };
24
+ export { CytoscapeEdge, CytoscapeElements, CytoscapeNode, toCytoscapeGraph };