@rs-x/state-manager 0.4.11 → 0.4.12

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 CHANGED
@@ -7,9 +7,9 @@ A context can be an object, and an index can be a property name — but it is no
7
7
 
8
8
  Examples of state indexes:
9
9
 
10
- - Object property or field → index = property or field name
11
- - Array item → index = numeric position
12
- - Map item → index = map key
10
+ - Object property or field → index = property or field name
11
+ - Array item → index = numeric position
12
+ - Map item → index = map key
13
13
 
14
14
  The State Manager does **not** automatically know how to detect changes for every state value data type, nor how to patch the corresponding state setter. Therefore, it relies on two services:
15
15
 
@@ -19,45 +19,38 @@ The State Manager does **not** automatically know how to detect changes for ever
19
19
  - A service implementing `IIndexValueAccessor`
20
20
  Responsible for retrieving the current value.
21
21
 
22
-
23
22
  The **State Manager** has the followng interface:
23
+
24
24
  ```ts
25
25
  export interface IStateManager {
26
- readonly changed: Observable<IStateChange>;
27
- readonly contextChanged: Observable<IContextChanged>;
28
- readonly startChangeCycle: Observable<void>;
29
- readonly endChangeCycle: Observable<void>;
30
-
31
- isWatched(
32
- context: unknown,
33
- index: unknown,
34
- mustProxify: MustProxify
35
- ): boolean;
36
-
37
- watchState(
38
- context: unknown,
39
- index: unknown,
40
- mustProxify?: MustProxify
41
- ): unknown;
42
-
43
- releaseState(
44
- oontext: unknown,
45
- index: unknown,
46
- mustProxify?: MustProxify
47
- ): void;
48
-
49
- getState<T>(
50
- context: unknown,
51
- index: unknown
52
- ): T;
53
-
54
- setState<T>(
55
- context: unknown,
56
- index: unknown,
57
- value: T
58
- ): void;
59
-
60
- clear(): void;
26
+ readonly changed: Observable<IStateChange>;
27
+ readonly contextChanged: Observable<IContextChanged>;
28
+ readonly startChangeCycle: Observable<void>;
29
+ readonly endChangeCycle: Observable<void>;
30
+
31
+ isWatched(
32
+ context: unknown,
33
+ index: unknown,
34
+ mustProxify: MustProxify,
35
+ ): boolean;
36
+
37
+ watchState(
38
+ context: unknown,
39
+ index: unknown,
40
+ mustProxify?: MustProxify,
41
+ ): unknown;
42
+
43
+ releaseState(
44
+ oontext: unknown,
45
+ index: unknown,
46
+ mustProxify?: MustProxify,
47
+ ): void;
48
+
49
+ getState<T>(context: unknown, index: unknown): T;
50
+
51
+ setState<T>(context: unknown, index: unknown, value: T): void;
52
+
53
+ clear(): void;
61
54
  }
62
55
  ```
63
56
 
