From fe91dac593db42d52f72867f3c38205401e1bdc4 Mon Sep 17 00:00:00 2001 From: Tim Shadel Date: Wed, 26 Feb 2025 14:54:19 -0600 Subject: [PATCH] feat(whitespace): handle whitespace-only changes If there is no difference between the logical structure of the JSON, then try to minimize file thrashing by picking a consistent winner. - If ours and theirs are identical, use that (should be no conflict) - Otherwise, use base (minimize whitespace-only changes to JSON file) --- bin/git-json-merge | 0 lib/git-json-merge.js | 14 ++++++++++---- test/git-json-merge.spec.js | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) mode change 100644 => 100755 bin/git-json-merge diff --git a/bin/git-json-merge b/bin/git-json-merge old mode 100644 new mode 100755 diff --git a/lib/git-json-merge.js b/lib/git-json-merge.js index bd4fbef..f5f66a6 100644 --- a/lib/git-json-merge.js +++ b/lib/git-json-merge.js @@ -20,10 +20,16 @@ function mergeJson (oursJson, baseJson, theirsJson) { var ours = JSON.parse(oursJson); var base = JSON.parse(baseJson); var theirs = JSON.parse(theirsJson); - var newOurs = merge(ours, base, theirs); - var newOursJson = JSON.stringify(newOurs, null, newOursIndent); - - return newOursJson; + var diff = xdiff.diff3(ours, base, theirs); + if (diff) { + var newOurs = xdiff.patch(base, diff); + var newOursJson = JSON.stringify(newOurs, null, newOursIndent); + return newOursJson; + } else if (oursJson === theirsJson) { + return oursJson; + } else { + return baseJson; + } } function merge (ours, base, theirs) { diff --git a/test/git-json-merge.spec.js b/test/git-json-merge.spec.js index 260831e..a7de889 100644 --- a/test/git-json-merge.spec.js +++ b/test/git-json-merge.spec.js @@ -32,6 +32,31 @@ describe('gitJsonMerge', function () { describeStripBomTest('[{"id":1,\uFEFF"field":"Foo"}]', '[{"id":1,\uFEFF"field":"Foo"}]'); describeStripBomTest('\uFEFF[{"id":1,"field":"Foo"}]\uFEFF', '[{"id":1,"field":"Foo"}]\uFEFF'); }); + + describe('Keep common string.', function() { + // All are identical + describeStringEquivalence( + '[{"id":1,"field":"Foo"}]', + '[{"id":1,"field":"Foo"}]', + '[{"id":1,"field":"Foo"}]', + '[{"id":1,"field":"Foo"}]' + ); + // Ours and theirs have identical whitespace-only changes + describeStringEquivalence( + '[\n {"id": 1,"field":"Foo"\n}\n]', + '[\n {"id":1,"field":"Foo"}\n]', + '[\n {"id": 1,"field":"Foo"\n}\n]', + '[\n {"id": 1,"field":"Foo"\n}\n]' + ); + // Ours and theirs have diverging whitespace-only changes + describeStringEquivalence( + '[{"id":1,"field": "Foo"}]', + '[\n {"id":1,"field":"Foo"}\n]', + '[\n {"id": 1,"field":"Foo"\n}\n]', + '[\n {"id":1,"field":"Foo"}\n]' + ); + }); + }); function toString (object) { @@ -85,3 +110,13 @@ function describeStripBomTest (str, expected) { }) }); } + +function describeStringEquivalence (ours, base, theirs, expected) { + describe('given arguments of ' + toString(ours) + ' as ours, ' + toString(base) + ' as base and ' + toString(theirs) + ' as theirs', function () { + var actual = gitJsonMerge.mergeJson(ours, base, theirs); + + it('should return ' + toString(expected), function () { + expect(actual).to.deep.equal(expected); + }) + }); +}