-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
60 lines (50 loc) · 2.15 KB
/
index.js
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
58
59
60
const SCOPE_DELIMITER = '/';
const SCOPE_WILDCARD = '*';
// prefix action type with given scope
const scopeType = (type, scope) => typeof type === 'string' ? scope + SCOPE_DELIMITER + type : scope + SCOPE_DELIMITER;
// remove given scope from action type
const descopeType = (type, scope) => typeof type === 'string' && type.startsWith(scope) ? type.substring(scope.length + SCOPE_DELIMITER.length) : type;
// remove any given scope from action type
const descopeAnyType = type => typeof type === 'string' ? type.substring(type.lastIndexOf(SCOPE_DELIMITER) + 1) : type;
// change the type of the action with given scope
const scopeAction = (action, scope) => {
action.type = scopeType(action.type, scope);
return action;
};
// change the type of the action with given scope
const descopeAction = (action, scope) => {
const type = (scope === SCOPE_WILDCARD) ? descopeAnyType(action.type) : descopeType(action.type, scope);
return Object.assign({}, action, {type});
};
// returns a new dispatch() function
// that prefixes all action types using given scope
const scopeDispatch = dispatch => scope => action => dispatch(scopeAction(action, scope));
// returns a new getState() function
// that extracts the a subset of the root state using given scope
const scopeGetState = getState => scope => () => {
const scopedGetState = (state, aScope) => {
if (state) {
const number = parseInt(aScope, 10);
return isNaN(number) ? state[aScope] : state[number];
}
return state;
}
return scope.split(SCOPE_DELIMITER).reduce(scopedGetState, getState());
};
// scopes the dispatch and getState functions of the store
const scopeStore = store => {
const createScopedDispatch = scopeDispatch(store.dispatch);
const createScopedGetState = scopeGetState(store.getState);
return scope => Object.assign({}, store, {
dispatch: createScopedDispatch(scope),
getState: createScopedGetState(scope)
});
};
// descopes all actions before passed to the reducer
const scopeReducer = reducer => scope => (previousState, action) => reducer(previousState, descopeAction(action, scope));
module.exports = {
scopeReducer,
scopeDispatch,
scopeStore,
scopeGetState
};