From 6ea96bcc33e42242bacc127f87ef85051bece0b0 Mon Sep 17 00:00:00 2001 From: Marco Link Date: Tue, 3 Sep 2024 20:05:38 +0200 Subject: [PATCH 1/2] feat: add max depth config --- src/index.spec.ts | 160 ++++++++++++++++++++++++++++------------------ src/index.ts | 9 ++- 2 files changed, 106 insertions(+), 63 deletions(-) diff --git a/src/index.spec.ts b/src/index.spec.ts index 522045f..a24c67e 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -1,7 +1,7 @@ -import type { JsonValue, ObjectHashContext, Patch } from './index'; -import { generateJSONPatch, pathInfo } from './index'; -import { applyPatch, deepClone } from 'fast-json-patch'; -import { assert, expect } from 'chai'; +import type {JsonValue, ObjectHashContext, Patch} from './index'; +import {generateJSONPatch, pathInfo} from './index'; +import {applyPatch, deepClone} from 'fast-json-patch'; +import {assert, expect} from 'chai'; type Title = string; type Before = JsonValue; @@ -18,9 +18,9 @@ const jsonValues = { primitiveNumberZero: 0, primitiveBooleanTrue: true, primitiveBooleanFalse: false, - jsonObjectWithFlatPropertiesAndStringValues: { a: 'a', b: 'b', c: 'c' }, - jsonObjectWithFlatPropertiesAndNumberValues: { a: 3, b: 2, c: 1 }, - jsonObjectWithFlatPropertiesAndMixedValues: { a: true, b: 'b', c: 12 }, + jsonObjectWithFlatPropertiesAndStringValues: {a: 'a', b: 'b', c: 'c'}, + jsonObjectWithFlatPropertiesAndNumberValues: {a: 3, b: 2, c: 1}, + jsonObjectWithFlatPropertiesAndMixedValues: {a: true, b: 'b', c: 12}, } as const; describe('a generate json patch function', () => { @@ -47,12 +47,12 @@ describe('a generate json patch function', () => { 'adds root array elements', [1, 2, 3], [1, 2, 3, 4], - [{ op: 'add', path: '/3', value: 4 }], + [{op: 'add', path: '/3', value: 4}], ], [ 'adds root object property', - { a: 'a', b: 'b' }, - { a: 'a', b: 'b', c: 'c' }, + {a: 'a', b: 'b'}, + {a: 'a', b: 'b', c: 'c'}, [ { op: 'add', @@ -65,38 +65,38 @@ describe('a generate json patch function', () => { 'removes root array elements', [1, 2, 3, 4], [1, 2, 3], - [{ op: 'remove', path: '/3' }], + [{op: 'remove', path: '/3'}], ], [ 'removes root object property', - { a: 'a', b: 'b', c: 'c' }, - { a: 'a', b: 'b' }, - [{ op: 'remove', path: '/c' }], + {a: 'a', b: 'b', c: 'c'}, + {a: 'a', b: 'b'}, + [{op: 'remove', path: '/c'}], ], [ 'replaces root number values', 1, 2, - [{ op: 'replace', path: '', value: 2 }], + [{op: 'replace', path: '', value: 2}], ], [ 'replaces root string values', 'hello', 'world', - [{ op: 'replace', path: '', value: 'world' }], + [{op: 'replace', path: '', value: 'world'}], ], [ 'replaces root boolean values', true, false, - [{ op: 'replace', path: '', value: false }], + [{op: 'replace', path: '', value: false}], ], ['replaces root empty arrays', [], [], []], [ 'replaces root object property', - { a: 'a', b: 'b' }, - { a: 'a', b: 'c' }, + {a: 'a', b: 'b'}, + {a: 'a', b: 'c'}, [ { op: 'replace', @@ -109,12 +109,12 @@ describe('a generate json patch function', () => { 'replaces root array elements', [1, 2, 3], [1, 2, 4], - [{ op: 'replace', path: '/2', value: 4 }], + [{op: 'replace', path: '/2', value: 4}], ], [ 'replaces an obj prop with an array property', - { prop: { hello: 'world' } }, - { prop: ['hello', 'world'] }, + {prop: {hello: 'world'}}, + {prop: ['hello', 'world']}, [ { op: 'replace', @@ -125,20 +125,20 @@ describe('a generate json patch function', () => { ], [ 'replaces an array prop with an obj property', - { prop: ['hello', 'world'] }, - { prop: { hello: 'world' } }, + {prop: ['hello', 'world']}, + {prop: {hello: 'world'}}, [ { op: 'replace', path: '/prop', - value: { hello: 'world' }, + value: {hello: 'world'}, }, ], ], [ 'replaces a deep nested object property', - { root: { first: { second: { third: 'before' } } } }, - { root: { first: { second: { third: 'after' } } } }, + {root: {first: {second: {third: 'before'}}}}, + {root: {first: {second: {third: 'after'}}}}, [ { op: 'replace', @@ -153,13 +153,13 @@ describe('a generate json patch function', () => { root: { first: [ {}, - { second: { third: 'before', list: ['hello', 'world'] } }, + {second: {third: 'before', list: ['hello', 'world']}}, ], }, }, { root: { - first: [{}, { second: { third: 'after', list: ['hello', 'world'] } }], + first: [{}, {second: {third: 'after', list: ['hello', 'world']}}], }, }, [ @@ -172,8 +172,8 @@ describe('a generate json patch function', () => { ], [ 'detects several changes on arrays by reference', - { root: [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }] }, - { root: [{ id: 4 }, { id: 3 }, { id: 2 }] }, + {root: [{id: 1}, {id: 2}, {id: 3}, {id: 4}]}, + {root: [{id: 4}, {id: 3}, {id: 2}]}, [ { op: 'remove', @@ -210,8 +210,8 @@ describe('a generate json patch function', () => { describe('with an array value hash function', () => { it('throws when objectHash is not a function', () => { - const before = [{ id: 1, paramOne: 'before' }]; - const after = [{ id: 2, paramOne: 'after' }]; + const before = [{id: 1, paramOne: 'before'}]; + const after = [{id: 2, paramOne: 'after'}]; assert.throws(() => generateJSONPatch(before, after, { @@ -223,12 +223,12 @@ describe('a generate json patch function', () => { it('handles changes with change and move on the same property', () => { const before = [ - { id: 1, paramOne: 'future', paramTwo: 'past' }, - { id: 2, paramOne: 'current' }, + {id: 1, paramOne: 'future', paramTwo: 'past'}, + {id: 2, paramOne: 'current'}, ]; const after = [ - { id: 2, paramOne: 'current' }, - { id: 1, paramOne: 'current' }, + {id: 2, paramOne: 'current'}, + {id: 1, paramOne: 'current'}, ]; const patch = generateJSONPatch(before, after, { @@ -239,19 +239,19 @@ describe('a generate json patch function', () => { const patched = doPatch(before, patch); expect(patched).to.be.eql([ - { id: 2, paramOne: 'current' }, - { id: 1, paramOne: 'current' }, + {id: 2, paramOne: 'current'}, + {id: 1, paramOne: 'current'}, ]); }); it('handles changes on array objects with different shape', () => { - const before = [{ id: 1, paramOne: 'current' }]; + const before = [{id: 1, paramOne: 'current'}]; const after = [ { id: 1, paramOne: 'future', paramTwo: 'past', - paramThree: { nested: 'some text' }, + paramThree: {nested: 'some text'}, }, ]; @@ -268,7 +268,7 @@ describe('a generate json patch function', () => { id: 1, paramOne: 'future', paramTwo: 'past', - paramThree: { nested: 'some text' }, + paramThree: {nested: 'some text'}, }, ]); }); @@ -487,7 +487,7 @@ describe('a generate json patch function', () => { objectHash: function (obj: any) { return `${obj.id}`; }, - array: { ignoreMove: true }, + array: {ignoreMove: true}, }); const patched = doPatch(before, patch); @@ -514,10 +514,10 @@ describe('a generate json patch function', () => { type: 'Granada', colors: ['red', 'silver', 'yellow'], engine: [ - { name: 'Cologne V6 2.6', hp: 125 }, - { name: 'Cologne V6 2.0', hp: 90 }, - { name: 'Cologne V6 2.3', hp: 108 }, - { name: 'Essex V6 3.0', hp: 150 }, + {name: 'Cologne V6 2.6', hp: 125}, + {name: 'Cologne V6 2.0', hp: 90}, + {name: 'Cologne V6 2.3', hp: 108}, + {name: 'Essex V6 3.0', hp: 150}, ], }; @@ -526,16 +526,16 @@ describe('a generate json patch function', () => { type: 'Granada', colors: ['red', 'silver', 'yellow'], engine: [ - { name: 'Essex V6 3.0', hp: 138 }, - { name: 'Cologne V6 2.6', hp: 125 }, - { name: 'Cologne V6 2.0', hp: 90 }, - { name: 'Cologne V6 2.3', hp: 108 }, + {name: 'Essex V6 3.0', hp: 138}, + {name: 'Cologne V6 2.6', hp: 125}, + {name: 'Cologne V6 2.0', hp: 90}, + {name: 'Cologne V6 2.3', hp: 108}, ], }; const patch = generateJSONPatch(before, after, { objectHash: function (value: JsonValue, context: ObjectHashContext) { - const { length, last } = pathInfo(context.path); + const {length, last} = pathInfo(context.path); if (length === 2 && last === 'engine') { // @ts-ignore return value?.name; @@ -548,8 +548,8 @@ describe('a generate json patch function', () => { expect(patched).to.be.eql(after); expect(patch).to.be.eql([ - { op: 'replace', path: '/engine/3/hp', value: 138 }, - { op: 'move', from: '/engine/3', path: '/engine/0' }, + {op: 'replace', path: '/engine/3/hp', value: 138}, + {op: 'move', from: '/engine/3', path: '/engine/0'}, ]); }); }); @@ -584,7 +584,7 @@ describe('a generate json patch function', () => { expect(patched).to.be.eql({ id: 1, paramOne: 'after', - paramTwo: { ignoreMe: 'before', doNotIgnoreMe: 'after' }, + paramTwo: {ignoreMe: 'before', doNotIgnoreMe: 'after'}, }); }); @@ -627,14 +627,14 @@ describe('a generate json patch function', () => { paramTwo: { ignoreMe: 'before', doNotIgnoreMe: 'after', - two: { ignoreMe: 'after' }, + two: {ignoreMe: 'after'}, }, }); expect(patch).to.eql([ - { op: 'replace', path: '/paramOne', value: 'after' }, - { op: 'replace', path: '/paramTwo/doNotIgnoreMe', value: 'after' }, - { op: 'replace', path: '/paramTwo/two/ignoreMe', value: 'after' }, + {op: 'replace', path: '/paramOne', value: 'after'}, + {op: 'replace', path: '/paramTwo/doNotIgnoreMe', value: 'after'}, + {op: 'replace', path: '/paramTwo/two/ignoreMe', value: 'after'}, ]); }); @@ -648,11 +648,49 @@ describe('a generate json patch function', () => { expect(patched).to.be.eql([1]); expect(patch).to.eql([ - { op: 'remove', path: '/2' }, - { op: 'remove', path: '/1' }, + {op: 'remove', path: '/2'}, + {op: 'remove', path: '/1'}, ]); }); }); + + describe('with maxDepth config', () => { + const before = { + firstLevel: { + secondLevel: { + thirdLevel: { + fourthLevel: "hello-world" + }, + thirdLevelTwo: "hello" + } + } + } + + const after = { + firstLevel: { + secondLevel: { + thirdLevel: { + fourthLevel: "hello-brave-new-world" + }, + thirdLevelTwo: "hello" + } + } + } + + const patch = generateJSONPatch(before, after, {maxDepth: 3}); + expect(patch).to.eql([ + { + op: 'replace', + path: '/firstLevel/secondLevel', + value: { + thirdLevel: { + fourthLevel: "hello-brave-new-world" + }, + thirdLevelTwo: "hello" + } + } + ]); + }) }); function doPatch(json: JsonValue, patch: Patch) { diff --git a/src/index.ts b/src/index.ts index 6bb0b3d..ce971d8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -71,6 +71,7 @@ export type JsonPatchConfig = { objectHash?: ObjectHash; propertyFilter?: PropertyFilter; array?: { ignoreMove?: boolean }; + maxDepth?: number }; export const defaultObjectHash: ObjectHash = (obj, context) => { @@ -82,7 +83,7 @@ export function generateJSONPatch( after: JsonValue, config: JsonPatchConfig = {} ): Patch { - const { objectHash = defaultObjectHash, propertyFilter } = config; + const { objectHash = defaultObjectHash, propertyFilter, maxDepth = Infinity } = config; const patch: Patch = []; const hasPropertyFilter = typeof propertyFilter === 'function'; @@ -181,7 +182,11 @@ export function generateJSONPatch( compareArrays(leftValue, rightValue, newPath); } else if (isJsonObject(rightValue)) { if (isJsonObject(leftValue)) { - compareObjects(newPath, leftValue, rightValue); + if(maxDepth <= path.split('/').length) { + patch.push({ op: 'replace', path: path, value: rightJsonValue }); + } else { + compareObjects(newPath, leftValue, rightValue); + } } else if (leftJsonValue.hasOwnProperty(rightKey)) { patch.push({ op: 'replace', path: newPath, value: rightValue }); } else { From 6c689b579713c5f99ed858fe4f71ca8dca987693 Mon Sep 17 00:00:00 2001 From: Marco Link Date: Tue, 3 Sep 2024 20:07:56 +0200 Subject: [PATCH 2/2] fix: linting --- src/index.spec.ts | 154 +++++++++++++++++++++++----------------------- src/index.ts | 10 ++- 2 files changed, 84 insertions(+), 80 deletions(-) diff --git a/src/index.spec.ts b/src/index.spec.ts index a24c67e..13fb91b 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -1,7 +1,7 @@ -import type {JsonValue, ObjectHashContext, Patch} from './index'; -import {generateJSONPatch, pathInfo} from './index'; -import {applyPatch, deepClone} from 'fast-json-patch'; -import {assert, expect} from 'chai'; +import type { JsonValue, ObjectHashContext, Patch } from './index'; +import { generateJSONPatch, pathInfo } from './index'; +import { applyPatch, deepClone } from 'fast-json-patch'; +import { assert, expect } from 'chai'; type Title = string; type Before = JsonValue; @@ -18,9 +18,9 @@ const jsonValues = { primitiveNumberZero: 0, primitiveBooleanTrue: true, primitiveBooleanFalse: false, - jsonObjectWithFlatPropertiesAndStringValues: {a: 'a', b: 'b', c: 'c'}, - jsonObjectWithFlatPropertiesAndNumberValues: {a: 3, b: 2, c: 1}, - jsonObjectWithFlatPropertiesAndMixedValues: {a: true, b: 'b', c: 12}, + jsonObjectWithFlatPropertiesAndStringValues: { a: 'a', b: 'b', c: 'c' }, + jsonObjectWithFlatPropertiesAndNumberValues: { a: 3, b: 2, c: 1 }, + jsonObjectWithFlatPropertiesAndMixedValues: { a: true, b: 'b', c: 12 }, } as const; describe('a generate json patch function', () => { @@ -47,12 +47,12 @@ describe('a generate json patch function', () => { 'adds root array elements', [1, 2, 3], [1, 2, 3, 4], - [{op: 'add', path: '/3', value: 4}], + [{ op: 'add', path: '/3', value: 4 }], ], [ 'adds root object property', - {a: 'a', b: 'b'}, - {a: 'a', b: 'b', c: 'c'}, + { a: 'a', b: 'b' }, + { a: 'a', b: 'b', c: 'c' }, [ { op: 'add', @@ -65,38 +65,38 @@ describe('a generate json patch function', () => { 'removes root array elements', [1, 2, 3, 4], [1, 2, 3], - [{op: 'remove', path: '/3'}], + [{ op: 'remove', path: '/3' }], ], [ 'removes root object property', - {a: 'a', b: 'b', c: 'c'}, - {a: 'a', b: 'b'}, - [{op: 'remove', path: '/c'}], + { a: 'a', b: 'b', c: 'c' }, + { a: 'a', b: 'b' }, + [{ op: 'remove', path: '/c' }], ], [ 'replaces root number values', 1, 2, - [{op: 'replace', path: '', value: 2}], + [{ op: 'replace', path: '', value: 2 }], ], [ 'replaces root string values', 'hello', 'world', - [{op: 'replace', path: '', value: 'world'}], + [{ op: 'replace', path: '', value: 'world' }], ], [ 'replaces root boolean values', true, false, - [{op: 'replace', path: '', value: false}], + [{ op: 'replace', path: '', value: false }], ], ['replaces root empty arrays', [], [], []], [ 'replaces root object property', - {a: 'a', b: 'b'}, - {a: 'a', b: 'c'}, + { a: 'a', b: 'b' }, + { a: 'a', b: 'c' }, [ { op: 'replace', @@ -109,12 +109,12 @@ describe('a generate json patch function', () => { 'replaces root array elements', [1, 2, 3], [1, 2, 4], - [{op: 'replace', path: '/2', value: 4}], + [{ op: 'replace', path: '/2', value: 4 }], ], [ 'replaces an obj prop with an array property', - {prop: {hello: 'world'}}, - {prop: ['hello', 'world']}, + { prop: { hello: 'world' } }, + { prop: ['hello', 'world'] }, [ { op: 'replace', @@ -125,20 +125,20 @@ describe('a generate json patch function', () => { ], [ 'replaces an array prop with an obj property', - {prop: ['hello', 'world']}, - {prop: {hello: 'world'}}, + { prop: ['hello', 'world'] }, + { prop: { hello: 'world' } }, [ { op: 'replace', path: '/prop', - value: {hello: 'world'}, + value: { hello: 'world' }, }, ], ], [ 'replaces a deep nested object property', - {root: {first: {second: {third: 'before'}}}}, - {root: {first: {second: {third: 'after'}}}}, + { root: { first: { second: { third: 'before' } } } }, + { root: { first: { second: { third: 'after' } } } }, [ { op: 'replace', @@ -153,13 +153,13 @@ describe('a generate json patch function', () => { root: { first: [ {}, - {second: {third: 'before', list: ['hello', 'world']}}, + { second: { third: 'before', list: ['hello', 'world'] } }, ], }, }, { root: { - first: [{}, {second: {third: 'after', list: ['hello', 'world']}}], + first: [{}, { second: { third: 'after', list: ['hello', 'world'] } }], }, }, [ @@ -172,8 +172,8 @@ describe('a generate json patch function', () => { ], [ 'detects several changes on arrays by reference', - {root: [{id: 1}, {id: 2}, {id: 3}, {id: 4}]}, - {root: [{id: 4}, {id: 3}, {id: 2}]}, + { root: [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }] }, + { root: [{ id: 4 }, { id: 3 }, { id: 2 }] }, [ { op: 'remove', @@ -210,8 +210,8 @@ describe('a generate json patch function', () => { describe('with an array value hash function', () => { it('throws when objectHash is not a function', () => { - const before = [{id: 1, paramOne: 'before'}]; - const after = [{id: 2, paramOne: 'after'}]; + const before = [{ id: 1, paramOne: 'before' }]; + const after = [{ id: 2, paramOne: 'after' }]; assert.throws(() => generateJSONPatch(before, after, { @@ -223,12 +223,12 @@ describe('a generate json patch function', () => { it('handles changes with change and move on the same property', () => { const before = [ - {id: 1, paramOne: 'future', paramTwo: 'past'}, - {id: 2, paramOne: 'current'}, + { id: 1, paramOne: 'future', paramTwo: 'past' }, + { id: 2, paramOne: 'current' }, ]; const after = [ - {id: 2, paramOne: 'current'}, - {id: 1, paramOne: 'current'}, + { id: 2, paramOne: 'current' }, + { id: 1, paramOne: 'current' }, ]; const patch = generateJSONPatch(before, after, { @@ -239,19 +239,19 @@ describe('a generate json patch function', () => { const patched = doPatch(before, patch); expect(patched).to.be.eql([ - {id: 2, paramOne: 'current'}, - {id: 1, paramOne: 'current'}, + { id: 2, paramOne: 'current' }, + { id: 1, paramOne: 'current' }, ]); }); it('handles changes on array objects with different shape', () => { - const before = [{id: 1, paramOne: 'current'}]; + const before = [{ id: 1, paramOne: 'current' }]; const after = [ { id: 1, paramOne: 'future', paramTwo: 'past', - paramThree: {nested: 'some text'}, + paramThree: { nested: 'some text' }, }, ]; @@ -268,7 +268,7 @@ describe('a generate json patch function', () => { id: 1, paramOne: 'future', paramTwo: 'past', - paramThree: {nested: 'some text'}, + paramThree: { nested: 'some text' }, }, ]); }); @@ -487,7 +487,7 @@ describe('a generate json patch function', () => { objectHash: function (obj: any) { return `${obj.id}`; }, - array: {ignoreMove: true}, + array: { ignoreMove: true }, }); const patched = doPatch(before, patch); @@ -514,10 +514,10 @@ describe('a generate json patch function', () => { type: 'Granada', colors: ['red', 'silver', 'yellow'], engine: [ - {name: 'Cologne V6 2.6', hp: 125}, - {name: 'Cologne V6 2.0', hp: 90}, - {name: 'Cologne V6 2.3', hp: 108}, - {name: 'Essex V6 3.0', hp: 150}, + { name: 'Cologne V6 2.6', hp: 125 }, + { name: 'Cologne V6 2.0', hp: 90 }, + { name: 'Cologne V6 2.3', hp: 108 }, + { name: 'Essex V6 3.0', hp: 150 }, ], }; @@ -526,16 +526,16 @@ describe('a generate json patch function', () => { type: 'Granada', colors: ['red', 'silver', 'yellow'], engine: [ - {name: 'Essex V6 3.0', hp: 138}, - {name: 'Cologne V6 2.6', hp: 125}, - {name: 'Cologne V6 2.0', hp: 90}, - {name: 'Cologne V6 2.3', hp: 108}, + { name: 'Essex V6 3.0', hp: 138 }, + { name: 'Cologne V6 2.6', hp: 125 }, + { name: 'Cologne V6 2.0', hp: 90 }, + { name: 'Cologne V6 2.3', hp: 108 }, ], }; const patch = generateJSONPatch(before, after, { objectHash: function (value: JsonValue, context: ObjectHashContext) { - const {length, last} = pathInfo(context.path); + const { length, last } = pathInfo(context.path); if (length === 2 && last === 'engine') { // @ts-ignore return value?.name; @@ -548,8 +548,8 @@ describe('a generate json patch function', () => { expect(patched).to.be.eql(after); expect(patch).to.be.eql([ - {op: 'replace', path: '/engine/3/hp', value: 138}, - {op: 'move', from: '/engine/3', path: '/engine/0'}, + { op: 'replace', path: '/engine/3/hp', value: 138 }, + { op: 'move', from: '/engine/3', path: '/engine/0' }, ]); }); }); @@ -584,7 +584,7 @@ describe('a generate json patch function', () => { expect(patched).to.be.eql({ id: 1, paramOne: 'after', - paramTwo: {ignoreMe: 'before', doNotIgnoreMe: 'after'}, + paramTwo: { ignoreMe: 'before', doNotIgnoreMe: 'after' }, }); }); @@ -627,14 +627,14 @@ describe('a generate json patch function', () => { paramTwo: { ignoreMe: 'before', doNotIgnoreMe: 'after', - two: {ignoreMe: 'after'}, + two: { ignoreMe: 'after' }, }, }); expect(patch).to.eql([ - {op: 'replace', path: '/paramOne', value: 'after'}, - {op: 'replace', path: '/paramTwo/doNotIgnoreMe', value: 'after'}, - {op: 'replace', path: '/paramTwo/two/ignoreMe', value: 'after'}, + { op: 'replace', path: '/paramOne', value: 'after' }, + { op: 'replace', path: '/paramTwo/doNotIgnoreMe', value: 'after' }, + { op: 'replace', path: '/paramTwo/two/ignoreMe', value: 'after' }, ]); }); @@ -648,8 +648,8 @@ describe('a generate json patch function', () => { expect(patched).to.be.eql([1]); expect(patch).to.eql([ - {op: 'remove', path: '/2'}, - {op: 'remove', path: '/1'}, + { op: 'remove', path: '/2' }, + { op: 'remove', path: '/1' }, ]); }); }); @@ -659,38 +659,38 @@ describe('a generate json patch function', () => { firstLevel: { secondLevel: { thirdLevel: { - fourthLevel: "hello-world" + fourthLevel: 'hello-world', }, - thirdLevelTwo: "hello" - } - } - } + thirdLevelTwo: 'hello', + }, + }, + }; const after = { firstLevel: { secondLevel: { thirdLevel: { - fourthLevel: "hello-brave-new-world" + fourthLevel: 'hello-brave-new-world', }, - thirdLevelTwo: "hello" - } - } - } + thirdLevelTwo: 'hello', + }, + }, + }; - const patch = generateJSONPatch(before, after, {maxDepth: 3}); + const patch = generateJSONPatch(before, after, { maxDepth: 3 }); expect(patch).to.eql([ { op: 'replace', path: '/firstLevel/secondLevel', value: { thirdLevel: { - fourthLevel: "hello-brave-new-world" + fourthLevel: 'hello-brave-new-world', }, - thirdLevelTwo: "hello" - } - } + thirdLevelTwo: 'hello', + }, + }, ]); - }) + }); }); function doPatch(json: JsonValue, patch: Patch) { diff --git a/src/index.ts b/src/index.ts index ce971d8..da52d65 100644 --- a/src/index.ts +++ b/src/index.ts @@ -71,7 +71,7 @@ export type JsonPatchConfig = { objectHash?: ObjectHash; propertyFilter?: PropertyFilter; array?: { ignoreMove?: boolean }; - maxDepth?: number + maxDepth?: number; }; export const defaultObjectHash: ObjectHash = (obj, context) => { @@ -83,7 +83,11 @@ export function generateJSONPatch( after: JsonValue, config: JsonPatchConfig = {} ): Patch { - const { objectHash = defaultObjectHash, propertyFilter, maxDepth = Infinity } = config; + const { + objectHash = defaultObjectHash, + propertyFilter, + maxDepth = Infinity, + } = config; const patch: Patch = []; const hasPropertyFilter = typeof propertyFilter === 'function'; @@ -182,7 +186,7 @@ export function generateJSONPatch( compareArrays(leftValue, rightValue, newPath); } else if (isJsonObject(rightValue)) { if (isJsonObject(leftValue)) { - if(maxDepth <= path.split('/').length) { + if (maxDepth <= path.split('/').length) { patch.push({ op: 'replace', path: path, value: rightJsonValue }); } else { compareObjects(newPath, leftValue, rightValue);