UNPKG

@johngw/stream

Version:

Reactive programming tools using the WHATWG Streams API.

95 lines 2.96 kB
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