@codefast/di 0.11.0 → 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.
- package/CHANGELOG.md +111 -0
- package/README.md +26 -12
- package/dist/container/{binding-builders.d.ts → binding-chain.d.ts} +21 -28
- package/dist/container/{binding-builders.js → binding-chain.js} +53 -163
- package/dist/container/container.d.ts +11 -2
- package/dist/container/container.js +107 -64
- package/dist/core/binding-builders.d.ts +114 -0
- package/dist/core/binding-declaration.d.ts +7 -0
- package/dist/core/binding-declaration.js +3 -2
- package/dist/core/binding.d.ts +21 -149
- package/dist/core/binding.js +15 -25
- package/dist/core/module.d.ts +1 -1
- package/dist/core/registry.d.ts +9 -24
- package/dist/core/registry.js +30 -155
- package/dist/core/tag.js +1 -1
- package/dist/decorators/inject.js +5 -5
- package/dist/decorators/injectable.js +2 -2
- package/dist/decorators/{lifecycle-decorators.js → lifecycle.js} +3 -3
- package/dist/decorators/{decorator-metadata.js → metadata-record.js} +1 -1
- package/dist/{errors/errors.d.ts → errors.d.ts} +7 -6
- package/dist/{errors/errors.js → errors.js} +8 -7
- package/dist/index.d.ts +12 -10
- package/dist/index.js +6 -6
- package/dist/injection/descriptor.d.ts +1 -1
- package/dist/introspection/dependency-graph.d.ts +1 -1
- package/dist/introspection/dependency-graph.js +3 -4
- package/dist/introspection/explanation.d.ts +101 -0
- package/dist/introspection/explanation.js +151 -0
- package/dist/introspection/inspector.d.ts +9 -2
- package/dist/introspection/inspector.js +25 -20
- package/dist/lifecycle/{lifecycle-manager.d.ts → hooks.d.ts} +9 -2
- package/dist/lifecycle/{lifecycle-manager.js → hooks.js} +45 -28
- package/dist/lifecycle/{scope-manager.d.ts → scopes.d.ts} +3 -5
- package/dist/lifecycle/{scope-manager.js → scopes.js} +8 -19
- package/dist/metadata/{metadata-reader-token.d.ts → reader-token.d.ts} +1 -1
- package/dist/metadata/{symbol-metadata-reader.d.ts → symbol-reader.d.ts} +1 -1
- package/dist/metadata/{symbol-metadata-reader.js → symbol-reader.js} +1 -1
- package/dist/metadata/{metadata-types.d.ts → types.d.ts} +1 -1
- package/dist/metadata/types.js +1 -0
- package/dist/metadata/verify.d.ts +43 -0
- package/dist/metadata/verify.js +133 -0
- package/dist/metadata/{verifying-metadata-reader.d.ts → verifying-reader.d.ts} +1 -1
- package/dist/metadata/{verifying-metadata-reader.js → verifying-reader.js} +2 -2
- package/dist/resolution/cache/activation-need.d.ts +1 -1
- package/dist/resolution/cache/activation-need.js +5 -1
- package/dist/resolution/cache/class-introspector.d.ts +27 -36
- package/dist/resolution/cache/class-introspector.js +61 -159
- package/dist/resolution/cache/{binding-lookup-cache.d.ts → lookup.d.ts} +7 -2
- package/dist/resolution/cache/{binding-lookup-cache.js → lookup.js} +40 -8
- package/dist/resolution/context.d.ts +1 -1
- package/dist/resolution/context.js +1 -1
- package/dist/resolution/{path/resolution-path.js → path.js} +1 -1
- package/dist/resolution/plan/{plan-codegen.d.ts → codegen.d.ts} +2 -4
- package/dist/resolution/plan/{plan-codegen.js → codegen.js} +2 -4
- package/dist/resolution/plan/{instantiation-plan.d.ts → compiler.d.ts} +1 -1
- package/dist/resolution/plan/{instantiation-plan.js → compiler.js} +4 -4
- package/dist/resolution/resolver.d.ts +7 -7
- package/dist/resolution/resolver.js +308 -121
- package/dist/resolution/select/{binding-select.d.ts → candidates.d.ts} +30 -0
- package/dist/resolution/select/{binding-select.js → candidates.js} +51 -10
- package/dist/resolution/select/constraints.js +1 -1
- package/package.json +79 -71
- package/dist/core/binding-scope.d.ts +0 -12
- package/dist/core/binding-scope.js +0 -12
- /package/dist/{ambient/active-container.d.ts → ambient-container.d.ts} +0 -0
- /package/dist/{ambient/active-container.js → ambient-container.js} +0 -0
- /package/dist/{metadata/metadata-types.js → core/binding-builders.js} +0 -0
- /package/dist/decorators/{lifecycle-decorators.d.ts → lifecycle.d.ts} +0 -0
- /package/dist/decorators/{decorator-metadata.d.ts → metadata-record.d.ts} +0 -0
- /package/dist/injection/{resolve-options.d.ts → dependency-slot.d.ts} +0 -0
- /package/dist/injection/{resolve-options.js → dependency-slot.js} +0 -0
- /package/dist/{errors → introspection}/diagnostics.d.ts +0 -0
- /package/dist/{errors → introspection}/diagnostics.js +0 -0
- /package/dist/metadata/{metadata-keys.d.ts → keys.d.ts} +0 -0
- /package/dist/metadata/{metadata-keys.js → keys.js} +0 -0
- /package/dist/metadata/{metadata-reader-token.js → reader-token.js} +0 -0
- /package/dist/resolution/{path/resolution-path.d.ts → path.d.ts} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { getActiveContainer, getAmbientResolution } from "#ambient
|
|
2
|
-
import { decoratorMetadataOf } from "#decorators/
|
|
3
|
-
import { MissingContainerContextError, StaticMemberDecoratorError } from "#errors
|
|
1
|
+
import { getActiveContainer, getAmbientResolution } from "#ambient-container";
|
|
2
|
+
import { decoratorMetadataOf } from "#decorators/metadata-record";
|
|
3
|
+
import { MissingContainerContextError, StaticMemberDecoratorError } from "#errors";
|
|
4
|
+
import { injectionSlotToResolveOptions } from "#injection/dependency-slot";
|
|
4
5
|
import { buildInjectionDescriptor } from "#injection/descriptor";
|
|
5
|
-
import {
|
|
6
|
-
import { INJECT_ACCESSOR_KEY } from "#metadata/metadata-keys";
|
|
6
|
+
import { INJECT_ACCESSOR_KEY } from "#metadata/keys";
|
|
7
7
|
/**
|
|
8
8
|
* The name of the class being constructed, or `undefined` when there is none to report.
|
|
9
9
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { decoratorMetadataOf } from "#decorators/
|
|
1
|
+
import { decoratorMetadataOf } from "#decorators/metadata-record";
|
|
2
2
|
import { normalizeToDescriptor } from "#injection/descriptor";
|
|
3
|
-
import { INJECTABLE_KEY } from "#metadata/
|
|
3
|
+
import { INJECTABLE_KEY } from "#metadata/keys";
|
|
4
4
|
/**
|
|
5
5
|
* Creates an empty auto-register registry.
|
|
6
6
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { decoratorMetadataOf } from "#decorators/
|
|
2
|
-
import { StaticMemberDecoratorError, SymbolKeyedLifecycleError } from "#errors
|
|
3
|
-
import { LIFECYCLE_KEY } from "#metadata/
|
|
1
|
+
import { decoratorMetadataOf } from "#decorators/metadata-record";
|
|
2
|
+
import { StaticMemberDecoratorError, SymbolKeyedLifecycleError } from "#errors";
|
|
3
|
+
import { LIFECYCLE_KEY } from "#metadata/keys";
|
|
4
4
|
/** Records the decorated method under one lifecycle phase; both decorators differ only in that phase. */
|
|
5
5
|
function recordLifecycleMethod(phase) {
|
|
6
6
|
return function (target, context) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The metadata record a decorator writes into, checked once for every decorator the library ships.
|
|
3
3
|
*/
|
|
4
|
-
import { MissingDecoratorMetadataError } from "#errors
|
|
4
|
+
import { MissingDecoratorMetadataError } from "#errors";
|
|
5
5
|
/**
|
|
6
6
|
* Returns the metadata record a decorator context carries.
|
|
7
7
|
*
|
|
@@ -246,10 +246,11 @@ export declare class MissingContainerContextError extends DiError {
|
|
|
246
246
|
constructor(className: string | undefined, accessorName: string | symbol);
|
|
247
247
|
}
|
|
248
248
|
/**
|
|
249
|
-
* 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.
|
|
250
250
|
*
|
|
251
|
-
* @remarks A chain is its binding
|
|
252
|
-
* calls, the second of which displaces the
|
|
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.
|
|
253
254
|
*
|
|
254
255
|
* @since 0.10.0
|
|
255
256
|
*/
|
|
@@ -274,11 +275,11 @@ export declare class ManyBindingSlotError extends DiError {
|
|
|
274
275
|
constructor(tokenName: string);
|
|
275
276
|
}
|
|
276
277
|
/**
|
|
277
|
-
* A fluent chain
|
|
278
|
+
* A scope, a lifecycle hook or `id()` asked of a fluent chain before a `to*()` call registered its binding.
|
|
278
279
|
*
|
|
279
280
|
* @remarks The builder types make this unreachable from TypeScript — `bind()` returns
|
|
280
|
-
* `BindToBuilder`, which exposes only `to*()`. It exists for JavaScript callers and
|
|
281
|
-
* 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.
|
|
282
283
|
*
|
|
283
284
|
* @since 0.10.0
|
|
284
285
|
*/
|
|
@@ -337,10 +337,11 @@ export class MissingContainerContextError extends DiError {
|
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
339
|
/**
|
|
340
|
-
* 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.
|
|
341
341
|
*
|
|
342
|
-
* @remarks A chain is its binding
|
|
343
|
-
* calls, the second of which displaces the
|
|
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.
|
|
344
345
|
*
|
|
345
346
|
* @since 0.10.0
|
|
346
347
|
*/
|
|
@@ -349,7 +350,7 @@ export class ChainAlreadyRegisteredError extends DiError {
|
|
|
349
350
|
code = "CHAIN_ALREADY_REGISTERED";
|
|
350
351
|
tokenName;
|
|
351
352
|
constructor(tokenName) {
|
|
352
|
-
super(`The binding for token '${tokenName}' is already registered on this chain.
|
|
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.`);
|
|
353
354
|
this.tokenName = tokenName;
|
|
354
355
|
}
|
|
355
356
|
}
|
|
@@ -371,11 +372,11 @@ export class ManyBindingSlotError extends DiError {
|
|
|
371
372
|
}
|
|
372
373
|
}
|
|
373
374
|
/**
|
|
374
|
-
* A fluent chain
|
|
375
|
+
* A scope, a lifecycle hook or `id()` asked of a fluent chain before a `to*()` call registered its binding.
|
|
375
376
|
*
|
|
376
377
|
* @remarks The builder types make this unreachable from TypeScript — `bind()` returns
|
|
377
|
-
* `BindToBuilder`, which exposes only `to*()`. It exists for JavaScript callers and
|
|
378
|
-
* 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.
|
|
379
380
|
*
|
|
380
381
|
* @since 0.10.0
|
|
381
382
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -3,13 +3,15 @@ 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
|
|
10
|
-
export { bindingSlotToResolveOptions, injectionSlotToResolveOptions, resolveOptionsForSlot, } from "#injection/
|
|
11
|
-
export type { DependencySlot } from "#injection/
|
|
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";
|
|
@@ -20,15 +22,15 @@ export { injectAll, isInjectionDescriptor, optional } from "#injection/descripto
|
|
|
20
22
|
export type { InjectionDescriptor, InjectOptions } from "#injection/descriptor";
|
|
21
23
|
export { injectable } from "#decorators/injectable";
|
|
22
24
|
export type { InjectableDependency, InjectableOptions } from "#decorators/injectable";
|
|
23
|
-
export { postConstruct, preDestroy } from "#decorators/lifecycle
|
|
25
|
+
export { postConstruct, preDestroy } from "#decorators/lifecycle";
|
|
24
26
|
export { createAutoRegisterRegistry } from "#decorators/injectable";
|
|
25
27
|
export type { AutoRegisterRegistry } from "#decorators/injectable";
|
|
26
|
-
export { MetadataReaderToken } from "#metadata/
|
|
27
|
-
export type { ConstructorMetadata, LifecycleMetadata, MetadataReader, MutableLifecycleMetadata, ParamMetadata, } from "#metadata/
|
|
28
|
-
export { defaultMetadataReader, SymbolMetadataReader } from "#metadata/symbol-
|
|
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";
|
|
29
31
|
export { whenAnyAncestorIs, whenAnyAncestorNamed, whenAnyAncestorTagged, whenAnyAncestorTaggedAll, whenNoAncestorIs, whenNoParentIs, whenParentIs, whenParentNamed, whenParentTagged, whenParentTaggedAll, } from "#resolution/select/constraints";
|
|
30
|
-
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
|
|
31
|
-
export type { ScopeViolationDetails } from "#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";
|
|
32
34
|
export { toDotGraph } from "#introspection/graph-adapters/dot";
|
|
33
35
|
export { toCytoscapeGraph } from "#introspection/graph-adapters/cytoscape";
|
|
34
36
|
export type { CytoscapeEdge, CytoscapeElements, CytoscapeNode } from "#introspection/graph-adapters/cytoscape";
|
package/dist/index.js
CHANGED
|
@@ -6,10 +6,10 @@ export { coversTagKeys, NO_TAG_KEYS, slotName, tag, tagKeyMaskOf } from "#core/t
|
|
|
6
6
|
export { Container } from "#container/container";
|
|
7
7
|
// Ambient container — the context an `@inject` accessor initializer resolves from. `resolution/context`
|
|
8
8
|
// stays internal: it hands out resolver callbacks, not public values.
|
|
9
|
-
export { getActiveContainer, runWithContainer } from "#ambient
|
|
9
|
+
export { getActiveContainer, runWithContainer } from "#ambient-container";
|
|
10
10
|
// `effectiveBindingScope` is deliberately absent: it reads a `Binding`, which is internal, and no
|
|
11
11
|
// public API hands one out. `BindingSnapshot.scope` and `GraphNode.scope` are the public answers.
|
|
12
|
-
export { bindingSlotToResolveOptions, injectionSlotToResolveOptions, resolveOptionsForSlot, } from "#injection/
|
|
12
|
+
export { bindingSlotToResolveOptions, injectionSlotToResolveOptions, resolveOptionsForSlot, } from "#injection/dependency-slot";
|
|
13
13
|
// Module
|
|
14
14
|
export { AsyncModule, isSyncModule, Module, SyncModule } from "#core/module";
|
|
15
15
|
export { binding } from "#core/binding-declaration";
|
|
@@ -17,16 +17,16 @@ export { binding } from "#core/binding-declaration";
|
|
|
17
17
|
export { inject } from "#decorators/inject";
|
|
18
18
|
export { injectAll, isInjectionDescriptor, optional } from "#injection/descriptor";
|
|
19
19
|
export { injectable } from "#decorators/injectable";
|
|
20
|
-
export { postConstruct, preDestroy } from "#decorators/lifecycle
|
|
20
|
+
export { postConstruct, preDestroy } from "#decorators/lifecycle";
|
|
21
21
|
// Auto-register
|
|
22
22
|
export { createAutoRegisterRegistry } from "#decorators/injectable";
|
|
23
23
|
// MetadataReader — everything a consumer needs to write one and pass it to Container.create()
|
|
24
|
-
export { MetadataReaderToken } from "#metadata/
|
|
25
|
-
export { defaultMetadataReader, SymbolMetadataReader } from "#metadata/symbol-
|
|
24
|
+
export { MetadataReaderToken } from "#metadata/reader-token";
|
|
25
|
+
export { defaultMetadataReader, SymbolMetadataReader } from "#metadata/symbol-reader";
|
|
26
26
|
// Constraints — contextual injection predicates for .when()
|
|
27
27
|
export { whenAnyAncestorIs, whenAnyAncestorNamed, whenAnyAncestorTagged, whenAnyAncestorTaggedAll, whenNoAncestorIs, whenNoParentIs, whenParentIs, whenParentNamed, whenParentTagged, whenParentTaggedAll, } from "#resolution/select/constraints";
|
|
28
28
|
// Errors
|
|
29
|
-
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
|
|
29
|
+
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";
|
|
30
30
|
// Graph adapters — render `generateDependencyGraph()` output for common viewers
|
|
31
31
|
export { toDotGraph } from "#introspection/graph-adapters/dot";
|
|
32
32
|
export { toCytoscapeGraph } from "#introspection/graph-adapters/cytoscape";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The one shape every declared dependency is normalised to, whatever channel declared it. */
|
|
2
2
|
import type { Token } from "#core/token";
|
|
3
3
|
import type { BindingTag, Constructor, TokenValue } from "#core/types";
|
|
4
|
-
import type { DependencySlot } from "#injection/
|
|
4
|
+
import type { DependencySlot } from "#injection/dependency-slot";
|
|
5
5
|
/**
|
|
6
6
|
* Slot-selection options — a name and tags — a declared dependency narrows its binding with.
|
|
7
7
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BindingRegistry } from "#core/registry";
|
|
2
2
|
import type { BindingKind, BindingScope } from "#core/types";
|
|
3
|
-
import type { MetadataReader } from "#metadata/
|
|
3
|
+
import type { MetadataReader } from "#metadata/types";
|
|
4
4
|
/**
|
|
5
5
|
* @remarks `kind`/`scope` are `"unbound"` for the placeholder node an optional, currently
|
|
6
6
|
* unsatisfied dependency points at.
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { stringifyTagValue } from "#core/binding";
|
|
2
|
-
import { effectiveBindingScope } from "#core/binding-scope";
|
|
1
|
+
import { effectiveBindingScope, stringifyTagValue } from "#core/binding";
|
|
3
2
|
import { slotName } from "#core/tag";
|
|
4
3
|
import { tokenName } from "#core/token";
|
|
5
|
-
import { bindingSlotToResolveOptions } from "#injection/
|
|
6
|
-
import { matchesSlot } from "#resolution/select/
|
|
4
|
+
import { bindingSlotToResolveOptions } from "#injection/dependency-slot";
|
|
5
|
+
import { matchesSlot } from "#resolution/select/candidates";
|
|
7
6
|
// ── Builder ──────────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
8
7
|
// Tokens are compared by object identity, and a name is free to repeat, so the graph mints its
|
|
9
8
|
// own per-process key. Weakly held: a discarded token takes its key with it.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { BindingRegistry } from "#core/registry";
|
|
2
|
+
import type { Token } from "#core/token";
|
|
3
|
+
import type { Constructor, ResolveOptions } from "#core/types";
|
|
4
|
+
import type { BindingSnapshot } from "#introspection/inspector";
|
|
5
|
+
import type { CandidateRule } from "#resolution/select/candidates";
|
|
6
|
+
/**
|
|
7
|
+
* A request to explain: the criteria a `resolve` would carry, and the resolutions it is nested in.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam Names - the slot names the token declares, as `ResolveOptions` narrows them
|
|
10
|
+
*
|
|
11
|
+
* @since 0.12.0
|
|
12
|
+
*/
|
|
13
|
+
export interface ExplainOptions<Names extends string = string> extends ResolveOptions<Names> {
|
|
14
|
+
/**
|
|
15
|
+
* The tokens whose resolution makes this request, outermost first, so a `when()` predicate reads the parent
|
|
16
|
+
* and ancestors it would read inside their factories.
|
|
17
|
+
*
|
|
18
|
+
* @remarks Each is selected as a request with no criteria, nested in the ones before it; one that selects
|
|
19
|
+
* nothing throws what its own `resolve` would.
|
|
20
|
+
*/
|
|
21
|
+
readonly ancestors?: ReadonlyArray<Token<unknown> | Constructor> | undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* What selection made of one binding: in the running, or out and why.
|
|
25
|
+
*
|
|
26
|
+
* @remarks `slot-mismatch`: the slot declares a criterion the request does not carry, or the request carries
|
|
27
|
+
* criteria and the slot is the default one. `predicate-refused`: the slot matched and the `when()` predicate
|
|
28
|
+
* returned `false`. `collection-member`: a `many()` binding, which only `resolveAll` takes.
|
|
29
|
+
*
|
|
30
|
+
* @since 0.12.0
|
|
31
|
+
*/
|
|
32
|
+
export type CandidateVerdict = "eligible" | "slot-mismatch" | "predicate-refused" | "collection-member";
|
|
33
|
+
/**
|
|
34
|
+
* The rule that settled one registry's answer.
|
|
35
|
+
*
|
|
36
|
+
* @remarks The four candidate rules of `CandidateRule`, plus `default-alias`: no slot matched, and the token's
|
|
37
|
+
* default-slot alias forwards the request's criteria to its target.
|
|
38
|
+
*
|
|
39
|
+
* @since 0.12.0
|
|
40
|
+
*/
|
|
41
|
+
export type SelectionRule = CandidateRule | "default-alias";
|
|
42
|
+
/**
|
|
43
|
+
* How an explained lookup ended, one outcome for each way `resolve` ends.
|
|
44
|
+
*
|
|
45
|
+
* @remarks `unbound` and `unmatched` are the lookups `resolve` reports as `TokenNotBoundError` and
|
|
46
|
+
* `NoMatchingBindingError`; `ambiguous` and `alias-cycle` are `AmbiguousBindingError` and `CircularDependencyError`.
|
|
47
|
+
*
|
|
48
|
+
* @since 0.12.0
|
|
49
|
+
*/
|
|
50
|
+
export type ExplanationOutcome = "selected" | "unbound" | "unmatched" | "ambiguous" | "alias-cycle";
|
|
51
|
+
/**
|
|
52
|
+
* One binding a registry offered the request, and what selection made of it.
|
|
53
|
+
*
|
|
54
|
+
* @since 0.12.0
|
|
55
|
+
*/
|
|
56
|
+
export interface CandidateExplanation {
|
|
57
|
+
readonly binding: BindingSnapshot;
|
|
58
|
+
readonly verdict: CandidateVerdict;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* One registry the lookup read, in the order `resolve` reads them.
|
|
62
|
+
*
|
|
63
|
+
* @since 0.12.0
|
|
64
|
+
*/
|
|
65
|
+
export interface ExplanationStep {
|
|
66
|
+
/** The token looked up here, which an alias hop changes. */
|
|
67
|
+
readonly tokenName: string;
|
|
68
|
+
/** How far up the chain the registry sits: `0` is the container asked, `1` its parent. */
|
|
69
|
+
readonly depth: number;
|
|
70
|
+
/** Every binding this registry holds for the token, in registration order. */
|
|
71
|
+
readonly candidates: ReadonlyArray<CandidateExplanation>;
|
|
72
|
+
/** The rule that settled this registry's answer, or `undefined` when no candidate was eligible. */
|
|
73
|
+
readonly rule: SelectionRule | undefined;
|
|
74
|
+
/** The binding this registry answered with, an alias included, or `undefined` when the lookup moved on. */
|
|
75
|
+
readonly selected: BindingSnapshot | undefined;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Why one request selects the binding it does, or why it selects none.
|
|
79
|
+
*
|
|
80
|
+
* @since 0.12.0
|
|
81
|
+
*/
|
|
82
|
+
export interface ResolutionExplanation {
|
|
83
|
+
/** The token the request asks for. */
|
|
84
|
+
readonly tokenName: string;
|
|
85
|
+
/** Every registry that holds a token the lookup asked for, once per alias hop, in the order it read them. */
|
|
86
|
+
readonly steps: ReadonlyArray<ExplanationStep>;
|
|
87
|
+
/** The binding the request resolves to after every alias, or `undefined` when it resolves to none. */
|
|
88
|
+
readonly selected: BindingSnapshot | undefined;
|
|
89
|
+
readonly outcome: ExplanationOutcome;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Explains a request against a container chain, without instantiating anything.
|
|
93
|
+
*
|
|
94
|
+
* @param registries - the asked container's registry first, then each ancestor's up to the root
|
|
95
|
+
* @param token - the token the request asks for
|
|
96
|
+
* @param options - the request's criteria and the resolutions it is nested in
|
|
97
|
+
* @throws An error `resolve` would throw, when one of `options.ancestors` selects no binding
|
|
98
|
+
*
|
|
99
|
+
* @since 0.12.0
|
|
100
|
+
*/
|
|
101
|
+
export declare function explainRequest(registries: ReadonlyArray<BindingRegistry>, token: Token<unknown> | Constructor, options: ExplainOptions | undefined): ResolutionExplanation;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { bindingSlotToString } from "#core/binding";
|
|
2
|
+
import { tokenName } from "#core/token";
|
|
3
|
+
import { AmbiguousBindingError, CircularDependencyError, InternalError, NoMatchingBindingError, TokenNotBoundError, } from "#errors";
|
|
4
|
+
import { snapshotOf } from "#introspection/inspector";
|
|
5
|
+
import { DefaultConstraintContext } from "#resolution/context";
|
|
6
|
+
import { buildResolutionFrame } from "#resolution/path";
|
|
7
|
+
import { candidateRuleOf, chooseCandidate, matchesSlot } from "#resolution/select/candidates";
|
|
8
|
+
// ── Explanation ──────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
9
|
+
/**
|
|
10
|
+
* Explains a request against a container chain, without instantiating anything.
|
|
11
|
+
*
|
|
12
|
+
* @param registries - the asked container's registry first, then each ancestor's up to the root
|
|
13
|
+
* @param token - the token the request asks for
|
|
14
|
+
* @param options - the request's criteria and the resolutions it is nested in
|
|
15
|
+
* @throws An error `resolve` would throw, when one of `options.ancestors` selects no binding
|
|
16
|
+
*
|
|
17
|
+
* @since 0.12.0
|
|
18
|
+
*/
|
|
19
|
+
export function explainRequest(registries, token, options) {
|
|
20
|
+
const stack = [];
|
|
21
|
+
for (const ancestor of options?.ancestors ?? []) {
|
|
22
|
+
const walk = walkLookup(registries, ancestor, undefined, stack);
|
|
23
|
+
if (walk.binding === undefined) {
|
|
24
|
+
throw lookupError(registries, walk);
|
|
25
|
+
}
|
|
26
|
+
stack.push(buildResolutionFrame(walk.binding, tokenName(walk.binding.token)));
|
|
27
|
+
}
|
|
28
|
+
const walk = walkLookup(registries, token, requestOf(options), stack);
|
|
29
|
+
return {
|
|
30
|
+
tokenName: tokenName(token),
|
|
31
|
+
steps: walk.steps,
|
|
32
|
+
selected: walk.binding === undefined ? undefined : snapshotOf(walk.binding),
|
|
33
|
+
outcome: walk.outcome,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// The `ancestors` key is explain's own, and a request carrying no criterion is the request with no options.
|
|
37
|
+
function requestOf(options) {
|
|
38
|
+
if (options === undefined ||
|
|
39
|
+
(options.name === undefined && options.tag === undefined && options.tags === undefined)) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const { ancestors: _ancestors, ...request } = options;
|
|
43
|
+
return request;
|
|
44
|
+
}
|
|
45
|
+
function walkLookup(registries, token, request, stack) {
|
|
46
|
+
const ctx = new DefaultConstraintContext(stack, request);
|
|
47
|
+
const steps = [];
|
|
48
|
+
let current = token;
|
|
49
|
+
let visited;
|
|
50
|
+
for (;;) {
|
|
51
|
+
const found = findInChain(registries, current, request, ctx, steps);
|
|
52
|
+
if (found.kind === "tie") {
|
|
53
|
+
return {
|
|
54
|
+
steps,
|
|
55
|
+
binding: undefined,
|
|
56
|
+
outcome: "ambiguous",
|
|
57
|
+
lastToken: current,
|
|
58
|
+
ambiguity: found.eligible,
|
|
59
|
+
cycle: undefined,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (found.kind === "none") {
|
|
63
|
+
const outcome = registries.some((registry) => registry.getAll(current).length > 0) ? "unmatched" : "unbound";
|
|
64
|
+
return { steps, binding: undefined, outcome, lastToken: current, ambiguity: undefined, cycle: undefined };
|
|
65
|
+
}
|
|
66
|
+
const binding = found.binding;
|
|
67
|
+
if (binding.kind !== "alias") {
|
|
68
|
+
return { steps, binding, outcome: "selected", lastToken: current, ambiguity: undefined, cycle: undefined };
|
|
69
|
+
}
|
|
70
|
+
// An alias hop restarts at the container asked, as `resolve` does, and a revisited token is a cycle.
|
|
71
|
+
const target = binding.target;
|
|
72
|
+
visited ??= new Set([current]);
|
|
73
|
+
if (visited.has(target)) {
|
|
74
|
+
return {
|
|
75
|
+
steps,
|
|
76
|
+
binding: undefined,
|
|
77
|
+
outcome: "alias-cycle",
|
|
78
|
+
lastToken: current,
|
|
79
|
+
ambiguity: undefined,
|
|
80
|
+
cycle: [...visited, target],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
visited.add(target);
|
|
84
|
+
current = target;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const NO_ANSWER = { kind: "none" };
|
|
88
|
+
function findInChain(registries, token, request, ctx, steps) {
|
|
89
|
+
for (let depth = 0; depth < registries.length; depth += 1) {
|
|
90
|
+
const registry = registries[depth];
|
|
91
|
+
const bindings = registry.getAll(token);
|
|
92
|
+
if (bindings.length === 0) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const candidates = [];
|
|
96
|
+
const eligible = [];
|
|
97
|
+
for (const binding of bindings) {
|
|
98
|
+
const verdict = verdictOf(binding, request, ctx);
|
|
99
|
+
candidates.push({ binding: snapshotOf(binding), verdict });
|
|
100
|
+
if (verdict === "eligible") {
|
|
101
|
+
eligible.push(binding);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const name = tokenName(token);
|
|
105
|
+
if (eligible.length > 0) {
|
|
106
|
+
const selected = chooseCandidate(eligible);
|
|
107
|
+
steps.push({
|
|
108
|
+
tokenName: name,
|
|
109
|
+
depth,
|
|
110
|
+
candidates,
|
|
111
|
+
rule: candidateRuleOf(eligible, selected),
|
|
112
|
+
selected: selected === undefined ? undefined : snapshotOf(selected),
|
|
113
|
+
});
|
|
114
|
+
return selected === undefined ? { kind: "tie", eligible } : { kind: "binding", binding: selected };
|
|
115
|
+
}
|
|
116
|
+
// A request carrying criteria that no slot here matches is forwarded by the token's default-slot alias.
|
|
117
|
+
const defaultSlot = request === undefined ? undefined : registry.defaultSlotAlias(token);
|
|
118
|
+
if (defaultSlot !== undefined) {
|
|
119
|
+
steps.push({ tokenName: name, depth, candidates, rule: "default-alias", selected: snapshotOf(defaultSlot) });
|
|
120
|
+
return { kind: "binding", binding: defaultSlot };
|
|
121
|
+
}
|
|
122
|
+
steps.push({ tokenName: name, depth, candidates, rule: undefined, selected: undefined });
|
|
123
|
+
}
|
|
124
|
+
return NO_ANSWER;
|
|
125
|
+
}
|
|
126
|
+
function verdictOf(binding, request, ctx) {
|
|
127
|
+
if (binding.isMany) {
|
|
128
|
+
return "collection-member";
|
|
129
|
+
}
|
|
130
|
+
if (!matchesSlot(binding.slot, request)) {
|
|
131
|
+
return "slot-mismatch";
|
|
132
|
+
}
|
|
133
|
+
const predicate = binding.predicate;
|
|
134
|
+
return predicate === undefined || predicate(ctx) ? "eligible" : "predicate-refused";
|
|
135
|
+
}
|
|
136
|
+
/** The error `resolve` throws for a lookup that ended without a binding. */
|
|
137
|
+
function lookupError(registries, walk) {
|
|
138
|
+
const name = tokenName(walk.lastToken);
|
|
139
|
+
switch (walk.outcome) {
|
|
140
|
+
case "ambiguous":
|
|
141
|
+
return new AmbiguousBindingError(name, (walk.ambiguity ?? []).map((binding) => binding.identifier));
|
|
142
|
+
case "alias-cycle":
|
|
143
|
+
return new CircularDependencyError((walk.cycle ?? []).map((entry) => tokenName(entry)));
|
|
144
|
+
case "unmatched":
|
|
145
|
+
return new NoMatchingBindingError(name, {}, registries.flatMap((registry) => registry.getAll(walk.lastToken).map((binding) => bindingSlotToString(binding.slot))));
|
|
146
|
+
case "unbound":
|
|
147
|
+
return new TokenNotBoundError(name);
|
|
148
|
+
case "selected":
|
|
149
|
+
return new InternalError("a lookup that selected a binding has no error");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { Binding } from "#core/binding";
|
|
1
2
|
import type { BindingRegistry } from "#core/registry";
|
|
2
3
|
import type { Token } from "#core/token";
|
|
3
4
|
import type { BindingIdentifier, BindingKind, BindingScope, BindingTag, Constructor, ResolveOptions } from "#core/types";
|
|
4
|
-
import type { ScopeManager } from "#lifecycle/
|
|
5
|
+
import type { ScopeManager } from "#lifecycle/scopes";
|
|
5
6
|
/**
|
|
6
7
|
* A read-only view of one binding: token, kind, scope, slot, and id.
|
|
7
8
|
*
|
|
@@ -42,4 +43,10 @@ export declare class Inspector {
|
|
|
42
43
|
lookupBindings<Value>(token: Token<Value> | Constructor<Value>): ReadonlyArray<BindingSnapshot>;
|
|
43
44
|
/** Whether this container's own registry holds a binding the request could select. */
|
|
44
45
|
hasOwn(token: Token<unknown> | Constructor, options?: ResolveOptions): boolean;
|
|
45
|
-
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The public snapshot of one binding, the shape every introspection read reports a binding in.
|
|
49
|
+
*
|
|
50
|
+
* @since 0.12.0
|
|
51
|
+
*/
|
|
52
|
+
export declare function snapshotOf(binding: Binding): BindingSnapshot;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { effectiveBindingScope } from "#core/binding
|
|
1
|
+
import { effectiveBindingScope } from "#core/binding";
|
|
2
2
|
import { tokenName } from "#core/token";
|
|
3
3
|
import { DefaultConstraintContext } from "#resolution/context";
|
|
4
|
-
import { selectAllBindings } from "#resolution/select/
|
|
4
|
+
import { selectAllBindings } from "#resolution/select/candidates";
|
|
5
5
|
// ── Inspector ────────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
6
6
|
/**
|
|
7
7
|
* The read-only introspection surface behind a container's `inspect()`.
|
|
@@ -21,7 +21,7 @@ export class Inspector {
|
|
|
21
21
|
}
|
|
22
22
|
inspect() {
|
|
23
23
|
return {
|
|
24
|
-
ownBindings: this.#registry.allBindings().map((binding) =>
|
|
24
|
+
ownBindings: this.#registry.allBindings().map((binding) => snapshotOf(binding)),
|
|
25
25
|
cachedSingletonCount: this.#scope.cachedSingletons().length,
|
|
26
26
|
hasParent: this.#hasParent,
|
|
27
27
|
isDisposed: this.#isDisposed(),
|
|
@@ -29,7 +29,7 @@ export class Inspector {
|
|
|
29
29
|
}
|
|
30
30
|
lookupBindings(token) {
|
|
31
31
|
const bindings = this.#registry.getAll(token);
|
|
32
|
-
return bindings.map((binding) =>
|
|
32
|
+
return bindings.map((binding) => snapshotOf(binding));
|
|
33
33
|
}
|
|
34
34
|
/** Whether this container's own registry holds a binding the request could select. */
|
|
35
35
|
hasOwn(token, options) {
|
|
@@ -42,24 +42,29 @@ export class Inspector {
|
|
|
42
42
|
// resolution has to pick one. A default-slot alias answers any criteria by forwarding them.
|
|
43
43
|
return (bindings.length > 0 &&
|
|
44
44
|
(selectAllBindings(bindings, options, this.#makeConstraintContext(options)).length > 0 ||
|
|
45
|
-
this.#registry.
|
|
45
|
+
this.#registry.defaultSlotAlias(token) !== undefined));
|
|
46
46
|
}
|
|
47
47
|
#makeConstraintContext(options) {
|
|
48
48
|
return new DefaultConstraintContext([], options);
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The public snapshot of one binding, the shape every introspection read reports a binding in.
|
|
53
|
+
*
|
|
54
|
+
* @since 0.12.0
|
|
55
|
+
*/
|
|
56
|
+
export function snapshotOf(binding) {
|
|
57
|
+
// Aliased, not copied: slot tags are frozen where they are built, so a caller's write throws
|
|
58
|
+
// instead of corrupting the registry — and the snapshot skips an allocation per binding.
|
|
59
|
+
const slot = binding.slot.name !== undefined
|
|
60
|
+
? { name: binding.slot.name, tags: binding.slot.tags }
|
|
61
|
+
: { tags: binding.slot.tags };
|
|
62
|
+
return {
|
|
63
|
+
tokenName: tokenName(binding.token),
|
|
64
|
+
kind: binding.kind,
|
|
65
|
+
scope: effectiveBindingScope(binding),
|
|
66
|
+
slot,
|
|
67
|
+
id: binding.identifier,
|
|
68
|
+
isMany: binding.isMany,
|
|
69
|
+
};
|
|
65
70
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Binding } from "#core/binding";
|
|
2
2
|
import type { Token } from "#core/token";
|
|
3
3
|
import type { ActivationHandler, Constructor, DeactivationHandler, DependencyKey, ResolutionContext } from "#core/types";
|
|
4
|
-
import type { MetadataReader } from "#metadata/
|
|
4
|
+
import type { MetadataReader } from "#metadata/types";
|
|
5
5
|
/**
|
|
6
6
|
* One container's registry of container-level activation and deactivation hooks, keyed by token.
|
|
7
7
|
*
|
|
@@ -19,7 +19,14 @@ export declare class LifecycleManager {
|
|
|
19
19
|
hasDeactivationHandlers<Value>(token: Token<Value> | Constructor<Value>): boolean;
|
|
20
20
|
/** Every token carrying a container-level hook, paired with the phase that registered it. */
|
|
21
21
|
hookedTokens(): Array<[DependencyKey, "onActivation" | "onDeactivation"]>;
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Runs the activation pipeline on the async lane: the activated instance, or its promise once a
|
|
24
|
+
* hook has returned one.
|
|
25
|
+
*
|
|
26
|
+
* @remarks A level yields only where a hook does, so a synchronous pipeline hands the instance
|
|
27
|
+
* back in the caller's own tick and a singleton it activates is cached before any sibling reads it.
|
|
28
|
+
*/
|
|
29
|
+
runActivation<Value>(resolutionContext: ResolutionContext, binding: Binding<Value>, instance: Value, metadataReader: MetadataReader): Value | Promise<Value>;
|
|
23
30
|
runActivationSync<Value>(resolutionContext: ResolutionContext, binding: Binding<Value>, instance: Value, metadataReader: MetadataReader): Value;
|
|
24
31
|
runDeactivation<Value>(binding: Binding<Value>, instance: Value, metadataReader: MetadataReader): Promise<void>;
|
|
25
32
|
runDeactivationSync<Value>(binding: Binding<Value>, instance: Value, metadataReader: MetadataReader): void;
|