-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.js
168 lines (145 loc) · 4.37 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
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
var extend = require("extend")
// dev || prod
var env = "dev"
var pSlice = Array.prototype.slice
var regSplit = /\s+|\./
var toString = Object.prototype.toString
function isObject(obj) {
return obj && typeof obj === "object"
}
function isPlainObject(obj) {
return obj && toString.call(obj) === '[object Object]'
}
function reportValueNotObject(props, prop, value) {
console.warn("[dvaReducer]: props contains not object value: ")
console.warn("[" + props.join(", ") + "]")
console.warn(prop)
console.warn(value)
}
function reportStateNotObject(state) {
console.warn("[dvaReducer]: state is not object")
console.warn(state)
}
function reportPropsTypeError(props) {
console.warn(props)
throw new Error("[dvaReducer]: props is not array or string, or is array with nothing")
}
function copy(target) {
var args = pSlice.call(arguments)
var holder = Array.isArray(target) ? [] : {}
args.unshift(holder)
return extend.apply(null, args)
}
/**
* @param {Object|Array} state
* @param {Object} action prop payload must be provided, and should be an object or array
*/
function save(state, action) {
if (!action || action.payload === void 0) {
return state
}
return copy(state, action.payload)
}
/**
* dvaReducer: a factory to make the dva reducer
* @param {Undefined|Object|String|Array} props [required]
* if no arg, the reducer would be an save handler
* if props is object, then, [defaultValue], [update], [props] would be provided
* and the [props] is required
* if props is string, it would be splitted into an array
* if props is array, it would be used, the last one is the target prop to be updated
* @param {*|Function} defaultValue when payload not provided, defaultValue would be the placeholder
* @param {Function} update to update the payload
* @return {Function} reducer
*/
function dvaReducer(props, defaultValue, update) {
if (!arguments.length) {
return save
}
if (arguments.length === 1 && isPlainObject(props)) {
var opts = props
update = opts.update
props = opts.props
defaultValue = opts.defaultValue
}
if (props && typeof props === "string") {
props = props.split(regSplit)
}
if (!Array.isArray(props) || !props.length) {
reportPropsTypeError(props)
return
}
if (typeof update !== "function") {
update = void 0
}
var defaultValueIsFn = defaultValue && typeof defaultValue === "function"
/**
* @param {Object|Array} state object is advised for the type of the state
* @param {Object} action the action type must be resolved by the upper layer warnic
* @param {Boolean} partial default value is true,
* set partial false if ensure to override the prop value
* when payload and the action are both object
* @param {*} payload the new value for the target prop(the last prop)
* @return {Object} an object with required route line props updated
*/
return function reducer(state, action) {
if (!isObject(state)) {
if (env === "dev") {
reportStateNotObject(state)
}
return state
}
if (!action) {
return state
}
var payload = action.payload
var partial = action.partial
var obj = copy(state)
var cursor = obj
var prop
var value
if (partial === void 0) {
partial = true
}
for (var i = 0, ii = props.length, last = ii - 1; i < ii; i++) {
prop = props[i]
value = cursor[prop]
if (i < last) {
if (!isObject(value)) {
if (env === "dev") {
reportValueNotObject(props, prop, value)
}
return state
}
cursor = cursor[prop] = copy(value)
} else {
if (update) {
payload = update(state, payload, value)
}
// TODO no change, so state should not be updated
// reducer is to update the state, we should lessen the operation of this kind
if (value === payload) {
return state
}
if (
partial &&
isObject(value) &&
isObject(payload)
) {
cursor[prop] = copy(value, payload)
} else {
cursor[prop] = payload === void 0
? defaultValueIsFn
? defaultValue()
: defaultValue
: payload
}
}
}
return obj
}
}
dvaReducer.prod = function () {
env = "prod"
}
module.exports = dvaReducer