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