UNPKG

@wordpress/data

Version:
150 lines (140 loc) 4.16 kB
/** * External dependencies */ import EquivalentKeyMap from 'equivalent-key-map'; import type { Reducer } from 'redux'; /** * Internal dependencies */ import { selectorArgsToStateKey, onSubKey } from './utils'; type Action = | ReturnType< typeof import('./actions').startResolution > | ReturnType< typeof import('./actions').finishResolution > | ReturnType< typeof import('./actions').failResolution > | ReturnType< typeof import('./actions').startResolutions > | ReturnType< typeof import('./actions').finishResolutions > | ReturnType< typeof import('./actions').failResolutions > | ReturnType< typeof import('./actions').invalidateResolution > | ReturnType< typeof import('./actions').invalidateResolutionForStore > | ReturnType< typeof import('./actions').invalidateResolutionForStoreSelector >; type StateKey = unknown[] | unknown; export type StateValue = | { status: 'resolving' | 'finished' } | { status: 'error'; error: Error | unknown }; export type Status = StateValue[ 'status' ]; export type State = EquivalentKeyMap< StateKey, StateValue >; /** * Reducer function returning next state for selector resolution of * subkeys, object form: * * selectorName -> EquivalentKeyMap<Array,boolean> */ const subKeysIsResolved: Reducer< Record< string, State >, Action > = onSubKey< State, Action >( 'selectorName' )( ( state = new EquivalentKeyMap(), action: Action ) => { switch ( action.type ) { case 'START_RESOLUTION': { const nextState = new EquivalentKeyMap( state ); nextState.set( selectorArgsToStateKey( action.args ), { status: 'resolving', } ); return nextState; } case 'FINISH_RESOLUTION': { const nextState = new EquivalentKeyMap( state ); nextState.set( selectorArgsToStateKey( action.args ), { status: 'finished', } ); return nextState; } case 'FAIL_RESOLUTION': { const nextState = new EquivalentKeyMap( state ); nextState.set( selectorArgsToStateKey( action.args ), { status: 'error', error: action.error, } ); return nextState; } case 'START_RESOLUTIONS': { const nextState = new EquivalentKeyMap( state ); for ( const resolutionArgs of action.args ) { nextState.set( selectorArgsToStateKey( resolutionArgs ), { status: 'resolving', } ); } return nextState; } case 'FINISH_RESOLUTIONS': { const nextState = new EquivalentKeyMap( state ); for ( const resolutionArgs of action.args ) { nextState.set( selectorArgsToStateKey( resolutionArgs ), { status: 'finished', } ); } return nextState; } case 'FAIL_RESOLUTIONS': { const nextState = new EquivalentKeyMap( state ); action.args.forEach( ( resolutionArgs, idx ) => { const resolutionState: StateValue = { status: 'error', error: undefined, }; const error = action.errors[ idx ]; if ( error ) { resolutionState.error = error; } nextState.set( selectorArgsToStateKey( resolutionArgs as unknown[] ), resolutionState ); } ); return nextState; } case 'INVALIDATE_RESOLUTION': { const nextState = new EquivalentKeyMap( state ); nextState.delete( selectorArgsToStateKey( action.args ) ); return nextState; } } return state; } ); /** * Reducer function returning next state for selector resolution, object form: * * selectorName -> EquivalentKeyMap<Array, boolean> * * @param state Current state. * @param action Dispatched action. * * @return Next state. */ const isResolved = ( state: Record< string, State > = {}, action: Action ) => { switch ( action.type ) { case 'INVALIDATE_RESOLUTION_FOR_STORE': return {}; case 'INVALIDATE_RESOLUTION_FOR_STORE_SELECTOR': { if ( action.selectorName in state ) { const { [ action.selectorName ]: removedSelector, ...restState } = state; return restState; } return state; } case 'START_RESOLUTION': case 'FINISH_RESOLUTION': case 'FAIL_RESOLUTION': case 'START_RESOLUTIONS': case 'FINISH_RESOLUTIONS': case 'FAIL_RESOLUTIONS': case 'INVALIDATE_RESOLUTION': return subKeysIsResolved( state, action ); } return state; }; export default isResolved;