-
-
Notifications
You must be signed in to change notification settings - Fork 842
/
immer.js
79 lines (65 loc) · 3.04 KB
/
immer.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
export {setAutoFreeze, setUseProxies, original, isProxy as isDraft} from "./common"
import {applyPatches as applyPatchesImpl} from "./patches"
import {isProxyable, getUseProxies, NOTHING} from "./common"
import {produceProxy} from "./proxy"
import {produceEs5} from "./es5"
/**
* produce takes a state, and runs a function against it.
* That function can freely mutate the state, as it will create copies-on-write.
* This means that the original state will stay unchanged, and once the function finishes, the modified state is returned
*
* @export
* @param {any} baseState - the state to start with
* @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
* @param {Function} patchListener - optional function that will be called with all the patches produced here
* @returns {any} a new state, or the base state if nothing was modified
*/
export function produce(baseState, producer, patchListener) {
// prettier-ignore
if (arguments.length < 1 || arguments.length > 3) throw new Error("produce expects 1 to 3 arguments, got " + arguments.length)
// curried invocation
if (typeof baseState === "function") {
// prettier-ignore
if (typeof producer === "function") throw new Error("if first argument is a function (curried invocation), the second argument to produce cannot be a function")
const initialState = producer
const recipe = baseState
return function() {
const args = arguments
const currentState =
args[0] === undefined && initialState !== undefined
? initialState
: args[0]
return produce(currentState, draft => {
args[0] = draft // blegh!
return recipe.apply(draft, args)
})
}
}
// prettier-ignore
{
if (typeof producer !== "function") throw new Error("if first argument is not a function, the second argument to produce should be a function")
if (patchListener !== undefined && typeof patchListener !== "function") throw new Error("the third argument of a producer should not be set or a function")
}
// if state is a primitive, don't bother proxying at all
if (typeof baseState !== "object" || baseState === null) {
const returnValue = producer(baseState)
return returnValue === undefined
? baseState
: normalizeResult(returnValue)
}
if (!isProxyable(baseState))
throw new Error(
`the first argument to an immer producer should be a primitive, plain object or array, got ${typeof baseState}: "${baseState}"`
)
return normalizeResult(
getUseProxies()
? produceProxy(baseState, producer, patchListener)
: produceEs5(baseState, producer, patchListener)
)
}
function normalizeResult(result) {
return result === NOTHING ? undefined : result
}
export default produce
export const applyPatches = produce(applyPatchesImpl)
export const nothing = NOTHING