From ad6e6e82d8a53d09f694eca090a085960f9896e9 Mon Sep 17 00:00:00 2001 From: Antoine Bolvy Date: Mon, 29 Oct 2018 12:04:44 +0100 Subject: [PATCH 1/2] Add tests for #33 --- test/tests.js | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/test/tests.js b/test/tests.js index 3a63199..baec49b 100644 --- a/test/tests.js +++ b/test/tests.js @@ -268,6 +268,23 @@ }); + describe('if the filtered config is passed as an object', function () { + + it('changes to the array to not appear as a difference', function () { + var prefilter = function (path, key) { + return key === 'supportedBy'; + }; + var diff = deep(lhs, rhs, {prefilter: prefilter}); + expect(diff).to.be.ok(); + expect(diff.length).to.be(2); + expect(diff[0]).to.have.property('kind'); + expect(diff[0].kind).to.be('E'); + expect(diff[1]).to.have.property('kind'); + expect(diff[1].kind).to.be('N'); + }); + + }); + describe('if the filtered property is not an array', function () { it('changes do not appear as a difference', function () { @@ -290,6 +307,57 @@ }); }); + describe('Can normalize properties to before diffing', function () { + var testLHS = { + array: [1, 2, 3, 4, 5], + }; + + var testRHS = { + array: '1/2/3/4/5', + }; + + it('changes do not appear as a difference', function () { + var filter = { + normalize: function (path, key, lhs, rhs) { + expect(key).to.be('array'); + + if (Array.isArray(lhs)) { + lhs = lhs.join('/'); + } + if (Array.isArray(rhs)) { + rhs = rhs.join('/'); + } + return [lhs, rhs]; + } + }; + + var diff; + + diff = deep(testLHS, testRHS, filter); + expect(diff).to.be.an('undefined'); + + diff = deep(testRHS, testLHS, filter); + expect(diff).to.be.an('undefined'); + }); + + it('falsy return does not normalize', function () { + var filter = { + // eslint-disable-next-line no-unused-vars + normalize: function (path, key, lhs, rhs) { + return false; + } + }; + + var diff; + + diff = deep(testLHS, testRHS, filter); + expect(diff).to.be.ok(); + + diff = deep(testRHS, testLHS, filter); + expect(diff).to.be.ok(); + }); + }); + describe('A target that has nested values', function () { var nestedOne = { noChange: 'same', From 73666ba91c5cdd99f892a737e4592a3c95a3123c Mon Sep 17 00:00:00 2001 From: Antoine Bolvy Date: Mon, 29 Oct 2018 12:29:22 +0100 Subject: [PATCH 2/2] Update README.md for normalize documentation --- Readme.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 8ee322a..2a7335b 100644 --- a/Readme.md +++ b/Readme.md @@ -154,6 +154,7 @@ var rhs = { it: 'has', an: 'array', with: ['a', 'few', 'more', 'elements', { than: 'before' }] + } }; observableDiff(lhs, rhs, function (d) { @@ -168,8 +169,8 @@ observableDiff(lhs, rhs, function (d) { A standard import of `var diff = require('deep-diff')` is assumed in all of the code examples. The import results in an object having the following public properties: -* `diff(lhs, rhs, prefilter, acc)` — calculates the differences between two objects, optionally prefiltering elements for comparison, and optionally using the specified accumulator. -* `observableDiff(lhs, rhs, observer, prefilter)` — calculates the differences between two objects and reports each to an observer function, optionally, prefiltering elements for comparison. +* `diff(lhs, rhs[, options, acc])` — calculates the differences between two objects, optionally using the specified accumulator. +* `observableDiff(lhs, rhs, observer[, options])` — calculates the differences between two objects and reports each to an observer function. * `applyDiff(target, source, filter)` — applies any structural differences from a source object to a target object, optionally filtering each difference. * `applyChange(target, source, change)` — applies a single change record to a target object. NOTE: `source` is unused and may be removed. * `revertChange(target, source, change)` reverts a single change record to a target object. NOTE: `source` is unused and may be removed. @@ -178,11 +179,14 @@ A standard import of `var diff = require('deep-diff')` is assumed in all of the The `diff` function calculates the difference between two objects. + #### Arguments * `lhs` - the left-hand operand; the origin object. * `rhs` - the right-hand operand; the object being compared structurally with the origin object. -* `prefilter` - an optional function that determines whether difference analysis should continue down the object graph. +* `options` - A configuration object that can have the following properties: + - `prefilter`: function that determines whether difference analysis should continue down the object graph. This function can also replace the `options` object in the parameters for backward compatibility. + - `normalize`: function that pre-processes every _leaf_ of the tree. * `acc` - an optional accumulator/array (requirement is that it have a `push` function). Each difference is pushed to the specified accumulator. Returns either an array of changes or, if there are no changes, `undefined`. This was originally chosen so the result would be pass a truthy test: @@ -227,6 +231,51 @@ const none = diff(data, clone, assert.equal(two.length, 2, 'should reflect two differences'); assert.ok(typeof none === 'undefined', 'should reflect no differences'); ``` +#### Normalizing object properties + +The `normalize`'s signature should be `function(path, key, lhs, rhs)` and it should return either a falsy value if no normalization has occured, or a `[lhs, rhs]` array to replace the original values. This step doesn't occur if the path was filtered out in the `prefilter` phase. + +```javascript +const diff = require('deep-diff'); +const assert = require('assert'); + +const data = { + pull: 149, + submittedBy: 'saveman71', +}; + +const clone = JSON.parse(JSON.stringify(data)); +clone.issue = 42; + +const two = diff(data, clone); +const none = diff(data, clone, { + normalize: (path, key, lhs, rhs) => { + if (lhs === 149) { + lhs = 42; + } + if (rhs === 149) { + rhs = 42; + } + return [lsh, rhs]; + } +}); + +assert.equal(two.length, 1, 'should reflect one difference'); +assert.ok(typeof none === 'undefined', 'should reflect no difference'); +``` + +### `observableDiff` + +The `observableDiff` function calculates the difference between two objects and reports each to an observer function. + +#### Argmuments + +* `lhs` - the left-hand operand; the origin object. +* `rhs` - the right-hand operand; the object being compared structurally with the origin object. +* `observer` - The observer to report to. +* `options` - A configuration object that can have the following properties: + - `prefilter`: function that determines whether difference analysis should continue down the object graph. This function can also replace the `options` object in the parameters for backward compatibility. + - `normalize`: function that pre-processes every _leaf_ of the tree. ## Contributing