ditox 3.1.0 → 3.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.
Files changed (53) hide show
  1. package/README.md +135 -32
  2. package/dist/index.cjs +518 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/{umd/index.d.ts → index.d.cts} +195 -197
  5. package/dist/{browser/index.d.ts → index.d.ts} +195 -197
  6. package/dist/index.js +501 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index.umd.js +524 -0
  9. package/dist/index.umd.js.map +1 -0
  10. package/package.json +22 -19
  11. package/src/container.test.ts +34 -33
  12. package/src/container.ts +12 -6
  13. package/src/index.ts +26 -23
  14. package/src/modules.test.ts +172 -37
  15. package/src/modules.ts +22 -5
  16. package/src/tokens.test.ts +9 -8
  17. package/src/tokens.ts +2 -2
  18. package/src/utils.test.ts +18 -17
  19. package/src/utils.ts +21 -21
  20. package/dist/browser/index.js +0 -2
  21. package/dist/browser/index.js.map +0 -1
  22. package/dist/cjs/container.d.ts +0 -88
  23. package/dist/cjs/container.js +0 -216
  24. package/dist/cjs/container.js.map +0 -1
  25. package/dist/cjs/index.d.ts +0 -7
  26. package/dist/cjs/index.js +0 -24
  27. package/dist/cjs/index.js.map +0 -1
  28. package/dist/cjs/modules.d.ts +0 -121
  29. package/dist/cjs/modules.js +0 -143
  30. package/dist/cjs/modules.js.map +0 -1
  31. package/dist/cjs/tokens.d.ts +0 -56
  32. package/dist/cjs/tokens.js +0 -20
  33. package/dist/cjs/tokens.js.map +0 -1
  34. package/dist/cjs/utils.d.ts +0 -137
  35. package/dist/cjs/utils.js +0 -156
  36. package/dist/cjs/utils.js.map +0 -1
  37. package/dist/esm/container.d.ts +0 -88
  38. package/dist/esm/container.js +0 -211
  39. package/dist/esm/container.js.map +0 -1
  40. package/dist/esm/index.d.ts +0 -7
  41. package/dist/esm/index.js +0 -5
  42. package/dist/esm/index.js.map +0 -1
  43. package/dist/esm/modules.d.ts +0 -121
  44. package/dist/esm/modules.js +0 -136
  45. package/dist/esm/modules.js.map +0 -1
  46. package/dist/esm/tokens.d.ts +0 -56
  47. package/dist/esm/tokens.js +0 -15
  48. package/dist/esm/tokens.js.map +0 -1
  49. package/dist/esm/utils.d.ts +0 -137
  50. package/dist/esm/utils.js +0 -145
  51. package/dist/esm/utils.js.map +0 -1
  52. package/dist/umd/index.js +0 -2
  53. package/dist/umd/index.js.map +0 -1
