@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.
- package/README.md +454 -27
- package/dist/cjs/Container.js +450 -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 +446 -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 +284 -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 +64 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +58 -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,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container class for dependency injection
|
|
3
|
+
*
|
|
4
|
+
* @module Container
|
|
5
|
+
*/
|
|
6
|
+
import type { ConditionFn, DisposeFn, FactoryFn, Lifecycle } from './types';
|
|
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 declare class Container {
|
|
20
|
+
/** Map-based storage for bindings - O(1) lookup */
|
|
21
|
+
private bindings;
|
|
22
|
+
/** Cache for singleton instances */
|
|
23
|
+
private instances;
|
|
24
|
+
/** Mapping of aliases to original keys */
|
|
25
|
+
private aliases;
|
|
26
|
+
/** Cache for resolved bindings - performance optimization */
|
|
27
|
+
private bindingCache;
|
|
28
|
+
/** Current resolution context for contextual binding */
|
|
29
|
+
private currentContext?;
|
|
30
|
+
/** Parent container for hierarchy */
|
|
31
|
+
private parent?;
|
|
32
|
+
/** Current active scope */
|
|
33
|
+
private currentScope?;
|
|
34
|
+
/** Resolution stack for circular dependency detection */
|
|
35
|
+
private resolutionStack;
|
|
36
|
+
/**
|
|
37
|
+
* Create a new container
|
|
38
|
+
* @param parent Optional parent container for hierarchy
|
|
39
|
+
*/
|
|
40
|
+
constructor(parent?: Container);
|
|
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<T>(key: string, factory: FactoryFn<T>, condition?: ConditionFn): void;
|
|
56
|
+
/**
|
|
57
|
+
* Register a singleton binding (single instance shared across all resolves)
|
|
58
|
+
*
|
|
59
|
+
* @template T The type of service being bound
|
|
60
|
+
* @param key The unique identifier for this service
|
|
61
|
+
* @param factory Factory function that creates the service instance
|
|
62
|
+
* @param condition Optional condition function for conditional binding
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* container.singleton('config', (c) => new Config());
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
singleton<T>(key: string, factory: FactoryFn<T>, condition?: ConditionFn): void;
|
|
70
|
+
/**
|
|
71
|
+
* Register a scoped binding (single instance per scope)
|
|
72
|
+
*
|
|
73
|
+
* @template T The type of service being bound
|
|
74
|
+
* @param key The unique identifier for this service
|
|
75
|
+
* @param factory Factory function that creates the service instance
|
|
76
|
+
* @param dispose Optional disposal function for cleanup
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* container.scoped('dbConnection', (c) => new DbConnection(), () => {
|
|
81
|
+
* console.log('Closing connection');
|
|
82
|
+
* });
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
scoped<T>(key: string, factory: FactoryFn<T>, dispose?: DisposeFn): void;
|
|
86
|
+
/**
|
|
87
|
+
* Register a lazy binding (deferred initialization)
|
|
88
|
+
*
|
|
89
|
+
* @template T The type of service being bound
|
|
90
|
+
* @param key The unique identifier for this service
|
|
91
|
+
* @param factory Factory function that creates the service instance
|
|
92
|
+
* @param lifecycle The lifecycle type (default: singleton)
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* container.lazy('heavyService', (c) => new HeavyService());
|
|
97
|
+
* const lazy = container.resolve<Lazy<HeavyService>>('heavyService');
|
|
98
|
+
* // Not initialized yet
|
|
99
|
+
* const service = lazy.value; // Initialized now
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
lazy<T>(key: string, factory: FactoryFn<T>, lifecycle?: Lifecycle): void;
|
|
103
|
+
/**
|
|
104
|
+
* Create an alias for an existing service key
|
|
105
|
+
*
|
|
106
|
+
* @param aliasKey The new alias name
|
|
107
|
+
* @param originalKey The original service key to alias
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* container.bind('UserRepository', () => new UserRepo());
|
|
112
|
+
* container.alias('UserRepo', 'UserRepository');
|
|
113
|
+
* // Both keys now resolve to the same binding
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
alias(aliasKey: string, originalKey: string): void;
|
|
117
|
+
/**
|
|
118
|
+
* Create a child container that inherits from this container
|
|
119
|
+
*
|
|
120
|
+
* @returns A new child container
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const parent = new Container();
|
|
125
|
+
* parent.singleton('config', () => new Config());
|
|
126
|
+
*
|
|
127
|
+
* const child = parent.createChild();
|
|
128
|
+
* child.bind('logger', () => new Logger());
|
|
129
|
+
*
|
|
130
|
+
* // Child can resolve both parent and own bindings
|
|
131
|
+
* const config = child.resolve('config'); // From parent
|
|
132
|
+
* const logger = child.resolve('logger'); // From child
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
createChild(): Container;
|
|
136
|
+
/**
|
|
137
|
+
* Create a new scope for scoped instances
|
|
138
|
+
*
|
|
139
|
+
* @returns A new scope
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const scope = container.createScope();
|
|
144
|
+
* container.scoped('request', () => new Request());
|
|
145
|
+
*
|
|
146
|
+
* const req1 = container.resolve('request'); // Same instance within scope
|
|
147
|
+
* const req2 = container.resolve('request'); // Same as req1
|
|
148
|
+
*
|
|
149
|
+
* await scope.dispose(); // Clean up scoped instances
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
createScope(): Scope;
|
|
153
|
+
/**
|
|
154
|
+
* Execute a callback with a temporary scope
|
|
155
|
+
* Auto-disposes the scope when done (like C# using statement)
|
|
156
|
+
*
|
|
157
|
+
* @param callback Function to execute within the scope
|
|
158
|
+
* @returns The result of the callback
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* await container.withScope(async (scope) => {
|
|
163
|
+
* const db = container.resolve('dbConnection');
|
|
164
|
+
* await db.query('...');
|
|
165
|
+
* // Auto-disposed when callback completes
|
|
166
|
+
* });
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
withScope<T>(callback: (scope: Scope) => T | Promise<T>): Promise<T>;
|
|
170
|
+
/**
|
|
171
|
+
* Find the appropriate binding for a given key and context
|
|
172
|
+
* Searches in current container and parent containers
|
|
173
|
+
* Uses cached result when possible for performance
|
|
174
|
+
*
|
|
175
|
+
* @private
|
|
176
|
+
* @param key The service key to find
|
|
177
|
+
* @param context Optional context for contextual binding
|
|
178
|
+
* @returns The matching binding or undefined
|
|
179
|
+
*/
|
|
180
|
+
private findBinding;
|
|
181
|
+
/**
|
|
182
|
+
* Resolve a service instance from the container
|
|
183
|
+
* Handles transient, singleton, scoped, and lazy bindings
|
|
184
|
+
*
|
|
185
|
+
* @template T The expected type of the resolved service
|
|
186
|
+
* @param key The service key to resolve
|
|
187
|
+
* @param context Optional context for contextual resolution
|
|
188
|
+
* @returns The resolved service instance
|
|
189
|
+
* @throws Error if no binding exists for the key
|
|
190
|
+
* @throws Error if circular dependency is detected
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const logger = container.resolve<Logger>('logger');
|
|
195
|
+
* const userRepo = container.resolve('UserRepo', 'UserService');
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
resolve<T>(key: string, context?: string): T;
|
|
199
|
+
/**
|
|
200
|
+
* Resolve a transient instance
|
|
201
|
+
* @private
|
|
202
|
+
*/
|
|
203
|
+
private resolveTransient;
|
|
204
|
+
/**
|
|
205
|
+
* Resolve a singleton instance
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
private resolveSingleton;
|
|
209
|
+
/**
|
|
210
|
+
* Resolve a scoped instance
|
|
211
|
+
* @private
|
|
212
|
+
*/
|
|
213
|
+
private resolveScoped;
|
|
214
|
+
/**
|
|
215
|
+
* Resolve a lazy instance
|
|
216
|
+
* @private
|
|
217
|
+
*/
|
|
218
|
+
private resolveLazy;
|
|
219
|
+
/**
|
|
220
|
+
* Create a contextual binding (different implementations based on context)
|
|
221
|
+
* Provides a fluent API for defining context-specific dependencies
|
|
222
|
+
*
|
|
223
|
+
* @param context The context identifier (usually a service name)
|
|
224
|
+
* @returns A fluent API object with needs() method
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* // UserService will receive MockUserRepo
|
|
229
|
+
* container.when('UserService').needs('UserRepo').give(() => new MockUserRepo());
|
|
230
|
+
*
|
|
231
|
+
* // OrderService will receive RealUserRepo
|
|
232
|
+
* container.when('OrderService').needs('UserRepo').give(() => new RealUserRepo());
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
when(context: string): {
|
|
236
|
+
needs: (depKey: string) => {
|
|
237
|
+
give: (factory: FactoryFn<any>) => void;
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
/**
|
|
241
|
+
* Check if a binding exists for a key
|
|
242
|
+
*
|
|
243
|
+
* @param key The service key to check
|
|
244
|
+
* @returns True if binding exists
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* if (container.has('logger')) {
|
|
249
|
+
* const logger = container.resolve('logger');
|
|
250
|
+
* }
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
has(key: string): boolean;
|
|
254
|
+
/**
|
|
255
|
+
* Get all registered service keys
|
|
256
|
+
*
|
|
257
|
+
* @returns Array of service keys
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```typescript
|
|
261
|
+
* const keys = container.keys();
|
|
262
|
+
* console.log('Registered services:', keys);
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
keys(): string[];
|
|
266
|
+
/**
|
|
267
|
+
* Reset the container to its initial state
|
|
268
|
+
* Clears all bindings, instances, aliases, and context
|
|
269
|
+
* Useful for testing scenarios
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```typescript
|
|
273
|
+
* afterEach(() => {
|
|
274
|
+
* container.reset();
|
|
275
|
+
* });
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
reset(): void;
|
|
279
|
+
/**
|
|
280
|
+
* Dispose the container and all its scoped instances
|
|
281
|
+
*/
|
|
282
|
+
dispose(): Promise<void>;
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=Container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../src/Container.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAEV,WAAW,EACX,SAAS,EACT,SAAS,EACT,SAAS,EACV,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;IACpB,mDAAmD;IACnD,OAAO,CAAC,QAAQ,CAAgC;IAEhD,oCAAoC;IAEpC,OAAO,CAAC,SAAS,CAA0B;IAE3C,0CAA0C;IAC1C,OAAO,CAAC,OAAO,CAA6B;IAE5C,6DAA6D;IAC7D,OAAO,CAAC,YAAY,CAA8B;IAElD,wDAAwD;IACxD,OAAO,CAAC,cAAc,CAAC,CAAS;IAEhC,qCAAqC;IACrC,OAAO,CAAC,MAAM,CAAC,CAAY;IAE3B,2BAA2B;IAC3B,OAAO,CAAC,YAAY,CAAC,CAAQ;IAE7B,yDAAyD;IACzD,OAAO,CAAC,eAAe,CAAgB;IAEvC;;;OAGG;gBACS,MAAM,CAAC,EAAE,SAAS;IAI9B;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,WAAW;IAOnE;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,WAAW;IAOxE;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,SAAS;IAOjE;;;;;;;;;;;;;;;OAeG;IACH,IAAI,CAAC,CAAC,EACJ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EACrB,SAAS,GAAE,SAAuB;IAQpC;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAI3C;;;;;;;;;;;;;;;;;OAiBG;IACH,WAAW,IAAI,SAAS;IAIxB;;;;;;;;;;;;;;;OAeG;IACH,WAAW,IAAI,KAAK;IAMpB;;;;;;;;;;;;;;;OAeG;IACG,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAS1E;;;;;;;;;OASG;IACH,OAAO,CAAC,WAAW;IA0CnB;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC;IA6C5C;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAgBrB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAgBnB;;;;;;;;;;;;;;;OAeG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM;wBAEA,MAAM;4BAEJ,SAAS,CAAC,GAAG,CAAC;;;IAepC;;;;;;;;;;;;OAYG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;;;;;;;;;OAUG;IACH,IAAI,IAAI,MAAM,EAAE;IAMhB;;;;;;;;;;;OAWG;IACH,KAAK;IAUL;;OAEG;IACG,OAAO;CAMd"}
|
|
@@ -0,0 +1,34 @@
|
|
|
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 declare class Lazy<T> {
|
|
21
|
+
private factory;
|
|
22
|
+
private _value?;
|
|
23
|
+
private _initialized;
|
|
24
|
+
constructor(factory: () => T);
|
|
25
|
+
/**
|
|
26
|
+
* Get the lazy value, initializing it if necessary
|
|
27
|
+
*/
|
|
28
|
+
get value(): T;
|
|
29
|
+
/**
|
|
30
|
+
* Check if the lazy value has been initialized
|
|
31
|
+
*/
|
|
32
|
+
get isInitialized(): boolean;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=Lazy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Lazy.d.ts","sourceRoot":"","sources":["../../src/Lazy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AACH,qBAAa,IAAI,CAAC,CAAC;IAIL,OAAO,CAAC,OAAO;IAH3B,OAAO,CAAC,MAAM,CAAC,CAAI;IACnB,OAAO,CAAC,YAAY,CAAS;gBAET,OAAO,EAAE,MAAM,CAAC;IAEpC;;OAEG;IACH,IAAI,KAAK,IAAI,CAAC,CAMb;IAED;;OAEG;IACH,IAAI,aAAa,IAAI,OAAO,CAE3B;CACF"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope management for scoped instances
|
|
3
|
+
*
|
|
4
|
+
* @module Scope
|
|
5
|
+
*/
|
|
6
|
+
import type { DisposeFn } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Scope class for managing scoped instances
|
|
9
|
+
* A scope contains instances that live for a specific duration (e.g., per HTTP request)
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const scope = container.createScope();
|
|
14
|
+
* const conn = container.resolve('dbConnection'); // Scoped instance
|
|
15
|
+
* await scope.dispose(); // Cleanup all scoped resources
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare class Scope {
|
|
19
|
+
private instances;
|
|
20
|
+
private disposables;
|
|
21
|
+
/**
|
|
22
|
+
* Get an instance from this scope
|
|
23
|
+
* @param key The service key
|
|
24
|
+
* @returns The instance or undefined
|
|
25
|
+
*/
|
|
26
|
+
get(key: string): any;
|
|
27
|
+
/**
|
|
28
|
+
* Set an instance in this scope with optional cleanup
|
|
29
|
+
* Auto-detects IDisposable instances
|
|
30
|
+
*
|
|
31
|
+
* @param key The service key
|
|
32
|
+
* @param value The instance to store
|
|
33
|
+
* @param dispose Optional disposal function
|
|
34
|
+
*/
|
|
35
|
+
set(key: string, value: any, dispose?: DisposeFn): void;
|
|
36
|
+
/**
|
|
37
|
+
* Check if instance exists in scope
|
|
38
|
+
* @param key The service key
|
|
39
|
+
* @returns True if the instance exists
|
|
40
|
+
*/
|
|
41
|
+
has(key: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Check if value implements IDisposable interface
|
|
44
|
+
* @private
|
|
45
|
+
* @param value The value to check
|
|
46
|
+
* @returns True if the value is disposable
|
|
47
|
+
*/
|
|
48
|
+
private isDisposable;
|
|
49
|
+
/**
|
|
50
|
+
* Dispose all instances in this scope
|
|
51
|
+
* Calls all registered disposal functions and clears the scope
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* await scope.dispose();
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
dispose(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=Scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Scope.d.ts","sourceRoot":"","sources":["../../src/Scope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,SAAS,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,qBAAa,KAAK;IAEhB,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,WAAW,CAAmB;IAEtC;;;;OAIG;IAEH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG;IAIrB;;;;;;;OAOG;IAEH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;IAahD;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;;;;OAKG;IAEH,OAAO,CAAC,YAAY;IASpB;;;;;;;;OAQG;IACG,OAAO;CAOd"}
|
|
@@ -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 { Container } from './Container';
|
|
31
|
+
export { Lazy } from './Lazy';
|
|
32
|
+
export { Scope } from './Scope';
|
|
33
|
+
export type { Lifecycle, IDisposable, DisposeFn } from './types';
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for Treasure Chest DI Container
|
|
3
|
+
*
|
|
4
|
+
* @module types
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Lifecycle type for service bindings
|
|
8
|
+
*/
|
|
9
|
+
export type Lifecycle = 'transient' | 'singleton' | 'scoped';
|
|
10
|
+
/**
|
|
11
|
+
* Interface for disposable resources
|
|
12
|
+
* Implement this interface to enable auto-cleanup
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* class DbConnection implements IDisposable {
|
|
17
|
+
* async dispose() {
|
|
18
|
+
* await this.close();
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export interface IDisposable {
|
|
24
|
+
dispose(): void | Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Disposal function for cleaning up resources
|
|
28
|
+
*/
|
|
29
|
+
export type DisposeFn = () => void | Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Factory function type that creates instances of type T
|
|
32
|
+
* @template T The type of instance to create
|
|
33
|
+
* @param _c The container instance for resolving dependencies
|
|
34
|
+
* @returns An instance of type T
|
|
35
|
+
*/
|
|
36
|
+
export type FactoryFn<T> = (_c: any) => T;
|
|
37
|
+
/**
|
|
38
|
+
* Condition function type for conditional bindings
|
|
39
|
+
* @param _c The container instance
|
|
40
|
+
* @returns True if the binding should be used
|
|
41
|
+
*/
|
|
42
|
+
export type ConditionFn = (_c: any) => boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Internal binding interface representing a service registration
|
|
45
|
+
* @template T The type of service being bound
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export interface Binding<T = any> {
|
|
49
|
+
/** The service key identifier */
|
|
50
|
+
key: string;
|
|
51
|
+
/** Factory function to create the service instance */
|
|
52
|
+
factory: FactoryFn<T>;
|
|
53
|
+
/** Lifecycle type: transient, singleton, or scoped */
|
|
54
|
+
lifecycle: Lifecycle;
|
|
55
|
+
/** Optional condition for conditional binding */
|
|
56
|
+
condition?: ConditionFn;
|
|
57
|
+
/** Optional context for contextual binding */
|
|
58
|
+
context?: string;
|
|
59
|
+
/** Whether this is a lazy binding */
|
|
60
|
+
lazy?: boolean;
|
|
61
|
+
/** Optional disposal function */
|
|
62
|
+
dispose?: DisposeFn;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE7D;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnD;;;;;GAKG;AAEH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC;AAE1C;;;;GAIG;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC;AAE/C;;;;GAIG;AAEH,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,GAAG;IAC9B,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB,sDAAsD;IACtD,SAAS,EAAE,SAAS,CAAC;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iCAAiC;IACjC,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB"}
|
package/package.json
CHANGED
|
@@ -1,22 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khapu2906/treasure-chest",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "A container
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "A lightweight TypeScript dependency injection container for managing service dependencies",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/types/index.d.ts",
|
|
11
|
+
"import": "./dist/esm/index.js",
|
|
12
|
+
"require": "./dist/cjs/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
7
15
|
"files": [
|
|
8
|
-
"dist"
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
9
19
|
],
|
|
10
20
|
"scripts": {
|
|
11
|
-
"build": "
|
|
12
|
-
"
|
|
21
|
+
"build": "npm run clean && npm run build:cjs && npm run build:esm && npm run build:types",
|
|
22
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
23
|
+
"build:esm": "tsc -p tsconfig.esm.json",
|
|
24
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
25
|
+
"clean": "rm -rf dist",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest",
|
|
13
28
|
"test:ui": "vitest --ui",
|
|
14
|
-
"
|
|
29
|
+
"test:coverage": "vitest run --coverage",
|
|
30
|
+
"bench": "tsx benchmarks/performance.ts",
|
|
31
|
+
"example": "tsx",
|
|
32
|
+
"example:01": "tsx examples/01-basic-usage.ts",
|
|
33
|
+
"example:02": "tsx examples/02-dependency-injection.ts",
|
|
34
|
+
"example:03": "tsx examples/03-conditional-binding.ts",
|
|
35
|
+
"example:04": "tsx examples/04-contextual-binding.ts",
|
|
36
|
+
"example:05": "tsx examples/05-alias.ts",
|
|
37
|
+
"example:06": "tsx examples/06-scoped-lifecycle.ts",
|
|
38
|
+
"example:07": "tsx examples/07-lazy-loading.ts",
|
|
39
|
+
"example:08": "tsx examples/08-child-containers.ts",
|
|
40
|
+
"example:09": "tsx examples/09-circular-dependency.ts",
|
|
41
|
+
"examples": "npm run example:01 && npm run example:02 && npm run example:03 && npm run example:04 && npm run example:05 && npm run example:06 && npm run example:07 && npm run example:08 && npm run example:09",
|
|
42
|
+
"lint": "eslint . --ext .ts",
|
|
43
|
+
"lint:fix": "eslint . --ext .ts --fix",
|
|
44
|
+
"format": "prettier --write \"**/*.{ts,json,md}\"",
|
|
45
|
+
"format:check": "prettier --check \"**/*.{ts,json,md}\"",
|
|
46
|
+
"prepublishOnly": "npm run lint && npm run format:check && npm run build && npm test"
|
|
15
47
|
},
|
|
16
48
|
"keywords": [
|
|
17
49
|
"container",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
50
|
+
"dependency-injection",
|
|
51
|
+
"di",
|
|
52
|
+
"ioc",
|
|
53
|
+
"inversion-of-control",
|
|
54
|
+
"service-container",
|
|
55
|
+
"typescript",
|
|
56
|
+
"singleton",
|
|
57
|
+
"transient",
|
|
58
|
+
"contextual-binding"
|
|
20
59
|
],
|
|
21
60
|
"author": "Kent Phung",
|
|
22
61
|
"license": "DIB",
|
|
@@ -30,10 +69,13 @@
|
|
|
30
69
|
"homepage": "https://github.com/khapu2906/treasure-chest#readme",
|
|
31
70
|
"devDependencies": {
|
|
32
71
|
"@types/node": "^24.10.0",
|
|
33
|
-
"typescript": "^
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
72
|
+
"@typescript-eslint/eslint-plugin": "^8.20.0",
|
|
73
|
+
"@typescript-eslint/parser": "^8.20.0",
|
|
74
|
+
"@vitest/coverage-v8": "^4.0.7",
|
|
75
|
+
"eslint": "^9.17.0",
|
|
76
|
+
"prettier": "^3.4.2",
|
|
77
|
+
"tsx": "^4.19.2",
|
|
78
|
+
"typescript": "^5.9.3",
|
|
79
|
+
"vitest": "^4.0.7"
|
|
38
80
|
}
|
|
39
|
-
}
|
|
81
|
+
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Treasure Chest Service Container in TypeScript
|
|
3
|
-
* Supports:
|
|
4
|
-
* - bind / singleton
|
|
5
|
-
* - conditional binding
|
|
6
|
-
* - contextual binding
|
|
7
|
-
* - alias
|
|
8
|
-
* - resolve
|
|
9
|
-
*/
|
|
10
|
-
type FactoryFn<T> = (c: Container) => T;
|
|
11
|
-
type ConditionFn = (c: Container) => boolean;
|
|
12
|
-
export declare class Container {
|
|
13
|
-
private bindings;
|
|
14
|
-
private instances;
|
|
15
|
-
private aliases;
|
|
16
|
-
private currentContext?;
|
|
17
|
-
/**
|
|
18
|
-
* Bind a dependency (default: transient)
|
|
19
|
-
*/
|
|
20
|
-
bind<T>(key: string, factory: FactoryFn<T>, condition?: ConditionFn): void;
|
|
21
|
-
/**
|
|
22
|
-
* Bind a dependency as singleton (only one instance created)
|
|
23
|
-
*/
|
|
24
|
-
singleton<T>(key: string, factory: FactoryFn<T>, condition?: ConditionFn): void;
|
|
25
|
-
/**
|
|
26
|
-
* Add an alias for an existing key
|
|
27
|
-
*/
|
|
28
|
-
alias(aliasKey: string, originalKey: string): void;
|
|
29
|
-
/**
|
|
30
|
-
* Internal: find correct binding based on key + condition + context
|
|
31
|
-
*/
|
|
32
|
-
private findBinding;
|
|
33
|
-
/**
|
|
34
|
-
* Resolve an instance from the container
|
|
35
|
-
*/
|
|
36
|
-
resolve<T>(key: string, context?: string): T;
|
|
37
|
-
/**
|
|
38
|
-
* Contextual binding:
|
|
39
|
-
* Example:
|
|
40
|
-
* container.when('UserService').needs('UserRepo').give(...)
|
|
41
|
-
*/
|
|
42
|
-
when(context: string): {
|
|
43
|
-
needs: (depKey: string) => {
|
|
44
|
-
give: (factory: FactoryFn<any>) => void;
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Clear all bindings and instances (useful for testing)
|
|
49
|
-
*/
|
|
50
|
-
reset(): void;
|
|
51
|
-
}
|
|
52
|
-
export {};
|
|
53
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,KAAK,CAAC,CAAC;AACxC,KAAK,WAAW,GAAG,CAAC,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC;AAU7C,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,cAAc,CAAC,CAAS;IAEhC;;OAEG;IACH,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,WAAW;IAInE;;OAEG;IACH,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,WAAW;IAIxE;;OAEG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAI3C;;OAEG;IACH,OAAO,CAAC,WAAW;IAsBnB;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC;IA8B5C;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM;wBAEA,MAAM;4BACJ,SAAS,CAAC,GAAG,CAAC;;;IAYpC;;OAEG;IACH,KAAK;CAMN"}
|