import type { ActionContext, Getter } from 'vuex';
import type {
ModuleBuilder,
Mutation,
ActionHandler,
ActionType,
} from './types';
import Vue from 'vue';
const actionCreator =
(
moduleName: () => string | undefined,
type: string,
) => (payload: P) => ({
type: moduleName() ? `${moduleName()}/${type}` : type,
payload,
});
function overrideActionContext(
action: ActionHandler,
) {
return (
store: ActionContext,
{ payload }: ReturnType>,
) =>
action(
{
...store,
commit: (type) => store.commit(type, { root: true }),
dispatch: (type) => store.dispatch(type, { root: true }),
},
payload,
);
}
/**
* Create a {@see ModuleBuilder} instance.
*
* ```ts
* interface RootState {
* module_one: {
* list: string[]
* }
* }
* const module = createModule({ list: [] });
*
* @param initialState - initial module state
* @typeParam State - Type of module state, usually an key in RootState.
* @typeParam RootState - Type of root store state
*/
export function createModule(
initialState: State,
): ModuleBuilder {
const mutations: Mutation[] = [];
const actions: ActionHandler[] = [];
const getters: Getter[] = [];
let moduleName: string;
const getModuleName = () => moduleName;
return >{
mutation(type: string, fn?: Mutation) {
if (!fn) {
return this.mutation(`${type}`, (state, value) => {
Vue.set(state as any, `${type}`, value);
});
}
fn.toString = () => `${type}`;
(mutations as Mutation[]).push(fn);
return actionCreator(getModuleName, type);
},
action(
type: string,
fn: ActionHandler,
) {
fn.toString = () => `${type}`;
(actions as ActionHandler[]).push(fn);
return actionCreator(getModuleName, type);
},
getter(type: string, fn: Getter) {
fn.toString = () => `${type}`;
getters.push(fn);
return (getter: any): Payload =>
getter[`${moduleName}/${type}`] || getter[type];
},
getModule(name = '') {
moduleName = name;
return {
name: moduleName,
namespaced: true,
state: initialState,
actions: actions.reduce((acc, action) => {
acc[action.toString()] = overrideActionContext(action);
return acc;
}, {}),
mutations: mutations.reduce((acc, mutation) => {
acc[mutation.toString()] = (store, { payload }) =>
mutation(store, payload);
return acc;
}, {}),
getters: getters.reduce((acc, getter) => {
acc[getter.toString()] = getter;
return acc;
}, {}),
};
},
};
}