@codefast/di 0.5.0-canary.9 → 0.6.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 +865 -0
- package/README.md +119 -30
- package/dist/ambient/active-container.d.ts +37 -0
- package/dist/ambient/active-container.d.ts.map +1 -0
- package/dist/ambient/active-container.js +41 -0
- package/dist/ambient/active-container.js.map +1 -0
- package/dist/container/binding-builders.d.ts +12 -8
- package/dist/container/binding-builders.d.ts.map +1 -1
- package/dist/container/binding-builders.js +56 -31
- package/dist/container/binding-builders.js.map +1 -1
- package/dist/container/container.d.ts +33 -19
- package/dist/container/container.d.ts.map +1 -1
- package/dist/container/container.js +279 -118
- package/dist/container/container.js.map +1 -1
- package/dist/{resolution → core}/binding-scope.d.ts +2 -2
- package/dist/core/binding-scope.d.ts.map +1 -0
- package/dist/core/binding-scope.js.map +1 -0
- package/dist/{binding.d.ts → core/binding.d.ts} +70 -15
- package/dist/core/binding.d.ts.map +1 -0
- package/dist/{binding.js → core/binding.js} +27 -12
- package/dist/core/binding.js.map +1 -0
- package/dist/core/constraint-requirement.d.ts +38 -0
- package/dist/core/constraint-requirement.d.ts.map +1 -0
- package/dist/core/constraint-requirement.js +28 -0
- package/dist/core/constraint-requirement.js.map +1 -0
- package/dist/{constructor-type.d.ts → core/constructor-type.d.ts} +1 -1
- package/dist/core/constructor-type.d.ts.map +1 -0
- package/dist/core/constructor-type.js.map +1 -0
- package/dist/{module.d.ts → core/module.d.ts} +5 -5
- package/dist/core/module.d.ts.map +1 -0
- package/dist/{module.js → core/module.js} +4 -4
- package/dist/core/module.js.map +1 -0
- package/dist/{registry.d.ts → core/registry.d.ts} +27 -7
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/{registry.js → core/registry.js} +125 -52
- package/dist/core/registry.js.map +1 -0
- package/dist/core/tag.d.ts +80 -0
- package/dist/core/tag.d.ts.map +1 -0
- package/dist/core/tag.js +84 -0
- package/dist/core/tag.js.map +1 -0
- package/dist/{token.d.ts → core/token.d.ts} +2 -6
- package/dist/core/token.d.ts.map +1 -0
- package/dist/core/token.js +13 -0
- package/dist/core/token.js.map +1 -0
- package/dist/{types.d.ts → core/types.d.ts} +27 -21
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js.map +1 -0
- package/dist/decorators/inject.d.ts +5 -49
- package/dist/decorators/inject.d.ts.map +1 -1
- package/dist/decorators/inject.js +34 -104
- package/dist/decorators/inject.js.map +1 -1
- package/dist/decorators/injectable.d.ts +25 -5
- package/dist/decorators/injectable.d.ts.map +1 -1
- package/dist/decorators/injectable.js +2 -3
- package/dist/decorators/injectable.js.map +1 -1
- package/dist/decorators/lifecycle-decorators.d.ts +4 -2
- package/dist/decorators/lifecycle-decorators.d.ts.map +1 -1
- package/dist/decorators/lifecycle-decorators.js +19 -25
- package/dist/decorators/lifecycle-decorators.js.map +1 -1
- package/dist/{resolution → errors}/diagnostics.d.ts +2 -0
- package/dist/errors/diagnostics.d.ts.map +1 -0
- package/dist/errors/diagnostics.js.map +1 -0
- package/dist/{errors.d.ts → errors/errors.d.ts} +89 -4
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/{errors.js → errors/errors.js} +129 -7
- package/dist/errors/errors.js.map +1 -0
- package/dist/index.d.ts +21 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/injection/descriptor.d.ts +79 -0
- package/dist/injection/descriptor.d.ts.map +1 -0
- package/dist/injection/descriptor.js +118 -0
- package/dist/injection/descriptor.js.map +1 -0
- package/dist/{resolution → injection}/resolve-options.d.ts +21 -11
- package/dist/injection/resolve-options.d.ts.map +1 -0
- package/dist/injection/resolve-options.js +101 -0
- package/dist/injection/resolve-options.js.map +1 -0
- package/dist/introspection/dependency-graph.d.ts +16 -5
- package/dist/introspection/dependency-graph.d.ts.map +1 -1
- package/dist/introspection/dependency-graph.js +138 -57
- package/dist/introspection/dependency-graph.js.map +1 -1
- package/dist/introspection/graph-adapters/cytoscape.d.ts +6 -3
- package/dist/introspection/graph-adapters/cytoscape.d.ts.map +1 -1
- package/dist/introspection/graph-adapters/cytoscape.js +3 -0
- package/dist/introspection/graph-adapters/cytoscape.js.map +1 -1
- package/dist/introspection/graph-adapters/dot.d.ts.map +1 -1
- package/dist/introspection/graph-adapters/dot.js +12 -5
- package/dist/introspection/graph-adapters/dot.js.map +1 -1
- package/dist/introspection/graph-adapters/mermaid.d.ts +9 -0
- package/dist/introspection/graph-adapters/mermaid.d.ts.map +1 -0
- package/dist/introspection/graph-adapters/mermaid.js +47 -0
- package/dist/introspection/graph-adapters/mermaid.js.map +1 -0
- package/dist/introspection/graph-adapters/reactflow.d.ts +6 -3
- package/dist/introspection/graph-adapters/reactflow.d.ts.map +1 -1
- package/dist/introspection/graph-adapters/reactflow.js +5 -1
- package/dist/introspection/graph-adapters/reactflow.js.map +1 -1
- package/dist/introspection/inspector.d.ts +4 -4
- package/dist/introspection/inspector.d.ts.map +1 -1
- package/dist/introspection/inspector.js +10 -6
- package/dist/introspection/inspector.js.map +1 -1
- package/dist/lifecycle/lifecycle-manager.d.ts +27 -0
- package/dist/lifecycle/lifecycle-manager.d.ts.map +1 -0
- package/dist/{resolution/lifecycle.js → lifecycle/lifecycle-manager.js} +39 -9
- package/dist/lifecycle/lifecycle-manager.js.map +1 -0
- package/dist/lifecycle/scope-manager.d.ts +48 -0
- package/dist/lifecycle/scope-manager.d.ts.map +1 -0
- package/dist/lifecycle/scope-manager.js +135 -0
- package/dist/lifecycle/scope-manager.js.map +1 -0
- package/dist/metadata/metadata-reader-token.d.ts +1 -1
- package/dist/metadata/metadata-reader-token.d.ts.map +1 -1
- package/dist/metadata/metadata-reader-token.js +1 -1
- package/dist/metadata/metadata-reader-token.js.map +1 -1
- package/dist/metadata/metadata-types.d.ts +9 -9
- package/dist/metadata/metadata-types.d.ts.map +1 -1
- package/dist/metadata/symbol-metadata-reader.d.ts +19 -6
- package/dist/metadata/symbol-metadata-reader.d.ts.map +1 -1
- package/dist/metadata/symbol-metadata-reader.js +89 -9
- package/dist/metadata/symbol-metadata-reader.js.map +1 -1
- package/dist/metadata/verifying-metadata-reader.d.ts +16 -0
- package/dist/metadata/verifying-metadata-reader.d.ts.map +1 -0
- package/dist/metadata/verifying-metadata-reader.js +32 -0
- package/dist/metadata/verifying-metadata-reader.js.map +1 -0
- package/dist/resolution/{activation-need.d.ts → cache/activation-need.d.ts} +5 -5
- package/dist/resolution/cache/activation-need.d.ts.map +1 -0
- package/dist/resolution/cache/activation-need.js.map +1 -0
- package/dist/resolution/{binding-lookup-cache.d.ts → cache/binding-lookup-cache.d.ts} +6 -5
- package/dist/resolution/cache/binding-lookup-cache.d.ts.map +1 -0
- package/dist/resolution/cache/binding-lookup-cache.js.map +1 -0
- package/dist/resolution/cache/class-introspector.d.ts +66 -0
- package/dist/resolution/cache/class-introspector.d.ts.map +1 -0
- package/dist/resolution/cache/class-introspector.js +194 -0
- package/dist/resolution/cache/class-introspector.js.map +1 -0
- package/dist/resolution/context.d.ts +84 -0
- package/dist/resolution/context.d.ts.map +1 -0
- package/dist/resolution/{environment.js → context.js} +54 -80
- package/dist/resolution/context.js.map +1 -0
- package/dist/resolution/path/resolution-path.d.ts +94 -0
- package/dist/resolution/path/resolution-path.d.ts.map +1 -0
- package/dist/resolution/path/resolution-path.js +117 -0
- package/dist/resolution/path/resolution-path.js.map +1 -0
- package/dist/resolution/{instantiation-plan.d.ts → plan/instantiation-plan.d.ts} +30 -7
- package/dist/resolution/plan/instantiation-plan.d.ts.map +1 -0
- package/dist/resolution/plan/instantiation-plan.js +390 -0
- package/dist/resolution/plan/instantiation-plan.js.map +1 -0
- package/dist/resolution/resolver.d.ts +28 -28
- package/dist/resolution/resolver.d.ts.map +1 -1
- package/dist/resolution/resolver.js +552 -239
- package/dist/resolution/resolver.js.map +1 -1
- package/dist/resolution/select/binding-select.d.ts +34 -0
- package/dist/resolution/select/binding-select.d.ts.map +1 -0
- package/dist/resolution/select/binding-select.js +175 -0
- package/dist/resolution/select/binding-select.js.map +1 -0
- package/dist/resolution/{constraints.d.ts → select/constraints.d.ts} +13 -12
- package/dist/resolution/select/constraints.d.ts.map +1 -0
- package/dist/resolution/{constraints.js → select/constraints.js} +33 -22
- package/dist/resolution/select/constraints.js.map +1 -0
- package/package.json +160 -20
- package/src/ambient/active-container.ts +65 -0
- package/src/container/binding-builders.ts +72 -44
- package/src/container/container.ts +355 -170
- package/src/{resolution → core}/binding-scope.ts +2 -2
- package/src/{binding.ts → core/binding.ts} +101 -39
- package/src/core/constraint-requirement.ts +51 -0
- package/src/{constructor-type.ts → core/constructor-type.ts} +1 -1
- package/src/{module.ts → core/module.ts} +10 -10
- package/src/core/registry.ts +365 -0
- package/src/core/tag.ts +144 -0
- package/src/{token.ts → core/token.ts} +2 -14
- package/src/{types.ts → core/types.ts} +37 -34
- package/src/decorators/inject.ts +39 -175
- package/src/decorators/injectable.ts +40 -10
- package/src/decorators/lifecycle-decorators.ts +22 -34
- package/src/{resolution → errors}/diagnostics.ts +2 -0
- package/src/{errors.ts → errors/errors.ts} +152 -8
- package/src/index.ts +43 -15
- package/src/injection/descriptor.ts +206 -0
- package/src/injection/resolve-options.ts +144 -0
- package/src/introspection/dependency-graph.ts +223 -63
- package/src/introspection/graph-adapters/cytoscape.ts +9 -3
- package/src/introspection/graph-adapters/dot.ts +13 -5
- package/src/introspection/graph-adapters/mermaid.ts +61 -0
- package/src/introspection/graph-adapters/reactflow.ts +11 -4
- package/src/introspection/inspector.ts +16 -12
- package/src/{resolution/lifecycle.ts → lifecycle/lifecycle-manager.ts} +68 -32
- package/src/lifecycle/scope-manager.ts +156 -0
- package/src/metadata/metadata-reader-token.ts +2 -2
- package/src/metadata/metadata-types.ts +9 -9
- package/src/metadata/symbol-metadata-reader.ts +95 -18
- package/src/metadata/verifying-metadata-reader.ts +41 -0
- package/src/resolution/{activation-need.ts → cache/activation-need.ts} +8 -8
- package/src/resolution/{binding-lookup-cache.ts → cache/binding-lookup-cache.ts} +6 -5
- package/src/resolution/cache/class-introspector.ts +251 -0
- package/src/resolution/{environment.ts → context.ts} +84 -145
- package/src/resolution/path/resolution-path.ts +167 -0
- package/src/resolution/plan/instantiation-plan.ts +579 -0
- package/src/resolution/resolver.ts +635 -313
- package/src/resolution/select/binding-select.ts +210 -0
- package/src/resolution/select/constraints.ts +130 -0
- package/dist/binding.d.ts.map +0 -1
- package/dist/binding.js.map +0 -1
- package/dist/constructor-type.d.ts.map +0 -1
- package/dist/constructor-type.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/module.d.ts.map +0 -1
- package/dist/module.js.map +0 -1
- package/dist/registry.d.ts.map +0 -1
- package/dist/registry.js.map +0 -1
- package/dist/resolution/activation-need.d.ts.map +0 -1
- package/dist/resolution/activation-need.js.map +0 -1
- package/dist/resolution/binding-lookup-cache.d.ts.map +0 -1
- package/dist/resolution/binding-lookup-cache.js.map +0 -1
- package/dist/resolution/binding-scope.d.ts.map +0 -1
- package/dist/resolution/binding-scope.js.map +0 -1
- package/dist/resolution/binding-select.d.ts +0 -23
- package/dist/resolution/binding-select.d.ts.map +0 -1
- package/dist/resolution/binding-select.js +0 -121
- package/dist/resolution/binding-select.js.map +0 -1
- package/dist/resolution/class-introspector.d.ts +0 -27
- package/dist/resolution/class-introspector.d.ts.map +0 -1
- package/dist/resolution/class-introspector.js +0 -60
- package/dist/resolution/class-introspector.js.map +0 -1
- package/dist/resolution/constraints.d.ts.map +0 -1
- package/dist/resolution/constraints.js.map +0 -1
- package/dist/resolution/diagnostics.d.ts.map +0 -1
- package/dist/resolution/diagnostics.js.map +0 -1
- package/dist/resolution/environment.d.ts +0 -94
- package/dist/resolution/environment.d.ts.map +0 -1
- package/dist/resolution/environment.js.map +0 -1
- package/dist/resolution/instantiation-plan.d.ts.map +0 -1
- package/dist/resolution/instantiation-plan.js +0 -183
- package/dist/resolution/instantiation-plan.js.map +0 -1
- package/dist/resolution/lifecycle.d.ts +0 -23
- package/dist/resolution/lifecycle.d.ts.map +0 -1
- package/dist/resolution/lifecycle.js.map +0 -1
- package/dist/resolution/resolution-path.d.ts +0 -98
- package/dist/resolution/resolution-path.d.ts.map +0 -1
- package/dist/resolution/resolution-path.js +0 -98
- package/dist/resolution/resolution-path.js.map +0 -1
- package/dist/resolution/resolve-options.d.ts.map +0 -1
- package/dist/resolution/resolve-options.js +0 -56
- package/dist/resolution/resolve-options.js.map +0 -1
- package/dist/resolution/scope.d.ts +0 -28
- package/dist/resolution/scope.d.ts.map +0 -1
- package/dist/resolution/scope.js +0 -88
- package/dist/resolution/scope.js.map +0 -1
- package/dist/token.d.ts.map +0 -1
- package/dist/token.js +0 -22
- package/dist/token.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/src/registry.ts +0 -282
- package/src/resolution/binding-select.ts +0 -154
- package/src/resolution/class-introspector.ts +0 -74
- package/src/resolution/constraints.ts +0 -121
- package/src/resolution/instantiation-plan.ts +0 -292
- package/src/resolution/resolution-path.ts +0 -156
- package/src/resolution/resolve-options.ts +0 -89
- package/src/resolution/scope.ts +0 -105
- /package/dist/{resolution → core}/binding-scope.js +0 -0
- /package/dist/{constructor-type.js → core/constructor-type.js} +0 -0
- /package/dist/{types.js → core/types.js} +0 -0
- /package/dist/{resolution → errors}/diagnostics.js +0 -0
- /package/dist/resolution/{activation-need.js → cache/activation-need.js} +0 -0
- /package/dist/resolution/{binding-lookup-cache.js → cache/binding-lookup-cache.js} +0 -0
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Foundation types
|
|
2
2
|
export type {
|
|
3
3
|
ActivationHandler,
|
|
4
|
+
BindingConstraint,
|
|
4
5
|
BindingIdentifier,
|
|
5
6
|
BindingKind,
|
|
6
7
|
BindingScope,
|
|
@@ -13,11 +14,15 @@ export type {
|
|
|
13
14
|
ResolveOptions,
|
|
14
15
|
ResolutionContext,
|
|
15
16
|
TokenValue,
|
|
16
|
-
} from "#/types";
|
|
17
|
+
} from "#/core/types";
|
|
17
18
|
|
|
18
19
|
// Token
|
|
19
|
-
export { token, tokenName
|
|
20
|
-
export type { Token } from "#/token";
|
|
20
|
+
export { token, tokenName } from "#/core/token";
|
|
21
|
+
export type { Token } from "#/core/token";
|
|
22
|
+
|
|
23
|
+
// Tag — the interned slot criteria a `whenTagged` and a resolve both take
|
|
24
|
+
export { coversTagKeys, NO_TAG_KEYS, tag, tagKeyMaskOf } from "#/core/tag";
|
|
25
|
+
export type { TagKey, TagKeyMask } from "#/core/tag";
|
|
21
26
|
|
|
22
27
|
// Binding builders — types only
|
|
23
28
|
export type {
|
|
@@ -30,15 +35,24 @@ export type {
|
|
|
30
35
|
SingletonLifecycleBuilder,
|
|
31
36
|
SlotConstrainedBuilder,
|
|
32
37
|
TransientBindingBuilder,
|
|
33
|
-
} from "#/binding";
|
|
38
|
+
} from "#/core/binding";
|
|
34
39
|
|
|
35
40
|
// Container
|
|
36
41
|
export { Container } from "#/container/container";
|
|
37
|
-
export type { Container as ContainerInterface, ContainerStatic } from "#/container/container";
|
|
42
|
+
export type { Container as ContainerInterface, ContainerOptions, ContainerStatic } from "#/container/container";
|
|
43
|
+
|
|
44
|
+
// Ambient container — the context an `@inject` accessor initializer resolves from. `resolution/context`
|
|
45
|
+
// stays internal: it hands out resolver callbacks, not public values.
|
|
46
|
+
export { getActiveContainer, runWithContainer } from "#/ambient/active-container";
|
|
38
47
|
|
|
39
48
|
// `effectiveBindingScope` is deliberately absent: it reads a `Binding`, which is internal, and no
|
|
40
49
|
// public API hands one out. `BindingSnapshot.scope` and `GraphNode.scope` are the public answers.
|
|
41
|
-
export {
|
|
50
|
+
export {
|
|
51
|
+
bindingSlotToResolveOptions,
|
|
52
|
+
injectionSlotToResolveOptions,
|
|
53
|
+
resolveOptionsForSlot,
|
|
54
|
+
} from "#/injection/resolve-options";
|
|
55
|
+
export type { DependencySlot } from "#/injection/resolve-options";
|
|
42
56
|
|
|
43
57
|
// Introspection types
|
|
44
58
|
export type { BindingSnapshot, ContainerSnapshot } from "#/introspection/inspector";
|
|
@@ -47,12 +61,13 @@ export type { BindingSnapshot, ContainerSnapshot } from "#/introspection/inspect
|
|
|
47
61
|
export type { ContainerGraphJson, GraphEdge, GraphNode, GraphOptions } from "#/introspection/dependency-graph";
|
|
48
62
|
|
|
49
63
|
// Module
|
|
50
|
-
export { AsyncModule, isSyncModule, Module, SyncModule } from "#/module";
|
|
51
|
-
export type { AsyncModuleBuilder, ModuleBuilder } from "#/module";
|
|
64
|
+
export { AsyncModule, isSyncModule, Module, SyncModule } from "#/core/module";
|
|
65
|
+
export type { AsyncModuleBuilder, ModuleBuilder } from "#/core/module";
|
|
52
66
|
|
|
53
67
|
// Decorators
|
|
54
|
-
export { inject
|
|
55
|
-
export
|
|
68
|
+
export { inject } from "#/decorators/inject";
|
|
69
|
+
export { injectAll, isInjectionDescriptor, optional } from "#/injection/descriptor";
|
|
70
|
+
export type { InjectionDescriptor, InjectOptions } from "#/injection/descriptor";
|
|
56
71
|
export { injectable } from "#/decorators/injectable";
|
|
57
72
|
export type { InjectableDependency, InjectableOptions } from "#/decorators/injectable";
|
|
58
73
|
export { postConstruct, preDestroy } from "#/decorators/lifecycle-decorators";
|
|
@@ -61,9 +76,16 @@ export { postConstruct, preDestroy } from "#/decorators/lifecycle-decorators";
|
|
|
61
76
|
export { createAutoRegisterRegistry } from "#/decorators/injectable";
|
|
62
77
|
export type { AutoRegisterRegistry } from "#/decorators/injectable";
|
|
63
78
|
|
|
64
|
-
// MetadataReader
|
|
79
|
+
// MetadataReader — everything a consumer needs to write one and pass it to Container.create()
|
|
65
80
|
export { MetadataReaderToken } from "#/metadata/metadata-reader-token";
|
|
66
|
-
export type {
|
|
81
|
+
export type {
|
|
82
|
+
ConstructorMetadata,
|
|
83
|
+
LifecycleMetadata,
|
|
84
|
+
MetadataReader,
|
|
85
|
+
MutableLifecycleMetadata,
|
|
86
|
+
ParamMetadata,
|
|
87
|
+
} from "#/metadata/metadata-types";
|
|
88
|
+
export { defaultMetadataReader, SymbolMetadataReader } from "#/metadata/symbol-metadata-reader";
|
|
67
89
|
|
|
68
90
|
// Constraints — contextual injection predicates for .when()
|
|
69
91
|
export {
|
|
@@ -77,7 +99,7 @@ export {
|
|
|
77
99
|
whenParentNamed,
|
|
78
100
|
whenParentTagged,
|
|
79
101
|
whenParentTaggedAll,
|
|
80
|
-
} from "#/resolution/constraints";
|
|
102
|
+
} from "#/resolution/select/constraints";
|
|
81
103
|
|
|
82
104
|
// Errors
|
|
83
105
|
export {
|
|
@@ -91,6 +113,7 @@ export {
|
|
|
91
113
|
DiError,
|
|
92
114
|
DisposedContainerError,
|
|
93
115
|
InternalError,
|
|
116
|
+
InvalidMetadataError,
|
|
94
117
|
MissingContainerContextError,
|
|
95
118
|
MissingMetadataError,
|
|
96
119
|
MissingScopeContextError,
|
|
@@ -98,10 +121,14 @@ export {
|
|
|
98
121
|
RebindUnboundTokenError,
|
|
99
122
|
ScopeViolationError,
|
|
100
123
|
SelfBindingRequiresClassError,
|
|
124
|
+
StaticMemberDecoratorError,
|
|
101
125
|
SyncDisposalNotSupportedError,
|
|
126
|
+
EmptyTagCriteriaError,
|
|
102
127
|
TokenNotBoundError,
|
|
103
|
-
|
|
104
|
-
|
|
128
|
+
UnreachableConstraintError,
|
|
129
|
+
UnreachableLifecycleHookError,
|
|
130
|
+
} from "#/errors/errors";
|
|
131
|
+
export type { ScopeViolationDetails } from "#/errors/errors";
|
|
105
132
|
|
|
106
133
|
// Graph adapters — render `generateDependencyGraph()` output for common viewers
|
|
107
134
|
export { toDotGraph } from "#/introspection/graph-adapters/dot";
|
|
@@ -109,3 +136,4 @@ export { toCytoscapeGraph } from "#/introspection/graph-adapters/cytoscape";
|
|
|
109
136
|
export type { CytoscapeEdge, CytoscapeElements, CytoscapeNode } from "#/introspection/graph-adapters/cytoscape";
|
|
110
137
|
export { toReactFlowGraph } from "#/introspection/graph-adapters/reactflow";
|
|
111
138
|
export type { ReactFlowEdge, ReactFlowGraph, ReactFlowNode } from "#/introspection/graph-adapters/reactflow";
|
|
139
|
+
export { toMermaidGraph } from "#/introspection/graph-adapters/mermaid";
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/** The one shape every declared dependency is normalised to, whatever channel declared it. */
|
|
2
|
+
import type { Token } from "#/core/token";
|
|
3
|
+
import type { BindingTag, Constructor, TokenValue } from "#/core/types";
|
|
4
|
+
import type { DependencySlot } from "#/injection/resolve-options";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @since 0.3.16-canary.0
|
|
8
|
+
*/
|
|
9
|
+
export interface InjectOptions {
|
|
10
|
+
name?: string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Single-tag shorthand, equivalent to listing the one pair in `tags`.
|
|
13
|
+
*
|
|
14
|
+
* @remarks Folded into `tags` when the descriptor is built, so nothing downstream sees two
|
|
15
|
+
* spellings of one request. Giving both is a request for every pair across the two.
|
|
16
|
+
*/
|
|
17
|
+
tag?: BindingTag | undefined;
|
|
18
|
+
tags?: ReadonlyArray<BindingTag> | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* One dependency a `toResolved` factory or an `@inject` accessor declares.
|
|
23
|
+
*
|
|
24
|
+
* @remarks Extends {@link DependencySlot} so the two dependency sources stay literally one shape,
|
|
25
|
+
* narrowing only `token` to carry the value type a factory's parameter is checked against.
|
|
26
|
+
*
|
|
27
|
+
* @since 0.3.16-canary.0
|
|
28
|
+
*/
|
|
29
|
+
export interface InjectionDescriptor<out Value = unknown> extends DependencySlot {
|
|
30
|
+
readonly token: Token<Value> | Constructor<Value>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @since 0.3.16-canary.0
|
|
35
|
+
*/
|
|
36
|
+
export type InjectableDependency<Value = unknown> = Token<Value> | Constructor<Value> | InjectionDescriptor<Value>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The value a factory receives for one declared dependency.
|
|
40
|
+
*
|
|
41
|
+
* @remarks `optional()` and `injectAll()` fold their effect into the descriptor's own type
|
|
42
|
+
* parameter, so reading it back is enough; bare tokens fall through to {@link TokenValue}.
|
|
43
|
+
*
|
|
44
|
+
* @since 0.5.0-canary.7
|
|
45
|
+
*/
|
|
46
|
+
export type ResolvedDependencyValue<Dependency> = Dependency extends { readonly multi: true }
|
|
47
|
+
? Array<DescribedValue<Dependency>>
|
|
48
|
+
: Dependency extends { readonly optional: true }
|
|
49
|
+
? DescribedValue<Dependency> | undefined
|
|
50
|
+
: DescribedValue<Dependency>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The value a dependency's own type parameter carries, before its flags are read.
|
|
54
|
+
*
|
|
55
|
+
* @remarks Split out because a hand-written descriptor states its flags and its value type
|
|
56
|
+
* separately, and only the flags are load-bearing: `{ token: Plugin, multi: true }` says `Plugin`
|
|
57
|
+
* and delivers `Array<Plugin>`. `injectAll()` and `optional()` already fold their effect in, so the
|
|
58
|
+
* flags find an array or an optional there and leave it alone.
|
|
59
|
+
*/
|
|
60
|
+
type DescribedValue<Dependency> = Dependency extends InjectionDescriptor<infer Value> ? Value : TokenValue<Dependency>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @since 0.3.16-canary.0
|
|
64
|
+
*/
|
|
65
|
+
export function isInjectionDescriptor(value: unknown): value is InjectionDescriptor {
|
|
66
|
+
if (value === null || value === undefined) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const type = typeof value;
|
|
70
|
+
// inject() returns a function (dual-role), so must check both object and function
|
|
71
|
+
if (type !== "object" && type !== "function") {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return (
|
|
75
|
+
"token" in (value as object) &&
|
|
76
|
+
"optional" in (value as object) &&
|
|
77
|
+
"multi" in (value as object) &&
|
|
78
|
+
typeof (value as InjectionDescriptor).optional === "boolean" &&
|
|
79
|
+
typeof (value as InjectionDescriptor).multi === "boolean"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @since 0.3.16-canary.0
|
|
85
|
+
*/
|
|
86
|
+
export function normalizeToDescriptor(dependency: InjectableDependency): InjectionDescriptor {
|
|
87
|
+
if (isInjectionDescriptor(dependency)) {
|
|
88
|
+
return materializeInjectionDescriptor(dependency);
|
|
89
|
+
}
|
|
90
|
+
return { token: dependency, optional: false, multi: false };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Dual-role `inject()` values are functions: [[Function]].name must not be treated as a DI slot name.
|
|
95
|
+
* Only enumerable own `name` / `tags` from `Object.defineProperties` are real injection options.
|
|
96
|
+
*/
|
|
97
|
+
function materializeInjectionDescriptor(dependency: InjectionDescriptor): InjectionDescriptor {
|
|
98
|
+
if (typeof dependency !== "function") {
|
|
99
|
+
return dependency;
|
|
100
|
+
}
|
|
101
|
+
const dualRole = dependency as InjectionDescriptor & ((...args: Array<unknown>) => unknown);
|
|
102
|
+
const base: Pick<InjectionDescriptor, "token" | "optional" | "multi"> = {
|
|
103
|
+
token: dualRole.token,
|
|
104
|
+
optional: dualRole.optional,
|
|
105
|
+
multi: dualRole.multi,
|
|
106
|
+
};
|
|
107
|
+
const nameDesc = Object.getOwnPropertyDescriptor(dualRole, "name");
|
|
108
|
+
const tagsDesc = Object.getOwnPropertyDescriptor(dualRole, "tags");
|
|
109
|
+
const explicitName = nameDesc?.enumerable === true && typeof nameDesc.value === "string" ? nameDesc.value : undefined;
|
|
110
|
+
// Annotated because `PropertyDescriptor.value` is `any`, and an `any` reaching the cast below
|
|
111
|
+
// would make it look checked when nothing checked it.
|
|
112
|
+
const explicitTags: unknown = tagsDesc?.enumerable === true ? tagsDesc.value : undefined;
|
|
113
|
+
|
|
114
|
+
if (explicitName !== undefined && explicitTags !== undefined) {
|
|
115
|
+
return {
|
|
116
|
+
...base,
|
|
117
|
+
name: explicitName,
|
|
118
|
+
tags: explicitTags as NonNullable<InjectionDescriptor["tags"]>,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (explicitName !== undefined) {
|
|
122
|
+
return { ...base, name: explicitName };
|
|
123
|
+
}
|
|
124
|
+
if (explicitTags !== undefined) {
|
|
125
|
+
return { ...base, tags: explicitTags as NonNullable<InjectionDescriptor["tags"]> };
|
|
126
|
+
}
|
|
127
|
+
return base;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The one tag list a request carries, with the single-tag shorthand folded in.
|
|
132
|
+
*
|
|
133
|
+
* @remarks Folding here is what keeps `tag` from reaching `InjectionDescriptor` and everything
|
|
134
|
+
* derived from it, so one request never has two spellings past this point.
|
|
135
|
+
*/
|
|
136
|
+
function requestedTagsOf(options: InjectOptions | undefined): ReadonlyArray<BindingTag> | undefined {
|
|
137
|
+
const shorthand = options?.tag;
|
|
138
|
+
const listed = options?.tags;
|
|
139
|
+
if (shorthand === undefined) {
|
|
140
|
+
return listed;
|
|
141
|
+
}
|
|
142
|
+
return listed === undefined || listed.length === 0 ? [shorthand] : [shorthand, ...listed];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function withOptions<DescValue>(
|
|
146
|
+
base: Pick<InjectionDescriptor<DescValue>, "token" | "optional" | "multi">,
|
|
147
|
+
options: InjectOptions | undefined,
|
|
148
|
+
): InjectionDescriptor<DescValue> {
|
|
149
|
+
const tags = requestedTagsOf(options);
|
|
150
|
+
if (options?.name !== undefined && tags !== undefined) {
|
|
151
|
+
return { ...base, name: options.name, tags };
|
|
152
|
+
}
|
|
153
|
+
if (options?.name !== undefined) {
|
|
154
|
+
return { ...base, name: options.name };
|
|
155
|
+
}
|
|
156
|
+
if (tags !== undefined) {
|
|
157
|
+
return { ...base, tags };
|
|
158
|
+
}
|
|
159
|
+
return base;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* The descriptor half of `inject()`, shared with the accessor decorator that wraps it.
|
|
164
|
+
*
|
|
165
|
+
* @since 0.6.0
|
|
166
|
+
*/
|
|
167
|
+
export function buildInjectionDescriptor<Value>(
|
|
168
|
+
token: Token<Value> | Constructor<Value>,
|
|
169
|
+
options?: InjectOptions,
|
|
170
|
+
): InjectionDescriptor<Value> {
|
|
171
|
+
return withOptions({ token, optional: false, multi: false }, options);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @since 0.3.16-canary.0
|
|
176
|
+
*/
|
|
177
|
+
export function optional<Value>(
|
|
178
|
+
token: Token<Value> | Constructor<Value>,
|
|
179
|
+
options?: InjectOptions,
|
|
180
|
+
): InjectionDescriptor<Value | undefined> {
|
|
181
|
+
return withOptions(
|
|
182
|
+
{
|
|
183
|
+
token: token as Token<Value | undefined> | Constructor<Value | undefined>,
|
|
184
|
+
optional: true,
|
|
185
|
+
multi: false,
|
|
186
|
+
},
|
|
187
|
+
options,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @since 0.3.16-canary.0
|
|
193
|
+
*/
|
|
194
|
+
export function injectAll<Value>(
|
|
195
|
+
token: Token<Value> | Constructor<Value>,
|
|
196
|
+
options?: InjectOptions,
|
|
197
|
+
): InjectionDescriptor<Array<Value>> {
|
|
198
|
+
return withOptions(
|
|
199
|
+
{
|
|
200
|
+
token: token as Token<Array<Value>> | Constructor<Array<Value>>,
|
|
201
|
+
optional: false,
|
|
202
|
+
multi: true,
|
|
203
|
+
},
|
|
204
|
+
options,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { BindingTag } from "#/core/tag";
|
|
2
|
+
import type { Token } from "#/core/token";
|
|
3
|
+
import type { Constructor, ResolveOptions } from "#/core/types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* What one resolvable dependency declares.
|
|
7
|
+
*
|
|
8
|
+
* @remarks Both dependency sources — a constructor's `ParamMetadata` and a `toResolved`
|
|
9
|
+
* `InjectionDescriptor` — are this shape, which is why one resolve routine serves both.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.5.0-canary.9
|
|
12
|
+
*/
|
|
13
|
+
export interface DependencySlot {
|
|
14
|
+
readonly token: Token<unknown> | Constructor;
|
|
15
|
+
readonly optional: boolean;
|
|
16
|
+
readonly multi: boolean;
|
|
17
|
+
readonly name?: string | undefined;
|
|
18
|
+
readonly tags?: ReadonlyArray<BindingTag> | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A request whose only criterion is a name — the shape the registry has a direct index for.
|
|
23
|
+
*
|
|
24
|
+
* @since 0.5.0-canary.9
|
|
25
|
+
*/
|
|
26
|
+
export function isNameOnlyOptions(options: ResolveOptions): options is ResolveOptions & { name: string } {
|
|
27
|
+
return (
|
|
28
|
+
options.name !== undefined && options.tag === undefined && (options.tags === undefined || options.tags.length === 0)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The lone tag of a request that asks for exactly one, written either way — the shape the registry
|
|
34
|
+
* has a direct tag index for.
|
|
35
|
+
*
|
|
36
|
+
* @remarks Both spellings answer here, so the index is not something one of them silently misses.
|
|
37
|
+
*
|
|
38
|
+
* @since 0.5.0-canary.9
|
|
39
|
+
*/
|
|
40
|
+
export function singleTagOnlyOf(options: ResolveOptions): BindingTag | undefined {
|
|
41
|
+
if (options.name !== undefined) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const listed = options.tags;
|
|
45
|
+
const shorthand = options.tag;
|
|
46
|
+
if (shorthand !== undefined) {
|
|
47
|
+
// Both sources present means the request carries two tags, which no single-tag index can answer.
|
|
48
|
+
return listed === undefined || listed.length === 0 ? shorthand : undefined;
|
|
49
|
+
}
|
|
50
|
+
return listed !== undefined && listed.length === 1 ? listed[0] : undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Shared core: build a ResolveOptions from already-normalised name + tags. */
|
|
54
|
+
function buildOptions(
|
|
55
|
+
name: string | undefined,
|
|
56
|
+
tags: ReadonlyArray<BindingTag> | undefined,
|
|
57
|
+
): ResolveOptions | undefined {
|
|
58
|
+
if (name === undefined && tags === undefined) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const options: ResolveOptions = {};
|
|
62
|
+
if (name !== undefined) {
|
|
63
|
+
options.name = name;
|
|
64
|
+
}
|
|
65
|
+
if (tags !== undefined) {
|
|
66
|
+
options.tags = tags;
|
|
67
|
+
}
|
|
68
|
+
return options;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Builds a {@link ResolveOptions} safe for `exactOptionalPropertyTypes`:
|
|
73
|
+
* omits keys instead of assigning `undefined`.
|
|
74
|
+
*
|
|
75
|
+
* @since 0.3.16-canary.0
|
|
76
|
+
*/
|
|
77
|
+
export function injectionSlotToResolveOptions(
|
|
78
|
+
injectionSlot: Pick<DependencySlot, "name" | "tags">,
|
|
79
|
+
): ResolveOptions | undefined {
|
|
80
|
+
return buildOptions(injectionSlot.name, injectionSlot.tags);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Where a slot's derived options are memoized, so the same object is handed out every resolve. */
|
|
84
|
+
const MEMOIZED_RESOLVE_OPTIONS: unique symbol = Symbol("di:resolve-options");
|
|
85
|
+
|
|
86
|
+
interface SlotWithMemoizedOptions {
|
|
87
|
+
[MEMOIZED_RESOLVE_OPTIONS]?: ResolveOptions;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The options a dependency resolves with — one object per slot, since a slot's criteria are fixed
|
|
92
|
+
* when it is declared.
|
|
93
|
+
*
|
|
94
|
+
* @remarks A slot carrying no criterion answers from its two fields, so the common shape never
|
|
95
|
+
* reaches the memo.
|
|
96
|
+
*
|
|
97
|
+
* @since 0.6.0
|
|
98
|
+
*/
|
|
99
|
+
export function resolveOptionsForSlot(injectionSlot: DependencySlot): ResolveOptions | undefined {
|
|
100
|
+
const { name, tags } = injectionSlot;
|
|
101
|
+
if (name === undefined && tags === undefined) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
const slot = injectionSlot as SlotWithMemoizedOptions;
|
|
105
|
+
const memoized = slot[MEMOIZED_RESOLVE_OPTIONS];
|
|
106
|
+
return memoized ?? memoizeResolveOptions(slot, name, tags);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Builds, freezes and stores a slot's options on first use.
|
|
111
|
+
*
|
|
112
|
+
* @remarks Frozen because one object answers every resolve of the slot and a constraint predicate is
|
|
113
|
+
* handed it. Split out for the `try`: in the caller it would cost the early return its inlining.
|
|
114
|
+
*/
|
|
115
|
+
function memoizeResolveOptions(
|
|
116
|
+
slot: SlotWithMemoizedOptions,
|
|
117
|
+
name: string | undefined,
|
|
118
|
+
tags: ReadonlyArray<BindingTag> | undefined,
|
|
119
|
+
): ResolveOptions {
|
|
120
|
+
const built = Object.freeze(buildOptions(name, tags) as ResolveOptions);
|
|
121
|
+
try {
|
|
122
|
+
slot[MEMOIZED_RESOLVE_OPTIONS] = built;
|
|
123
|
+
} catch {
|
|
124
|
+
// A frozen slot rebuilds on every hop rather than throwing.
|
|
125
|
+
}
|
|
126
|
+
return built;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Resolve options derived from a binding slot (tags may be empty; omits when nothing to match).
|
|
131
|
+
*
|
|
132
|
+
* @remarks Takes the slot structurally rather than as `BindingSlot`, so the slot on a public
|
|
133
|
+
* `BindingSnapshot` — where `name` is an optional property, not a required one holding `undefined` —
|
|
134
|
+
* is accepted by the same call.
|
|
135
|
+
*
|
|
136
|
+
* @since 0.3.16-canary.0
|
|
137
|
+
*/
|
|
138
|
+
export function bindingSlotToResolveOptions(bindingSlot: {
|
|
139
|
+
readonly name?: string | undefined;
|
|
140
|
+
readonly tags?: ReadonlyArray<BindingTag> | undefined;
|
|
141
|
+
}): ResolveOptions | undefined {
|
|
142
|
+
const tags = bindingSlot.tags;
|
|
143
|
+
return buildOptions(bindingSlot.name, tags !== undefined && tags.length > 0 ? tags : undefined);
|
|
144
|
+
}
|