From 6351d38ae6e6edbb9567f0d32eabd47d02e806a0 Mon Sep 17 00:00:00 2001 From: Nicholas Blott Date: Mon, 22 Jan 2024 19:14:27 +0100 Subject: [PATCH 1/4] Update to use identity ({}) as output for matching values Also includes refactor to simplify code and updates tests to match new functionality. --- lib/generate.js | 58 +++++++++++++++----------------------------- test/lib/generate.js | 12 ++++----- 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/lib/generate.js b/lib/generate.js index b2a5f68..f93ba3c 100644 --- a/lib/generate.js +++ b/lib/generate.js @@ -19,53 +19,35 @@ module.exports = function generate(before, after) { before = serialize(before); after = serialize(after); + if (!(before instanceof Object) && + !(after instanceof Object) && + before === after) { // Return no op when values match + return {} + } + if (before === null || after === null || typeof before !== 'object' || typeof after !== 'object' || - Array.isArray(before) !== Array.isArray(after)) { - return after; + Array.isArray(before) || Array.isArray(after)) { + return serialize(after); } - if (Array.isArray(before)) { - if (!arrayEquals(before, after)) { - return after; + let patch = {}; + for (let key of Object.keys(before)) { + let newVal = null; + if (key in after) { + newVal = generate(before[key], after[key]); } - return undefined; - } - - var patch = {}; - var beforeKeys = Object.keys(before); - var afterKeys = Object.keys(after); - - var key, i; - - // new elements - var newKeys = {}; - for (i = 0; i < afterKeys.length; i++) { - key = afterKeys[i]; - if (beforeKeys.indexOf(key) === -1) { - newKeys[key] = true; - patch[key] = serialize(after[key]); + if (equal(newVal, {})) { + continue; } + patch[key] = serialize(newVal); } - // removed & modified elements - var removedKeys = {}; - for (i = 0; i < beforeKeys.length; i++) { - key = beforeKeys[i]; - if (afterKeys.indexOf(key) === -1) { - removedKeys[key] = true; - patch[key] = null; - } else { - if (before[key] !== null && typeof before[key] === 'object') { - var subPatch = generate(before[key], after[key]); - if (subPatch !== undefined) { - patch[key] = subPatch; - } - } else if (before[key] !== after[key]) { - patch[key] = serialize(after[key]); - } + for (let key of Object.keys(after)) { + if (!(key in before)) { + patch[key] = serialize(after[key]); } } - return (Object.keys(patch).length > 0 ? patch : undefined); + return (Object.keys(patch).length > 0 ? patch : {}); }; diff --git a/test/lib/generate.js b/test/lib/generate.js index a91499b..c1c47e4 100644 --- a/test/lib/generate.js +++ b/test/lib/generate.js @@ -126,24 +126,24 @@ describe('generate', function() { ); }); - it('should return undefined if the object hasnt changed', function() { + it('should return {} if the object hasnt changed', function() { assert.deepEqual( generate({a: 'a'}, {a: 'a'}), - undefined + {} ); }); - it('should return undefined if the object with sub attributes hasnt changed', function() { + it('should return {} if the object with sub attributes hasnt changed', function() { assert.deepEqual( generate({a: {b: 'c'}}, {a: {b: 'c'}}), - undefined + {} ); }); - it('should return undefined if the array hasnt changed', function() { + it('should return the target if the output is an array', function() { assert.deepEqual( generate([1, 2, 3], [1, 2, 3]), - undefined + [1,2,3] ); }); From 5cd1ebd33229390259582272ddcd515439840efe Mon Sep 17 00:00:00 2001 From: Nicholas Blott Date: Mon, 22 Jan 2024 20:17:39 +0100 Subject: [PATCH 2/4] Update semver because of breaking change --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36861d3..8970c6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-merge-patch", - "version": "1.0.2", + "version": "2.0.0", "description": "Implementation of JSON Merge Patch (RFC 7396)", "main": "index.js", "directories": { From 2dc16cc362cf4a7a4d2a114420c39845fa4ab0d0 Mon Sep 17 00:00:00 2001 From: Nicholas Blott Date: Mon, 22 Jan 2024 20:24:45 +0100 Subject: [PATCH 3/4] Mvoe value selection to start for simplicity in loops --- lib/generate.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/generate.js b/lib/generate.js index f93ba3c..830d80d 100644 --- a/lib/generate.js +++ b/lib/generate.js @@ -19,6 +19,11 @@ module.exports = function generate(before, after) { before = serialize(before); after = serialize(after); + // An undefined target is a deletion attempt + if (after === undefined) { + return null; + } + if (!(before instanceof Object) && !(after instanceof Object) && before === after) { // Return no op when values match @@ -33,10 +38,8 @@ module.exports = function generate(before, after) { let patch = {}; for (let key of Object.keys(before)) { - let newVal = null; - if (key in after) { - newVal = generate(before[key], after[key]); - } + let newVal = generate(before[key], after[key]); + // Omit noops if (equal(newVal, {})) { continue; } From 1a1b9518d7d48bba5a309a8e6c43da761b0e21c3 Mon Sep 17 00:00:00 2001 From: Nicholas Blott Date: Sat, 10 Feb 2024 11:44:47 +0100 Subject: [PATCH 4/4] Use nulls for delete --- lib/generate.js | 7 +------ package.json | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/generate.js b/lib/generate.js index 830d80d..ba5d6f2 100644 --- a/lib/generate.js +++ b/lib/generate.js @@ -19,11 +19,6 @@ module.exports = function generate(before, after) { before = serialize(before); after = serialize(after); - // An undefined target is a deletion attempt - if (after === undefined) { - return null; - } - if (!(before instanceof Object) && !(after instanceof Object) && before === after) { // Return no op when values match @@ -38,7 +33,7 @@ module.exports = function generate(before, after) { let patch = {}; for (let key of Object.keys(before)) { - let newVal = generate(before[key], after[key]); + let newVal = generate(before[key] ?? null, after[key] ?? null); // Omit noops if (equal(newVal, {})) { continue; diff --git a/package.json b/package.json index 8970c6a..b22fad0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-merge-patch", - "version": "2.0.0", + "version": "2.1.0", "description": "Implementation of JSON Merge Patch (RFC 7396)", "main": "index.js", "directories": {