@codefast/di 0.3.16-canary.2 → 0.4.0-canary.4

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 +16 -0
  2. package/README.md +5 -17
  3. package/dist/binding.d.mts +24 -24
  4. package/dist/constraints.d.mts +3 -3
  5. package/dist/container.d.mts +3 -3
  6. package/dist/container.mjs +89 -157
  7. package/dist/decorators/inject.d.mts +3 -2
  8. package/dist/decorators/inject.mjs +14 -41
  9. package/dist/decorators/injectable.mjs +4 -12
  10. package/dist/decorators/lifecycle-decorators.mjs +13 -74
  11. package/dist/dependency-graph.d.mts +1 -1
  12. package/dist/dependency-graph.mjs +6 -4
  13. package/dist/graph-adapters/cytoscape.d.mts +12 -12
  14. package/dist/graph-adapters/cytoscape.mjs +7 -7
  15. package/dist/graph-adapters/reactflow.d.mts +15 -15
  16. package/dist/graph-adapters/reactflow.mjs +6 -9
  17. package/dist/index.d.mts +6 -6
  18. package/dist/index.mjs +1 -1
  19. package/dist/inspector.d.mts +3 -2
  20. package/dist/inspector.mjs +7 -10
  21. package/dist/lifecycle.mjs +2 -12
  22. package/dist/metadata/metadata-keys.d.mts +8 -33
  23. package/dist/metadata/metadata-keys.mjs +8 -21
  24. package/dist/metadata/metadata-types.d.mts +5 -0
  25. package/dist/metadata/symbol-metadata-reader.d.mts +1 -0
  26. package/dist/metadata/symbol-metadata-reader.mjs +11 -33
  27. package/dist/module.mjs +1 -1
  28. package/dist/registry.mjs +3 -22
  29. package/dist/resolve-options.d.mts +2 -2
  30. package/dist/resolve-options.mjs +10 -8
  31. package/dist/resolver.d.mts +6 -1
  32. package/dist/resolver.mjs +15 -21
  33. package/dist/types.d.mts +10 -4
  34. package/package.json +40 -14
  35. package/src/binding-scope.ts +26 -0
  36. package/src/binding-select.ts +158 -0
  37. package/src/binding.ts +277 -0
  38. package/src/constraints.ts +121 -0
  39. package/src/constructor-type.ts +19 -0
  40. package/src/container.ts +1135 -0
  41. package/src/decorators/inject.ts +222 -0
  42. package/src/decorators/injectable.ts +85 -0
  43. package/src/decorators/lifecycle-decorators.ts +51 -0
  44. package/src/dependency-graph.ts +116 -0
  45. package/src/environment.ts +207 -0
  46. package/src/errors.ts +260 -0
  47. package/src/graph-adapters/cytoscape.ts +64 -0
  48. package/src/graph-adapters/dot.ts +22 -0
  49. package/src/graph-adapters/reactflow.ts +58 -0
  50. package/src/index.ts +101 -0
  51. package/src/inspector.ts +125 -0
  52. package/src/lifecycle.ts +217 -0
  53. package/src/metadata/metadata-keys.ts +25 -0
  54. package/src/metadata/metadata-reader-token.ts +8 -0
  55. package/src/metadata/metadata-types.ts +51 -0
  56. package/src/metadata/symbol-metadata-reader.ts +45 -0
  57. package/src/module.ts +93 -0
  58. package/src/registry.ts +232 -0
  59. package/src/resolve-options.ts +42 -0
  60. package/src/resolver.ts +1609 -0
  61. package/src/scope.ts +77 -0
  62. package/src/token.ts +40 -0
  63. package/src/types.ts +123 -0
  64. package/dist/graph-adapters/types.d.mts +0 -2
  65. package/dist/graph-adapters/types.mjs +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @codefast/di
2
2
 
