Skip to content

Commit 3f25d3b

Browse files
ktsnyyx990803
authored andcommitted
Support circular structure for logger (vuejs#327)
* support circular structure for logger * add deepCopy unit test
1 parent 10be6af commit 3f25d3b

File tree

4 files changed

+95
-3
lines changed

4 files changed

+95
-3
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"chat": "cd examples/chat && webpack-dev-server --inline --hot --config ../webpack.shared.config.js",
2121
"build": "node build/build.js",
2222
"build-examples": "BABEL_ENV=development webpack --config examples/webpack.build-all.config.js",
23-
"unit": "BABEL_ENV=development mocha test/unit/test.js --compilers js:babel-core/register",
23+
"unit": "BABEL_ENV=development mocha test/unit/*.js --compilers js:babel-core/register",
2424
"pree2e": "npm run build-examples",
2525
"e2e": "casperjs test --concise ./test/e2e",
2626
"test": "eslint src && npm run unit && npm run e2e",

src/plugins/logger.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
// Credits: borrowed code from fcomb/redux-logger
22

3+
import { deepCopy } from '../util'
4+
35
export default function createLogger ({
46
collapsed = true,
57
transformer = state => state,
68
mutationTransformer = mut => mut
79
} = {}) {
810
return store => {
9-
let prevState = JSON.parse(JSON.stringify(store.state))
11+
let prevState = deepCopy(store.state)
1012

1113
store.subscribe((mutation, state) => {
1214
if (typeof console === 'undefined') {
1315
return
1416
}
15-
const nextState = JSON.parse(JSON.stringify(state))
17+
const nextState = deepCopy(state)
1618
const time = new Date()
1719
const formattedTime = ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`
1820
const formattedMutation = mutationTransformer(mutation)

src/util.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,54 @@ export function mergeObjects (arr) {
2525
}, {})
2626
}
2727

28+
/**
29+
* Get the first item that pass the test
30+
* by second argument function
31+
*
32+
* @param {Array} list
33+
* @param {Function} f
34+
* @return {*}
35+
*/
36+
function find (list, f) {
37+
return list.filter(f)[0]
38+
}
39+
40+
/**
41+
* Deep copy the given object considering circular structure.
42+
* This function caches all nested objects and its copies.
43+
* If it detects circular structure, use cached copy to avoid infinite loop.
44+
*
45+
* @param {*} obj
46+
* @param {Array<Object>} cache
47+
* @return {*}
48+
*/
49+
export function deepCopy (obj, cache = []) {
50+
// just return if obj is immutable value
51+
if (obj === null || typeof obj !== 'object') {
52+
return obj
53+
}
54+
55+
// if obj is hit, it is in circular structure
56+
const hit = find(cache, c => c.original === obj)
57+
if (hit) {
58+
return hit.copy
59+
}
60+
61+
const copy = Array.isArray(obj) ? [] : {}
62+
// put the copy into cache at first
63+
// because we want to refer it in recursive deepCopy
64+
cache.push({
65+
original: obj,
66+
copy
67+
})
68+
69+
Object.keys(obj).forEach(key => {
70+
copy[key] = deepCopy(obj[key], cache)
71+
})
72+
73+
return copy
74+
}
75+
2876
/**
2977
* Check whether the given value is Object or not
3078
*

test/unit/util.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { expect } from 'chai'
2+
import { deepCopy } from '../../src/util'
3+
4+
describe('util', () => {
5+
it('deepCopy: nornal structure', () => {
6+
const original = {
7+
a: 1,
8+
b: 'string',
9+
c: true,
10+
d: null,
11+
e: undefined
12+
}
13+
const copy = deepCopy(original)
14+
15+
expect(copy).to.deep.equal(original)
16+
})
17+
18+
it('deepCopy: nested structure', () => {
19+
const original = {
20+
a: {
21+
b: 1,
22+
c: [2, 3, {
23+
d: 4
24+
}]
25+
}
26+
}
27+
const copy = deepCopy(original)
28+
29+
expect(copy).to.deep.equal(original)
30+
})
31+
32+
it('deepCopy: circular structure', () => {
33+
const original = {
34+
a: 1
35+
}
36+
original.circular = original
37+
38+
const copy = deepCopy(original)
39+
40+
expect(copy).to.deep.equal(original)
41+
})
42+
})

0 commit comments

Comments
 (0)