@codefast/di 0.3.16-canary.2 → 0.4.0-canary.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +5 -17
- package/dist/binding.d.mts +24 -24
- package/dist/constraints.d.mts +3 -3
- package/dist/container.d.mts +3 -3
- package/dist/container.mjs +89 -157
- package/dist/decorators/inject.d.mts +3 -2
- package/dist/decorators/inject.mjs +14 -41
- package/dist/decorators/injectable.mjs +4 -12
- package/dist/decorators/lifecycle-decorators.mjs +13 -74
- package/dist/dependency-graph.d.mts +1 -1
- package/dist/dependency-graph.mjs +6 -4
- package/dist/graph-adapters/cytoscape.d.mts +12 -12
- package/dist/graph-adapters/cytoscape.mjs +7 -7
- package/dist/graph-adapters/reactflow.d.mts +15 -15
- package/dist/graph-adapters/reactflow.mjs +6 -9
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +1 -1
- package/dist/inspector.d.mts +3 -2
- package/dist/inspector.mjs +7 -10
- package/dist/lifecycle.mjs +2 -12
- package/dist/metadata/metadata-keys.d.mts +8 -33
- package/dist/metadata/metadata-keys.mjs +8 -21
- package/dist/metadata/metadata-types.d.mts +5 -0
- package/dist/metadata/symbol-metadata-reader.d.mts +1 -0
- package/dist/metadata/symbol-metadata-reader.mjs +11 -33
- package/dist/module.mjs +1 -1
- package/dist/registry.mjs +3 -22
- package/dist/resolve-options.d.mts +2 -2
- package/dist/resolve-options.mjs +10 -8
- package/dist/resolver.d.mts +6 -1
- package/dist/resolver.mjs +15 -21
- package/dist/types.d.mts +10 -4
- package/package.json +40 -14
- package/src/binding-scope.ts +26 -0
- package/src/binding-select.ts +158 -0
- package/src/binding.ts +277 -0
- package/src/constraints.ts +121 -0
- package/src/constructor-type.ts +19 -0
- package/src/container.ts +1135 -0
- package/src/decorators/inject.ts +222 -0
- package/src/decorators/injectable.ts +85 -0
- package/src/decorators/lifecycle-decorators.ts +51 -0
- package/src/dependency-graph.ts +116 -0
- package/src/environment.ts +207 -0
- package/src/errors.ts +260 -0
- package/src/graph-adapters/cytoscape.ts +64 -0
- package/src/graph-adapters/dot.ts +22 -0
- package/src/graph-adapters/reactflow.ts +58 -0
- package/src/index.ts +101 -0
- package/src/inspector.ts +125 -0
- package/src/lifecycle.ts +217 -0
- package/src/metadata/metadata-keys.ts +25 -0
- package/src/metadata/metadata-reader-token.ts +8 -0
- package/src/metadata/metadata-types.ts +51 -0
- package/src/metadata/symbol-metadata-reader.ts +45 -0
- package/src/module.ts +93 -0
- package/src/registry.ts +232 -0
- package/src/resolve-options.ts +42 -0
- package/src/resolver.ts +1609 -0
- package/src/scope.ts +77 -0
- package/src/token.ts +40 -0
- package/src/types.ts +123 -0
- package/dist/graph-adapters/types.d.mts +0 -2
- package/dist/graph-adapters/types.mjs +0 -1
package/src/scope.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { MissingScopeContextError } from "#/errors";
|
|
2
|
+
import type { BindingIdentifier } from "#/types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @since 0.3.16-canary.0
|
|
6
|
+
*/
|
|
7
|
+
export class ScopeManager {
|
|
8
|
+
// Singleton cache: bindingId -> instance
|
|
9
|
+
private readonly _singletons = new Map<BindingIdentifier, unknown>();
|
|
10
|
+
// In-flight promises for async singleton creation
|
|
11
|
+
private readonly _inflight = new Map<BindingIdentifier, Promise<unknown>>();
|
|
12
|
+
// Scoped cache (for child containers): bindingId -> instance
|
|
13
|
+
private readonly _scoped = new Map<BindingIdentifier, unknown>();
|
|
14
|
+
|
|
15
|
+
readonly isChild: boolean;
|
|
16
|
+
|
|
17
|
+
constructor(isChild = false) {
|
|
18
|
+
this.isChild = isChild;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
hasSingleton(id: BindingIdentifier): boolean {
|
|
22
|
+
return this._singletons.has(id);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getSingleton<Value>(id: BindingIdentifier): Value {
|
|
26
|
+
return this._singletons.get(id) as Value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setSingleton(id: BindingIdentifier, instance: unknown): void {
|
|
30
|
+
this._singletons.set(id, instance);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
deleteSingleton(id: BindingIdentifier): boolean {
|
|
34
|
+
return this._singletons.delete(id);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getAllSingletons(): ReadonlyMap<BindingIdentifier, unknown> {
|
|
38
|
+
return this._singletons;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getInflight(id: BindingIdentifier): Promise<unknown> | undefined {
|
|
42
|
+
return this._inflight.get(id);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setInflight(id: BindingIdentifier, p: Promise<unknown>): void {
|
|
46
|
+
this._inflight.set(id, p);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
clearInflight(id: BindingIdentifier): void {
|
|
50
|
+
this._inflight.delete(id);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
hasScoped(id: BindingIdentifier): boolean {
|
|
54
|
+
return this._scoped.has(id);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getScoped<Value>(id: BindingIdentifier): Value {
|
|
58
|
+
return this._scoped.get(id) as Value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setScoped(id: BindingIdentifier, instance: unknown): void {
|
|
62
|
+
if (!this.isChild) {
|
|
63
|
+
throw new MissingScopeContextError("(unknown)");
|
|
64
|
+
}
|
|
65
|
+
this._scoped.set(id, instance);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getAllScoped(): ReadonlyMap<BindingIdentifier, unknown> {
|
|
69
|
+
return this._scoped;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
clearAll(): void {
|
|
73
|
+
this._singletons.clear();
|
|
74
|
+
this._inflight.clear();
|
|
75
|
+
this._scoped.clear();
|
|
76
|
+
}
|
|
77
|
+
}
|
package/src/token.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Constructor } from "#/constructor-type";
|
|
2
|
+
|
|
3
|
+
declare const TOKEN_BRAND: unique symbol;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @since 0.3.16-canary.0
|
|
7
|
+
*/
|
|
8
|
+
export interface Token<Value> {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly [TOKEN_BRAND]: Value;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @since 0.3.16-canary.0
|
|
15
|
+
*/
|
|
16
|
+
export function token<Value>(name: string): Token<Value> {
|
|
17
|
+
return { name } as Token<Value>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @since 0.3.16-canary.0
|
|
22
|
+
*/
|
|
23
|
+
export function tokenName(dependency: Token<unknown> | Constructor): string {
|
|
24
|
+
if (typeof dependency === "function") {
|
|
25
|
+
return dependency.name;
|
|
26
|
+
}
|
|
27
|
+
return dependency.name;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @since 0.3.16-canary.0
|
|
32
|
+
*/
|
|
33
|
+
export function isToken(value: unknown): value is Token<unknown> {
|
|
34
|
+
return (
|
|
35
|
+
typeof value === "object" &&
|
|
36
|
+
value !== null &&
|
|
37
|
+
"name" in value &&
|
|
38
|
+
typeof (value as Record<string, unknown>)["name"] === "string"
|
|
39
|
+
);
|
|
40
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { Constructor } from "#/constructor-type";
|
|
2
|
+
import type { Token } from "#/token";
|
|
3
|
+
|
|
4
|
+
// Re-export for consumers that import from `#/types`
|
|
5
|
+
export type { Constructor } from "#/constructor-type";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A single [tag, value] pair used in slot constraints and resolve hints.
|
|
9
|
+
*
|
|
10
|
+
* @since 0.3.16-canary.0
|
|
11
|
+
*/
|
|
12
|
+
export type BindingTag = readonly [tag: string, value: unknown];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Token or class constructor used as a binding / injection / resolve key.
|
|
16
|
+
*
|
|
17
|
+
* @since 0.3.16-canary.0
|
|
18
|
+
*/
|
|
19
|
+
export type DependencyKey = Token<unknown> | Constructor;
|
|
20
|
+
|
|
21
|
+
// ── BindingScope ────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @since 0.3.16-canary.0
|
|
25
|
+
*/
|
|
26
|
+
export type BindingScope = "singleton" | "transient" | "scoped";
|
|
27
|
+
|
|
28
|
+
// ── BindingIdentifier ────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
declare const BINDING_ID_BRAND: unique symbol;
|
|
31
|
+
/**
|
|
32
|
+
* @since 0.3.16-canary.0
|
|
33
|
+
*/
|
|
34
|
+
export type BindingIdentifier = string & { readonly [BINDING_ID_BRAND]: true };
|
|
35
|
+
|
|
36
|
+
// ── BindingKind ───────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @since 0.3.16-canary.0
|
|
40
|
+
*/
|
|
41
|
+
export type BindingKind = "class" | "dynamic" | "dynamic-async" | "resolved" | "resolved-async" | "constant" | "alias";
|
|
42
|
+
|
|
43
|
+
// ── Handlers ─────────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @since 0.3.16-canary.0
|
|
47
|
+
*/
|
|
48
|
+
export type ActivationHandler<Value> = (ctx: ResolutionContext, instance: Value) => Value | Promise<Value>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @since 0.3.16-canary.0
|
|
52
|
+
*/
|
|
53
|
+
export type DeactivationHandler<Value> = (instance: Value) => void | Promise<void>;
|
|
54
|
+
|
|
55
|
+
// ── ResolveOptions ────────────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @since 0.3.16-canary.0
|
|
59
|
+
*/
|
|
60
|
+
export interface ResolveOptions {
|
|
61
|
+
name?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Single-tag shorthand — semantics match including one pair in `tags`.
|
|
64
|
+
* Enables fast-path lookup alongside `tags`.
|
|
65
|
+
*/
|
|
66
|
+
tag?: BindingTag;
|
|
67
|
+
tags?: ReadonlyArray<BindingTag>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ── ResolutionFrame ──────────────────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @since 0.3.16-canary.0
|
|
74
|
+
*/
|
|
75
|
+
export interface ResolutionFrame {
|
|
76
|
+
readonly tokenName: string;
|
|
77
|
+
readonly scope: BindingScope;
|
|
78
|
+
readonly bindingId: BindingIdentifier;
|
|
79
|
+
readonly kind: BindingKind;
|
|
80
|
+
readonly slot: {
|
|
81
|
+
readonly name: string | undefined;
|
|
82
|
+
readonly tags: ReadonlyArray<BindingTag>;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── ConstraintContext ─────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @since 0.3.16-canary.0
|
|
90
|
+
*/
|
|
91
|
+
export interface ConstraintContext {
|
|
92
|
+
readonly resolutionPath: ReadonlyArray<string>;
|
|
93
|
+
readonly resolutionStack: ReadonlyArray<ResolutionFrame>;
|
|
94
|
+
readonly parent: ResolutionFrame | undefined;
|
|
95
|
+
readonly ancestors: ReadonlyArray<ResolutionFrame>;
|
|
96
|
+
readonly currentResolveHint: ResolveOptions | undefined;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── ResolutionContext ─────────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @since 0.3.16-canary.0
|
|
103
|
+
*/
|
|
104
|
+
export interface ResolutionContext {
|
|
105
|
+
resolve<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value;
|
|
106
|
+
resolveAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Value>;
|
|
107
|
+
resolveOptional<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Value | undefined;
|
|
108
|
+
resolveOptionalAsync<const Value>(
|
|
109
|
+
token: Token<Value> | Constructor<Value>,
|
|
110
|
+
hint?: ResolveOptions,
|
|
111
|
+
): Promise<Value | undefined>;
|
|
112
|
+
resolveAll<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Array<Value>;
|
|
113
|
+
resolveAllAsync<const Value>(token: Token<Value> | Constructor<Value>, hint?: ResolveOptions): Promise<Array<Value>>;
|
|
114
|
+
readonly graph: ConstraintContext;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── TokenValue ────────────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @since 0.3.16-canary.0
|
|
121
|
+
*/
|
|
122
|
+
export type TokenValue<Type> =
|
|
123
|
+
Type extends Token<infer Value> ? Value : Type extends Constructor<infer Value> ? Value : never;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|