@codefast/di 0.3.16-canary.0 → 0.3.16-canary.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @codefast/di
2
2
 
3
+ ## 0.3.16-canary.1
4
+
3
5
  ## 0.3.16-canary.0
4
6
 
5
7
  ## 0.3.15
package/README.md CHANGED
@@ -203,7 +203,10 @@ container.bind(DbToken).toDynamicAsync(async (ctx) => {
203
203
 
204
204
  container
205
205
  .bind(UserServiceToken)
206
- .toResolved((repo, cfg) => new UserService(repo, cfg), [UserRepository, AppConfigToken] as const);
206
+ .toResolved((repository, config) => new UserService(repository, config), [
207
+ UserRepository,
208
+ AppConfigToken,
209
+ ] as const);
207
210
 
208
211
  container
209
212
  .bind(MetricsToken)
@@ -8,12 +8,12 @@ import { Binding } from "./binding.mjs";
8
8
  *
9
9
  * @since 0.3.16-canary.0
10
10
  */
11
- declare function selectBinding(bindings: readonly Binding[], hint: ResolveOptions | undefined, ctx: ConstraintContext, tName: string): Binding | undefined;
11
+ declare function selectBinding(bindings: ReadonlyArray<Binding>, hint: ResolveOptions | undefined, ctx: ConstraintContext, tName: string): Binding | undefined;
12
12
  /**
13
13
  * Select all candidates matching hint + predicates.
14
14
  *
15
15
  * @since 0.3.16-canary.0
16
16
  */
17
- declare function selectAllBindings(bindings: readonly Binding[], hint: ResolveOptions | undefined, ctx: ConstraintContext): Binding[];
17
+ declare function selectAllBindings(bindings: ReadonlyArray<Binding>, hint: ResolveOptions | undefined, ctx: ConstraintContext): Array<Binding>;
18
18
  //#endregion
19
19
  export { selectAllBindings, selectBinding };
@@ -64,8 +64,8 @@ interface DynamicAsyncBinding<Value> extends BindingBase<Value> {
64
64
  */
65
65
  interface ResolvedBinding<Value> extends BindingBase<Value> {
66
66
  readonly kind: "resolved";
67
- readonly factory: (...args: unknown[]) => Value;
68
- readonly deps: readonly InjectionDescriptor[];
67
+ readonly factory: (...args: Array<unknown>) => Value;
68
+ readonly deps: ReadonlyArray<InjectionDescriptor>;
69
69
  readonly scope: BindingScope;
70
70
  readonly onActivation?: ActivationHandler<Value>;
71
71
  readonly onDeactivation?: DeactivationHandler<Value>;
@@ -75,8 +75,8 @@ interface ResolvedBinding<Value> extends BindingBase<Value> {
75
75
  */
76
76
  interface ResolvedAsyncBinding<Value> extends BindingBase<Value> {
77
77
  readonly kind: "resolved-async";
78
- readonly factory: (...args: unknown[]) => Promise<Value>;
79
- readonly deps: readonly InjectionDescriptor[];
78
+ readonly factory: (...args: Array<unknown>) => Promise<Value>;
79
+ readonly deps: ReadonlyArray<InjectionDescriptor>;
80
80
  readonly scope: BindingScope;
81
81
  readonly onActivation?: ActivationHandler<Value>;
82
82
  readonly onDeactivation?: DeactivationHandler<Value>;
@@ -121,8 +121,8 @@ interface BindToBuilder<Value> {
121
121
  toConstantValue(value: Value): ConstantBindingBuilder<Value>;
122
122
  toDynamic(factory: (ctx: ResolutionContext) => Value): BindingBuilder<Value>;
123
123
  toDynamicAsync(factory: (ctx: ResolutionContext) => Promise<Value>): BindingBuilder<Value>;
124
- toResolved<const Deps extends readonly DependencyKey[]>(factory: (...args: { [K in keyof Deps]: TokenValue<NoInfer<Deps>[K]> }) => Value, deps: Deps): BindingBuilder<Value>;
125
- toResolvedAsync<const Deps extends readonly DependencyKey[]>(factory: (...args: { [K in keyof Deps]: TokenValue<NoInfer<Deps>[K]> }) => Promise<Value>, deps: Deps): BindingBuilder<Value>;
124
+ toResolved<const Deps extends ReadonlyArray<DependencyKey>>(factory: (...args: { [K in keyof Deps]: TokenValue<NoInfer<Deps>[K]> }) => Value, deps: Deps): BindingBuilder<Value>;
125
+ toResolvedAsync<const Deps extends ReadonlyArray<DependencyKey>>(factory: (...args: { [K in keyof Deps]: TokenValue<NoInfer<Deps>[K]> }) => Promise<Value>, deps: Deps): BindingBuilder<Value>;
126
126
  toAlias(target: Token<Value> | Constructor<Value>): AliasBindingBuilder;
127
127
  }
128
128
  /**
@@ -6,34 +6,50 @@ import { ConstraintContext } from "./types.mjs";
6
6
  /**
7
7
  * @since 0.3.16-canary.0
8
8
  */
9
- declare function whenParentIs(t: Token<unknown> | Constructor): (ctx: ConstraintContext) => boolean;
9
+ declare function whenParentIs(token: Token<unknown> | Constructor): (constraintContext: ConstraintContext) => boolean;
10
10
  /**
11
11
  * @since 0.3.16-canary.0
12
12
  */
13
- declare function whenNoParentIs(t: Token<unknown> | Constructor): (ctx: ConstraintContext) => boolean;
13
+ declare function whenNoParentIs(token: Token<unknown> | Constructor): (constraintContext: ConstraintContext) => boolean;
14
14
  /**
15
15
  * @since 0.3.16-canary.0
16
16
  */
17
- declare function whenAnyAncestorIs(t: Token<unknown> | Constructor): (ctx: ConstraintContext) => boolean;
17
+ declare function whenAnyAncestorIs(token: Token<unknown> | Constructor): (constraintContext: ConstraintContext) => boolean;
18
18
  /**
19
19
  * @since 0.3.16-canary.0
20
20
  */
21
- declare function whenNoAncestorIs(t: Token<unknown> | Constructor): (ctx: ConstraintContext) => boolean;
21
+ declare function whenNoAncestorIs(token: Token<unknown> | Constructor): (constraintContext: ConstraintContext) => boolean;
22
22
  /**
23
23
  * @since 0.3.16-canary.0
24
24
  */
25
- declare function whenParentNamed(name: string): (ctx: ConstraintContext) => boolean;
25
+ declare function whenParentNamed(name: string): (constraintContext: ConstraintContext) => boolean;
26
26
  /**
27
27
  * @since 0.3.16-canary.0
28
28
  */
29
- declare function whenAnyAncestorNamed(name: string): (ctx: ConstraintContext) => boolean;
29
+ declare function whenAnyAncestorNamed(name: string): (constraintContext: ConstraintContext) => boolean;
30
30
  /**
31
31
  * @since 0.3.16-canary.0
32
32
  */
33
- declare function whenParentTagged(tag: string, value: unknown): (ctx: ConstraintContext) => boolean;
33
+ declare function whenParentTagged(tag: string, value: unknown): (constraintContext: ConstraintContext) => boolean;
34
34
  /**
35
35
  * @since 0.3.16-canary.0
36
36
  */
37
- declare function whenAnyAncestorTagged(tag: string, value: unknown): (ctx: ConstraintContext) => boolean;
37
+ declare function whenAnyAncestorTagged(tag: string, value: unknown): (constraintContext: ConstraintContext) => boolean;
38
+ /**
39
+ * Matches when the direct parent slot carries **all** of the given tag pairs.
40
+ * Equivalent to AND-composing multiple `whenParentTagged` calls but evaluates
41
+ * in a single predicate invocation — no intermediate closure allocations.
42
+ *
43
+ * @since 0.3.16-canary.1
44
+ */
45
+ declare function whenParentTaggedAll(tags: ReadonlyArray<readonly [tag: string, value: unknown]>): (constraintContext: ConstraintContext) => boolean;
46
+ /**
47
+ * Matches when at least one ancestor slot carries **all** of the given tag pairs.
48
+ * Equivalent to AND-composing multiple `whenAnyAncestorTagged` calls but evaluates
49
+ * in a single predicate invocation — no intermediate closure allocations.
50
+ *
51
+ * @since 0.3.16-canary.1
52
+ */
53
+ declare function whenAnyAncestorTaggedAll(tags: ReadonlyArray<readonly [tag: string, value: unknown]>): (constraintContext: ConstraintContext) => boolean;
38
54
  //#endregion
39
- export { whenAnyAncestorIs, whenAnyAncestorNamed, whenAnyAncestorTagged, whenNoAncestorIs, whenNoParentIs, whenParentIs, whenParentNamed, whenParentTagged };
55
+ export { whenAnyAncestorIs, whenAnyAncestorNamed, whenAnyAncestorTagged, whenAnyAncestorTaggedAll, whenNoAncestorIs, whenNoParentIs, whenParentIs, whenParentNamed, whenParentTagged, whenParentTaggedAll };
@@ -1,59 +1,87 @@
1
1
  import { tokenName } from "./token.mjs";
2
2
  //#region src/constraints.ts
3
- function tokenNameOf(t) {
4
- return tokenName(t);
3
+ function tokenNameOf(token) {
4
+ return tokenName(token);
5
5
  }
6
6
  /**
7
7
  * @since 0.3.16-canary.0
8
8
  */
9
- function whenParentIs(t) {
10
- const name = tokenNameOf(t);
11
- return (ctx) => ctx.parent !== void 0 && ctx.parent.tokenName === name;
9
+ function whenParentIs(token) {
10
+ const tokenDisplayName = tokenNameOf(token);
11
+ return (constraintContext) => constraintContext.parent !== void 0 && constraintContext.parent.tokenName === tokenDisplayName;
12
12
  }
13
13
  /**
14
14
  * @since 0.3.16-canary.0
15
15
  */
16
- function whenNoParentIs(t) {
17
- const name = tokenNameOf(t);
18
- return (ctx) => ctx.parent === void 0 || ctx.parent.tokenName !== name;
16
+ function whenNoParentIs(token) {
17
+ const tokenDisplayName = tokenNameOf(token);
18
+ return (constraintContext) => constraintContext.parent === void 0 || constraintContext.parent.tokenName !== tokenDisplayName;
19
19
  }
20
20
  /**
21
21
  * @since 0.3.16-canary.0
22
22
  */
23
- function whenAnyAncestorIs(t) {
24
- const name = tokenNameOf(t);
25
- return (ctx) => ctx.ancestors.some((f) => f.tokenName === name);
23
+ function whenAnyAncestorIs(token) {
24
+ const tokenDisplayName = tokenNameOf(token);
25
+ return (constraintContext) => constraintContext.ancestors.some((ancestorFrame) => ancestorFrame.tokenName === tokenDisplayName);
26
26
  }
27
27
  /**
28
28
  * @since 0.3.16-canary.0
29
29
  */
30
- function whenNoAncestorIs(t) {
31
- const name = tokenNameOf(t);
32
- return (ctx) => ctx.ancestors.every((f) => f.tokenName !== name);
30
+ function whenNoAncestorIs(token) {
31
+ const tokenDisplayName = tokenNameOf(token);
32
+ return (constraintContext) => constraintContext.ancestors.every((ancestorFrame) => ancestorFrame.tokenName !== tokenDisplayName);
33
33
  }
34
34
  /**
35
35
  * @since 0.3.16-canary.0
36
36
  */
37
37
  function whenParentNamed(name) {
38
- return (ctx) => ctx.parent !== void 0 && ctx.parent.slot.name === name;
38
+ return (constraintContext) => constraintContext.parent !== void 0 && constraintContext.parent.slot.name === name;
39
39
  }
40
40
  /**
41
41
  * @since 0.3.16-canary.0
42
42
  */
43
43
  function whenAnyAncestorNamed(name) {
44
- return (ctx) => ctx.ancestors.some((f) => f.slot.name === name);
44
+ return (constraintContext) => constraintContext.ancestors.some((ancestorFrame) => ancestorFrame.slot.name === name);
45
45
  }
46
46
  /**
47
47
  * @since 0.3.16-canary.0
48
48
  */
49
49
  function whenParentTagged(tag, value) {
50
- return (ctx) => ctx.parent !== void 0 && ctx.parent.slot.tags.some(([t, v]) => t === tag && Object.is(v, value));
50
+ return (constraintContext) => constraintContext.parent !== void 0 && constraintContext.parent.slot.tags.some(([tagKey, tagValue]) => tagKey === tag && Object.is(tagValue, value));
51
51
  }
52
52
  /**
53
53
  * @since 0.3.16-canary.0
54
54
  */
55
55
  function whenAnyAncestorTagged(tag, value) {
56
- return (ctx) => ctx.ancestors.some((f) => f.slot.tags.some(([t, v]) => t === tag && Object.is(v, value)));
56
+ return (constraintContext) => constraintContext.ancestors.some((ancestorFrame) => ancestorFrame.slot.tags.some(([tagKey, tagValue]) => tagKey === tag && Object.is(tagValue, value)));
57
+ }
58
+ /**
59
+ * Matches when the direct parent slot carries **all** of the given tag pairs.
60
+ * Equivalent to AND-composing multiple `whenParentTagged` calls but evaluates
61
+ * in a single predicate invocation — no intermediate closure allocations.
62
+ *
63
+ * @since 0.3.16-canary.1
64
+ */
65
+ function whenParentTaggedAll(tags) {
66
+ return (constraintContext) => {
67
+ const { parent } = constraintContext;
68
+ if (parent === void 0) return false;
69
+ const { tags: parentTags } = parent.slot;
70
+ return tags.every(([tagKey, tagValue]) => parentTags.some(([k, v]) => k === tagKey && Object.is(v, tagValue)));
71
+ };
72
+ }
73
+ /**
74
+ * Matches when at least one ancestor slot carries **all** of the given tag pairs.
75
+ * Equivalent to AND-composing multiple `whenAnyAncestorTagged` calls but evaluates
76
+ * in a single predicate invocation — no intermediate closure allocations.
77
+ *
78
+ * @since 0.3.16-canary.1
79
+ */
80
+ function whenAnyAncestorTaggedAll(tags) {
81
+ return (constraintContext) => constraintContext.ancestors.some((frame) => {
82
+ const { tags: frameTags } = frame.slot;
83
+ return tags.every(([tagKey, tagValue]) => frameTags.some(([k, v]) => k === tagKey && Object.is(v, tagValue)));
84
+ });
57
85
  }
58
86
  //#endregion
59
- export { whenAnyAncestorIs, whenAnyAncestorNamed, whenAnyAncestorTagged, whenNoAncestorIs, whenNoParentIs, whenParentIs, whenParentNamed, whenParentTagged };
87
+ export { whenAnyAncestorIs, whenAnyAncestorNamed, whenAnyAncestorTagged, whenAnyAncestorTaggedAll, whenNoAncestorIs, whenNoParentIs, whenParentIs, whenParentNamed, whenParentTagged, whenParentTaggedAll };
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @since 0.3.16-canary.0
10
10
  */
11
- type Constructor<Value = unknown> = new (...args: never[]) => Value;
11
+ type Constructor<Value = unknown> = new (...args: Array<never>) => Value;
12
12
  /**
13
13
  * Class constructor as invoked by the resolver after metadata-driven
14
14
  * resolution of `unknown[]` dependencies — separate from {@link Constructor},
@@ -16,6 +16,6 @@ type Constructor<Value = unknown> = new (...args: never[]) => Value;
16
16
  *
17
17
  * @since 0.3.16-canary.0
18
18
  */
19
- type ConstructorInvocation = new (...args: unknown[]) => unknown;
19
+ type ConstructorInvocation = new (...args: Array<unknown>) => unknown;
20
20
  //#endregion
21
21
  export { Constructor, ConstructorInvocation };
@@ -19,9 +19,9 @@ interface Container {
19
19
  unbindAll(): void;
20
20
  unbindAllAsync(): Promise<void>;
21
21
  rebind<const Value>(token: Token<Value> | Constructor<Value>): BindToBuilder<Value>;
22
- load(...modules: SyncModule[]): void;
22
+ load(...modules: Array<SyncModule>): void;
23
23
  loadAsync(...modules: Array<SyncModule | AsyncModule>): Promise<void>;
24
- unload(...modules: SyncModule[]): void;
24
+ unload(...modules: Array<SyncModule>): void;
25
25
  unloadAsync(...modules: Array<SyncModule | AsyncModule>): Promise<void>;
26
26
  loadAutoRegistered(registry: AutoRegisterRegistry): number;
27
27
  onActivation<const Value>(token: Token<Value> | Constructor<Value>, handler: ActivationHandler<Value>): void;
@@ -30,8 +30,8 @@ interface Container {
30
30
  resolveAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value>;
31
31
  resolveOptional<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value | undefined;
32
32
  resolveOptionalAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value | undefined>;
33
- resolveAll<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value[];
34
- resolveAllAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value[]>;
33
+ resolveAll<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Array<Value>;
34
+ resolveAllAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Array<Value>>;
35
35
  createChild(): Container;
36
36
  dispose(): Promise<void>;
37
37
  [Symbol.asyncDispose](): Promise<void>;
@@ -40,7 +40,7 @@ interface Container {
40
40
  validate(): void;
41
41
  has(token: Token<unknown> | Constructor, hint?: ResolveOptions): boolean;
42
42
  hasOwn(token: Token<unknown> | Constructor, hint?: ResolveOptions): boolean;
43
- lookupBindings<const Value>(token: Token<Value> | Constructor<Value>): readonly BindingSnapshot[];
43
+ lookupBindings<const Value>(token: Token<Value> | Constructor<Value>): ReadonlyArray<BindingSnapshot>;
44
44
  inspect(): ContainerSnapshot;
45
45
  generateDependencyGraph(options?: GraphOptions): ContainerGraphJson;
46
46
  }
@@ -49,7 +49,7 @@ interface Container {
49
49
  */
50
50
  interface ContainerStatic {
51
51
  create(): Container;
52
- fromModules(...modules: SyncModule[]): Container;
52
+ fromModules(...modules: Array<SyncModule>): Container;
53
53
  fromModulesAsync(...modules: Array<SyncModule | AsyncModule>): Promise<Container>;
54
54
  }
55
55
  /**
@@ -1,11 +1,11 @@
1
1
  import { effectiveBindingScope } from "./binding-scope.mjs";
2
- import { DisposedContainerError, RebindUnboundTokenError, ScopeViolationError, SyncDisposalNotSupportedError } from "./errors.mjs";
2
+ import { AsyncModuleLoadError, CircularDependencyError, DisposedContainerError, InternalError, RebindUnboundTokenError, ScopeViolationError, SyncDisposalNotSupportedError } from "./errors.mjs";
3
3
  import { DEFAULT_SLOT, generateBindingId } from "./binding.mjs";
4
4
  import { tokenName } from "./token.mjs";
5
5
  import { BindingRegistry } from "./registry.mjs";
6
6
  import { ScopeManager } from "./scope.mjs";
7
7
  import { LifecycleManager } from "./lifecycle.mjs";
8
- import { slotKeyToResolveOptions } from "./resolve-options.mjs";
8
+ import { injectableSlotToResolveOptions, slotKeyToResolveOptions } from "./resolve-options.mjs";
9
9
  import { DependencyResolver } from "./resolver.mjs";
10
10
  import { Inspector } from "./inspector.mjs";
11
11
  import { buildDependencyGraph } from "./dependency-graph.mjs";
@@ -142,6 +142,7 @@ var DefaultContainer = class DefaultContainer {
142
142
  _loadSyncModules(modules) {
143
143
  const toLoad = this._collectModuleDeps(modules);
144
144
  for (const mod of toLoad) {
145
+ if (!isSyncModule(mod)) throw new AsyncModuleLoadError(mod.name);
145
146
  const ref = mod;
146
147
  const existing = this._moduleRefs.get(ref);
147
148
  if (existing !== void 0) {
@@ -332,43 +333,116 @@ var DefaultContainer = class DefaultContainer {
332
333
  const reader = this._getMetadataReader();
333
334
  const allBindings = this._registry.allBindings();
334
335
  for (const binding of allBindings) {
335
- if (binding.kind === "alias" || binding.kind === "constant" || binding.kind === "dynamic" || binding.kind === "dynamic-async") continue;
336
- const scope = effectiveBindingScope(binding);
337
- if (scope !== "singleton") continue;
338
- const deps = this._getDepsForBinding(binding, reader);
339
- for (const dep of deps) this._validateDep(tokenName(binding.token), scope, dep, [tokenName(binding.token)], reader);
336
+ if (!this._isSingletonStaticAnalyzableBinding(binding)) continue;
337
+ this._validateSingletonBindingGraph(binding, reader);
340
338
  }
341
339
  }
342
- _getDepsForBinding(binding, reader) {
343
- const result = [];
344
- if (binding.kind === "class") {
345
- const meta = reader.getConstructorMetadata(binding.target);
346
- if (meta !== void 0) for (const param of meta.params) {
347
- const depBindings = this._registry.getAll(param.token);
348
- for (const db of depBindings) if (db.kind !== "alias") result.push({
349
- token: param.token,
350
- scope: effectiveBindingScope(db)
340
+ _isSingletonStaticAnalyzableBinding(binding) {
341
+ if (effectiveBindingScope(binding) !== "singleton") return false;
342
+ return binding.kind === "class" || binding.kind === "resolved" || binding.kind === "resolved-async";
343
+ }
344
+ /**
345
+ * DFS over explicit constructor / `toResolved*` dependency edges. Follows `toAlias` chains to the
346
+ * terminal binding for scope checks (SPEC §6.9). Skips `toDynamic*` subtrees (opaque).
347
+ */
348
+ _validateSingletonBindingGraph(root, reader) {
349
+ const rootName = tokenName(root.token);
350
+ const dfs = (current, pathNames, pathBindingIds) => {
351
+ if (pathBindingIds.has(current.id)) return;
352
+ const extendedPathIds = new Set(pathBindingIds);
353
+ extendedPathIds.add(current.id);
354
+ for (const edge of this._collectStaticDependencyEdges(current, reader)) {
355
+ const { terminal, depTokenName } = edge;
356
+ const depScope = this._validationScopeFromTerminal(terminal);
357
+ if (depScope === "opaque") continue;
358
+ if (depScope === "scoped" || depScope === "transient") throw new ScopeViolationError({
359
+ consumerToken: rootName,
360
+ consumerScope: "singleton",
361
+ dependencyToken: depTokenName,
362
+ dependencyScope: depScope,
363
+ path: [...pathNames, depTokenName]
351
364
  });
365
+ if (terminal.kind === "class" || terminal.kind === "resolved" || terminal.kind === "resolved-async") dfs(terminal, [...pathNames, depTokenName], extendedPathIds);
352
366
  }
353
- } else if (binding.kind === "resolved" || binding.kind === "resolved-async") for (const dep of binding.deps) {
354
- const depBindings = this._registry.getAll(dep.token);
355
- for (const db of depBindings) if (db.kind !== "alias") result.push({
356
- token: dep.token,
357
- scope: effectiveBindingScope(db)
358
- });
367
+ };
368
+ dfs(root, [rootName], /* @__PURE__ */ new Set());
369
+ }
370
+ _validationScopeFromTerminal(terminal) {
371
+ switch (terminal.kind) {
372
+ case "constant": return "singleton";
373
+ case "dynamic":
374
+ case "dynamic-async": return "opaque";
375
+ case "class":
376
+ case "resolved":
377
+ case "resolved-async": return terminal.scope;
378
+ case "alias": throw new InternalError("validate: expected terminal binding after alias resolution");
379
+ default: return terminal;
359
380
  }
360
- return result;
361
381
  }
362
- _validateDep(consumerToken, consumerScope, dep, path, _reader) {
363
- if (consumerScope === "singleton") {
364
- if (dep.scope === "scoped" || dep.scope === "transient") throw new ScopeViolationError({
365
- consumerToken,
366
- consumerScope,
367
- dependencyToken: tokenName(dep.token),
368
- dependencyScope: dep.scope,
369
- path
382
+ _followAliasChainToTerminal(binding, hint) {
383
+ const cyclePath = [];
384
+ const seenAliasIds = /* @__PURE__ */ new Set();
385
+ let current = binding;
386
+ while (current !== void 0 && current.kind === "alias") {
387
+ if (seenAliasIds.has(current.id)) throw new CircularDependencyError(cyclePath);
388
+ seenAliasIds.add(current.id);
389
+ cyclePath.push(tokenName(current.token));
390
+ const nextToken = current.target;
391
+ const next = this._resolver.peekBindingForValidate(nextToken, hint);
392
+ if (next === void 0) return;
393
+ current = next.binding;
394
+ }
395
+ return current;
396
+ }
397
+ _collectStaticDependencyEdges(binding, reader) {
398
+ const edges = [];
399
+ const pushTerminal = (terminal, displayName) => {
400
+ if (terminal === void 0) return;
401
+ edges.push({
402
+ terminal,
403
+ depTokenName: displayName
370
404
  });
405
+ };
406
+ if (binding.kind === "class") {
407
+ const meta = reader.getConstructorMetadata(binding.target);
408
+ if (meta === void 0) return edges;
409
+ for (const param of meta.params) {
410
+ const paramHint = injectableSlotToResolveOptions(param);
411
+ if (param.optional) continue;
412
+ const tokenRef = param.token;
413
+ if (param.multi) {
414
+ const candidates = this._resolver.peekCandidateBindingsForValidate(tokenRef, paramHint);
415
+ for (const cand of candidates) {
416
+ const term = this._followAliasChainToTerminal(cand, paramHint);
417
+ pushTerminal(term, term !== void 0 ? tokenName(term.token) : "");
418
+ }
419
+ continue;
420
+ }
421
+ const found = paramHint === void 0 ? this._resolver.peekBindingForValidate(tokenRef, void 0) : this._resolver.peekBindingForValidate(tokenRef, paramHint);
422
+ if (found === void 0) continue;
423
+ const term = this._followAliasChainToTerminal(found.binding, paramHint);
424
+ pushTerminal(term, term !== void 0 ? tokenName(term.token) : "");
425
+ }
426
+ return edges;
371
427
  }
428
+ if (binding.kind === "resolved" || binding.kind === "resolved-async") for (const dep of binding.deps) {
429
+ const depHint = injectableSlotToResolveOptions(dep);
430
+ if (dep.optional) continue;
431
+ const tokenRef = dep.token;
432
+ if (dep.multi) {
433
+ const candidates = this._resolver.peekCandidateBindingsForValidate(tokenRef, depHint);
434
+ for (const cand of candidates) {
435
+ const term = this._followAliasChainToTerminal(cand, depHint);
436
+ pushTerminal(term, term !== void 0 ? tokenName(term.token) : "");
437
+ }
438
+ continue;
439
+ }
440
+ const found = depHint === void 0 ? this._resolver.peekBindingForValidate(tokenRef, void 0) : this._resolver.peekBindingForValidate(tokenRef, depHint);
441
+ if (found === void 0) continue;
442
+ const term = this._followAliasChainToTerminal(found.binding, depHint);
443
+ pushTerminal(term, term !== void 0 ? tokenName(term.token) : "");
444
+ }
445
+ return edges;
372
446
  }
373
447
  has(token, hint) {
374
448
  this._assertNotDisposed();
@@ -394,7 +468,19 @@ var DefaultContainer = class DefaultContainer {
394
468
  if (this._disposed) throw new DisposedContainerError();
395
469
  }
396
470
  };
471
+ function updateSlotTag(slot, tag, value) {
472
+ const existing = [...slot.tags];
473
+ const idx = existing.findIndex(([k]) => k === tag);
474
+ if (idx !== -1) existing[idx] = [tag, value];
475
+ else existing.push([tag, value]);
476
+ return {
477
+ ...slot,
478
+ tags: existing
479
+ };
480
+ }
397
481
  var BindToBuilderImpl = class {
482
+ _token;
483
+ _commit;
398
484
  constructor(_token, _commit) {
399
485
  this._token = _token;
400
486
  this._commit = _commit;
@@ -454,6 +540,9 @@ var BindToBuilderImpl = class {
454
540
  }
455
541
  };
456
542
  var BindingBuilderImpl = class {
543
+ _token;
544
+ _partial;
545
+ _commit;
457
546
  _slot;
458
547
  _predicate;
459
548
  _committed;
@@ -492,14 +581,7 @@ var BindingBuilderImpl = class {
492
581
  return this;
493
582
  }
494
583
  whenTagged(tag, value) {
495
- const existing = [...this._slot.tags];
496
- const idx = existing.findIndex(([k]) => k === tag);
497
- if (idx !== -1) existing[idx] = [tag, value];
498
- else existing.push([tag, value]);
499
- this._slot = {
500
- ...this._slot,
501
- tags: existing
502
- };
584
+ this._slot = updateSlotTag(this._slot, tag, value);
503
585
  this._doCommit();
504
586
  return this;
505
587
  }
@@ -535,6 +617,13 @@ var BindingBuilderImpl = class {
535
617
  }
536
618
  };
537
619
  var ScopeBuilderImpl = class {
620
+ _token;
621
+ _partial;
622
+ _slot;
623
+ _predicate;
624
+ _commit;
625
+ _scope;
626
+ _initialPreviousId;
538
627
  _onActivation;
539
628
  _onDeactivation;
540
629
  _committed;
@@ -576,6 +665,9 @@ var ScopeBuilderImpl = class {
576
665
  }
577
666
  };
578
667
  var ConstantBindingBuilderImpl = class {
668
+ _token;
669
+ _value;
670
+ _commit;
579
671
  _slot;
580
672
  _predicate;
581
673
  _onActivation;
@@ -620,14 +712,7 @@ var ConstantBindingBuilderImpl = class {
620
712
  return this;
621
713
  }
622
714
  whenTagged(tag, value) {
623
- const existing = [...this._slot.tags];
624
- const idx = existing.findIndex(([k]) => k === tag);
625
- if (idx !== -1) existing[idx] = [tag, value];
626
- else existing.push([tag, value]);
627
- this._slot = {
628
- ...this._slot,
629
- tags: existing
630
- };
715
+ this._slot = updateSlotTag(this._slot, tag, value);
631
716
  this._doCommit();
632
717
  return this;
633
718
  }
@@ -649,6 +734,9 @@ var ConstantBindingBuilderImpl = class {
649
734
  }
650
735
  };
651
736
  var AliasBindingBuilderImpl = class {
737
+ _token;
738
+ _target;
739
+ _commit;
652
740
  _slot;
653
741
  _predicate;
654
742
  _committed;
@@ -688,14 +776,7 @@ var AliasBindingBuilderImpl = class {
688
776
  return this;
689
777
  }
690
778
  whenTagged(tag, value) {
691
- const existing = [...this._slot.tags];
692
- const idx = existing.findIndex(([k]) => k === tag);
693
- if (idx !== -1) existing[idx] = [tag, value];
694
- else existing.push([tag, value]);
695
- this._slot = {
696
- ...this._slot,
697
- tags: existing
698
- };
779
+ this._slot = updateSlotTag(this._slot, tag, value);
699
780
  this._doCommit();
700
781
  return this;
701
782
  }
@@ -35,14 +35,14 @@ type ClassAccessorDecorator<This, Value> = (target: ClassAccessorDecoratorTarget
35
35
  /**
36
36
  * @since 0.3.16-canary.0
37
37
  */
38
- declare function inject<const Value>(t: Token<Value> | Constructor<Value>, options?: InjectOptions): InjectionDescriptor<Value> & ClassAccessorDecorator<unknown, Value>;
38
+ declare function inject<const Value>(token: Token<Value> | Constructor<Value>, options?: InjectOptions): InjectionDescriptor<Value> & ClassAccessorDecorator<unknown, Value>;
39
39
  /**
40
40
  * @since 0.3.16-canary.0
41
41
  */
42
- declare function optional<const Value>(t: Token<Value> | Constructor<Value>, options?: InjectOptions): InjectionDescriptor<Value | undefined>;
42
+ declare function optional<const Value>(token: Token<Value> | Constructor<Value>, options?: InjectOptions): InjectionDescriptor<Value | undefined>;
43
43
  /**
44
44
  * @since 0.3.16-canary.0
45
45
  */
46
- declare function injectAll<const Value>(t: Token<Value> | Constructor<Value>, options?: InjectOptions): InjectionDescriptor<Value[]>;
46
+ declare function injectAll<const Value>(token: Token<Value> | Constructor<Value>, options?: InjectOptions): InjectionDescriptor<Array<Value>>;
47
47
  //#endregion
48
48
  export { InjectOptions, InjectableDependency, InjectionDescriptor, inject, injectAll, isInjectionDescriptor, normalizeToDescriptor, optional };