diff --git a/src/index.spec.ts b/src/index.spec.ts index 7d69d97..a7095ef 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -662,6 +662,7 @@ describe('a generate json patch function', () => { fourthLevel: 'hello-world', }, thirdLevelTwo: 'hello', + thirdLevelThree: ['hello', 'world'], }, }, }; @@ -673,6 +674,7 @@ describe('a generate json patch function', () => { fourthLevel: 'hello-brave-new-world', }, thirdLevelTwo: 'hello', + thirdLevelThree: ['hello', 'world'], }, }, }; @@ -688,13 +690,16 @@ describe('a generate json patch function', () => { fourthLevel: 'hello-brave-new-world', }, thirdLevelTwo: 'hello', + thirdLevelThree: ['hello', 'world'], }, }, ]); }); it('detects changes as a given depth of 4', () => { - const patch = generateJSONPatch(before, after, { maxDepth: 4 }); + const afterModified = structuredClone(after); + afterModified.firstLevel.secondLevel.thirdLevelTwo = 'hello-world'; + const patch = generateJSONPatch(before, afterModified, { maxDepth: 4 }); expect(patch).to.eql([ { op: 'replace', @@ -703,6 +708,51 @@ describe('a generate json patch function', () => { fourthLevel: 'hello-brave-new-world', }, }, + { + op: 'replace', + path: '/firstLevel/secondLevel/thirdLevelTwo', + value: 'hello-world', + }, + ]); + }); + + it('detects changes as a given depth of 4 for an array value', () => { + const afterModified = structuredClone(before); + afterModified.firstLevel.secondLevel.thirdLevelThree = ['test']; + const patch = generateJSONPatch(before, afterModified, { maxDepth: 4 }); + expect(patch).to.eql([ + { + op: 'replace', + path: '/firstLevel/secondLevel/thirdLevelThree', + value: ['test'], + }, + ]); + }); + + it('detects changes as a given depth of 4 for an removed array value', () => { + const afterModified = structuredClone(before); + // @ts-ignore + delete afterModified.firstLevel.secondLevel.thirdLevelThree; + const patch = generateJSONPatch(before, afterModified, { maxDepth: 4 }); + expect(patch).to.eql([ + { + op: 'remove', + path: '/firstLevel/secondLevel/thirdLevelThree', + }, + ]); + }); + + it('detects changes as a given depth of 4 for an nullyfied array value', () => { + const afterModified = structuredClone(before); + // @ts-ignore + afterModified.firstLevel.secondLevel.thirdLevelThree = null; + const patch = generateJSONPatch(before, afterModified, { maxDepth: 4 }); + expect(patch).to.eql([ + { + op: 'replace', + path: '/firstLevel/secondLevel/thirdLevelThree', + value: null, + }, ]); }); }); diff --git a/src/index.ts b/src/index.ts index 3765314..3a41a14 100644 --- a/src/index.ts +++ b/src/index.ts @@ -91,6 +91,10 @@ export function generateJSONPatch( const patch: Patch = []; const hasPropertyFilter = typeof propertyFilter === 'function'; + function maxDepthReached(path: string) { + return maxDepth <= path.split('/').length; + } + function compareArrays(leftArr: any[], rightArr: any[], path: string) { // if arrays are equal, no further comparison is required if (JSON.stringify(leftArr) === JSON.stringify(rightArr)) return; @@ -105,6 +109,11 @@ export function generateJSONPatch( let currentIndex = leftArr.length - 1; const targetHashes: string[] = []; + if (maxDepthReached(path)) { + patch.push({ op: 'replace', path: path, value: rightArr }); + return; + } + // Change iteration direction: from back to front for (let i = leftArr.length - 1; i >= 0; i--) { const newPathIndex = `${path}/${currentIndex--}`; @@ -154,7 +163,7 @@ export function generateJSONPatch( path === '' && [leftJsonValue, rightJsonValue].every(Array.isArray); if (isPrimitiveValue(leftJsonValue) || isPrimitiveValue(rightJsonValue)) { - if (leftJsonValue !== rightJsonValue) { + if (JSON.stringify(leftJsonValue) !== JSON.stringify(rightJsonValue)) { patch.push({ op: 'replace', path: path, value: rightJsonValue }); } return; @@ -186,8 +195,10 @@ export function generateJSONPatch( compareArrays(leftValue, rightValue, newPath); } else if (isJsonObject(rightValue)) { if (isJsonObject(leftValue)) { - if (maxDepth <= newPath.split('/').length) { - patch.push({ op: 'replace', path: newPath, value: rightValue }); + if (maxDepthReached(newPath)) { + if (JSON.stringify(leftValue) !== JSON.stringify(rightValue)) { + patch.push({ op: 'replace', path: newPath, value: rightValue }); + } } else { compareObjects(newPath, leftValue, rightValue); }