Skip to content

Commit 32c08ac

Browse files
committed
Inline tiny-invariant and json-stringify-safe
1 parent 6b83a39 commit 32c08ac

File tree

1 file changed

+70
-17
lines changed

1 file changed

+70
-17
lines changed

src/immutableStateInvariantMiddleware.ts

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,64 @@
1-
import invariant from 'invariant'
2-
import stringify from 'json-stringify-safe'
31
import { Middleware } from 'redux'
42

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
104

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+
}
1662

1763
export function isImmutableDefault(value: unknown): boolean {
1864
return (
@@ -150,8 +196,11 @@ export function createImmutableStateInvariantMiddleware(
150196

151197
invariant(
152198
!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)`
155204
)
156205

157206
const dispatchedAction = next(action)
@@ -164,9 +213,13 @@ export function createImmutableStateInvariantMiddleware(
164213
result.wasMutated &&
165214
invariant(
166215
!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)`
170223
)
171224

172225
return dispatchedAction

0 commit comments

Comments
 (0)