@medamajs/compose
Version:
Composable state management extension for medama with support for hierarchical state layers, dynamic composition, and parallel state synchronization
64 lines (51 loc) • 1.95 kB
text/typescript
import type { Pupil, SubscribeToState } from 'medama';
import type { CStateG } from './auxiliaryTypes';
/**
* Higher-order function similar to Array.reduce but specialized for traversing
* nested states. Key features:
*
* 1. Sequential processing: Iterates through pupil records, allowing custom
* processing via processLayer
* 2. Final transform: Applies final operation to accumulated result
* 3. Selector sealing: Prevents re-evaluation of emitted steps when triggered
* as a selector in subscription events
*
* @param pupilRecords Array of tuples containing state keys and associated
* pupils
* @param processLayer Function to process each layer (can accumulate state,
* handle subscriptions, etc.)
* @param final Function to transform accumulated result into final value
* @returns Result of applying final function to accumulated value
*/
export const traverseThroughPupils = <CS extends CStateG, Acc, R>(
pupilRecords: [keyof CS, Pupil<CS[keyof CS]>][],
processLayer: (
key: keyof CS,
layerState: CS[keyof CS],
subscribeToState: SubscribeToState<CS[keyof CS]>,
selectorIdentity: (state: CS[keyof CS]) => void,
acc?: Acc
) => Acc,
final: (acc: Acc) => R
): R => {
let i = 0;
let selectorToSeal = false;
let acc: Acc | undefined;
const stepLogic = () => {
const nextPupilWithKey = pupilRecords[i++];
const [, { readState }] = nextPupilWithKey;
const nextStep = createStep(...nextPupilWithKey);
return readState(nextStep);
};
const createStep = (key: keyof CS, { subscribeToState }: Pupil<CS[keyof CS]>) => {
const stepEmitted = (state: CS[keyof CS]): R => {
if (selectorToSeal) return undefined as R;
acc = processLayer(key, state, subscribeToState, stepEmitted, acc);
if (i < pupilRecords.length) return stepLogic();
selectorToSeal = true;
return final(acc);
};
return stepEmitted;
};
return stepLogic();
};