ditox 3.2.0 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -27
- package/dist/index.cjs +531 -0
- package/dist/index.cjs.map +1 -0
- package/dist/{umd/index.d.ts → index.d.cts} +191 -196
- package/dist/{browser/index.d.ts → index.d.ts} +191 -196
- package/dist/index.js +514 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.js +537 -0
- package/dist/index.umd.js.map +1 -0
- package/package.json +22 -20
- package/src/container.test.ts +77 -33
- package/src/container.ts +26 -11
- package/src/index.ts +22 -24
- package/src/modules.test.ts +190 -37
- package/src/modules.ts +22 -5
- package/src/removal-compatibility.test.ts +259 -0
- package/src/removal.test.ts +190 -0
- package/src/tokens.test.ts +9 -8
- package/src/tokens.ts +2 -2
- package/src/utils.test.ts +18 -17
- package/src/utils.ts +21 -21
- package/dist/browser/index.js +0 -2
- package/dist/browser/index.js.map +0 -1
- package/dist/cjs/container.d.ts +0 -93
- package/dist/cjs/container.js +0 -216
- package/dist/cjs/container.js.map +0 -1
- package/dist/cjs/index.d.ts +0 -7
- package/dist/cjs/index.js +0 -24
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/modules.d.ts +0 -121
- package/dist/cjs/modules.js +0 -143
- package/dist/cjs/modules.js.map +0 -1
- package/dist/cjs/tokens.d.ts +0 -56
- package/dist/cjs/tokens.js +0 -20
- package/dist/cjs/tokens.js.map +0 -1
- package/dist/cjs/utils.d.ts +0 -137
- package/dist/cjs/utils.js +0 -156
- package/dist/cjs/utils.js.map +0 -1
- package/dist/esm/container.d.ts +0 -93
- package/dist/esm/container.js +0 -211
- package/dist/esm/container.js.map +0 -1
- package/dist/esm/index.d.ts +0 -7
- package/dist/esm/index.js +0 -5
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/modules.d.ts +0 -121
- package/dist/esm/modules.js +0 -136
- package/dist/esm/modules.js.map +0 -1
- package/dist/esm/tokens.d.ts +0 -56
- package/dist/esm/tokens.js +0 -15
- package/dist/esm/tokens.js.map +0 -1
- package/dist/esm/utils.d.ts +0 -137
- package/dist/esm/utils.js +0 -145
- package/dist/esm/utils.js.map +0 -1
- package/dist/umd/index.js +0 -2
- package/dist/umd/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -20,11 +20,12 @@ You can use the following command to install this package:
|
|
|
20
20
|
npm install --save ditox
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
The package can be used as [UMD](https://github.com/umdjs/umd) module. Use
|
|
23
|
+
The package can be used as an [UMD](https://github.com/umdjs/umd) module. Use
|
|
24
24
|
[jsdelivr.com](https://jsdelivr.com) CDN site to load
|
|
25
25
|
[ditox](https://www.jsdelivr.com/package/npm/ditox):
|
|
26
26
|
|
|
27
27
|
```html
|
|
28
|
+
|
|
28
29
|
<script src="//cdn.jsdelivr.net/npm/ditox/dist/umd/index.js"></script>
|
|
29
30
|
<script>
|
|
30
31
|
const container = Ditox.createContainer();
|
|
@@ -33,8 +34,8 @@ The package can be used as [UMD](https://github.com/umdjs/umd) module. Use
|
|
|
33
34
|
|
|
34
35
|
## General description
|
|
35
36
|
|
|
36
|
-
DI pattern in general allows
|
|
37
|
-
application. It can be described by following phases:
|
|
37
|
+
DI pattern in general allows declaring and construct a code graph of an
|
|
38
|
+
application. It can be described by the following phases:
|
|
38
39
|
|
|
39
40
|
1. Code declaration phase:
|
|
40
41
|
|
|
@@ -59,15 +60,18 @@ Diagram:
|
|
|
59
60
|
## Usage Example
|
|
60
61
|
|
|
61
62
|
```js
|
|
62
|
-
import {createContainer, injectable, optional, token} from 'ditox';
|
|
63
|
+
import { createContainer, injectable, optional, token } from 'ditox';
|
|
63
64
|
|
|
64
65
|
// This is app code, some factory functions and classes:
|
|
65
|
-
function createStorage(config) {
|
|
66
|
+
function createStorage(config) {
|
|
67
|
+
}
|
|
66
68
|
|
|
67
|
-
function createLogger(config) {
|
|
69
|
+
function createLogger(config) {
|
|
70
|
+
}
|
|
68
71
|
|
|
69
72
|
class UserService {
|
|
70
|
-
constructor(storage, logger) {
|
|
73
|
+
constructor(storage, logger) {
|
|
74
|
+
}
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
// Define tokens for injections.
|
|
@@ -76,13 +80,13 @@ const LOGGER_TOKEN = token();
|
|
|
76
80
|
const USER_SERVICE_TOKEN = token();
|
|
77
81
|
|
|
78
82
|
// Token can be optional with a default value.
|
|
79
|
-
const STORAGE_CONFIG_TOKEN = optional(token(), {name: 'default storage'});
|
|
83
|
+
const STORAGE_CONFIG_TOKEN = optional(token(), { name: 'default storage' });
|
|
80
84
|
|
|
81
85
|
// Create the container.
|
|
82
86
|
const container = createContainer();
|
|
83
87
|
|
|
84
88
|
// Provide a value to the container.
|
|
85
|
-
container.bindValue(STORAGE_CONFIG_TOKEN, {name: 'custom storage'});
|
|
89
|
+
container.bindValue(STORAGE_CONFIG_TOKEN, { name: 'custom storage' });
|
|
86
90
|
|
|
87
91
|
// Dynamic values are provided by factories.
|
|
88
92
|
|
|
@@ -94,7 +98,7 @@ container.bindFactory(
|
|
|
94
98
|
);
|
|
95
99
|
|
|
96
100
|
// A factory can have `transient` lifetime to create a value on each resolving.
|
|
97
|
-
container.bindFactory(LOGGER_TOKEN, createLogger, {scope: 'transient'});
|
|
101
|
+
container.bindFactory(LOGGER_TOKEN, createLogger, { scope: 'transient' });
|
|
98
102
|
|
|
99
103
|
// A class can be injected by `injectableClass()` which calls its constructor
|
|
100
104
|
// with injected dependencies as arguments.
|
|
@@ -128,13 +132,40 @@ container.remove(LOGGER_TOKEN);
|
|
|
128
132
|
container.removeAll();
|
|
129
133
|
```
|
|
130
134
|
|
|
135
|
+
### Errors during bulk cleanup
|
|
136
|
+
|
|
137
|
+
`removeAll()` continues visiting factories after an `onRemoved` callback or a
|
|
138
|
+
cleanup options accessor throws. It clears local bindings and restores internal
|
|
139
|
+
tokens before rethrowing the first thrown value unchanged, including non-`Error`
|
|
140
|
+
values. Later errors are discarded. The container can be reused after cleanup;
|
|
141
|
+
a subsequent `removeAll()` does not retry callbacks for the cleared bindings.
|
|
142
|
+
|
|
143
|
+
Bindings remain available to callbacks until explicitly removed or cleared at
|
|
144
|
+
the end. Cleanup does not resolve unused factories or dispose transient values
|
|
145
|
+
or values owned by a parent container. A failing callback must handle its own
|
|
146
|
+
internal cleanup; the container cannot resume execution inside it.
|
|
147
|
+
|
|
148
|
+
`remove(token)` retains its existing behavior: if its callback throws, the binding
|
|
149
|
+
remains and removal can be retried. This also applies to single-module removal
|
|
150
|
+
when `destroy()` throws.
|
|
151
|
+
|
|
152
|
+
Reentrant removal and mutation retain the existing live traversal behavior.
|
|
153
|
+
Nested removals run immediately and can invoke a callback more than once.
|
|
154
|
+
New factory entries appended during traversal can be visited. Replacing an
|
|
155
|
+
existing entry without deleting it does not revisit an already visited key;
|
|
156
|
+
deleting and reinserting it appends a new entry that can be visited again.
|
|
157
|
+
This fix does not add recursion guards or guarantee cleanup of every value
|
|
158
|
+
created during callbacks. Callbacks must
|
|
159
|
+
avoid unbounded recursive removal or endlessly adding bindings. Cleanup remains
|
|
160
|
+
synchronous; returned promises are not awaited.
|
|
161
|
+
|
|
131
162
|
## Container Hierarchy
|
|
132
163
|
|
|
133
164
|
Ditox.js supports a "parent-child" hierarchy. If the child container cannot
|
|
134
165
|
resolve a token, it asks the parent container to resolve it:
|
|
135
166
|
|
|
136
167
|
```js
|
|
137
|
-
import {createContainer, token} from 'ditox';
|
|
168
|
+
import { createContainer, token } from 'ditox';
|
|
138
169
|
|
|
139
170
|
const V1_TOKEN = token();
|
|
140
171
|
const V2_TOKEN = token();
|
|
@@ -157,7 +188,7 @@ creating a container. During resolution, parents are queried from left to right,
|
|
|
157
188
|
and the first parent that provides the token wins.
|
|
158
189
|
|
|
159
190
|
```js
|
|
160
|
-
import {createContainer, token} from 'ditox';
|
|
191
|
+
import { createContainer, token } from 'ditox';
|
|
161
192
|
|
|
162
193
|
const VALUE = token();
|
|
163
194
|
|
|
@@ -182,8 +213,8 @@ child2.resolve(VALUE); // 'from-child'
|
|
|
182
213
|
|
|
183
214
|
## Factory Lifetimes
|
|
184
215
|
|
|
185
|
-
Ditox.js supports managing the lifetime of values which
|
|
186
|
-
|
|
216
|
+
Ditox.js supports managing the lifetime of values which factories produce. There
|
|
217
|
+
are the following types:
|
|
187
218
|
|
|
188
219
|
- `singleton` - **This is the default**. The value is created and cached by the
|
|
189
220
|
most distant parent container which owns the factory function.
|
|
@@ -193,11 +224,11 @@ factories. There are the following types:
|
|
|
193
224
|
|
|
194
225
|
### `singleton`
|
|
195
226
|
|
|
196
|
-
**This is the default scope**. "Singleton" allows
|
|
227
|
+
**This is the default scope**. "Singleton" allows caching a produced value by a
|
|
197
228
|
most distant parent container which registered the factory function:
|
|
198
229
|
|
|
199
230
|
```js
|
|
200
|
-
import {createContainer, token} from 'ditox';
|
|
231
|
+
import { createContainer, token } from 'ditox';
|
|
201
232
|
|
|
202
233
|
const TAG_TOKEN = token();
|
|
203
234
|
const LOGGER_TOKEN = token();
|
|
@@ -223,12 +254,12 @@ container2.resolve(LOGGER_TOKEN)('bar'); // [parent] bar
|
|
|
223
254
|
|
|
224
255
|
### `scoped`
|
|
225
256
|
|
|
226
|
-
"Scoped" lifetime allows
|
|
257
|
+
"Scoped" lifetime allows having sub-containers with own instances of some
|
|
227
258
|
services which can be disposed. For example, a context during HTTP request
|
|
228
|
-
handling, or
|
|
259
|
+
handling, or another unit of work:
|
|
229
260
|
|
|
230
261
|
```js
|
|
231
|
-
import {createContainer, token} from 'ditox';
|
|
262
|
+
import { createContainer, token } from 'ditox';
|
|
232
263
|
|
|
233
264
|
const TAG_TOKEN = token();
|
|
234
265
|
const LOGGER_TOKEN = token();
|
|
@@ -260,7 +291,7 @@ container1.removeAll();
|
|
|
260
291
|
"Transient" makes the factory produce a new value for each resolution:
|
|
261
292
|
|
|
262
293
|
```js
|
|
263
|
-
import {createContainer, token} from 'ditox';
|
|
294
|
+
import { createContainer, token } from 'ditox';
|
|
264
295
|
|
|
265
296
|
const TAG_TOKEN = token();
|
|
266
297
|
const LOGGER_TOKEN = token();
|
|
@@ -293,14 +324,22 @@ Dependencies can be organized as modules in declarative way with
|
|
|
293
324
|
`ModuleDeclaration`. It is useful for providing pieces of functionality from
|
|
294
325
|
libraries to an app which depends on them.
|
|
295
326
|
|
|
327
|
+
The `strategy` field determines when the module's factory is executed:
|
|
328
|
+
|
|
329
|
+
- `lazy` (**default**): The factory is called only when the module or its
|
|
330
|
+
exported tokens are first resolved.
|
|
331
|
+
- `eager`: The factory is called immediately after the module is bound to the
|
|
332
|
+
container. This is useful for modules that need to initialize listeners or
|
|
333
|
+
start background processes right away.
|
|
334
|
+
|
|
296
335
|
```typescript
|
|
297
|
-
import {Module, ModuleDeclaration, token} from 'ditox';
|
|
298
|
-
import {TRANSPORT_TOKEN} from './transport';
|
|
336
|
+
import { Module, ModuleDeclaration, token } from 'ditox';
|
|
337
|
+
import { TRANSPORT_TOKEN } from './transport';
|
|
299
338
|
|
|
300
|
-
export type Logger = {log: (message: string) => void};
|
|
339
|
+
export type Logger = { log: (message: string) => void };
|
|
301
340
|
export const LOGGER_TOKEN = token<Logger>();
|
|
302
341
|
|
|
303
|
-
type LoggerModule = Module<{logger: Logger}>;
|
|
342
|
+
type LoggerModule = Module<{ logger: Logger }>;
|
|
304
343
|
|
|
305
344
|
const LOGGER_MODULE_TOKEN = token<LoggerModule>();
|
|
306
345
|
|
|
@@ -308,10 +347,13 @@ const LOGGER_MODULE: ModuleDeclaration<LoggerModule> = {
|
|
|
308
347
|
// An optional explicit token for a module itself
|
|
309
348
|
token: LOGGER_MODULE_TOKEN,
|
|
310
349
|
|
|
350
|
+
// Use "eager" strategy to initialize the module immediately after binding
|
|
351
|
+
strategy: 'eager',
|
|
352
|
+
|
|
311
353
|
factory: (container) => {
|
|
312
354
|
const transport = container.resolve(TRANSPORT_TOKEN).open();
|
|
313
355
|
return {
|
|
314
|
-
logger: {log: (message) => transport.write(message)},
|
|
356
|
+
logger: { log: (message) => transport.write(message) },
|
|
315
357
|
destroy: () => transport.close(),
|
|
316
358
|
};
|
|
317
359
|
},
|
|
@@ -419,13 +461,20 @@ const APP_MODULE = declareModuleBindings([LOGGER_MODULE, DATABASE_MODULE]);
|
|
|
419
461
|
- Types
|
|
420
462
|
- Module<Props = {}> — a module object: exported values plus optional
|
|
421
463
|
destroy(): void
|
|
422
|
-
- ModuleDeclaration<T extends Module> — declarative description of a module
|
|
464
|
+
- ModuleDeclaration<T extends Module> — declarative description of a module:
|
|
465
|
+
- token: Token<T> — required token
|
|
466
|
+
- imports?: ReadonlyArray<ModuleBindingEntry> — optional imports
|
|
467
|
+
- factory: (container: Container) => T — factory function
|
|
468
|
+
- exports?: Dictionary — optional exported tokens
|
|
469
|
+
- beforeBinding?: (container: Container) => void — optional callback
|
|
470
|
+
- afterBinding?: (container: Container) => void — optional callback
|
|
471
|
+
- strategy?: 'eager' | 'lazy' — execution strategy (default: 'lazy')
|
|
423
472
|
- BindModuleOptions — { scope?: 'scoped' | 'singleton' }
|
|
424
473
|
- ModuleBindingEntry — ModuleDeclaration or { module, options }
|
|
425
474
|
- bindModule(container: Container, module: ModuleDeclaration<T>, options?:
|
|
426
475
|
BindModuleOptions): void
|
|
427
476
|
- Binds a module; exported values are bound via factories; module factory
|
|
428
|
-
respects scope; calls destroy() and removes exports on
|
|
477
|
+
respects scope; calls destroy() and removes exports on unbinding
|
|
429
478
|
- bindModules(container: Container, modules:
|
|
430
479
|
ReadonlyArray<ModuleBindingEntry>): void — binds multiple modules
|
|
431
480
|
- declareModule(declaration): ModuleDeclaration<T>
|