getbox 1.1.0 → 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/CONTEXT.md +1 -3
- package/README.md +50 -14
- package/dist/context.d.cts +1 -1
- package/dist/context.d.mts +1 -1
- package/dist/index.cjs +93 -4
- package/dist/index.d.cts +77 -4
- package/dist/index.d.mts +77 -4
- package/dist/index.mjs +91 -4
- package/package.json +1 -1
package/CONTEXT.md
CHANGED
|
@@ -57,9 +57,7 @@ import { Box } from "getbox";
|
|
|
57
57
|
class UserService {
|
|
58
58
|
constructor(private db: Database, private logger: Logger) {}
|
|
59
59
|
|
|
60
|
-
static init
|
|
61
|
-
return box.for(UserService).get(Database, LoggerFactory);
|
|
62
|
-
}
|
|
60
|
+
static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
63
61
|
}
|
|
64
62
|
```
|
|
65
63
|
|
package/README.md
CHANGED
|
@@ -43,10 +43,7 @@ import { Printer } from "./printer";
|
|
|
43
43
|
export class Office {
|
|
44
44
|
constructor(public printer: Printer) {}
|
|
45
45
|
|
|
46
|
-
static init
|
|
47
|
-
const printer = box.get(Printer);
|
|
48
|
-
return new Office(printer);
|
|
49
|
-
}
|
|
46
|
+
static init = Box.init(Office).get(Printer);
|
|
50
47
|
}
|
|
51
48
|
```
|
|
52
49
|
|
|
@@ -125,10 +122,7 @@ import { Logger, LoggerFactory } from "./logger";
|
|
|
125
122
|
export class UserService {
|
|
126
123
|
constructor(private logger: Logger) {}
|
|
127
124
|
|
|
128
|
-
static init
|
|
129
|
-
const logger = box.get(LoggerFactory);
|
|
130
|
-
return new UserService(logger);
|
|
131
|
-
}
|
|
125
|
+
static init = Box.init(UserService).get(LoggerFactory);
|
|
132
126
|
|
|
133
127
|
createUser(name: string) {
|
|
134
128
|
this.logger.log(`Creating user: ${name}`);
|
|
@@ -172,6 +166,23 @@ const ApiUrl = factory((box: Box) => {
|
|
|
172
166
|
const apiUrl = box.get(ApiUrl); // "https://example.com/api"
|
|
173
167
|
```
|
|
174
168
|
|
|
169
|
+
## Transient factories
|
|
170
|
+
|
|
171
|
+
Use the `transient` helper to create a factory whose result is never cached. The factory is called on every resolution, even when retrieved via `box.get()`.
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { Box, transient } from "getbox";
|
|
175
|
+
|
|
176
|
+
const RequestId = transient(() => crypto.randomUUID());
|
|
177
|
+
|
|
178
|
+
const box = new Box();
|
|
179
|
+
|
|
180
|
+
const id1 = box.get(RequestId);
|
|
181
|
+
const id2 = box.get(RequestId);
|
|
182
|
+
|
|
183
|
+
console.log(id1 === id2); // false
|
|
184
|
+
```
|
|
185
|
+
|
|
175
186
|
## Resolving multiple constructors
|
|
176
187
|
|
|
177
188
|
Use `box.all.get()` to resolve multiple constructors at once. Pass an object to get an object of instances, or an array to get an array of instances.
|
|
@@ -202,18 +213,15 @@ console.log(db === db2); // false (transient)
|
|
|
202
213
|
|
|
203
214
|
## Class constructors
|
|
204
215
|
|
|
205
|
-
Use `
|
|
216
|
+
Use `Box.init` to allow resolving classes that have constructor parameters.
|
|
206
217
|
|
|
207
218
|
```ts
|
|
208
|
-
import { Box
|
|
219
|
+
import { Box } from "getbox";
|
|
209
220
|
|
|
210
221
|
class UserService {
|
|
211
222
|
constructor(private db: Database, private logger: Logger) {}
|
|
212
223
|
|
|
213
|
-
static init
|
|
214
|
-
// Create new instance with cached dependencies
|
|
215
|
-
return box.for(UserService).get(Database, LoggerFactory);
|
|
216
|
-
}
|
|
224
|
+
static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
217
225
|
|
|
218
226
|
createUser(name: string) {
|
|
219
227
|
this.logger.log(`Creating user: ${name}`);
|
|
@@ -225,6 +233,34 @@ const service = box.get(UserService);
|
|
|
225
233
|
service.createUser("Alice");
|
|
226
234
|
```
|
|
227
235
|
|
|
236
|
+
`Box.init` is shorthand for writing the `static init` method yourself.
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
class UserService {
|
|
240
|
+
constructor(private db: Database, private logger: Logger) {}
|
|
241
|
+
|
|
242
|
+
static init(box: Box) {
|
|
243
|
+
return new UserService(box.get(Database), box.get(LoggerFactory));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Use `box.for()` when you need custom logic alongside dependency resolution.
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
class UserService {
|
|
252
|
+
constructor(private db: Database, private logger: Logger) {}
|
|
253
|
+
|
|
254
|
+
static init(box: Box) {
|
|
255
|
+
const logger = box.get(LoggerFactory);
|
|
256
|
+
logger.log("Initializing UserService");
|
|
257
|
+
return box.for(UserService).get(Database, LoggerFactory);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Classes with no constructor parameters are resolved automatically without needing `static init`. If `static init` is defined, it takes priority over the default constructor.
|
|
263
|
+
|
|
228
264
|
## Mocking
|
|
229
265
|
|
|
230
266
|
You can mock dependencies for testing using `Box.mock`. This is particularly useful with factories and interfaces.
|
package/dist/context.d.cts
CHANGED
|
@@ -17,7 +17,7 @@ declare function useBox(): Box;
|
|
|
17
17
|
* Resolves a cached instance from the current {@link withBox} scope.
|
|
18
18
|
* Shorthand for `useBox().get(constructor)`.
|
|
19
19
|
*/
|
|
20
|
-
declare function resolve<T
|
|
20
|
+
declare function resolve<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
21
21
|
/**
|
|
22
22
|
* Resolves multiple cached instances from the current {@link withBox} scope.
|
|
23
23
|
* Shorthand for `useBox().all.get(constructors)`.
|
package/dist/context.d.mts
CHANGED
|
@@ -17,7 +17,7 @@ declare function useBox(): Box;
|
|
|
17
17
|
* Resolves a cached instance from the current {@link withBox} scope.
|
|
18
18
|
* Shorthand for `useBox().get(constructor)`.
|
|
19
19
|
*/
|
|
20
|
-
declare function resolve<T
|
|
20
|
+
declare function resolve<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
21
21
|
/**
|
|
22
22
|
* Resolves multiple cached instances from the current {@link withBox} scope.
|
|
23
23
|
* Shorthand for `useBox().all.get(constructors)`.
|
package/dist/index.cjs
CHANGED
|
@@ -16,7 +16,26 @@
|
|
|
16
16
|
function factory(init) {
|
|
17
17
|
return { init };
|
|
18
18
|
}
|
|
19
|
-
const
|
|
19
|
+
const noCacheSymbol = Symbol("Box.noCache");
|
|
20
|
+
/**
|
|
21
|
+
* Creates a {@link Constructor} from a factory function whose result is never cached.
|
|
22
|
+
* The factory is called on every resolution, always returning a fresh value
|
|
23
|
+
* even when retrieved via {@link Box.get}.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const RequestId = transient(() => crypto.randomUUID());
|
|
28
|
+
* const id1 = box.get(RequestId);
|
|
29
|
+
* const id2 = box.get(RequestId);
|
|
30
|
+
* console.log(id1 === id2); // false
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function transient(init) {
|
|
34
|
+
return {
|
|
35
|
+
init,
|
|
36
|
+
[noCacheSymbol]: true
|
|
37
|
+
};
|
|
38
|
+
}
|
|
20
39
|
/**
|
|
21
40
|
* Creates a {@link Constructor} that always resolves to the given constant value.
|
|
22
41
|
* Constant values are never cached since they are already fixed.
|
|
@@ -30,7 +49,7 @@ const constantSymbol = Symbol("Box constant");
|
|
|
30
49
|
function constant(value) {
|
|
31
50
|
return {
|
|
32
51
|
init: () => value,
|
|
33
|
-
[
|
|
52
|
+
[noCacheSymbol]: true
|
|
34
53
|
};
|
|
35
54
|
}
|
|
36
55
|
/**
|
|
@@ -79,7 +98,7 @@ var Box = class {
|
|
|
79
98
|
get(constructor) {
|
|
80
99
|
if (this.cache.has(constructor)) return this.cache.get(constructor);
|
|
81
100
|
const value = this.new(constructor);
|
|
82
|
-
if (!(
|
|
101
|
+
if (!(noCacheSymbol in constructor && constructor[noCacheSymbol])) this.cache.set(constructor, value);
|
|
83
102
|
return value;
|
|
84
103
|
}
|
|
85
104
|
/** Resolves multiple constructors at once. */
|
|
@@ -96,6 +115,21 @@ var Box = class {
|
|
|
96
115
|
return new Construct(this, constructor);
|
|
97
116
|
}
|
|
98
117
|
/**
|
|
118
|
+
* Returns a {@link StaticConstruct} builder for defining a `static init` method.
|
|
119
|
+
* The result can be assigned directly to `static init`.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```ts
|
|
123
|
+
* class UserService {
|
|
124
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
125
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
126
|
+
* }
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
static init(constructor) {
|
|
130
|
+
return new StaticConstruct(constructor);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
99
133
|
* Registers a mock value in the box's cache for a given constructor.
|
|
100
134
|
* Useful for replacing dependencies in tests.
|
|
101
135
|
*/
|
|
@@ -178,9 +212,64 @@ var Construct = class {
|
|
|
178
212
|
return new this.construct(...instances);
|
|
179
213
|
}
|
|
180
214
|
};
|
|
215
|
+
/**
|
|
216
|
+
* Builder for creating a `static init` function with constructor dependencies
|
|
217
|
+
* resolved from a {@link Box}.
|
|
218
|
+
*/
|
|
219
|
+
var StaticConstruct = class {
|
|
220
|
+
constructor(construct) {
|
|
221
|
+
this.construct = construct;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Resolves each dependency as a new transient instance via {@link Box.new},
|
|
225
|
+
* meaning dependencies are not cached or shared.
|
|
226
|
+
* Returns a function compatible with `static init` that can be assigned directly.
|
|
227
|
+
*
|
|
228
|
+
* The returned instance is cached or transient depending on whether the
|
|
229
|
+
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```ts
|
|
233
|
+
* class UserService {
|
|
234
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
235
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
236
|
+
* }
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
new(...args) {
|
|
240
|
+
return (box) => {
|
|
241
|
+
const instances = args.map((arg) => box.new(arg));
|
|
242
|
+
return new this.construct(...instances);
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Resolves each dependency as a cached instance via {@link Box.get},
|
|
247
|
+
* meaning dependencies are shared across the box.
|
|
248
|
+
* Returns a function compatible with `static init` that can be assigned directly.
|
|
249
|
+
*
|
|
250
|
+
* The returned instance is cached or transient depending on whether the
|
|
251
|
+
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* class UserService {
|
|
256
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
257
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
258
|
+
* }
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
get(...args) {
|
|
262
|
+
return (box) => {
|
|
263
|
+
const instances = args.map((arg) => box.get(arg));
|
|
264
|
+
return new this.construct(...instances);
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
};
|
|
181
268
|
|
|
182
269
|
//#endregion
|
|
183
270
|
exports.Box = Box;
|
|
184
271
|
exports.Construct = Construct;
|
|
272
|
+
exports.StaticConstruct = StaticConstruct;
|
|
185
273
|
exports.constant = constant;
|
|
186
|
-
exports.factory = factory;
|
|
274
|
+
exports.factory = factory;
|
|
275
|
+
exports.transient = transient;
|
package/dist/index.d.cts
CHANGED
|
@@ -10,7 +10,11 @@ type Constructor<T> = {
|
|
|
10
10
|
new (): T;
|
|
11
11
|
};
|
|
12
12
|
/** Extracts the instance type from a {@link Constructor}. */
|
|
13
|
-
type ConstructorInstanceType<T> = T extends
|
|
13
|
+
type ConstructorInstanceType<T> = T extends {
|
|
14
|
+
init(box: Box): infer U;
|
|
15
|
+
} ? U : T extends {
|
|
16
|
+
new (): infer U;
|
|
17
|
+
} ? U : never;
|
|
14
18
|
/**
|
|
15
19
|
* Creates a {@link Constructor} from a factory function.
|
|
16
20
|
* The factory receives the box as an argument, allowing it to resolve other dependencies.
|
|
@@ -25,6 +29,20 @@ type ConstructorInstanceType<T> = T extends Constructor<infer U> ? U : never;
|
|
|
25
29
|
* ```
|
|
26
30
|
*/
|
|
27
31
|
declare function factory<T>(init: (box: Box) => T): Constructor<T>;
|
|
32
|
+
/**
|
|
33
|
+
* Creates a {@link Constructor} from a factory function whose result is never cached.
|
|
34
|
+
* The factory is called on every resolution, always returning a fresh value
|
|
35
|
+
* even when retrieved via {@link Box.get}.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* const RequestId = transient(() => crypto.randomUUID());
|
|
40
|
+
* const id1 = box.get(RequestId);
|
|
41
|
+
* const id2 = box.get(RequestId);
|
|
42
|
+
* console.log(id1 === id2); // false
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare function transient<T>(init: (box: Box) => T): Constructor<T>;
|
|
28
46
|
/**
|
|
29
47
|
* Creates a {@link Constructor} that always resolves to the given constant value.
|
|
30
48
|
* Constant values are never cached since they are already fixed.
|
|
@@ -72,12 +90,12 @@ declare class Box {
|
|
|
72
90
|
* Creates a new (transient) instance without caching. Useful for instances
|
|
73
91
|
* that should not be shared.
|
|
74
92
|
*/
|
|
75
|
-
new<T
|
|
93
|
+
new<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
76
94
|
/**
|
|
77
95
|
* Resolves an instance from the cache, or creates and caches a new one.
|
|
78
96
|
* Subsequent calls with the same constructor return the cached instance.
|
|
79
97
|
*/
|
|
80
|
-
get<T
|
|
98
|
+
get<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
81
99
|
/** Resolves multiple constructors at once. */
|
|
82
100
|
readonly all: BoxAll;
|
|
83
101
|
/**
|
|
@@ -89,6 +107,19 @@ declare class Box {
|
|
|
89
107
|
* the class is retrieved via {@link Box.get} or kept transient via {@link Box.new}.
|
|
90
108
|
*/
|
|
91
109
|
for<T extends ClassConstructor<any>>(constructor: T): Construct<T>;
|
|
110
|
+
/**
|
|
111
|
+
* Returns a {@link StaticConstruct} builder for defining a `static init` method.
|
|
112
|
+
* The result can be assigned directly to `static init`.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* class UserService {
|
|
117
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
118
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
119
|
+
* }
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
static init<T extends ClassConstructor<any>>(constructor: T): StaticConstruct<T>;
|
|
92
123
|
/**
|
|
93
124
|
* Registers a mock value in the box's cache for a given constructor.
|
|
94
125
|
* Useful for replacing dependencies in tests.
|
|
@@ -159,6 +190,48 @@ declare class Construct<T extends ClassConstructor<any>> {
|
|
|
159
190
|
*/
|
|
160
191
|
get(...args: ClassConstructorArgs<T>): InstanceType<T>;
|
|
161
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Builder for creating a `static init` function with constructor dependencies
|
|
195
|
+
* resolved from a {@link Box}.
|
|
196
|
+
*/
|
|
197
|
+
declare class StaticConstruct<T extends ClassConstructor<any>> {
|
|
198
|
+
private construct;
|
|
199
|
+
constructor(construct: T);
|
|
200
|
+
/**
|
|
201
|
+
* Resolves each dependency as a new transient instance via {@link Box.new},
|
|
202
|
+
* meaning dependencies are not cached or shared.
|
|
203
|
+
* Returns a function compatible with `static init` that can be assigned directly.
|
|
204
|
+
*
|
|
205
|
+
* The returned instance is cached or transient depending on whether the
|
|
206
|
+
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* class UserService {
|
|
211
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
212
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
213
|
+
* }
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
new(...args: ClassConstructorArgs<T>): (box: Box) => InstanceType<T>;
|
|
217
|
+
/**
|
|
218
|
+
* Resolves each dependency as a cached instance via {@link Box.get},
|
|
219
|
+
* meaning dependencies are shared across the box.
|
|
220
|
+
* Returns a function compatible with `static init` that can be assigned directly.
|
|
221
|
+
*
|
|
222
|
+
* The returned instance is cached or transient depending on whether the
|
|
223
|
+
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```ts
|
|
227
|
+
* class UserService {
|
|
228
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
229
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
230
|
+
* }
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
get(...args: ClassConstructorArgs<T>): (box: Box) => InstanceType<T>;
|
|
234
|
+
}
|
|
162
235
|
/** A class with any constructor signature. */
|
|
163
236
|
type ClassConstructor<T> = {
|
|
164
237
|
new (...args: any): T;
|
|
@@ -166,4 +239,4 @@ type ClassConstructor<T> = {
|
|
|
166
239
|
/** Maps each constructor parameter to its corresponding {@link Constructor} type. */
|
|
167
240
|
type ClassConstructorArgs<T extends ClassConstructor<any>, Args = ConstructorParameters<T>> = { [K in keyof Args]: Constructor<Args[K]> };
|
|
168
241
|
//#endregion
|
|
169
|
-
export { Box, Construct, Constructor, ConstructorInstanceType, constant, factory };
|
|
242
|
+
export { Box, Construct, Constructor, ConstructorInstanceType, StaticConstruct, constant, factory, transient };
|
package/dist/index.d.mts
CHANGED
|
@@ -10,7 +10,11 @@ type Constructor<T> = {
|
|
|
10
10
|
new (): T;
|
|
11
11
|
};
|
|
12
12
|
/** Extracts the instance type from a {@link Constructor}. */
|
|
13
|
-
type ConstructorInstanceType<T> = T extends
|
|
13
|
+
type ConstructorInstanceType<T> = T extends {
|
|
14
|
+
init(box: Box): infer U;
|
|
15
|
+
} ? U : T extends {
|
|
16
|
+
new (): infer U;
|
|
17
|
+
} ? U : never;
|
|
14
18
|
/**
|
|
15
19
|
* Creates a {@link Constructor} from a factory function.
|
|
16
20
|
* The factory receives the box as an argument, allowing it to resolve other dependencies.
|
|
@@ -25,6 +29,20 @@ type ConstructorInstanceType<T> = T extends Constructor<infer U> ? U : never;
|
|
|
25
29
|
* ```
|
|
26
30
|
*/
|
|
27
31
|
declare function factory<T>(init: (box: Box) => T): Constructor<T>;
|
|
32
|
+
/**
|
|
33
|
+
* Creates a {@link Constructor} from a factory function whose result is never cached.
|
|
34
|
+
* The factory is called on every resolution, always returning a fresh value
|
|
35
|
+
* even when retrieved via {@link Box.get}.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* const RequestId = transient(() => crypto.randomUUID());
|
|
40
|
+
* const id1 = box.get(RequestId);
|
|
41
|
+
* const id2 = box.get(RequestId);
|
|
42
|
+
* console.log(id1 === id2); // false
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare function transient<T>(init: (box: Box) => T): Constructor<T>;
|
|
28
46
|
/**
|
|
29
47
|
* Creates a {@link Constructor} that always resolves to the given constant value.
|
|
30
48
|
* Constant values are never cached since they are already fixed.
|
|
@@ -72,12 +90,12 @@ declare class Box {
|
|
|
72
90
|
* Creates a new (transient) instance without caching. Useful for instances
|
|
73
91
|
* that should not be shared.
|
|
74
92
|
*/
|
|
75
|
-
new<T
|
|
93
|
+
new<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
76
94
|
/**
|
|
77
95
|
* Resolves an instance from the cache, or creates and caches a new one.
|
|
78
96
|
* Subsequent calls with the same constructor return the cached instance.
|
|
79
97
|
*/
|
|
80
|
-
get<T
|
|
98
|
+
get<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
81
99
|
/** Resolves multiple constructors at once. */
|
|
82
100
|
readonly all: BoxAll;
|
|
83
101
|
/**
|
|
@@ -89,6 +107,19 @@ declare class Box {
|
|
|
89
107
|
* the class is retrieved via {@link Box.get} or kept transient via {@link Box.new}.
|
|
90
108
|
*/
|
|
91
109
|
for<T extends ClassConstructor<any>>(constructor: T): Construct<T>;
|
|
110
|
+
/**
|
|
111
|
+
* Returns a {@link StaticConstruct} builder for defining a `static init` method.
|
|
112
|
+
* The result can be assigned directly to `static init`.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* class UserService {
|
|
117
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
118
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
119
|
+
* }
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
static init<T extends ClassConstructor<any>>(constructor: T): StaticConstruct<T>;
|
|
92
123
|
/**
|
|
93
124
|
* Registers a mock value in the box's cache for a given constructor.
|
|
94
125
|
* Useful for replacing dependencies in tests.
|
|
@@ -159,6 +190,48 @@ declare class Construct<T extends ClassConstructor<any>> {
|
|
|
159
190
|
*/
|
|
160
191
|
get(...args: ClassConstructorArgs<T>): InstanceType<T>;
|
|
161
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Builder for creating a `static init` function with constructor dependencies
|
|
195
|
+
* resolved from a {@link Box}.
|
|
196
|
+
*/
|
|
197
|
+
declare class StaticConstruct<T extends ClassConstructor<any>> {
|
|
198
|
+
private construct;
|
|
199
|
+
constructor(construct: T);
|
|
200
|
+
/**
|
|
201
|
+
* Resolves each dependency as a new transient instance via {@link Box.new},
|
|
202
|
+
* meaning dependencies are not cached or shared.
|
|
203
|
+
* Returns a function compatible with `static init` that can be assigned directly.
|
|
204
|
+
*
|
|
205
|
+
* The returned instance is cached or transient depending on whether the
|
|
206
|
+
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* class UserService {
|
|
211
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
212
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
213
|
+
* }
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
new(...args: ClassConstructorArgs<T>): (box: Box) => InstanceType<T>;
|
|
217
|
+
/**
|
|
218
|
+
* Resolves each dependency as a cached instance via {@link Box.get},
|
|
219
|
+
* meaning dependencies are shared across the box.
|
|
220
|
+
* Returns a function compatible with `static init` that can be assigned directly.
|
|
221
|
+
*
|
|
222
|
+
* The returned instance is cached or transient depending on whether the
|
|
223
|
+
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```ts
|
|
227
|
+
* class UserService {
|
|
228
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
229
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
230
|
+
* }
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
get(...args: ClassConstructorArgs<T>): (box: Box) => InstanceType<T>;
|
|
234
|
+
}
|
|
162
235
|
/** A class with any constructor signature. */
|
|
163
236
|
type ClassConstructor<T> = {
|
|
164
237
|
new (...args: any): T;
|
|
@@ -166,4 +239,4 @@ type ClassConstructor<T> = {
|
|
|
166
239
|
/** Maps each constructor parameter to its corresponding {@link Constructor} type. */
|
|
167
240
|
type ClassConstructorArgs<T extends ClassConstructor<any>, Args = ConstructorParameters<T>> = { [K in keyof Args]: Constructor<Args[K]> };
|
|
168
241
|
//#endregion
|
|
169
|
-
export { Box, Construct, Constructor, ConstructorInstanceType, constant, factory };
|
|
242
|
+
export { Box, Construct, Constructor, ConstructorInstanceType, StaticConstruct, constant, factory, transient };
|
package/dist/index.mjs
CHANGED
|
@@ -15,7 +15,26 @@
|
|
|
15
15
|
function factory(init) {
|
|
16
16
|
return { init };
|
|
17
17
|
}
|
|
18
|
-
const
|
|
18
|
+
const noCacheSymbol = Symbol("Box.noCache");
|
|
19
|
+
/**
|
|
20
|
+
* Creates a {@link Constructor} from a factory function whose result is never cached.
|
|
21
|
+
* The factory is called on every resolution, always returning a fresh value
|
|
22
|
+
* even when retrieved via {@link Box.get}.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const RequestId = transient(() => crypto.randomUUID());
|
|
27
|
+
* const id1 = box.get(RequestId);
|
|
28
|
+
* const id2 = box.get(RequestId);
|
|
29
|
+
* console.log(id1 === id2); // false
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
function transient(init) {
|
|
33
|
+
return {
|
|
34
|
+
init,
|
|
35
|
+
[noCacheSymbol]: true
|
|
36
|
+
};
|
|
37
|
+
}
|
|
19
38
|
/**
|
|
20
39
|
* Creates a {@link Constructor} that always resolves to the given constant value.
|
|
21
40
|
* Constant values are never cached since they are already fixed.
|
|
@@ -29,7 +48,7 @@ const constantSymbol = Symbol("Box constant");
|
|
|
29
48
|
function constant(value) {
|
|
30
49
|
return {
|
|
31
50
|
init: () => value,
|
|
32
|
-
[
|
|
51
|
+
[noCacheSymbol]: true
|
|
33
52
|
};
|
|
34
53
|
}
|
|
35
54
|
/**
|
|
@@ -78,7 +97,7 @@ var Box = class {
|
|
|
78
97
|
get(constructor) {
|
|
79
98
|
if (this.cache.has(constructor)) return this.cache.get(constructor);
|
|
80
99
|
const value = this.new(constructor);
|
|
81
|
-
if (!(
|
|
100
|
+
if (!(noCacheSymbol in constructor && constructor[noCacheSymbol])) this.cache.set(constructor, value);
|
|
82
101
|
return value;
|
|
83
102
|
}
|
|
84
103
|
/** Resolves multiple constructors at once. */
|
|
@@ -95,6 +114,21 @@ var Box = class {
|
|
|
95
114
|
return new Construct(this, constructor);
|
|
96
115
|
}
|
|
97
116
|
/**
|
|
117
|
+
* Returns a {@link StaticConstruct} builder for defining a `static init` method.
|
|
118
|
+
* The result can be assigned directly to `static init`.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* class UserService {
|
|
123
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
124
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
125
|
+
* }
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
static init(constructor) {
|
|
129
|
+
return new StaticConstruct(constructor);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
98
132
|
* Registers a mock value in the box's cache for a given constructor.
|
|
99
133
|
* Useful for replacing dependencies in tests.
|
|
100
134
|
*/
|
|
@@ -177,6 +211,59 @@ var Construct = class {
|
|
|
177
211
|
return new this.construct(...instances);
|
|
178
212
|
}
|
|
179
213
|
};
|
|
214
|
+
/**
|
|
215
|
+
* Builder for creating a `static init` function with constructor dependencies
|
|
216
|
+
* resolved from a {@link Box}.
|
|
217
|
+
*/
|
|
218
|
+
var StaticConstruct = class {
|
|
219
|
+
constructor(construct) {
|
|
220
|
+
this.construct = construct;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Resolves each dependency as a new transient instance via {@link Box.new},
|
|
224
|
+
* meaning dependencies are not cached or shared.
|
|
225
|
+
* Returns a function compatible with `static init` that can be assigned directly.
|
|
226
|
+
*
|
|
227
|
+
* The returned instance is cached or transient depending on whether the
|
|
228
|
+
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```ts
|
|
232
|
+
* class UserService {
|
|
233
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
234
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
235
|
+
* }
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
new(...args) {
|
|
239
|
+
return (box) => {
|
|
240
|
+
const instances = args.map((arg) => box.new(arg));
|
|
241
|
+
return new this.construct(...instances);
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Resolves each dependency as a cached instance via {@link Box.get},
|
|
246
|
+
* meaning dependencies are shared across the box.
|
|
247
|
+
* Returns a function compatible with `static init` that can be assigned directly.
|
|
248
|
+
*
|
|
249
|
+
* The returned instance is cached or transient depending on whether the
|
|
250
|
+
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* class UserService {
|
|
255
|
+
* constructor(private db: Database, private logger: Logger) {}
|
|
256
|
+
* static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
257
|
+
* }
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
get(...args) {
|
|
261
|
+
return (box) => {
|
|
262
|
+
const instances = args.map((arg) => box.get(arg));
|
|
263
|
+
return new this.construct(...instances);
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
};
|
|
180
267
|
|
|
181
268
|
//#endregion
|
|
182
|
-
export { Box, Construct, constant, factory };
|
|
269
|
+
export { Box, Construct, StaticConstruct, constant, factory, transient };
|