Skip to content

Commit c285010

Browse files
committed
New serializeState and serializeAction parameters
1 parent b301e34 commit c285010

File tree

4 files changed

+62
-14
lines changed

4 files changed

+62
-14
lines changed

docs/API/Arguments.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ Use `window.__REDUX_DEVTOOLS_EXTENSION__([config])` or `window.__REDUX_DEVTOOLS_
2626
```
2727
- **deserializeAction(action): transformedAction** (*function*) - optional transformation of actions deserialized from debug session (useful if actions are not plain object. Example: immutable-js action payload)
2828
- action, transformedAction - Redux action objects
29-
- **serializeState(key, value): transformedState** (*function*) - optional serialization function (useful if state is not plain object. Example: for mori data structures)
30-
Example of usage:
29+
- **serializeState** (*boolean or function or object*) - specify how and what should be handled during serialization (useful if state is not plain object). Could be:
30+
- `false` - handle only circular references.
31+
- `true` - handle also dates, regexes, undefined, error objects, and functions.
32+
- `function(key, value)` - JSON replacer. Example of usage with mori data structures:
3133

3234
```js
3335
const store = Redux.createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__({
@@ -36,7 +38,20 @@ Use `window.__REDUX_DEVTOOLS_EXTENSION__([config])` or `window.__REDUX_DEVTOOLS_
3638
)
3739
}));
3840
```
39-
- **serializeAction(key, value): transformedAction** (*function*) - optional serialization function (useful if actions are not plain object. Example: for mori data structures in actions payload)
41+
42+
- object (`{ replacer: function, options: object } `) - in addition to the replacer function, specify an options object, which contains `date`, `regexe`, `undefined`, `error`, and `function` keys. Fo each of them you can indicate whether to include (if set as `true`). For `function` key you can also specify a custom function which handles serialization. See [`jsan`](https://github.com/kolodny/jsan) for more details. Example:
43+
```js
44+
const store = Redux.createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__({
45+
serializeState: {
46+
options: {
47+
undefined: true,
48+
function: function(fn) { return fn.toString() }
49+
}
50+
}
51+
}));
52+
```
53+
54+
- **serializeAction** (*boolean or function or object*) - same as `serializeState` but used for actions payloads.
4055
- **actionsBlacklist** (*array*) - actions to be hidden in DevTools. Overwrites corresponding global setting in the options page.
4156
- **actionsWhitelist** (*array*) - all other actions will be hidden in DevTools. Overwrites corresponding global setting in the options page.
4257
- **actionSanitizer** (*function*) - function which takes `action` object and id number as arguments, and should return `action` object back. See the example bellow.

src/app/api/index.js

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
1-
import { stringify } from 'jsan';
1+
import jsan from 'jsan';
22

33
const listeners = {};
44
export const source = '@devtools-page';
55

6+
function stringify(obj, serialize) {
7+
if (typeof serialize === 'undefined') {
8+
return jsan.stringify(obj);
9+
}
10+
if (serialize === true) {
11+
return jsan.stringify(obj, function(key, value) {
12+
if (value && value.toJS) { return value.toJS(); }
13+
return value;
14+
}, null, true);
15+
}
16+
return jsan.stringify(obj, serialize.replacer, null, serialize.options);
17+
}
18+
619
export function generateId(instanceId) {
720
return instanceId || Math.random().toString(36).substr(2);
821
}
@@ -11,17 +24,22 @@ function post(message) {
1124
window.postMessage(message, '*');
1225
}
1326

14-
export function toContentScript(message, serializeState, serializeAction) {
27+
export function toContentScript(message, serializeState, serializeAction, shouldSerialize) {
1528
if (message.type === 'ACTION') {
1629
message.action = stringify(message.action, serializeAction);
1730
message.payload = stringify(message.payload, serializeState);
1831
} else if (message.type === 'STATE') {
19-
const { actionsById, computedStates, committedState, ...rest } = message.payload;
20-
message.payload = rest;
21-
message.actionsById = stringify(actionsById, serializeAction);
22-
message.computedStates = stringify(computedStates, serializeState);
23-
message.committedState = stringify(committedState, serializeState);
32+
if (serializeState === false) {
33+
message.payload = jsan.stringify(message.payload, null, null, false);
34+
} else {
35+
const { actionsById, computedStates, committedState, ...rest } = message.payload;
36+
message.payload = rest;
37+
message.actionsById = stringify(actionsById, serializeAction);
38+
message.computedStates = stringify(computedStates, serializeState);
39+
message.committedState = stringify(committedState, serializeState);
40+
}
2441
}
42+
message.serialize = shouldSerialize;
2543
post(message);
2644
}
2745

src/browser/extension/inject/pageScript.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ const devToolsExtension = function(reducer, preloadedState, config) {
3434
let maxAge;
3535
let isExcess;
3636
let actionCreators;
37+
let shouldSerialize;
38+
let serializeState;
39+
let serializeAction;
3740
const instanceId = generateId(config.instanceId);
3841
const localFilter = getLocalFilter(config);
3942
let { statesFilter, actionsFilter, stateSanitizer, actionSanitizer, predicate } = config;
@@ -48,6 +51,17 @@ const devToolsExtension = function(reducer, preloadedState, config) {
4851
actionSanitizer = actionsFilter; // eslint-disable-line no-param-reassign
4952
}
5053

54+
if (config.serializeState) {
55+
serializeState = config.serializeState;
56+
if (typeof serializeState === 'function') serializeState = { replacer: serializeState };
57+
else shouldSerialize = true;
58+
}
59+
if (config.serializeAction) {
60+
serializeAction = config.serializeAction;
61+
if (typeof serializeAction === 'function') serializeAction = { replacer: serializeAction };
62+
else shouldSerialize = true;
63+
}
64+
5165
const monitor = new Monitor(relayState);
5266
if (config.getMonitor) config.getMonitor(monitor);
5367

@@ -70,7 +84,7 @@ const devToolsExtension = function(reducer, preloadedState, config) {
7084
message.name = config.name || document.title;
7185
}
7286

73-
toContentScript(message, config.serializeState, config.serializeAction);
87+
toContentScript(message, serializeState, serializeAction, shouldSerialize);
7488
}
7589

7690
function relayState(actions, shouldInit) {

test/app/inject/api.spec.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ describe('API', () => {
4141
});
4242

4343
message = await listenMessage(() => {
44-
window.devToolsExtension.send({ type: 'hi' }, { counter: 1 }, false, 1);
44+
window.devToolsExtension.send({ type: 'hi' }, { counter: 1 }, 1);
4545
});
4646
expect(message).toInclude({
4747
type: 'ACTION',
@@ -53,7 +53,7 @@ describe('API', () => {
5353
});
5454

5555
message = await listenMessage(() => {
56-
window.devToolsExtension.send({ type: 'hi' }, { counter: 1 }, true, 1);
56+
window.devToolsExtension.send({ type: 'hi' }, { counter: 1 }, 1);
5757
});
5858
expect(message).toInclude({
5959
type: 'ACTION',
@@ -65,11 +65,12 @@ describe('API', () => {
6565
expect(message.action).toBe('{"action":{"type":"hi"}}');
6666

6767
message = await listenMessage(() => {
68-
window.devToolsExtension.send(undefined, { counter: 1 }, false, 1);
68+
window.devToolsExtension.send(undefined, { counter: 1 }, 1);
6969
});
7070
expect(message).toEqual({
7171
type: 'STATE',
7272
payload: { counter: 1 },
73+
serialize: undefined,
7374
actionsById: undefined,
7475
computedStates: undefined,
7576
committedState: undefined,

0 commit comments

Comments
 (0)