aboutsummaryrefslogtreecommitdiffstats
path: root/src/actions/lib/actions.ts
blob: da27c2e2b815b0d92ed1defe22d20d0b021d78cb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import PropTypes from 'prop-types';

export interface ActionDefinitions {
  [key: string]: {
    [key: string]: PropTypes.InferType<any>;
  };
}

export interface Actions {
  [key: string]: {
    [key: string]: {
      (...args: any[]): void;
      listeners: Function[];
      notify: (params: any) => void;
      listen: (listener: (params: any) => void) => void;
      off: (listener: (params: any) => void) => void;
    };
  };
}

export const createActionsFromDefinitions = <T extends {}>(
  actionDefinitions: ActionDefinitions,
  validate: any,
): T => {
  const actions = {};
  // eslint-disable-next-line unicorn/no-array-for-each
  Object.keys(actionDefinitions).forEach(actionName => {
    const action = (params = {}) => {
      const schema = actionDefinitions[actionName];
      validate(schema, params, actionName);
      action.notify(params);
    };
    actions[actionName] = action;
    action.listeners = [];
    action.listen = listener => action.listeners.push(listener);
    action.off = listener => {
      const { listeners } = action;
      listeners.splice(listeners.indexOf(listener), 1);
    };
    action.notify = params =>
      // eslint-disable-next-line unicorn/no-array-for-each
      action.listeners.forEach(listener => listener(params));
  });
  return actions as T;
};

export default (definitions, validate) => {
  const newActions = {};
  // eslint-disable-next-line unicorn/no-array-for-each
  Object.keys(definitions).forEach(scopeName => {
    newActions[scopeName] = createActionsFromDefinitions(
      definitions[scopeName],
      validate,
    );
  });
  return newActions;
};