@codefast/di 0.10.1 → 0.12.0

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 (88) hide show
  1. package/CHANGELOG.md +376 -0
  2. package/README.md +94 -17
  3. package/dist/{ambient/active-container.d.ts → ambient-container.d.ts} +7 -2
  4. package/dist/{ambient/active-container.js → ambient-container.js} +6 -1
  5. package/dist/container/{binding-builders.d.ts → binding-chain.d.ts} +27 -16
  6. package/dist/container/binding-chain.js +254 -0
  7. package/dist/container/container.d.ts +11 -2
  8. package/dist/container/container.js +293 -73
  9. package/dist/core/binding-builders.d.ts +114 -0
  10. package/dist/core/binding-declaration.d.ts +127 -0
  11. package/dist/core/binding-declaration.js +187 -0
  12. package/dist/core/binding.d.ts +62 -138
  13. package/dist/core/binding.js +54 -17
  14. package/dist/core/module.d.ts +8 -5
  15. package/dist/core/module.js +17 -3
  16. package/dist/core/registry.d.ts +17 -28
  17. package/dist/core/registry.js +92 -133
  18. package/dist/core/state-epoch.d.ts +18 -1
  19. package/dist/core/state-epoch.js +17 -0
  20. package/dist/core/tag.js +1 -1
  21. package/dist/decorators/inject.js +6 -5
  22. package/dist/decorators/injectable.js +4 -2
  23. package/dist/decorators/{lifecycle-decorators.js → lifecycle.js} +9 -3
  24. package/dist/decorators/metadata-record.d.ts +9 -0
  25. package/dist/decorators/metadata-record.js +20 -0
  26. package/dist/{errors/errors.d.ts → errors.d.ts} +84 -9
  27. package/dist/{errors/errors.js → errors.js} +101 -17
  28. package/dist/index.d.ts +14 -10
  29. package/dist/index.js +7 -6
  30. package/dist/injection/{resolve-options.js → dependency-slot.js} +6 -4
  31. package/dist/injection/descriptor.d.ts +1 -1
  32. package/dist/injection/descriptor.js +3 -7
  33. package/dist/introspection/dependency-graph.d.ts +8 -3
  34. package/dist/introspection/dependency-graph.js +48 -26
  35. package/dist/introspection/explanation.d.ts +101 -0
  36. package/dist/introspection/explanation.js +151 -0
  37. package/dist/introspection/graph-adapters/reactflow.js +6 -4
  38. package/dist/introspection/inspector.d.ts +9 -2
  39. package/dist/introspection/inspector.js +30 -28
  40. package/dist/lifecycle/{lifecycle-manager.d.ts → hooks.d.ts} +9 -2
  41. package/dist/lifecycle/{lifecycle-manager.js → hooks.js} +59 -30
  42. package/dist/lifecycle/{scope-manager.d.ts → scopes.d.ts} +3 -5
  43. package/dist/lifecycle/{scope-manager.js → scopes.js} +36 -29
  44. package/dist/metadata/{metadata-reader-token.d.ts → reader-token.d.ts} +1 -1
  45. package/dist/metadata/{symbol-metadata-reader.d.ts → symbol-reader.d.ts} +1 -1
  46. package/dist/metadata/{symbol-metadata-reader.js → symbol-reader.js} +1 -1
  47. package/dist/metadata/{metadata-types.d.ts → types.d.ts} +1 -1
  48. package/dist/metadata/types.js +1 -0
  49. package/dist/metadata/verify.d.ts +43 -0
  50. package/dist/metadata/verify.js +133 -0
  51. package/dist/metadata/{verifying-metadata-reader.d.ts → verifying-reader.d.ts} +5 -4
  52. package/dist/metadata/verifying-reader.js +53 -0
  53. package/dist/resolution/async-fan-out.d.ts +12 -0
  54. package/dist/resolution/async-fan-out.js +26 -0
  55. package/dist/resolution/cache/activation-need.d.ts +1 -2
  56. package/dist/resolution/cache/activation-need.js +16 -19
  57. package/dist/resolution/cache/class-introspector.d.ts +38 -36
  58. package/dist/resolution/cache/class-introspector.js +79 -159
  59. package/dist/resolution/cache/{binding-lookup-cache.d.ts → lookup.d.ts} +7 -9
  60. package/dist/resolution/cache/{binding-lookup-cache.js → lookup.js} +70 -25
  61. package/dist/resolution/context.d.ts +16 -24
  62. package/dist/resolution/context.js +47 -56
  63. package/dist/resolution/path.d.ts +128 -0
  64. package/dist/resolution/path.js +167 -0
  65. package/dist/resolution/plan/{plan-codegen.d.ts → codegen.d.ts} +5 -4
  66. package/dist/resolution/plan/{plan-codegen.js → codegen.js} +58 -32
  67. package/dist/resolution/plan/{instantiation-plan.d.ts → compiler.d.ts} +1 -1
  68. package/dist/resolution/plan/{instantiation-plan.js → compiler.js} +64 -24
  69. package/dist/resolution/resolver.d.ts +11 -12
  70. package/dist/resolution/resolver.js +573 -356
  71. package/dist/resolution/select/{binding-select.d.ts → candidates.d.ts} +30 -0
  72. package/dist/resolution/select/{binding-select.js → candidates.js} +51 -10
  73. package/dist/resolution/select/constraints.js +1 -1
  74. package/package.json +87 -67
  75. package/dist/container/binding-builders.js +0 -305
  76. package/dist/core/binding-scope.d.ts +0 -12
  77. package/dist/core/binding-scope.js +0 -12
  78. package/dist/metadata/verifying-metadata-reader.js +0 -31
  79. package/dist/resolution/path/resolution-path.d.ts +0 -93
  80. package/dist/resolution/path/resolution-path.js +0 -116
  81. /package/dist/{metadata/metadata-types.js → core/binding-builders.js} +0 -0
  82. /package/dist/decorators/{lifecycle-decorators.d.ts → lifecycle.d.ts} +0 -0
  83. /package/dist/injection/{resolve-options.d.ts → dependency-slot.d.ts} +0 -0
  84. /package/dist/{errors → introspection}/diagnostics.d.ts +0 -0
  85. /package/dist/{errors → introspection}/diagnostics.js +0 -0
  86. /package/dist/metadata/{metadata-keys.d.ts → keys.d.ts} +0 -0
  87. /package/dist/metadata/{metadata-keys.js → keys.js} +0 -0
  88. /package/dist/metadata/{metadata-reader-token.js → reader-token.js} +0 -0
