diff --git a/packages/wxa-core/src/diff/flatten.js b/packages/wxa-core/src/diff/flatten.js index 0b0c58bf..6610aa16 100644 --- a/packages/wxa-core/src/diff/flatten.js +++ b/packages/wxa-core/src/diff/flatten.js @@ -1,6 +1,13 @@ // fork from https://github.com/hughsk/flat/blob/master/index.js // modify for wxa +const getType = (v) => Object.prototype.toString.call(v); + +const is = (t, v) => { + return getType(v) === `[object ${t}]`; +}; + + function flatten(oldValue, newValue, diff, opts) { // if diff element is an array, then just return the array in wxa. so we allways need safe options in wxa. opts = opts || {safe: true}; @@ -10,59 +17,75 @@ function flatten(oldValue, newValue, diff, opts) { let output = {}; function step(oldValue, newValue, diff, prev, currentDepth) { - currentDepth = currentDepth || 1; - Object.keys(diff).forEach(function(key) { - let diffChildValue = diff[key]; - let isDiffChildValueArray = opts.safe && Array.isArray(diffChildValue); - - let typeOfDiff = Object.prototype.toString.call(diffChildValue); - let isDiffChildValueObject = ( - typeOfDiff === '[object Object]' || - typeOfDiff === '[object Array]' - ); + currentDepth = currentDepth || 1; - let sourceValue; - let newKey; - let newChildValue = newValue[key]; + Object.keys(diff).forEach(function(key) { + let diffChildValue = diff[key]; + // new child array added + let isDiffChildValueArray = + opts.safe && Array.isArray(diffChildValue); - // Only digits (0-9) can be put inside [] in the path string - newKey = prev ? /^\d+$/.test(key) ? prev + '[' + key + ']' : prev + delimiter + key : key; + let isDiffChildValueObject = is('Object', diffChildValue) || is('Array', diffChildValue); + let newKey; + let newChildValue = newValue[key]; + let sourceValue = oldValue ? oldValue[key] : void(0); - if (oldValue) { - // hasValue, meaning that new value still contain old one. - sourceValue = oldValue[key]; + if (Array.isArray(oldValue) && Array.isArray(newValue)) { + // array element changed or added. + newKey = prev ? prev + `[${key}]` : key; + } else { + newKey = prev ? prev + delimiter + key : key; + } + // Check Array if ( - ( - Array.isArray(sourceValue) || - (Object.prototype.toString.call(sourceValue) === '[object Object]') - ) && - Object.keys(diffChildValue).some((key)=>diffChildValue[key]===void(0)) + (Array.isArray(sourceValue) || is('Object', sourceValue)) && + Object.keys(diffChildValue).some((key) => diffChildValue[key] === void 0) ) { - // console.log(currentDepth, ' element deleted ', newKey); // some array or object element have been deleted. // return new array or object. - output[newKey] = newChildValue; - return; - } else if (Array.isArray(oldValue)) { - // array element changed or added. - newKey = prev ? prev + `[${key}]` : key; + return output[newKey] = newChildValue; + } + + if ( + !isDiffChildValueObject || + getType(sourceValue) !== getType(newChildValue) + ) { + return output[newKey] = diffChildValue; } - } - if (!isDiffChildValueArray && isDiffChildValueObject && Object.keys(diffChildValue).length && - (!opts.maxDepth || currentDepth < maxDepth)) { - return step(sourceValue, newChildValue, diffChildValue, newKey, currentDepth + 1); - } + if ( + !isDiffChildValueArray && + isDiffChildValueObject && + Object.keys(diffChildValue).length && + (!opts.maxDepth || currentDepth < maxDepth) + ) { + if ( + currentDepth < 2 || + (currentDepth >= 2 && Object.keys(diffChildValue).length <= 4) + ) { + // tiny object + // end process go next step + return step( + sourceValue, + newChildValue, + diffChildValue, + newKey, + currentDepth + 1 + ); + } else { + return output[newKey] = newChildValue; + } + } - output[newKey] = diffChildValue; - }); + output[newKey] = diffChildValue; + }); } step(oldValue, newValue, diff); return output; - } +} export default flatten; diff --git a/packages/wxa-core/test/diff/diff.test.js b/packages/wxa-core/test/diff/diff.test.js index c31fb7ad..d422dee2 100644 --- a/packages/wxa-core/test/diff/diff.test.js +++ b/packages/wxa-core/test/diff/diff.test.js @@ -52,4 +52,16 @@ describe('diff array', ()=>{ expect(pageDiff({x: arr2})).toMatchObject({'x[0]': {a: 1, b: 2}}); }); + + test('get diff properties', ()=>{ + let page = { + data: { + x: arr1, + }, + }; + + let pageDiff = diff.bind(page); + + expect(pageDiff({x: [{a: 1, b: 2, c: {a: 1}}]})).toMatchObject({'x[0].c': {a: 1}}); + }); }); diff --git a/packages/wxa-core/test/diff/flatten.test.js b/packages/wxa-core/test/diff/flatten.test.js index 0829e99e..b03bb3d5 100644 --- a/packages/wxa-core/test/diff/flatten.test.js +++ b/packages/wxa-core/test/diff/flatten.test.js @@ -24,7 +24,7 @@ describe('flatten object for wxa', ()=>{ expect(flatten( { - a: 2, + a: {c: {d: 3}}, }, { a: {c: {d: 1}}, @@ -76,7 +76,7 @@ describe('flatten object for wxa', ()=>{ '1': {b: 1}, }, }, - })).toMatchObject({'a.c[1].b': 1}); + })).toMatchObject({'a.c[1]': {'b': 1}}); expect(flatten( { @@ -152,4 +152,68 @@ describe('flatten object for wxa', ()=>{ expect(flatten(oldValue, newValueWithDelete, {school: void(0), fav: {a: void(0), b: 'football'}})).toMatchObject({school: void(0), fav: {b: 'football'}}); }); + + test('Big Different Object', ()=>{ + expect(flatten( + { + user$: { + b: 3, + order: { + c: [1, 2], + d: 1, + e: 2, + f: 3, + d1: 1, + e22: 2, + f2: 4, + }, + }, + }, + { + user$: { + b: 3, + order: { + c: [1, 2], + d: 1, + e: 2, + f: 3, + d1: 1, + e22: 2, + f2: 4, + }, + }, + }, + { + user$: { + b: 4, + order: { + c: [1, 2], + d: 1, + e: 2, + f: 3, + d1: 1, + }, + }, + } + )).toMatchObject({ + 'user$.b': 4, + 'user$.order': {c: [1, 2], d: 1, e: 2, f: 3, d1: 1, e22: 2, f2: 4}, + }); + }); + + test('diff data Array to Object', ()=>{ + expect(flatten( + { + user$: {}, + }, + { + user$: [], + }, + { + user$: [], + } + )).toMatchObject({ + 'user$': [], + }); + }); });