stunk 2.0.0 → 2.1.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 +1 -1
- package/dist/core/asyncChunk.d.ts +4 -4
- package/dist/core/asyncChunk.js +2 -3
- package/dist/core/computed.js +36 -24
- package/dist/core/selector.js +3 -17
- package/dist/core/types.d.ts +3 -3
- package/dist/use-react/hooks/useAsyncChunk.d.ts +3 -3
- package/dist/use-react/hooks/useAsyncChunk.js +1 -1
- package/package.json +26 -14
- package/jest.config.js +0 -4
- package/src/core/asyncChunk.ts +0 -83
- package/src/core/computed.ts +0 -65
- package/src/core/core.ts +0 -128
- package/src/core/selector.ts +0 -27
- package/src/core/types.ts +0 -17
- package/src/index.ts +0 -10
- package/src/middleware/history.ts +0 -113
- package/src/middleware/index.ts +0 -7
- package/src/middleware/logger.ts +0 -6
- package/src/middleware/persistence.ts +0 -45
- package/src/middleware/validator.ts +0 -8
- package/src/use-react/hooks/useAsyncChunk.ts +0 -38
- package/src/use-react/hooks/useChunk.ts +0 -40
- package/src/use-react/hooks/useChunkProperty.ts +0 -21
- package/src/use-react/hooks/useChunkValue.ts +0 -15
- package/src/use-react/hooks/useChunkValues.ts +0 -35
- package/src/use-react/hooks/useComputed.ts +0 -34
- package/src/use-react/hooks/useDerive.ts +0 -15
- package/src/use-react/index.ts +0 -9
- package/src/utils.ts +0 -103
- package/tests/async-chunk.test.ts +0 -215
- package/tests/batch-chunk.test.ts +0 -108
- package/tests/chunk.test.ts +0 -189
- package/tests/computed.test.ts +0 -93
- package/tests/history.test.ts +0 -99
- package/tests/middleware.test.ts +0 -37
- package/tests/persist.test.ts +0 -57
- package/tests/select-chunk.test.ts +0 -133
- package/tests/update.test.ts +0 -70
- package/tsconfig.json +0 -23
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { Chunk } from "../core/core";
|
|
2
|
-
|
|
3
|
-
export interface ChunkWithHistory<T> extends Chunk<T> {
|
|
4
|
-
/**
|
|
5
|
-
* Reverts to the previous state (if available).
|
|
6
|
-
*/
|
|
7
|
-
undo: () => void;
|
|
8
|
-
/**
|
|
9
|
-
* Moves to the next state (if available).
|
|
10
|
-
*/
|
|
11
|
-
redo: () => void;
|
|
12
|
-
/**
|
|
13
|
-
* Returns true if there is a previous state to revert to.
|
|
14
|
-
*/
|
|
15
|
-
canUndo: () => boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Returns true if there is a next state to move to.
|
|
18
|
-
*/
|
|
19
|
-
canRedo: () => boolean;
|
|
20
|
-
/**
|
|
21
|
-
* Returns an array of all the values in the history.
|
|
22
|
-
*/
|
|
23
|
-
getHistory: () => T[];
|
|
24
|
-
/**
|
|
25
|
-
* Clears the history, keeping only the current value.
|
|
26
|
-
*/
|
|
27
|
-
clearHistory: () => void;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function withHistory<T>(
|
|
31
|
-
baseChunk: Chunk<T>,
|
|
32
|
-
options: { maxHistory?: number } = {}
|
|
33
|
-
): ChunkWithHistory<T> {
|
|
34
|
-
const { maxHistory = 100 } = options;
|
|
35
|
-
const history: T[] = [baseChunk.get()];
|
|
36
|
-
let currentIndex = 0;
|
|
37
|
-
let isHistoryAction = false;
|
|
38
|
-
|
|
39
|
-
const historyChunk: ChunkWithHistory<T> = {
|
|
40
|
-
...baseChunk,
|
|
41
|
-
|
|
42
|
-
set: (newValueOrUpdater: T | ((currentValue: T) => T)) => {
|
|
43
|
-
if (isHistoryAction) {
|
|
44
|
-
baseChunk.set(newValueOrUpdater);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Process the value or updater function
|
|
49
|
-
let newValue: T;
|
|
50
|
-
if (typeof newValueOrUpdater === 'function') {
|
|
51
|
-
// Get current value and apply the updater function
|
|
52
|
-
const currentValue = baseChunk.get();
|
|
53
|
-
newValue = (newValueOrUpdater as ((currentValue: T) => T))(currentValue);
|
|
54
|
-
} else {
|
|
55
|
-
// Use directly as the new value
|
|
56
|
-
newValue = newValueOrUpdater;
|
|
57
|
-
}
|
|
58
|
-
history.splice(currentIndex + 1);
|
|
59
|
-
history.push(newValue);
|
|
60
|
-
|
|
61
|
-
// Limit history size
|
|
62
|
-
if (history.length > maxHistory) {
|
|
63
|
-
console.warn("History limit reached. Removing oldest entries.");
|
|
64
|
-
const removeCount = history.length - maxHistory;
|
|
65
|
-
history.splice(0, removeCount);
|
|
66
|
-
currentIndex = Math.max(0, currentIndex - removeCount);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
currentIndex = history.length - 1;
|
|
70
|
-
baseChunk.set(newValue);
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
undo: () => {
|
|
74
|
-
if (!historyChunk.canUndo()) return;
|
|
75
|
-
|
|
76
|
-
isHistoryAction = true;
|
|
77
|
-
currentIndex--;
|
|
78
|
-
historyChunk.set(history[currentIndex]);
|
|
79
|
-
isHistoryAction = false;
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
redo: () => {
|
|
83
|
-
if (!historyChunk.canRedo()) return;
|
|
84
|
-
|
|
85
|
-
isHistoryAction = true;
|
|
86
|
-
currentIndex++;
|
|
87
|
-
historyChunk.set(history[currentIndex]);
|
|
88
|
-
isHistoryAction = false;
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
canUndo: () => currentIndex > 0,
|
|
92
|
-
|
|
93
|
-
canRedo: () => currentIndex < history.length - 1,
|
|
94
|
-
|
|
95
|
-
getHistory: () => [...history],
|
|
96
|
-
|
|
97
|
-
clearHistory: () => {
|
|
98
|
-
const currentValue = baseChunk.get();
|
|
99
|
-
history.length = 0;
|
|
100
|
-
history.push(currentValue);
|
|
101
|
-
currentIndex = 0;
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
// Override destroy to clean up history
|
|
105
|
-
destroy: () => {
|
|
106
|
-
history.length = 0;
|
|
107
|
-
baseChunk.destroy();
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return historyChunk;
|
|
112
|
-
|
|
113
|
-
}
|
package/src/middleware/index.ts
DELETED
package/src/middleware/logger.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Chunk } from "../core/core";
|
|
2
|
-
|
|
3
|
-
export interface PersistOptions<T> {
|
|
4
|
-
key: string;
|
|
5
|
-
storage?: Storage;
|
|
6
|
-
serialize?: (value: T) => string;
|
|
7
|
-
deserialize?: (value: string) => T;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function withPersistence<T>(
|
|
11
|
-
baseChunk: Chunk<T>,
|
|
12
|
-
options: PersistOptions<T>
|
|
13
|
-
): Chunk<T> {
|
|
14
|
-
const {
|
|
15
|
-
key,
|
|
16
|
-
storage = localStorage,
|
|
17
|
-
serialize = JSON.stringify,
|
|
18
|
-
deserialize = JSON.parse,
|
|
19
|
-
} = options;
|
|
20
|
-
|
|
21
|
-
// Try to load initial state from storage
|
|
22
|
-
try {
|
|
23
|
-
const savedChunk = storage.getItem(key);
|
|
24
|
-
if (savedChunk) {
|
|
25
|
-
const parsed = deserialize(savedChunk);
|
|
26
|
-
baseChunk.set(parsed)
|
|
27
|
-
}
|
|
28
|
-
} catch (error) {
|
|
29
|
-
console.error('Failed to load persisted state:', error);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Save to storage
|
|
33
|
-
baseChunk.subscribe((newValue) => {
|
|
34
|
-
try {
|
|
35
|
-
const serialized = serialize(newValue);
|
|
36
|
-
storage.setItem(key, serialized);
|
|
37
|
-
|
|
38
|
-
} catch (error) {
|
|
39
|
-
console.log('Failed to persist chunk', error)
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
return baseChunk
|
|
44
|
-
|
|
45
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback } from "react";
|
|
2
|
-
|
|
3
|
-
import { AsyncChunk, AsyncState } from "../../core/asyncChunk";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* A hook that handles asynchronous state with built-in reactivity.
|
|
7
|
-
* Provides loading, error, and data states.
|
|
8
|
-
*/
|
|
9
|
-
export function useAsyncChunk<T>(asyncChunk: AsyncChunk<T>) {
|
|
10
|
-
const [state, setState] = useState<AsyncState<T>>(() => asyncChunk.get());
|
|
11
|
-
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
const unsubscribe = asyncChunk.subscribe((newState) => {
|
|
14
|
-
setState(newState);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
return () => unsubscribe();
|
|
18
|
-
}, [asyncChunk]);
|
|
19
|
-
|
|
20
|
-
const reload = useCallback(() => asyncChunk.reload(), [asyncChunk]);
|
|
21
|
-
const mutate = useCallback(
|
|
22
|
-
(mutator: (currentData: T | null) => T) => asyncChunk.mutate(mutator),
|
|
23
|
-
[asyncChunk]
|
|
24
|
-
);
|
|
25
|
-
const reset = useCallback(() => asyncChunk.reset(), [asyncChunk]);
|
|
26
|
-
|
|
27
|
-
const { data, loading, error } = state;
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
state,
|
|
31
|
-
data,
|
|
32
|
-
loading,
|
|
33
|
-
error,
|
|
34
|
-
reload,
|
|
35
|
-
mutate,
|
|
36
|
-
reset
|
|
37
|
-
};
|
|
38
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback } from "react";
|
|
2
|
-
|
|
3
|
-
import { select } from "../../core/selector";
|
|
4
|
-
|
|
5
|
-
import type { Chunk } from "../../core/core";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A lightweight hook that subscribes to a chunk and returns its current value, along with setters, selector, reset and destroy.
|
|
9
|
-
* Ensures reactivity and prevents unnecessary re-renders.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export function useChunk<T, S = T>(
|
|
13
|
-
chunk: Chunk<T>,
|
|
14
|
-
selector?: (value: T) => S
|
|
15
|
-
) {
|
|
16
|
-
const selectedChunk = selector ? select(chunk, selector) : chunk;
|
|
17
|
-
|
|
18
|
-
const [state, setState] = useState<S>(() => selectedChunk.get() as S);
|
|
19
|
-
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
const unsubscribe = selectedChunk.subscribe((newValue) => {
|
|
22
|
-
setState(() => newValue as S);
|
|
23
|
-
});
|
|
24
|
-
return () => unsubscribe();
|
|
25
|
-
}, [selectedChunk]);
|
|
26
|
-
|
|
27
|
-
const set = useCallback((valueOrUpdater: T | ((currentValue: T) => T)) => {
|
|
28
|
-
chunk.set(valueOrUpdater);
|
|
29
|
-
}, [chunk]);
|
|
30
|
-
|
|
31
|
-
const reset = useCallback(() => {
|
|
32
|
-
chunk.reset();
|
|
33
|
-
}, [chunk]);
|
|
34
|
-
|
|
35
|
-
const destroy = useCallback(() => {
|
|
36
|
-
chunk.destroy();
|
|
37
|
-
}, [chunk]);
|
|
38
|
-
|
|
39
|
-
return [state, set, reset, destroy] as const;
|
|
40
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
2
|
-
|
|
3
|
-
import { useChunkValue } from "./useChunkValue";
|
|
4
|
-
|
|
5
|
-
import type { Chunk } from "../../core/core";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A hook that subscribes to a specific property of a chunk.
|
|
9
|
-
* This optimizes renders by only updating when the selected property changes.
|
|
10
|
-
*/
|
|
11
|
-
export function useChunkProperty<T, K extends keyof T>(
|
|
12
|
-
chunk: Chunk<T>,
|
|
13
|
-
property: K
|
|
14
|
-
): T[K] {
|
|
15
|
-
const selector = useMemo(
|
|
16
|
-
() => (state: T) => state[property],
|
|
17
|
-
[property]
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
return useChunkValue(chunk, selector);
|
|
21
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { useChunk } from "./useChunk";
|
|
2
|
-
|
|
3
|
-
import type { Chunk } from "../../core/core";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* A lightweight hook that subscribes to a chunk and returns only its current value.
|
|
7
|
-
* Useful for read-only components that don't need to update the chunk.
|
|
8
|
-
*/
|
|
9
|
-
export function useChunkValue<T, S = T>(
|
|
10
|
-
chunk: Chunk<T>,
|
|
11
|
-
selector?: (value: T) => S
|
|
12
|
-
): S {
|
|
13
|
-
const [value] = useChunk(chunk, selector);
|
|
14
|
-
return value;
|
|
15
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from "react";
|
|
2
|
-
|
|
3
|
-
import type { Chunk } from "../../core/core";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Hook to read values from multiple chunks at once.
|
|
7
|
-
* Only re-renders when any of the chunk values change.
|
|
8
|
-
*/
|
|
9
|
-
export function useChunkValues<T extends Chunk<any>[]>(
|
|
10
|
-
chunks: [...T]
|
|
11
|
-
): { [K in keyof T]: T[K] extends Chunk<infer U> ? U : never } {
|
|
12
|
-
type ReturnType = { [K in keyof T]: T[K] extends Chunk<infer U> ? U : never };
|
|
13
|
-
|
|
14
|
-
const [values, setValues] = useState<ReturnType>(() => {
|
|
15
|
-
return chunks.map(chunk => chunk.get()) as ReturnType;
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
const unsubscribes = chunks.map((chunk, index) => {
|
|
20
|
-
return chunk.subscribe((newValue) => {
|
|
21
|
-
setValues(prev => {
|
|
22
|
-
const newValues = [...prev] as ReturnType;
|
|
23
|
-
newValues[index] = newValue;
|
|
24
|
-
return newValues;
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
return () => {
|
|
30
|
-
unsubscribes.forEach(unsubscribe => unsubscribe());
|
|
31
|
-
};
|
|
32
|
-
}, [chunks]);
|
|
33
|
-
|
|
34
|
-
return values;
|
|
35
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useMemo } from "react";
|
|
2
|
-
|
|
3
|
-
import { computed, DependencyValues } from "../../core/computed";
|
|
4
|
-
import type { Chunk } from "../../core/core";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A hook that computes a value based on multiple chunks.
|
|
8
|
-
* Automatically re-computes when any dependency changes.
|
|
9
|
-
*/
|
|
10
|
-
export function useComputed<TDeps extends Chunk<any>[], TResult>(
|
|
11
|
-
dependencies: [...TDeps],
|
|
12
|
-
computeFn: (...args: DependencyValues<TDeps>) => TResult
|
|
13
|
-
): TResult {
|
|
14
|
-
// Create the computed value - memoize it based on dependencies to prevent recreation
|
|
15
|
-
const computedValue = useMemo(
|
|
16
|
-
() => computed(dependencies, computeFn),
|
|
17
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
18
|
-
[...dependencies]
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
const [state, setState] = useState<TResult>(() => computedValue.get());
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
const unsubscribe = computedValue.subscribe((newValue) => {
|
|
25
|
-
setState(newValue);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
return () => {
|
|
29
|
-
unsubscribe();
|
|
30
|
-
};
|
|
31
|
-
}, [computedValue]);
|
|
32
|
-
|
|
33
|
-
return state;
|
|
34
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
2
|
-
|
|
3
|
-
import { useChunk } from "./useChunk";
|
|
4
|
-
import type { Chunk } from "../../core/core";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A hook for creating a read-only derived value from a chunk.
|
|
8
|
-
* Ensures reactivity and updates when the source chunk changes.
|
|
9
|
-
*/
|
|
10
|
-
export function useDerive<T, D>(chunk: Chunk<T>, fn: (value: T) => D): D {
|
|
11
|
-
const derivedChunk = useMemo(() => chunk.derive(fn), [chunk, fn]);
|
|
12
|
-
const [derivedValue] = useChunk(derivedChunk);
|
|
13
|
-
|
|
14
|
-
return derivedValue;
|
|
15
|
-
}
|
package/src/use-react/index.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export { useChunk } from './hooks/useChunk'
|
|
2
|
-
export { useDerive } from './hooks/useDerive'
|
|
3
|
-
export { useComputed } from './hooks/useComputed'
|
|
4
|
-
|
|
5
|
-
export { useChunkValue } from './hooks/useChunkValue'
|
|
6
|
-
export { useChunkProperty } from './hooks/useChunkProperty'
|
|
7
|
-
export { useChunkValues } from './hooks/useChunkValues'
|
|
8
|
-
|
|
9
|
-
export { useAsyncChunk } from './hooks/useAsyncChunk'
|
package/src/utils.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { chunk, Chunk, Middleware } from "./core/core";
|
|
2
|
-
|
|
3
|
-
import { AsyncChunk } from "./core/asyncChunk";
|
|
4
|
-
import { CombinedData, CombinedState, InferAsyncData } from "./core/types";
|
|
5
|
-
|
|
6
|
-
export function isValidChunkValue(value: any): boolean {
|
|
7
|
-
return value !== null && value !== undefined;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function isChunk<T>(value: any): value is Chunk<T> {
|
|
11
|
-
return value &&
|
|
12
|
-
typeof value.get === 'function' &&
|
|
13
|
-
typeof value.set === 'function' &&
|
|
14
|
-
typeof value.update === 'function' &&
|
|
15
|
-
typeof value.subscribe === 'function' &&
|
|
16
|
-
typeof value.derive === 'function' &&
|
|
17
|
-
typeof value.reset === 'function' &&
|
|
18
|
-
typeof value.destroy === 'function';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function once<T>(fn: () => T): () => T {
|
|
22
|
-
let called = false;
|
|
23
|
-
let result: T;
|
|
24
|
-
return () => {
|
|
25
|
-
if (!called) {
|
|
26
|
-
result = fn();
|
|
27
|
-
called = true;
|
|
28
|
-
}
|
|
29
|
-
return result;
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function combineAsyncChunks<T extends Record<string, AsyncChunk<any>>>(
|
|
34
|
-
chunks: T
|
|
35
|
-
): Chunk<{
|
|
36
|
-
loading: boolean;
|
|
37
|
-
error: Error | null;
|
|
38
|
-
data: { [K in keyof T]: InferAsyncData<T[K]> | null };
|
|
39
|
-
}> {
|
|
40
|
-
// Create initial state with proper typing
|
|
41
|
-
const initialData = Object.keys(chunks).reduce((acc, key) => {
|
|
42
|
-
acc[key as keyof T] = null;
|
|
43
|
-
return acc;
|
|
44
|
-
}, {} as CombinedData<T>);
|
|
45
|
-
|
|
46
|
-
const initialState: CombinedState<T> = {
|
|
47
|
-
loading: true,
|
|
48
|
-
error: null,
|
|
49
|
-
data: initialData
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const combined = chunk(initialState);
|
|
53
|
-
|
|
54
|
-
Object.entries(chunks).forEach(([key, asyncChunk]) => {
|
|
55
|
-
asyncChunk.subscribe((state) => {
|
|
56
|
-
const currentState = combined.get();
|
|
57
|
-
|
|
58
|
-
combined.set({
|
|
59
|
-
loading: Object.values(chunks).some(chunk => chunk.get().loading),
|
|
60
|
-
error: Object.values(chunks)
|
|
61
|
-
.map(chunk => chunk.get().error)
|
|
62
|
-
.find(error => error !== null) || null,
|
|
63
|
-
data: {
|
|
64
|
-
...currentState.data,
|
|
65
|
-
[key]: state.data
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
return combined;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function processMiddleware<T>(initialValue: T, middleware: Middleware<T>[] = []): T {
|
|
75
|
-
if (initialValue === null || initialValue === undefined) {
|
|
76
|
-
throw new Error("Value cannot be null or undefined.");
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let currentValue = initialValue;
|
|
80
|
-
let index = 0;
|
|
81
|
-
|
|
82
|
-
while (index < middleware.length) {
|
|
83
|
-
const currentMiddleware = middleware[index];
|
|
84
|
-
let nextCalled = false;
|
|
85
|
-
let nextValue: T | null = null;
|
|
86
|
-
|
|
87
|
-
currentMiddleware(currentValue, (val) => {
|
|
88
|
-
nextCalled = true;
|
|
89
|
-
nextValue = val;
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
if (!nextCalled) break;
|
|
93
|
-
|
|
94
|
-
if (nextValue === null || nextValue === undefined) {
|
|
95
|
-
throw new Error("Value cannot be null or undefined.");
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
currentValue = nextValue;
|
|
99
|
-
index++;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return currentValue;
|
|
103
|
-
}
|