@@ -66,12 +59,14 @@ export interface IStateManager {
66
59
  ## Members
67
60
 
68
61
  ### **changed**
62
+
69
63
  **Type:** `Observable<IStateChange>`
70
64
  Emits whenever a state item value changes.
71
65
 
72
66
  ---
73
67
 
74
68
  ### **contextChanged**
69
+
75
70
  **Type:** `Observable<IContextChanged>`
76
71
  Emits whenever an entire context is replaced.
77
72
  This happens, for example, when a nested object is replaced.
@@ -79,38 +74,42 @@ This happens, for example, when a nested object is replaced.
79
74
  ---
80
75
 
81
76
  ### **startChangeCycle**
77
+
82
78
  **Type:** `Observable<void>`
83
79
  Emits at the start of processing a state item change.
84
80
 
85
81
  ---
86
82
 
87
83
  ### **endChangeCycle**
84
+
88
85
  **Type:** `Observable<void>`
89
86
  Emits at the end of processing a state item change.
90
87
 
91
88
  ---
92
89
 
93
90
  ### **isWatched(context, index, mustProxify)**
91
+
94
92
  Returns whether the state item identified by the `(context, index, mustProxify)` triplet is currently being watched.
95
93
 
96
- | Parameter | Type | Description |
97
- | --------------- | -------------------------- | --------------------------------------------------------------- |
98
- | **context** | `unknown` | The context to which the state index belongs. |
99
- | **index** | `unknown` | The index identifying the state on the given context. |
100
- | **mustProxify** | `MustProxify` *(optional)* | Predicate determining whether a nested state value must be proxified. It should be the same predicate that was passed to `watchState`. |
94
+ | Parameter | Type | Description |
95
+ | --------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
96
+ | **context** | `unknown` | The context to which the state index belongs. |
97
+ | **index** | `unknown` | The index identifying the state on the given context. |
98
+ | **mustProxify** | `MustProxify` _(optional)_ | Predicate determining whether a nested state value must be proxified. It should be the same predicate that was passed to `watchState`. |
101
99
 
102
100
  **Returns:** `boolean`
103
101
 
104
102
  ---
105
103
 
106
104
  ### **watchState(context, index, mustProxify?)**
105
+
107
106
  Watches a state item identified by the `(context, index, mustProxify)` triplet so that its value is proxified and tracked.
108
107
 
109
- | Parameter | Type | Description |
110
- | --------------- | -------------------------- | --------------------------------------------------------------- |
111
- | **context** | `unknown` | The state context. |
112
- | **index** | `unknown` | The index identifying the state on the given context. |
113
- | **mustProxify** | `MustProxify` *(optional)* | Predicate determining whether a nested state value must be proxified.|
108
+ | Parameter | Type | Description |
109
+ | --------------- | -------------------------- | --------------------------------------------------------------------- |
110
+ | **context** | `unknown` | The state context. |
111
+ | **index** | `unknown` | The index identifying the state on the given context. |
112
+ | **mustProxify** | `MustProxify` _(optional)_ | Predicate determining whether a nested state value must be proxified. |
114
113
 
115
114
  **Returns:**
116
115
  `unknown` — the state item value if it was already being watched; otherwise `undefined`.
@@ -118,46 +117,50 @@ Watches a state item identified by the `(context, index, mustProxify)` triplet s
118
117
  ---
119
118
 
120
119
  ### **releaseState(context, index, mustProxify?)**
120
+
121
121
  Releases the state item identified by the `(context, index, mustProxify)` triplet.
122
122
  Each call to `watchState` should have a corresponding `releaseState` call to ensure the state item is released when it is no longer needed.
123
123
 
124
- | Parameter | Type | Description |
125
- | --------------- | -------------------------- | --------------------------------------------------------------- |
126
- | **context** | `unknown` | The state context. |
127
- | **index** | `unknown` | The index identifying the state on the given context. |
128
- | **mustProxify** | `MustProxify` *(optional)* | Predicate determining whether a nested state value must be proxified. It should be the same predicate that was passed to `watchState`. . |
124
+ | Parameter | Type | Description |
125
+ | --------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
126
+ | **context** | `unknown` | The state context. |
127
+ | **index** | `unknown` | The index identifying the state on the given context. |
128
+ | **mustProxify** | `MustProxify` _(optional)_ | Predicate determining whether a nested state value must be proxified. It should be the same predicate that was passed to `watchState`. . |
129
129
 
130
130
  **Returns:** `void`
131
131
 
132
132
  ---
133
133
 
134
134
  ### **getState(context, index)**
135
+
135
136
  Retrieves the current state item value identified by the `(context, index)` pair.
136
137
 
137
- | Parameter | Type | Description |
138
- | ----------- | --------- | --------------------------------------------------------------- |
139
- | **context** | `unknown` | The state context. |
140
- | **index** | `unknown` | The index identifying the state on the given context. |
138
+ | Parameter | Type | Description |
139
+ | ----------- | --------- | ----------------------------------------------------- |
140
+ | **context** | `unknown` | The state context. |
141
+ | **index** | `unknown` | The index identifying the state on the given context. |
141
142
 
142
143
  **Returns:** `unknown`
143
144
 
144
145
  ---
145
146
 
146
147
  ### **setState(context, index, value)**
148
+
147
149
  Sets the value of the state item identified by the `(context, index)` pair.
148
150
 
149
151
  Unlike `watchState`, `setState` does **not** track changes. It does not patch setters or proxify values.
150
152
  A change event is emitted on the first `setState` call and again whenever the value changes in subsequent calls.
151
153
 
152
- | Parameter | Type | Description |
153
- | ----------- | --------- | --------------------------------------------------------------- |
154
- | **context** | `unknown` | The state context. |
155
- | **index** | `unknown` | The index identifying the state on the given context. |
156
- | **value** | `unknown` | The state value. |
154
+ | Parameter | Type | Description |
155
+ | ----------- | --------- | ----------------------------------------------------- |
156
+ | **context** | `unknown` | The state context. |
157
+ | **index** | `unknown` | The index identifying the state on the given context. |
158
+ | **value** | `unknown` | The state value. |
157
159
 
158
160
  ---
159
161
 
160
162
  ### **clear()**
163
+
161
164
  Releases all registered state items.
162
165
 
163
166
  **Returns:** `void`
@@ -183,10 +186,13 @@ There are two ways to get an instance:
183
186
 
184
187
  ```ts
185
188
  import { InjectionContainer } from '@rs-x/core';
186
- import { IIStateManager, RsXStateManagerInjectionTokens } from '@rs-x/state-manager';
189
+ import {
190
+ IIStateManager,
191
+ RsXStateManagerInjectionTokens,
192
+ } from '@rs-x/state-manager';
187
193
 
188
194
  const stateManager: IIStateManager = InjectionContainer.get(
189
- RsXStateManagerInjectionTokens.IStateManager
195
+ RsXStateManagerInjectionTokens.IStateManager,
190
196
  );
191
197
  ```
192
198
 
@@ -194,14 +200,16 @@ const stateManager: IIStateManager = InjectionContainer.get(
194
200
 
195
201
  ```ts
196
202
  import { Inject } from '@rs-x/core';
197
- import { IIStateManager, RsXStateManagerInjectionTokens } from '@rs-x/state-manager';
203
+ import {
204
+ IIStateManager,
205
+ RsXStateManagerInjectionTokens,
206
+ } from '@rs-x/state-manager';
198
207
 
199
208
  export class MyClass {
200
-
201
- constructor(
202
- @Inject(RsXStateManagerInjectionTokens.IStateManager)
203
- private readonly _stateManager: IIStateManager
204
- ) {}
209
+ constructor(
210
+ @Inject(RsXStateManagerInjectionTokens.IStateManager)
211
+ private readonly _stateManager: IIStateManager,
212
+ ) {}
205
213
  }
206
214
  ```
207
215
 
@@ -211,60 +219,61 @@ export class MyClass {
211
219
 
212
220
  There are two variants:
213
221
 
214
- ### Non-recursive
222
+ ### Non-recursive
223
+
215
224
  Monitors only assignment of a **new value** to the index.
216
225
 
217
226
  ```ts
218
227
  import { InjectionContainer, printValue } from '@rs-x/core';
219
228
  import {
220
- IStateChange,
221
- IStateManager,
222
- RsXStateManagerInjectionTokens,
223
- RsXStateManagerModule
229
+ IStateChange,
230
+ IStateManager,
231
+ RsXStateManagerInjectionTokens,
232
+ RsXStateManagerModule,
224
233
  } from '@rs-x/state-manager';
225
234
 
226
235
  // Load the state manager module into the injection container
227
236
  InjectionContainer.load(RsXStateManagerModule);
228
237
 
229
238
  export const run = (() => {
230
- const stateManager: IStateManager = InjectionContainer.get(
231
- RsXStateManagerInjectionTokens.IStateManager
232
- );
233
-
234
- const stateContext = {
235
- x: { y: 10 }
239
+ const stateManager: IStateManager = InjectionContainer.get(
240
+ RsXStateManagerInjectionTokens.IStateManager,
241
+ );
242
+
243
+ const stateContext = {
244
+ x: { y: 10 },
245
+ };
246
+
247
+ // This will emit a change event with the initial (current) value.
248
+ console.log('Initial value:');
249
+ const changedSubsription = stateManager.changed.subscribe(
250
+ (change: IStateChange) => {
251
+ printValue(change.newValue);
252
+ },
253
+ );
254
+
255
+ try {
256
+ // This will emit the new value { y: 10 }
257
+ stateManager.watchState(stateContext, 'x');
258
+
259
+ console.log('Changed value:');
260
+ // This will emit the new value { y: 10 }
261
+ stateContext.x = {
262
+ y: 20,
236
263
  };
237
264
 
238
- // This will emit a change event with the initial (current) value.
239
- console.log('Initial value:');
240
- const changedSubsription = stateManager.changed.subscribe((change: IStateChange) => {
241
- printValue(change.newValue);
242
- });
243
-
244
- try {
245
- // This will emit the new value { y: 10 }
246
- stateManager.watchState(stateContext, 'x');
247
-
248
- console.log('Changed value:');
249
- // This will emit the new value { y: 10 }
250
- stateContext.x = {
251
- y: 20
252
- };
253
-
254
- console.log(`Latest value:`);
255
- printValue(stateManager.getState(stateContext, 'x'));
256
-
257
- // This will emit no change because the state is not recursive.
258
- console.log('\nstateContext.x.y = 30 will not emit any change:\n---\n');
259
- stateContext.x.y = 30;
260
-
261
- } finally {
262
- changedSubsription.unsubscribe();
263
- // Always release the state when it is no longer needed.
264
- stateManager.releaseState(stateContext, 'x');
265
- }
265
+ console.log(`Latest value:`);
266
+ printValue(stateManager.getState(stateContext, 'x'));
267
+
268
+ // This will emit no change because the state is not recursive.
269
+ console.log('\nstateContext.x.y = 30 will not emit any change:\n---\n');
270
+ stateContext.x.y = 30;
271
+ } finally {
272
+ changedSubsription.unsubscribe();
273
+ // Always release the state when it is no longer needed.
274
+ stateManager.releaseState(stateContext, 'x');
275
+ }
266
276
  })();
267
-
268
277
  ```
269
278
 
270
279
  **Output:**
@@ -290,61 +299,63 @@ stateContext.x.y = 30 will not emit any change:
290
299
 
291
300
  ---
292
301
 
293
- ### Recursive
294
- Monitors assignments **and** changes *inside* the value.
302
+ ### Recursive
303
+
304
+ Monitors assignments **and** changes _inside_ the value.
295
305
  Example: if the value is an object, internal object changes are also observed. You can make a state item recursive by passing in a **mustProxify** predicate to a **watchState** call. The mustProxify will be called for every nested index. If you return true it will watch the index otherwise not.
296
306
 
297
307
  ```ts
298
308
  import { InjectionContainer, printValue, truePredicate } from '@rs-x/core';
299
309
  import {
300
- IStateChange,
301
- IStateManager,
302
- RsXStateManagerInjectionTokens,
303
- RsXStateManagerModule
310
+ IStateChange,
311
+ IStateManager,
312
+ RsXStateManagerInjectionTokens,
313
+ RsXStateManagerModule,
304
314
  } from '@rs-x/state-manager';
305
315
 
306
316
  // Load the state manager module into the injection container
307
317
  InjectionContainer.load(RsXStateManagerModule);
308
318
 
309
319
  export const run = (() => {
310
- const stateManager: IStateManager = InjectionContainer.get(
311
- RsXStateManagerInjectionTokens.IStateManager
312
- );
313
- const stateContext = {
314
- x: { y: 10 }
315
- };
316
- const changedSubscription = stateManager.changed.subscribe((change: IStateChange) => {
317
- printValue(change.newValue)
318
- });
319
-
320
- try {
321
- // We register recursive state by passing
322
- // a predicate as the third argument.
323
- // In this case, we want to watch the entire value,
324
- // so we pass a predicate that always returns true.
325
- // This will emit an initial value { y: 10 }
326
- console.log('Initial value:');
327
- stateManager.watchState(stateContext, 'x', truePredicate);
328
-
329
- console.log('Changed value:');
330
- // This will emit the new value { y: 10 }
331
- stateContext.x = {
332
- y: 20
333
- };
334
-
335
- console.log('Changed (recursive) value:');
336
- // This will emit the new value { y: 30 } because x
337
- // is registered as a recursive state.
338
- stateContext.x.y = 30;
320
+ const stateManager: IStateManager = InjectionContainer.get(
321
+ RsXStateManagerInjectionTokens.IStateManager,
322
+ );
323
+ const stateContext = {
324
+ x: { y: 10 },
325
+ };
326
+ const changedSubscription = stateManager.changed.subscribe(
327
+ (change: IStateChange) => {
328
+ printValue(change.newValue);
329
+ },
330
+ );
331
+
332
+ try {
333
+ // We register recursive state by passing
334
+ // a predicate as the third argument.
335
+ // In this case, we want to watch the entire value,
336
+ // so we pass a predicate that always returns true.
337
+ // This will emit an initial value { y: 10 }
338
+ console.log('Initial value:');
339
+ stateManager.watchState(stateContext, 'x', truePredicate);
339
340
 
340
- console.log(`Latest value:`);
341
- printValue(stateManager.getState(stateContext, 'x'));
341
+ console.log('Changed value:');
342
+ // This will emit the new value { y: 10 }
343
+ stateContext.x = {
344
+ y: 20,
345
+ };
342
346
 
343
- } finally {
344
- changedSubscription.unsubscribe();
345
- // Always release the state when it is no longer needed.
346
- stateManager.releaseState(stateContext, 'x', truePredicate);
347
- }
347
+ console.log('Changed (recursive) value:');
348
+ // This will emit the new value { y: 30 } because x
349
+ // is registered as a recursive state.
350
+ stateContext.x.y = 30;
351
+
352
+ console.log(`Latest value:`);
353
+ printValue(stateManager.getState(stateContext, 'x'));
354
+ } finally {
355
+ changedSubscription.unsubscribe();
356
+ // Always release the state when it is no longer needed.
357
+ stateManager.releaseState(stateContext, 'x', truePredicate);
358
+ }
348
359
  })();
349
360
  ```
350
361
 
@@ -370,82 +381,87 @@ Besides that you can register a watched stated (calling `watchedState`) you can
370
381
  ```ts
371
382
  import { InjectionContainer, printValue } from '@rs-x/core';
372
383
  import {
373
- IStateChange,
374
- IStateManager,
375
- RsXStateManagerInjectionTokens,
376
- RsXStateManagerModule
384
+ IStateChange,
385
+ IStateManager,
386
+ RsXStateManagerInjectionTokens,
387
+ RsXStateManagerModule,
377
388
  } from '@rs-x/state-manager';
378
389
 
379
390
  // Load the state manager module into the injection container
380
391
  InjectionContainer.load(RsXStateManagerModule);
381
392
 
382
393
  export const run = (() => {
383
- const stateManager: IStateManager = InjectionContainer.get(
384
- RsXStateManagerInjectionTokens.IStateManager
385
- );
386
-
387
- class StateContext {
388
- private readonly _aPlusBId = 'a+b';
389
- private _a = 10;
390
- private _b = 20;
394
+ const stateManager: IStateManager = InjectionContainer.get(
395
+ RsXStateManagerInjectionTokens.IStateManager,
396
+ );
391
397
 
392
- constructor() {
393
- this.setAPlusB();
394
- }
398
+ class StateContext {
399
+ private readonly _aPlusBId = 'a+b';
400
+ private _a = 10;
401
+ private _b = 20;
395
402
 
396
- public dispose(): void {
397
- return stateManager.releaseState(this, this._aPlusBId);
398
- }
403
+ constructor() {
404
+ this.setAPlusB();
405
+ }
399
406
 
400
- public get aPlusB(): number {
401
- return stateManager.getState(this, this._aPlusBId);
402
- }
407
+ public dispose(): void {
408
+ return stateManager.releaseState(this, this._aPlusBId);
409
+ }
403
410
 
404
- public get a(): number {
405
- return this._a;
406
- }
411
+ public get aPlusB(): number {
412
+ return stateManager.getState(this, this._aPlusBId);
413
+ }
407
414
 
408
- public set a(value: number) {
409
- this._a = value;
410
- this.setAPlusB();
411
- }
415
+ public get a(): number {
416
+ return this._a;
417
+ }
412
418
 
413
- public get b(): number {
414
- return this._b;
415
- }
419
+ public set a(value: number) {
420
+ this._a = value;
421
+ this.setAPlusB();
422
+ }
416
423
 
417
- public set b(value: number) {
418
- this._b = value;
419
- this.setAPlusB();
420
- }
424
+ public get b(): number {
425
+ return this._b;
426
+ }
421
427
 
422
- private setAPlusB(): void {
423
- stateManager.setState(this, this._aPlusBId, this._a + this._b)
424
- }
428
+ public set b(value: number) {
429
+ this._b = value;
430
+ this.setAPlusB();
425
431
  }
426
432
 
427
- const stateContext = new StateContext();
428
- const changeSubscription = stateManager.changed.subscribe((change: IStateChange) => {
429
- printValue(change.newValue);
430
- });
433
+ private setAPlusB(): void {
434
+ stateManager.setState(this, this._aPlusBId, this._a + this._b);
435
+ }
436
+ }
431
437
 
432
- try {
433
- console.log(`Initial value for readonly property 'aPlusB':`);
434
- console.log(stateContext.aPlusB);
438
+ const stateContext = new StateContext();
439
+ const changeSubscription = stateManager.changed.subscribe(
440
+ (change: IStateChange) => {
441
+ printValue(change.newValue);
442
+ },
443
+ );
435
444
 
436
- console.log(`set 'stateContext.a' to '100' will emit a change event for readonly property 'aPlusB'`);
437
- console.log(`Changed value for readonly property 'aPlusB':`);
438
- stateContext.a = 100;
445
+ try {
446
+ console.log(`Initial value for readonly property 'aPlusB':`);
447
+ console.log(stateContext.aPlusB);
439
448
 
440
- console.log(`set 'stateContext.b' to '200' will emit a change event for readonly property 'aPlusB'`);
441
- console.log(`Changed value for readonly property 'aPlusB':`);
442
- stateContext.b = 200;
449
+ console.log(
450
+ `set 'stateContext.a' to '100' will emit a change event for readonly property 'aPlusB'`,
451
+ );
452
+ console.log(`Changed value for readonly property 'aPlusB':`);
453
+ stateContext.a = 100;
443
454
 
444
- } finally {
445
- changeSubscription.unsubscribe();
446
- // Always release the state when it is no longer needed.
447
- stateContext.dispose();
448
- }
455
+ console.log(
456
+ `set 'stateContext.b' to '200' will emit a change event for readonly property 'aPlusB'`,
457
+ );
458
+ console.log(`Changed value for readonly property 'aPlusB':`);
459
+ stateContext.b = 200;
460
+ } finally {
461
+ changeSubscription.unsubscribe();
462
+ // Always release the state when it is no longer needed.
463
+ stateContext.dispose();
464
+ }
449
465
  })();
450
466
  ```
451
467
 
@@ -476,52 +492,57 @@ When done, release the state:
476
492
  ```ts
477
493
  import { InjectionContainer, printValue } from '@rs-x/core';
478
494
  import {
479
- IStateChange,
480
- IStateManager,
481
- RsXStateManagerInjectionTokens,
482
- RsXStateManagerModule
495
+ IStateChange,
496
+ IStateManager,
497
+ RsXStateManagerInjectionTokens,
498
+ RsXStateManagerModule,
483
499
  } from '@rs-x/state-manager';
484
500
 
485
501
  // Load the state manager module into the injection container
486
502
  InjectionContainer.load(RsXStateManagerModule);
487
503
 
488
504
  export const run = (() => {
489
- const stateManager: IStateManager = InjectionContainer.get(
490
- RsXStateManagerInjectionTokens.IStateManager
491
- );
492
- const stateContext = {
493
- x: { y: 10 }
494
- };
495
- const changedSubscription = stateManager.changed.subscribe((change: IStateChange) => {
496
- printValue(change.newValue);
497
- });
498
-
499
- try {
500
- // Register is idempotent: you can register the same state multiple times.
501
- // For every register call, make sure you call unregister when you're done.
502
- console.log('Initial value:');
503
- stateManager.watchState(stateContext, 'x');
504
- stateManager.watchState(stateContext, 'x');
505
-
506
- console.log('Changed value:');
507
- stateContext.x = { y: 20 };
505
+ const stateManager: IStateManager = InjectionContainer.get(
506
+ RsXStateManagerInjectionTokens.IStateManager,
507
+ );
508
+ const stateContext = {
509
+ x: { y: 10 },
510
+ };
511
+ const changedSubscription = stateManager.changed.subscribe(
512
+ (change: IStateChange) => {
513
+ printValue(change.newValue);
514
+ },
515
+ );
516
+
517
+ try {
518
+ // Register is idempotent: you can register the same state multiple times.
519
+ // For every register call, make sure you call unregister when you're done.
520
+ console.log('Initial value:');
521
+ stateManager.watchState(stateContext, 'x');
522
+ stateManager.watchState(stateContext, 'x');
508
523
 
509
- stateManager.releaseState(stateContext, 'x');
524
+ console.log('Changed value:');
525
+ stateContext.x = { y: 20 };
510
526
 
511
- console.log('Changed event is still emitted after unregister because one observer remains.');
512
- console.log('Changed value:');
513
- stateContext.x = { y: 30 };
527
+ stateManager.releaseState(stateContext, 'x');
514
528
 
515
- stateManager.releaseState(stateContext, 'x');
529
+ console.log(
530
+ 'Changed event is still emitted after unregister because one observer remains.',
531
+ );
532
+ console.log('Changed value:');
533
+ stateContext.x = { y: 30 };
516
534
 
517
- console.log('Changed event is no longer emitted after the last observer unregisters.');
518
- console.log('Changed value:');
519
- console.log('---');
520
- stateContext.x = { y: 30 };
535
+ stateManager.releaseState(stateContext, 'x');
521
536
 
522
- } finally {
523
- changedSubscription.unsubscribe();
524
- }
537
+ console.log(
538
+ 'Changed event is no longer emitted after the last observer unregisters.',
539
+ );
540
+ console.log('Changed value:');
541
+ console.log('---');
542
+ stateContext.x = { y: 30 };
543
+ } finally {
544
+ changedSubscription.unsubscribe();
545
+ }
525
546
  })();
526
547
  ```
527
548
 
@@ -560,7 +581,7 @@ You can override this factory list by providing your own custom provider service
560
581
  | Observable | Not indexable | Subscribe | [example](#observable) |
561
582
  | Custom type | user defined | user defined | [example](#customtype) |
562
583
 
563
- State item is identified by a **context**, **index** and **mustProxify** predicate for a recursive state item
584
+ State item is identified by a **context**, **index** and **mustProxify** predicate for a recursive state item
564
585
  The manager checks each observer factory to determine support based on the **context** and **index**.
565
586
 
566
587
  Behavior:
@@ -571,86 +592,93 @@ Behavior:
571
592
  The following example illustrates the different state types:
572
593
 
573
594
  ### Object property/field
595
+
574
596
  **Example**
597
+
575
598
  ```ts
576
599
  import { InjectionContainer, printValue, truePredicate } from '@rs-x/core';
577
600
  import {
578
- IStateChange,
579
- IStateManager,
580
- RsXStateManagerInjectionTokens,
581
- RsXStateManagerModule
601
+ IStateChange,
602
+ IStateManager,
603
+ RsXStateManagerInjectionTokens,
604
+ RsXStateManagerModule,
582
605
  } from '@rs-x/state-manager';
583
606
 
584
607
  // Load the state manager module into the injection container
585
608
  InjectionContainer.load(RsXStateManagerModule);
586
609
 
587
610
  interface INestStateConext {
588
- a: number;
589
- nested?: INestStateConext;
611
+ a: number;
612
+ nested?: INestStateConext;
590
613
  }
591
614
 
592
615
  class StateContext {
593
- private _b: INestStateConext = {
594
- a: 10,
616
+ private _b: INestStateConext = {
617
+ a: 10,
618
+ nested: {
619
+ a: 20,
620
+ nested: {
621
+ a: 30,
595
622
  nested: {
596
- a: 20,
597
- nested: {
598
- a: 30,
599
- nested: {
600
- a: 40
601
- }
602
- }
603
- }
604
- };
605
-
606
- public get b(): INestStateConext {
607
- return this._b;
608
- }
609
-
610
- public set b(value: INestStateConext) {
611
- this._b = value;
612
- }
623
+ a: 40,
624
+ },
625
+ },
626
+ },
627
+ };
628
+
629
+ public get b(): INestStateConext {
630
+ return this._b;
631
+ }
632
+
633
+ public set b(value: INestStateConext) {
634
+ this._b = value;
635
+ }
613
636
  }
614
637
 
615
638
  export const run = (() => {
616
- const stateManager: IStateManager = InjectionContainer.get(
617
- RsXStateManagerInjectionTokens.IStateManager
618
- );
639
+ const stateManager: IStateManager = InjectionContainer.get(
640
+ RsXStateManagerInjectionTokens.IStateManager,
641
+ );
619
642
 
620
- const stateContext = new StateContext();
643
+ const stateContext = new StateContext();
621
644
 
622
- const changeSubscription = stateManager.changed.subscribe((change: IStateChange) => {
623
- printValue(change.newValue);
624
- });
625
-
626
- try {
627
- // Observe property `b` recursively.
628
- // Otherwise, only assigning a new value to stateContext.b would emit a change event.
629
- // This will emit a change event with the initial (current) value.
630
- console.log('Initial value:');
631
- stateManager.watchState(stateContext, 'b', truePredicate);
645
+ const changeSubscription = stateManager.changed.subscribe(
646
+ (change: IStateChange) => {
647
+ printValue(change.newValue);
648
+ },
649
+ );
632
650
 
633
- console.log('\nReplacing stateContext.b.nested.nested will emit a change event');
634
- console.log('Changed value:');
651
+ try {
652
+ // Observe property `b` recursively.
653
+ // Otherwise, only assigning a new value to stateContext.b would emit a change event.
654
+ // This will emit a change event with the initial (current) value.
655
+ console.log('Initial value:');
656
+ stateManager.watchState(stateContext, 'b', truePredicate);
635
657
 
636
- stateContext.b.nested.nested = {
637
- a: -30,
638
- nested: {
639
- a: -40
640
- }
641
- };
658
+ console.log(
659
+ '\nReplacing stateContext.b.nested.nested will emit a change event',
660
+ );
661
+ console.log('Changed value:');
642
662
 
643
- console.log(`Latest value:`);
644
- printValue(stateManager.getState(stateContext, 'b'));
663
+ stateContext.b.nested.nested = {
664
+ a: -30,
665
+ nested: {
666
+ a: -40,
667
+ },
668
+ };
645
669
 
646
- } finally {
647
- changeSubscription.unsubscribe();
648
- // Always release the state when it is no longer needed.
649
- stateManager.releaseState(stateContext, 'b', truePredicate);
650
- }
670
+ console.log(`Latest value:`);
671
+ printValue(stateManager.getState(stateContext, 'b'));
672
+ } finally {
673
+ changeSubscription.unsubscribe();
674
+ // Always release the state when it is no longer needed.
675
+ stateManager.releaseState(stateContext, 'b', truePredicate);
676
+ }
651
677
  })();
652
678
  ```
679
+
653
680
  **Output:**
681
+
654
682
  ```console
655
683
  Running demo: /Users/robertsanders/projects/rs-x/demo/src/rs-x-state-manager/register-property.ts
656
684
  Initial value:
@@ -697,86 +725,97 @@ Latest value:
697
725
  ```
698
726
 
699
727
  ### Date
728
+
700
729
  **Example**
730
+
701
731
  ```ts
702
732
  import { InjectionContainer, truePredicate, utCDate } from '@rs-x/core';
703
733
  import {
704
- IProxyRegistry,
705
- IStateChange,
706
- IStateManager,
707
- RsXStateManagerInjectionTokens,
708
- RsXStateManagerModule
734
+ IProxyRegistry,
735
+ IStateChange,
736
+ IStateManager,
737
+ RsXStateManagerInjectionTokens,
738
+ RsXStateManagerModule,
709
739
  } from '@rs-x/state-manager';
710
740
 
711
741
  // Load the state manager module into the injection container
712
742
  InjectionContainer.load(RsXStateManagerModule);
713
743
 
714
744
  function watchDate(stateManager: IStateManager) {
715
- console.log('\n******************************************');
716
- console.log('* Watching date');
717
- console.log('******************************************\n');
718
-
719
- const stateContext = {
720
- date: utCDate(2021, 2, 5)
721
- };
722
- const changeSubscription = stateManager.changed.subscribe((change: IStateChange) => {
723
- console.log(`${change.key}: ${(change.newValue as Date).toUTCString()}`);
724
- });
725
- try {
726
- console.log('Initial value:');
727
- stateManager.watchState(stateContext, 'date', truePredicate);
745
+ console.log('\n******************************************');
746
+ console.log('* Watching date');
747
+ console.log('******************************************\n');
748
+
749
+ const stateContext = {
750
+ date: utCDate(2021, 2, 5),
751
+ };
752
+ const changeSubscription = stateManager.changed.subscribe(
753
+ (change: IStateChange) => {
754
+ console.log(`${change.key}: ${(change.newValue as Date).toUTCString()}`);
755
+ },
756
+ );
757
+ try {
758
+ console.log('Initial value:');
759
+ stateManager.watchState(stateContext, 'date', truePredicate);
728
760
 
729
- console.log('Changed value:');
730
- stateContext.date.setFullYear(2023);
761
+ console.log('Changed value:');
762
+ stateContext.date.setFullYear(2023);
731
763
 
732
- console.log('Set value:');
733
- stateContext.date = new Date(2024, 5, 6);
764
+ console.log('Set value:');
765
+ stateContext.date = new Date(2024, 5, 6);
734
766
 
735
- console.log('Latest value:');
736
- console.log(stateManager.getState<Date>(stateContext, 'date').toUTCString());
737
- } finally {
738
- changeSubscription.unsubscribe();
739
- // Always release the state when it is no longer needed.
740
- stateManager.releaseState(stateContext, 'date', truePredicate);
741
- }
767
+ console.log('Latest value:');
768
+ console.log(
769
+ stateManager.getState<Date>(stateContext, 'date').toUTCString(),
770
+ );
771
+ } finally {
772
+ changeSubscription.unsubscribe();
773
+ // Always release the state when it is no longer needed.
774
+ stateManager.releaseState(stateContext, 'date', truePredicate);
775
+ }
742
776
  }
743
777
 
744
778
  function watchDateProperty(stateManager: IStateManager) {
745
- console.log('\n******************************************');
746
- console.log('* Watching year');
747
- console.log('******************************************\n');
748
- const date = utCDate(2021, 2, 5);
749
- const changeSubscription = stateManager.changed.subscribe((change: IStateChange) => {
750
- console.log(change.newValue);
751
- });
752
- try {
753
- // This will emit a change event with the initial (current) value.
754
- console.log('Initial value:');
755
- stateManager.watchState(date, 'year');
756
-
757
- const proxyRegister: IProxyRegistry = InjectionContainer.get(RsXStateManagerInjectionTokens.IProxyRegistry);
758
- const dateProxy = proxyRegister.getProxy<Date>(date);
759
- console.log('Changed value:');
760
- dateProxy.setFullYear(2023);
761
-
762
- console.log('Latest value:');
763
- console.log(stateManager.getState(date, 'year'));
779
+ console.log('\n******************************************');
780
+ console.log('* Watching year');
781
+ console.log('******************************************\n');
782
+ const date = utCDate(2021, 2, 5);
783
+ const changeSubscription = stateManager.changed.subscribe(
784
+ (change: IStateChange) => {
785
+ console.log(change.newValue);
786
+ },
787
+ );
788
+ try {
789
+ // This will emit a change event with the initial (current) value.
790
+ console.log('Initial value:');
791
+ stateManager.watchState(date, 'year');
764
792
 
765
- } finally {
766
- changeSubscription.unsubscribe();
767
- stateManager.releaseState(date, 'year');
768
- }
793
+ const proxyRegister: IProxyRegistry = InjectionContainer.get(
794
+ RsXStateManagerInjectionTokens.IProxyRegistry,
795
+ );
796
+ const dateProxy = proxyRegister.getProxy<Date>(date);
797
+ console.log('Changed value:');
798
+ dateProxy.setFullYear(2023);
799
+
800
+ console.log('Latest value:');
801
+ console.log(stateManager.getState(date, 'year'));
802
+ } finally {
803
+ changeSubscription.unsubscribe();
804
+ stateManager.releaseState(date, 'year');
805
+ }
769
806
  }
770
807
 
771
808
  export const run = (() => {
772
- const stateManager: IStateManager = InjectionContainer.get(
773
- RsXStateManagerInjectionTokens.IStateManager
774
- );
775
- watchDate(stateManager);
776
- watchDateProperty(stateManager);
809
+ const stateManager: IStateManager = InjectionContainer.get(
810
+ RsXStateManagerInjectionTokens.IStateManager,
811
+ );
812
+ watchDate(stateManager);
813
+ watchDateProperty(stateManager);
777
814
  })();
778
815
  ```
816
+
779
817
  **Output:**
818
+
780
819
  ```console
781
820
  Running demo: demo/src/rs-x-state-manager/register-date.ts
782
821
 
@@ -806,54 +845,59 @@ Latest value:
806
845
  ```
807
846
 
808
847
  ### Array
848
+
809
849
  **Example**
850
+
810
851
  ```ts
811
852
  import { InjectionContainer, printValue, truePredicate } from '@rs-x/core';
812
853
  import {
813
- IStateChange,
814
- IStateManager,
815
- RsXStateManagerInjectionTokens,
816
- RsXStateManagerModule
854
+ IStateChange,
855
+ IStateManager,
856
+ RsXStateManagerInjectionTokens,
857
+ RsXStateManagerModule,
817
858
  } from '@rs-x/state-manager';
818
859
 
819
860
  // Load the state manager module into the injection container
820
861
  InjectionContainer.load(RsXStateManagerModule);
821
862
 
822
863
  export const run = (() => {
823
- const stateManager: IStateManager = InjectionContainer.get(
824
- RsXStateManagerInjectionTokens.IStateManager
825
- );
826
-
827
- const stateContext = {
828
- array: [
829
- [1, 2],
830
- [3, 4]
831
- ]
832
- };
833
-
834
- const changeSubscription = stateManager.changed.subscribe((change: IStateChange) => {
835
- printValue(change.newValue);
836
- });
837
-
838
- try {
839
- // This will emit a change event with the initial (current) value.
840
- console.log('Initial value:');
841
- stateManager.watchState(stateContext, 'array', truePredicate);
842
-
843
- console.log('Changed value:');
844
- stateContext.array[1].push(5);
864
+ const stateManager: IStateManager = InjectionContainer.get(
865
+ RsXStateManagerInjectionTokens.IStateManager,
866
+ );
867
+
868
+ const stateContext = {
869
+ array: [
870
+ [1, 2],
871
+ [3, 4],
872
+ ],
873
+ };
845
874
 
846
- console.log('Latest value:');
847
- printValue(stateManager.getState(stateContext, 'array'));
875
+ const changeSubscription = stateManager.changed.subscribe(
876
+ (change: IStateChange) => {
877
+ printValue(change.newValue);
878
+ },
879
+ );
848
880
 
849
- } finally {
850
- changeSubscription.unsubscribe();
851
- // Always release the state when it is no longer needed.
852
- stateManager.releaseState(stateContext, 'array', truePredicate);
853
- }
881
+ try {
882
+ // This will emit a change event with the initial (current) value.
883
+ console.log('Initial value:');
884
+ stateManager.watchState(stateContext, 'array', truePredicate);
885
+
886
+ console.log('Changed value:');
887
+ stateContext.array[1].push(5);
888
+
889
+ console.log('Latest value:');
890
+ printValue(stateManager.getState(stateContext, 'array'));
891
+ } finally {
892
+ changeSubscription.unsubscribe();
893
+ // Always release the state when it is no longer needed.
894
+ stateManager.releaseState(stateContext, 'array', truePredicate);
895
+ }
854
896
  })();
855
897
  ```
898
+
856
899
  **Output:**
900
+
857
901
  ```console
858
902
  Running demo: /Users/robertsanders/projects/rs-x/demo/src/rs-x-state-manager/register-array.ts
859
903
  Initial value:
@@ -894,54 +938,59 @@ Latest value:
894
938
  ```
895
939
 
896
940
  ### Map
941
+
897
942
  **Example**
943
+
898
944
  ```ts
899
945
  import { InjectionContainer, printValue, truePredicate } from '@rs-x/core';
900
946
  import {
901
- IStateChange,
902
- IStateManager,
903
- RsXStateManagerInjectionTokens,
904
- RsXStateManagerModule
947
+ IStateChange,
948
+ IStateManager,
949
+ RsXStateManagerInjectionTokens,
950
+ RsXStateManagerModule,
905
951
  } from '@rs-x/state-manager';
906
952
 
907
953
  // Load the state manager module into the injection container
908
954
  InjectionContainer.load(RsXStateManagerModule);
909
955
 
910
956
  const stateManager: IStateManager = InjectionContainer.get(
911
- RsXStateManagerInjectionTokens.IStateManager
957
+ RsXStateManagerInjectionTokens.IStateManager,
912
958
  );
913
959
 
914
960
  export const run = (() => {
915
- const stateContext = {
916
- map: new Map([
917
- ['a', [1, 2]],
918
- ['b', [3, 4]]
919
- ])
920
- };
921
-
922
- const changeSubscription = stateManager.changed.subscribe((change: IStateChange) => {
923
- printValue(change.newValue);
924
- });
925
-
926
- try {
927
- // This will emit a change event with the initial (current) value.
928
- console.log('Initial value:');
929
- stateManager.watchState(stateContext, 'map', truePredicate);
930
-
931
- console.log('Changed value:');
932
- stateContext.map.get('b').push(5);
933
-
934
- console.log('Latest value:');
935
- printValue(stateManager.getState(stateContext, 'map'))
936
-
937
- } finally {
938
- changeSubscription.unsubscribe();
939
- // Always release the state when it is no longer needed.
940
- stateManager.releaseState(stateContext, 'array', truePredicate);
941
- }
961
+ const stateContext = {
962
+ map: new Map([
963
+ ['a', [1, 2]],
964
+ ['b', [3, 4]],
965
+ ]),
966
+ };
967
+
968
+ const changeSubscription = stateManager.changed.subscribe(
969
+ (change: IStateChange) => {
970
+ printValue(change.newValue);
971
+ },
972
+ );
973
+
974
+ try {
975
+ // This will emit a change event with the initial (current) value.
976
+ console.log('Initial value:');
977
+ stateManager.watchState(stateContext, 'map', truePredicate);
978
+
979
+ console.log('Changed value:');
980
+ stateContext.map.get('b').push(5);
981
+
982
+ console.log('Latest value:');
983
+ printValue(stateManager.getState(stateContext, 'map'));
984
+ } finally {
985
+ changeSubscription.unsubscribe();
986
+ // Always release the state when it is no longer needed.
987
+ stateManager.releaseState(stateContext, 'array', truePredicate);
988
+ }
942
989
  })();
943
990
  ```
991
+
944
992
  **Output:**
993
+
945
994
  ```console
946
995
  Running demo: /Users/robertsanders/projects/rs-x/demo/src/rs-x-state-manager/register-map.ts
947
996
  Initial value:
@@ -1000,53 +1049,60 @@ Latest value:
1000
1049
  ```
1001
1050
 
1002
1051
  ### Set
1052
+
1003
1053
  **Example**
1054
+
1004
1055
  ```ts
1005
1056
  import { InjectionContainer, printValue, truePredicate } from '@rs-x/core';
1006
1057
  import {
1007
- IProxyRegistry,
1008
- IStateChange,
1009
- IStateManager,
1010
- RsXStateManagerInjectionTokens,
1011
- RsXStateManagerModule
1058
+ IProxyRegistry,
1059
+ IStateChange,
1060
+ IStateManager,
1061
+ RsXStateManagerInjectionTokens,
1062
+ RsXStateManagerModule,
1012
1063
  } from '@rs-x/state-manager';
1013
1064
 
1014
1065
  // Load the state manager module into the injection container
1015
1066
  InjectionContainer.load(RsXStateManagerModule);
1016
1067
 
1017
1068
  export const run = (() => {
1018
- const stateManager: IStateManager = InjectionContainer.get(
1019
- RsXStateManagerInjectionTokens.IStateManager
1020
- );
1021
- const item1 = [1, 2];
1022
- const item2 = [3, 4];
1023
- const stateContext = {
1024
- set: new Set([item1, item2])
1025
- };
1026
- const changeSubscription = stateManager.changed.subscribe((change: IStateChange) => {
1027
- printValue(change.newValue);
1028
- });
1029
-
1030
- try {
1031
- // This will emit a change event with the initial (current) value.
1032
- console.log('Initial value:');
1033
- stateManager.watchState(stateContext, 'set', truePredicate);
1034
-
1035
- console.log('Changed value:');
1036
- const proxyRegister: IProxyRegistry = InjectionContainer.get(RsXStateManagerInjectionTokens.IProxyRegistry);
1037
- proxyRegister.getProxy<number[]>(item2).push(5);
1038
-
1039
- console.log('Latest value:');
1040
- printValue(stateManager.getState(stateContext, 'set'));
1069
+ const stateManager: IStateManager = InjectionContainer.get(
1070
+ RsXStateManagerInjectionTokens.IStateManager,
1071
+ );
1072
+ const item1 = [1, 2];
1073
+ const item2 = [3, 4];
1074
+ const stateContext = {
1075
+ set: new Set([item1, item2]),
1076
+ };
1077
+ const changeSubscription = stateManager.changed.subscribe(
1078
+ (change: IStateChange) => {
1079
+ printValue(change.newValue);
1080
+ },
1081
+ );
1082
+
1083
+ try {
1084
+ // This will emit a change event with the initial (current) value.
1085
+ console.log('Initial value:');
1086
+ stateManager.watchState(stateContext, 'set', truePredicate);
1041
1087
 
1042
- } finally {
1043
- changeSubscription.unsubscribe();
1044
- // Always release the state when it is no longer needed.
1045
- stateManager.releaseState(stateContext, 'set', truePredicate);
1046
- }
1088
+ console.log('Changed value:');
1089
+ const proxyRegister: IProxyRegistry = InjectionContainer.get(
1090
+ RsXStateManagerInjectionTokens.IProxyRegistry,
1091
+ );
1092
+ proxyRegister.getProxy<number[]>(item2).push(5);
1093
+
1094
+ console.log('Latest value:');
1095
+ printValue(stateManager.getState(stateContext, 'set'));
1096
+ } finally {
1097
+ changeSubscription.unsubscribe();
1098
+ // Always release the state when it is no longer needed.
1099
+ stateManager.releaseState(stateContext, 'set', truePredicate);
1100
+ }
1047
1101
  })();
1048
1102
  ```
1103
+
1049
1104
  **Output:**
1105
+
1050
1106
  ```console
1051
1107
  Running demo: /Users/robertsanders/projects/rs-x/demo/src/rs-x-state-manager/register-set.ts
1052
1108
  Initial value:
@@ -1087,54 +1143,64 @@ Latest value:
1087
1143
  ```
1088
1144
 
1089
1145
  ### Promise
1146
+
1090
1147
  **Example**
1148
+
1091
1149
  ```ts
1092
1150
  import { InjectionContainer, WaitForEvent } from '@rs-x/core';
1093
1151
  import {
1094
- IStateChange,
1095
- IStateManager,
1096
- RsXStateManagerInjectionTokens,
1097
- RsXStateManagerModule
1152
+ IStateChange,
1153
+ IStateManager,
1154
+ RsXStateManagerInjectionTokens,
1155
+ RsXStateManagerModule,
1098
1156
  } from '@rs-x/state-manager';
1099
1157
 
1100
1158
  // Load the state manager module into the injection container
1101
1159
  InjectionContainer.load(RsXStateManagerModule);
1102
1160
 
1103
1161
  export const run = (async () => {
1104
- const stateManager: IStateManager = InjectionContainer.get(
1105
- RsXStateManagerInjectionTokens.IStateManager
1106
- );
1107
-
1108
- const stateContext = {
1109
- promise: Promise.resolve(10)
1110
- };
1111
- const changeSubscription = stateManager.changed.subscribe((change: IStateChange) => {
1112
- console.log(change.newValue);
1162
+ const stateManager: IStateManager = InjectionContainer.get(
1163
+ RsXStateManagerInjectionTokens.IStateManager,
1164
+ );
1165
+
1166
+ const stateContext = {
1167
+ promise: Promise.resolve(10),
1168
+ };
1169
+ const changeSubscription = stateManager.changed.subscribe(
1170
+ (change: IStateChange) => {
1171
+ console.log(change.newValue);
1172
+ },
1173
+ );
1174
+
1175
+ try {
1176
+ await new WaitForEvent(stateManager, 'changed').wait(() => {
1177
+ // This will emit a change event with the initial (current) value.
1178
+ console.log('Initial value:');
1179
+ stateManager.watchState(stateContext, 'promise');
1113
1180
  });
1114
1181
 
1115
- try {
1116
- await new WaitForEvent(stateManager, 'changed').wait(() => {
1117
- // This will emit a change event with the initial (current) value.
1118
- console.log('Initial value:');
1119
- stateManager.watchState(stateContext, 'promise');
1120
- });
1121
-
1122
- await new WaitForEvent(stateManager, 'changed').wait(() => {
1123
- console.log('Changed value:');
1124
- let resolveHandler: (value: number) => void;
1125
- stateContext.promise = new Promise((resolve) => { resolveHandler = resolve; });
1126
- resolveHandler(30);
1127
- });
1182
+ await new WaitForEvent(stateManager, 'changed').wait(() => {
1183
+ console.log('Changed value:');
1184
+ let resolveHandler: (value: number) => void;
1185
+ stateContext.promise = new Promise((resolve) => {
1186
+ resolveHandler = resolve;
1187
+ });
1188
+ resolveHandler(30);
1189
+ });
1128
1190
 
1129
- console.log(`Latest value: ${stateManager.getState(stateContext, 'promise')}`);
1130
- } finally {
1131
- changeSubscription.unsubscribe();
1132
- // Always release the state when it is no longer needed.
1133
- stateManager.releaseState(stateContext, 'promise');
1134
- }
1191
+ console.log(
1192
+ `Latest value: ${stateManager.getState(stateContext, 'promise')}`,
1193
+ );
1194
+ } finally {
1195
+ changeSubscription.unsubscribe();
1196
+ // Always release the state when it is no longer needed.
1197
+ stateManager.releaseState(stateContext, 'promise');
1198
+ }
1135
1199
  })();
1136
1200
  ```
1201
+
1137
1202
  **Output:**
1203
+
1138
1204
  ```console
1139
1205
  Running demo: /Users/robertsanders/projects/rs-x/demo/src/rs-x-state-manager/register-promise.ts
1140
1206
  Initial value:
@@ -1145,14 +1211,16 @@ Latest value: 30
1145
1211
  ```
1146
1212
 
1147
1213
  ### Observable
1214
+
1148
1215
  **Example**
1216
+
1149
1217
  ```ts
1150
1218
  import { InjectionContainer, WaitForEvent } from '@rs-x/core';
1151
1219
  import {
1152
- IStateChange,
1153
- IStateManager,
1154
- RsXStateManagerInjectionTokens,
1155
- RsXStateManagerModule
1220
+ IStateChange,
1221
+ IStateManager,
1222
+ RsXStateManagerInjectionTokens,
1223
+ RsXStateManagerModule,
1156
1224
  } from '@rs-x/state-manager';
1157
1225
  import { of, Subject } from 'rxjs';
1158
1226
 
@@ -1160,44 +1228,49 @@ import { of, Subject } from 'rxjs';
1160
1228
  InjectionContainer.load(RsXStateManagerModule);
1161
1229
 
1162
1230
  export const run = (async () => {
1163
- const stateManager: IStateManager = InjectionContainer.get(
1164
- RsXStateManagerInjectionTokens.IStateManager
1165
- );
1166
-
1167
- const stateContext = {
1168
- observable: of(10)
1169
- };
1170
-
1171
- const changeSubscription = stateManager.changed.subscribe((change: IStateChange) => {
1172
- console.log(change.newValue);
1231
+ const stateManager: IStateManager = InjectionContainer.get(
1232
+ RsXStateManagerInjectionTokens.IStateManager,
1233
+ );
1234
+
1235
+ const stateContext = {
1236
+ observable: of(10),
1237
+ };
1238
+
1239
+ const changeSubscription = stateManager.changed.subscribe(
1240
+ (change: IStateChange) => {
1241
+ console.log(change.newValue);
1242
+ },
1243
+ );
1244
+
1245
+ try {
1246
+ // We need to wait here until the event is emitted,
1247
+ // otherwise the demo will exit before the change event occurs.
1248
+ await new WaitForEvent(stateManager, 'changed').wait(() => {
1249
+ // This will emit a change event with the initial (current) value.
1250
+ console.log('Initial value:');
1251
+ stateManager.watchState(stateContext, 'observable');
1173
1252
  });
1174
1253
 
1175
- try {
1176
- // We need to wait here until the event is emitted,
1177
- // otherwise the demo will exit before the change event occurs.
1178
- await new WaitForEvent(stateManager, 'changed').wait(() => {
1179
- // This will emit a change event with the initial (current) value.
1180
- console.log('Initial value:');
1181
- stateManager.watchState(stateContext, 'observable');
1182
- });
1183
-
1184
- await new WaitForEvent(stateManager, 'changed').wait(() => {
1185
- console.log('Changed value:');
1186
- const subject = new Subject<number>();
1187
- stateContext.observable = subject
1188
- subject.next(30);
1189
- });
1190
-
1191
- console.log(`Latest value: ${stateManager.getState(stateContext, 'observable')}`);
1254
+ await new WaitForEvent(stateManager, 'changed').wait(() => {
1255
+ console.log('Changed value:');
1256
+ const subject = new Subject<number>();
1257
+ stateContext.observable = subject;
1258
+ subject.next(30);
1259
+ });
1192
1260
 
1193
- } finally {
1194
- changeSubscription.unsubscribe();
1195
- // Always release the state when it is no longer needed.
1196
- stateManager.releaseState(stateContext, 'observable');
1197
- }
1261
+ console.log(
1262
+ `Latest value: ${stateManager.getState(stateContext, 'observable')}`,
1263
+ );
1264
+ } finally {
1265
+ changeSubscription.unsubscribe();
1266
+ // Always release the state when it is no longer needed.
1267
+ stateManager.releaseState(stateContext, 'observable');
1268
+ }
1198
1269
  })();
1199
1270
  ```
1271
+
1200
1272
  **Output:**
1273
+
1201
1274
  ```console
1202
1275
  Running demo: /Users/robertsanders/projects/rs-x/demo/src/rs-x-state-manager/register-observable.ts
1203
1276
  Initial value:
@@ -1208,14 +1281,16 @@ Latest value: 30
1208
1281
  ```
1209
1282
 
1210
1283
  ### Custom type
1211
- 1. Create an accessor to retrieve index values on your type.
1212
- 2. Create a factory to create an observer for your data type.
1284
+
1285
+ 1. Create an accessor to retrieve index values on your type.
1286
+ 2. Create a factory to create an observer for your data type.
1213
1287
  3. Create a factory to create an observer for an index on your data instance.
1214
1288
 
1215
1289
  The following example demonstrates adding support for a custom `TextDocument` class:
1216
1290
 
1217
1291
  **Example**
1218
- ```ts
1292
+
1293
+ ````ts
1219
1294
  import {
1220
1295
  ContainerModule,
1221
1296
  defaultIndexValueAccessorList,
@@ -1664,7 +1739,7 @@ function testMonitoreSpecificLineInDocument(stateManager: IStateManager, stateCo
1664
1739
  });
1665
1740
 
1666
1741
  try {
1667
- // Here we only watch line 3 on page 1.
1742
+ // Here we only watch line 3 on page 1.
1668
1743
  // Notice that the line does not have to exist yet.
1669
1744
  // The initial book does not have a line 3 on page 1.
1670
1745
  //
@@ -1684,7 +1759,7 @@ function testMonitoreSpecificLineInDocument(stateManager: IStateManager, stateCo
1684
1759
  bookProxy.setLine({ pageIndex: 0, lineIndex: 0 }, 'a troll was born');
1685
1760
 
1686
1761
  } finally {
1687
- // Stop monitoring line 3 on page 1.
1762
+ // Stop monitoring line 3 on page 1.
1688
1763
  stateManager.releaseState(stateContext.myBook, line3OnPage1Index);
1689
1764
  lineSubscription.unsubscribe();
1690
1765
  }
@@ -1711,8 +1786,10 @@ export const run = (() => {
1711
1786
  testMonitoreSpecificLineInDocument(stateManager, stateContext);
1712
1787
  })();
1713
1788
  ```nclude_relative ../demo/src/rs-x-state-manager/register-set.ts %}
1714
- ```
1789
+ ````
1790
+
1715
1791
  **Output:**
1792
+
1716
1793
  ```console
1717
1794
  Running demo: /Users/robertsanders/projects/rs-x/demo/src/rs-x-state-manager/state-manager-customize.ts
1718
1795
 
@@ -1762,4 +1839,3 @@ Page 1:
1762
1839
  Changing line 1 on page 1 does not emit change:
1763
1840
  ---
1764
1841
  ```
1765
-