@khapu2906/treasure-chest 1.0.4 → 1.2.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.
@@ -0,0 +1,450 @@
1
+ "use strict";
2
+ /**
3
+ * Container class for dependency injection
4
+ *
5
+ * @module Container
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.Container = void 0;
9
+ const Lazy_1 = require("./Lazy");
10
+ const Scope_1 = require("./Scope");
11
+ /**
12
+ * Container class for dependency injection
13
+ * Manages service bindings, instances, and resolution logic
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const container = new Container();
18
+ * container.bind('logger', () => new Logger());
19
+ * const logger = container.resolve<Logger>('logger');
20
+ * ```
21
+ */
22
+ class Container {
23
+ /**
24
+ * Create a new container
25
+ * @param parent Optional parent container for hierarchy
26
+ */
27
+ constructor(parent) {
28
+ /** Map-based storage for bindings - O(1) lookup */
29
+ this.bindings = new Map();
30
+ /** Cache for singleton instances */
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ this.instances = new Map();
33
+ /** Mapping of aliases to original keys */
34
+ this.aliases = new Map();
35
+ /** Cache for resolved bindings - performance optimization */
36
+ this.bindingCache = new Map();
37
+ /** Resolution stack for circular dependency detection */
38
+ this.resolutionStack = [];
39
+ this.parent = parent;
40
+ }
41
+ /**
42
+ * Register a transient binding (new instance on each resolve)
43
+ *
44
+ * @template T The type of service being bound
45
+ * @param key The unique identifier for this service
46
+ * @param factory Factory function that creates the service instance
47
+ * @param condition Optional condition function for conditional binding
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * container.bind('database', (c) => new Database());
52
+ * container.bind('cache', (c) => new Cache(), (c) => process.env.CACHE_ENABLED === 'true');
53
+ * ```
54
+ */
55
+ bind(key, factory, condition) {
56
+ const existing = this.bindings.get(key) || [];
57
+ existing.push({ key, factory, lifecycle: 'transient', condition });
58
+ this.bindings.set(key, existing);
59
+ this.bindingCache.clear(); // Invalidate cache
60
+ }
61
+ /**
62
+ * Register a singleton binding (single instance shared across all resolves)
63
+ *
64
+ * @template T The type of service being bound
65
+ * @param key The unique identifier for this service
66
+ * @param factory Factory function that creates the service instance
67
+ * @param condition Optional condition function for conditional binding
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * container.singleton('config', (c) => new Config());
72
+ * ```
73
+ */
74
+ singleton(key, factory, condition) {
75
+ const existing = this.bindings.get(key) || [];
76
+ existing.push({ key, factory, lifecycle: 'singleton', condition });
77
+ this.bindings.set(key, existing);
78
+ this.bindingCache.clear();
79
+ }
80
+ /**
81
+ * Register a scoped binding (single instance per scope)
82
+ *
83
+ * @template T The type of service being bound
84
+ * @param key The unique identifier for this service
85
+ * @param factory Factory function that creates the service instance
86
+ * @param dispose Optional disposal function for cleanup
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * container.scoped('dbConnection', (c) => new DbConnection(), () => {
91
+ * console.log('Closing connection');
92
+ * });
93
+ * ```
94
+ */
95
+ scoped(key, factory, dispose) {
96
+ const existing = this.bindings.get(key) || [];
97
+ existing.push({ key, factory, lifecycle: 'scoped', dispose });
98
+ this.bindings.set(key, existing);
99
+ this.bindingCache.clear();
100
+ }
101
+ /**
102
+ * Register a lazy binding (deferred initialization)
103
+ *
104
+ * @template T The type of service being bound
105
+ * @param key The unique identifier for this service
106
+ * @param factory Factory function that creates the service instance
107
+ * @param lifecycle The lifecycle type (default: singleton)
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * container.lazy('heavyService', (c) => new HeavyService());
112
+ * const lazy = container.resolve<Lazy<HeavyService>>('heavyService');
113
+ * // Not initialized yet
114
+ * const service = lazy.value; // Initialized now
115
+ * ```
116
+ */
117
+ lazy(key, factory, lifecycle = 'singleton') {
118
+ const existing = this.bindings.get(key) || [];
119
+ existing.push({ key, factory, lifecycle, lazy: true });
120
+ this.bindings.set(key, existing);
121
+ this.bindingCache.clear();
122
+ }
123
+ /**
124
+ * Create an alias for an existing service key
125
+ *
126
+ * @param aliasKey The new alias name
127
+ * @param originalKey The original service key to alias
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * container.bind('UserRepository', () => new UserRepo());
132
+ * container.alias('UserRepo', 'UserRepository');
133
+ * // Both keys now resolve to the same binding
134
+ * ```
135
+ */
136
+ alias(aliasKey, originalKey) {
137
+ this.aliases.set(aliasKey, originalKey);
138
+ }
139
+ /**
140
+ * Create a child container that inherits from this container
141
+ *
142
+ * @returns A new child container
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * const parent = new Container();
147
+ * parent.singleton('config', () => new Config());
148
+ *
149
+ * const child = parent.createChild();
150
+ * child.bind('logger', () => new Logger());
151
+ *
152
+ * // Child can resolve both parent and own bindings
153
+ * const config = child.resolve('config'); // From parent
154
+ * const logger = child.resolve('logger'); // From child
155
+ * ```
156
+ */
157
+ createChild() {
158
+ return new Container(this);
159
+ }
160
+ /**
161
+ * Create a new scope for scoped instances
162
+ *
163
+ * @returns A new scope
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * const scope = container.createScope();
168
+ * container.scoped('request', () => new Request());
169
+ *
170
+ * const req1 = container.resolve('request'); // Same instance within scope
171
+ * const req2 = container.resolve('request'); // Same as req1
172
+ *
173
+ * await scope.dispose(); // Clean up scoped instances
174
+ * ```
175
+ */
176
+ createScope() {
177
+ const scope = new Scope_1.Scope();
178
+ this.currentScope = scope;
179
+ return scope;
180
+ }
181
+ /**
182
+ * Execute a callback with a temporary scope
183
+ * Auto-disposes the scope when done (like C# using statement)
184
+ *
185
+ * @param callback Function to execute within the scope
186
+ * @returns The result of the callback
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * await container.withScope(async (scope) => {
191
+ * const db = container.resolve('dbConnection');
192
+ * await db.query('...');
193
+ * // Auto-disposed when callback completes
194
+ * });
195
+ * ```
196
+ */
197
+ async withScope(callback) {
198
+ const scope = this.createScope();
199
+ try {
200
+ return await callback(scope);
201
+ }
202
+ finally {
203
+ await scope.dispose();
204
+ }
205
+ }
206
+ /**
207
+ * Find the appropriate binding for a given key and context
208
+ * Searches in current container and parent containers
209
+ * Uses cached result when possible for performance
210
+ *
211
+ * @private
212
+ * @param key The service key to find
213
+ * @param context Optional context for contextual binding
214
+ * @returns The matching binding or undefined
215
+ */
216
+ findBinding(key, context) {
217
+ const realKey = this.aliases.get(key) || key;
218
+ const cacheKey = context ? `${realKey}::${context}` : realKey;
219
+ // Check cache first
220
+ if (this.bindingCache.has(cacheKey)) {
221
+ return this.bindingCache.get(cacheKey);
222
+ }
223
+ // O(1) Map lookup instead of O(n) array filter
224
+ const bindings = this.bindings.get(realKey);
225
+ if (bindings && bindings.length > 0) {
226
+ // Priority:
227
+ // 1. Binding with context and condition true
228
+ // 2. Binding without context but condition true
229
+ // 3. Binding default first
230
+ const match = bindings.find((b) => b.context === context && (!b.condition || b.condition(this))) ||
231
+ bindings.find((b) => !b.context && (!b.condition || b.condition(this))) ||
232
+ bindings[0];
233
+ // Cache the result only if no conditions (conditions are dynamic)
234
+ if (match && !match.condition) {
235
+ this.bindingCache.set(cacheKey, match);
236
+ }
237
+ return match;
238
+ }
239
+ // Try parent container
240
+ if (this.parent) {
241
+ return this.parent.findBinding(key, context);
242
+ }
243
+ return undefined;
244
+ }
245
+ /**
246
+ * Resolve a service instance from the container
247
+ * Handles transient, singleton, scoped, and lazy bindings
248
+ *
249
+ * @template T The expected type of the resolved service
250
+ * @param key The service key to resolve
251
+ * @param context Optional context for contextual resolution
252
+ * @returns The resolved service instance
253
+ * @throws Error if no binding exists for the key
254
+ * @throws Error if circular dependency is detected
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * const logger = container.resolve<Logger>('logger');
259
+ * const userRepo = container.resolve('UserRepo', 'UserService');
260
+ * ```
261
+ */
262
+ resolve(key, context) {
263
+ const realKey = this.aliases.get(key) || key;
264
+ // Circular dependency detection
265
+ if (this.resolutionStack.includes(realKey)) {
266
+ const chain = [...this.resolutionStack, realKey].join(' -> ');
267
+ throw new Error(`Circular dependency detected: ${chain}`);
268
+ }
269
+ const prevContext = this.currentContext;
270
+ this.currentContext = context || key;
271
+ const binding = this.findBinding(key, this.currentContext);
272
+ if (!binding) {
273
+ throw new Error(`No binding found for key: ${realKey}`);
274
+ }
275
+ // Add to resolution stack
276
+ this.resolutionStack.push(realKey);
277
+ try {
278
+ // Handle lazy binding
279
+ if (binding.lazy) {
280
+ const instance = this.resolveLazy(binding, realKey);
281
+ return instance;
282
+ }
283
+ // Handle different lifecycles
284
+ switch (binding.lifecycle) {
285
+ case 'singleton':
286
+ return this.resolveSingleton(binding, realKey);
287
+ case 'scoped':
288
+ return this.resolveScoped(binding, realKey);
289
+ case 'transient':
290
+ default:
291
+ return this.resolveTransient(binding);
292
+ }
293
+ }
294
+ finally {
295
+ // Remove from resolution stack
296
+ this.resolutionStack.pop();
297
+ this.currentContext = prevContext;
298
+ }
299
+ }
300
+ /**
301
+ * Resolve a transient instance
302
+ * @private
303
+ */
304
+ resolveTransient(binding) {
305
+ return binding.factory(this);
306
+ }
307
+ /**
308
+ * Resolve a singleton instance
309
+ * @private
310
+ */
311
+ resolveSingleton(binding, cacheKey) {
312
+ const fullCacheKey = binding.context
313
+ ? `${cacheKey}::${binding.context}`
314
+ : cacheKey;
315
+ if (this.instances.has(fullCacheKey)) {
316
+ return this.instances.get(fullCacheKey);
317
+ }
318
+ const instance = binding.factory(this);
319
+ this.instances.set(fullCacheKey, instance);
320
+ return instance;
321
+ }
322
+ /**
323
+ * Resolve a scoped instance
324
+ * @private
325
+ */
326
+ resolveScoped(binding, key) {
327
+ if (!this.currentScope) {
328
+ throw new Error(`No active scope for scoped binding: ${key}. Call createScope() first.`);
329
+ }
330
+ if (this.currentScope.has(key)) {
331
+ return this.currentScope.get(key);
332
+ }
333
+ const instance = binding.factory(this);
334
+ this.currentScope.set(key, instance, binding.dispose);
335
+ return instance;
336
+ }
337
+ /**
338
+ * Resolve a lazy instance
339
+ * @private
340
+ */
341
+ resolveLazy(binding, cacheKey) {
342
+ const fullCacheKey = `lazy::${cacheKey}`;
343
+ if (this.instances.has(fullCacheKey)) {
344
+ return this.instances.get(fullCacheKey);
345
+ }
346
+ const lazy = new Lazy_1.Lazy(() => binding.factory(this));
347
+ if (binding.lifecycle === 'singleton') {
348
+ this.instances.set(fullCacheKey, lazy);
349
+ }
350
+ return lazy;
351
+ }
352
+ /**
353
+ * Create a contextual binding (different implementations based on context)
354
+ * Provides a fluent API for defining context-specific dependencies
355
+ *
356
+ * @param context The context identifier (usually a service name)
357
+ * @returns A fluent API object with needs() method
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * // UserService will receive MockUserRepo
362
+ * container.when('UserService').needs('UserRepo').give(() => new MockUserRepo());
363
+ *
364
+ * // OrderService will receive RealUserRepo
365
+ * container.when('OrderService').needs('UserRepo').give(() => new RealUserRepo());
366
+ * ```
367
+ */
368
+ when(context) {
369
+ return {
370
+ needs: (depKey) => ({
371
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
372
+ give: (factory) => {
373
+ const existing = this.bindings.get(depKey) || [];
374
+ existing.push({
375
+ key: depKey,
376
+ factory,
377
+ lifecycle: 'transient',
378
+ context,
379
+ });
380
+ this.bindings.set(depKey, existing);
381
+ this.bindingCache.clear();
382
+ },
383
+ }),
384
+ };
385
+ }
386
+ /**
387
+ * Check if a binding exists for a key
388
+ *
389
+ * @param key The service key to check
390
+ * @returns True if binding exists
391
+ *
392
+ * @example
393
+ * ```typescript
394
+ * if (container.has('logger')) {
395
+ * const logger = container.resolve('logger');
396
+ * }
397
+ * ```
398
+ */
399
+ has(key) {
400
+ return this.findBinding(key) !== undefined;
401
+ }
402
+ /**
403
+ * Get all registered service keys
404
+ *
405
+ * @returns Array of service keys
406
+ *
407
+ * @example
408
+ * ```typescript
409
+ * const keys = container.keys();
410
+ * console.log('Registered services:', keys);
411
+ * ```
412
+ */
413
+ keys() {
414
+ const ownKeys = Array.from(this.bindings.keys());
415
+ const parentKeys = this.parent ? this.parent.keys() : [];
416
+ return [...new Set([...ownKeys, ...parentKeys])];
417
+ }
418
+ /**
419
+ * Reset the container to its initial state
420
+ * Clears all bindings, instances, aliases, and context
421
+ * Useful for testing scenarios
422
+ *
423
+ * @example
424
+ * ```typescript
425
+ * afterEach(() => {
426
+ * container.reset();
427
+ * });
428
+ * ```
429
+ */
430
+ reset() {
431
+ this.bindings.clear();
432
+ this.instances.clear();
433
+ this.aliases.clear();
434
+ this.bindingCache.clear();
435
+ this.currentContext = undefined;
436
+ this.currentScope = undefined;
437
+ this.resolutionStack = [];
438
+ }
439
+ /**
440
+ * Dispose the container and all its scoped instances
441
+ */
442
+ async dispose() {
443
+ if (this.currentScope) {
444
+ await this.currentScope.dispose();
445
+ }
446
+ this.reset();
447
+ }
448
+ }
449
+ exports.Container = Container;
450
+ //# sourceMappingURL=Container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Container.js","sourceRoot":"","sources":["../../src/Container.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /**
3
+ * Lazy wrapper for deferred initialization
4
+ *
5
+ * @module Lazy
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.Lazy = void 0;
9
+ /**
10
+ * Lazy wrapper for deferred initialization
11
+ * Delays the creation of an instance until it's actually accessed
12
+ *
13
+ * @template T The type of the lazy value
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const lazy = new Lazy(() => new ExpensiveService());
18
+ * console.log(lazy.isInitialized); // false
19
+ * const service = lazy.value; // NOW it's created
20
+ * console.log(lazy.isInitialized); // true
21
+ * ```
22
+ */
23
+ class Lazy {
24
+ constructor(factory) {
25
+ this.factory = factory;
26
+ this._initialized = false;
27
+ }
28
+ /**
29
+ * Get the lazy value, initializing it if necessary
30
+ */
31
+ get value() {
32
+ if (!this._initialized) {
33
+ this._value = this.factory();
34
+ this._initialized = true;
35
+ }
36
+ return this._value;
37
+ }
38
+ /**
39
+ * Check if the lazy value has been initialized
40
+ */
41
+ get isInitialized() {
42
+ return this._initialized;
43
+ }
44
+ }
45
+ exports.Lazy = Lazy;
46
+ //# 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,MAAa,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;AAvBD,oBAuBC"}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ /**
3
+ * Scope management for scoped instances
4
+ *
5
+ * @module Scope
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.Scope = void 0;
9
+ /**
10
+ * Scope class for managing scoped instances
11
+ * A scope contains instances that live for a specific duration (e.g., per HTTP request)
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const scope = container.createScope();
16
+ * const conn = container.resolve('dbConnection'); // Scoped instance
17
+ * await scope.dispose(); // Cleanup all scoped resources
18
+ * ```
19
+ */
20
+ class Scope {
21
+ constructor() {
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ this.instances = new Map();
24
+ this.disposables = [];
25
+ }
26
+ /**
27
+ * Get an instance from this scope
28
+ * @param key The service key
29
+ * @returns The instance or undefined
30
+ */
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ get(key) {
33
+ return this.instances.get(key);
34
+ }
35
+ /**
36
+ * Set an instance in this scope with optional cleanup
37
+ * Auto-detects IDisposable instances
38
+ *
39
+ * @param key The service key
40
+ * @param value The instance to store
41
+ * @param dispose Optional disposal function
42
+ */
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ set(key, value, dispose) {
45
+ this.instances.set(key, value);
46
+ // Auto-detect IDisposable
47
+ if (!dispose && this.isDisposable(value)) {
48
+ dispose = () => value.dispose();
49
+ }
50
+ if (dispose) {
51
+ this.disposables.push(dispose);
52
+ }
53
+ }
54
+ /**
55
+ * Check if instance exists in scope
56
+ * @param key The service key
57
+ * @returns True if the instance exists
58
+ */
59
+ has(key) {
60
+ return this.instances.has(key);
61
+ }
62
+ /**
63
+ * Check if value implements IDisposable interface
64
+ * @private
65
+ * @param value The value to check
66
+ * @returns True if the value is disposable
67
+ */
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ isDisposable(value) {
70
+ return (value !== null &&
71
+ value !== undefined &&
72
+ typeof value === 'object' &&
73
+ typeof value.dispose === 'function');
74
+ }
75
+ /**
76
+ * Dispose all instances in this scope
77
+ * Calls all registered disposal functions and clears the scope
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * await scope.dispose();
82
+ * ```
83
+ */
84
+ async dispose() {
85
+ for (const disposeFn of this.disposables) {
86
+ await disposeFn();
87
+ }
88
+ this.instances.clear();
89
+ this.disposables = [];
90
+ }
91
+ }
92
+ exports.Scope = Scope;
93
+ //# sourceMappingURL=Scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scope.js","sourceRoot":"","sources":["../../src/Scope.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAIH;;;;;;;;;;GAUG;AACH,MAAa,KAAK;IAAlB;QACE,8DAA8D;QACtD,cAAS,GAAqB,IAAI,GAAG,EAAE,CAAC;QACxC,gBAAW,GAAgB,EAAE,CAAC;IA2ExC,CAAC;IAzEC;;;;OAIG;IACH,8DAA8D;IAC9D,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;OAOG;IACH,8DAA8D;IAC9D,GAAG,CAAC,GAAW,EAAE,KAAU,EAAE,OAAmB;QAC9C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE/B,0BAA0B;QAC1B,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QAClC,CAAC;QAED,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED;;;;;OAKG;IACH,8DAA8D;IACtD,YAAY,CAAC,KAAU;QAC7B,OAAO,CACL,KAAK,KAAK,IAAI;YACd,KAAK,KAAK,SAAS;YACnB,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU,CACpC,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO;QACX,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACzC,MAAM,SAAS,EAAE,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;IACxB,CAAC;CACF;AA9ED,sBA8EC"}
@@ -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,8 @@
1
+ "use strict";
2
+ /**
3
+ * Type definitions for Treasure Chest DI Container
4
+ *
5
+ * @module types
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG"}