getbox 1.3.0 → 1.4.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 +15 -30
- package/README.md +109 -159
- package/dist/context.cjs +15 -2
- package/dist/context.d.cts +13 -2
- package/dist/context.d.mts +13 -2
- package/dist/context.mjs +14 -3
- package/dist/index.cjs +36 -27
- package/dist/index.d.cts +34 -28
- package/dist/index.d.mts +34 -28
- package/dist/index.mjs +36 -28
- package/package.json +1 -1
package/CONTEXT.md
CHANGED
|
@@ -11,8 +11,8 @@ import { withBox } from "getbox/context";
|
|
|
11
11
|
|
|
12
12
|
withBox(() => {
|
|
13
13
|
// All code in this scope can resolve dependencies
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const service = inject(UserService);
|
|
15
|
+
service.createUser("Alice");
|
|
16
16
|
});
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -23,24 +23,24 @@ import { Box } from "getbox";
|
|
|
23
23
|
import { withBox } from "getbox/context";
|
|
24
24
|
|
|
25
25
|
const box = new Box();
|
|
26
|
-
Box.mock(box, LoggerFactory, new
|
|
26
|
+
Box.mock(box, LoggerFactory, new MockLogger());
|
|
27
27
|
|
|
28
28
|
withBox(box, () => {
|
|
29
|
-
const
|
|
30
|
-
|
|
29
|
+
const service = inject(UserService);
|
|
30
|
+
service.createUser("Alice");
|
|
31
31
|
});
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Resolving dependencies
|
|
35
35
|
|
|
36
|
-
With the context pattern, classes can use `
|
|
36
|
+
With the context pattern, classes can use `inject` directly as field initializers. No `static init` property is needed.
|
|
37
37
|
|
|
38
38
|
```ts
|
|
39
|
-
import {
|
|
39
|
+
import { inject } from "getbox/context";
|
|
40
40
|
|
|
41
41
|
class UserService {
|
|
42
|
-
public db =
|
|
43
|
-
public logger =
|
|
42
|
+
public db = inject(Database);
|
|
43
|
+
public logger = inject(LoggerFactory);
|
|
44
44
|
|
|
45
45
|
createUser(name: string) {
|
|
46
46
|
this.logger.log(`Creating user: ${name}`);
|
|
@@ -63,36 +63,21 @@ class UserService {
|
|
|
63
63
|
|
|
64
64
|
## Resolving multiple dependencies
|
|
65
65
|
|
|
66
|
-
Use `
|
|
66
|
+
Use `injectAll` to resolve multiple constructors at once. Accepts an object or array of constructors.
|
|
67
67
|
|
|
68
68
|
```ts
|
|
69
69
|
withBox(() => {
|
|
70
70
|
// Object form
|
|
71
|
-
const { db, logger } =
|
|
71
|
+
const { db, logger } = injectAll({ db: Database, logger: LoggerFactory });
|
|
72
72
|
|
|
73
73
|
// Array form
|
|
74
|
-
const [db2, logger2] =
|
|
74
|
+
const [db2, logger2] = injectAll([Database, LoggerFactory]);
|
|
75
75
|
|
|
76
76
|
console.log(db === db2); // true (cached)
|
|
77
77
|
console.log(logger === logger2); // true (cached)
|
|
78
78
|
});
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
## Resolving constructor parameters
|
|
82
|
-
|
|
83
|
-
Use `construct` to create a class instance with resolved constructor parameters.
|
|
84
|
-
|
|
85
|
-
```ts
|
|
86
|
-
class UserService {
|
|
87
|
-
constructor(private db: Database, private logger: Logger) {}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
withBox(() => {
|
|
91
|
-
const service = construct(UserService).get(Database, LoggerFactory);
|
|
92
|
-
service.createUser("Alice");
|
|
93
|
-
});
|
|
94
|
-
```
|
|
95
|
-
|
|
96
81
|
## Accessing the box
|
|
97
82
|
|
|
98
83
|
Use `useBox()` to get the current box from the scope. This is useful when you need full access to the box API.
|
|
@@ -110,11 +95,11 @@ Each `withBox` call creates an independent scope. Nested scopes do not share the
|
|
|
110
95
|
|
|
111
96
|
```ts
|
|
112
97
|
withBox(() => {
|
|
113
|
-
const db =
|
|
98
|
+
const db = inject(Database);
|
|
114
99
|
|
|
115
|
-
// Inner scope gets a
|
|
100
|
+
// Inner scope gets a new box
|
|
116
101
|
withBox(() => {
|
|
117
|
-
const db2 =
|
|
102
|
+
const db2 = inject(Database);
|
|
118
103
|
console.log(db === db2); // false (different scope)
|
|
119
104
|
});
|
|
120
105
|
});
|
package/README.md
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
### Lightweight dependency injection for TypeScript.
|
|
4
4
|
|
|
5
|
-
`getbox`
|
|
5
|
+
`getbox` is a lightweight inversion of control container for TypeScript. Constructors declare their own dependencies, keeping instantiation logic colocated with the type that owns it.
|
|
6
6
|
|
|
7
|
-
Callers
|
|
8
|
-
|
|
9
|
-
For an alternative pattern using AsyncLocalStorage where classes can resolve dependencies directly in their constructors, see [getbox/context](./CONTEXT.md).
|
|
7
|
+
Callers depend on types, not implementations. The box resolves and caches instances automatically on first use.
|
|
10
8
|
|
|
11
9
|
## Installation
|
|
12
10
|
|
|
@@ -16,254 +14,206 @@ npm install getbox
|
|
|
16
14
|
|
|
17
15
|
## Usage
|
|
18
16
|
|
|
19
|
-
`getbox` has a very small API surface. You typically only need
|
|
17
|
+
`getbox` has a very small API surface. You typically only need `box.get()` and optionally `static init` or the `factory` helper.
|
|
18
|
+
|
|
19
|
+
For an alternative pattern using AsyncLocalStorage where classes can resolve dependencies directly, see [getbox/context](./CONTEXT.md).
|
|
20
20
|
|
|
21
|
-
###
|
|
21
|
+
### Quick start
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Create a `Box` instance and call `box.get()` to resolve instances. The box automatically resolves dependencies and caches every instance, so shared dependencies always point to the same reference.
|
|
24
24
|
|
|
25
25
|
```ts
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
import { Box } from "getbox";
|
|
27
|
+
|
|
28
|
+
class Printer {
|
|
29
|
+
print(text: string) {
|
|
29
30
|
return text.toUpperCase();
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
```
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Retrieve instances by calling `box.get(Constructor)` within your class constructor or factory function.
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
// office.ts
|
|
40
|
-
import { Box, factory } from "getbox";
|
|
41
|
-
import { Printer } from "./printer";
|
|
42
|
-
|
|
43
|
-
export class Office {
|
|
34
|
+
class Office {
|
|
44
35
|
constructor(public printer: Printer) {}
|
|
45
36
|
|
|
46
37
|
static init = Box.init(Office).get(Printer);
|
|
47
38
|
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Use in application
|
|
51
|
-
|
|
52
|
-
Create a Box instance to hold cached instances.
|
|
53
|
-
|
|
54
|
-
When initializing a class, any dependencies it has will also be cached, ensuring that shared dependencies use the same instance.
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
// main.ts
|
|
58
|
-
import { Box } from "getbox";
|
|
59
|
-
import { Office } from "./office";
|
|
60
|
-
import { Printer } from "./printer";
|
|
61
39
|
|
|
62
40
|
const box = new Box();
|
|
63
41
|
|
|
64
42
|
const office = box.get(Office);
|
|
65
43
|
office.printer.print("hello world");
|
|
66
44
|
|
|
67
|
-
//
|
|
45
|
+
// Dependencies are cached and shared
|
|
68
46
|
const printer = box.get(Printer);
|
|
69
47
|
console.log(office.printer === printer); // true
|
|
70
48
|
```
|
|
71
49
|
|
|
72
|
-
##
|
|
50
|
+
## Constructors
|
|
73
51
|
|
|
74
|
-
|
|
52
|
+
Constructors define what the box resolves. `getbox` supports classes, factories, derived values, and constants. Because constructors act as interfaces, the underlying implementation can change without affecting any consumer.
|
|
53
|
+
|
|
54
|
+
### Classes
|
|
55
|
+
|
|
56
|
+
Define a `static init` property to allow the box to resolve classes that have constructor parameters. Classes with no parameters do not require it.
|
|
75
57
|
|
|
76
58
|
```ts
|
|
77
|
-
// main.ts
|
|
78
59
|
import { Box } from "getbox";
|
|
79
60
|
|
|
80
|
-
class
|
|
81
|
-
|
|
82
|
-
|
|
61
|
+
class UserService {
|
|
62
|
+
constructor(private db: Database, private logger: Logger) {}
|
|
63
|
+
|
|
64
|
+
static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
65
|
+
|
|
66
|
+
createUser(name: string) {
|
|
67
|
+
this.logger.log(`Creating user: ${name}`);
|
|
83
68
|
}
|
|
84
69
|
}
|
|
85
70
|
|
|
86
71
|
const box = new Box();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const db2 = box.new(Database);
|
|
90
|
-
|
|
91
|
-
console.log(db1 === db2); // false
|
|
72
|
+
const service = box.get(UserService);
|
|
73
|
+
service.createUser("Alice");
|
|
92
74
|
```
|
|
93
75
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
Use the `factory` helper to create function-based constructors instead of classes. Factories work well with interfaces for better abstraction.
|
|
76
|
+
`Box.init` is shorthand for writing the `static init` property yourself.
|
|
97
77
|
|
|
98
78
|
```ts
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
export interface Logger {
|
|
103
|
-
log(message: string): void;
|
|
104
|
-
}
|
|
79
|
+
class UserService {
|
|
80
|
+
constructor(private db: Database, private logger: Logger) {}
|
|
105
81
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
console.log(`[LOG] ${message}`);
|
|
82
|
+
static init(box: Box) {
|
|
83
|
+
return new UserService(box.get(Database), box.get(LoggerFactory));
|
|
109
84
|
}
|
|
110
85
|
}
|
|
111
|
-
|
|
112
|
-
const LoggerFactory = factory((box: Box): Logger => {
|
|
113
|
-
return new ConsoleLogger();
|
|
114
|
-
});
|
|
115
86
|
```
|
|
116
87
|
|
|
117
|
-
|
|
118
|
-
// service.ts
|
|
119
|
-
import { Box } from "getbox";
|
|
120
|
-
import { Logger, LoggerFactory } from "./logger";
|
|
121
|
-
|
|
122
|
-
export class UserService {
|
|
123
|
-
constructor(private logger: Logger) {}
|
|
88
|
+
Use `box.for()` when you need custom logic alongside dependency resolution.
|
|
124
89
|
|
|
125
|
-
|
|
90
|
+
```ts
|
|
91
|
+
class UserService {
|
|
92
|
+
constructor(private db: Database, private logger: Logger) {}
|
|
126
93
|
|
|
127
|
-
|
|
128
|
-
|
|
94
|
+
static init(box: Box) {
|
|
95
|
+
const logger = box.get(LoggerFactory);
|
|
96
|
+
logger.log("Initializing UserService");
|
|
97
|
+
return box.for(UserService).get(Database, LoggerFactory);
|
|
129
98
|
}
|
|
130
99
|
}
|
|
131
100
|
```
|
|
132
101
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
Use the `constant` helper to register constant values without needing a factory or class. Constant values are never cached since they are already fixed.
|
|
136
|
-
|
|
137
|
-
```ts
|
|
138
|
-
import { Box, constant } from "getbox";
|
|
102
|
+
If `static init` is defined, it takes priority over the class constructor.
|
|
139
103
|
|
|
140
|
-
|
|
141
|
-
const Port = constant(3000);
|
|
142
|
-
const Config = constant({
|
|
143
|
-
baseUrl: "https://example.com",
|
|
144
|
-
timeout: 5000,
|
|
145
|
-
});
|
|
104
|
+
### Factory functions
|
|
146
105
|
|
|
147
|
-
|
|
106
|
+
Use the `factory` helper to create function-based constructors instead of classes. Factories work well with interfaces for better abstraction.
|
|
148
107
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const config = box.get(Config);
|
|
108
|
+
```ts
|
|
109
|
+
import { Box, factory } from "getbox";
|
|
152
110
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
```
|
|
111
|
+
interface Logger {
|
|
112
|
+
log(message: string): void;
|
|
113
|
+
}
|
|
157
114
|
|
|
158
|
-
|
|
115
|
+
const LoggerFactory = factory(
|
|
116
|
+
(): Logger => ({
|
|
117
|
+
log(message: string) {
|
|
118
|
+
console.log(`[LOG] ${message}`);
|
|
119
|
+
},
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
159
122
|
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
const config = box.get(Config);
|
|
163
|
-
return `${config.baseUrl}/api`;
|
|
164
|
-
});
|
|
123
|
+
const box = new Box();
|
|
124
|
+
const logger = box.get(LoggerFactory);
|
|
165
125
|
|
|
166
|
-
|
|
126
|
+
logger.log("hello world");
|
|
167
127
|
```
|
|
168
128
|
|
|
169
|
-
|
|
129
|
+
### Derived values
|
|
170
130
|
|
|
171
|
-
Use the `
|
|
131
|
+
Use the `derive` helper to compute a value from the box without caching the result.
|
|
172
132
|
|
|
173
133
|
```ts
|
|
174
|
-
import { Box,
|
|
134
|
+
import { Box, derive } from "getbox";
|
|
175
135
|
|
|
176
|
-
|
|
136
|
+
class Config {
|
|
137
|
+
baseUrl = "https://example.com";
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const RequestContext = derive((box) => ({
|
|
141
|
+
baseUrl: box.get(Config).baseUrl,
|
|
142
|
+
timestamp: Date.now(),
|
|
143
|
+
}));
|
|
177
144
|
|
|
178
145
|
const box = new Box();
|
|
179
146
|
|
|
180
|
-
const
|
|
181
|
-
const
|
|
147
|
+
const ctx1 = box.get(RequestContext);
|
|
148
|
+
const ctx2 = box.get(RequestContext);
|
|
182
149
|
|
|
183
|
-
console.log(
|
|
150
|
+
console.log(ctx1 === ctx2); // false
|
|
184
151
|
```
|
|
185
152
|
|
|
186
|
-
|
|
153
|
+
### Constants
|
|
187
154
|
|
|
188
|
-
Use `
|
|
155
|
+
Use the `constant` helper to wrap a fixed value as a constructor. Constant values are never cached and always return the same stable reference.
|
|
189
156
|
|
|
190
157
|
```ts
|
|
191
|
-
import { Box } from "getbox";
|
|
192
|
-
|
|
193
|
-
const box = new Box();
|
|
194
|
-
|
|
195
|
-
// Object form
|
|
196
|
-
const { db, logger } = box.all.get({ db: Database, logger: LoggerFactory });
|
|
197
|
-
|
|
198
|
-
// Array form
|
|
199
|
-
const [db2, logger2] = box.all.get([Database, LoggerFactory]);
|
|
200
|
-
|
|
201
|
-
console.log(db === db2); // true (cached)
|
|
202
|
-
console.log(logger === logger2); // true (cached)
|
|
203
|
-
```
|
|
158
|
+
import { Box, constant } from "getbox";
|
|
204
159
|
|
|
205
|
-
|
|
160
|
+
const ApiUrl = constant("https://api.example.com");
|
|
161
|
+
const Port = constant(3000);
|
|
162
|
+
const Config = constant({
|
|
163
|
+
baseUrl: "https://example.com",
|
|
164
|
+
timeout: 5000,
|
|
165
|
+
});
|
|
206
166
|
|
|
207
|
-
|
|
208
|
-
const { db } = box.all.new({ db: Database });
|
|
209
|
-
const [db2] = box.all.new([Database]);
|
|
167
|
+
const box = new Box();
|
|
210
168
|
|
|
211
|
-
console.log(
|
|
169
|
+
console.log(box.get(ApiUrl)); // "https://api.example.com"
|
|
170
|
+
console.log(box.get(Port)); // 3000
|
|
171
|
+
console.log(box.get(Config).timeout); // 5000
|
|
212
172
|
```
|
|
213
173
|
|
|
214
|
-
##
|
|
174
|
+
## Resolving instances
|
|
215
175
|
|
|
216
|
-
Use `
|
|
176
|
+
Use `box.get()` to resolve a cached instance. The box resolves the constructor on first call and returns the same instance on every subsequent call. Use `box.new()` to always get a new instance without caching.
|
|
217
177
|
|
|
218
178
|
```ts
|
|
219
179
|
import { Box } from "getbox";
|
|
220
180
|
|
|
221
|
-
class
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
static init = Box.init(UserService).get(Database, LoggerFactory);
|
|
225
|
-
|
|
226
|
-
createUser(name: string) {
|
|
227
|
-
this.logger.log(`Creating user: ${name}`);
|
|
181
|
+
class Database {
|
|
182
|
+
connect() {
|
|
183
|
+
/* ... */
|
|
228
184
|
}
|
|
229
185
|
}
|
|
230
186
|
|
|
231
187
|
const box = new Box();
|
|
232
|
-
const service = box.get(UserService);
|
|
233
|
-
service.createUser("Alice");
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
`Box.init` is shorthand for writing the `static init` method yourself.
|
|
237
188
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
189
|
+
const db1 = box.get(Database);
|
|
190
|
+
const db2 = box.get(Database);
|
|
191
|
+
console.log(db1 === db2); // true (cached)
|
|
241
192
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
193
|
+
const db3 = box.new(Database);
|
|
194
|
+
const db4 = box.new(Database);
|
|
195
|
+
console.log(db3 === db4); // false (never cached)
|
|
246
196
|
```
|
|
247
197
|
|
|
248
|
-
Use `box.
|
|
198
|
+
Use `box.all.get()` or `box.all.new()` to resolve multiple constructors at once. Pass an array to get an array of instances, or an object to get an object of instances.
|
|
249
199
|
|
|
250
200
|
```ts
|
|
251
|
-
|
|
252
|
-
constructor(private db: Database, private logger: Logger) {}
|
|
201
|
+
const box = new Box();
|
|
253
202
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
203
|
+
// Cached
|
|
204
|
+
const { db, logger } = box.all.get({ db: Database, logger: LoggerFactory });
|
|
205
|
+
const [db2, logger2] = box.all.get([Database, LoggerFactory]);
|
|
206
|
+
|
|
207
|
+
// New instances
|
|
208
|
+
const { db3 } = box.all.new({ db3: Database });
|
|
209
|
+
const [db4] = box.all.new([Database]);
|
|
260
210
|
```
|
|
261
211
|
|
|
262
|
-
|
|
212
|
+
> `box.get()` does not cache `derive` or `constant` values.
|
|
263
213
|
|
|
264
214
|
## Mocking
|
|
265
215
|
|
|
266
|
-
You can mock dependencies for testing using `Box.mock`.
|
|
216
|
+
You can mock dependencies for testing using `Box.mock`.
|
|
267
217
|
|
|
268
218
|
```ts
|
|
269
219
|
// service.test.ts
|
|
@@ -308,7 +258,7 @@ Box.clear(box);
|
|
|
308
258
|
|
|
309
259
|
## Circular dependencies
|
|
310
260
|
|
|
311
|
-
`getbox` does not prevent circular dependencies. You should structure your code to avoid
|
|
261
|
+
`getbox` does not prevent circular dependencies. You should structure your code to avoid them.
|
|
312
262
|
|
|
313
263
|
## License
|
|
314
264
|
|
package/dist/context.cjs
CHANGED
|
@@ -20,15 +20,26 @@ function useBox() {
|
|
|
20
20
|
* Resolves a cached instance from the current {@link withBox} scope.
|
|
21
21
|
* Shorthand for `useBox().get(constructor)`.
|
|
22
22
|
*/
|
|
23
|
-
function
|
|
23
|
+
function inject(constructor) {
|
|
24
24
|
return useBox().get(constructor);
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated Use {@link inject} instead.
|
|
28
|
+
*/
|
|
29
|
+
function resolve(constructor) {
|
|
30
|
+
return inject(constructor);
|
|
31
|
+
}
|
|
32
|
+
function injectAll(constructors) {
|
|
27
33
|
return useBox().all.get(constructors);
|
|
28
34
|
}
|
|
35
|
+
function resolveAll(constructors) {
|
|
36
|
+
return injectAll(constructors);
|
|
37
|
+
}
|
|
29
38
|
/**
|
|
30
39
|
* Returns a builder for creating a class instance with resolved constructor
|
|
31
40
|
* parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
|
|
41
|
+
*
|
|
42
|
+
* @deprecated
|
|
32
43
|
*/
|
|
33
44
|
function construct(constructor) {
|
|
34
45
|
return useBox().for(constructor);
|
|
@@ -36,6 +47,8 @@ function construct(constructor) {
|
|
|
36
47
|
|
|
37
48
|
//#endregion
|
|
38
49
|
exports.construct = construct;
|
|
50
|
+
exports.inject = inject;
|
|
51
|
+
exports.injectAll = injectAll;
|
|
39
52
|
exports.resolve = resolve;
|
|
40
53
|
exports.resolveAll = resolveAll;
|
|
41
54
|
exports.useBox = useBox;
|
package/dist/context.d.cts
CHANGED
|
@@ -4,7 +4,7 @@ import { Box, Construct, Constructor, ConstructorInstanceType } from "./index.cj
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Runs a function within a scoped {@link Box} context using AsyncLocalStorage.
|
|
7
|
-
* Creates a
|
|
7
|
+
* Creates a new Box if none is provided.
|
|
8
8
|
*/
|
|
9
9
|
declare function withBox<T>(fn: () => T): T;
|
|
10
10
|
declare function withBox<T>(box: Box, fn: () => T): T;
|
|
@@ -17,17 +17,28 @@ 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 inject<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated Use {@link inject} instead.
|
|
23
|
+
*/
|
|
20
24
|
declare function resolve<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
21
25
|
/**
|
|
22
26
|
* Resolves multiple cached instances from the current {@link withBox} scope.
|
|
23
27
|
* Shorthand for `useBox().all.get(constructors)`.
|
|
24
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
|
+
*/
|
|
25
34
|
declare function resolveAll<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
26
35
|
declare function resolveAll<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
27
36
|
/**
|
|
28
37
|
* Returns a builder for creating a class instance with resolved constructor
|
|
29
38
|
* parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
|
|
39
|
+
*
|
|
40
|
+
* @deprecated
|
|
30
41
|
*/
|
|
31
42
|
declare function construct<T extends new (...args: any) => any>(constructor: T): Construct<T>;
|
|
32
43
|
//#endregion
|
|
33
|
-
export { construct, resolve, resolveAll, useBox, withBox };
|
|
44
|
+
export { construct, inject, injectAll, resolve, resolveAll, useBox, withBox };
|
package/dist/context.d.mts
CHANGED
|
@@ -4,7 +4,7 @@ import { Box, Construct, Constructor, ConstructorInstanceType } from "./index.mj
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Runs a function within a scoped {@link Box} context using AsyncLocalStorage.
|
|
7
|
-
* Creates a
|
|
7
|
+
* Creates a new Box if none is provided.
|
|
8
8
|
*/
|
|
9
9
|
declare function withBox<T>(fn: () => T): T;
|
|
10
10
|
declare function withBox<T>(box: Box, fn: () => T): T;
|
|
@@ -17,17 +17,28 @@ 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 inject<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated Use {@link inject} instead.
|
|
23
|
+
*/
|
|
20
24
|
declare function resolve<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
21
25
|
/**
|
|
22
26
|
* Resolves multiple cached instances from the current {@link withBox} scope.
|
|
23
27
|
* Shorthand for `useBox().all.get(constructors)`.
|
|
24
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
|
+
*/
|
|
25
34
|
declare function resolveAll<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
26
35
|
declare function resolveAll<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
27
36
|
/**
|
|
28
37
|
* Returns a builder for creating a class instance with resolved constructor
|
|
29
38
|
* parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
|
|
39
|
+
*
|
|
40
|
+
* @deprecated
|
|
30
41
|
*/
|
|
31
42
|
declare function construct<T extends new (...args: any) => any>(constructor: T): Construct<T>;
|
|
32
43
|
//#endregion
|
|
33
|
-
export { construct, resolve, resolveAll, useBox, withBox };
|
|
44
|
+
export { construct, inject, injectAll, resolve, resolveAll, useBox, withBox };
|
package/dist/context.mjs
CHANGED
|
@@ -20,19 +20,30 @@ function useBox() {
|
|
|
20
20
|
* Resolves a cached instance from the current {@link withBox} scope.
|
|
21
21
|
* Shorthand for `useBox().get(constructor)`.
|
|
22
22
|
*/
|
|
23
|
-
function
|
|
23
|
+
function inject(constructor) {
|
|
24
24
|
return useBox().get(constructor);
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated Use {@link inject} instead.
|
|
28
|
+
*/
|
|
29
|
+
function resolve(constructor) {
|
|
30
|
+
return inject(constructor);
|
|
31
|
+
}
|
|
32
|
+
function injectAll(constructors) {
|
|
27
33
|
return useBox().all.get(constructors);
|
|
28
34
|
}
|
|
35
|
+
function resolveAll(constructors) {
|
|
36
|
+
return injectAll(constructors);
|
|
37
|
+
}
|
|
29
38
|
/**
|
|
30
39
|
* Returns a builder for creating a class instance with resolved constructor
|
|
31
40
|
* parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
|
|
41
|
+
*
|
|
42
|
+
* @deprecated
|
|
32
43
|
*/
|
|
33
44
|
function construct(constructor) {
|
|
34
45
|
return useBox().for(constructor);
|
|
35
46
|
}
|
|
36
47
|
|
|
37
48
|
//#endregion
|
|
38
|
-
export { construct, resolve, resolveAll, useBox, withBox };
|
|
49
|
+
export { construct, inject, injectAll, resolve, resolveAll, useBox, withBox };
|
package/dist/index.cjs
CHANGED
|
@@ -18,25 +18,37 @@ function factory(init) {
|
|
|
18
18
|
}
|
|
19
19
|
const noCacheSymbol = Symbol("Box.noCache");
|
|
20
20
|
/**
|
|
21
|
-
* Creates a {@link Constructor}
|
|
22
|
-
* The factory is called on every resolution, always returning a fresh value
|
|
23
|
-
* even when retrieved via {@link Box.get}.
|
|
21
|
+
* Creates a {@link Constructor} that computes a value from the box without caching the result.
|
|
24
22
|
*
|
|
25
23
|
* @example
|
|
26
24
|
* ```ts
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
25
|
+
* class Config {
|
|
26
|
+
* baseUrl = "https://example.com";
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* const RequestContext = derive((box) => ({
|
|
30
|
+
* baseUrl: box.get(Config).baseUrl,
|
|
31
|
+
* timestamp: Date.now(),
|
|
32
|
+
* }));
|
|
33
|
+
*
|
|
34
|
+
* const ctx1 = box.get(RequestContext);
|
|
35
|
+
* const ctx2 = box.get(RequestContext);
|
|
36
|
+
* console.log(ctx1 === ctx2); // false
|
|
31
37
|
* ```
|
|
32
38
|
*/
|
|
33
|
-
function
|
|
39
|
+
function derive(init) {
|
|
34
40
|
return {
|
|
35
41
|
init,
|
|
36
42
|
[noCacheSymbol]: true
|
|
37
43
|
};
|
|
38
44
|
}
|
|
39
45
|
/**
|
|
46
|
+
* @deprecated Use {@link derive} instead.
|
|
47
|
+
*/
|
|
48
|
+
function transient(init) {
|
|
49
|
+
return derive(init);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
40
52
|
* Creates a {@link Constructor} that always resolves to the given constant value.
|
|
41
53
|
* Constant values are never cached since they are already fixed.
|
|
42
54
|
*
|
|
@@ -69,9 +81,7 @@ function constant(value) {
|
|
|
69
81
|
*
|
|
70
82
|
* class UserService {
|
|
71
83
|
* constructor(private db: Database) {}
|
|
72
|
-
* static init
|
|
73
|
-
* return new UserService(box.get(Database));
|
|
74
|
-
* }
|
|
84
|
+
* static init = Box.init(UserService).get(Database);
|
|
75
85
|
* }
|
|
76
86
|
*
|
|
77
87
|
* const box = new Box();
|
|
@@ -79,14 +89,12 @@ function constant(value) {
|
|
|
79
89
|
* const db = box.get(Database);
|
|
80
90
|
*
|
|
81
91
|
* console.log(service.db === db); // true (cached)
|
|
82
|
-
* console.log(box.new(Database) === db); // false (transient)
|
|
83
92
|
* ```
|
|
84
93
|
*/
|
|
85
94
|
var Box = class {
|
|
86
95
|
cache = /* @__PURE__ */ new Map();
|
|
87
96
|
/**
|
|
88
|
-
* Creates a new
|
|
89
|
-
* that should not be shared.
|
|
97
|
+
* Creates a new instance without caching.
|
|
90
98
|
*/
|
|
91
99
|
new(constructor) {
|
|
92
100
|
return "init" in constructor ? constructor.init(this) : new constructor();
|
|
@@ -109,7 +117,7 @@ var Box = class {
|
|
|
109
117
|
*
|
|
110
118
|
* Intended to be used inside a class's `static init` method. The instance
|
|
111
119
|
* returned by the builder is never cached itself, but can be cached when
|
|
112
|
-
* the class is retrieved via {@link Box.get} or
|
|
120
|
+
* the class is retrieved via {@link Box.get} or new via {@link Box.new}.
|
|
113
121
|
*/
|
|
114
122
|
for(constructor) {
|
|
115
123
|
return new Construct(this, constructor);
|
|
@@ -150,18 +158,18 @@ var BoxAll = class {
|
|
|
150
158
|
constructor(box) {
|
|
151
159
|
this.box = box;
|
|
152
160
|
}
|
|
153
|
-
get(constructors) {
|
|
154
|
-
if (Array.isArray(constructors)) return constructors.map((c) => this.box.get(c));
|
|
155
|
-
const result = {};
|
|
156
|
-
for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.get(constructor);
|
|
157
|
-
return result;
|
|
158
|
-
}
|
|
159
161
|
new(constructors) {
|
|
160
162
|
if (Array.isArray(constructors)) return constructors.map((c) => this.box.new(c));
|
|
161
163
|
const result = {};
|
|
162
164
|
for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.new(constructor);
|
|
163
165
|
return result;
|
|
164
166
|
}
|
|
167
|
+
get(constructors) {
|
|
168
|
+
if (Array.isArray(constructors)) return constructors.map((c) => this.box.get(c));
|
|
169
|
+
const result = {};
|
|
170
|
+
for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.get(constructor);
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
165
173
|
};
|
|
166
174
|
/** Builder for creating class instances with constructor dependencies resolved from a {@link Box}. */
|
|
167
175
|
var Construct = class {
|
|
@@ -170,10 +178,10 @@ var Construct = class {
|
|
|
170
178
|
this.construct = construct;
|
|
171
179
|
}
|
|
172
180
|
/**
|
|
173
|
-
* Resolves each dependency as a new
|
|
181
|
+
* Resolves each dependency as a new instance via {@link Box.new},
|
|
174
182
|
* meaning dependencies are not cached or shared.
|
|
175
183
|
*
|
|
176
|
-
* The returned instance is cached or
|
|
184
|
+
* The returned instance is cached or new depending on whether the
|
|
177
185
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
178
186
|
*
|
|
179
187
|
* @example
|
|
@@ -194,7 +202,7 @@ var Construct = class {
|
|
|
194
202
|
* Resolves each dependency as a cached instance via {@link Box.get},
|
|
195
203
|
* meaning dependencies are shared across the box.
|
|
196
204
|
*
|
|
197
|
-
* The returned instance is cached or
|
|
205
|
+
* The returned instance is cached or new depending on whether the
|
|
198
206
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
199
207
|
*
|
|
200
208
|
* @example
|
|
@@ -221,11 +229,11 @@ var StaticConstruct = class {
|
|
|
221
229
|
this.construct = construct;
|
|
222
230
|
}
|
|
223
231
|
/**
|
|
224
|
-
* Resolves each dependency as a new
|
|
232
|
+
* Resolves each dependency as a new instance via {@link Box.new},
|
|
225
233
|
* meaning dependencies are not cached or shared.
|
|
226
234
|
* Returns a function compatible with `static init` that can be assigned directly.
|
|
227
235
|
*
|
|
228
|
-
* The returned instance is cached or
|
|
236
|
+
* The returned instance is cached or new depending on whether the
|
|
229
237
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
230
238
|
*
|
|
231
239
|
* @example
|
|
@@ -247,7 +255,7 @@ var StaticConstruct = class {
|
|
|
247
255
|
* meaning dependencies are shared across the box.
|
|
248
256
|
* Returns a function compatible with `static init` that can be assigned directly.
|
|
249
257
|
*
|
|
250
|
-
* The returned instance is cached or
|
|
258
|
+
* The returned instance is cached or new depending on whether the
|
|
251
259
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
252
260
|
*
|
|
253
261
|
* @example
|
|
@@ -271,5 +279,6 @@ exports.Box = Box;
|
|
|
271
279
|
exports.Construct = Construct;
|
|
272
280
|
exports.StaticConstruct = StaticConstruct;
|
|
273
281
|
exports.constant = constant;
|
|
282
|
+
exports.derive = derive;
|
|
274
283
|
exports.factory = factory;
|
|
275
284
|
exports.transient = transient;
|
package/dist/index.d.cts
CHANGED
|
@@ -30,18 +30,28 @@ type ConstructorInstanceType<T> = T extends {
|
|
|
30
30
|
*/
|
|
31
31
|
declare function factory<T>(init: (box: Box) => T): Constructor<T>;
|
|
32
32
|
/**
|
|
33
|
-
* Creates a {@link Constructor}
|
|
34
|
-
* The factory is called on every resolution, always returning a fresh value
|
|
35
|
-
* even when retrieved via {@link Box.get}.
|
|
33
|
+
* Creates a {@link Constructor} that computes a value from the box without caching the result.
|
|
36
34
|
*
|
|
37
35
|
* @example
|
|
38
36
|
* ```ts
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
37
|
+
* class Config {
|
|
38
|
+
* baseUrl = "https://example.com";
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* const RequestContext = derive((box) => ({
|
|
42
|
+
* baseUrl: box.get(Config).baseUrl,
|
|
43
|
+
* timestamp: Date.now(),
|
|
44
|
+
* }));
|
|
45
|
+
*
|
|
46
|
+
* const ctx1 = box.get(RequestContext);
|
|
47
|
+
* const ctx2 = box.get(RequestContext);
|
|
48
|
+
* console.log(ctx1 === ctx2); // false
|
|
43
49
|
* ```
|
|
44
50
|
*/
|
|
51
|
+
declare function derive<T>(init: (box: Box) => T): Constructor<T>;
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated Use {@link derive} instead.
|
|
54
|
+
*/
|
|
45
55
|
declare function transient<T>(init: (box: Box) => T): Constructor<T>;
|
|
46
56
|
/**
|
|
47
57
|
* Creates a {@link Constructor} that always resolves to the given constant value.
|
|
@@ -71,9 +81,7 @@ declare function constant<const T>(value: T): Constructor<T>;
|
|
|
71
81
|
*
|
|
72
82
|
* class UserService {
|
|
73
83
|
* constructor(private db: Database) {}
|
|
74
|
-
* static init
|
|
75
|
-
* return new UserService(box.get(Database));
|
|
76
|
-
* }
|
|
84
|
+
* static init = Box.init(UserService).get(Database);
|
|
77
85
|
* }
|
|
78
86
|
*
|
|
79
87
|
* const box = new Box();
|
|
@@ -81,14 +89,12 @@ declare function constant<const T>(value: T): Constructor<T>;
|
|
|
81
89
|
* const db = box.get(Database);
|
|
82
90
|
*
|
|
83
91
|
* console.log(service.db === db); // true (cached)
|
|
84
|
-
* console.log(box.new(Database) === db); // false (transient)
|
|
85
92
|
* ```
|
|
86
93
|
*/
|
|
87
94
|
declare class Box {
|
|
88
|
-
|
|
95
|
+
protected cache: Map<Constructor<any>, any>;
|
|
89
96
|
/**
|
|
90
|
-
* Creates a new
|
|
91
|
-
* that should not be shared.
|
|
97
|
+
* Creates a new instance without caching.
|
|
92
98
|
*/
|
|
93
99
|
new<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
94
100
|
/**
|
|
@@ -104,7 +110,7 @@ declare class Box {
|
|
|
104
110
|
*
|
|
105
111
|
* Intended to be used inside a class's `static init` method. The instance
|
|
106
112
|
* returned by the builder is never cached itself, but can be cached when
|
|
107
|
-
* the class is retrieved via {@link Box.get} or
|
|
113
|
+
* the class is retrieved via {@link Box.get} or new via {@link Box.new}.
|
|
108
114
|
*/
|
|
109
115
|
for<T extends ClassConstructor<any>>(constructor: T): Construct<T>;
|
|
110
116
|
/**
|
|
@@ -136,17 +142,17 @@ declare class BoxAll {
|
|
|
136
142
|
private box;
|
|
137
143
|
constructor(box: Box);
|
|
138
144
|
/**
|
|
139
|
-
* Resolves each constructor as a
|
|
145
|
+
* Resolves each constructor as a new instance via {@link Box.new}.
|
|
140
146
|
* Accepts an array or object of constructors and returns instances in the same shape.
|
|
141
147
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
148
|
+
new<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
149
|
+
new<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
144
150
|
/**
|
|
145
|
-
* Resolves each constructor as a
|
|
151
|
+
* Resolves each constructor as a cached instance via {@link Box.get}.
|
|
146
152
|
* Accepts an array or object of constructors and returns instances in the same shape.
|
|
147
153
|
*/
|
|
148
|
-
|
|
149
|
-
|
|
154
|
+
get<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
155
|
+
get<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
150
156
|
}
|
|
151
157
|
/** Builder for creating class instances with constructor dependencies resolved from a {@link Box}. */
|
|
152
158
|
declare class Construct<T extends ClassConstructor<any>> {
|
|
@@ -154,10 +160,10 @@ declare class Construct<T extends ClassConstructor<any>> {
|
|
|
154
160
|
private construct;
|
|
155
161
|
constructor(box: Box, construct: T);
|
|
156
162
|
/**
|
|
157
|
-
* Resolves each dependency as a new
|
|
163
|
+
* Resolves each dependency as a new instance via {@link Box.new},
|
|
158
164
|
* meaning dependencies are not cached or shared.
|
|
159
165
|
*
|
|
160
|
-
* The returned instance is cached or
|
|
166
|
+
* The returned instance is cached or new depending on whether the
|
|
161
167
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
162
168
|
*
|
|
163
169
|
* @example
|
|
@@ -175,7 +181,7 @@ declare class Construct<T extends ClassConstructor<any>> {
|
|
|
175
181
|
* Resolves each dependency as a cached instance via {@link Box.get},
|
|
176
182
|
* meaning dependencies are shared across the box.
|
|
177
183
|
*
|
|
178
|
-
* The returned instance is cached or
|
|
184
|
+
* The returned instance is cached or new depending on whether the
|
|
179
185
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
180
186
|
*
|
|
181
187
|
* @example
|
|
@@ -198,11 +204,11 @@ declare class StaticConstruct<T extends ClassConstructor<any>> {
|
|
|
198
204
|
private construct;
|
|
199
205
|
constructor(construct: T);
|
|
200
206
|
/**
|
|
201
|
-
* Resolves each dependency as a new
|
|
207
|
+
* Resolves each dependency as a new instance via {@link Box.new},
|
|
202
208
|
* meaning dependencies are not cached or shared.
|
|
203
209
|
* Returns a function compatible with `static init` that can be assigned directly.
|
|
204
210
|
*
|
|
205
|
-
* The returned instance is cached or
|
|
211
|
+
* The returned instance is cached or new depending on whether the
|
|
206
212
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
207
213
|
*
|
|
208
214
|
* @example
|
|
@@ -219,7 +225,7 @@ declare class StaticConstruct<T extends ClassConstructor<any>> {
|
|
|
219
225
|
* meaning dependencies are shared across the box.
|
|
220
226
|
* Returns a function compatible with `static init` that can be assigned directly.
|
|
221
227
|
*
|
|
222
|
-
* The returned instance is cached or
|
|
228
|
+
* The returned instance is cached or new depending on whether the
|
|
223
229
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
224
230
|
*
|
|
225
231
|
* @example
|
|
@@ -239,4 +245,4 @@ type ClassConstructor<T> = {
|
|
|
239
245
|
/** Maps each constructor parameter to its corresponding {@link Constructor} type. */
|
|
240
246
|
type ClassConstructorArgs<T extends ClassConstructor<any>, Args = ConstructorParameters<T>> = { [K in keyof Args]: Constructor<Args[K]> };
|
|
241
247
|
//#endregion
|
|
242
|
-
export { Box, Construct, Constructor, ConstructorInstanceType, StaticConstruct, constant, factory, transient };
|
|
248
|
+
export { Box, Construct, Constructor, ConstructorInstanceType, StaticConstruct, constant, derive, factory, transient };
|
package/dist/index.d.mts
CHANGED
|
@@ -30,18 +30,28 @@ type ConstructorInstanceType<T> = T extends {
|
|
|
30
30
|
*/
|
|
31
31
|
declare function factory<T>(init: (box: Box) => T): Constructor<T>;
|
|
32
32
|
/**
|
|
33
|
-
* Creates a {@link Constructor}
|
|
34
|
-
* The factory is called on every resolution, always returning a fresh value
|
|
35
|
-
* even when retrieved via {@link Box.get}.
|
|
33
|
+
* Creates a {@link Constructor} that computes a value from the box without caching the result.
|
|
36
34
|
*
|
|
37
35
|
* @example
|
|
38
36
|
* ```ts
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
37
|
+
* class Config {
|
|
38
|
+
* baseUrl = "https://example.com";
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* const RequestContext = derive((box) => ({
|
|
42
|
+
* baseUrl: box.get(Config).baseUrl,
|
|
43
|
+
* timestamp: Date.now(),
|
|
44
|
+
* }));
|
|
45
|
+
*
|
|
46
|
+
* const ctx1 = box.get(RequestContext);
|
|
47
|
+
* const ctx2 = box.get(RequestContext);
|
|
48
|
+
* console.log(ctx1 === ctx2); // false
|
|
43
49
|
* ```
|
|
44
50
|
*/
|
|
51
|
+
declare function derive<T>(init: (box: Box) => T): Constructor<T>;
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated Use {@link derive} instead.
|
|
54
|
+
*/
|
|
45
55
|
declare function transient<T>(init: (box: Box) => T): Constructor<T>;
|
|
46
56
|
/**
|
|
47
57
|
* Creates a {@link Constructor} that always resolves to the given constant value.
|
|
@@ -71,9 +81,7 @@ declare function constant<const T>(value: T): Constructor<T>;
|
|
|
71
81
|
*
|
|
72
82
|
* class UserService {
|
|
73
83
|
* constructor(private db: Database) {}
|
|
74
|
-
* static init
|
|
75
|
-
* return new UserService(box.get(Database));
|
|
76
|
-
* }
|
|
84
|
+
* static init = Box.init(UserService).get(Database);
|
|
77
85
|
* }
|
|
78
86
|
*
|
|
79
87
|
* const box = new Box();
|
|
@@ -81,14 +89,12 @@ declare function constant<const T>(value: T): Constructor<T>;
|
|
|
81
89
|
* const db = box.get(Database);
|
|
82
90
|
*
|
|
83
91
|
* console.log(service.db === db); // true (cached)
|
|
84
|
-
* console.log(box.new(Database) === db); // false (transient)
|
|
85
92
|
* ```
|
|
86
93
|
*/
|
|
87
94
|
declare class Box {
|
|
88
|
-
|
|
95
|
+
protected cache: Map<Constructor<any>, any>;
|
|
89
96
|
/**
|
|
90
|
-
* Creates a new
|
|
91
|
-
* that should not be shared.
|
|
97
|
+
* Creates a new instance without caching.
|
|
92
98
|
*/
|
|
93
99
|
new<T extends Constructor<any>>(constructor: T): ConstructorInstanceType<T>;
|
|
94
100
|
/**
|
|
@@ -104,7 +110,7 @@ declare class Box {
|
|
|
104
110
|
*
|
|
105
111
|
* Intended to be used inside a class's `static init` method. The instance
|
|
106
112
|
* returned by the builder is never cached itself, but can be cached when
|
|
107
|
-
* the class is retrieved via {@link Box.get} or
|
|
113
|
+
* the class is retrieved via {@link Box.get} or new via {@link Box.new}.
|
|
108
114
|
*/
|
|
109
115
|
for<T extends ClassConstructor<any>>(constructor: T): Construct<T>;
|
|
110
116
|
/**
|
|
@@ -136,17 +142,17 @@ declare class BoxAll {
|
|
|
136
142
|
private box;
|
|
137
143
|
constructor(box: Box);
|
|
138
144
|
/**
|
|
139
|
-
* Resolves each constructor as a
|
|
145
|
+
* Resolves each constructor as a new instance via {@link Box.new}.
|
|
140
146
|
* Accepts an array or object of constructors and returns instances in the same shape.
|
|
141
147
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
148
|
+
new<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
149
|
+
new<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
144
150
|
/**
|
|
145
|
-
* Resolves each constructor as a
|
|
151
|
+
* Resolves each constructor as a cached instance via {@link Box.get}.
|
|
146
152
|
* Accepts an array or object of constructors and returns instances in the same shape.
|
|
147
153
|
*/
|
|
148
|
-
|
|
149
|
-
|
|
154
|
+
get<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
155
|
+
get<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
|
|
150
156
|
}
|
|
151
157
|
/** Builder for creating class instances with constructor dependencies resolved from a {@link Box}. */
|
|
152
158
|
declare class Construct<T extends ClassConstructor<any>> {
|
|
@@ -154,10 +160,10 @@ declare class Construct<T extends ClassConstructor<any>> {
|
|
|
154
160
|
private construct;
|
|
155
161
|
constructor(box: Box, construct: T);
|
|
156
162
|
/**
|
|
157
|
-
* Resolves each dependency as a new
|
|
163
|
+
* Resolves each dependency as a new instance via {@link Box.new},
|
|
158
164
|
* meaning dependencies are not cached or shared.
|
|
159
165
|
*
|
|
160
|
-
* The returned instance is cached or
|
|
166
|
+
* The returned instance is cached or new depending on whether the
|
|
161
167
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
162
168
|
*
|
|
163
169
|
* @example
|
|
@@ -175,7 +181,7 @@ declare class Construct<T extends ClassConstructor<any>> {
|
|
|
175
181
|
* Resolves each dependency as a cached instance via {@link Box.get},
|
|
176
182
|
* meaning dependencies are shared across the box.
|
|
177
183
|
*
|
|
178
|
-
* The returned instance is cached or
|
|
184
|
+
* The returned instance is cached or new depending on whether the
|
|
179
185
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
180
186
|
*
|
|
181
187
|
* @example
|
|
@@ -198,11 +204,11 @@ declare class StaticConstruct<T extends ClassConstructor<any>> {
|
|
|
198
204
|
private construct;
|
|
199
205
|
constructor(construct: T);
|
|
200
206
|
/**
|
|
201
|
-
* Resolves each dependency as a new
|
|
207
|
+
* Resolves each dependency as a new instance via {@link Box.new},
|
|
202
208
|
* meaning dependencies are not cached or shared.
|
|
203
209
|
* Returns a function compatible with `static init` that can be assigned directly.
|
|
204
210
|
*
|
|
205
|
-
* The returned instance is cached or
|
|
211
|
+
* The returned instance is cached or new depending on whether the
|
|
206
212
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
207
213
|
*
|
|
208
214
|
* @example
|
|
@@ -219,7 +225,7 @@ declare class StaticConstruct<T extends ClassConstructor<any>> {
|
|
|
219
225
|
* meaning dependencies are shared across the box.
|
|
220
226
|
* Returns a function compatible with `static init` that can be assigned directly.
|
|
221
227
|
*
|
|
222
|
-
* The returned instance is cached or
|
|
228
|
+
* The returned instance is cached or new depending on whether the
|
|
223
229
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
224
230
|
*
|
|
225
231
|
* @example
|
|
@@ -239,4 +245,4 @@ type ClassConstructor<T> = {
|
|
|
239
245
|
/** Maps each constructor parameter to its corresponding {@link Constructor} type. */
|
|
240
246
|
type ClassConstructorArgs<T extends ClassConstructor<any>, Args = ConstructorParameters<T>> = { [K in keyof Args]: Constructor<Args[K]> };
|
|
241
247
|
//#endregion
|
|
242
|
-
export { Box, Construct, Constructor, ConstructorInstanceType, StaticConstruct, constant, factory, transient };
|
|
248
|
+
export { Box, Construct, Constructor, ConstructorInstanceType, StaticConstruct, constant, derive, factory, transient };
|
package/dist/index.mjs
CHANGED
|
@@ -17,25 +17,37 @@ function factory(init) {
|
|
|
17
17
|
}
|
|
18
18
|
const noCacheSymbol = Symbol("Box.noCache");
|
|
19
19
|
/**
|
|
20
|
-
* Creates a {@link Constructor}
|
|
21
|
-
* The factory is called on every resolution, always returning a fresh value
|
|
22
|
-
* even when retrieved via {@link Box.get}.
|
|
20
|
+
* Creates a {@link Constructor} that computes a value from the box without caching the result.
|
|
23
21
|
*
|
|
24
22
|
* @example
|
|
25
23
|
* ```ts
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
24
|
+
* class Config {
|
|
25
|
+
* baseUrl = "https://example.com";
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* const RequestContext = derive((box) => ({
|
|
29
|
+
* baseUrl: box.get(Config).baseUrl,
|
|
30
|
+
* timestamp: Date.now(),
|
|
31
|
+
* }));
|
|
32
|
+
*
|
|
33
|
+
* const ctx1 = box.get(RequestContext);
|
|
34
|
+
* const ctx2 = box.get(RequestContext);
|
|
35
|
+
* console.log(ctx1 === ctx2); // false
|
|
30
36
|
* ```
|
|
31
37
|
*/
|
|
32
|
-
function
|
|
38
|
+
function derive(init) {
|
|
33
39
|
return {
|
|
34
40
|
init,
|
|
35
41
|
[noCacheSymbol]: true
|
|
36
42
|
};
|
|
37
43
|
}
|
|
38
44
|
/**
|
|
45
|
+
* @deprecated Use {@link derive} instead.
|
|
46
|
+
*/
|
|
47
|
+
function transient(init) {
|
|
48
|
+
return derive(init);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
39
51
|
* Creates a {@link Constructor} that always resolves to the given constant value.
|
|
40
52
|
* Constant values are never cached since they are already fixed.
|
|
41
53
|
*
|
|
@@ -68,9 +80,7 @@ function constant(value) {
|
|
|
68
80
|
*
|
|
69
81
|
* class UserService {
|
|
70
82
|
* constructor(private db: Database) {}
|
|
71
|
-
* static init
|
|
72
|
-
* return new UserService(box.get(Database));
|
|
73
|
-
* }
|
|
83
|
+
* static init = Box.init(UserService).get(Database);
|
|
74
84
|
* }
|
|
75
85
|
*
|
|
76
86
|
* const box = new Box();
|
|
@@ -78,14 +88,12 @@ function constant(value) {
|
|
|
78
88
|
* const db = box.get(Database);
|
|
79
89
|
*
|
|
80
90
|
* console.log(service.db === db); // true (cached)
|
|
81
|
-
* console.log(box.new(Database) === db); // false (transient)
|
|
82
91
|
* ```
|
|
83
92
|
*/
|
|
84
93
|
var Box = class {
|
|
85
94
|
cache = /* @__PURE__ */ new Map();
|
|
86
95
|
/**
|
|
87
|
-
* Creates a new
|
|
88
|
-
* that should not be shared.
|
|
96
|
+
* Creates a new instance without caching.
|
|
89
97
|
*/
|
|
90
98
|
new(constructor) {
|
|
91
99
|
return "init" in constructor ? constructor.init(this) : new constructor();
|
|
@@ -108,7 +116,7 @@ var Box = class {
|
|
|
108
116
|
*
|
|
109
117
|
* Intended to be used inside a class's `static init` method. The instance
|
|
110
118
|
* returned by the builder is never cached itself, but can be cached when
|
|
111
|
-
* the class is retrieved via {@link Box.get} or
|
|
119
|
+
* the class is retrieved via {@link Box.get} or new via {@link Box.new}.
|
|
112
120
|
*/
|
|
113
121
|
for(constructor) {
|
|
114
122
|
return new Construct(this, constructor);
|
|
@@ -149,18 +157,18 @@ var BoxAll = class {
|
|
|
149
157
|
constructor(box) {
|
|
150
158
|
this.box = box;
|
|
151
159
|
}
|
|
152
|
-
get(constructors) {
|
|
153
|
-
if (Array.isArray(constructors)) return constructors.map((c) => this.box.get(c));
|
|
154
|
-
const result = {};
|
|
155
|
-
for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.get(constructor);
|
|
156
|
-
return result;
|
|
157
|
-
}
|
|
158
160
|
new(constructors) {
|
|
159
161
|
if (Array.isArray(constructors)) return constructors.map((c) => this.box.new(c));
|
|
160
162
|
const result = {};
|
|
161
163
|
for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.new(constructor);
|
|
162
164
|
return result;
|
|
163
165
|
}
|
|
166
|
+
get(constructors) {
|
|
167
|
+
if (Array.isArray(constructors)) return constructors.map((c) => this.box.get(c));
|
|
168
|
+
const result = {};
|
|
169
|
+
for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.get(constructor);
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
164
172
|
};
|
|
165
173
|
/** Builder for creating class instances with constructor dependencies resolved from a {@link Box}. */
|
|
166
174
|
var Construct = class {
|
|
@@ -169,10 +177,10 @@ var Construct = class {
|
|
|
169
177
|
this.construct = construct;
|
|
170
178
|
}
|
|
171
179
|
/**
|
|
172
|
-
* Resolves each dependency as a new
|
|
180
|
+
* Resolves each dependency as a new instance via {@link Box.new},
|
|
173
181
|
* meaning dependencies are not cached or shared.
|
|
174
182
|
*
|
|
175
|
-
* The returned instance is cached or
|
|
183
|
+
* The returned instance is cached or new depending on whether the
|
|
176
184
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
177
185
|
*
|
|
178
186
|
* @example
|
|
@@ -193,7 +201,7 @@ var Construct = class {
|
|
|
193
201
|
* Resolves each dependency as a cached instance via {@link Box.get},
|
|
194
202
|
* meaning dependencies are shared across the box.
|
|
195
203
|
*
|
|
196
|
-
* The returned instance is cached or
|
|
204
|
+
* The returned instance is cached or new depending on whether the
|
|
197
205
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
198
206
|
*
|
|
199
207
|
* @example
|
|
@@ -220,11 +228,11 @@ var StaticConstruct = class {
|
|
|
220
228
|
this.construct = construct;
|
|
221
229
|
}
|
|
222
230
|
/**
|
|
223
|
-
* Resolves each dependency as a new
|
|
231
|
+
* Resolves each dependency as a new instance via {@link Box.new},
|
|
224
232
|
* meaning dependencies are not cached or shared.
|
|
225
233
|
* Returns a function compatible with `static init` that can be assigned directly.
|
|
226
234
|
*
|
|
227
|
-
* The returned instance is cached or
|
|
235
|
+
* The returned instance is cached or new depending on whether the
|
|
228
236
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
229
237
|
*
|
|
230
238
|
* @example
|
|
@@ -246,7 +254,7 @@ var StaticConstruct = class {
|
|
|
246
254
|
* meaning dependencies are shared across the box.
|
|
247
255
|
* Returns a function compatible with `static init` that can be assigned directly.
|
|
248
256
|
*
|
|
249
|
-
* The returned instance is cached or
|
|
257
|
+
* The returned instance is cached or new depending on whether the
|
|
250
258
|
* class is retrieved via {@link Box.get} or {@link Box.new}.
|
|
251
259
|
*
|
|
252
260
|
* @example
|
|
@@ -266,4 +274,4 @@ var StaticConstruct = class {
|
|
|
266
274
|
};
|
|
267
275
|
|
|
268
276
|
//#endregion
|
|
269
|
-
export { Box, Construct, StaticConstruct, constant, factory, transient };
|
|
277
|
+
export { Box, Construct, StaticConstruct, constant, derive, factory, transient };
|