-
Notifications
You must be signed in to change notification settings - Fork 0
/
updeep.ts
135 lines (118 loc) · 4.82 KB
/
updeep.ts
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import updeep = require('updeep');
import { Action, Reducer, Store, createStore } from 'redux';
// The get method is used to extract data from an object hierarchy. Path
// is just a type we are importing here.
import { get, Path } from './access';
import { FluxStandardAction as FSA } from './actions';
export interface PathPayload {
path: Path; // member reference
}
// The SetPathPayload type is used by the setPath action
export interface SetPathPayload extends PathPayload {
v: any; // value to give that member
}
// The MapPathPayload type is used by the mapPath action
export interface MapPathPayload<T> extends PathPayload {
f: (v: T) => T; // function to apply to that member
}
export type PathAction<T extends PathPayload> = FSA<T, void>;
export type SetAction = PathAction<SetPathPayload>;
export type MapAction<T> = PathAction<MapPathPayload<T>>;
// Constant used as the action type for the setPath action
export const UPDEEP_SET_PATH: string = 'UPDEEP_SET_PATH';
// An action creator that creates an action that sets a given
// element in an object hierarchy to a specified value
export const setPath = <T>(path: Path, v: T): SetAction => {
return {
"type": UPDEEP_SET_PATH,
"payload": {
path: path,
v: v,
},
};
};
// An action creator that creates an action that overlays
// data a portion of the state on top of the previous state.
// For this action to be used, the overlay fragment has to
// have the same type as the state. This typically means
// that many elements of the state need to be optional.
// This is nearly analogous to the setPath action except
// that a) it allows more fields to be set and b) it provides
// greater type safety.
export const UPDEEP_OVERLAY: string = 'UPDEEP_OVERLAY';
export const updeepOverlay = <T>(partial: T): FSA<T, void> => {
return {
"type": UPDEEP_OVERLAY,
"payload": partial,
};
};
// Constant used as the action type for the mapPath action
export const UPDEEP_MAP_PATH = 'UPDEEP_MAP_PATH';
// An action creator that creates an action that applies the provided
// function to the value of a specified element in an object hierarchy
export const mapPath = <T>(path: Path, f: (v: T) => T): MapAction<T> => {
return {
"type": UPDEEP_MAP_PATH,
"payload": {
"path": path,
"f": f,
},
};
};
// This function takes an existing PathAction (one where the target is specified
// with a Array<string|number>) and prepends some additional path elements to
// the path. This creates a new action and has no impact on the value of the
// action passed as an argument.
export function applyAt<T extends PathPayload>(path: Path, action: PathAction<T>)
: PathAction<T> {
'use strict';
let newpath: Path = [].concat(path).concat(action.payload.path);
return updeep({payload: { path: newpath}}, action);
}
export interface UpdeepAction<T> {
(s: T, action: Action): T;
}
export type ActionMap<T> = { [key: string]: UpdeepAction<T> };
export function updeepReducer2<T extends {}>(state0: T, actions: ActionMap<T>): Reducer<T> {
'use strict';
return function red(state: T = state0, action: Action): T {
let act = actions[action.type];
if (act) {
return act(state, action);
}
return state;
};
};
// This function produces a reducer that manages an object of the specified
// type, T. To create the reducer, an initial state value must be provided.
// This type of reducer responds to the following actions:
// - UPDEEP_SET_PATH: Set a given element to a specified value
// - UPDEEP_MAP_PATH: Apply the specified function an the value of the given element
// - UPDEEP_OVERLAY: Apply an overlay to a given value
export function updeepReducer<T extends {}>(state0: T): Reducer<T> {
'use strict';
return function red(state: T = state0, action: Action): T {
switch (action.type) {
case UPDEEP_SET_PATH:
let sa = action as SetAction;
// Update the value in the hierarchy to a prescribed value
return updeep.updateIn(sa.payload.path, sa.payload.v, state);
case UPDEEP_MAP_PATH:
let ma = action as MapAction<any>;
// Get the current value of the specified element
let mcur: any = get(ma.payload.path, state);
// Update it's value to the result of applying the provided function
return updeep.updateIn(ma.payload.path, ma.payload.f(mcur), state);
case UPDEEP_OVERLAY:
let oa = action as FSA<{}, any>;
return updeep(oa.payload, state);
default:
return state;
}
};
};
// Create a store for a state of type T given an initial state.
export function updeepStore<T extends {}>(state0: T): Store<T> {
'use strict';
return createStore(updeepReducer(state0));
}