1
- import invariant from 'invariant'
2
- import stringify from 'json-stringify-safe'
3
1
import { Middleware } from 'redux'
4
2
5
- const BETWEEN_DISPATCHES_MESSAGE = [
6
- 'A state mutation was detected between dispatches, in the path `%s`.' ,
7
- 'This may cause incorrect behavior.' ,
8
- '(http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments)'
9
- ] . join ( ' ' )
3
+ type EntryProcessor = ( key : string , value : any ) => any
10
4
11
- const INSIDE_DISPATCH_MESSAGE = [
12
- 'A state mutation was detected inside a dispatch, in the path: `%s`.' ,
13
- 'Take a look at the reducer(s) handling the action %s.' ,
14
- '(http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments)'
15
- ] . join ( ' ' )
5
+ const isProduction : boolean = process . env . NODE_ENV === 'production'
6
+ const prefix : string = 'Invariant failed'
7
+
8
+ // Throw an error if the condition fails
9
+ // Strip out error messages for production
10
+ // > Not providing an inline default argument for message as the result is smaller
11
+ function invariant ( condition : any , message ?: string ) {
12
+ if ( condition ) {
13
+ return
14
+ }
15
+ // Condition not passed
16
+
17
+ // In production we strip the message but still throw
18
+ if ( isProduction ) {
19
+ throw new Error ( prefix )
20
+ }
21
+
22
+ // When not in production we allow the message to pass through
23
+ // *This block will be removed in production builds*
24
+ throw new Error ( `${ prefix } : ${ message || '' } ` )
25
+ }
26
+
27
+ function stringify (
28
+ obj : any ,
29
+ serializer ?: EntryProcessor ,
30
+ indent ?: string | number ,
31
+ decycler ?: EntryProcessor
32
+ ) : string {
33
+ return JSON . stringify ( obj , getSerialize ( serializer , decycler ) , indent )
34
+ }
35
+
36
+ function getSerialize (
37
+ serializer ?: EntryProcessor ,
38
+ decycler ?: EntryProcessor
39
+ ) : EntryProcessor {
40
+ let stack : any [ ] = [ ] ,
41
+ keys : any [ ] = [ ]
42
+
43
+ if ( ! decycler )
44
+ decycler = function ( _ : string , value : any ) {
45
+ if ( stack [ 0 ] === value ) return '[Circular ~]'
46
+ return (
47
+ '[Circular ~.' + keys . slice ( 0 , stack . indexOf ( value ) ) . join ( '.' ) + ']'
48
+ )
49
+ }
50
+
51
+ return function ( this : any , key : string , value : any ) {
52
+ if ( stack . length > 0 ) {
53
+ var thisPos = stack . indexOf ( this )
54
+ ~ thisPos ? stack . splice ( thisPos + 1 ) : stack . push ( this )
55
+ ~ thisPos ? keys . splice ( thisPos , Infinity , key ) : keys . push ( key )
56
+ if ( ~ stack . indexOf ( value ) ) value = decycler ! . call ( this , key , value )
57
+ } else stack . push ( value )
58
+
59
+ return serializer == null ? value : serializer . call ( this , key , value )
60
+ }
61
+ }
16
62
17
63
export function isImmutableDefault ( value : unknown ) : boolean {
18
64
return (
@@ -150,8 +196,11 @@ export function createImmutableStateInvariantMiddleware(
150
196
151
197
invariant (
152
198
! result . wasMutated ,
153
- BETWEEN_DISPATCHES_MESSAGE ,
154
- ( result . path || [ ] ) . join ( '.' )
199
+ `A state mutation was detected between dispatches, in the path '${ (
200
+ result . path || [ ]
201
+ ) . join (
202
+ '.'
203
+ ) } '. This may cause incorrect behavior. (http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments)`
155
204
)
156
205
157
206
const dispatchedAction = next ( action )
@@ -164,9 +213,13 @@ export function createImmutableStateInvariantMiddleware(
164
213
result . wasMutated &&
165
214
invariant (
166
215
! result . wasMutated ,
167
- INSIDE_DISPATCH_MESSAGE ,
168
- ( result . path || [ ] ) . join ( '.' ) ,
169
- stringify ( action )
216
+ `A state mutation was detected inside a dispatch, in the path: ${ (
217
+ result . path || [ ]
218
+ ) . join (
219
+ '.'
220
+ ) } . Take a look at the reducer(s) handling the action ${ stringify (
221
+ action
222
+ ) } . (http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments)`
170
223
)
171
224
172
225
return dispatchedAction
0 commit comments