import { get } from 'lodash' import { Reducer } from 'redux-actions' import { IDefinitionReducerMap, IInvokeDefinitionOptions, ReducerMapOrConstructor, IReducerDefinition, DefinitionGenerator } from '../types/definition' import { IModelDefinition } from '../types/model' import { makeScope } from '../makeScope' import { getActionType } from '../utils' import { getFormattedInitialState } from './initialState' import { ISelector, ISelectorMap } from '../types/selector' export interface ICreateModelGenerator { options: IInvokeDefinitionOptions defaultState: any reducerMap: ReducerMapOrConstructor selectorMap: ISelectorMap transformInitialState?: (state: any, params: { namespacing: string[] }) => LocalState } export const createModelGenerator = (params: ICreateModelGenerator) => (namespacing: string[]): IModelDefinition => { const { options, defaultState, reducerMap, selectorMap, transformInitialState, } = params const formattedInitialState = getFormattedInitialState({ initialState: options.initialState, defaultState, transformInitialState, namespacing }) const model: IModelDefinition = { kind: 'definition', actions: {}, initialState: formattedInitialState, reducers: {}, selectors: {} } let reducers: IDefinitionReducerMap if (typeof reducerMap === 'function') { reducers = reducerMap(options) } else { reducers = reducerMap } type ReducerTuple = [string, Reducer] const scope = makeScope(namespacing) for (const [key, fn] of Object.entries(reducers) as ReducerTuple[]) { const type = getActionType(namespacing, key) const { reducer, action } = scope(type, fn) model.reducers[type] = reducer model.actions[key] = action } type SelectorTuple = [string, ISelector] for (const [key, fn] of Object.entries(selectorMap) as SelectorTuple[]) { const selector: ISelector<{}> = (state: {}, args?: any) => fn(get(state, namespacing), args) model.selectors[key] = selector } return model }