package/README.md CHANGED
@@ -9,7 +9,7 @@ Please see the documentation at [ditox.js.org](https://ditox.js.org)
9
9
  [![npm](https://img.shields.io/npm/v/ditox)](https://www.npmjs.com/package/ditox)
10
10
  [![stars](https://img.shields.io/github/stars/mnasyrov/ditox)](https://github.com/mnasyrov/ditox/stargazers)
11
11
  [![types](https://img.shields.io/npm/types/ditox)](https://www.npmjs.com/package/ditox)
12
- [![licence](https://img.shields.io/github/license/mnasyrov/ditox)](https://github.com/mnasyrov/ditox/blob/master/LICENSE)
12
+ [![license](https://img.shields.io/github/license/mnasyrov/ditox)](https://github.com/mnasyrov/ditox/blob/master/LICENSE)
13
13
  [![coverage](https://coveralls.io/repos/github/mnasyrov/ditox/badge)](https://coveralls.io/github/mnasyrov/ditox)
14
14
 
15
15
  ## Installation
@@ -20,12 +20,13 @@ 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
- <script src="//cdn.jsdelivr.net/npm/ditox/dist/umd/index.js" />
28
+
29
+ <script src="//cdn.jsdelivr.net/npm/ditox/dist/umd/index.js"></script>
29
30
  <script>
30
31
  const container = Ditox.createContainer();
31
32
  </script>
@@ -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 to declare and construct a code graph of an
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,30 +60,33 @@ 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.
74
- const STORAGE_TOKEN = token < UserService > 'Token description for debugging';
78
+ const STORAGE_TOKEN = token('Token description for debugging');
75
79
  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.
@@ -130,11 +134,11 @@ container.removeAll();
130
134
 
131
135
  ## Container Hierarchy
132
136
 
133
- Ditox.js supports "parent-child" hierarchy. If the child container cannot to
137
+ Ditox.js supports a "parent-child" hierarchy. If the child container cannot
134
138
  resolve a token, it asks the parent container to resolve it:
135
139
 
136
140
  ```js
137
- import {creatContainer, token} from 'ditox';
141
+ import { createContainer, token } from 'ditox';
138
142
 
139
143
  const V1_TOKEN = token();
140
144
  const V2_TOKEN = token();
@@ -157,7 +161,7 @@ creating a container. During resolution, parents are queried from left to right,
157
161
  and the first parent that provides the token wins.
158
162
 
159
163
  ```js
160
- import {createContainer, token} from 'ditox';
164
+ import { createContainer, token } from 'ditox';
161
165
 
162
166
  const VALUE = token();
163
167
 
@@ -182,8 +186,8 @@ child2.resolve(VALUE); // 'from-child'
182
186
 
183
187
  ## Factory Lifetimes
184
188
 
185
- Ditox.js supports managing the lifetime of values which are produced by
186
- factories. There are the following types:
189
+ Ditox.js supports managing the lifetime of values which factories produce. There
190
+ are the following types:
187
191
 
188
192
  - `singleton` - **This is the default**. The value is created and cached by the
189
193
  most distant parent container which owns the factory function.
@@ -193,11 +197,11 @@ factories. There are the following types:
193
197
 
194
198
  ### `singleton`
195
199
 
196
- **This is the default scope**. "Singleton" allows to cache a produced value by a
200
+ **This is the default scope**. "Singleton" allows caching a produced value by a
197
201
  most distant parent container which registered the factory function:
198
202
 
199
203
  ```js
200
- import {creatContainer, token} from 'ditox';
204
+ import { createContainer, token } from 'ditox';
201
205
 
202
206
  const TAG_TOKEN = token();
203
207
  const LOGGER_TOKEN = token();
@@ -223,12 +227,12 @@ container2.resolve(LOGGER_TOKEN)('bar'); // [parent] bar
223
227
 
224
228
  ### `scoped`
225
229
 
226
- "Scoped" lifetime allows to have sub-containers with own instances of some
230
+ "Scoped" lifetime allows having sub-containers with own instances of some
227
231
  services which can be disposed. For example, a context during HTTP request
228
- handling, or other unit of work:
232
+ handling, or another unit of work:
229
233
 
230
234
  ```js
231
- import {creatContainer, token} from 'ditox';
235
+ import { createContainer, token } from 'ditox';
232
236
 
233
237
  const TAG_TOKEN = token();
234
238
  const LOGGER_TOKEN = token();
@@ -257,10 +261,10 @@ container1.removeAll();
257
261
 
258
262
  ### `transient`
259
263
 
260
- "Transient" makes to a produce values by the factory for each resolving:
264
+ "Transient" makes the factory produce a new value for each resolution:
261
265
 
262
266
  ```js
263
- import {createContainer, token} from 'ditox';
267
+ import { createContainer, token } from 'ditox';
264
268
 
265
269
  const TAG_TOKEN = token();
266
270
  const LOGGER_TOKEN = token();
@@ -293,14 +297,22 @@ Dependencies can be organized as modules in declarative way with
293
297
  `ModuleDeclaration`. It is useful for providing pieces of functionality from
294
298
  libraries to an app which depends on them.
295
299
 
300
+ The `strategy` field determines when the module's factory is executed:
301
+
302
+ - `lazy` (**default**): The factory is called only when the module or its
303
+ exported tokens are first resolved.
304
+ - `eager`: The factory is called immediately after the module is bound to the
305
+ container. This is useful for modules that need to initialize listeners or
306
+ start background processes right away.
307
+
296
308
  ```typescript
297
- import {Module, ModuleDeclaration, token} from 'ditox';
298
- import {TRANSPORT_TOKEN} from './transport';
309
+ import { Module, ModuleDeclaration, token } from 'ditox';
310
+ import { TRANSPORT_TOKEN } from './transport';
299
311
 
300
- export type Logger = {log: (message: string) => void};
312
+ export type Logger = { log: (message: string) => void };
301
313
  export const LOGGER_TOKEN = token<Logger>();
302
314
 
303
- type LoggerModule = Module<{logger: Logger}>;
315
+ type LoggerModule = Module<{ logger: Logger }>;
304
316
 
305
317
  const LOGGER_MODULE_TOKEN = token<LoggerModule>();
306
318
 
@@ -308,10 +320,13 @@ const LOGGER_MODULE: ModuleDeclaration<LoggerModule> = {
308
320
  // An optional explicit token for a module itself
309
321
  token: LOGGER_MODULE_TOKEN,
310
322
 
323
+ // Use "eager" strategy to initialize the module immediately after binding
324
+ strategy: 'eager',
325
+
311
326
  factory: (container) => {
312
327
  const transport = container.resolve(TRANSPORT_TOKEN).open();
313
328
  return {
314
- logger: {log: (message) => transport.write(message)},
329
+ logger: { log: (message) => transport.write(message) },
315
330
  destroy: () => transport.close(),
316
331
  };
317
332
  },
@@ -329,7 +344,7 @@ const container = createContainer();
329
344
  // bind a single module
330
345
  bindModule(container, LOGGER_MODULE);
331
346
 
332
- // or bind multiple depenendency modules
347
+ // or bind multiple dependency modules
333
348
  bindModules(container, [DATABASE_MODULE, CONFIG_MODULE, API_MODULE]);
334
349
  ```
335
350
 
@@ -350,9 +365,97 @@ const LOGGER_MODULE = declareModule<LoggerModule>({
350
365
  },
351
366
  });
352
367
 
353
- const APP_MODULE = declareModuleBinding([LOGGER_MODULE, DATABASE_MODULE]);
368
+ const APP_MODULE = declareModuleBindings([LOGGER_MODULE, DATABASE_MODULE]);
354
369
  ```
355
370
 
371
+ ## API Reference
372
+
373
+ - Tokens
374
+
375
+ - token<T>(options?: { key?: string; description?: string } | string):
376
+ Token<T>
377
+ - Creates a new binding token. Use `key` to create shareable tokens via
378
+ `Symbol.for(key)`; otherwise a descriptive `Symbol(description)` is
379
+ created
380
+ - optional<T>(token: Token<T>, optionalValue?: T): OptionalToken<T |
381
+ undefined>
382
+ - Marks the token as optional and provides a default value for resolution
383
+ when not bound
384
+ - Types: Token<T>, RequiredToken<T>, OptionalToken<T>
385
+
386
+ - Container
387
+
388
+ - createContainer(parent?: Container | ReadonlyArray<Container>): Container
389
+ - Creates a new container optionally linked to one or more parents; parents
390
+ are queried left-to-right
391
+ - class ResolverError extends Error
392
+ - Thrown by `resolve()` when a token is not found and no optional default
393
+ exists
394
+ - type FactoryScope = 'scoped' | 'singleton' | 'transient'
395
+ - type FactoryOptions<T>
396
+ - For 'scoped' | 'singleton': { scope?: 'scoped' | 'singleton'; onRemoved?:
397
+ (value: T) => void }
398
+ - For 'transient': { scope: 'transient' }
399
+ - type Container API
400
+ - bindValue<T>(token: Token<T>, value: T): void — bind a concrete value
401
+ - bindFactory<T>(token: Token<T>, factory: (container: Container) => T,
402
+ options?: FactoryOptions<T>): void — bind a factory with lifetime options
403
+ - hasToken(token: Token<unknown>): boolean — check token presence in
404
+ hierarchy
405
+ - get<T>(token: Token<T>): T | undefined — try resolve or return undefined;
406
+ optional tokens return their default
407
+ - resolve<T>(token: Token<T>): T — resolve or throw ResolverError; optional
408
+ tokens return their default
409
+ - remove<T>(token: Token<T>): void — remove binding; for scoped/singleton
410
+ factories calls `onRemoved` if provided
411
+ - removeAll(): void — remove all bindings and call `onRemoved` for
412
+ applicable factories
413
+
414
+ - Utilities
415
+
416
+ - isToken<T>(value: unknown): value is Token<T> — checks if a value looks like
417
+ a token
418
+ - bindMultiValue<T>(container: Container, token: Token<ReadonlyArray<T>>,
419
+ value: T): void — appends a value to an array token
420
+ - tryResolveValue(container: Container, tokenOrMap): value | object — resolves
421
+ or returns undefined for missing tokens; supports an object map of tokens
422
+ - tryResolveValues(container: Container, ...tokenOrMaps): array — batched
423
+ variant of tryResolveValue
424
+ - resolveValue(container: Container, tokenOrMap): value | object — resolves or
425
+ throws on missing tokens; supports an object map of tokens
426
+ - resolveValues(container: Container, ...tokenOrMaps): array — batched variant
427
+ of resolveValue
428
+ - injectable(factory, ...tokens): (container: Container) => Result — decorates
429
+ a factory to receive resolved values as arguments
430
+ - injectableClass(Class, ...tokens): (container: Container) => Instance —
431
+ decorates a class constructor to receive resolved values
432
+
433
+ - Modules
434
+ - Types
435
+ - Module<Props = {}> — a module object: exported values plus optional
436
+ destroy(): void
437
+ - ModuleDeclaration<T extends Module> — declarative description of a module:
438
+ - token: Token<T> — required token
439
+ - imports?: ReadonlyArray<ModuleBindingEntry> — optional imports
440
+ - factory: (container: Container) => T — factory function
441
+ - exports?: Dictionary — optional exported tokens
442
+ - beforeBinding?: (container: Container) => void — optional callback
443
+ - afterBinding?: (container: Container) => void — optional callback
444
+ - strategy?: 'eager' | 'lazy' — execution strategy (default: 'lazy')
445
+ - BindModuleOptions — { scope?: 'scoped' | 'singleton' }
446
+ - ModuleBindingEntry — ModuleDeclaration or { module, options }
447
+ - bindModule(container: Container, module: ModuleDeclaration<T>, options?:
448
+ BindModuleOptions): void
449
+ - Binds a module; exported values are bound via factories; module factory
450
+ respects scope; calls destroy() and removes exports on unbinding
451
+ - bindModules(container: Container, modules:
452
+ ReadonlyArray<ModuleBindingEntry>): void — binds multiple modules
453
+ - declareModule(declaration): ModuleDeclaration<T>
454
+ - Creates a module declaration; generates a token if not provided
455
+ - declareModuleBindings(modules: ReadonlyArray<ModuleBindingEntry>):
456
+ ModuleDeclaration<Module>
457
+ - Declares an anonymous module that binds the provided modules
458
+
356
459
  ---
357
460
 
358
461
  This project is licensed under the