@veams/status-quo 1.3.0 → 1.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/dist/store/__tests__/signal-state-handler.spec.js +55 -0
- package/dist/store/__tests__/signal-state-handler.spec.js.map +1 -1
- package/dist/store/signal-state-handler.d.ts +0 -2
- package/dist/store/signal-state-handler.js +15 -15
- package/dist/store/signal-state-handler.js.map +1 -1
- package/package.json +1 -1
- package/src/store/__tests__/signal-state-handler.spec.ts +75 -0
- package/src/store/signal-state-handler.ts +17 -17
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resetStatusQuoForTests, setupStatusQuo } from '../../config/status-quo-config.js';
|
|
2
2
|
import { SignalStateHandler } from '../signal-state-handler.js';
|
|
3
|
+
import { makeStateSingleton } from '../state-singleton.js';
|
|
3
4
|
class TestSignalStateHandler extends SignalStateHandler {
|
|
4
5
|
constructor({ withDevTools, distinct, useDistinctUntilChanged } = {}) {
|
|
5
6
|
super({
|
|
@@ -31,6 +32,44 @@ class TestSignalStateHandler extends SignalStateHandler {
|
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
34
|
}
|
|
35
|
+
class CounterSignalStateHandler extends SignalStateHandler {
|
|
36
|
+
constructor(initialCount = 0) {
|
|
37
|
+
super({
|
|
38
|
+
initialState: {
|
|
39
|
+
count: initialCount,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
getActions() {
|
|
44
|
+
return {
|
|
45
|
+
increase: () => {
|
|
46
|
+
this.setState({ count: this.getState().count + 1 }, 'increase');
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
class CounterSignalBridgeStateHandler extends SignalStateHandler {
|
|
52
|
+
constructor(counterSingleton, onCounterSync) {
|
|
53
|
+
super({
|
|
54
|
+
initialState: {
|
|
55
|
+
count: 0,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
const counterStateHandler = counterSingleton.getInstance();
|
|
59
|
+
this.bindSubscribable({
|
|
60
|
+
subscribe: (listener) => counterStateHandler.subscribe(() => listener(counterStateHandler.getSnapshot())),
|
|
61
|
+
getSnapshot: () => counterStateHandler.getSnapshot(),
|
|
62
|
+
}, (nextCounterState) => {
|
|
63
|
+
onCounterSync(nextCounterState);
|
|
64
|
+
this.setState({ count: nextCounterState.count }, 'sync-counter');
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
getActions() {
|
|
68
|
+
return {
|
|
69
|
+
noop: () => undefined,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
34
73
|
describe('Signal State Handler', () => {
|
|
35
74
|
let stateHandler;
|
|
36
75
|
beforeEach(() => {
|
|
@@ -133,5 +172,21 @@ describe('Signal State Handler', () => {
|
|
|
133
172
|
unsubscribe();
|
|
134
173
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
135
174
|
});
|
|
175
|
+
it('should notify another signal state handler for each singleton counter update', () => {
|
|
176
|
+
const counterSingleton = makeStateSingleton(() => new CounterSignalStateHandler(0), {
|
|
177
|
+
destroyOnNoConsumers: false,
|
|
178
|
+
});
|
|
179
|
+
const syncSpy = jest.fn();
|
|
180
|
+
const bridgeStateHandler = new CounterSignalBridgeStateHandler(counterSingleton, syncSpy);
|
|
181
|
+
const counterStateHandler = counterSingleton.getInstance();
|
|
182
|
+
counterStateHandler.getActions().increase();
|
|
183
|
+
counterStateHandler.getActions().increase();
|
|
184
|
+
expect(syncSpy).toHaveBeenCalledTimes(3);
|
|
185
|
+
expect(syncSpy).toHaveBeenNthCalledWith(1, { count: 0 });
|
|
186
|
+
expect(syncSpy).toHaveBeenNthCalledWith(2, { count: 1 });
|
|
187
|
+
expect(syncSpy).toHaveBeenNthCalledWith(3, { count: 2 });
|
|
188
|
+
expect(bridgeStateHandler.getState()).toStrictEqual({ count: 2 });
|
|
189
|
+
bridgeStateHandler.destroy();
|
|
190
|
+
});
|
|
136
191
|
});
|
|
137
192
|
//# sourceMappingURL=signal-state-handler.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signal-state-handler.spec.js","sourceRoot":"","sources":["../../../src/store/__tests__/signal-state-handler.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"signal-state-handler.spec.js","sourceRoot":"","sources":["../../../src/store/__tests__/signal-state-handler.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,13 +15,11 @@ type SignalStateHandlerProps<S> = {
|
|
|
15
15
|
type Listener = () => void;
|
|
16
16
|
export declare abstract class SignalStateHandler<S, A> extends BaseStateHandler<S, A> {
|
|
17
17
|
private readonly state;
|
|
18
|
-
private readonly listeners;
|
|
19
18
|
private readonly distinctOptions;
|
|
20
19
|
protected constructor({ initialState, options }: SignalStateHandlerProps<S>);
|
|
21
20
|
getSignal(): Signal<S>;
|
|
22
21
|
subscribe(listener: Listener): () => void;
|
|
23
22
|
protected getStateValue(): S;
|
|
24
23
|
protected setStateValue(nextState: S): void;
|
|
25
|
-
private notify;
|
|
26
24
|
}
|
|
27
25
|
export {};
|
|
@@ -3,7 +3,6 @@ import { BaseStateHandler } from './base-state-handler.js';
|
|
|
3
3
|
import { resolveDistinctOptions } from '../config/status-quo-config.js';
|
|
4
4
|
export class SignalStateHandler extends BaseStateHandler {
|
|
5
5
|
state;
|
|
6
|
-
listeners = new Map();
|
|
7
6
|
distinctOptions;
|
|
8
7
|
constructor({ initialState, options }) {
|
|
9
8
|
super(initialState);
|
|
@@ -15,26 +14,27 @@ export class SignalStateHandler extends BaseStateHandler {
|
|
|
15
14
|
return this.state;
|
|
16
15
|
}
|
|
17
16
|
subscribe(listener) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
let initialized = false;
|
|
18
|
+
let previousSnapshot = this.state.value;
|
|
19
|
+
return this.state.subscribe((nextState) => {
|
|
20
|
+
if (!initialized) {
|
|
21
|
+
initialized = true;
|
|
22
|
+
previousSnapshot = nextState;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (this.distinctOptions.enabled && this.distinctOptions.comparator(previousSnapshot, nextState)) {
|
|
26
|
+
previousSnapshot = nextState;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
previousSnapshot = nextState;
|
|
30
|
+
listener();
|
|
31
|
+
});
|
|
22
32
|
}
|
|
23
33
|
getStateValue() {
|
|
24
34
|
return this.state.value;
|
|
25
35
|
}
|
|
26
36
|
setStateValue(nextState) {
|
|
27
37
|
this.state.value = nextState;
|
|
28
|
-
this.notify(nextState);
|
|
29
|
-
}
|
|
30
|
-
notify(nextState) {
|
|
31
|
-
for (const [listener, lastSnapshot] of this.listeners.entries()) {
|
|
32
|
-
if (this.distinctOptions.enabled && this.distinctOptions.comparator(lastSnapshot, nextState)) {
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
this.listeners.set(listener, nextState);
|
|
36
|
-
listener();
|
|
37
|
-
}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
//# sourceMappingURL=signal-state-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signal-state-handler.js","sourceRoot":"","sources":["../../src/store/signal-state-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAmBxE,MAAM,OAAgB,kBAAyB,SAAQ,gBAAsB;IAC1D,KAAK,CAAY;IACjB,
|
|
1
|
+
{"version":3,"file":"signal-state-handler.js","sourceRoot":"","sources":["../../src/store/signal-state-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAmBxE,MAAM,OAAgB,kBAAyB,SAAQ,gBAAsB;IAC1D,KAAK,CAAY;IACjB,eAAe,CAA+C;IAE/E,YAAsB,EAAE,YAAY,EAAE,OAAO,EAA8B;QACzE,KAAK,CAAC,YAAY,CAAC,CAAC;QAEpB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAI,YAAY,CAAC,CAAC;QACrC,IAAI,CAAC,eAAe,GAAG,sBAAsB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC;QACnG,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,SAAS,CAAC,QAAkB;QAC1B,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,IAAI,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAExC,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,EAAE;YACxC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,WAAW,GAAG,IAAI,CAAC;gBACnB,gBAAgB,GAAG,SAAS,CAAC;gBAC7B,OAAO;YACT,CAAC;YAED,IAAI,IAAI,CAAC,eAAe,CAAC,OAAO,IAAI,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,gBAAgB,EAAE,SAAS,CAAC,EAAE,CAAC;gBACjG,gBAAgB,GAAG,SAAS,CAAC;gBAC7B,OAAO;YACT,CAAC;YAED,gBAAgB,GAAG,SAAS,CAAC;YAC7B,QAAQ,EAAE,CAAC;QACb,CAAC,CAAC,CAAC;IACL,CAAC;IAES,aAAa;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAC1B,CAAC;IAES,aAAa,CAAC,SAAY;QAClC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC;IAC/B,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resetStatusQuoForTests, setupStatusQuo } from '../../config/status-quo-config.js';
|
|
2
2
|
import { SignalStateHandler } from '../signal-state-handler.js';
|
|
3
|
+
import { makeStateSingleton } from '../state-singleton.js';
|
|
3
4
|
import type { DistinctOptions } from '../../config/status-quo-config.js';
|
|
4
5
|
|
|
5
6
|
type TestState = { test: string; test2: string };
|
|
@@ -43,6 +44,60 @@ class TestSignalStateHandler extends SignalStateHandler<TestState, TestActions>
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
type CounterState = { count: number };
|
|
48
|
+
type CounterActions = { increase: () => void };
|
|
49
|
+
|
|
50
|
+
class CounterSignalStateHandler extends SignalStateHandler<CounterState, CounterActions> {
|
|
51
|
+
constructor(initialCount = 0) {
|
|
52
|
+
super({
|
|
53
|
+
initialState: {
|
|
54
|
+
count: initialCount,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getActions(): CounterActions {
|
|
60
|
+
return {
|
|
61
|
+
increase: () => {
|
|
62
|
+
this.setState({ count: this.getState().count + 1 }, 'increase');
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
class CounterSignalBridgeStateHandler extends SignalStateHandler<CounterState, { noop: () => void }> {
|
|
69
|
+
constructor(
|
|
70
|
+
counterSingleton: ReturnType<typeof makeStateSingleton<CounterState, CounterActions>>,
|
|
71
|
+
onCounterSync: (counterState: CounterState) => void
|
|
72
|
+
) {
|
|
73
|
+
super({
|
|
74
|
+
initialState: {
|
|
75
|
+
count: 0,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const counterStateHandler = counterSingleton.getInstance();
|
|
80
|
+
|
|
81
|
+
this.bindSubscribable<CounterState>(
|
|
82
|
+
{
|
|
83
|
+
subscribe: (listener) =>
|
|
84
|
+
counterStateHandler.subscribe(() => listener(counterStateHandler.getSnapshot())),
|
|
85
|
+
getSnapshot: () => counterStateHandler.getSnapshot(),
|
|
86
|
+
},
|
|
87
|
+
(nextCounterState) => {
|
|
88
|
+
onCounterSync(nextCounterState);
|
|
89
|
+
this.setState({ count: nextCounterState.count }, 'sync-counter');
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
getActions(): { noop: () => void } {
|
|
95
|
+
return {
|
|
96
|
+
noop: () => undefined,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
46
101
|
describe('Signal State Handler', () => {
|
|
47
102
|
let stateHandler: TestSignalStateHandler;
|
|
48
103
|
|
|
@@ -175,4 +230,24 @@ describe('Signal State Handler', () => {
|
|
|
175
230
|
|
|
176
231
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
177
232
|
});
|
|
233
|
+
|
|
234
|
+
it('should notify another signal state handler for each singleton counter update', () => {
|
|
235
|
+
const counterSingleton = makeStateSingleton(() => new CounterSignalStateHandler(0), {
|
|
236
|
+
destroyOnNoConsumers: false,
|
|
237
|
+
});
|
|
238
|
+
const syncSpy = jest.fn();
|
|
239
|
+
const bridgeStateHandler = new CounterSignalBridgeStateHandler(counterSingleton, syncSpy);
|
|
240
|
+
const counterStateHandler = counterSingleton.getInstance();
|
|
241
|
+
|
|
242
|
+
counterStateHandler.getActions().increase();
|
|
243
|
+
counterStateHandler.getActions().increase();
|
|
244
|
+
|
|
245
|
+
expect(syncSpy).toHaveBeenCalledTimes(3);
|
|
246
|
+
expect(syncSpy).toHaveBeenNthCalledWith(1, { count: 0 });
|
|
247
|
+
expect(syncSpy).toHaveBeenNthCalledWith(2, { count: 1 });
|
|
248
|
+
expect(syncSpy).toHaveBeenNthCalledWith(3, { count: 2 });
|
|
249
|
+
expect(bridgeStateHandler.getState()).toStrictEqual({ count: 2 });
|
|
250
|
+
|
|
251
|
+
bridgeStateHandler.destroy();
|
|
252
|
+
});
|
|
178
253
|
});
|
|
@@ -22,7 +22,6 @@ type Listener = () => void;
|
|
|
22
22
|
|
|
23
23
|
export abstract class SignalStateHandler<S, A> extends BaseStateHandler<S, A> {
|
|
24
24
|
private readonly state: Signal<S>;
|
|
25
|
-
private readonly listeners = new Map<Listener, S>();
|
|
26
25
|
private readonly distinctOptions: ReturnType<typeof resolveDistinctOptions<S>>;
|
|
27
26
|
|
|
28
27
|
protected constructor({ initialState, options }: SignalStateHandlerProps<S>) {
|
|
@@ -38,11 +37,24 @@ export abstract class SignalStateHandler<S, A> extends BaseStateHandler<S, A> {
|
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
subscribe(listener: Listener) {
|
|
41
|
-
|
|
40
|
+
let initialized = false;
|
|
41
|
+
let previousSnapshot = this.state.value;
|
|
42
42
|
|
|
43
|
-
return () => {
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
return this.state.subscribe((nextState) => {
|
|
44
|
+
if (!initialized) {
|
|
45
|
+
initialized = true;
|
|
46
|
+
previousSnapshot = nextState;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (this.distinctOptions.enabled && this.distinctOptions.comparator(previousSnapshot, nextState)) {
|
|
51
|
+
previousSnapshot = nextState;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
previousSnapshot = nextState;
|
|
56
|
+
listener();
|
|
57
|
+
});
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
protected getStateValue() {
|
|
@@ -51,17 +63,5 @@ export abstract class SignalStateHandler<S, A> extends BaseStateHandler<S, A> {
|
|
|
51
63
|
|
|
52
64
|
protected setStateValue(nextState: S) {
|
|
53
65
|
this.state.value = nextState;
|
|
54
|
-
this.notify(nextState);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
private notify(nextState: S) {
|
|
58
|
-
for (const [listener, lastSnapshot] of this.listeners.entries()) {
|
|
59
|
-
if (this.distinctOptions.enabled && this.distinctOptions.comparator(lastSnapshot, nextState)) {
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
this.listeners.set(listener, nextState);
|
|
64
|
-
listener();
|
|
65
|
-
}
|
|
66
66
|
}
|
|
67
67
|
}
|