@khapu2906/treasure-chest 1.0.4 → 1.3.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/README.md +490 -27
- package/dist/cjs/Container.js +491 -0
- package/dist/cjs/Container.js.map +1 -0
- package/dist/cjs/Lazy.js +46 -0
- package/dist/cjs/Lazy.js.map +1 -0
- package/dist/cjs/Scope.js +93 -0
- package/dist/cjs/Scope.js.map +1 -0
- package/dist/cjs/index.js +40 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/types.js +8 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/Container.js +487 -0
- package/dist/esm/Container.js.map +1 -0
- package/dist/esm/Lazy.js +42 -0
- package/dist/esm/Lazy.js.map +1 -0
- package/dist/esm/Scope.js +89 -0
- package/dist/esm/Scope.js.map +1 -0
- package/dist/esm/index.js +34 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types.js +7 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/types/Container.d.ts +299 -0
- package/dist/types/Container.d.ts.map +1 -0
- package/dist/types/Lazy.d.ts +34 -0
- package/dist/types/Lazy.d.ts.map +1 -0
- package/dist/types/Scope.d.ts +60 -0
- package/dist/types/Scope.d.ts.map +1 -0
- package/dist/types/index.d.ts +34 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types.d.ts +77 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +63 -16
- package/dist/index.d.ts +0 -53
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -110
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Treasure Chest - A lightweight TypeScript dependency injection container
|
|
4
|
+
*
|
|
5
|
+
* @module treasure-chest
|
|
6
|
+
* @author Kent Phung
|
|
7
|
+
* @license DIB
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Transient, Singleton, and Scoped bindings
|
|
11
|
+
* - Conditional binding based on runtime conditions
|
|
12
|
+
* - Contextual binding for different implementations per context
|
|
13
|
+
* - Alias support for service keys
|
|
14
|
+
* - Nested dependency resolution
|
|
15
|
+
* - Lazy loading with deferred initialization
|
|
16
|
+
* - Child containers with hierarchy
|
|
17
|
+
* - Circular dependency detection
|
|
18
|
+
* - High-performance Map-based storage (v1.2.0)
|
|
19
|
+
* - Auto-dispose for IDisposable instances (v1.2.0)
|
|
20
|
+
* - Modular architecture (v1.2.0)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { Container } from '@khapu2906/treasure-chest';
|
|
25
|
+
*
|
|
26
|
+
* const container = new Container();
|
|
27
|
+
* container.bind('logger', () => new Logger());
|
|
28
|
+
* const logger = container.resolve('logger');
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.Scope = exports.Lazy = exports.Container = void 0;
|
|
33
|
+
// Export main classes
|
|
34
|
+
var Container_1 = require("./Container");
|
|
35
|
+
Object.defineProperty(exports, "Container", { enumerable: true, get: function () { return Container_1.Container; } });
|
|
36
|
+
var Lazy_1 = require("./Lazy");
|
|
37
|
+
Object.defineProperty(exports, "Lazy", { enumerable: true, get: function () { return Lazy_1.Lazy; } });
|
|
38
|
+
var Scope_1 = require("./Scope");
|
|
39
|
+
Object.defineProperty(exports, "Scope", { enumerable: true, get: function () { return Scope_1.Scope; } });
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;;;AAEH,sBAAsB;AACtB,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAClB,+BAA8B;AAArB,4FAAA,IAAI,OAAA;AACb,iCAAgC;AAAvB,8FAAA,KAAK,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container class for dependency injection
|
|
3
|
+
*
|
|
4
|
+
* @module Container
|
|
5
|
+
*/
|
|
6
|
+
import { Lazy } from './Lazy';
|
|
7
|
+
import { Scope } from './Scope';
|
|
8
|
+
/**
|
|
9
|
+
* Container class for dependency injection
|
|
10
|
+
* Manages service bindings, instances, and resolution logic
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const container = new Container();
|
|
15
|
+
* container.bind('logger', () => new Logger());
|
|
16
|
+
* const logger = container.resolve<Logger>('logger');
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export class Container {
|
|
20
|
+
/**
|
|
21
|
+
* Create a new container
|
|
22
|
+
* @param parent Optional parent container for hierarchy
|
|
23
|
+
*/
|
|
24
|
+
constructor(parent) {
|
|
25
|
+
/** Map-based storage for bindings - O(1) lookup */
|
|
26
|
+
this.bindings = new Map();
|
|
27
|
+
/** Cache for singleton instances */
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
this.instances = new Map();
|
|
30
|
+
/** Mapping of aliases to original keys */
|
|
31
|
+
this.aliases = new Map();
|
|
32
|
+
/** Cache for resolved bindings - performance optimization */
|
|
33
|
+
this.bindingCache = new Map();
|
|
34
|
+
/** Composed containers for composition pattern */
|
|
35
|
+
this.composedContainers = [];
|
|
36
|
+
/** Resolution stack for circular dependency detection */
|
|
37
|
+
this.resolutionStack = [];
|
|
38
|
+
this.parent = parent;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Register a transient binding (new instance on each resolve)
|
|
42
|
+
*
|
|
43
|
+
* @template T The type of service being bound
|
|
44
|
+
* @param key The unique identifier for this service
|
|
45
|
+
* @param factory Factory function that creates the service instance
|
|
46
|
+
* @param condition Optional condition function for conditional binding
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* container.bind('database', (c) => new Database());
|
|
51
|
+
* container.bind('cache', (c) => new Cache(), (c) => process.env.CACHE_ENABLED === 'true');
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
bind(key, factory, condition) {
|
|
55
|
+
const existing = this.bindings.get(key) || [];
|
|
56
|
+
existing.push({ key, factory, lifecycle: 'transient', condition });
|
|
57
|
+
this.bindings.set(key, existing);
|
|
58
|
+
this.bindingCache.clear(); // Invalidate cache
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Register a singleton binding (single instance shared across all resolves)
|
|
62
|
+
*
|
|
63
|
+
* @template T The type of service being bound
|
|
64
|
+
* @param key The unique identifier for this service
|
|
65
|
+
* @param factory Factory function that creates the service instance
|
|
66
|
+
* @param condition Optional condition function for conditional binding
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* container.singleton('config', (c) => new Config());
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
singleton(key, factory, condition) {
|
|
74
|
+
const existing = this.bindings.get(key) || [];
|
|
75
|
+
existing.push({ key, factory, lifecycle: 'singleton', condition });
|
|
76
|
+
this.bindings.set(key, existing);
|
|
77
|
+
this.bindingCache.clear();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Register a scoped binding (single instance per scope)
|
|
81
|
+
*
|
|
82
|
+
* @template T The type of service being bound
|
|
83
|
+
* @param key The unique identifier for this service
|
|
84
|
+
* @param factory Factory function that creates the service instance
|
|
85
|
+
* @param dispose Optional disposal function for cleanup
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* container.scoped('dbConnection', (c) => new DbConnection(), () => {
|
|
90
|
+
* console.log('Closing connection');
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
scoped(key, factory, dispose) {
|
|
95
|
+
const existing = this.bindings.get(key) || [];
|
|
96
|
+
existing.push({ key, factory, lifecycle: 'scoped', dispose });
|
|
97
|
+
this.bindings.set(key, existing);
|
|
98
|
+
this.bindingCache.clear();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Register a lazy binding (deferred initialization)
|
|
102
|
+
*
|
|
103
|
+
* @template T The type of service being bound
|
|
104
|
+
* @param key The unique identifier for this service
|
|
105
|
+
* @param factory Factory function that creates the service instance
|
|
106
|
+
* @param lifecycle The lifecycle type (default: singleton)
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* container.lazy('heavyService', (c) => new HeavyService());
|
|
111
|
+
* const lazy = container.resolve<Lazy<HeavyService>>('heavyService');
|
|
112
|
+
* // Not initialized yet
|
|
113
|
+
* const service = lazy.value; // Initialized now
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
lazy(key, factory, lifecycle = 'singleton') {
|
|
117
|
+
const existing = this.bindings.get(key) || [];
|
|
118
|
+
existing.push({ key, factory, lifecycle, lazy: true });
|
|
119
|
+
this.bindings.set(key, existing);
|
|
120
|
+
this.bindingCache.clear();
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Create an alias for an existing service key
|
|
124
|
+
*
|
|
125
|
+
* @param aliasKey The new alias name
|
|
126
|
+
* @param originalKey The original service key to alias
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* container.bind('UserRepository', () => new UserRepo());
|
|
131
|
+
* container.alias('UserRepo', 'UserRepository');
|
|
132
|
+
* // Both keys now resolve to the same binding
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
alias(aliasKey, originalKey) {
|
|
136
|
+
this.aliases.set(aliasKey, originalKey);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Create a child container that inherits from this container
|
|
140
|
+
*
|
|
141
|
+
* @returns A new child container
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* const parent = new Container();
|
|
146
|
+
* parent.singleton('config', () => new Config());
|
|
147
|
+
*
|
|
148
|
+
* const child = parent.createChild();
|
|
149
|
+
* child.bind('logger', () => new Logger());
|
|
150
|
+
*
|
|
151
|
+
* // Child can resolve both parent and own bindings
|
|
152
|
+
* const config = child.resolve('config'); // From parent
|
|
153
|
+
* const logger = child.resolve('logger'); // From child
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
createChild() {
|
|
157
|
+
return new Container(this);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Create a new scope for scoped instances
|
|
161
|
+
*
|
|
162
|
+
* @returns A new scope
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* const scope = container.createScope();
|
|
167
|
+
* container.scoped('request', () => new Request());
|
|
168
|
+
*
|
|
169
|
+
* const req1 = container.resolve('request'); // Same instance within scope
|
|
170
|
+
* const req2 = container.resolve('request'); // Same as req1
|
|
171
|
+
*
|
|
172
|
+
* await scope.dispose(); // Clean up scoped instances
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
createScope() {
|
|
176
|
+
const scope = new Scope();
|
|
177
|
+
this.currentScope = scope;
|
|
178
|
+
return scope;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Execute a callback with a temporary scope
|
|
182
|
+
* Auto-disposes the scope when done (like C# using statement)
|
|
183
|
+
*
|
|
184
|
+
* @param callback Function to execute within the scope
|
|
185
|
+
* @returns The result of the callback
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* await container.withScope(async (scope) => {
|
|
190
|
+
* const db = container.resolve('dbConnection');
|
|
191
|
+
* await db.query('...');
|
|
192
|
+
* // Auto-disposed when callback completes
|
|
193
|
+
* });
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
async withScope(callback) {
|
|
197
|
+
const scope = this.createScope();
|
|
198
|
+
try {
|
|
199
|
+
return await callback(scope);
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
await scope.dispose();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Find the appropriate binding for a given key and context
|
|
207
|
+
* Searches in current container and parent containers
|
|
208
|
+
* Uses cached result when possible for performance
|
|
209
|
+
*
|
|
210
|
+
* @private
|
|
211
|
+
* @param key The service key to find
|
|
212
|
+
* @param context Optional context for contextual binding
|
|
213
|
+
* @returns The matching binding or undefined
|
|
214
|
+
*/
|
|
215
|
+
findBinding(key, context) {
|
|
216
|
+
const realKey = this.aliases.get(key) || key;
|
|
217
|
+
const cacheKey = context ? `${realKey}::${context}` : realKey;
|
|
218
|
+
// Check cache first
|
|
219
|
+
if (this.bindingCache.has(cacheKey)) {
|
|
220
|
+
return this.bindingCache.get(cacheKey);
|
|
221
|
+
}
|
|
222
|
+
// O(1) Map lookup instead of O(n) array filter
|
|
223
|
+
const bindings = this.bindings.get(realKey);
|
|
224
|
+
if (bindings && bindings.length > 0) {
|
|
225
|
+
// Priority:
|
|
226
|
+
// 1. Binding with context and condition true
|
|
227
|
+
// 2. Binding without context but condition true
|
|
228
|
+
// 3. Binding default first
|
|
229
|
+
const match = bindings.find((b) => b.context === context && (!b.condition || b.condition(this))) ||
|
|
230
|
+
bindings.find((b) => !b.context && (!b.condition || b.condition(this))) ||
|
|
231
|
+
bindings[0];
|
|
232
|
+
// Cache the result only if no conditions (conditions are dynamic)
|
|
233
|
+
if (match && !match.condition) {
|
|
234
|
+
this.bindingCache.set(cacheKey, match);
|
|
235
|
+
}
|
|
236
|
+
return match;
|
|
237
|
+
}
|
|
238
|
+
// Try parent container
|
|
239
|
+
if (this.parent) {
|
|
240
|
+
return this.parent.findBinding(key, context);
|
|
241
|
+
}
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Resolve a service instance from the container
|
|
246
|
+
* Handles transient, singleton, scoped, and lazy bindings
|
|
247
|
+
*
|
|
248
|
+
* @template T The expected type of the resolved service
|
|
249
|
+
* @param key The service key to resolve
|
|
250
|
+
* @param context Optional context for contextual resolution
|
|
251
|
+
* @returns The resolved service instance
|
|
252
|
+
* @throws Error if no binding exists for the key
|
|
253
|
+
* @throws Error if circular dependency is detected
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* const logger = container.resolve<Logger>('logger');
|
|
258
|
+
* const userRepo = container.resolve('UserRepo', 'UserService');
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
resolve(key, context) {
|
|
262
|
+
const realKey = this.aliases.get(key) || key;
|
|
263
|
+
// Circular dependency detection
|
|
264
|
+
if (this.resolutionStack.includes(realKey)) {
|
|
265
|
+
const chain = [...this.resolutionStack, realKey].join(' -> ');
|
|
266
|
+
throw new Error(`Circular dependency detected: ${chain}`);
|
|
267
|
+
}
|
|
268
|
+
const prevContext = this.currentContext;
|
|
269
|
+
this.currentContext = context || key;
|
|
270
|
+
const binding = this.findBinding(key, this.currentContext);
|
|
271
|
+
if (!binding) {
|
|
272
|
+
throw new Error(`No binding found for key: ${realKey}`);
|
|
273
|
+
}
|
|
274
|
+
// Add to resolution stack
|
|
275
|
+
this.resolutionStack.push(realKey);
|
|
276
|
+
try {
|
|
277
|
+
// Handle lazy binding
|
|
278
|
+
if (binding.lazy) {
|
|
279
|
+
const instance = this.resolveLazy(binding, realKey);
|
|
280
|
+
return instance;
|
|
281
|
+
}
|
|
282
|
+
// Handle different lifecycles
|
|
283
|
+
switch (binding.lifecycle) {
|
|
284
|
+
case 'singleton':
|
|
285
|
+
return this.resolveSingleton(binding, realKey);
|
|
286
|
+
case 'scoped':
|
|
287
|
+
return this.resolveScoped(binding, realKey);
|
|
288
|
+
case 'transient':
|
|
289
|
+
default:
|
|
290
|
+
return this.resolveTransient(binding);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
finally {
|
|
294
|
+
// Remove from resolution stack
|
|
295
|
+
this.resolutionStack.pop();
|
|
296
|
+
this.currentContext = prevContext;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Resolve a transient instance
|
|
301
|
+
* @private
|
|
302
|
+
*/
|
|
303
|
+
resolveTransient(binding) {
|
|
304
|
+
return binding.factory(this);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Resolve a singleton instance
|
|
308
|
+
* @private
|
|
309
|
+
*/
|
|
310
|
+
resolveSingleton(binding, cacheKey) {
|
|
311
|
+
const fullCacheKey = binding.context
|
|
312
|
+
? `${cacheKey}::${binding.context}`
|
|
313
|
+
: cacheKey;
|
|
314
|
+
if (this.instances.has(fullCacheKey)) {
|
|
315
|
+
return this.instances.get(fullCacheKey);
|
|
316
|
+
}
|
|
317
|
+
const instance = binding.factory(this);
|
|
318
|
+
this.instances.set(fullCacheKey, instance);
|
|
319
|
+
return instance;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Resolve a scoped instance
|
|
323
|
+
* @private
|
|
324
|
+
*/
|
|
325
|
+
resolveScoped(binding, key) {
|
|
326
|
+
if (!this.currentScope) {
|
|
327
|
+
throw new Error(`No active scope for scoped binding: ${key}. Call createScope() first.`);
|
|
328
|
+
}
|
|
329
|
+
if (this.currentScope.has(key)) {
|
|
330
|
+
return this.currentScope.get(key);
|
|
331
|
+
}
|
|
332
|
+
const instance = binding.factory(this);
|
|
333
|
+
this.currentScope.set(key, instance, binding.dispose);
|
|
334
|
+
return instance;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Resolve a lazy instance
|
|
338
|
+
* @private
|
|
339
|
+
*/
|
|
340
|
+
resolveLazy(binding, cacheKey) {
|
|
341
|
+
const fullCacheKey = `lazy::${cacheKey}`;
|
|
342
|
+
if (this.instances.has(fullCacheKey)) {
|
|
343
|
+
return this.instances.get(fullCacheKey);
|
|
344
|
+
}
|
|
345
|
+
const lazy = new Lazy(() => binding.factory(this));
|
|
346
|
+
if (binding.lifecycle === 'singleton') {
|
|
347
|
+
this.instances.set(fullCacheKey, lazy);
|
|
348
|
+
}
|
|
349
|
+
return lazy;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Create a contextual binding (different implementations based on context)
|
|
353
|
+
* Provides a fluent API for defining context-specific dependencies
|
|
354
|
+
*
|
|
355
|
+
* @param context The context identifier (usually a service name)
|
|
356
|
+
* @returns A fluent API object with needs() method
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
* ```typescript
|
|
360
|
+
* // UserService will receive MockUserRepo
|
|
361
|
+
* container.when('UserService').needs('UserRepo').give(() => new MockUserRepo());
|
|
362
|
+
*
|
|
363
|
+
* // OrderService will receive RealUserRepo
|
|
364
|
+
* container.when('OrderService').needs('UserRepo').give(() => new RealUserRepo());
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
when(context) {
|
|
368
|
+
return {
|
|
369
|
+
needs: (depKey) => ({
|
|
370
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
371
|
+
give: (factory) => {
|
|
372
|
+
const existing = this.bindings.get(depKey) || [];
|
|
373
|
+
existing.push({
|
|
374
|
+
key: depKey,
|
|
375
|
+
factory,
|
|
376
|
+
lifecycle: 'transient',
|
|
377
|
+
context,
|
|
378
|
+
});
|
|
379
|
+
this.bindings.set(depKey, existing);
|
|
380
|
+
this.bindingCache.clear();
|
|
381
|
+
},
|
|
382
|
+
}),
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Check if a binding exists for a key
|
|
387
|
+
*
|
|
388
|
+
* @param key The service key to check
|
|
389
|
+
* @returns True if binding exists
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```typescript
|
|
393
|
+
* if (container.has('logger')) {
|
|
394
|
+
* const logger = container.resolve('logger');
|
|
395
|
+
* }
|
|
396
|
+
* ```
|
|
397
|
+
*/
|
|
398
|
+
has(key) {
|
|
399
|
+
return this.findBinding(key) !== undefined;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Get all registered service keys
|
|
403
|
+
*
|
|
404
|
+
* @returns Array of service keys
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```typescript
|
|
408
|
+
* const keys = container.keys();
|
|
409
|
+
* console.log('Registered services:', keys);
|
|
410
|
+
* ```
|
|
411
|
+
*/
|
|
412
|
+
keys() {
|
|
413
|
+
const ownKeys = Array.from(this.bindings.keys());
|
|
414
|
+
const parentKeys = this.parent ? this.parent.keys() : [];
|
|
415
|
+
return [...new Set([...ownKeys, ...parentKeys])];
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Reset the container to its initial state
|
|
419
|
+
* Clears all bindings, instances, aliases, and context
|
|
420
|
+
* Useful for testing scenarios
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
* ```typescript
|
|
424
|
+
* afterEach(() => {
|
|
425
|
+
* container.reset();
|
|
426
|
+
* });
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
reset() {
|
|
430
|
+
this.bindings.clear();
|
|
431
|
+
this.instances.clear();
|
|
432
|
+
this.aliases.clear();
|
|
433
|
+
this.bindingCache.clear();
|
|
434
|
+
this.currentContext = undefined;
|
|
435
|
+
this.currentScope = undefined;
|
|
436
|
+
this.resolutionStack = [];
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Compose multiple containers into a new container
|
|
440
|
+
* This allows mixing services from different domains without inheritance
|
|
441
|
+
*
|
|
442
|
+
* @param containers Array of containers to compose
|
|
443
|
+
* @returns New composed container
|
|
444
|
+
*/
|
|
445
|
+
static compose(containers) {
|
|
446
|
+
const composed = new Container();
|
|
447
|
+
// Validate containers
|
|
448
|
+
if (!containers || containers.length === 0) {
|
|
449
|
+
throw new Error('At least one container must be provided for composition');
|
|
450
|
+
}
|
|
451
|
+
// Store composed containers
|
|
452
|
+
composed.composedContainers = [...containers];
|
|
453
|
+
// Create proxy bindings for all keys from composed containers
|
|
454
|
+
const allKeys = new Set();
|
|
455
|
+
containers.forEach((container) => {
|
|
456
|
+
container.keys().forEach((key) => allKeys.add(key));
|
|
457
|
+
});
|
|
458
|
+
// Bind proxy resolvers
|
|
459
|
+
for (const key of allKeys) {
|
|
460
|
+
composed.bind(key, (c) => c.resolveFromComposition(key));
|
|
461
|
+
}
|
|
462
|
+
return composed;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Resolve a service from composed containers
|
|
466
|
+
* @private
|
|
467
|
+
*/
|
|
468
|
+
resolveFromComposition(key) {
|
|
469
|
+
// Search through composed containers in order
|
|
470
|
+
for (const container of this.composedContainers) {
|
|
471
|
+
if (container.has(key)) {
|
|
472
|
+
return container.resolve(key);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
throw new Error(`No binding found for key: ${key}`);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Dispose the container and all its scoped instances
|
|
479
|
+
*/
|
|
480
|
+
async dispose() {
|
|
481
|
+
if (this.currentScope) {
|
|
482
|
+
await this.currentScope.dispose();
|
|
483
|
+
}
|
|
484
|
+
this.reset();
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
//# sourceMappingURL=Container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Container.js","sourceRoot":"","sources":["../../src/Container.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/Lazy.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy wrapper for deferred initialization
|
|
3
|
+
*
|
|
4
|
+
* @module Lazy
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Lazy wrapper for deferred initialization
|
|
8
|
+
* Delays the creation of an instance until it's actually accessed
|
|
9
|
+
*
|
|
10
|
+
* @template T The type of the lazy value
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const lazy = new Lazy(() => new ExpensiveService());
|
|
15
|
+
* console.log(lazy.isInitialized); // false
|
|
16
|
+
* const service = lazy.value; // NOW it's created
|
|
17
|
+
* console.log(lazy.isInitialized); // true
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export class Lazy {
|
|
21
|
+
constructor(factory) {
|
|
22
|
+
this.factory = factory;
|
|
23
|
+
this._initialized = false;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get the lazy value, initializing it if necessary
|
|
27
|
+
*/
|
|
28
|
+
get value() {
|
|
29
|
+
if (!this._initialized) {
|
|
30
|
+
this._value = this.factory();
|
|
31
|
+
this._initialized = true;
|
|
32
|
+
}
|
|
33
|
+
return this._value;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if the lazy value has been initialized
|
|
37
|
+
*/
|
|
38
|
+
get isInitialized() {
|
|
39
|
+
return this._initialized;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=Lazy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Lazy.js","sourceRoot":"","sources":["../../src/Lazy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,IAAI;IAIf,YAAoB,OAAgB;QAAhB,YAAO,GAAP,OAAO,CAAS;QAF5B,iBAAY,GAAG,KAAK,CAAC;IAEU,CAAC;IAExC;;OAEG;IACH,IAAI,KAAK;QACP,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC,MAAO,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;CACF"}
|