synstate 1.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -10
- package/dist/core/class/child-observable-class.d.mts.map +1 -1
- package/dist/core/class/child-observable-class.mjs +148 -140
- package/dist/core/class/child-observable-class.mjs.map +1 -1
- package/dist/core/class/observable-base-class.d.mts.map +1 -1
- package/dist/core/class/observable-base-class.mjs +111 -107
- package/dist/core/class/observable-base-class.mjs.map +1 -1
- package/dist/core/class/root-observable-class.d.mts.map +1 -1
- package/dist/core/class/root-observable-class.mjs +32 -24
- package/dist/core/class/root-observable-class.mjs.map +1 -1
- package/dist/core/combine/combine.d.mts +3 -3
- package/dist/core/combine/combine.d.mts.map +1 -1
- package/dist/core/combine/combine.mjs +31 -113
- package/dist/core/combine/combine.mjs.map +1 -1
- package/dist/core/combine/merge.d.mts +2 -2
- package/dist/core/combine/merge.d.mts.map +1 -1
- package/dist/core/combine/merge.mjs +21 -69
- package/dist/core/combine/merge.mjs.map +1 -1
- package/dist/core/combine/zip.d.mts +2 -2
- package/dist/core/combine/zip.d.mts.map +1 -1
- package/dist/core/combine/zip.mjs +34 -79
- package/dist/core/combine/zip.mjs.map +1 -1
- package/dist/core/create/counter.d.mts +1 -1
- package/dist/core/create/counter.d.mts.map +1 -1
- package/dist/core/create/counter.mjs +45 -84
- package/dist/core/create/counter.mjs.map +1 -1
- package/dist/core/create/from-abortable-promise.d.mts.map +1 -1
- package/dist/core/create/from-abortable-promise.mjs +29 -61
- package/dist/core/create/from-abortable-promise.mjs.map +1 -1
- package/dist/core/create/from-promise.d.mts.map +1 -1
- package/dist/core/create/from-promise.mjs +17 -66
- package/dist/core/create/from-promise.mjs.map +1 -1
- package/dist/core/create/from-subscribable.d.mts.map +1 -1
- package/dist/core/create/from-subscribable.mjs +18 -69
- package/dist/core/create/from-subscribable.mjs.map +1 -1
- package/dist/core/create/just.d.mts.map +1 -1
- package/dist/core/create/just.mjs +5 -35
- package/dist/core/create/just.mjs.map +1 -1
- package/dist/core/create/source.mjs +10 -13
- package/dist/core/create/source.mjs.map +1 -1
- package/dist/core/create/timer.d.mts.map +1 -1
- package/dist/core/create/timer.mjs +32 -68
- package/dist/core/create/timer.mjs.map +1 -1
- package/dist/core/operators/audit.d.mts.map +1 -1
- package/dist/core/operators/audit.mjs +39 -133
- package/dist/core/operators/audit.mjs.map +1 -1
- package/dist/core/operators/debounce.d.mts.map +1 -1
- package/dist/core/operators/debounce.mjs +36 -119
- package/dist/core/operators/debounce.mjs.map +1 -1
- package/dist/core/operators/filter.mjs +22 -25
- package/dist/core/operators/filter.mjs.map +1 -1
- package/dist/core/operators/map.d.mts.map +1 -1
- package/dist/core/operators/map.mjs +28 -61
- package/dist/core/operators/map.mjs.map +1 -1
- package/dist/core/operators/merge-map.d.mts +1 -1
- package/dist/core/operators/merge-map.d.mts.map +1 -1
- package/dist/core/operators/merge-map.mjs +34 -130
- package/dist/core/operators/merge-map.mjs.map +1 -1
- package/dist/core/operators/pairwise.d.mts +3 -2
- package/dist/core/operators/pairwise.d.mts.map +1 -1
- package/dist/core/operators/pairwise.mjs +19 -75
- package/dist/core/operators/pairwise.mjs.map +1 -1
- package/dist/core/operators/scan.d.mts.map +1 -1
- package/dist/core/operators/scan.mjs +16 -67
- package/dist/core/operators/scan.mjs.map +1 -1
- package/dist/core/operators/skip-if-no-change.d.mts +1 -1
- package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
- package/dist/core/operators/skip-if-no-change.mjs +28 -92
- package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
- package/dist/core/operators/skip-until.d.mts.map +1 -1
- package/dist/core/operators/skip-until.mjs +23 -72
- package/dist/core/operators/skip-until.mjs.map +1 -1
- package/dist/core/operators/skip-while.d.mts.map +1 -1
- package/dist/core/operators/skip-while.mjs +26 -88
- package/dist/core/operators/skip-while.mjs.map +1 -1
- package/dist/core/operators/switch-map.d.mts.map +1 -1
- package/dist/core/operators/switch-map.mjs +31 -124
- package/dist/core/operators/switch-map.mjs.map +1 -1
- package/dist/core/operators/take-until.d.mts.map +1 -1
- package/dist/core/operators/take-until.mjs +28 -69
- package/dist/core/operators/take-until.mjs.map +1 -1
- package/dist/core/operators/take-while.d.mts.map +1 -1
- package/dist/core/operators/take-while.mjs +23 -83
- package/dist/core/operators/take-while.mjs.map +1 -1
- package/dist/core/operators/throttle.d.mts.map +1 -1
- package/dist/core/operators/throttle.mjs +38 -115
- package/dist/core/operators/throttle.mjs.map +1 -1
- package/dist/core/operators/with-buffered-from.d.mts +1 -1
- package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
- package/dist/core/operators/with-buffered-from.mjs +37 -90
- package/dist/core/operators/with-buffered-from.mjs.map +1 -1
- package/dist/core/operators/with-current-value-from.d.mts +1 -1
- package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
- package/dist/core/operators/with-current-value-from.mjs +23 -84
- package/dist/core/operators/with-current-value-from.mjs.map +1 -1
- package/dist/core/operators/with-initial-value.d.mts.map +1 -1
- package/dist/core/operators/with-initial-value.mjs +13 -58
- package/dist/core/operators/with-initial-value.mjs.map +1 -1
- package/dist/core/predefined/operators/attach-index.d.mts +1 -1
- package/dist/core/predefined/operators/attach-index.d.mts.map +1 -1
- package/dist/core/predefined/operators/attach-index.mjs +0 -53
- package/dist/core/predefined/operators/attach-index.mjs.map +1 -1
- package/dist/core/predefined/operators/map-optional.d.mts.map +1 -1
- package/dist/core/predefined/operators/map-optional.mjs +1 -48
- package/dist/core/predefined/operators/map-optional.mjs.map +1 -1
- package/dist/core/predefined/operators/map-result-err.d.mts.map +1 -1
- package/dist/core/predefined/operators/map-result-err.mjs +1 -48
- package/dist/core/predefined/operators/map-result-err.mjs.map +1 -1
- package/dist/core/predefined/operators/map-result-ok.d.mts.map +1 -1
- package/dist/core/predefined/operators/map-result-ok.mjs +1 -48
- package/dist/core/predefined/operators/map-result-ok.mjs.map +1 -1
- package/dist/core/predefined/operators/map-to.d.mts.map +1 -1
- package/dist/core/predefined/operators/map-to.mjs +0 -40
- package/dist/core/predefined/operators/map-to.mjs.map +1 -1
- package/dist/core/predefined/operators/pluck.d.mts +1 -1
- package/dist/core/predefined/operators/pluck.d.mts.map +1 -1
- package/dist/core/predefined/operators/pluck.mjs +0 -43
- package/dist/core/predefined/operators/pluck.mjs.map +1 -1
- package/dist/core/predefined/operators/skip.d.mts.map +1 -1
- package/dist/core/predefined/operators/skip.mjs +0 -47
- package/dist/core/predefined/operators/skip.mjs.map +1 -1
- package/dist/core/predefined/operators/take.d.mts.map +1 -1
- package/dist/core/predefined/operators/take.mjs +0 -41
- package/dist/core/predefined/operators/take.mjs.map +1 -1
- package/dist/core/predefined/operators/unwrap-optional.mjs +4 -43
- package/dist/core/predefined/operators/unwrap-optional.mjs.map +1 -1
- package/dist/core/predefined/operators/unwrap-result-err.mjs +0 -40
- package/dist/core/predefined/operators/unwrap-result-err.mjs.map +1 -1
- package/dist/core/predefined/operators/unwrap-result-ok.mjs +4 -43
- package/dist/core/predefined/operators/unwrap-result-ok.mjs.map +1 -1
- package/dist/core/types/observable-family.d.mts +10 -10
- package/dist/core/types/observable-family.d.mts.map +1 -1
- package/dist/core/types/observable.d.mts.map +1 -1
- package/dist/core/types/observable.mjs +3 -5
- package/dist/core/types/observable.mjs.map +1 -1
- package/dist/core/types/types.d.mts +2 -1
- package/dist/core/types/types.d.mts.map +1 -1
- package/dist/core/utils/id-maker.mjs +5 -6
- package/dist/core/utils/id-maker.mjs.map +1 -1
- package/dist/core/utils/max-depth.d.mts.map +1 -1
- package/dist/core/utils/max-depth.mjs +1 -3
- package/dist/core/utils/max-depth.mjs.map +1 -1
- package/dist/core/utils/observable-utils.d.mts.map +1 -1
- package/dist/core/utils/observable-utils.mjs +3 -2
- package/dist/core/utils/observable-utils.mjs.map +1 -1
- package/dist/core/utils/utils.d.mts.map +1 -1
- package/dist/core/utils/utils.mjs +23 -30
- package/dist/core/utils/utils.mjs.map +1 -1
- package/dist/utils/collect-to-array.d.mts.map +1 -1
- package/dist/utils/collect-to-array.mjs +9 -6
- package/dist/utils/collect-to-array.mjs.map +1 -1
- package/dist/utils/create-boolean-state.d.mts +1 -1
- package/dist/utils/create-boolean-state.d.mts.map +1 -1
- package/dist/utils/create-boolean-state.mjs +18 -46
- package/dist/utils/create-boolean-state.mjs.map +1 -1
- package/dist/utils/create-event-emitter.mjs +10 -64
- package/dist/utils/create-event-emitter.mjs.map +1 -1
- package/dist/utils/create-reducer.d.mts +1 -1
- package/dist/utils/create-reducer.d.mts.map +1 -1
- package/dist/utils/create-reducer.mjs +8 -52
- package/dist/utils/create-reducer.mjs.map +1 -1
- package/dist/utils/create-state.d.mts +1 -1
- package/dist/utils/create-state.d.mts.map +1 -1
- package/dist/utils/create-state.mjs +23 -53
- package/dist/utils/create-state.mjs.map +1 -1
- package/package.json +13 -14
- package/src/core/class/child-observable-class.mts +1 -1
- package/src/core/class/observable-base-class.mts +16 -16
- package/src/core/combine/combine.mts +38 -16
- package/src/core/combine/merge.mts +3 -3
- package/src/core/combine/zip.mts +24 -13
- package/src/core/create/counter.mts +11 -9
- package/src/core/create/counter.test.mts +11 -0
- package/src/core/create/timer.mts +6 -6
- package/src/core/create/timer.test.mts +11 -0
- package/src/core/operators/audit-throttle-teardown.test.mts +21 -0
- package/src/core/operators/audit.mts +6 -6
- package/src/core/operators/debounce.mts +6 -6
- package/src/core/operators/pairwise.mts +10 -5
- package/src/core/operators/skip-while.mts +1 -5
- package/src/core/operators/skip-while.test.mts +20 -0
- package/src/core/operators/throttle.mts +6 -6
- package/src/core/operators/with-buffered-from.mts +4 -4
- package/src/core/predefined/operators/map-optional.mts +1 -2
- package/src/core/predefined/operators/map-result-err.mts +1 -1
- package/src/core/predefined/operators/map-result-ok.mts +1 -1
- package/src/core/types/observable-family.mts +12 -11
- package/src/core/types/observable.mts +5 -7
- package/src/core/types/types.mts +2 -1
- package/src/core/utils/max-depth.mts +5 -1
- package/src/core/utils/utils.mts +1 -1
- package/src/utils/create-boolean-state.mts +1 -1
- package/src/utils/create-reducer.mts +1 -1
- package/src/utils/create-state.mts +1 -1
|
@@ -32,7 +32,7 @@ import { type InitializedObservable } from '../core/index.mjs';
|
|
|
32
32
|
* assert.deepStrictEqual(stateHistory, [0, 10, 11, 0]);
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
|
-
export declare const createState: <S>(initialState: S) => readonly [state: InitializedObservable<S>, setState: (v: S) => S, Readonly<{
|
|
35
|
+
export declare const createState: <S>(initialState: S) => readonly [state: InitializedObservable<S>, setState: (v: S) => S, utils: Readonly<{
|
|
36
36
|
updateState: (updateFn: (prev: S) => S) => S;
|
|
37
37
|
resetState: () => S;
|
|
38
38
|
getSnapshot: () => S;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-state.d.mts","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAwB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"create-state.d.mts","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAwB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,gBACb,CAAC,KACd,SAAS,CACV,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAC/B,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EACrB,KAAK,EAAE,QAAQ,CAAC;IACd,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CAyBH,CAAC"}
|
|
@@ -1,61 +1,31 @@
|
|
|
1
1
|
import { createReducer } from './create-reducer.mjs';
|
|
2
2
|
|
|
3
3
|
const reducer = (state, action) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
switch (action.type) {
|
|
5
|
+
case "set":
|
|
6
|
+
return action.nextState;
|
|
7
|
+
case "update":
|
|
8
|
+
return action.updateFn(state);
|
|
9
|
+
}
|
|
10
10
|
};
|
|
11
|
-
/**
|
|
12
|
-
* Creates a reactive state container with getter and setter methods.
|
|
13
|
-
* Provides a simple state management solution with observable state.
|
|
14
|
-
*
|
|
15
|
-
* @template S - The type of the state
|
|
16
|
-
* @param initialState - The initial value of the state
|
|
17
|
-
* @returns A 3-element tuple: `[state, setState, { updateState, resetState, getSnapshot, initialState }]`
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* const [state, setState, { updateState, resetState }] = createState(0);
|
|
22
|
-
*
|
|
23
|
-
* const stateHistory: number[] = [];
|
|
24
|
-
*
|
|
25
|
-
* state.subscribe((value: number) => {
|
|
26
|
-
* stateHistory.push(value);
|
|
27
|
-
* });
|
|
28
|
-
*
|
|
29
|
-
* assert.deepStrictEqual(stateHistory, [0]);
|
|
30
|
-
*
|
|
31
|
-
* setState(10); // logs: 10
|
|
32
|
-
*
|
|
33
|
-
* assert.deepStrictEqual(stateHistory, [0, 10]);
|
|
34
|
-
*
|
|
35
|
-
* updateState((prev: number) => prev + 1); // logs: 11
|
|
36
|
-
*
|
|
37
|
-
* assert.deepStrictEqual(stateHistory, [0, 10, 11]);
|
|
38
|
-
*
|
|
39
|
-
* resetState(); // logs: 0
|
|
40
|
-
*
|
|
41
|
-
* assert.deepStrictEqual(stateHistory, [0, 10, 11, 0]);
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
11
|
const createState = (initialState) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
12
|
+
const [state, dispatch, { getSnapshot }] = createReducer(
|
|
13
|
+
reducer,
|
|
14
|
+
initialState
|
|
15
|
+
);
|
|
16
|
+
const updateState = (updateFn) => dispatch({ type: "update", updateFn });
|
|
17
|
+
const setState = (nextState) => dispatch({ type: "set", nextState });
|
|
18
|
+
const resetState = () => dispatch({ type: "set", nextState: initialState });
|
|
19
|
+
return [
|
|
20
|
+
state,
|
|
21
|
+
setState,
|
|
22
|
+
{
|
|
23
|
+
updateState,
|
|
24
|
+
resetState,
|
|
25
|
+
getSnapshot,
|
|
26
|
+
initialState
|
|
27
|
+
}
|
|
28
|
+
];
|
|
59
29
|
};
|
|
60
30
|
|
|
61
31
|
export { createState };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-state.mjs","sources":["../../src/utils/create-state.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"create-state.mjs","sources":["../../src/utils/create-state.mts"],"sourcesContent":["import { type InitializedObservable } from '../core/index.mjs';\nimport { createReducer } from './create-reducer.mjs';\n\ntype Action<S> = Readonly<\n | {\n type: 'set';\n nextState: S;\n }\n | {\n type: 'update';\n updateFn: (a: S) => S;\n }\n>;\n\nconst reducer = <S,>(state: S, action: Action<S>): S => {\n switch (action.type) {\n case 'set':\n return action.nextState;\n\n case 'update':\n return action.updateFn(state);\n }\n};\n\n/**\n * Creates a reactive state container with getter and setter methods.\n * Provides a simple state management solution with observable state.\n *\n * @template S - The type of the state\n * @param initialState - The initial value of the state\n * @returns A 3-element tuple: `[state, setState, { updateState, resetState, getSnapshot, initialState }]`\n *\n * @example\n * ```ts\n * const [state, setState, { updateState, resetState }] = createState(0);\n *\n * const stateHistory: number[] = [];\n *\n * state.subscribe((value: number) => {\n * stateHistory.push(value);\n * });\n *\n * assert.deepStrictEqual(stateHistory, [0]);\n *\n * setState(10); // logs: 10\n *\n * assert.deepStrictEqual(stateHistory, [0, 10]);\n *\n * updateState((prev: number) => prev + 1); // logs: 11\n *\n * assert.deepStrictEqual(stateHistory, [0, 10, 11]);\n *\n * resetState(); // logs: 0\n *\n * assert.deepStrictEqual(stateHistory, [0, 10, 11, 0]);\n * ```\n */\nexport const createState = <S,>(\n initialState: S,\n): readonly [\n state: InitializedObservable<S>,\n setState: (v: S) => S,\n utils: Readonly<{\n updateState: (updateFn: (prev: S) => S) => S;\n resetState: () => S;\n getSnapshot: () => S;\n initialState: S;\n }>,\n] => {\n const [state, dispatch, { getSnapshot }] = createReducer<S, Action<S>>(\n reducer,\n initialState,\n );\n\n const updateState = (updateFn: (prev: S) => S): S =>\n dispatch({ type: 'update', updateFn });\n\n const setState = (nextState: S): S => dispatch({ type: 'set', nextState });\n\n const resetState = (): S =>\n dispatch({ type: 'set', nextState: initialState });\n\n return [\n state,\n setState,\n {\n updateState,\n resetState,\n getSnapshot,\n initialState,\n },\n ] as const;\n};\n"],"names":[],"mappings":";;AAcA,MAAM,OAAA,GAAU,CAAK,KAAA,EAAU,MAAA,KAAyB;AACtD,EAAA,QAAQ,OAAO,IAAA;AAAM,IACnB,KAAK,KAAA;AACH,MAAA,OAAO,MAAA,CAAO,SAAA;AAAA,IAEhB,KAAK,QAAA;AACH,MAAA,OAAO,MAAA,CAAO,SAAS,KAAK,CAAA;AAAA;AAElC,CAAA;AAmCO,MAAM,WAAA,GAAc,CACzB,YAAA,KAUG;AACH,EAAA,MAAM,CAAC,KAAA,EAAO,QAAA,EAAU,EAAE,WAAA,EAAa,CAAA,GAAI,aAAA;AAAA,IACzC,OAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,QAAA,KACnB,QAAA,CAAS,EAAE,IAAA,EAAM,QAAA,EAAU,UAAU,CAAA;AAEvC,EAAA,MAAM,QAAA,GAAW,CAAC,SAAA,KAAoB,QAAA,CAAS,EAAE,IAAA,EAAM,KAAA,EAAO,WAAW,CAAA;AAEzE,EAAA,MAAM,UAAA,GAAa,MACjB,QAAA,CAAS,EAAE,MAAM,KAAA,EAAO,SAAA,EAAW,cAAc,CAAA;AAEnD,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,MACE,WAAA;AAAA,MACA,UAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA;AACF,GACF;AACF;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "synstate",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Type-safe State Management Library for TypeScript/JavaScript",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,20 +28,20 @@
|
|
|
28
28
|
"LICENSE"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"ts-data-forge": "^
|
|
32
|
-
"ts-type-forge": "^
|
|
31
|
+
"ts-data-forge": "^14.2.0",
|
|
32
|
+
"ts-type-forge": "^9.2.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@reduxjs/toolkit": "2.12.0",
|
|
36
36
|
"@types/argparse": "2.0.17",
|
|
37
|
-
"@types/react": "19.2.
|
|
38
|
-
"argparse": "
|
|
39
|
-
"jotai": "2.
|
|
40
|
-
"mobx": "
|
|
41
|
-
"react": "19.2.
|
|
37
|
+
"@types/react": "19.2.18",
|
|
38
|
+
"argparse": "3.0.0",
|
|
39
|
+
"jotai": "2.20.2",
|
|
40
|
+
"mobx": "7.0.0",
|
|
41
|
+
"react": "19.2.8",
|
|
42
42
|
"rxjs": "7.8.2",
|
|
43
|
-
"valtio": "2.3.
|
|
44
|
-
"zustand": "5.0.
|
|
43
|
+
"valtio": "2.3.2",
|
|
44
|
+
"zustand": "5.0.14"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"benchmark": "tsx ./scripts/cmd/run-benchmark.mts",
|
|
@@ -68,10 +68,9 @@
|
|
|
68
68
|
"test:cov:ui": "vite preview --outDir ./coverage",
|
|
69
69
|
"test:ui": "pnpm run z:vitest:node --ui",
|
|
70
70
|
"testw": "pnpm run z:vitest:node watch",
|
|
71
|
-
"tsc": "tsc --noEmit",
|
|
72
|
-
"tscw": "tsc --noEmit --watch",
|
|
73
|
-
"type-check": "tsc --noEmit",
|
|
74
|
-
"update-packages": "pnpm update --latest",
|
|
71
|
+
"tsc": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
|
|
72
|
+
"tscw": "node ../../node_modules/typescript-native/bin/tsc --noEmit --watch",
|
|
73
|
+
"type-check": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
|
|
75
74
|
"z:prettier": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --ignore-path ../../.gitignore --ignore-unknown --no-error-on-unmatched-pattern --write",
|
|
76
75
|
"z:vitest": "vitest --config ./configs/vitest.config.mts",
|
|
77
76
|
"z:vitest:node": "pnpm run z:vitest --project='Node.js'",
|
|
@@ -128,8 +128,8 @@ export class AsyncChildObservableClass<A, const P extends NonEmptyUnknownList>
|
|
|
128
128
|
extends ObservableBaseClass<A, 'async child', number>
|
|
129
129
|
implements AsyncChildObservable<A, P>
|
|
130
130
|
{
|
|
131
|
-
readonly parents;
|
|
132
131
|
#mut_propagationOrder: readonly ChildObservable<unknown>[];
|
|
132
|
+
readonly parents;
|
|
133
133
|
protected readonly descendantsIdSet: MutableSet<ObservableId>;
|
|
134
134
|
|
|
135
135
|
constructor({
|
|
@@ -24,14 +24,14 @@ export class ObservableBaseClass<
|
|
|
24
24
|
Kind extends ObservableBase<A>['kind'],
|
|
25
25
|
Depth extends ObservableBase<A>['depth'],
|
|
26
26
|
> implements ObservableBase<A> {
|
|
27
|
-
readonly id;
|
|
28
|
-
readonly kind: Kind;
|
|
29
|
-
readonly depth: Depth;
|
|
30
27
|
#mut_children: readonly ChildObservable<unknown>[];
|
|
31
28
|
readonly #subscribers: MutableMap<SubscriberId, Subscriber<A>>;
|
|
32
29
|
#mut_currentValue: ReturnType<ObservableBase<A>['getSnapshot']>;
|
|
33
30
|
#mut_isCompleted: ObservableBase<A>['isCompleted'];
|
|
34
31
|
#mut_updateToken: ObservableBase<A>['updateToken'];
|
|
32
|
+
readonly id;
|
|
33
|
+
readonly kind: Kind;
|
|
34
|
+
readonly depth: Depth;
|
|
35
35
|
|
|
36
36
|
constructor({
|
|
37
37
|
kind,
|
|
@@ -59,6 +59,19 @@ export class ObservableBaseClass<
|
|
|
59
59
|
this.#mut_updateToken = issueUpdateToken();
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
#addSubscriber(s: Subscriber<A>): SubscriberId {
|
|
63
|
+
// return the id of added subscriber
|
|
64
|
+
const id = issueSubscriberId();
|
|
65
|
+
|
|
66
|
+
this.#subscribers.set(id, s);
|
|
67
|
+
|
|
68
|
+
return id;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
#removeSubscriber(id: SubscriberId): void {
|
|
72
|
+
this.#subscribers.delete(id);
|
|
73
|
+
}
|
|
74
|
+
|
|
62
75
|
addChild<B>(child: ChildObservable<B>): void {
|
|
63
76
|
this.#mut_children = Arr.toPushed(
|
|
64
77
|
this.#mut_children,
|
|
@@ -171,17 +184,4 @@ export class ObservableBaseClass<
|
|
|
171
184
|
},
|
|
172
185
|
};
|
|
173
186
|
}
|
|
174
|
-
|
|
175
|
-
#addSubscriber(s: Subscriber<A>): SubscriberId {
|
|
176
|
-
// return the id of added subscriber
|
|
177
|
-
const id = issueSubscriberId();
|
|
178
|
-
|
|
179
|
-
this.#subscribers.set(id, s);
|
|
180
|
-
|
|
181
|
-
return id;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
#removeSubscriber(id: SubscriberId): void {
|
|
185
|
-
this.#subscribers.delete(id);
|
|
186
|
-
}
|
|
187
187
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Arr,
|
|
2
|
-
import { type
|
|
1
|
+
import { Arr, expectType, Optional } from 'ts-data-forge';
|
|
2
|
+
import { type NonEmptyTuple, type Tuple } from 'ts-type-forge';
|
|
3
3
|
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
4
4
|
import { source } from '../create/index.mjs';
|
|
5
5
|
import { withInitialValue } from '../operators/index.mjs';
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
* ]);
|
|
73
73
|
* ```
|
|
74
74
|
*/
|
|
75
|
-
export const combine = <const OS extends
|
|
75
|
+
export const combine = <const OS extends NonEmptyTuple<Observable<unknown>>>(
|
|
76
76
|
parents: OS,
|
|
77
77
|
): CombineObservableRefined<OS> =>
|
|
78
78
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
@@ -91,35 +91,57 @@ class CombineObservableClass<const A extends NonEmptyUnknownList>
|
|
|
91
91
|
implements CombineObservable<A>
|
|
92
92
|
{
|
|
93
93
|
constructor(parents: Wrap<A>) {
|
|
94
|
-
const parentsValues =
|
|
94
|
+
const parentsValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
|
|
95
|
+
parents,
|
|
96
|
+
(p) => p.getSnapshot(),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// The annotation on `initialValue` is what replaces the type assertion.
|
|
100
|
+
// `Arr.map` carries a single result element type, so it reports `A[number]`
|
|
101
|
+
// at every position, and `Tuple.MapTo<A[number], A>` — the uniform mapping
|
|
102
|
+
// — is *not* assignable back to `A`. The positional
|
|
103
|
+
// `Readonly<{ [K in keyof A]: A[K] }>` is, and TypeScript accepts the
|
|
104
|
+
// uniform result into it because the two mapped types share `keyof A`. So
|
|
105
|
+
// it is the annotation, not an assertion, that records the position-wise
|
|
106
|
+
// fact the checker cannot derive on its own.
|
|
107
|
+
const initialValue: Optional<Readonly<{ [K in keyof A]: A[K] }>> =
|
|
108
|
+
Arr.every(parentsValues, Optional.isSome)
|
|
109
|
+
? Optional.some(Arr.map(parentsValues, (c) => c.value))
|
|
110
|
+
: Optional.none;
|
|
95
111
|
|
|
96
112
|
super({
|
|
97
113
|
parents,
|
|
98
|
-
initialValue
|
|
99
|
-
? Optional.some(
|
|
100
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
101
|
-
Arr.map(parentsValues, (c) => c.value) as A,
|
|
102
|
-
)
|
|
103
|
-
: Optional.none,
|
|
114
|
+
initialValue,
|
|
104
115
|
});
|
|
105
116
|
}
|
|
106
117
|
|
|
107
118
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
108
119
|
if (this.parents.every((o) => o.updateToken !== updateToken)) return; // all parents are skipped
|
|
109
120
|
|
|
110
|
-
|
|
121
|
+
// Same shape-preserving chain as the constructor: `Arr.map` (not the
|
|
122
|
+
// native one, which drops the tuple shape) into the uniform
|
|
123
|
+
// `Tuple.MapTo`, then a positional annotation to get back to `A`.
|
|
124
|
+
const parentValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
|
|
125
|
+
this.parents,
|
|
126
|
+
(a) => a.getSnapshot(),
|
|
127
|
+
);
|
|
111
128
|
|
|
112
|
-
if (
|
|
113
|
-
const nextValue =
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
if (Arr.every(parentValues, Optional.isSome)) {
|
|
130
|
+
const nextValue: Readonly<{ [K in keyof A]: A[K] }> = Arr.map(
|
|
131
|
+
parentValues,
|
|
132
|
+
(a) => a.value,
|
|
133
|
+
);
|
|
116
134
|
|
|
117
135
|
this.setNext(nextValue, updateToken);
|
|
118
136
|
}
|
|
119
137
|
}
|
|
120
138
|
}
|
|
121
139
|
|
|
122
|
-
{
|
|
140
|
+
if (import.meta.vitest !== undefined) {
|
|
141
|
+
test('type test', () => {
|
|
142
|
+
expect(1).toBe(1); // dummy
|
|
143
|
+
});
|
|
144
|
+
|
|
123
145
|
{
|
|
124
146
|
const s1: Observable<1> = source<1>();
|
|
125
147
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Optional, expectType } from 'ts-data-forge';
|
|
2
|
-
import { type ArrayElement, type
|
|
2
|
+
import { type ArrayElement, type NonEmptyTuple } from 'ts-type-forge';
|
|
3
3
|
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
4
4
|
import { source } from '../create/index.mjs';
|
|
5
5
|
import {
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
* @note To improve code readability, consider using `createState` instead of `merge`,
|
|
64
64
|
* subscribing to `parents` and calling `setState` within it.
|
|
65
65
|
*/
|
|
66
|
-
export const merge = <const OS extends
|
|
66
|
+
export const merge = <const OS extends NonEmptyTuple<Observable<unknown>>>(
|
|
67
67
|
parents: OS,
|
|
68
68
|
): MergeObservableRefined<OS> =>
|
|
69
69
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
@@ -104,7 +104,7 @@ if (import.meta.vitest !== undefined) {
|
|
|
104
104
|
|
|
105
105
|
const r2 = source('a');
|
|
106
106
|
|
|
107
|
-
const _m = merge([r1, r2]
|
|
107
|
+
const _m = merge([r1, r2]);
|
|
108
108
|
|
|
109
109
|
expectType<typeof _m, SyncChildObservable<number | string>>('<=');
|
|
110
110
|
}
|
package/src/core/combine/zip.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Arr, Optional, createQueue, expectType } from 'ts-data-forge';
|
|
2
|
-
import { type
|
|
2
|
+
import { type NonEmptyTuple, type Tuple } from 'ts-type-forge';
|
|
3
3
|
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
4
4
|
import { source } from '../create/index.mjs';
|
|
5
5
|
import { withInitialValue } from '../operators/index.mjs';
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
* ]);
|
|
66
66
|
* ```
|
|
67
67
|
*/
|
|
68
|
-
export const zip = <const OS extends
|
|
68
|
+
export const zip = <const OS extends NonEmptyTuple<Observable<unknown>>>(
|
|
69
69
|
parents: OS,
|
|
70
70
|
): ZipObservableRefined<OS> =>
|
|
71
71
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
@@ -78,21 +78,30 @@ class ZipObservableClass<const A extends NonEmptyUnknownList>
|
|
|
78
78
|
readonly #queues: TupleToQueueTuple<A>;
|
|
79
79
|
|
|
80
80
|
constructor(parents: Wrap<A>) {
|
|
81
|
-
const parentsValues =
|
|
81
|
+
const parentsValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
|
|
82
|
+
parents,
|
|
83
|
+
(p) => p.getSnapshot(),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// The annotation on `initialValue` is what replaces the type assertion.
|
|
87
|
+
// `Arr.map` carries a single result element type, so it reports `A[number]`
|
|
88
|
+
// at every position, and `Tuple.MapTo<A[number], A>` — the uniform mapping
|
|
89
|
+
// — is *not* assignable back to `A`. The positional
|
|
90
|
+
// `Readonly<{ [K in keyof A]: A[K] }>` is, and TypeScript accepts the
|
|
91
|
+
// uniform result into it because the two mapped types share `keyof A`. So
|
|
92
|
+
// it is the annotation, not an assertion, that records the position-wise
|
|
93
|
+
// fact the checker cannot derive on its own.
|
|
94
|
+
const initialValue: Optional<Readonly<{ [K in keyof A]: A[K] }>> =
|
|
95
|
+
Arr.every(parentsValues, Optional.isSome)
|
|
96
|
+
? Optional.some(Arr.map(parentsValues, (c) => c.value))
|
|
97
|
+
: Optional.none;
|
|
82
98
|
|
|
83
99
|
super({
|
|
84
100
|
parents,
|
|
85
|
-
initialValue
|
|
86
|
-
? Optional.some(
|
|
87
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
88
|
-
Arr.map(parentsValues, (c) => c.value) as A,
|
|
89
|
-
)
|
|
90
|
-
: Optional.none,
|
|
101
|
+
initialValue,
|
|
91
102
|
});
|
|
92
103
|
|
|
93
|
-
this.#queues = Arr.map(parents, () =>
|
|
94
|
-
createQueue(),
|
|
95
|
-
) satisfies TupleToQueueTuple<A>;
|
|
104
|
+
this.#queues = Arr.map(parents, () => createQueue());
|
|
96
105
|
}
|
|
97
106
|
|
|
98
107
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
@@ -108,6 +117,8 @@ class ZipObservableClass<const A extends NonEmptyUnknownList>
|
|
|
108
117
|
|
|
109
118
|
if (queues.every((list) => !list.isEmpty)) {
|
|
110
119
|
const nextValue =
|
|
120
|
+
// `Arr.map` has a single result element type, so it reports
|
|
121
|
+
// `A[number] | undefined` per position rather than `A[P]`.
|
|
111
122
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
112
123
|
Arr.map(queues, (q) => Optional.unwrap(q.dequeue())) as A;
|
|
113
124
|
|
|
@@ -160,7 +171,7 @@ if (import.meta.vitest !== undefined) {
|
|
|
160
171
|
|
|
161
172
|
const r2 = source('a');
|
|
162
173
|
|
|
163
|
-
const _z = zip([r1, r2]
|
|
174
|
+
const _z = zip([r1, r2]);
|
|
164
175
|
|
|
165
176
|
const _zi = zip([
|
|
166
177
|
r1.pipe(withInitialValue(0)),
|
|
@@ -36,7 +36,7 @@ import { type CounterObservable, type TimerId } from '../types/index.mjs';
|
|
|
36
36
|
*
|
|
37
37
|
* subscription.unsubscribe();
|
|
38
38
|
*
|
|
39
|
-
* assert.isTrue(Arr.
|
|
39
|
+
* assert.isTrue(Arr.isMinLengthArray(3, valueHistory));
|
|
40
40
|
*
|
|
41
41
|
* assert.deepStrictEqual(valueHistory[0], 0);
|
|
42
42
|
*
|
|
@@ -84,6 +84,16 @@ class CounterObservableClass
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
#resetTimer(): void {
|
|
88
|
+
if (this.#mut_timerId0 === undefined || this.#mut_timerId === undefined) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
clearInterval(this.#mut_timerId0);
|
|
93
|
+
|
|
94
|
+
clearInterval(this.#mut_timerId);
|
|
95
|
+
}
|
|
96
|
+
|
|
87
97
|
start(): void {
|
|
88
98
|
if (this.#mut_isStarted) {
|
|
89
99
|
console.warn('cannot start twice');
|
|
@@ -110,14 +120,6 @@ class CounterObservableClass
|
|
|
110
120
|
}, this.#intervalMilliSeconds);
|
|
111
121
|
}
|
|
112
122
|
|
|
113
|
-
#resetTimer(): void {
|
|
114
|
-
if (this.#mut_timerId0 !== undefined && this.#mut_timerId !== undefined) {
|
|
115
|
-
clearInterval(this.#mut_timerId0);
|
|
116
|
-
|
|
117
|
-
clearInterval(this.#mut_timerId);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
123
|
override complete(): void {
|
|
122
124
|
this.#resetTimer();
|
|
123
125
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { counter } from './counter.mjs';
|
|
2
|
+
|
|
3
|
+
describe(counter, () => {
|
|
4
|
+
test('completing before start() tears down without touching the timers', () => {
|
|
5
|
+
const counter$ = counter(10, { startManually: true });
|
|
6
|
+
|
|
7
|
+
counter$.complete();
|
|
8
|
+
|
|
9
|
+
assert.isTrue(counter$.isCompleted);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -68,6 +68,12 @@ class TimerObservableClass
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
#resetTimer(): void {
|
|
72
|
+
if (this.#mut_timerId !== undefined) {
|
|
73
|
+
clearTimeout(this.#mut_timerId);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
71
77
|
start(): void {
|
|
72
78
|
if (this.#mut_isStarted) {
|
|
73
79
|
console.warn('cannot start twice');
|
|
@@ -90,12 +96,6 @@ class TimerObservableClass
|
|
|
90
96
|
}, this.#milliSeconds);
|
|
91
97
|
}
|
|
92
98
|
|
|
93
|
-
#resetTimer(): void {
|
|
94
|
-
if (this.#mut_timerId !== undefined) {
|
|
95
|
-
clearTimeout(this.#mut_timerId);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
99
|
override complete(): void {
|
|
100
100
|
this.#resetTimer();
|
|
101
101
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { timer } from './timer.mjs';
|
|
2
|
+
|
|
3
|
+
describe(timer, () => {
|
|
4
|
+
test('completing before start() tears down without touching the timer', () => {
|
|
5
|
+
const timer$ = timer(10, { startManually: true });
|
|
6
|
+
|
|
7
|
+
timer$.complete();
|
|
8
|
+
|
|
9
|
+
assert.isTrue(timer$.isCompleted);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { source } from '../create/index.mjs';
|
|
2
|
+
import { audit } from './audit.mjs';
|
|
3
|
+
import { throttle } from './throttle.mjs';
|
|
4
|
+
|
|
5
|
+
describe('completing before any emission', () => {
|
|
6
|
+
test('audit tears down without a pending timer', () => {
|
|
7
|
+
const audited$ = source<number>().pipe(audit(10));
|
|
8
|
+
|
|
9
|
+
audited$.complete();
|
|
10
|
+
|
|
11
|
+
assert.isTrue(audited$.isCompleted);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('throttle tears down without a pending timer', () => {
|
|
15
|
+
const throttled$ = source<number>().pipe(throttle(10));
|
|
16
|
+
|
|
17
|
+
throttled$.complete();
|
|
18
|
+
|
|
19
|
+
assert.isTrue(throttled$.isCompleted);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -133,6 +133,12 @@ class AuditObservableClass<A>
|
|
|
133
133
|
this.#milliSeconds = milliSeconds;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
#resetTimer(): void {
|
|
137
|
+
if (this.#mut_timerId !== undefined) {
|
|
138
|
+
clearTimeout(this.#mut_timerId);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
136
142
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
137
143
|
const par = this.parents[0];
|
|
138
144
|
|
|
@@ -158,12 +164,6 @@ class AuditObservableClass<A>
|
|
|
158
164
|
}, this.#milliSeconds);
|
|
159
165
|
}
|
|
160
166
|
|
|
161
|
-
#resetTimer(): void {
|
|
162
|
-
if (this.#mut_timerId !== undefined) {
|
|
163
|
-
clearTimeout(this.#mut_timerId);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
167
|
override complete(): void {
|
|
168
168
|
this.#resetTimer();
|
|
169
169
|
|
|
@@ -121,6 +121,12 @@ class DebounceObservableClass<A>
|
|
|
121
121
|
this.#milliSeconds = milliSeconds;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
#resetTimer(): void {
|
|
125
|
+
if (this.#mut_timerId !== undefined) {
|
|
126
|
+
clearTimeout(this.#mut_timerId);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
124
130
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
125
131
|
const par = this.parents[0];
|
|
126
132
|
|
|
@@ -140,12 +146,6 @@ class DebounceObservableClass<A>
|
|
|
140
146
|
}, this.#milliSeconds);
|
|
141
147
|
}
|
|
142
148
|
|
|
143
|
-
#resetTimer(): void {
|
|
144
|
-
if (this.#mut_timerId !== undefined) {
|
|
145
|
-
clearTimeout(this.#mut_timerId);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
149
|
override complete(): void {
|
|
150
150
|
this.#resetTimer();
|
|
151
151
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Optional } from 'ts-data-forge';
|
|
2
|
+
import { type FixedLengthTuple } from 'ts-type-forge';
|
|
2
3
|
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
4
|
import {
|
|
4
5
|
type DropInitialValueOperator,
|
|
@@ -30,7 +31,7 @@ import {
|
|
|
30
31
|
*
|
|
31
32
|
* const pairs$ = num$.pipe(pairwise());
|
|
32
33
|
*
|
|
33
|
-
* const valueHistory:
|
|
34
|
+
* const valueHistory: FixedLengthTuple<2, number>[] = [];
|
|
34
35
|
*
|
|
35
36
|
* pairs$.subscribe(([prev, curr]) => {
|
|
36
37
|
* valueHistory.push([prev, curr]);
|
|
@@ -60,14 +61,18 @@ import {
|
|
|
60
61
|
* ]);
|
|
61
62
|
* ```
|
|
62
63
|
*/
|
|
63
|
-
export const pairwise = <A,>(): DropInitialValueOperator<
|
|
64
|
-
|
|
64
|
+
export const pairwise = <A,>(): DropInitialValueOperator<
|
|
65
|
+
A,
|
|
66
|
+
FixedLengthTuple<2, A>
|
|
67
|
+
> => f;
|
|
65
68
|
|
|
66
|
-
const f = <A,>(
|
|
69
|
+
const f = <A,>(
|
|
70
|
+
parentObservable: Observable<A>,
|
|
71
|
+
): Observable<FixedLengthTuple<2, A>> =>
|
|
67
72
|
new PairwiseObservableClass(parentObservable);
|
|
68
73
|
|
|
69
74
|
class PairwiseObservableClass<A>
|
|
70
|
-
extends SyncChildObservableClass<
|
|
75
|
+
extends SyncChildObservableClass<FixedLengthTuple<2, A>, readonly [A]>
|
|
71
76
|
implements PairwiseOperatorObservable<A>
|
|
72
77
|
{
|
|
73
78
|
#mut_previousValue: Optional<A>;
|
|
@@ -89,11 +89,7 @@ class SkipWhileObservableClass<A>
|
|
|
89
89
|
super({
|
|
90
90
|
parents: [parentObservable],
|
|
91
91
|
initialValue: pipe(parentObservable.getSnapshot()).map((sn) =>
|
|
92
|
-
Optional.isNone(sn)
|
|
93
|
-
? Optional.none
|
|
94
|
-
: predicate(sn.value, -1)
|
|
95
|
-
? Optional.none
|
|
96
|
-
: sn,
|
|
92
|
+
Optional.isNone(sn) || predicate(sn.value, -1) ? Optional.none : sn,
|
|
97
93
|
).value,
|
|
98
94
|
});
|
|
99
95
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Optional } from 'ts-data-forge';
|
|
2
|
+
import { just } from '../create/index.mjs';
|
|
3
|
+
import { skipWhile } from './skip-while.mjs';
|
|
4
|
+
|
|
5
|
+
describe(skipWhile, () => {
|
|
6
|
+
// Widened so the predicate is not statically decidable.
|
|
7
|
+
const seed: number = 1;
|
|
8
|
+
|
|
9
|
+
test('keeps an initialized parent value the predicate does not skip', () => {
|
|
10
|
+
const kept$ = just(seed).pipe(skipWhile((x) => x > 10));
|
|
11
|
+
|
|
12
|
+
expect(Optional.unwrapOr(kept$.getSnapshot(), -1)).toBe(1);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('drops an initialized parent value the predicate skips', () => {
|
|
16
|
+
const dropped$ = just(seed).pipe(skipWhile((x) => x < 10));
|
|
17
|
+
|
|
18
|
+
assert.isTrue(Optional.isNone(dropped$.getSnapshot()));
|
|
19
|
+
});
|
|
20
|
+
});
|