import { formatter } from './formatter.util' ; import { StoreConfigInterface } from './InterfaceDefinitions' ; const createSharedInterfaces = ( path , appName , storeConfig , zip ) : any => { const filePath = 'src/Interfaces.ts' ; const interfaceObj = storeConfig . interfaces ; const interfaceObjKeys = Object . keys ( interfaceObj ) ; if ( interfaceObjKeys . length === 0 ) return ; let data = '' ; interfaceObjKeys . forEach ( ( interfaceName ) => { let curInterface = `export interface ${ interfaceName } {\n` ; Object . keys ( interfaceObj [ interfaceName ] ) . forEach ( ( property ) => { const curType = interfaceObj [ interfaceName ] [ property ] ; curInterface += `${ property }: ${ curType };\n` ; } ) ; curInterface += '}\n\n' ; data += curInterface ; } ) ; zip . file ( filePath , formatter ( data ) ) ; } ; function createActionFiles ( path , appName , storeConfig , reducerName , zip ) { const reducerObj = storeConfig . reducers [ reducerName ] ; const actionTypesFile = `src/actions/${ reducerName }ActionTypes.ts` ; const actions = Object . keys ( reducerObj . actions ) ; let actionInterfacesText = '' ; let actionCreatorsText = '' ; const actionInterfaceNames = [ ] ; if ( actions . length === 0 ) return ; actions . forEach ( ( actionName , i ) => { const curActionObj = reducerObj . actions [ actionName ] ; const actionInterfaceName = `${ actionName }ActionInterface` ; actionInterfaceNames . push ( actionInterfaceName ) ; const bracketsIfPayloadIsAnArray = curActionObj . payload . array ? '[]' : '' ; const payloadType = curActionObj . payload . type ; const curActionInterface = `export interface ${ actionInterfaceName }{\n
      type: ${ reducerName }ActionTypes.${ actionName };
      payload?: ${ payloadType }${ bracketsIfPayloadIsAnArray };
    }\n\n` ; actionInterfacesText += curActionInterface ; let curActionCreatorText ; const bracketsIfParamIsAnArray = curActionObj . parameter . array ? '[]' : '' ; const paramWithColonIfParamExists = curActionObj . parameter . name ? `${ curActionObj . parameter . name } : ` : '' ; if ( curActionObj . async ) { curActionCreatorText = `export const ${ actionName } = (${ paramWithColonIfParamExists }${ curActionObj . parameter . type }${ bracketsIfParamIsAnArray }) => {
        return async (dispatch: Dispatch) => {
          // your code here ! add your own payload to the dispatched action.
          dispatch<${ actionInterfaceName }>({
            type: ${ reducerName }ActionTypes.${ actionName }
          });
        };
      };` ; } else { curActionCreatorText = `export const ${ actionName } =
      (${ paramWithColonIfParamExists }${ curActionObj . parameter . type }${ bracketsIfParamIsAnArray }) :
      ${ actionInterfaceName } => {
          // your code here ! add your own payload to the dispatched action.
          return {
            type: ${ reducerName }ActionTypes.${ actionName }
          };
      };` ; } actionCreatorsText += curActionCreatorText ; } ) ; const interfaceNameArray = Object . keys ( storeConfig . interfaces ) ; const interfacesImportText = interfaceNameArray . length ? `import {${ interfaceNameArray . toString ( ) }} from '../Interfaces';\n\n` : '' ; const actionTypesEnumText = `export enum ${ reducerName }ActionTypes{${ actions . toString ( ) }};\n\n` ; const typeGuardText = `export type ${ reducerName }ActionInterfaceUnion = ${ actionInterfaceNames . join ( '|' ) };\n\n` ; const firstFormat = formatter ( interfacesImportText + actionInterfacesText ) ; const secondFormat = formatter ( typeGuardText ) ; zip . file ( actionTypesFile , firstFormat + actionTypesEnumText + secondFormat ) ; const actionsFile = `src/actions/${ reducerName }Actions.ts` ; const actionsImportText = `import {Dispatch} from 'redux';
  import {${ reducerName }ActionTypes, ${ actionInterfaceNames . join ( ',' ) }} 
  from './${ reducerName }ActionTypes'\n` ; zip . file ( actionsFile , formatter ( actionsImportText + interfacesImportText + actionCreatorsText ) ) ; } function createReducerFiles ( path , appName , storeConfig , reducerName , zip ) { const reducerFile = `src/reducers/${ reducerName }Reducer.ts` ; const currentReducerStoreSlice = storeConfig . reducers [ reducerName ] . store ; const currentReducerStoreSliceKeys = Object . keys ( currentReducerStoreSlice ) ; const numberOfActions = Object . keys ( storeConfig . reducers [ reducerName ] . actions ) . length ; let importText = numberOfActions ? `import {${ reducerName }ActionInterfaceUnion, ${ reducerName }ActionTypes} from '../actions/${ reducerName }ActionTypes'\n` : '' ; const interfaceNameArray = Object . keys ( storeConfig . interfaces ) ; importText += interfaceNameArray . length ? `import {${ interfaceNameArray . toString ( ) }} from '../Interfaces';\n\n` : '' ; let storeSliceInterfaceText = `export interface ${ reducerName }StoreSliceInterface {` ; const initialState = { } ; currentReducerStoreSliceKeys . forEach ( ( storeSlicePropertyName ) => { const storeSlicePropObj = currentReducerStoreSlice [ storeSlicePropertyName ] ; const bracketsIfPropIsAnArray = storeSlicePropObj . array ? '[]' : '' ; storeSliceInterfaceText += `${ storeSlicePropertyName }: ${ storeSlicePropObj . type }${ bracketsIfPropIsAnArray };\n` ; try { const replacedStr = storeSlicePropObj . initialValue . replace ( /(\w+) ?(:)/g , ( wholeMatch , groupOne , groupTwo ) => `"${ groupOne }"${ groupTwo }` ) . replace ( /'/g , '"' ) ; initialState [ storeSlicePropertyName ] = JSON . parse ( replacedStr ) ; } catch ( e ) { initialState [ storeSlicePropertyName ] = storeSlicePropObj . initialValue ; } } ) ; storeSliceInterfaceText += '};\n\n' ; const initialStateText = `const initialState: ${ reducerName }StoreSliceInterface = ${ JSON . stringify ( initialState ) }\n\n` ; let reducerText = `export const ${ reducerName }Reducer =
  (state: ${ reducerName }StoreSliceInterface = initialState, action: ${ numberOfActions ? `${ reducerName }ActionInterfaceUnion` : 'any' }) => {
    switch(action.type){\n` ; Object . keys ( storeConfig . reducers [ reducerName ] . actions ) . forEach ( ( actionTypeName ) => { reducerText += `case ${ reducerName }ActionTypes.${ actionTypeName }:
    // your logic here!
    return state;\n` ; } ) ; reducerText += `default:
      return state;
    }
  };` ; zip . file ( reducerFile , formatter ( importText + storeSliceInterfaceText + initialStateText + reducerText ) ) ; } const createActionsAndStoresForEachReducer = ( path , appName , storeConfig , zip ) : void => { const rootReducerFile = 'src/reducers/index.ts' ; let rootReducerImportsText = "import {combineReducers} from 'redux';\n" ; let storeInterfaceText = 'export interface StoreInterface {\n' ; let combineReducersText = 'export const reducers = combineReducers<StoreInterface>({\n' ; const reducerNamesArray = Object . keys ( storeConfig . reducers ) ; if ( reducerNamesArray . length === 0 ) return ; reducerNamesArray . forEach ( ( reducerName ) => { rootReducerImportsText += `import {${ reducerName }Reducer, ${ reducerName }StoreSliceInterface } from './${ reducerName }Reducer';\n` ; storeInterfaceText += `${ reducerName }: ${ reducerName }StoreSliceInterface;\n` ; combineReducersText += `${ reducerName }: ${ reducerName }Reducer,\n` ; createActionFiles ( path , appName , storeConfig , reducerName , zip ) ; createReducerFiles ( path , appName , storeConfig , reducerName , zip ) ; } ) ; rootReducerImportsText += '\n' ; storeInterfaceText += '}\n\n' ; combineReducersText += '});\n' ; zip . file ( rootReducerFile , formatter ( rootReducerImportsText + storeInterfaceText + combineReducersText ) ) ; } ; export const createReduxFiles = async ( path , appName , storeConfig , zip ) : Promise < string > => { createSharedInterfaces ( path , appName , storeConfig , zip ) ; createActionsAndStoresForEachReducer ( path , appName , storeConfig , zip ) ; return null ; } ;