@djodjonx/wiredi 0.0.2
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 +22 -0
- package/README.md +516 -0
- package/dist/index.cjs +931 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1139 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +1139 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +915 -0
- package/dist/index.mjs.map +1 -0
- package/dist/plugin/ConfigurationAnalyzer.d.ts +59 -0
- package/dist/plugin/ConfigurationAnalyzer.d.ts.map +1 -0
- package/dist/plugin/ConfigurationAnalyzer.js +321 -0
- package/dist/plugin/ConfigurationAnalyzer.js.map +1 -0
- package/dist/plugin/DependencyAnalyzer.d.ts +54 -0
- package/dist/plugin/DependencyAnalyzer.d.ts.map +1 -0
- package/dist/plugin/DependencyAnalyzer.js +208 -0
- package/dist/plugin/DependencyAnalyzer.js.map +1 -0
- package/dist/plugin/TokenNormalizer.d.ts +51 -0
- package/dist/plugin/TokenNormalizer.d.ts.map +1 -0
- package/dist/plugin/TokenNormalizer.js +208 -0
- package/dist/plugin/TokenNormalizer.js.map +1 -0
- package/dist/plugin/ValidationEngine.d.ts +53 -0
- package/dist/plugin/ValidationEngine.d.ts.map +1 -0
- package/dist/plugin/ValidationEngine.js +250 -0
- package/dist/plugin/ValidationEngine.js.map +1 -0
- package/dist/plugin/index.d.ts +2 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +144 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/package.json +6 -0
- package/dist/plugin/types.d.ts +152 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/plugin/types.js +3 -0
- package/dist/plugin/types.js.map +1 -0
- package/package.json +95 -0
- package/plugin.js +1 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,931 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
let awilix = require("awilix");
|
|
3
|
+
|
|
4
|
+
//#region src/Provider/types.ts
|
|
5
|
+
/**
|
|
6
|
+
* Dependency lifecycle options
|
|
7
|
+
* Independent of the underlying container implementation
|
|
8
|
+
*/
|
|
9
|
+
let ProviderLifecycle = /* @__PURE__ */ function(ProviderLifecycle) {
|
|
10
|
+
/** Single shared instance throughout the application (default) */
|
|
11
|
+
ProviderLifecycle["Singleton"] = "singleton";
|
|
12
|
+
/** New instance created on each resolution */
|
|
13
|
+
ProviderLifecycle["Transient"] = "transient";
|
|
14
|
+
/** One instance per scope/child container */
|
|
15
|
+
ProviderLifecycle["Scoped"] = "scoped";
|
|
16
|
+
return ProviderLifecycle;
|
|
17
|
+
}({});
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/Provider/ProviderManager.ts
|
|
21
|
+
/**
|
|
22
|
+
* Currently configured global provider
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
let currentProvider = null;
|
|
26
|
+
/**
|
|
27
|
+
* Configures the DI container provider to use globally
|
|
28
|
+
*
|
|
29
|
+
* Must be called ONCE at the application entry point,
|
|
30
|
+
* before any calls to `useBuilder`.
|
|
31
|
+
*
|
|
32
|
+
* @param provider - The provider instance to use
|
|
33
|
+
* @throws Error if a provider is already configured
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* // main.ts - Application entry point
|
|
38
|
+
* import 'reflect-metadata'
|
|
39
|
+
* import { container, Lifecycle } from 'tsyringe'
|
|
40
|
+
* import { useContainerProvider, TsyringeProvider } from '@djodjonx/wiredi'
|
|
41
|
+
*
|
|
42
|
+
* useContainerProvider(new TsyringeProvider({ container, Lifecycle }))
|
|
43
|
+
*
|
|
44
|
+
* // Now useBuilder can be used anywhere
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function useContainerProvider(provider) {
|
|
48
|
+
if (currentProvider !== null) throw new Error(`[WireDI] Provider already configured (${currentProvider.name}). useContainerProvider() should only be called once at app entry point. Use resetContainerProvider() first if you need to reconfigure.`);
|
|
49
|
+
currentProvider = provider;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Retrieves the configured container provider
|
|
53
|
+
*
|
|
54
|
+
* @returns The configured provider instance
|
|
55
|
+
* @throws Error if no provider is configured
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const provider = getContainerProvider()
|
|
60
|
+
* const service = provider.resolve(MyService)
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
function getContainerProvider() {
|
|
64
|
+
if (currentProvider === null) throw new Error("[WireDI] No container provider configured. Call useContainerProvider(provider) at your app entry point before using useBuilder. Example: useContainerProvider(new TsyringeProvider({ container, Lifecycle }))");
|
|
65
|
+
return currentProvider;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Checks if a provider is currently configured
|
|
69
|
+
*
|
|
70
|
+
* @returns `true` if a provider is configured, `false` otherwise
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* if (!hasContainerProvider()) {
|
|
75
|
+
* useContainerProvider(new TsyringeProvider({ container, Lifecycle }))
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
function hasContainerProvider() {
|
|
80
|
+
return currentProvider !== null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resets the global provider (primarily for testing)
|
|
84
|
+
*
|
|
85
|
+
* ⚠️ WARNING: Do not use in production, only for testing purposes
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* // In a test file
|
|
90
|
+
* beforeEach(() => {
|
|
91
|
+
* resetContainerProvider()
|
|
92
|
+
* useContainerProvider(new TsyringeProvider({ container, Lifecycle }))
|
|
93
|
+
* })
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
function resetContainerProvider() {
|
|
97
|
+
if (currentProvider !== null) try {
|
|
98
|
+
currentProvider.dispose();
|
|
99
|
+
} catch {}
|
|
100
|
+
currentProvider = null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/Provider/adapters/TsyringeProvider.ts
|
|
105
|
+
/**
|
|
106
|
+
* tsyringe adapter implementing the ContainerProvider interface
|
|
107
|
+
*
|
|
108
|
+
* Provides integration between WireDI and tsyringe,
|
|
109
|
+
* allowing you to use tsyringe as your DI container while benefiting
|
|
110
|
+
* from WireDI's configuration and validation features.
|
|
111
|
+
*/
|
|
112
|
+
var TsyringeProvider = class TsyringeProvider {
|
|
113
|
+
/** @inheritdoc */
|
|
114
|
+
name = "tsyringe";
|
|
115
|
+
/** The tsyringe container instance */
|
|
116
|
+
container;
|
|
117
|
+
/** The tsyringe Lifecycle enum reference */
|
|
118
|
+
Lifecycle;
|
|
119
|
+
/**
|
|
120
|
+
* Creates a new TsyringeProvider instance
|
|
121
|
+
*
|
|
122
|
+
* @param dependencies - tsyringe dependencies (container and Lifecycle)
|
|
123
|
+
* @param options - Configuration options
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* import { container, Lifecycle } from 'tsyringe'
|
|
128
|
+
*
|
|
129
|
+
* const provider = new TsyringeProvider(
|
|
130
|
+
* { container, Lifecycle },
|
|
131
|
+
* { useChildContainer: true }
|
|
132
|
+
* )
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
constructor(dependencies, options = {}) {
|
|
136
|
+
this.Lifecycle = dependencies.Lifecycle;
|
|
137
|
+
this.container = options.useChildContainer ? dependencies.container.createChildContainer() : dependencies.container;
|
|
138
|
+
}
|
|
139
|
+
/** @inheritdoc */
|
|
140
|
+
registerValue(token, value) {
|
|
141
|
+
this.container.register(token, { useValue: value });
|
|
142
|
+
}
|
|
143
|
+
/** @inheritdoc */
|
|
144
|
+
registerFactory(token, factory) {
|
|
145
|
+
this.container.register(token, { useFactory: () => factory(this) });
|
|
146
|
+
}
|
|
147
|
+
/** @inheritdoc */
|
|
148
|
+
registerClass(token, implementation, lifecycle = ProviderLifecycle.Singleton) {
|
|
149
|
+
const tsyringeLifecycle = this.mapLifecycle(lifecycle);
|
|
150
|
+
if (this.isConstructor(token)) this.container.register(token, { useClass: implementation ?? token }, { lifecycle: tsyringeLifecycle });
|
|
151
|
+
else {
|
|
152
|
+
if (!implementation) throw new Error(`[TsyringeProvider] Implementation required when registering symbol token: ${String(token)}`);
|
|
153
|
+
this.container.register(token, { useClass: implementation }, { lifecycle: tsyringeLifecycle });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** @inheritdoc */
|
|
157
|
+
isRegistered(token) {
|
|
158
|
+
return this.container.isRegistered(token);
|
|
159
|
+
}
|
|
160
|
+
/** @inheritdoc */
|
|
161
|
+
resolve(token) {
|
|
162
|
+
return this.container.resolve(token);
|
|
163
|
+
}
|
|
164
|
+
/** @inheritdoc */
|
|
165
|
+
createScope() {
|
|
166
|
+
return new TsyringeProvider({
|
|
167
|
+
container: this.container.createChildContainer(),
|
|
168
|
+
Lifecycle: this.Lifecycle
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/** @inheritdoc */
|
|
172
|
+
dispose() {
|
|
173
|
+
try {
|
|
174
|
+
this.container.clearInstances();
|
|
175
|
+
} catch {}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Returns the underlying tsyringe DependencyContainer
|
|
179
|
+
* @returns The tsyringe container instance
|
|
180
|
+
*/
|
|
181
|
+
getUnderlyingContainer() {
|
|
182
|
+
return this.container;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Maps WireDI lifecycle to tsyringe Lifecycle
|
|
186
|
+
* @internal
|
|
187
|
+
*/
|
|
188
|
+
mapLifecycle(lifecycle) {
|
|
189
|
+
switch (lifecycle) {
|
|
190
|
+
case ProviderLifecycle.Singleton: return this.Lifecycle.Singleton;
|
|
191
|
+
case ProviderLifecycle.Transient: return this.Lifecycle.Transient;
|
|
192
|
+
case ProviderLifecycle.Scoped: return this.Lifecycle.ContainerScoped;
|
|
193
|
+
default: return this.Lifecycle.Singleton;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Type guard to check if a token is a class constructor
|
|
198
|
+
* @internal
|
|
199
|
+
*/
|
|
200
|
+
isConstructor(token) {
|
|
201
|
+
return typeof token === "function" && !!token.prototype && token.prototype.constructor === token;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region src/Provider/adapters/AwilixProvider.ts
|
|
207
|
+
/**
|
|
208
|
+
* Awilix adapter implementing the ContainerProvider interface
|
|
209
|
+
*
|
|
210
|
+
* Provides integration between WireDI and Awilix,
|
|
211
|
+
* allowing you to use Awilix as your DI container while benefiting
|
|
212
|
+
* from WireDI's configuration and validation features.
|
|
213
|
+
*/
|
|
214
|
+
var AwilixProvider = class AwilixProvider {
|
|
215
|
+
/** @inheritdoc */
|
|
216
|
+
name = "awilix";
|
|
217
|
+
/** The Awilix container instance */
|
|
218
|
+
container;
|
|
219
|
+
/** Maps tokens to Awilix string-based registration names */
|
|
220
|
+
tokenToName = /* @__PURE__ */ new Map();
|
|
221
|
+
/** Counter for generating unique token names */
|
|
222
|
+
nameCounter = 0;
|
|
223
|
+
/** Lazily loaded awilix module */
|
|
224
|
+
awilix = null;
|
|
225
|
+
/**
|
|
226
|
+
* Creates a new AwilixProvider instance
|
|
227
|
+
*
|
|
228
|
+
* @param options - Configuration options
|
|
229
|
+
*
|
|
230
|
+
* @remarks
|
|
231
|
+
* When using the constructor directly, you must call `init()` before use,
|
|
232
|
+
* or use `createSync()` for synchronous initialization.
|
|
233
|
+
*/
|
|
234
|
+
constructor(options = {}) {
|
|
235
|
+
this.options = options;
|
|
236
|
+
this.container = null;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Lazily initializes the container (async)
|
|
240
|
+
* @internal
|
|
241
|
+
*/
|
|
242
|
+
async ensureInitialized() {
|
|
243
|
+
if (this.container) return;
|
|
244
|
+
this.awilix = await import("awilix");
|
|
245
|
+
this.container = this.options.container ?? this.awilix.createContainer({ injectionMode: this.options.injectionMode === "CLASSIC" ? this.awilix.InjectionMode.CLASSIC : this.awilix.InjectionMode.PROXY });
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Throws if container is not initialized
|
|
249
|
+
* @internal
|
|
250
|
+
*/
|
|
251
|
+
ensureInitializedSync() {
|
|
252
|
+
if (!this.container) throw new Error("[AwilixProvider] Container not initialized. Call await provider.init() first, or pass a pre-created container in options.");
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Initializes the provider asynchronously
|
|
256
|
+
*
|
|
257
|
+
* @remarks
|
|
258
|
+
* Required before using the provider if not using `createSync()`.
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```typescript
|
|
262
|
+
* const provider = new AwilixProvider({ injectionMode: 'PROXY' })
|
|
263
|
+
* await provider.init()
|
|
264
|
+
* useContainerProvider(provider)
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
async init() {
|
|
268
|
+
await this.ensureInitialized();
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Creates a pre-initialized provider synchronously
|
|
272
|
+
*
|
|
273
|
+
* @param awilix - The awilix module import
|
|
274
|
+
* @param options - Configuration options
|
|
275
|
+
* @returns Fully initialized AwilixProvider instance
|
|
276
|
+
*
|
|
277
|
+
* @remarks
|
|
278
|
+
* This is the recommended way to create an AwilixProvider as it
|
|
279
|
+
* avoids async initialization and ensures the provider is ready immediately.
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```typescript
|
|
283
|
+
* import * as awilix from 'awilix'
|
|
284
|
+
*
|
|
285
|
+
* const provider = AwilixProvider.createSync(awilix, {
|
|
286
|
+
* injectionMode: 'CLASSIC'
|
|
287
|
+
* })
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
static createSync(awilix$1, options = {}) {
|
|
291
|
+
const provider = new AwilixProvider(options);
|
|
292
|
+
provider.awilix = awilix$1;
|
|
293
|
+
provider.container = options.container ?? awilix$1.createContainer({ injectionMode: options.injectionMode === "CLASSIC" ? awilix$1.InjectionMode.CLASSIC : awilix$1.InjectionMode.PROXY });
|
|
294
|
+
return provider;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Gets or creates a unique string name for a token
|
|
298
|
+
* Awilix uses string-based registration, so we map symbols/classes to strings
|
|
299
|
+
* @internal
|
|
300
|
+
*/
|
|
301
|
+
getTokenName(token) {
|
|
302
|
+
if (!this.tokenToName.has(token)) {
|
|
303
|
+
const name = typeof token === "symbol" ? token.description ?? `token_${this.nameCounter++}` : token.name;
|
|
304
|
+
this.tokenToName.set(token, name);
|
|
305
|
+
}
|
|
306
|
+
return this.tokenToName.get(token);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Maps WireDI lifecycle to Awilix Lifetime
|
|
310
|
+
* @internal
|
|
311
|
+
*/
|
|
312
|
+
mapLifecycle(lifecycle) {
|
|
313
|
+
this.ensureInitializedSync();
|
|
314
|
+
switch (lifecycle) {
|
|
315
|
+
case ProviderLifecycle.Transient: return awilix.Lifetime.TRANSIENT;
|
|
316
|
+
case ProviderLifecycle.Scoped: return awilix.Lifetime.SCOPED;
|
|
317
|
+
case ProviderLifecycle.Singleton:
|
|
318
|
+
default: return awilix.Lifetime.SINGLETON;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/** @inheritdoc */
|
|
322
|
+
registerValue(token, value) {
|
|
323
|
+
this.ensureInitializedSync();
|
|
324
|
+
const { asValue } = this.awilix;
|
|
325
|
+
const name = this.getTokenName(token);
|
|
326
|
+
this.container.register({ [name]: asValue(value) });
|
|
327
|
+
}
|
|
328
|
+
/** @inheritdoc */
|
|
329
|
+
registerFactory(token, factory) {
|
|
330
|
+
this.ensureInitializedSync();
|
|
331
|
+
const { asFunction } = this.awilix;
|
|
332
|
+
const name = this.getTokenName(token);
|
|
333
|
+
this.container.register({ [name]: asFunction(() => factory(this)).singleton() });
|
|
334
|
+
}
|
|
335
|
+
/** @inheritdoc */
|
|
336
|
+
registerClass(token, impl, lifecycle) {
|
|
337
|
+
this.ensureInitializedSync();
|
|
338
|
+
const { asClass } = this.awilix;
|
|
339
|
+
const name = this.getTokenName(token);
|
|
340
|
+
const ClassToRegister = impl ?? token;
|
|
341
|
+
const lifetime = this.mapLifecycle(lifecycle);
|
|
342
|
+
this.container.register({ [name]: asClass(ClassToRegister).setLifetime(lifetime) });
|
|
343
|
+
}
|
|
344
|
+
/** @inheritdoc */
|
|
345
|
+
isRegistered(token) {
|
|
346
|
+
this.ensureInitializedSync();
|
|
347
|
+
const name = this.getTokenName(token);
|
|
348
|
+
return this.container.hasRegistration(name);
|
|
349
|
+
}
|
|
350
|
+
/** @inheritdoc */
|
|
351
|
+
resolve(token) {
|
|
352
|
+
this.ensureInitializedSync();
|
|
353
|
+
const name = this.getTokenName(token);
|
|
354
|
+
return this.container.resolve(name);
|
|
355
|
+
}
|
|
356
|
+
/** @inheritdoc */
|
|
357
|
+
createScope() {
|
|
358
|
+
this.ensureInitializedSync();
|
|
359
|
+
const scopedContainer = this.container.createScope();
|
|
360
|
+
const scopedProvider = AwilixProvider.createSync(this.awilix, { container: scopedContainer });
|
|
361
|
+
this.tokenToName.forEach((name, token) => {
|
|
362
|
+
scopedProvider.tokenToName.set(token, name);
|
|
363
|
+
});
|
|
364
|
+
return scopedProvider;
|
|
365
|
+
}
|
|
366
|
+
/** @inheritdoc */
|
|
367
|
+
dispose() {
|
|
368
|
+
if (this.container) this.container.dispose();
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Returns the underlying Awilix container instance
|
|
372
|
+
* @returns The AwilixContainer instance
|
|
373
|
+
*/
|
|
374
|
+
getUnderlyingContainer() {
|
|
375
|
+
this.ensureInitializedSync();
|
|
376
|
+
return this.container;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
//#endregion
|
|
381
|
+
//#region src/Provider/adapters/InversifyProvider.ts
|
|
382
|
+
/**
|
|
383
|
+
* InversifyJS adapter implementing the ContainerProvider interface
|
|
384
|
+
*
|
|
385
|
+
* Provides integration between WireDI and InversifyJS,
|
|
386
|
+
* allowing you to use InversifyJS as your DI container while benefiting
|
|
387
|
+
* from WireDI's configuration and validation features.
|
|
388
|
+
*/
|
|
389
|
+
var InversifyProvider = class InversifyProvider {
|
|
390
|
+
/** @inheritdoc */
|
|
391
|
+
name = "inversify";
|
|
392
|
+
/** The InversifyJS container instance */
|
|
393
|
+
container;
|
|
394
|
+
/** Default scope for bindings */
|
|
395
|
+
defaultScope;
|
|
396
|
+
/** Lazily loaded inversify module */
|
|
397
|
+
inversify = null;
|
|
398
|
+
/**
|
|
399
|
+
* Creates a new InversifyProvider instance
|
|
400
|
+
*
|
|
401
|
+
* @param options - Configuration options
|
|
402
|
+
*
|
|
403
|
+
* @remarks
|
|
404
|
+
* When using the constructor directly, you must call `init()` before use,
|
|
405
|
+
* or use `createSync()` for synchronous initialization.
|
|
406
|
+
*/
|
|
407
|
+
constructor(options = {}) {
|
|
408
|
+
this.options = options;
|
|
409
|
+
this.defaultScope = options.defaultScope ?? "Singleton";
|
|
410
|
+
this.container = null;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Lazily initializes the container (async)
|
|
414
|
+
* @internal
|
|
415
|
+
*/
|
|
416
|
+
async ensureInitialized() {
|
|
417
|
+
if (this.container) return;
|
|
418
|
+
this.inversify = await import("inversify");
|
|
419
|
+
this.container = this.options.container ?? new this.inversify.Container();
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Throws if container is not initialized
|
|
423
|
+
* @internal
|
|
424
|
+
*/
|
|
425
|
+
ensureInitializedSync() {
|
|
426
|
+
if (!this.container) throw new Error("[InversifyProvider] Container not initialized. Call await provider.init() first, or pass a pre-created container in options.");
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Initializes the provider asynchronously
|
|
430
|
+
*
|
|
431
|
+
* @remarks
|
|
432
|
+
* Required before using the provider if not using `createSync()`.
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* ```typescript
|
|
436
|
+
* const provider = new InversifyProvider()
|
|
437
|
+
* await provider.init()
|
|
438
|
+
* useContainerProvider(provider)
|
|
439
|
+
* ```
|
|
440
|
+
*/
|
|
441
|
+
async init() {
|
|
442
|
+
await this.ensureInitialized();
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Creates a pre-initialized provider synchronously
|
|
446
|
+
*
|
|
447
|
+
* @param inversify - The inversify module import
|
|
448
|
+
* @param options - Configuration options
|
|
449
|
+
* @returns Fully initialized InversifyProvider instance
|
|
450
|
+
*
|
|
451
|
+
* @remarks
|
|
452
|
+
* This is the recommended way to create an InversifyProvider as it
|
|
453
|
+
* avoids async initialization and ensures the provider is ready immediately.
|
|
454
|
+
*
|
|
455
|
+
* @example
|
|
456
|
+
* ```typescript
|
|
457
|
+
* import * as inversify from 'inversify'
|
|
458
|
+
*
|
|
459
|
+
* const provider = InversifyProvider.createSync(inversify, {
|
|
460
|
+
* defaultScope: 'Transient'
|
|
461
|
+
* })
|
|
462
|
+
* ```
|
|
463
|
+
*/
|
|
464
|
+
static createSync(inversify, options = {}) {
|
|
465
|
+
const provider = new InversifyProvider(options);
|
|
466
|
+
provider.inversify = inversify;
|
|
467
|
+
provider.container = options.container ?? new inversify.Container();
|
|
468
|
+
return provider;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Maps WireDI lifecycle to InversifyJS binding scope
|
|
472
|
+
* @internal
|
|
473
|
+
*/
|
|
474
|
+
mapLifecycle(lifecycle) {
|
|
475
|
+
switch (lifecycle) {
|
|
476
|
+
case ProviderLifecycle.Transient: return "Transient";
|
|
477
|
+
case ProviderLifecycle.Scoped: return "Request";
|
|
478
|
+
case ProviderLifecycle.Singleton:
|
|
479
|
+
default: return "Singleton";
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Applies the scope to an InversifyJS binding
|
|
484
|
+
* @internal
|
|
485
|
+
*/
|
|
486
|
+
applyScope(binding, scope) {
|
|
487
|
+
switch (scope) {
|
|
488
|
+
case "Singleton":
|
|
489
|
+
binding.inSingletonScope();
|
|
490
|
+
break;
|
|
491
|
+
case "Transient":
|
|
492
|
+
binding.inTransientScope();
|
|
493
|
+
break;
|
|
494
|
+
case "Request":
|
|
495
|
+
binding.inRequestScope();
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/** @inheritdoc */
|
|
500
|
+
registerValue(token, value) {
|
|
501
|
+
this.ensureInitializedSync();
|
|
502
|
+
if (this.container.isBound(token)) this.container.unbind(token);
|
|
503
|
+
this.container.bind(token).toConstantValue(value);
|
|
504
|
+
}
|
|
505
|
+
/** @inheritdoc */
|
|
506
|
+
registerFactory(token, factory) {
|
|
507
|
+
this.ensureInitializedSync();
|
|
508
|
+
if (this.container.isBound(token)) this.container.unbind(token);
|
|
509
|
+
this.container.bind(token).toDynamicValue(() => factory(this));
|
|
510
|
+
}
|
|
511
|
+
/** @inheritdoc */
|
|
512
|
+
registerClass(token, impl, lifecycle) {
|
|
513
|
+
this.ensureInitializedSync();
|
|
514
|
+
const ClassToRegister = impl ?? token;
|
|
515
|
+
const scope = this.mapLifecycle(lifecycle);
|
|
516
|
+
if (this.container.isBound(token)) this.container.unbind(token);
|
|
517
|
+
const binding = this.container.bind(token).to(ClassToRegister);
|
|
518
|
+
this.applyScope(binding, scope);
|
|
519
|
+
}
|
|
520
|
+
/** @inheritdoc */
|
|
521
|
+
isRegistered(token) {
|
|
522
|
+
this.ensureInitializedSync();
|
|
523
|
+
return this.container.isBound(token);
|
|
524
|
+
}
|
|
525
|
+
/** @inheritdoc */
|
|
526
|
+
resolve(token) {
|
|
527
|
+
this.ensureInitializedSync();
|
|
528
|
+
return this.container.get(token);
|
|
529
|
+
}
|
|
530
|
+
/** @inheritdoc */
|
|
531
|
+
createScope() {
|
|
532
|
+
this.ensureInitializedSync();
|
|
533
|
+
const childContainer = new this.inversify.Container();
|
|
534
|
+
return InversifyProvider.createSync(this.inversify, {
|
|
535
|
+
container: childContainer,
|
|
536
|
+
defaultScope: this.defaultScope
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
/** @inheritdoc */
|
|
540
|
+
dispose() {
|
|
541
|
+
if (this.container) this.container.unbindAll();
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Returns the underlying InversifyJS Container instance
|
|
545
|
+
* @returns The InversifyJS Container
|
|
546
|
+
*/
|
|
547
|
+
getUnderlyingContainer() {
|
|
548
|
+
this.ensureInitializedSync();
|
|
549
|
+
return this.container;
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
//#endregion
|
|
554
|
+
//#region src/EventDispatcher/Provider/MutableEventDispatcherProvider.ts
|
|
555
|
+
/**
|
|
556
|
+
* Default EventDispatcherProvider implementation
|
|
557
|
+
*
|
|
558
|
+
* This provider stores listeners in memory and resolves them through the DI container
|
|
559
|
+
* when dispatching events. Each listener must implement an `onEvent(event)` method.
|
|
560
|
+
*
|
|
561
|
+
* @example Basic usage
|
|
562
|
+
* ```typescript
|
|
563
|
+
* import {
|
|
564
|
+
* MutableEventDispatcherProvider,
|
|
565
|
+
* useEventDispatcherProvider,
|
|
566
|
+
* getContainerProvider
|
|
567
|
+
* } from '@djodjonx/wiredi'
|
|
568
|
+
*
|
|
569
|
+
* const eventProvider = new MutableEventDispatcherProvider({
|
|
570
|
+
* containerProvider: getContainerProvider()
|
|
571
|
+
* })
|
|
572
|
+
* useEventDispatcherProvider(eventProvider)
|
|
573
|
+
* ```
|
|
574
|
+
*
|
|
575
|
+
* @example Dispatching events
|
|
576
|
+
* ```typescript
|
|
577
|
+
* const dispatcher = getEventDispatcherProvider()
|
|
578
|
+
* dispatcher.dispatch(new UserCreatedEvent(user))
|
|
579
|
+
* ```
|
|
580
|
+
*/
|
|
581
|
+
var MutableEventDispatcherProvider = class {
|
|
582
|
+
/** @inheritdoc */
|
|
583
|
+
name = "mutable-event-dispatcher";
|
|
584
|
+
/** Map of event names to their registered listener tokens */
|
|
585
|
+
listeners = /* @__PURE__ */ new Map();
|
|
586
|
+
/** DI container provider for resolving listener instances */
|
|
587
|
+
containerProvider;
|
|
588
|
+
/**
|
|
589
|
+
* Creates a new MutableEventDispatcherProvider instance
|
|
590
|
+
*
|
|
591
|
+
* @param options - Configuration options including the container provider
|
|
592
|
+
*/
|
|
593
|
+
constructor(options) {
|
|
594
|
+
this.containerProvider = options.containerProvider;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Extracts the event name from an event token (class constructor)
|
|
598
|
+
* @internal
|
|
599
|
+
*/
|
|
600
|
+
getEventName(eventToken) {
|
|
601
|
+
return eventToken.name;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Extracts the event name from an event instance
|
|
605
|
+
* @internal
|
|
606
|
+
*/
|
|
607
|
+
getEventNameFromInstance(event) {
|
|
608
|
+
return event.constructor.name;
|
|
609
|
+
}
|
|
610
|
+
/** @inheritdoc */
|
|
611
|
+
register(eventToken, listenerToken) {
|
|
612
|
+
const eventName = this.getEventName(eventToken);
|
|
613
|
+
if (!this.listeners.has(eventName)) this.listeners.set(eventName, []);
|
|
614
|
+
this.listeners.get(eventName).push(listenerToken);
|
|
615
|
+
}
|
|
616
|
+
/** @inheritdoc */
|
|
617
|
+
dispatch(event) {
|
|
618
|
+
const eventName = this.getEventNameFromInstance(event);
|
|
619
|
+
const listenerTokens = this.listeners.get(eventName) ?? [];
|
|
620
|
+
for (const listenerToken of listenerTokens) try {
|
|
621
|
+
this.containerProvider.resolve(listenerToken).onEvent(event);
|
|
622
|
+
} catch (error) {
|
|
623
|
+
console.error(`[MutableEventDispatcherProvider] Error dispatching event "${eventName}":`, error.stack || error.message);
|
|
624
|
+
throw error;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
/** @inheritdoc */
|
|
628
|
+
hasListeners(eventToken) {
|
|
629
|
+
const eventName = this.getEventName(eventToken);
|
|
630
|
+
const listeners = this.listeners.get(eventName);
|
|
631
|
+
return listeners !== void 0 && listeners.length > 0;
|
|
632
|
+
}
|
|
633
|
+
/** @inheritdoc */
|
|
634
|
+
clearListeners(eventToken) {
|
|
635
|
+
const eventName = this.getEventName(eventToken);
|
|
636
|
+
this.listeners.delete(eventName);
|
|
637
|
+
}
|
|
638
|
+
/** @inheritdoc */
|
|
639
|
+
clearAllListeners() {
|
|
640
|
+
this.listeners.clear();
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Returns the internal listeners map
|
|
644
|
+
* @returns Map of event names to listener tokens
|
|
645
|
+
*/
|
|
646
|
+
getUnderlyingDispatcher() {
|
|
647
|
+
return this.listeners;
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
//#endregion
|
|
652
|
+
//#region src/EventDispatcher/Provider/index.ts
|
|
653
|
+
/**
|
|
654
|
+
* Currently configured global event dispatcher provider
|
|
655
|
+
* @internal
|
|
656
|
+
*/
|
|
657
|
+
let globalEventDispatcherProvider = null;
|
|
658
|
+
/**
|
|
659
|
+
* Sets the global EventDispatcherProvider instance
|
|
660
|
+
*
|
|
661
|
+
* Call this once at application startup after setting up the container provider.
|
|
662
|
+
* The event dispatcher uses the container provider to resolve listener instances.
|
|
663
|
+
*
|
|
664
|
+
* @param provider - The EventDispatcherProvider implementation to use
|
|
665
|
+
* @throws Error if a provider is already registered
|
|
666
|
+
*
|
|
667
|
+
* @example
|
|
668
|
+
* ```typescript
|
|
669
|
+
* import {
|
|
670
|
+
* useContainerProvider,
|
|
671
|
+
* TsyringeProvider,
|
|
672
|
+
* useEventDispatcherProvider,
|
|
673
|
+
* MutableEventDispatcherProvider,
|
|
674
|
+
* getContainerProvider
|
|
675
|
+
* } from '@djodjonx/wiredi'
|
|
676
|
+
*
|
|
677
|
+
* // 1. Setup DI container first
|
|
678
|
+
* useContainerProvider(new TsyringeProvider({ container, Lifecycle }))
|
|
679
|
+
*
|
|
680
|
+
* // 2. Setup event dispatcher (optional)
|
|
681
|
+
* useEventDispatcherProvider(new MutableEventDispatcherProvider({
|
|
682
|
+
* containerProvider: getContainerProvider()
|
|
683
|
+
* }))
|
|
684
|
+
* ```
|
|
685
|
+
*/
|
|
686
|
+
function useEventDispatcherProvider(provider) {
|
|
687
|
+
if (globalEventDispatcherProvider !== null) throw new Error(`[EventDispatcher] Provider already registered: "${globalEventDispatcherProvider.name}". Cannot register "${provider.name}". Call resetEventDispatcherProvider() first if you need to change it.`);
|
|
688
|
+
globalEventDispatcherProvider = provider;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Retrieves the currently registered EventDispatcherProvider
|
|
692
|
+
*
|
|
693
|
+
* @returns The registered EventDispatcherProvider instance
|
|
694
|
+
* @throws Error if no provider has been registered
|
|
695
|
+
*
|
|
696
|
+
* @example
|
|
697
|
+
* ```typescript
|
|
698
|
+
* const eventDispatcher = getEventDispatcherProvider()
|
|
699
|
+
* eventDispatcher.dispatch(new UserCreatedEvent(user))
|
|
700
|
+
* ```
|
|
701
|
+
*/
|
|
702
|
+
function getEventDispatcherProvider() {
|
|
703
|
+
if (globalEventDispatcherProvider === null) throw new Error("[EventDispatcher] No provider registered. Call useEventDispatcherProvider() at application startup.");
|
|
704
|
+
return globalEventDispatcherProvider;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Checks if an EventDispatcherProvider has been registered
|
|
708
|
+
*
|
|
709
|
+
* @returns `true` if a provider is registered, `false` otherwise
|
|
710
|
+
*
|
|
711
|
+
* @example
|
|
712
|
+
* ```typescript
|
|
713
|
+
* if (hasEventDispatcherProvider()) {
|
|
714
|
+
* getEventDispatcherProvider().dispatch(event)
|
|
715
|
+
* }
|
|
716
|
+
* ```
|
|
717
|
+
*/
|
|
718
|
+
function hasEventDispatcherProvider() {
|
|
719
|
+
return globalEventDispatcherProvider !== null;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Resets the global EventDispatcherProvider
|
|
723
|
+
*
|
|
724
|
+
* Clears all registered listeners and removes the provider.
|
|
725
|
+
* Useful for testing or reconfiguration scenarios.
|
|
726
|
+
*
|
|
727
|
+
* ⚠️ WARNING: This should rarely be used in production code.
|
|
728
|
+
*
|
|
729
|
+
* @example
|
|
730
|
+
* ```typescript
|
|
731
|
+
* // In a test file
|
|
732
|
+
* afterEach(() => {
|
|
733
|
+
* resetEventDispatcherProvider()
|
|
734
|
+
* })
|
|
735
|
+
* ```
|
|
736
|
+
*/
|
|
737
|
+
function resetEventDispatcherProvider() {
|
|
738
|
+
if (globalEventDispatcherProvider !== null) globalEventDispatcherProvider.clearAllListeners();
|
|
739
|
+
globalEventDispatcherProvider = null;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
//#endregion
|
|
743
|
+
//#region src/index.ts
|
|
744
|
+
/**
|
|
745
|
+
* Type guard to check if a token is a constructor (class).
|
|
746
|
+
* @param token The token to check.
|
|
747
|
+
* @returns True if the token is a constructor, false otherwise.
|
|
748
|
+
*/
|
|
749
|
+
function isConstructor(token) {
|
|
750
|
+
return typeof token === "function" && !!token.prototype && token.prototype.constructor === token;
|
|
751
|
+
}
|
|
752
|
+
function registerConfig(provider, injections, context) {
|
|
753
|
+
injections.forEach((entry) => {
|
|
754
|
+
if (provider.isRegistered(entry.token)) return;
|
|
755
|
+
if ("value" in entry) provider.registerValue(entry.token, entry.value(context));
|
|
756
|
+
else if ("factory" in entry) provider.registerFactory(entry.token, () => entry.factory(provider));
|
|
757
|
+
else if (isConstructor(entry.token)) {
|
|
758
|
+
const lifecycle = entry.lifecycle ?? ProviderLifecycle.Singleton;
|
|
759
|
+
provider.registerClass(entry.token, entry.token, lifecycle);
|
|
760
|
+
} else {
|
|
761
|
+
if (!("provider" in entry)) throw new Error(`Provider required when registering token Symbol: ${String(entry.token)}`);
|
|
762
|
+
const lifecycle = entry.lifecycle ?? ProviderLifecycle.Singleton;
|
|
763
|
+
provider.registerClass(entry.token, entry.provider, lifecycle);
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
function registerEvent(_provider, listeners) {
|
|
768
|
+
if (!listeners.length) return;
|
|
769
|
+
if (!hasEventDispatcherProvider()) return;
|
|
770
|
+
const eventDispatcher = getEventDispatcherProvider();
|
|
771
|
+
listeners.forEach((configEntry) => {
|
|
772
|
+
eventDispatcher.register(configEntry.event, configEntry.listener);
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Helper to define a partial configuration (injections/listeners).
|
|
777
|
+
*
|
|
778
|
+
* Partials are designed to be flat collections of dependencies. They do not support
|
|
779
|
+
* inheritance (`extends`) or overriding to prevent complex dependency graphs.
|
|
780
|
+
* All conflict resolution must happen in the main `defineBuilderConfig`.
|
|
781
|
+
*
|
|
782
|
+
* @template C The type of the context object (optional).
|
|
783
|
+
* @template I The specific type of the injections array (inferred).
|
|
784
|
+
* @param config The partial builder configuration object.
|
|
785
|
+
* @returns The configuration object typed as TypedPartialConfig.
|
|
786
|
+
*/
|
|
787
|
+
function definePartialConfig(config) {
|
|
788
|
+
return config;
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* A helper function to define a builder configuration with strict type inference and inheritance.
|
|
792
|
+
* Use this instead of manually casting with `satisfies BuilderConfig` or `as const`
|
|
793
|
+
* to ensure that `useBuilder` can correctly infer the available tokens.
|
|
794
|
+
*
|
|
795
|
+
* This function now supports `extends` to inherit from `definePartialConfig` definitions.
|
|
796
|
+
* Token collisions are strictly forbidden - each token must be unique across all partials
|
|
797
|
+
* and the main configuration to prevent accidental redefinition.
|
|
798
|
+
*
|
|
799
|
+
* @template C The type of the context object (optional).
|
|
800
|
+
* @template Partials The tuple of partial configs to extend.
|
|
801
|
+
* @template LocalInjections The specific type of the local injections array (inferred).
|
|
802
|
+
* @param config The builder configuration object.
|
|
803
|
+
* @returns The configuration object typed as TypedBuilderConfig to simplify IDE display.
|
|
804
|
+
*
|
|
805
|
+
* @example
|
|
806
|
+
* ```typescript
|
|
807
|
+
* import { Lifecycle } from 'tsyringe';
|
|
808
|
+
*
|
|
809
|
+
* class MyService {}
|
|
810
|
+
* class MyProvider {}
|
|
811
|
+
* class MyEvent {}
|
|
812
|
+
* class MyEventListener {
|
|
813
|
+
* onEvent(event: MyEvent) {
|
|
814
|
+
* console.log('Event received:', event);
|
|
815
|
+
* }
|
|
816
|
+
* }
|
|
817
|
+
*
|
|
818
|
+
* const MY_TOKEN = Symbol('MY_TOKEN');
|
|
819
|
+
* const MY_VALUE_TOKEN = Symbol('MY_VALUE_TOKEN');
|
|
820
|
+
* const MY_FACTORY_TOKEN = Symbol('MY_FACTORY_TOKEN');
|
|
821
|
+
*
|
|
822
|
+
* // --- Partial Configuration ---
|
|
823
|
+
* const myPartial = definePartialConfig({
|
|
824
|
+
* injections: [
|
|
825
|
+
* { token: MyService } // Provides MyService
|
|
826
|
+
* ],
|
|
827
|
+
* listeners: [
|
|
828
|
+
* { event: MyEvent, listener: MyEventListener }
|
|
829
|
+
* ]
|
|
830
|
+
* });
|
|
831
|
+
*
|
|
832
|
+
* // --- Main Builder Configuration ---
|
|
833
|
+
* const myBuilderConfig = defineBuilderConfig({
|
|
834
|
+
* builderId: 'my.unique.builder',
|
|
835
|
+
* extends: [myPartial],
|
|
836
|
+
* injections: [
|
|
837
|
+
* // ❌ ERROR: Token collision - MyService is already defined in myPartial
|
|
838
|
+
* // { token: MyService },
|
|
839
|
+
*
|
|
840
|
+
* // ✅ OK: New tokens not in partials
|
|
841
|
+
* { token: MY_TOKEN, provider: MyProvider },
|
|
842
|
+
* { token: MY_TOKEN, provider: MyProvider, lifecycle: Lifecycle.Transient },
|
|
843
|
+
*
|
|
844
|
+
* // 3. Value Injection (can use optional context)
|
|
845
|
+
* { token: MY_VALUE_TOKEN, value: (context) => context?.someConfig ?? 'defaultValue' },
|
|
846
|
+
*
|
|
847
|
+
* // 4. Factory Injection
|
|
848
|
+
* { token: MY_FACTORY_TOKEN, factory: (container) => new MyService() },
|
|
849
|
+
* ],
|
|
850
|
+
* listeners: [
|
|
851
|
+
* // ❌ ERROR: Duplicate listener (Event + Listener pair already in myPartial)
|
|
852
|
+
* // { event: MyEvent, listener: MyEventListener },
|
|
853
|
+
*
|
|
854
|
+
* // ✅ OK: New listener not in partials
|
|
855
|
+
* { event: OtherEvent, listener: OtherEventListener },
|
|
856
|
+
* ],
|
|
857
|
+
* });
|
|
858
|
+
*
|
|
859
|
+
* // Usage:
|
|
860
|
+
* // const { resolve } = useBuilder(myBuilderConfig, { someConfig: 'custom' });
|
|
861
|
+
* // const service = resolve(MyService);
|
|
862
|
+
* // const value = resolve(MY_VALUE_TOKEN);
|
|
863
|
+
* ```
|
|
864
|
+
*/
|
|
865
|
+
function defineBuilderConfig(config) {
|
|
866
|
+
const mergedInjections = [...config.injections, ...(config.extends || []).flatMap((p) => p.injections || [])];
|
|
867
|
+
const mergedListeners = [...(config.extends || []).flatMap((p) => p.listeners || []), ...config.listeners];
|
|
868
|
+
return {
|
|
869
|
+
...config,
|
|
870
|
+
injections: mergedInjections,
|
|
871
|
+
listeners: mergedListeners
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* A composable function for setting up and interacting with a dependency injection container
|
|
876
|
+
* based on a `BuilderConfig`. It ensures that dependencies are registered only once per builderId
|
|
877
|
+
* and provides a type-safe `resolve` method.
|
|
878
|
+
*
|
|
879
|
+
* The `resolve` method is strictly type-checked to only allow tokens defined within the `injections`
|
|
880
|
+
* array of the provided `config`.
|
|
881
|
+
*
|
|
882
|
+
* ⚠️ Requires `useContainerProvider()` to be called first at app entry point.
|
|
883
|
+
*
|
|
884
|
+
* @template C The type of the context object that might be passed to value providers.
|
|
885
|
+
* @template Tokens The inferred tuple of allowed tokens from the config.
|
|
886
|
+
* @param config The typed builder configuration object.
|
|
887
|
+
* @param context An optional context object that can be passed to value providers in the injections.
|
|
888
|
+
* @returns An `IUseBuilder` instance with a type-safe `resolve` method.
|
|
889
|
+
*
|
|
890
|
+
* @example
|
|
891
|
+
* ```typescript
|
|
892
|
+
* // main.ts - Entry point
|
|
893
|
+
* import { useContainerProvider, TsyringeProvider } from '@djodjonx/wiredi'
|
|
894
|
+
* useContainerProvider(new TsyringeProvider())
|
|
895
|
+
*
|
|
896
|
+
* // anywhere.ts
|
|
897
|
+
* import { useBuilder } from '@djodjonx/wiredi'
|
|
898
|
+
* const { resolve } = useBuilder(myConfig)
|
|
899
|
+
* const service = resolve(MyService)
|
|
900
|
+
* ```
|
|
901
|
+
*/
|
|
902
|
+
function useBuilder(config, context) {
|
|
903
|
+
const provider = getContainerProvider();
|
|
904
|
+
const builderIdToken = Symbol.for(`__builder__${config.builderId}`);
|
|
905
|
+
if (!provider.isRegistered(builderIdToken)) {
|
|
906
|
+
registerConfig(provider, config.injections, context);
|
|
907
|
+
registerEvent(provider, config.listeners);
|
|
908
|
+
provider.registerValue(builderIdToken, config.builderId);
|
|
909
|
+
}
|
|
910
|
+
const resolve = (token) => provider.resolve(token);
|
|
911
|
+
return { resolve };
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
//#endregion
|
|
915
|
+
exports.AwilixProvider = AwilixProvider;
|
|
916
|
+
exports.InversifyProvider = InversifyProvider;
|
|
917
|
+
exports.MutableEventDispatcherProvider = MutableEventDispatcherProvider;
|
|
918
|
+
exports.ProviderLifecycle = ProviderLifecycle;
|
|
919
|
+
exports.TsyringeProvider = TsyringeProvider;
|
|
920
|
+
exports.default = useBuilder;
|
|
921
|
+
exports.defineBuilderConfig = defineBuilderConfig;
|
|
922
|
+
exports.definePartialConfig = definePartialConfig;
|
|
923
|
+
exports.getContainerProvider = getContainerProvider;
|
|
924
|
+
exports.getEventDispatcherProvider = getEventDispatcherProvider;
|
|
925
|
+
exports.hasContainerProvider = hasContainerProvider;
|
|
926
|
+
exports.hasEventDispatcherProvider = hasEventDispatcherProvider;
|
|
927
|
+
exports.resetContainerProvider = resetContainerProvider;
|
|
928
|
+
exports.resetEventDispatcherProvider = resetEventDispatcherProvider;
|
|
929
|
+
exports.useContainerProvider = useContainerProvider;
|
|
930
|
+
exports.useEventDispatcherProvider = useEventDispatcherProvider;
|
|
931
|
+
//# sourceMappingURL=index.cjs.map
|