getbox 1.4.0 → 2.1.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 +5 -5
- package/README.md +52 -35
- package/dist/context.cjs +8 -37
- package/dist/context.d.cts +13 -30
- package/dist/context.d.mts +13 -30
- package/dist/context.mjs +8 -33
- package/dist/index.cjs +99 -150
- package/dist/index.d.cts +70 -113
- package/dist/index.d.mts +70 -113
- package/dist/index.mjs +95 -146
- package/package.json +1 -1
package/CONTEXT.md
CHANGED
|
@@ -63,15 +63,15 @@ class UserService {
|
|
|
63
63
|
|
|
64
64
|
## Resolving multiple dependencies
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
Pass an array or object of constructors to `inject` to resolve multiple at once.
|
|
67
67
|
|
|
68
68
|
```ts
|
|
69
69
|
withBox(() => {
|
|
70
70
|
// Object form
|
|
71
|
-
const { db, logger } =
|
|
71
|
+
const { db, logger } = inject({ db: Database, logger: LoggerFactory });
|
|
72
72
|
|
|
73
73
|
// Array form
|
|
74
|
-
const [db2, logger2] =
|
|
74
|
+
const [db2, logger2] = inject([Database, LoggerFactory]);
|
|
75
75
|
|
|
76
76
|
console.log(db === db2); // true (cached)
|
|
77
77
|
console.log(logger === logger2); // true (cached)
|
|
@@ -80,11 +80,11 @@ withBox(() => {
|
|
|
80
80
|
|
|
81
81
|
## Accessing the box
|
|
82
82
|
|
|
83
|
-
Use `
|
|
83
|
+
Use `getBox()` to get the current box from the scope. This is useful when you need full access to the box API.
|
|
84
84
|
|
|
85
85
|
```ts
|
|
86
86
|
withBox(() => {
|
|
87
|
-
const box =
|
|
87
|
+
const box = getBox();
|
|
88
88
|
const db = box.new(Database);
|
|
89
89
|
});
|
|
90
90
|
```
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npm install getbox
|
|
|
14
14
|
|
|
15
15
|
## Usage
|
|
16
16
|
|
|
17
|
-
`getbox` has a very small API surface. You typically only need `box.get()` and optionally `
|
|
17
|
+
`getbox` has a very small API surface. You typically only need `box.get()` and optionally `Box.init()` or the `factory` helper.
|
|
18
18
|
|
|
19
19
|
For an alternative pattern using AsyncLocalStorage where classes can resolve dependencies directly, see [getbox/context](./CONTEXT.md).
|
|
20
20
|
|
|
@@ -49,7 +49,7 @@ console.log(office.printer === printer); // true
|
|
|
49
49
|
|
|
50
50
|
## Constructors
|
|
51
51
|
|
|
52
|
-
Constructors define what the box resolves. `getbox` supports classes, factories,
|
|
52
|
+
Constructors define what the box resolves. `getbox` supports classes, factories, computed values, and constants. Because constructors act as interfaces, the underlying implementation can change without affecting any consumer.
|
|
53
53
|
|
|
54
54
|
### Classes
|
|
55
55
|
|
|
@@ -73,33 +73,35 @@ const service = box.get(UserService);
|
|
|
73
73
|
service.createUser("Alice");
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
`Box.
|
|
76
|
+
Use `Box.fn` to write the initializer manually when you need more control.
|
|
77
77
|
|
|
78
78
|
```ts
|
|
79
79
|
class UserService {
|
|
80
80
|
constructor(private db: Database, private logger: Logger) {}
|
|
81
81
|
|
|
82
|
-
static init(box
|
|
82
|
+
static init = Box.fn((box) => {
|
|
83
83
|
return new UserService(box.get(Database), box.get(LoggerFactory));
|
|
84
|
-
}
|
|
84
|
+
});
|
|
85
85
|
}
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
If a `static init` initializer is defined, it takes priority over the class constructor.
|
|
89
|
+
|
|
90
|
+
Set `static [boxCache] = false` to opt a class out of caching. The box will call the initializer on every `box.get()` instead of returning a cached instance.
|
|
89
91
|
|
|
90
92
|
```ts
|
|
91
|
-
|
|
92
|
-
constructor(private db: Database, private logger: Logger) {}
|
|
93
|
+
import { Box, boxCache } from "getbox";
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return box.for(UserService).get(Database, LoggerFactory);
|
|
98
|
-
}
|
|
95
|
+
class RequestContext {
|
|
96
|
+
timestamp = Date.now();
|
|
97
|
+
static [boxCache] = false;
|
|
99
98
|
}
|
|
100
|
-
```
|
|
101
99
|
|
|
102
|
-
|
|
100
|
+
const box = new Box();
|
|
101
|
+
const ctx1 = box.get(RequestContext);
|
|
102
|
+
const ctx2 = box.get(RequestContext);
|
|
103
|
+
console.log(ctx1 === ctx2); // false
|
|
104
|
+
```
|
|
103
105
|
|
|
104
106
|
### Factory functions
|
|
105
107
|
|
|
@@ -112,13 +114,11 @@ interface Logger {
|
|
|
112
114
|
log(message: string): void;
|
|
113
115
|
}
|
|
114
116
|
|
|
115
|
-
const LoggerFactory = factory(
|
|
116
|
-
(
|
|
117
|
-
log(message
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}),
|
|
121
|
-
);
|
|
117
|
+
const LoggerFactory = factory<Logger>(() => ({
|
|
118
|
+
log(message: string) {
|
|
119
|
+
console.log(`[LOG] ${message}`);
|
|
120
|
+
},
|
|
121
|
+
}));
|
|
122
122
|
|
|
123
123
|
const box = new Box();
|
|
124
124
|
const logger = box.get(LoggerFactory);
|
|
@@ -126,18 +126,18 @@ const logger = box.get(LoggerFactory);
|
|
|
126
126
|
logger.log("hello world");
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
###
|
|
129
|
+
### Computed values
|
|
130
130
|
|
|
131
|
-
Use the `
|
|
131
|
+
Use the `computed` helper to compute a value from the box without caching the result.
|
|
132
132
|
|
|
133
133
|
```ts
|
|
134
|
-
import { Box,
|
|
134
|
+
import { Box, computed } from "getbox";
|
|
135
135
|
|
|
136
136
|
class Config {
|
|
137
137
|
baseUrl = "https://example.com";
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
const RequestContext =
|
|
140
|
+
const RequestContext = computed((box) => ({
|
|
141
141
|
baseUrl: box.get(Config).baseUrl,
|
|
142
142
|
timestamp: Date.now(),
|
|
143
143
|
}));
|
|
@@ -152,7 +152,7 @@ console.log(ctx1 === ctx2); // false
|
|
|
152
152
|
|
|
153
153
|
### Constants
|
|
154
154
|
|
|
155
|
-
Use the `constant` helper to wrap a fixed value as a constructor. Constant values are
|
|
155
|
+
Use the `constant` helper to wrap a fixed value as a constructor. Constant values are already fixed and do not need caching.
|
|
156
156
|
|
|
157
157
|
```ts
|
|
158
158
|
import { Box, constant } from "getbox";
|
|
@@ -195,21 +195,34 @@ const db4 = box.new(Database);
|
|
|
195
195
|
console.log(db3 === db4); // false (never cached)
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
-
|
|
198
|
+
Both `box.get()` and `box.new()` also accept an array or object of constructors to resolve multiple at once.
|
|
199
199
|
|
|
200
200
|
```ts
|
|
201
201
|
const box = new Box();
|
|
202
202
|
|
|
203
203
|
// Cached
|
|
204
|
-
const { db, logger } = box.
|
|
205
|
-
const [db2, logger2] = box.
|
|
204
|
+
const { db, logger } = box.get({ db: Database, logger: LoggerFactory });
|
|
205
|
+
const [db2, logger2] = box.get([Database, LoggerFactory]);
|
|
206
206
|
|
|
207
207
|
// New instances
|
|
208
|
-
const { db3 } = box.
|
|
209
|
-
const [db4] = box.
|
|
208
|
+
const { db3 } = box.new({ db3: Database });
|
|
209
|
+
const [db4] = box.new([Database]);
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
> `box.get()` does not cache `
|
|
212
|
+
> `box.get()` does not cache `computed` or `constant` values.
|
|
213
|
+
|
|
214
|
+
`Box` itself can be resolved as a dependency. `box.get(Box)` returns the current box instance.
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
class ServiceLocator {
|
|
218
|
+
constructor(private box: Box) {}
|
|
219
|
+
static init = Box.init(ServiceLocator).get(Box);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const box = new Box();
|
|
223
|
+
const locator = box.get(ServiceLocator);
|
|
224
|
+
console.log(locator.box === box); // true
|
|
225
|
+
```
|
|
213
226
|
|
|
214
227
|
## Mocking
|
|
215
228
|
|
|
@@ -243,17 +256,21 @@ console.log(mockLogger.messages); // ["Creating user: Alice"]
|
|
|
243
256
|
|
|
244
257
|
Use `Box.clear` to remove cached instances. Pass a specific constructor to clear a single entry, or omit it to clear all cached instances.
|
|
245
258
|
|
|
259
|
+
Returns `true` if an instance was removed, `false` otherwise.
|
|
260
|
+
|
|
246
261
|
```ts
|
|
247
262
|
const box = new Box();
|
|
248
263
|
|
|
249
264
|
const db = box.get(Database);
|
|
250
265
|
|
|
251
266
|
// Clear a specific constructor
|
|
252
|
-
Box.clear(box, Database);
|
|
267
|
+
const cleared = Box.clear(box, Database);
|
|
268
|
+
console.log(cleared);
|
|
253
269
|
console.log(box.get(Database) === db); // false (new instance)
|
|
254
270
|
|
|
255
271
|
// Clear all cached instances
|
|
256
|
-
Box.clear(box);
|
|
272
|
+
const clearedAll = Box.clear(box);
|
|
273
|
+
console.log(clearedAll);
|
|
257
274
|
```
|
|
258
275
|
|
|
259
276
|
## Circular dependencies
|
package/dist/context.cjs
CHANGED
|
@@ -8,48 +8,19 @@ function withBox(boxOrFn, fn) {
|
|
|
8
8
|
return storage.run(boxOrFn, fn);
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Returns the current
|
|
12
|
-
* Throws if called outside a scope.
|
|
11
|
+
* Returns the current Box from the active Box scope.
|
|
12
|
+
* Throws if called outside a Box scope.
|
|
13
13
|
*/
|
|
14
|
-
function
|
|
14
|
+
function getBox() {
|
|
15
15
|
const box = storage.getStore();
|
|
16
|
-
if (
|
|
17
|
-
|
|
16
|
+
if (box) return box;
|
|
17
|
+
throw new Error("getBox() must be called within a withBox() scope");
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* Shorthand for `useBox().get(constructor)`.
|
|
22
|
-
*/
|
|
23
|
-
function inject(constructor) {
|
|
24
|
-
return useBox().get(constructor);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* @deprecated Use {@link inject} instead.
|
|
28
|
-
*/
|
|
29
|
-
function resolve(constructor) {
|
|
30
|
-
return inject(constructor);
|
|
31
|
-
}
|
|
32
|
-
function injectAll(constructors) {
|
|
33
|
-
return useBox().all.get(constructors);
|
|
34
|
-
}
|
|
35
|
-
function resolveAll(constructors) {
|
|
36
|
-
return injectAll(constructors);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Returns a builder for creating a class instance with resolved constructor
|
|
40
|
-
* parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
|
|
41
|
-
*
|
|
42
|
-
* @deprecated
|
|
43
|
-
*/
|
|
44
|
-
function construct(constructor) {
|
|
45
|
-
return useBox().for(constructor);
|
|
19
|
+
function inject(arg) {
|
|
20
|
+
return getBox().get(arg);
|
|
46
21
|
}
|
|
47
22
|
|
|
48
23
|
//#endregion
|
|
49
|
-
exports.
|
|
24
|
+
exports.getBox = getBox;
|
|
50
25
|
exports.inject = inject;
|
|
51
|
-
exports.injectAll = injectAll;
|
|
52
|
-
exports.resolve = resolve;
|
|
53
|
-
exports.resolveAll = resolveAll;
|
|
54
|
-
exports.useBox = useBox;
|
|
55
26
|
exports.withBox = withBox;
|
package/dist/context.d.cts
CHANGED
|
@@ -1,44 +1,27 @@
|
|
|
1
|
-
import { Box,
|
|
1
|
+
import { Box, Constructor, ConstructorInstanceType } from "./index.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/context.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Runs a function within a
|
|
6
|
+
* Runs a function within a Box scope using AsyncLocalStorage.
|
|
7
7
|
* Creates a new Box if none is provided.
|
|
8
|
+
*
|
|
9
|
+
* If the callback function throws an error, the error is thrown by withBox too.
|
|
8
10
|
*/
|
|
9
11
|
declare function withBox<T>(fn: () => T): T;
|
|
10
12
|
declare function withBox<T>(box: Box, fn: () => T): T;
|
|
11
13
|
/**
|
|
12
|
-
* Returns the current
|
|
13
|
-
* Throws if called outside a scope.
|
|
14
|
+
* Returns the current Box from the active Box scope.
|
|
15
|
+
* Throws if called outside a Box scope.
|
|
14
16
|
*/
|
|
15
|
-
declare function
|
|
17
|
+
declare function getBox(): Box;
|
|
16
18
|
/**
|
|
17
|
-
* Resolves
|
|
18
|
-
*
|
|
19
|
+
* Resolves instances from the active Box scope.
|
|
20
|
+
* Accepts a single constructor, an array of constructors, or an object map of constructors.
|
|
21
|
+
* Throws if called outside a Box scope.
|
|
19
22
|
*/
|
|
20
23
|
declare function inject<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
declare function resolve<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
25
|
-
/**
|
|
26
|
-
* Resolves multiple cached instances from the current {@link withBox} scope.
|
|
27
|
-
* Shorthand for `useBox().all.get(constructors)`.
|
|
28
|
-
*/
|
|
29
|
-
declare function injectAll<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
30
|
-
declare function injectAll<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
31
|
-
/**
|
|
32
|
-
* @deprecated Use {@link injectAll} instead.
|
|
33
|
-
*/
|
|
34
|
-
declare function resolveAll<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
35
|
-
declare function resolveAll<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
36
|
-
/**
|
|
37
|
-
* Returns a builder for creating a class instance with resolved constructor
|
|
38
|
-
* parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
|
|
39
|
-
*
|
|
40
|
-
* @deprecated
|
|
41
|
-
*/
|
|
42
|
-
declare function construct<T extends new (...args: any) => any>(constructor: T): Construct<T>;
|
|
24
|
+
declare function inject<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
25
|
+
declare function inject<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
43
26
|
//#endregion
|
|
44
|
-
export {
|
|
27
|
+
export { getBox, inject, withBox };
|
package/dist/context.d.mts
CHANGED
|
@@ -1,44 +1,27 @@
|
|
|
1
|
-
import { Box,
|
|
1
|
+
import { Box, Constructor, ConstructorInstanceType } from "./index.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/context.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Runs a function within a
|
|
6
|
+
* Runs a function within a Box scope using AsyncLocalStorage.
|
|
7
7
|
* Creates a new Box if none is provided.
|
|
8
|
+
*
|
|
9
|
+
* If the callback function throws an error, the error is thrown by withBox too.
|
|
8
10
|
*/
|
|
9
11
|
declare function withBox<T>(fn: () => T): T;
|
|
10
12
|
declare function withBox<T>(box: Box, fn: () => T): T;
|
|
11
13
|
/**
|
|
12
|
-
* Returns the current
|
|
13
|
-
* Throws if called outside a scope.
|
|
14
|
+
* Returns the current Box from the active Box scope.
|
|
15
|
+
* Throws if called outside a Box scope.
|
|
14
16
|
*/
|
|
15
|
-
declare function
|
|
17
|
+
declare function getBox(): Box;
|
|
16
18
|
/**
|
|
17
|
-
* Resolves
|
|
18
|
-
*
|
|
19
|
+
* Resolves instances from the active Box scope.
|
|
20
|
+
* Accepts a single constructor, an array of constructors, or an object map of constructors.
|
|
21
|
+
* Throws if called outside a Box scope.
|
|
19
22
|
*/
|
|
20
23
|
declare function inject<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
declare function resolve<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
25
|
-
/**
|
|
26
|
-
* Resolves multiple cached instances from the current {@link withBox} scope.
|
|
27
|
-
* Shorthand for `useBox().all.get(constructors)`.
|
|
28
|
-
*/
|
|
29
|
-
declare function injectAll<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
30
|
-
declare function injectAll<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
31
|
-
/**
|
|
32
|
-
* @deprecated Use {@link injectAll} instead.
|
|
33
|
-
*/
|
|
34
|
-
declare function resolveAll<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
35
|
-
declare function resolveAll<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
36
|
-
/**
|
|
37
|
-
* Returns a builder for creating a class instance with resolved constructor
|
|
38
|
-
* parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
|
|
39
|
-
*
|
|
40
|
-
* @deprecated
|
|
41
|
-
*/
|
|
42
|
-
declare function construct<T extends new (...args: any) => any>(constructor: T): Construct<T>;
|
|
24
|
+
declare function inject<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
25
|
+
declare function inject<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
43
26
|
//#endregion
|
|
44
|
-
export {
|
|
27
|
+
export { getBox, inject, withBox };
|
package/dist/context.mjs
CHANGED
|
@@ -8,42 +8,17 @@ function withBox(boxOrFn, fn) {
|
|
|
8
8
|
return storage.run(boxOrFn, fn);
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Returns the current
|
|
12
|
-
* Throws if called outside a scope.
|
|
11
|
+
* Returns the current Box from the active Box scope.
|
|
12
|
+
* Throws if called outside a Box scope.
|
|
13
13
|
*/
|
|
14
|
-
function
|
|
14
|
+
function getBox() {
|
|
15
15
|
const box = storage.getStore();
|
|
16
|
-
if (
|
|
17
|
-
|
|
16
|
+
if (box) return box;
|
|
17
|
+
throw new Error("getBox() must be called within a withBox() scope");
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* Shorthand for `useBox().get(constructor)`.
|
|
22
|
-
*/
|
|
23
|
-
function inject(constructor) {
|
|
24
|
-
return useBox().get(constructor);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* @deprecated Use {@link inject} instead.
|
|
28
|
-
*/
|
|
29
|
-
function resolve(constructor) {
|
|
30
|
-
return inject(constructor);
|
|
31
|
-
}
|
|
32
|
-
function injectAll(constructors) {
|
|
33
|
-
return useBox().all.get(constructors);
|
|
34
|
-
}
|
|
35
|
-
function resolveAll(constructors) {
|
|
36
|
-
return injectAll(constructors);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Returns a builder for creating a class instance with resolved constructor
|
|
40
|
-
* parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
|
|
41
|
-
*
|
|
42
|
-
* @deprecated
|
|
43
|
-
*/
|
|
44
|
-
function construct(constructor) {
|
|
45
|
-
return useBox().for(constructor);
|
|
19
|
+
function inject(arg) {
|
|
20
|
+
return getBox().get(arg);
|
|
46
21
|
}
|
|
47
22
|
|
|
48
23
|
//#endregion
|
|
49
|
-
export {
|
|
24
|
+
export { getBox, inject, withBox };
|