@johngw/stream
Version:
Reactive programming tools using the WHATWG Streams API.
95 lines • 2.96 kB
JavaScript
import { StateReducerInit, } from '#transformers/stateReducer/Reducers';
/**
* Consumes actions and queues changes to a piece state with provided reducers.
*
* It's important to note that if the result of an action does not change
* the state then nothing is queued to the stream.
*
* @group Transformers
* @see {@link StatefulSubject:class}
* @example
* ```
* ---------------{'add author','Jane Austin'}--|
*
* stateReducer({
* __INIT__: () => ({ authors: [] }),
* 'add author': (state, author) => ({
* ...state,
* authors: [...state.authors, author]
* })
* })
*
* --{authors:[]}--{authors:['Jane Austin']}-----
* ```
*
* @example
* ```
* // The State will be the type of data you want to manipulate.
* interface State {
* authors: string[]
* }
*
* // The Actions are a record of "action name" to a parameter.
* // If the action doesn't require a parameter, use `void`.
* type Actions = {
* 'add author': string
* 'action that doesnt need a parameter': void
* }
*
* const controllable = new ControllableStream<StateReducerInput<Actions>>()
*
* // To get the best out of this API, pass the Actions type and State
* // during invocation.
* controllable
* .pipeThrough(stateReducer<Actions, State>(
* {
* __INIT__: () => ({ authors: [] }),
*
* 'add author': (state, author) => state.authors.includes(author) ? state : {
* ...state,
* authors: [...state.authors, author],
* },
*
* 'action that doesnt need a parameter': (state) => state
* }
* ))
* .pipeTo(write(console.info))
* // { action: '__INIT__', state: { authors: [] } }
*
* controllable.enqueue({ action: 'add author', param: 'Jane Austin' })
* // { action: 'add author', param: 'Jane Austin', state: { authors: ['Jane Austin'] } }
*
* controllable.enqueue({ action: 'add author', param: 'Jane Austin' })
* // **Nothing will be queued as the state did not change.**
* ```
*/
export function stateReducer(reducers) {
let state = Object.freeze(reducers[StateReducerInit]());
return new TransformStream({
start(controller) {
controller.enqueue({
action: StateReducerInit,
state,
});
},
transform(chunk, controller) {
let $state;
try {
// No idea why `chunk` (`StateReducerInput`) doesn't have typed properties.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
$state = reducers[chunk.action](state, chunk.param);
}
catch (error) {
return controller.error(error);
}
if ($state !== state) {
state = Object.freeze($state);
controller.enqueue({
...chunk,
state,
});
}
},
});
}
//# sourceMappingURL=stateReducer.js.map