3
+ ## 0.4.0-canary.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [#495](https://github.com/codefastlabs/codefast/pull/495) [`a66946d`](https://github.com/codefastlabs/codefast/commit/a66946d7b4f249927caea567232a9c05cd861020) Thanks [@thevuong](https://github.com/thevuong)! - Drop redundant type assertions in the container, resolver, decorators, and module wiring — behavior is unchanged; the types now flow without casts.
8
+
9
+ - [#495](https://github.com/codefastlabs/codefast/pull/495) [`fa338d6`](https://github.com/codefastlabs/codefast/commit/fa338d61fbfafb94beaa4d05d93d01e2c005cc91) Thanks [@thevuong](https://github.com/thevuong)! - Normalize import statement order and package.json key order repo-wide via the new oxfmt `sortImports`/`sortPackageJson` settings — purely mechanical, no runtime behavior change.
10
+
11
+ ## 0.3.16-canary.3
12
+
13
+ ### Patch Changes
14
+
15
+ - [`2a82188`](https://github.com/codefastlabs/codefast/commit/2a82188264c204b0b519b3324402ae962594d29b) Thanks [@thevuong](https://github.com/thevuong)! - feat(dev): enable source condition for zero-rebuild HMR in apps/docs
16
+
17
+ - [`bed2f30`](https://github.com/codefastlabs/codefast/commit/bed2f30df74128fe3b1a98dd9d03f6bb96099164) Thanks [@thevuong](https://github.com/thevuong)! - feat(web): refactor theme management to color scheme system
18
+
3
19
  ## 0.3.16-canary.2
4
20
 
5
21
  ### Patch Changes
package/README.md CHANGED
@@ -62,7 +62,7 @@ Type-safe, ESM-only dependency injection for modern TypeScript — built on TC39
62
62
 
63
63
  ## Requirements
64
64
 
65
- - Node.js `>= 22.0.0` (see `package.json` → `engines`)
65
+ - Node.js `>= 24.0.0` (see `package.json` → `engines`)
66
66
  - TypeScript `>= 5.2` with native Stage 3 decorators (TypeScript `5.9+` recommended for best inference, consistent with other Codefast packages)
67
67
 
68
68
  Enable native decorators in `tsconfig.json` — do **not** enable `experimentalDecorators`:
@@ -203,14 +203,9 @@ container.bind(DbToken).toDynamicAsync(async (ctx) => {
203
203
 
204
204
  container
205
205
  .bind(UserServiceToken)
206
- .toResolved((repository, config) => new UserService(repository, config), [
207
- UserRepository,
208
- AppConfigToken,
209
- ] as const);
206
+ .toResolved((repository, config) => new UserService(repository, config), [UserRepository, AppConfigToken] as const);
210
207
 
211
- container
212
- .bind(MetricsToken)
213
- .toResolvedAsync(async (db) => new MetricsCollector(db), [DbToken] as const);
208
+ container.bind(MetricsToken).toResolvedAsync(async (db) => new MetricsCollector(db), [DbToken] as const);
214
209
 
215
210
  container.bind(LegacyServiceToken).toAlias(NewServiceToken);
216
211
  ```
@@ -602,12 +597,7 @@ All errors extend `DiError` and expose a stable `code` property.
602
597
  | `TokenNotBoundError` | `"TOKEN_NOT_BOUND"` | Required token has no binding |
603
598
 
604
599
  ```typescript
605
- import {
606
- AmbiguousBindingError,
607
- DiError,
608
- ScopeViolationError,
609
- TokenNotBoundError,
610
- } from "@codefast/di";
600
+ import { AmbiguousBindingError, DiError, ScopeViolationError, TokenNotBoundError } from "@codefast/di";
611
601
 
612
602
  try {
613
603
  container.resolve(ServiceToken);
@@ -615,9 +605,7 @@ try {
615
605
  if (error instanceof TokenNotBoundError) {
616
606
  console.error(`Not registered: ${error.tokenName}`);
617
607
  } else if (error instanceof ScopeViolationError) {
618
- console.error(
619
- `Scope violation: ${error.details.consumerToken} → ${error.details.dependencyToken}`,
620
- );
608
+ console.error(`Scope violation: ${error.details.consumerToken} → ${error.details.dependencyToken}`);
621
609
  } else if (error instanceof AmbiguousBindingError) {
622
610
  console.error(`Ambiguous: ${error.tokenName}`, error.candidateIds);
623
611
  } else if (error instanceof DiError) {
@@ -1,6 +1,6 @@
1
1
  import { Constructor } from "./constructor-type.mjs";
2
2
  import { Token } from "./token.mjs";
3
- import { ActivationHandler, BindingIdentifier, BindingScope, ConstraintContext, DeactivationHandler, DependencyKey, ResolutionContext, TokenValue } from "./types.mjs";
3
+ import { ActivationHandler, BindingIdentifier, BindingScope, BindingTag, ConstraintContext, DeactivationHandler, DependencyKey, ResolutionContext, TokenValue } from "./types.mjs";
4
4
  import { InjectionDescriptor } from "./decorators/inject.mjs";
5
5
 
6
6
  //#region src/binding.d.ts
@@ -9,7 +9,7 @@ import { InjectionDescriptor } from "./decorators/inject.mjs";
9
9
  */
10
10
  interface BindingSlot {
11
11
  readonly name: string | undefined;
12
- readonly tags: ReadonlyArray<readonly [tag: string, value: unknown]>;
12
+ readonly tags: ReadonlyArray<BindingTag>;
13
13
  }
14
14
  /**
15
15
  * @since 0.3.16-canary.0
@@ -18,7 +18,10 @@ declare function bindingSlotEquals(left: BindingSlot, right: BindingSlot): boole
18
18
  /**
19
19
  * @since 0.3.16-canary.0
20
20
  */
21
- declare const DEFAULT_BINDING_SLOT: BindingSlot;
21
+ declare const DEFAULT_BINDING_SLOT: {
22
+ name: undefined;
23
+ tags: never[];
24
+ };
22
25
  /**
23
26
  * @since 0.3.16-canary.0
24
27
  */
@@ -29,6 +32,7 @@ interface BindingBase<Value> {
29
32
  readonly slot: BindingSlot;
30
33
  readonly predicate?: (ctx: ConstraintContext) => boolean;
31
34
  }
35
+ type BindingBaseKeys = keyof BindingBase<unknown>;
32
36
  /**
33
37
  * @since 0.3.16-canary.0
34
38
  */
@@ -107,11 +111,23 @@ type Binding<Value = unknown> = ClassBinding<Value> | DynamicBinding<Value> | Dy
107
111
  *
108
112
  * @since 0.3.16-canary.0
109
113
  */
110
- type PartialBinding<Value> = Omit<ClassBinding<Value>, "id" | "token" | "slot" | "predicate"> | Omit<DynamicBinding<Value>, "id" | "token" | "slot" | "predicate"> | Omit<DynamicAsyncBinding<Value>, "id" | "token" | "slot" | "predicate"> | Omit<ResolvedBinding<Value>, "id" | "token" | "slot" | "predicate"> | Omit<ResolvedAsyncBinding<Value>, "id" | "token" | "slot" | "predicate"> | Omit<ConstantBinding<Value>, "id" | "token" | "slot" | "predicate"> | Omit<AliasBinding<Value>, "id" | "token" | "slot" | "predicate">;
114
+ type PartialBinding<Value> = Omit<ClassBinding<Value>, BindingBaseKeys> | Omit<DynamicBinding<Value>, BindingBaseKeys> | Omit<DynamicAsyncBinding<Value>, BindingBaseKeys> | Omit<ResolvedBinding<Value>, BindingBaseKeys> | Omit<ResolvedAsyncBinding<Value>, BindingBaseKeys> | Omit<ConstantBinding<Value>, BindingBaseKeys> | Omit<AliasBinding<Value>, BindingBaseKeys>;
111
115
  /**
112
116
  * @since 0.3.16-canary.0
113
117
  */
114
118
  declare function generateBindingId(): BindingIdentifier;
119
+ /**
120
+ * Common slot-constraint + id methods shared by all concrete binding builders.
121
+ *
122
+ * @since 0.3.16-canary.0
123
+ */
124
+ interface SlotConstrainedBuilder {
125
+ when(predicate: (ctx: ConstraintContext) => boolean): this;
126
+ whenNamed(name: string): this;
127
+ whenTagged(tag: string, value: unknown): this;
128
+ whenDefault(): this;
129
+ id(): BindingIdentifier;
130
+ }
115
131
  /**
116
132
  * @since 0.3.16-canary.0
117
133
  */
@@ -128,38 +144,22 @@ interface BindToBuilder<Value> {
128
144
  /**
129
145
  * @since 0.3.16-canary.0
130
146
  */
131
- interface BindingBuilder<Value> {
132
- when(predicate: (ctx: ConstraintContext) => boolean): this;
133
- whenNamed(name: string): this;
134
- whenTagged(tag: string, value: unknown): this;
135
- whenDefault(): this;
147
+ interface BindingBuilder<Value> extends SlotConstrainedBuilder {
136
148
  singleton(): SingletonBindingBuilder<Value>;
137
149
  transient(): TransientBindingBuilder<Value>;
138
150
  scoped(): ScopedBindingBuilder<Value>;
139
- id(): BindingIdentifier;
140
151
  }
141
152
  /**
142
153
  * @since 0.3.16-canary.0
143
154
  */
144
- interface ConstantBindingBuilder<Value> {
145
- when(predicate: (ctx: ConstraintContext) => boolean): this;
146
- whenNamed(name: string): this;
147
- whenTagged(tag: string, value: unknown): this;
148
- whenDefault(): this;
155
+ interface ConstantBindingBuilder<Value> extends SlotConstrainedBuilder {
149
156
  onActivation(fn: ActivationHandler<Value>): SingletonLifecycleBuilder<Value>;
150
157
  onDeactivation(fn: DeactivationHandler<Value>): SingletonLifecycleBuilder<Value>;
151
- id(): BindingIdentifier;
152
158
  }
153
159
  /**
154
160
  * @since 0.3.16-canary.0
155
161
  */
156
- interface AliasBindingBuilder {
157
- when(predicate: (ctx: ConstraintContext) => boolean): this;
158
- whenNamed(name: string): this;
159
- whenTagged(tag: string, value: unknown): this;
160
- whenDefault(): this;
161
- id(): BindingIdentifier;
162
- }
162
+ interface AliasBindingBuilder extends SlotConstrainedBuilder {}
163
163
  /**
164
164
  * @since 0.3.16-canary.0
165
165
  */
@@ -188,4 +188,4 @@ interface SingletonLifecycleBuilder<Value> {
188
188
  id(): BindingIdentifier;
189
189
  }
190
190
  //#endregion
191
- export { AliasBinding, AliasBindingBuilder, BindToBuilder, Binding, BindingBuilder, BindingSlot, ClassBinding, ConstantBinding, ConstantBindingBuilder, DEFAULT_BINDING_SLOT, DynamicAsyncBinding, DynamicBinding, PartialBinding, ResolvedAsyncBinding, ResolvedBinding, ScopedBindingBuilder, SingletonBindingBuilder, SingletonLifecycleBuilder, TransientBindingBuilder, bindingSlotEquals, bindingSlotToString, generateBindingId };
191
+ export { AliasBinding, AliasBindingBuilder, BindToBuilder, Binding, BindingBuilder, BindingSlot, ClassBinding, ConstantBinding, ConstantBindingBuilder, DEFAULT_BINDING_SLOT, DynamicAsyncBinding, DynamicBinding, PartialBinding, ResolvedAsyncBinding, ResolvedBinding, ScopedBindingBuilder, SingletonBindingBuilder, SingletonLifecycleBuilder, SlotConstrainedBuilder, TransientBindingBuilder, bindingSlotEquals, bindingSlotToString, generateBindingId };
@@ -1,6 +1,6 @@
1
1
  import { Constructor } from "./constructor-type.mjs";
2
2
  import { Token } from "./token.mjs";
3
- import { ConstraintContext } from "./types.mjs";
3
+ import { BindingTag, ConstraintContext } from "./types.mjs";
4
4
 
5
5
  //#region src/constraints.d.ts
6
6
  /**
@@ -42,7 +42,7 @@ declare function whenAnyAncestorTagged(tag: string, value: unknown): (constraint
42
42
  *
43
43
  * @since 0.3.16-canary.1
44
44
  */
45
- declare function whenParentTaggedAll(tags: ReadonlyArray<readonly [tag: string, value: unknown]>): (constraintContext: ConstraintContext) => boolean;
45
+ declare function whenParentTaggedAll(tags: ReadonlyArray<BindingTag>): (constraintContext: ConstraintContext) => boolean;
46
46
  /**
47
47
  * Matches when at least one ancestor slot carries **all** of the given tag pairs.
48
48
  * Equivalent to AND-composing multiple `whenAnyAncestorTagged` calls but evaluates
@@ -50,6 +50,6 @@ declare function whenParentTaggedAll(tags: ReadonlyArray<readonly [tag: string,
50
50
  *
51
51
  * @since 0.3.16-canary.1
52
52
  */
53
- declare function whenAnyAncestorTaggedAll(tags: ReadonlyArray<readonly [tag: string, value: unknown]>): (constraintContext: ConstraintContext) => boolean;
53
+ declare function whenAnyAncestorTaggedAll(tags: ReadonlyArray<BindingTag>): (constraintContext: ConstraintContext) => boolean;
54
54
  //#endregion
55
55
  export { whenAnyAncestorIs, whenAnyAncestorNamed, whenAnyAncestorTagged, whenAnyAncestorTaggedAll, whenNoAncestorIs, whenNoParentIs, whenParentIs, whenParentNamed, whenParentTagged, whenParentTaggedAll };
@@ -2,10 +2,10 @@ import { Constructor } from "./constructor-type.mjs";
2
2
  import { Token } from "./token.mjs";
3
3
  import { ActivationHandler, BindingIdentifier, DeactivationHandler, ResolveOptions } from "./types.mjs";
4
4
  import { BindToBuilder } from "./binding.mjs";
5
- import { AsyncModule, SyncModule } from "./module.mjs";
6
- import { BindingSnapshot, ContainerSnapshot } from "./inspector.mjs";
7
- import { ContainerGraphJson, GraphOptions } from "./dependency-graph.mjs";
8
5
  import { AutoRegisterRegistry } from "./decorators/injectable.mjs";
6
+ import { ContainerGraphJson, GraphOptions } from "./dependency-graph.mjs";
7
+ import { BindingSnapshot, ContainerSnapshot } from "./inspector.mjs";
8
+ import { AsyncModule, SyncModule } from "./module.mjs";
9
9
 
10
10
  //#region src/container.d.ts
11
11
  /**
@@ -2,17 +2,17 @@ import { effectiveBindingScope } from "./binding-scope.mjs";
2
2
  import { AsyncModuleLoadError, CircularDependencyError, DisposedContainerError, InternalError, RebindUnboundTokenError, ScopeViolationError, SyncDisposalNotSupportedError } from "./errors.mjs";
3
3
  import { DEFAULT_BINDING_SLOT, generateBindingId } from "./binding.mjs";
4
4
  import { tokenName } from "./token.mjs";
5
- import { BindingRegistry } from "./registry.mjs";
6
- import { ScopeManager } from "./scope.mjs";
7
- import { LifecycleManager } from "./lifecycle.mjs";
8
5
  import { bindingSlotToResolveOptions, injectionSlotToResolveOptions } from "./resolve-options.mjs";
9
- import { DependencyResolver } from "./resolver.mjs";
10
- import { Inspector } from "./inspector.mjs";
6
+ import { normalizeToDescriptor } from "./decorators/inject.mjs";
11
7
  import { buildDependencyGraph } from "./dependency-graph.mjs";
12
- import { defaultMetadataReader } from "./metadata/symbol-metadata-reader.mjs";
8
+ import { Inspector } from "./inspector.mjs";
9
+ import { LifecycleManager } from "./lifecycle.mjs";
13
10
  import { MetadataReaderToken } from "./metadata/metadata-reader-token.mjs";
14
- import { normalizeToDescriptor } from "./decorators/inject.mjs";
11
+ import { defaultMetadataReader } from "./metadata/symbol-metadata-reader.mjs";
15
12
  import { isSyncModule } from "./module.mjs";
13
+ import { BindingRegistry } from "./registry.mjs";
14
+ import { DependencyResolver } from "./resolver.mjs";
15
+ import { ScopeManager } from "./scope.mjs";
16
16
  //#region src/container.ts
17
17
  var DefaultContainer = class DefaultContainer {
18
18
  _disposed = false;
@@ -81,46 +81,45 @@ var DefaultContainer = class DefaultContainer {
81
81
  this._assertNotDisposed();
82
82
  this._unbindSync(tokenOrId);
83
83
  }
84
- _unbindSync(tokenOrId) {
85
- const bindings = this._getBindingsForTokenOrId(tokenOrId);
86
- for (const binding of bindings) {
84
+ /** Remove bindings from registry + scope and collect [binding, instance] pairs for deactivation. */
85
+ _collectDeactivationPairs(tokenOrId) {
86
+ const pairs = [];
87
+ for (const binding of this._getBindingsForTokenOrId(tokenOrId)) {
87
88
  this._registry.removeById(binding.id);
88
89
  if (this._scope.hasSingleton(binding.id)) {
89
- const instance = this._scope.getSingleton(binding.id);
90
+ pairs.push([binding, this._scope.getSingleton(binding.id)]);
90
91
  this._scope.deleteSingleton(binding.id);
91
- this._lifecycle.runDeactivationSync(binding, instance, this._getMetadataReader());
92
92
  }
93
93
  }
94
+ return pairs;
95
+ }
96
+ /** Drain singleton scope entries for a set of already-removed bindings. */
97
+ _drainSingletons(bindings) {
98
+ const pairs = [];
99
+ for (const binding of bindings) if (this._scope.hasSingleton(binding.id)) {
100
+ pairs.push([binding, this._scope.getSingleton(binding.id)]);
101
+ this._scope.deleteSingleton(binding.id);
102
+ }
103
+ return pairs;
104
+ }
105
+ _unbindSync(tokenOrId) {
106
+ const reader = this._getMetadataReader();
107
+ for (const [binding, instance] of this._collectDeactivationPairs(tokenOrId)) this._lifecycle.runDeactivationSync(binding, instance, reader);
94
108
  }
95
109
  async unbindAsync(tokenOrId) {
96
110
  this._assertNotDisposed();
97
- const bindings = this._getBindingsForTokenOrId(tokenOrId);
98
- for (const binding of bindings) {
99
- this._registry.removeById(binding.id);
100
- if (this._scope.hasSingleton(binding.id)) {
101
- const instance = this._scope.getSingleton(binding.id);
102
- this._scope.deleteSingleton(binding.id);
103
- await this._lifecycle.runDeactivation(binding, instance, this._getMetadataReader());
104
- }
105
- }
111
+ const reader = this._getMetadataReader();
112
+ for (const [binding, instance] of this._collectDeactivationPairs(tokenOrId)) await this._lifecycle.runDeactivation(binding, instance, reader);
106
113
  }
107
114
  unbindAll() {
108
115
  this._assertNotDisposed();
109
- const all = this._registry.clear();
110
- for (const binding of all) if (this._scope.hasSingleton(binding.id)) {
111
- const instance = this._scope.getSingleton(binding.id);
112
- this._scope.deleteSingleton(binding.id);
113
- this._lifecycle.runDeactivationSync(binding, instance, this._getMetadataReader());
114
- }
116
+ const reader = this._getMetadataReader();
117
+ for (const [binding, instance] of this._drainSingletons(this._registry.clear())) this._lifecycle.runDeactivationSync(binding, instance, reader);
115
118
  }
116
119
  async unbindAllAsync() {
117
120
  this._assertNotDisposed();
118
- const all = this._registry.clear();
119
- for (const binding of all) if (this._scope.hasSingleton(binding.id)) {
120
- const instance = this._scope.getSingleton(binding.id);
121
- this._scope.deleteSingleton(binding.id);
122
- await this._lifecycle.runDeactivation(binding, instance, this._getMetadataReader());
123
- }
121
+ const reader = this._getMetadataReader();
122
+ for (const [binding, instance] of this._drainSingletons(this._registry.clear())) await this._lifecycle.runDeactivation(binding, instance, reader);
124
123
  }
125
124
  rebind(token) {
126
125
  this._assertNotDisposed();
@@ -208,23 +207,29 @@ var DefaultContainer = class DefaultContainer {
208
207
  this._assertNotDisposed();
209
208
  for (const module of modules) this._unloadModuleSync(module);
210
209
  }
210
+ /** Unregister module bindings and collect [binding, instance] pairs for deactivation. */
211
+ _removeModuleBindings(ref) {
212
+ this._moduleRefs.delete(ref);
213
+ const ids = this._moduleBindingIds.get(ref) ?? [];
214
+ this._moduleBindingIds.delete(ref);
215
+ const pairs = [];
216
+ for (const id of ids) {
217
+ const binding = this._registry.getById(id);
218
+ if (binding !== void 0) {
219
+ this._registry.removeById(id);
220
+ if (this._scope.hasSingleton(id)) {
221
+ pairs.push([binding, this._scope.getSingleton(id)]);
222
+ this._scope.deleteSingleton(id);
223
+ }
224
+ }
225
+ }
226
+ return pairs;
227
+ }
211
228
  _unloadModuleSync(ref) {
212
229
  const count = this._moduleRefs.get(ref) ?? 0;
213
230
  if (count <= 1) {
214
- this._moduleRefs.delete(ref);
215
- const ids = this._moduleBindingIds.get(ref) ?? [];
216
- this._moduleBindingIds.delete(ref);
217
- for (const id of ids) {
218
- const binding = this._registry.getById(id);
219
- if (binding !== void 0) {
220
- this._registry.removeById(id);
221
- if (this._scope.hasSingleton(id)) {
222
- const instance = this._scope.getSingleton(id);
223
- this._scope.deleteSingleton(id);
224
- this._lifecycle.runDeactivationSync(binding, instance, this._getMetadataReader());
225
- }
226
- }
227
- }
231
+ const reader = this._getMetadataReader();
232
+ for (const [binding, instance] of this._removeModuleBindings(ref)) this._lifecycle.runDeactivationSync(binding, instance, reader);
228
233
  } else this._moduleRefs.set(ref, count - 1);
229
234
  }
230
235
  async unloadAsync(...modules) {
@@ -234,20 +239,8 @@ var DefaultContainer = class DefaultContainer {
234
239
  async _unloadModuleAsync(ref) {
235
240
  const count = this._moduleRefs.get(ref) ?? 0;
236
241
  if (count <= 1) {
237
- this._moduleRefs.delete(ref);
238
- const ids = this._moduleBindingIds.get(ref) ?? [];
239
- this._moduleBindingIds.delete(ref);
240
- for (const id of ids) {
241
- const binding = this._registry.getById(id);
242
- if (binding !== void 0) {
243
- this._registry.removeById(id);
244
- if (this._scope.hasSingleton(id)) {
245
- const instance = this._scope.getSingleton(id);
246
- this._scope.deleteSingleton(id);
247
- await this._lifecycle.runDeactivation(binding, instance, this._getMetadataReader());
248
- }
249
- }
250
- }
242
+ const reader = this._getMetadataReader();
243
+ for (const [binding, instance] of this._removeModuleBindings(ref)) await this._lifecycle.runDeactivation(binding, instance, reader);
251
244
  } else this._moduleRefs.set(ref, count - 1);
252
245
  }
253
246
  loadAutoRegistered(registry) {
@@ -478,6 +471,35 @@ function updateSlotTag(slot, tag, value) {
478
471
  tags: existing
479
472
  };
480
473
  }
474
+ var SlotBuilder = class {
475
+ _slot = DEFAULT_BINDING_SLOT;
476
+ _predicate;
477
+ _committed;
478
+ when(predicate) {
479
+ this._predicate = predicate;
480
+ this._doCommit();
481
+ return this;
482
+ }
483
+ whenNamed(name) {
484
+ this._slot = {
485
+ ...this._slot,
486
+ name
487
+ };
488
+ this._doCommit();
489
+ return this;
490
+ }
491
+ whenTagged(tag, value) {
492
+ this._slot = updateSlotTag(this._slot, tag, value);
493
+ this._doCommit();
494
+ return this;
495
+ }
496
+ whenDefault() {
497
+ return this;
498
+ }
499
+ id() {
500
+ return this._committed;
501
+ }
502
+ };
481
503
  var BindingEntry = class {
482
504
  _token;
483
505
  _commit;
@@ -539,21 +561,15 @@ var BindingEntry = class {
539
561
  return new AliasBuilder(this._token, target, this._commit);
540
562
  }
541
563
  };
542
- var ConstraintBuilder = class {
564
+ var ConstraintBuilder = class extends SlotBuilder {
543
565
  _token;
544
566
  _partial;
545
567
  _commit;
546
- _slot;
547
- _predicate;
548
- _committed;
549
568
  constructor(_token, _partial, _commit) {
569
+ super();
550
570
  this._token = _token;
551
571
  this._partial = _partial;
552
572
  this._commit = _commit;
553
- this._slot = {
554
- ...DEFAULT_BINDING_SLOT,
555
- tags: []
556
- };
557
573
  this._doCommit();
558
574
  }
559
575
  _doCommit() {
@@ -567,27 +583,6 @@ var ConstraintBuilder = class {
567
583
  };
568
584
  this._committed = this._commit(binding, previousId);
569
585
  }
570
- when(predicate) {
571
- this._predicate = predicate;
572
- this._doCommit();
573
- return this;
574
- }
575
- whenNamed(name) {
576
- this._slot = {
577
- ...this._slot,
578
- name
579
- };
580
- this._doCommit();
581
- return this;
582
- }
583
- whenTagged(tag, value) {
584
- this._slot = updateSlotTag(this._slot, tag, value);
585
- this._doCommit();
586
- return this;
587
- }
588
- whenDefault() {
589
- return this;
590
- }
591
586
  singleton() {
592
587
  const previousId = this._committed;
593
588
  this._committed = void 0;
@@ -612,9 +607,6 @@ var ConstraintBuilder = class {
612
607
  scope: "scoped"
613
608
  }, this._slot, this._predicate, this._commit, "scoped", previousId);
614
609
  }
615
- id() {
616
- return this._committed;
617
- }
618
610
  };
619
611
  var ScopeBuilder = class {
620
612
  _token;
@@ -664,23 +656,17 @@ var ScopeBuilder = class {
664
656
  return this._committed;
665
657
  }
666
658
  };
667
- var ConstantBuilder = class {
659
+ var ConstantBuilder = class extends SlotBuilder {
668
660
  _token;
669
661
  _value;
670
662
  _commit;
671
- _slot;
672
- _predicate;
673
663
  _onActivation;
674
664
  _onDeactivation;
675
- _committed;
676
665
  constructor(_token, _value, _commit) {
666
+ super();
677
667
  this._token = _token;
678
668
  this._value = _value;
679
669
  this._commit = _commit;
680
- this._slot = {
681
- ...DEFAULT_BINDING_SLOT,
682
- tags: []
683
- };
684
670
  this._doCommit();
685
671
  }
686
672
  _doCommit() {
@@ -698,27 +684,6 @@ var ConstantBuilder = class {
698
684
  };
699
685
  this._committed = this._commit(binding, previousId);
700
686
  }
701
- when(predicate) {
702
- this._predicate = predicate;
703
- this._doCommit();
704
- return this;
705
- }
706
- whenNamed(name) {
707
- this._slot = {
708
- ...this._slot,
709
- name
710
- };
711
- this._doCommit();
712
- return this;
713
- }
714
- whenTagged(tag, value) {
715
- this._slot = updateSlotTag(this._slot, tag, value);
716
- this._doCommit();
717
- return this;
718
- }
719
- whenDefault() {
720
- return this;
721
- }
722
687
  onActivation(fn) {
723
688
  this._onActivation = fn;
724
689
  this._doCommit();
@@ -729,25 +694,16 @@ var ConstantBuilder = class {
729
694
  this._doCommit();
730
695
  return this;
731
696
  }
732
- id() {
733
- return this._committed;
734
- }
735
697
  };
736
- var AliasBuilder = class {
698
+ var AliasBuilder = class extends SlotBuilder {
737
699
  _token;
738
700
  _target;
739
701
  _commit;
740
- _slot;
741
- _predicate;
742
- _committed;
743
702
  constructor(_token, _target, _commit) {
703
+ super();
744
704
  this._token = _token;
745
705
  this._target = _target;
746
706
  this._commit = _commit;
747
- this._slot = {
748
- ...DEFAULT_BINDING_SLOT,
749
- tags: []
750
- };
751
707
  this._doCommit();
752
708
  }
753
709
  _doCommit() {
@@ -762,30 +718,6 @@ var AliasBuilder = class {
762
718
  };
763
719
  this._committed = this._commit(binding, previousId);
764
720
  }
765
- when(predicate) {
766
- this._predicate = predicate;
767
- this._doCommit();
768
- return this;
769
- }
770
- whenNamed(name) {
771
- this._slot = {
772
- ...this._slot,
773
- name
774
- };
775
- this._doCommit();
776
- return this;
777
- }
778
- whenTagged(tag, value) {
779
- this._slot = updateSlotTag(this._slot, tag, value);
780
- this._doCommit();
781
- return this;
782
- }
783
- whenDefault() {
784
- return this;
785
- }
786
- id() {
787
- return this._committed;
788
- }
789
721
  };
790
722
  /**
791
723
  * @since 0.3.16-canary.0
@@ -1,5 +1,6 @@
1
1
  import { Constructor } from "../constructor-type.mjs";
2
2
  import { Token } from "../token.mjs";
3
+ import { BindingTag } from "../types.mjs";
3
4
 
4
5
  //#region src/decorators/inject.d.ts
5
6
  /**
@@ -7,7 +8,7 @@ import { Token } from "../token.mjs";
7
8
  */
8
9
  interface InjectOptions {
9
10
  name?: string;
10
- tags?: ReadonlyArray<readonly [tag: string, value: unknown]>;
11
+ tags?: ReadonlyArray<BindingTag>;
11
12
  }
12
13
  /**
13
14
  * @since 0.3.16-canary.0
@@ -17,7 +18,7 @@ interface InjectionDescriptor<Value = unknown> {
17
18
  readonly optional: boolean;
18
19
  readonly multi: boolean;
19
20
  readonly name?: string;
20
- readonly tags?: ReadonlyArray<readonly [string, unknown]>;
21
+ readonly tags?: ReadonlyArray<BindingTag>;
21
22
  }
22
23
  /**
23
24
  * @since 0.3.16-canary.0