@@ -3,39 +3,37 @@ import {
3
3
IProduce ,
4
4
ImmerState ,
5
5
Drafted ,
6
- isDraftable ,
7
- processResult ,
8
6
Patch ,
9
7
Objectish ,
10
- DRAFT_STATE ,
11
8
Draft ,
12
9
PatchListener ,
13
- isDraft ,
14
10
isMap ,
15
11
isSet ,
16
12
createProxyProxy ,
17
13
getPlugin ,
18
- die ,
19
- enterScope ,
20
- revokeScope ,
21
- leaveScope ,
22
- usePatchesInScope ,
23
14
getCurrentScope ,
24
- NOTHING ,
25
- freeze ,
26
- current
15
+ DEFAULT_AUTOFREEZE ,
16
+ DEFAULT_USE_STRICT_SHALLOW_COPY ,
17
+ ImmerContext ,
18
+ applyPatchesImpl ,
19
+ createDraftImpl ,
20
+ finishDraftImpl ,
21
+ produceImpl ,
22
+ produceWithPatchesImpl ,
23
+ setAutoFreezeImpl ,
24
+ setUseStrictShallowCopyImpl
27
25
} from "../internal"
28
26
29
27
interface ProducersFns {
30
28
produce : IProduce
31
29
produceWithPatches : IProduceWithPatches
32
30
}
33
31
34
- export type StrictMode = boolean | "class_only" ;
32
+ export type StrictMode = boolean | "class_only"
35
33
36
- export class Immer implements ProducersFns {
37
- autoFreeze_ : boolean = true
38
- useStrictShallowCopy_ : StrictMode = false
34
+ export class Immer implements ProducersFns , ImmerContext {
35
+ autoFreeze_ : boolean = DEFAULT_AUTOFREEZE
36
+ useStrictShallowCopy_ : StrictMode = DEFAULT_USE_STRICT_SHALLOW_COPY
39
37
40
38
constructor ( config ?: {
41
39
autoFreeze ?: boolean
@@ -66,139 +64,37 @@ export class Immer implements ProducersFns {
66
64
* @param {Function } patchListener - optional function that will be called with all the patches produced here
67
65
* @returns {any } a new state, or the initial state if nothing was modified
68
66
*/
69
- produce : IProduce = ( base : any , recipe ?: any , patchListener ?: any ) => {
70
- // curried invocation
71
- if ( typeof base === "function" && typeof recipe !== "function" ) {
72
- const defaultBase = recipe
73
- recipe = base
67
+ produce : IProduce = produceImpl . bind ( this )
74
68
75
- const self = this
76
- return function curriedProduce (
77
- this : any ,
78
- base = defaultBase ,
79
- ...args : any [ ]
80
- ) {
81
- return self . produce ( base , ( draft : Drafted ) => recipe . call ( this , draft , ...args ) ) // prettier-ignore
82
- }
83
- }
69
+ produceWithPatches : IProduceWithPatches = produceWithPatchesImpl . bind ( this )
84
70
85
- if ( typeof recipe !== "function" ) die ( 6 )
86
- if ( patchListener !== undefined && typeof patchListener !== "function" )
87
- die ( 7 )
71
+ createDraft = createDraftImpl . bind ( this ) as < T extends Objectish > (
72
+ base : T
73
+ ) => Draft < T >
88
74
89
- let result
90
-
91
- // Only plain objects, arrays, and "immerable classes" are drafted.
92
- if ( isDraftable ( base ) ) {
93
- const scope = enterScope ( this )
94
- const proxy = createProxy ( base , undefined )
95
- let hasError = true
96
- try {
97
- result = recipe ( proxy )
98
- hasError = false
99
- } finally {
100
- // finally instead of catch + rethrow better preserves original stack
101
- if ( hasError ) revokeScope ( scope )
102
- else leaveScope ( scope )
103
- }
104
- usePatchesInScope ( scope , patchListener )
105
- return processResult ( result , scope )
106
- } else if ( ! base || typeof base !== "object" ) {
107
- result = recipe ( base )
108
- if ( result === undefined ) result = base
109
- if ( result === NOTHING ) result = undefined
110
- if ( this . autoFreeze_ ) freeze ( result , true )
111
- if ( patchListener ) {
112
- const p : Patch [ ] = [ ]
113
- const ip : Patch [ ] = [ ]
114
- getPlugin ( "Patches" ) . generateReplacementPatches_ ( base , result , p , ip )
115
- patchListener ( p , ip )
116
- }
117
- return result
118
- } else die ( 1 , base )
119
- }
120
-
121
- produceWithPatches : IProduceWithPatches = ( base : any , recipe ?: any ) : any => {
122
- // curried invocation
123
- if ( typeof base === "function" ) {
124
- return ( state : any , ...args : any [ ] ) =>
125
- this . produceWithPatches ( state , ( draft : any ) => base ( draft , ...args ) )
126
- }
127
-
128
- let patches : Patch [ ] , inversePatches : Patch [ ]
129
- const result = this . produce ( base , recipe , ( p : Patch [ ] , ip : Patch [ ] ) => {
130
- patches = p
131
- inversePatches = ip
132
- } )
133
- return [ result , patches ! , inversePatches ! ]
134
- }
135
-
136
- createDraft < T extends Objectish > ( base : T ) : Draft < T > {
137
- if ( ! isDraftable ( base ) ) die ( 8 )
138
- if ( isDraft ( base ) ) base = current ( base )
139
- const scope = enterScope ( this )
140
- const proxy = createProxy ( base , undefined )
141
- proxy [ DRAFT_STATE ] . isManual_ = true
142
- leaveScope ( scope )
143
- return proxy as any
144
- }
145
-
146
- finishDraft < D extends Draft < any > > (
75
+ finishDraft = finishDraftImpl . bind ( this ) as < D extends Draft < any > > (
147
76
draft : D ,
148
77
patchListener ?: PatchListener
149
- ) : D extends Draft < infer T > ? T : never {
150
- const state : ImmerState = draft && ( draft as any ) [ DRAFT_STATE ]
151
- if ( ! state || ! state . isManual_ ) die ( 9 )
152
- const { scope_ : scope } = state
153
- usePatchesInScope ( scope , patchListener )
154
- return processResult ( undefined , scope )
155
- }
78
+ ) => D extends Draft < infer T > ? T : never
156
79
157
80
/**
158
81
* Pass true to automatically freeze all copies created by Immer.
159
82
*
160
83
* By default, auto-freezing is enabled.
161
84
*/
162
- setAutoFreeze ( value : boolean ) {
163
- this . autoFreeze_ = value
164
- }
85
+ setAutoFreeze = setAutoFreezeImpl . bind ( this )
165
86
166
87
/**
167
88
* Pass true to enable strict shallow copy.
168
89
*
169
90
* By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
170
91
*/
171
- setUseStrictShallowCopy ( value : StrictMode ) {
172
- this . useStrictShallowCopy_ = value
173
- }
174
-
175
- applyPatches < T extends Objectish > ( base : T , patches : readonly Patch [ ] ) : T {
176
- // If a patch replaces the entire state, take that replacement as base
177
- // before applying patches
178
- let i : number
179
- for ( i = patches . length - 1 ; i >= 0 ; i -- ) {
180
- const patch = patches [ i ]
181
- if ( patch . path . length === 0 && patch . op === "replace" ) {
182
- base = patch . value
183
- break
184
- }
185
- }
186
- // If there was a patch that replaced the entire state, start from the
187
- // patch after that.
188
- if ( i > - 1 ) {
189
- patches = patches . slice ( i + 1 )
190
- }
92
+ setUseStrictShallowCopy = setUseStrictShallowCopyImpl . bind ( this )
191
93
192
- const applyPatchesImpl = getPlugin ( "Patches" ) . applyPatches_
193
- if ( isDraft ( base ) ) {
194
- // N.B: never hits if some patch a replacement, patches are never drafts
195
- return applyPatchesImpl ( base , patches )
196
- }
197
- // Otherwise, produce a copy of the base state.
198
- return this . produce ( base , ( draft : Drafted ) =>
199
- applyPatchesImpl ( draft , patches )
200
- )
201
- }
94
+ applyPatches = applyPatchesImpl . bind ( this ) as < T extends Objectish > (
95
+ base : T ,
96
+ patches : readonly Patch [ ]
97
+ ) => T
202
98
}
203
99
204
100
export function createProxy < T extends Objectish > (
0 commit comments