@typewirets/inversify 0.1.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/LICENSE +21 -0
- package/README.md +183 -0
- package/dist/cjs/index.d.ts +114 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +182 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.d.ts +114 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +176 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/types/index.d.ts +114 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +176 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +69 -0
- package/src/index.ts +199 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyTypeSymbol,
|
|
3
|
+
AnyTypeWire,
|
|
4
|
+
BindingContext,
|
|
5
|
+
TypeSymbol,
|
|
6
|
+
ResolutionContext as TypeWireResolutionContext,
|
|
7
|
+
} from "@typewirets/core";
|
|
8
|
+
import type { BindingScope, Container } from "inversify";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Converts a TypeWire scope string to the equivalent InversifyJS BindingScope.
|
|
12
|
+
*
|
|
13
|
+
* @param scope - The TypeWire scope string (e.g., 'singleton', 'transient', 'request')
|
|
14
|
+
* @returns The equivalent InversifyJS BindingScope or undefined if no conversion is possible
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Convert a TypeWire scope to InversifyJS scope
|
|
19
|
+
* const inversifyScope = adoptScope('singleton'); // returns 'Singleton'
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function adoptScope(scope?: string): BindingScope | undefined {
|
|
23
|
+
if (!scope) {
|
|
24
|
+
return "Singleton";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
switch (scope.toLowerCase()) {
|
|
28
|
+
case "singleton":
|
|
29
|
+
return "Singleton";
|
|
30
|
+
case "transient":
|
|
31
|
+
return "Transient";
|
|
32
|
+
case "request":
|
|
33
|
+
return "Request";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Adapter class that provides both TypeWire ResolutionContext and BindingContext
|
|
39
|
+
* interfaces on top of an InversifyJS container.
|
|
40
|
+
*
|
|
41
|
+
* This adapter allows TypeWire definitions to work with an existing InversifyJS
|
|
42
|
+
* container, providing a bridge between the two dependency injection systems.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const container = new Container();
|
|
47
|
+
* const adapter = new InversifyAdapter(container);
|
|
48
|
+
*
|
|
49
|
+
* // Now you can use TypeWire with your InversifyJS container
|
|
50
|
+
* await serviceWire.apply(adapter);
|
|
51
|
+
* const service = await serviceWire.getInstance(adapter);
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export class InversifyAdapter
|
|
55
|
+
implements TypeWireResolutionContext, BindingContext
|
|
56
|
+
{
|
|
57
|
+
/**
|
|
58
|
+
* Set of symbols for which instances have been loaded/initialized.
|
|
59
|
+
* Used to track which singleton instances have already been created.
|
|
60
|
+
*/
|
|
61
|
+
private readonly loaded: Set<symbol> = new Set();
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Set of symbols that represent singleton-scoped dependencies.
|
|
65
|
+
*/
|
|
66
|
+
private readonly singletons: Set<symbol> = new Set();
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Creates a new InversifyAdapter for the specified container.
|
|
70
|
+
*
|
|
71
|
+
* @param container - The InversifyJS container to adapt
|
|
72
|
+
*/
|
|
73
|
+
constructor(readonly container: Container) {}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Checks if a symbol represents a singleton-scoped dependency.
|
|
77
|
+
*
|
|
78
|
+
* @param symbol - The symbol to check
|
|
79
|
+
* @returns True if the dependency is singleton-scoped, false otherwise
|
|
80
|
+
*/
|
|
81
|
+
#isSingleton(symbol: symbol): boolean {
|
|
82
|
+
return this.singletons.has(symbol);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Gets an instance of type T synchronously.
|
|
87
|
+
* For singleton-scoped dependencies, also tracks that they have been loaded.
|
|
88
|
+
*
|
|
89
|
+
* @template T - The type of instance to get
|
|
90
|
+
* @param typeSymbol - The type symbol identifying the dependency
|
|
91
|
+
* @returns An instance of type T
|
|
92
|
+
* @throws Error if the dependency cannot be resolved synchronously
|
|
93
|
+
*/
|
|
94
|
+
getSync<T>(typeSymbol: AnyTypeSymbol): T {
|
|
95
|
+
if (!this.#isSingleton(typeSymbol.symbol)) {
|
|
96
|
+
return this.container.get(typeSymbol.symbol);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const result = this.container.get(typeSymbol.symbol) as T;
|
|
100
|
+
this.loaded.add(typeSymbol.symbol);
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Gets an instance of type T asynchronously.
|
|
106
|
+
* For singleton-scoped dependencies, also tracks that they have been loaded.
|
|
107
|
+
*
|
|
108
|
+
* @template T - The type of instance to get
|
|
109
|
+
* @param typeSymbol - The type symbol identifying the dependency
|
|
110
|
+
* @returns A promise that resolves to an instance of type T
|
|
111
|
+
* @throws Error if the dependency is not found
|
|
112
|
+
*/
|
|
113
|
+
async get<T>(typeSymbol: TypeSymbol<T>): Promise<T> {
|
|
114
|
+
if (!this.#isSingleton(typeSymbol.symbol)) {
|
|
115
|
+
return this.container.getAsync(typeSymbol.symbol);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const result = await this.container.getAsync(typeSymbol.symbol);
|
|
119
|
+
this.loaded.add(typeSymbol.symbol);
|
|
120
|
+
return result as T;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Binds a TypeWire to the InversifyJS container.
|
|
125
|
+
* Configures the binding with the appropriate scope and creator function.
|
|
126
|
+
*
|
|
127
|
+
* @param typeWire - The TypeWire to bind
|
|
128
|
+
*/
|
|
129
|
+
bind(typeWire: AnyTypeWire): void | Promise<void> {
|
|
130
|
+
const bound = this.container
|
|
131
|
+
.bind(typeWire.type.symbol)
|
|
132
|
+
.toDynamicValue((_ctx) => {
|
|
133
|
+
return typeWire.creator(this);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const scope = adoptScope(typeWire.scope);
|
|
137
|
+
if (scope) {
|
|
138
|
+
switch (scope) {
|
|
139
|
+
case "Singleton":
|
|
140
|
+
this.singletons.add(typeWire.type.symbol);
|
|
141
|
+
bound.inSingletonScope();
|
|
142
|
+
break;
|
|
143
|
+
case "Transient":
|
|
144
|
+
bound.inTransientScope();
|
|
145
|
+
break;
|
|
146
|
+
case "Request":
|
|
147
|
+
bound.inRequestScope();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Removes a binding from the InversifyJS container.
|
|
154
|
+
* Also removes any tracking information for the binding.
|
|
155
|
+
*
|
|
156
|
+
* @param typeSymbol - The type symbol identifying the binding to remove
|
|
157
|
+
* @returns A promise that resolves when the unbinding is complete
|
|
158
|
+
*/
|
|
159
|
+
async unbind(typeSymbol: AnyTypeSymbol): Promise<void> {
|
|
160
|
+
this.loaded.delete(typeSymbol.symbol);
|
|
161
|
+
this.singletons.delete(typeSymbol.symbol);
|
|
162
|
+
return this.container.unbind(typeSymbol.symbol);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Checks if a binding exists in the InversifyJS container.
|
|
167
|
+
*
|
|
168
|
+
* @param typeSymbol - The type symbol to check
|
|
169
|
+
* @returns True if the binding exists, false otherwise
|
|
170
|
+
*/
|
|
171
|
+
isBound(typeSymbol: AnyTypeSymbol): boolean {
|
|
172
|
+
return this.container.isBound(typeSymbol.symbol);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Creates an adapter that provides both TypeWire ResolutionContext and BindingContext
|
|
178
|
+
* interfaces using an InversifyJS container.
|
|
179
|
+
*
|
|
180
|
+
* This is a convenience function for creating an InversifyAdapter.
|
|
181
|
+
*
|
|
182
|
+
* @param container - The InversifyJS container to adapt
|
|
183
|
+
* @returns An object implementing both TypeWire interfaces
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* const container = new Container();
|
|
188
|
+
* const adapter = createInversifyAdapter(container);
|
|
189
|
+
*
|
|
190
|
+
* // Now you can use TypeWire with your InversifyJS container
|
|
191
|
+
* await serviceWire.apply(adapter);
|
|
192
|
+
* const service = await serviceWire.getInstance(adapter);
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
export function createInversifyAdapter(
|
|
196
|
+
container: Container,
|
|
197
|
+
): TypeWireResolutionContext & BindingContext {
|
|
198
|
+
return new InversifyAdapter(container);
|
|
199
|
+
}
|