@@ -7,7 +7,7 @@ import type { BindingIdentifier, BindingScope, ResolveOptions } from "#core/type
7
7
  */
8
8
  export declare abstract class DiError extends Error {
9
9
  abstract readonly code: string;
10
- constructor(message: string);
10
+ abstract readonly name: string;
11
11
  }
12
12
  /**
13
13
  * An internal assertion failure — a library bug, never caller misuse.
@@ -15,6 +15,7 @@ export declare abstract class DiError extends Error {
15
15
  * @since 0.3.16-canary.0
16
16
  */
17
17
  export declare class InternalError extends DiError {
18
+ readonly name = "InternalError";
18
19
  readonly code = "INTERNAL_ERROR";
19
20
  constructor(message: string);
20
21
  }
@@ -24,6 +25,7 @@ export declare class InternalError extends DiError {
24
25
  * @since 0.3.16-canary.0
25
26
  */
26
27
  export declare class TokenNotBoundError extends DiError {
28
+ readonly name = "TokenNotBoundError";
27
29
  readonly code = "TOKEN_NOT_BOUND";
28
30
  readonly tokenName: string;
29
31
  constructor(tokenName: string);
@@ -34,6 +36,7 @@ export declare class TokenNotBoundError extends DiError {
34
36
  * @since 0.3.16-canary.0
35
37
  */
36
38
  export declare class NoMatchingBindingError extends DiError {
39
+ readonly name = "NoMatchingBindingError";
37
40
  readonly code = "NO_MATCHING_BINDING";
38
41
  readonly tokenName: string;
39
42
  readonly options: ResolveOptions;
@@ -46,6 +49,7 @@ export declare class NoMatchingBindingError extends DiError {
46
49
  * @since 0.3.16-canary.0
47
50
  */
48
51
  export declare class AmbiguousBindingError extends DiError {
52
+ readonly name = "AmbiguousBindingError";
49
53
  readonly code = "AMBIGUOUS_BINDING";
50
54
  readonly tokenName: string;
51
55
  readonly candidateIds: ReadonlyArray<BindingIdentifier>;
@@ -57,6 +61,7 @@ export declare class AmbiguousBindingError extends DiError {
57
61
  * @since 0.3.16-canary.0
58
62
  */
59
63
  export declare class CircularDependencyError extends DiError {
64
+ readonly name = "CircularDependencyError";
60
65
  readonly code = "CIRCULAR_DEPENDENCY";
61
66
  readonly cycle: Array<string>;
62
67
  constructor(cycle: Array<string>);
@@ -67,6 +72,7 @@ export declare class CircularDependencyError extends DiError {
67
72
  * @since 0.3.16-canary.0
68
73
  */
69
74
  export declare class AsyncResolutionError extends DiError {
75
+ readonly name = "AsyncResolutionError";
70
76
  readonly code = "ASYNC_RESOLUTION";
71
77
  /** The token the caller asked for — what `resolveAsync` has to be called with. */
72
78
  readonly tokenName: string;
@@ -80,6 +86,7 @@ export declare class AsyncResolutionError extends DiError {
80
86
  * @since 0.3.16-canary.0
81
87
  */
82
88
  export declare class AsyncDeactivationError extends DiError {
89
+ readonly name = "AsyncDeactivationError";
83
90
  readonly code = "ASYNC_DEACTIVATION";
84
91
  readonly tokenName: string;
85
92
  constructor(tokenName: string);
@@ -102,6 +109,7 @@ export interface ScopeViolationDetails {
102
109
  * @since 0.3.16-canary.0
103
110
  */
104
111
  export declare class ScopeViolationError extends DiError {
112
+ readonly name = "ScopeViolationError";
105
113
  readonly code = "SCOPE_VIOLATION";
106
114
  readonly details: ScopeViolationDetails;
107
115
  constructor(details: ScopeViolationDetails);
@@ -116,6 +124,7 @@ export declare class ScopeViolationError extends DiError {
116
124
  * @since 0.6.0
117
125
  */
118
126
  export declare class EmptyTagCriteriaError extends DiError {
127
+ readonly name = "EmptyTagCriteriaError";
119
128
  readonly code = "EMPTY_TAG_CRITERIA";
120
129
  readonly helperName: string;
121
130
  constructor(helperName: string);
@@ -130,6 +139,7 @@ export declare class EmptyTagCriteriaError extends DiError {
130
139
  * @since 0.6.0
131
140
  */
132
141
  export declare class UnreachableConstraintError extends DiError {
142
+ readonly name = "UnreachableConstraintError";
133
143
  readonly code = "UNREACHABLE_CONSTRAINT";
134
144
  readonly tokenName: string;
135
145
  readonly requiredName: string;
@@ -148,10 +158,13 @@ export declare class UnreachableConstraintError extends DiError {
148
158
  * @since 0.6.0
149
159
  */
150
160
  export declare class UnreachableLifecycleHookError extends DiError {
161
+ readonly name = "UnreachableLifecycleHookError";
151
162
  readonly code = "UNREACHABLE_LIFECYCLE_HOOK";
152
163
  readonly tokenName: string;
153
164
  readonly phase: "onActivation" | "onDeactivation";
154
- constructor(tokenName: string, phase: "onActivation" | "onDeactivation");
165
+ /** Nothing binds the token, or — for a deactivation hook — every binding it has is transient or scoped. */
166
+ readonly reason: "unbound" | "no-deactivatable-binding";
167
+ constructor(tokenName: string, phase: "onActivation" | "onDeactivation", reason?: "unbound" | "no-deactivatable-binding");
155
168
  }
156
169
  /**
157
170
  * A {@link MetadataReader} described a class with something the container cannot use.
@@ -163,6 +176,7 @@ export declare class UnreachableLifecycleHookError extends DiError {
163
176
  * @since 0.6.0
164
177
  */
165
178
  export declare class InvalidMetadataError extends DiError {
179
+ readonly name = "InvalidMetadataError";
166
180
  readonly code = "INVALID_METADATA";
167
181
  readonly targetName: string;
168
182
  readonly reason: string;
@@ -174,9 +188,13 @@ export declare class InvalidMetadataError extends DiError {
174
188
  * @since 0.3.16-canary.0
175
189
  */
176
190
  export declare class MissingMetadataError extends DiError {
191
+ readonly name = "MissingMetadataError";
177
192
  readonly code = "MISSING_METADATA";
178
193
  readonly targetName: string;
179
- constructor(targetName: string);
194
+ constructor(targetName: string, inheritedFrom?: {
195
+ readonly baseName: string;
196
+ readonly dependencyCount: number;
197
+ });
180
198
  }
181
199
  /**
182
200
  * A sync `load()` given a module that needs async setup.
@@ -184,6 +202,7 @@ export declare class MissingMetadataError extends DiError {
184
202
  * @since 0.3.16-canary.0
185
203
  */
186
204
  export declare class AsyncModuleLoadError extends DiError {
205
+ readonly name = "AsyncModuleLoadError";
187
206
  readonly code = "ASYNC_MODULE_LOAD";
188
207
  readonly moduleName: string;
189
208
  constructor(moduleName: string);
@@ -194,6 +213,7 @@ export declare class AsyncModuleLoadError extends DiError {
194
213
  * @since 0.3.16-canary.0
195
214
  */
196
215
  export declare class SyncDisposalNotSupportedError extends DiError {
216
+ readonly name = "SyncDisposalNotSupportedError";
197
217
  readonly code = "SYNC_DISPOSAL_NOT_SUPPORTED";
198
218
  constructor();
199
219
  }
@@ -203,6 +223,7 @@ export declare class SyncDisposalNotSupportedError extends DiError {
203
223
  * @since 0.3.16-canary.0
204
224
  */
205
225
  export declare class MissingScopeContextError extends DiError {
226
+ readonly name = "MissingScopeContextError";
206
227
  readonly code = "MISSING_SCOPE_CONTEXT";
207
228
  readonly tokenName: string;
208
229
  constructor(tokenName: string);
@@ -217,6 +238,7 @@ export declare class MissingScopeContextError extends DiError {
217
238
  * @since 0.3.16-canary.0
218
239
  */
219
240
  export declare class MissingContainerContextError extends DiError {
241
+ readonly name = "MissingContainerContextError";
220
242
  readonly code = "MISSING_CONTAINER_CONTEXT";
221
243
  /** The class being constructed, or `undefined` when it has no readable name. */
222
244
  readonly className: string | undefined;
@@ -224,14 +246,16 @@ export declare class MissingContainerContextError extends DiError {
224
246
  constructor(className: string | undefined, accessorName: string | symbol);
225
247
  }
226
248
  /**
227
- * A second `to*()` on a chain that already registered its binding.
249
+ * A slot step or a second `to*()` on a chain that already registered its binding.
228
250
  *
229
- * @remarks A chain is its binding, so it registers exactly once; a token bound twice is two `bind()`
230
- * calls, the second of which displaces the first under slot last-wins.
251
+ * @remarks A chain is its binding and registers exactly once, in its final shape, so its slot is
252
+ * settled by `to*()`; a token bound twice is two `bind()` calls, the second of which displaces the
253
+ * first under slot last-wins.
231
254
  *
232
255
  * @since 0.10.0
233
256
  */
234
257
  export declare class ChainAlreadyRegisteredError extends DiError {
258
+ readonly name = "ChainAlreadyRegisteredError";
235
259
  readonly code = "CHAIN_ALREADY_REGISTERED";
236
260
  readonly tokenName: string;
237
261
  constructor(tokenName: string);
@@ -245,20 +269,22 @@ export declare class ChainAlreadyRegisteredError extends DiError {
245
269
  * @since 0.10.0
246
270
  */
247
271
  export declare class ManyBindingSlotError extends DiError {
272
+ readonly name = "ManyBindingSlotError";
248
273
  readonly code = "MANY_BINDING_SLOT";
249
274
  readonly tokenName: string;
250
275
  constructor(tokenName: string);
251
276
  }
252
277
  /**
253
- * A fluent chain was refined before a `to*()` call gave it a binding to refine.
278
+ * A scope, a lifecycle hook or `id()` asked of a fluent chain before a `to*()` call registered its binding.
254
279
  *
255
280
  * @remarks The builder types make this unreachable from TypeScript — `bind()` returns
256
- * `BindToBuilder`, which exposes only `to*()`. It exists for JavaScript callers and for anyone who
257
- * casts past the types, so the misuse fails loudly instead of mutating nothing.
281
+ * `BindToBuilder`, which exposes only the slot steps and `to*()`. It exists for JavaScript callers and
282
+ * for anyone who casts past the types, so the misuse fails loudly instead of mutating nothing.
258
283
  *
259
284
  * @since 0.10.0
260
285
  */
261
286
  export declare class ChainNotRegisteredError extends DiError {
287
+ readonly name = "ChainNotRegisteredError";
262
288
  readonly code = "CHAIN_NOT_REGISTERED";
263
289
  readonly tokenName: string;
264
290
  constructor(tokenName: string);
@@ -269,6 +295,7 @@ export declare class ChainNotRegisteredError extends DiError {
269
295
  * @since 0.3.16-canary.0
270
296
  */
271
297
  export declare class RebindUnboundTokenError extends DiError {
298
+ readonly name = "RebindUnboundTokenError";
272
299
  readonly code = "REBIND_UNBOUND_TOKEN";
273
300
  readonly tokenName: string;
274
301
  constructor(tokenName: string);
@@ -279,6 +306,7 @@ export declare class RebindUnboundTokenError extends DiError {
279
306
  * @since 0.5.0-canary.9
280
307
  */
281
308
  export declare class SelfBindingRequiresClassError extends DiError {
309
+ readonly name = "SelfBindingRequiresClassError";
282
310
  readonly code = "SELF_BINDING_REQUIRES_CLASS";
283
311
  readonly tokenName: string;
284
312
  constructor(tokenName: string);
@@ -293,17 +321,63 @@ export declare class SelfBindingRequiresClassError extends DiError {
293
321
  * @since 0.6.0
294
322
  */
295
323
  export declare class StaticMemberDecoratorError extends DiError {
324
+ readonly name = "StaticMemberDecoratorError";
296
325
  readonly code = "STATIC_MEMBER_DECORATOR";
297
326
  readonly decoratorName: string;
298
327
  readonly memberName: string;
299
328
  constructor(decoratorName: string, memberName: string);
300
329
  }
330
+ /**
331
+ * A `@postConstruct` or `@preDestroy` on a method whose key is a symbol, which the lifecycle reader cannot name.
332
+ *
333
+ * @remarks Reported at decoration rather than at resolve, so the error points at the declaration
334
+ * instead of a `MetadataReader` the caller never configured.
335
+ *
336
+ * @since 0.11.0
337
+ */
338
+ export declare class SymbolKeyedLifecycleError extends DiError {
339
+ readonly name = "SymbolKeyedLifecycleError";
340
+ readonly code = "SYMBOL_KEYED_LIFECYCLE";
341
+ readonly decoratorName: string;
342
+ readonly memberName: string;
343
+ constructor(decoratorName: string, memberName: string);
344
+ }
345
+ /**
346
+ * A decorator handed no metadata object, because the runtime has no `Symbol.metadata` to key one by.
347
+ *
348
+ * @remarks TypeScript compiles `context.metadata` to `undefined` when `Symbol.metadata` is missing, so
349
+ * the fix is installing it before any decorated class is defined — the key this library reads.
350
+ *
351
+ * @since 0.11.0
352
+ */
353
+ export declare class MissingDecoratorMetadataError extends DiError {
354
+ readonly name = "MissingDecoratorMetadataError";
355
+ readonly code = "MISSING_DECORATOR_METADATA";
356
+ readonly decoratorName: string;
357
+ constructor(decoratorName: string);
358
+ }
359
+ /**
360
+ * A `binding()` definition no chain could spell: no strategy, several, or a key its strategy does not allow.
361
+ *
362
+ * @remarks Raised where the declaration is written, for callers the compiler cannot reach, so a
363
+ * declared module that was built can always be loaded.
364
+ *
365
+ * @since 0.11.0
366
+ */
367
+ export declare class InvalidBindingDeclarationError extends DiError {
368
+ readonly name = "InvalidBindingDeclarationError";
369
+ readonly code = "INVALID_BINDING_DECLARATION";
370
+ readonly tokenName: string;
371
+ readonly reason: string;
372
+ constructor(tokenName: string, reason: string);
373
+ }
301
374
  /**
302
375
  * An operation attempted on a container that has already been disposed.
303
376
  *
304
377
  * @since 0.3.16-canary.0
305
378
  */
306
379
  export declare class DisposedContainerError extends DiError {
380
+ readonly name = "DisposedContainerError";
307
381
  readonly code = "DISPOSED_CONTAINER";
308
382
  constructor();
309
383
  }
@@ -313,6 +387,7 @@ export declare class DisposedContainerError extends DiError {
313
387
  * @since 0.3.16-canary.0
314
388
  */
315
389
  export declare class AsyncActivationError extends DiError {
390
+ readonly name = "AsyncActivationError";
316
391
  readonly code = "ASYNC_ACTIVATION";
317
392
  readonly tokenName: string;
318
393
  readonly hookKind: "postConstruct" | "onActivation";
@@ -5,10 +5,6 @@ import { slotName } from "#core/tag";
5
5
  * @since 0.3.16-canary.0
6
6
  */
7
7
  export class DiError extends Error {
8
- constructor(message) {
9
- super(message);
10
- this.name = this.constructor.name;
11
- }
12
8
  }
13
9
  /**
14
10
  * An internal assertion failure — a library bug, never caller misuse.
@@ -16,6 +12,7 @@ export class DiError extends Error {
16
12
  * @since 0.3.16-canary.0
17
13
  */
18
14
  export class InternalError extends DiError {
15
+ name = "InternalError";
19
16
  code = "INTERNAL_ERROR";
20
17
  constructor(message) {
21
18
  super(message);
@@ -27,6 +24,7 @@ export class InternalError extends DiError {
27
24
  * @since 0.3.16-canary.0
28
25
  */
29
26
  export class TokenNotBoundError extends DiError {
27
+ name = "TokenNotBoundError";
30
28
  code = "TOKEN_NOT_BOUND";
31
29
  tokenName;
32
30
  constructor(tokenName) {
@@ -75,6 +73,7 @@ function describeResolveOptions(options) {
75
73
  * @since 0.3.16-canary.0
76
74
  */
77
75
  export class NoMatchingBindingError extends DiError {
76
+ name = "NoMatchingBindingError";
78
77
  code = "NO_MATCHING_BINDING";
79
78
  tokenName;
80
79
  options;
@@ -94,6 +93,7 @@ export class NoMatchingBindingError extends DiError {
94
93
  * @since 0.3.16-canary.0
95
94
  */
96
95
  export class AmbiguousBindingError extends DiError {
96
+ name = "AmbiguousBindingError";
97
97
  code = "AMBIGUOUS_BINDING";
98
98
  tokenName;
99
99
  candidateIds;
@@ -109,6 +109,7 @@ export class AmbiguousBindingError extends DiError {
109
109
  * @since 0.3.16-canary.0
110
110
  */
111
111
  export class CircularDependencyError extends DiError {
112
+ name = "CircularDependencyError";
112
113
  code = "CIRCULAR_DEPENDENCY";
113
114
  cycle;
114
115
  constructor(cycle) {
@@ -122,6 +123,7 @@ export class CircularDependencyError extends DiError {
122
123
  * @since 0.3.16-canary.0
123
124
  */
124
125
  export class AsyncResolutionError extends DiError {
126
+ name = "AsyncResolutionError";
125
127
  code = "ASYNC_RESOLUTION";
126
128
  /** The token the caller asked for — what `resolveAsync` has to be called with. */
127
129
  tokenName;
@@ -141,6 +143,7 @@ export class AsyncResolutionError extends DiError {
141
143
  * @since 0.3.16-canary.0
142
144
  */
143
145
  export class AsyncDeactivationError extends DiError {
146
+ name = "AsyncDeactivationError";
144
147
  code = "ASYNC_DEACTIVATION";
145
148
  tokenName;
146
149
  constructor(tokenName) {
@@ -154,6 +157,7 @@ export class AsyncDeactivationError extends DiError {
154
157
  * @since 0.3.16-canary.0
155
158
  */
156
159
  export class ScopeViolationError extends DiError {
160
+ name = "ScopeViolationError";
157
161
  code = "SCOPE_VIOLATION";
158
162
  details;
159
163
  constructor(details) {
@@ -171,6 +175,7 @@ export class ScopeViolationError extends DiError {
171
175
  * @since 0.6.0
172
176
  */
173
177
  export class EmptyTagCriteriaError extends DiError {
178
+ name = "EmptyTagCriteriaError";
174
179
  code = "EMPTY_TAG_CRITERIA";
175
180
  helperName;
176
181
  constructor(helperName) {
@@ -188,6 +193,7 @@ export class EmptyTagCriteriaError extends DiError {
188
193
  * @since 0.6.0
189
194
  */
190
195
  export class UnreachableConstraintError extends DiError {
196
+ name = "UnreachableConstraintError";
191
197
  code = "UNREACHABLE_CONSTRAINT";
192
198
  tokenName;
193
199
  requiredName;
@@ -215,13 +221,19 @@ export class UnreachableConstraintError extends DiError {
215
221
  * @since 0.6.0
216
222
  */
217
223
  export class UnreachableLifecycleHookError extends DiError {
224
+ name = "UnreachableLifecycleHookError";
218
225
  code = "UNREACHABLE_LIFECYCLE_HOOK";
219
226
  tokenName;
220
227
  phase;
221
- constructor(tokenName, phase) {
222
- super(`${phase}() is registered for '${tokenName}', which nothing is bound to in this container or its ancestors, so the hook can never run. Bind the token, or — if '${tokenName}' is a class you bound as an implementation via .to(${tokenName}) — register the hook against the token you bound instead.`);
228
+ /** Nothing binds the token, or — for a deactivation hook — every binding it has is transient or scoped. */
229
+ reason;
230
+ constructor(tokenName, phase, reason = "unbound") {
231
+ super(reason === "unbound"
232
+ ? `${phase}() is registered for '${tokenName}', which nothing is bound to in this container or its ancestors, so the hook can never run. Bind the token, or — if '${tokenName}' is a class you bound as an implementation via .to(${tokenName}) — register the hook against the token you bound instead.`
233
+ : `${phase}() is registered for '${tokenName}', whose every binding in this container and its ancestors is transient or scoped, so the hook can never run: only a singleton or a constant is deactivated. Make one of its bindings a singleton, or drop the hook.`);
223
234
  this.tokenName = tokenName;
224
235
  this.phase = phase;
236
+ this.reason = reason;
225
237
  }
226
238
  }
227
239
  /**
@@ -234,6 +246,7 @@ export class UnreachableLifecycleHookError extends DiError {
234
246
  * @since 0.6.0
235
247
  */
236
248
  export class InvalidMetadataError extends DiError {
249
+ name = "InvalidMetadataError";
237
250
  code = "INVALID_METADATA";
238
251
  targetName;
239
252
  reason;
@@ -249,10 +262,13 @@ export class InvalidMetadataError extends DiError {
249
262
  * @since 0.3.16-canary.0
250
263
  */
251
264
  export class MissingMetadataError extends DiError {
265
+ name = "MissingMetadataError";
252
266
  code = "MISSING_METADATA";
253
267
  targetName;
254
- constructor(targetName) {
255
- super(`Class '${targetName}' is missing @injectable() decorator. Add @injectable([...deps]) or use toDynamic()/toResolved() instead.`);
268
+ constructor(targetName, inheritedFrom) {
269
+ super(inheritedFrom === undefined
270
+ ? `Class '${targetName}' is missing @injectable() decorator. Add @injectable([...deps]) or use toDynamic()/toResolved() instead.`
271
+ : `Class '${targetName}' inherits ${String(inheritedFrom.dependencyCount)} declared constructor ${inheritedFrom.dependencyCount === 1 ? "dependency" : "dependencies"} from '${inheritedFrom.baseName}' but declares none of its own. Add @injectable([...deps]) to '${targetName}' — @injectable([]) if it takes none — or bind it with toDynamic()/toResolved().`);
256
272
  this.targetName = targetName;
257
273
  }
258
274
  }
@@ -262,6 +278,7 @@ export class MissingMetadataError extends DiError {
262
278
  * @since 0.3.16-canary.0
263
279
  */
264
280
  export class AsyncModuleLoadError extends DiError {
281
+ name = "AsyncModuleLoadError";
265
282
  code = "ASYNC_MODULE_LOAD";
266
283
  moduleName;
267
284
  constructor(moduleName) {
@@ -275,6 +292,7 @@ export class AsyncModuleLoadError extends DiError {
275
292
  * @since 0.3.16-canary.0
276
293
  */
277
294
  export class SyncDisposalNotSupportedError extends DiError {
295
+ name = "SyncDisposalNotSupportedError";
278
296
  code = "SYNC_DISPOSAL_NOT_SUPPORTED";
279
297
  constructor() {
280
298
  super("Container cannot be disposed synchronously because onDeactivation handlers may be async. Use `await using` or call container.dispose() explicitly.");
@@ -286,6 +304,7 @@ export class SyncDisposalNotSupportedError extends DiError {
286
304
  * @since 0.3.16-canary.0
287
305
  */
288
306
  export class MissingScopeContextError extends DiError {
307
+ name = "MissingScopeContextError";
289
308
  code = "MISSING_SCOPE_CONTEXT";
290
309
  tokenName;
291
310
  constructor(tokenName) {
@@ -303,6 +322,7 @@ export class MissingScopeContextError extends DiError {
303
322
  * @since 0.3.16-canary.0
304
323
  */
305
324
  export class MissingContainerContextError extends DiError {
325
+ name = "MissingContainerContextError";
306
326
  code = "MISSING_CONTAINER_CONTEXT";
307
327
  /** The class being constructed, or `undefined` when it has no readable name. */
308
328
  className;
@@ -310,25 +330,27 @@ export class MissingContainerContextError extends DiError {
310
330
  constructor(className, accessorName) {
311
331
  const accessor = `@inject accessor '${String(accessorName)}'`;
312
332
  super(className === undefined
313
- ? `An ${accessor} was initialized outside a container context. Resolve its class through a container, or open a context with runWithContainer().`
314
- : `Class '${className}' has an ${accessor} but was constructed outside a container context. Resolve it via container.resolve(${className}), or open a context with runWithContainer().`);
333
+ ? `An ${accessor} was initialized outside a container context. Resolve its class through a container, or open a synchronous context with runWithContainer() (the context does not survive an await).`
334
+ : `Class '${className}' has an ${accessor} but was constructed outside a container context. Resolve it via container.resolve(${className}), or open a synchronous context with runWithContainer() (the context does not survive an await).`);
315
335
  this.className = className;
316
336
  this.accessorName = accessorName;
317
337
  }
318
338
  }
319
339
  /**
320
- * A second `to*()` on a chain that already registered its binding.
340
+ * A slot step or a second `to*()` on a chain that already registered its binding.
321
341
  *
322
- * @remarks A chain is its binding, so it registers exactly once; a token bound twice is two `bind()`
323
- * calls, the second of which displaces the first under slot last-wins.
342
+ * @remarks A chain is its binding and registers exactly once, in its final shape, so its slot is
343
+ * settled by `to*()`; a token bound twice is two `bind()` calls, the second of which displaces the
344
+ * first under slot last-wins.
324
345
  *
325
346
  * @since 0.10.0
326
347
  */
327
348
  export class ChainAlreadyRegisteredError extends DiError {
349
+ name = "ChainAlreadyRegisteredError";
328
350
  code = "CHAIN_ALREADY_REGISTERED";
329
351
  tokenName;
330
352
  constructor(tokenName) {
331
- super(`The binding for token '${tokenName}' is already registered on this chain. Call bind() again to register another binding for the token.`);
353
+ super(`The binding for token '${tokenName}' is already registered on this chain, so its slot is final. Declare when*() and many() before to*(), or call bind() again to register another binding for the token.`);
332
354
  this.tokenName = tokenName;
333
355
  }
334
356
  }
@@ -341,6 +363,7 @@ export class ChainAlreadyRegisteredError extends DiError {
341
363
  * @since 0.10.0
342
364
  */
343
365
  export class ManyBindingSlotError extends DiError {
366
+ name = "ManyBindingSlotError";
344
367
  code = "MANY_BINDING_SLOT";
345
368
  tokenName;
346
369
  constructor(tokenName) {
@@ -349,15 +372,16 @@ export class ManyBindingSlotError extends DiError {
349
372
  }
350
373
  }
351
374
  /**
352
- * A fluent chain was refined before a `to*()` call gave it a binding to refine.
375
+ * A scope, a lifecycle hook or `id()` asked of a fluent chain before a `to*()` call registered its binding.
353
376
  *
354
377
  * @remarks The builder types make this unreachable from TypeScript — `bind()` returns
355
- * `BindToBuilder`, which exposes only `to*()`. It exists for JavaScript callers and for anyone who
356
- * casts past the types, so the misuse fails loudly instead of mutating nothing.
378
+ * `BindToBuilder`, which exposes only the slot steps and `to*()`. It exists for JavaScript callers and
379
+ * for anyone who casts past the types, so the misuse fails loudly instead of mutating nothing.
357
380
  *
358
381
  * @since 0.10.0
359
382
  */
360
383
  export class ChainNotRegisteredError extends DiError {
384
+ name = "ChainNotRegisteredError";
361
385
  code = "CHAIN_NOT_REGISTERED";
362
386
  tokenName;
363
387
  constructor(tokenName) {
@@ -371,6 +395,7 @@ export class ChainNotRegisteredError extends DiError {
371
395
  * @since 0.3.16-canary.0
372
396
  */
373
397
  export class RebindUnboundTokenError extends DiError {
398
+ name = "RebindUnboundTokenError";
374
399
  code = "REBIND_UNBOUND_TOKEN";
375
400
  tokenName;
376
401
  constructor(tokenName) {
@@ -384,6 +409,7 @@ export class RebindUnboundTokenError extends DiError {
384
409
  * @since 0.5.0-canary.9
385
410
  */
386
411
  export class SelfBindingRequiresClassError extends DiError {
412
+ name = "SelfBindingRequiresClassError";
387
413
  code = "SELF_BINDING_REQUIRES_CLASS";
388
414
  tokenName;
389
415
  constructor(tokenName) {
@@ -401,6 +427,7 @@ export class SelfBindingRequiresClassError extends DiError {
401
427
  * @since 0.6.0
402
428
  */
403
429
  export class StaticMemberDecoratorError extends DiError {
430
+ name = "StaticMemberDecoratorError";
404
431
  code = "STATIC_MEMBER_DECORATOR";
405
432
  decoratorName;
406
433
  memberName;
@@ -410,12 +437,68 @@ export class StaticMemberDecoratorError extends DiError {
410
437
  this.memberName = memberName;
411
438
  }
412
439
  }
440
+ /**
441
+ * A `@postConstruct` or `@preDestroy` on a method whose key is a symbol, which the lifecycle reader cannot name.
442
+ *
443
+ * @remarks Reported at decoration rather than at resolve, so the error points at the declaration
444
+ * instead of a `MetadataReader` the caller never configured.
445
+ *
446
+ * @since 0.11.0
447
+ */
448
+ export class SymbolKeyedLifecycleError extends DiError {
449
+ name = "SymbolKeyedLifecycleError";
450
+ code = "SYMBOL_KEYED_LIFECYCLE";
451
+ decoratorName;
452
+ memberName;
453
+ constructor(decoratorName, memberName) {
454
+ super(`@${decoratorName}() does not support a symbol-keyed method ('${memberName}'). Give the lifecycle method a string name.`);
455
+ this.decoratorName = decoratorName;
456
+ this.memberName = memberName;
457
+ }
458
+ }
459
+ /**
460
+ * A decorator handed no metadata object, because the runtime has no `Symbol.metadata` to key one by.
461
+ *
462
+ * @remarks TypeScript compiles `context.metadata` to `undefined` when `Symbol.metadata` is missing, so
463
+ * the fix is installing it before any decorated class is defined — the key this library reads.
464
+ *
465
+ * @since 0.11.0
466
+ */
467
+ export class MissingDecoratorMetadataError extends DiError {
468
+ name = "MissingDecoratorMetadataError";
469
+ code = "MISSING_DECORATOR_METADATA";
470
+ decoratorName;
471
+ constructor(decoratorName) {
472
+ super(`@${decoratorName}() received no decorator metadata: this runtime has no Symbol.metadata. Install it before any decorated class is defined, e.g. in a module imported first: (Symbol as { metadata?: symbol }).metadata ??= Symbol.for("Symbol.metadata");`);
473
+ this.decoratorName = decoratorName;
474
+ }
475
+ }
476
+ /**
477
+ * A `binding()` definition no chain could spell: no strategy, several, or a key its strategy does not allow.
478
+ *
479
+ * @remarks Raised where the declaration is written, for callers the compiler cannot reach, so a
480
+ * declared module that was built can always be loaded.
481
+ *
482
+ * @since 0.11.0
483
+ */
484
+ export class InvalidBindingDeclarationError extends DiError {
485
+ name = "InvalidBindingDeclarationError";
486
+ code = "INVALID_BINDING_DECLARATION";
487
+ tokenName;
488
+ reason;
489
+ constructor(tokenName, reason) {
490
+ super(`Invalid binding declaration for '${tokenName}': ${reason}.`);
491
+ this.tokenName = tokenName;
492
+ this.reason = reason;
493
+ }
494
+ }
413
495
  /**
414
496
  * An operation attempted on a container that has already been disposed.
415
497
  *
416
498
  * @since 0.3.16-canary.0
417
499
  */
418
500
  export class DisposedContainerError extends DiError {
501
+ name = "DisposedContainerError";
419
502
  code = "DISPOSED_CONTAINER";
420
503
  constructor() {
421
504
  super("Cannot perform operations on a disposed container.");
@@ -427,6 +510,7 @@ export class DisposedContainerError extends DiError {
427
510
  * @since 0.3.16-canary.0
428
511
  */
429
512
  export class AsyncActivationError extends DiError {
513
+ name = "AsyncActivationError";
430
514
  code = "ASYNC_ACTIVATION";
431
515
  tokenName;
432
516
  hookKind;
package/dist/index.d.ts CHANGED
@@ -3,30 +3,34 @@ export { token, tokenName } from "#core/token";
3
3
  export type { SlotNamesOf, Token } from "#core/token";
4
4
  export { coversTagKeys, NO_TAG_KEYS, slotName, tag, tagKeyMaskOf } from "#core/tag";
5
5
  export type { TagKey, TagKeyMask } from "#core/tag";
6
- export type { AliasBindingBuilder, BindToBuilder, BindingBuilder, ConstantBindingBuilder, ScopedBindingBuilder, SingletonBindingBuilder, SingletonLifecycleBuilder, SlotConstrainedBuilder, TransientBindingBuilder, } from "#core/binding";
6
+ export type { AliasBindingBuilder, BindToBuilder, BindingBuilder, ConstantBindingBuilder, ScopedBindingBuilder, SingletonBindingBuilder, SingletonLifecycleBuilder, SlotConstrainedBuilder, TransientBindingBuilder, } from "#core/binding-builders";
7
7
  export { Container } from "#container/container";
8
8
  export type { Container as ContainerInterface, ContainerOptions, ContainerStatic } from "#container/container";
9
- export { getActiveContainer, runWithContainer } from "#ambient/active-container";
10
- export { bindingSlotToResolveOptions, injectionSlotToResolveOptions, resolveOptionsForSlot, } from "#injection/resolve-options";
11
- export type { DependencySlot } from "#injection/resolve-options";
9
+ export { getActiveContainer, runWithContainer } from "#ambient-container";
10
+ export { bindingSlotToResolveOptions, injectionSlotToResolveOptions, resolveOptionsForSlot, } from "#injection/dependency-slot";
11
+ export type { DependencySlot } from "#injection/dependency-slot";
12
12
  export type { BindingSnapshot, ContainerSnapshot } from "#introspection/inspector";
13
+ export type { CandidateExplanation, CandidateVerdict, ExplainOptions, ExplanationOutcome, ExplanationStep, ResolutionExplanation, SelectionRule, } from "#introspection/explanation";
14
+ export type { CandidateRule } from "#resolution/select/candidates";
13
15
  export type { ContainerGraphJson, GraphEdge, GraphNode, GraphOptions } from "#introspection/dependency-graph";
14
16
  export { AsyncModule, isSyncModule, Module, SyncModule } from "#core/module";
15
17
  export type { AsyncModuleBuilder, ModuleBuilder } from "#core/module";
18
+ export { binding } from "#core/binding-declaration";
19
+ export type { BindingDeclaration, BindingDefinition } from "#core/binding-declaration";
16
20
  export { inject } from "#decorators/inject";
17
21
  export { injectAll, isInjectionDescriptor, optional } from "#injection/descriptor";
18
22
  export type { InjectionDescriptor, InjectOptions } from "#injection/descriptor";
19
23
  export { injectable } from "#decorators/injectable";
20
24
  export type { InjectableDependency, InjectableOptions } from "#decorators/injectable";
21
- export { postConstruct, preDestroy } from "#decorators/lifecycle-decorators";
25
+ export { postConstruct, preDestroy } from "#decorators/lifecycle";
22
26
  export { createAutoRegisterRegistry } from "#decorators/injectable";
23
27
  export type { AutoRegisterRegistry } from "#decorators/injectable";
24
- export { MetadataReaderToken } from "#metadata/metadata-reader-token";
25
- export type { ConstructorMetadata, LifecycleMetadata, MetadataReader, MutableLifecycleMetadata, ParamMetadata, } from "#metadata/metadata-types";
26
- export { defaultMetadataReader, SymbolMetadataReader } from "#metadata/symbol-metadata-reader";
28
+ export { MetadataReaderToken } from "#metadata/reader-token";
29
+ export type { ConstructorMetadata, LifecycleMetadata, MetadataReader, MutableLifecycleMetadata, ParamMetadata, } from "#metadata/types";
30
+ export { defaultMetadataReader, SymbolMetadataReader } from "#metadata/symbol-reader";
27
31
  export { whenAnyAncestorIs, whenAnyAncestorNamed, whenAnyAncestorTagged, whenAnyAncestorTaggedAll, whenNoAncestorIs, whenNoParentIs, whenParentIs, whenParentNamed, whenParentTagged, whenParentTaggedAll, } from "#resolution/select/constraints";
28
- export { AmbiguousBindingError, AsyncActivationError, AsyncDeactivationError, AsyncModuleLoadError, AsyncResolutionError, ChainAlreadyRegisteredError, ChainNotRegisteredError, ManyBindingSlotError, CircularDependencyError, DiError, DisposedContainerError, InternalError, InvalidMetadataError, MissingContainerContextError, MissingMetadataError, MissingScopeContextError, NoMatchingBindingError, RebindUnboundTokenError, ScopeViolationError, SelfBindingRequiresClassError, StaticMemberDecoratorError, SyncDisposalNotSupportedError, EmptyTagCriteriaError, TokenNotBoundError, UnreachableConstraintError, UnreachableLifecycleHookError, } from "#errors/errors";
29
- export type { ScopeViolationDetails } from "#errors/errors";
32
+ export { AmbiguousBindingError, AsyncActivationError, AsyncDeactivationError, AsyncModuleLoadError, AsyncResolutionError, ChainAlreadyRegisteredError, ChainNotRegisteredError, ManyBindingSlotError, CircularDependencyError, DiError, DisposedContainerError, InternalError, InvalidBindingDeclarationError, InvalidMetadataError, MissingContainerContextError, MissingDecoratorMetadataError, MissingMetadataError, MissingScopeContextError, NoMatchingBindingError, RebindUnboundTokenError, ScopeViolationError, SelfBindingRequiresClassError, StaticMemberDecoratorError, SymbolKeyedLifecycleError, SyncDisposalNotSupportedError, EmptyTagCriteriaError, TokenNotBoundError, UnreachableConstraintError, UnreachableLifecycleHookError, } from "#errors";
33
+ export type { ScopeViolationDetails } from "#errors";
30
34
  export { toDotGraph } from "#introspection/graph-adapters/dot";
31
35
  export { toCytoscapeGraph } from "#introspection/graph-adapters/cytoscape";
32
36
  export type { CytoscapeEdge, CytoscapeElements, CytoscapeNode } from "#introspection/graph-adapters/cytoscape";