diff --git a/release-notes.md b/release-notes.md index 64ddbf75..c3d1df85 100644 --- a/release-notes.md +++ b/release-notes.md @@ -3,6 +3,7 @@ ## 9.1.0 (prerelease) - [#697](https://github.com/kpdecker/jsdiff/pull/697) *`diffJson` now correctly handles JSON objects containing a key named `__proto__`*. (Previously, the returned diff would be as if the `__proto__` key did not exist on either of the objects being diffed.) +- [#700](https://github.com/kpdecker/jsdiff/pull/700) *`diffJson` now correctly handles JSON objects containing a non-callable property named `toJSON`* - i.e. it gives such a property no special behaviour whatsoever, just as `JSON.stringify` doesn't. Previously, such properties caused an error to be thrown. (*Callable* `toJSON` properties continue to get the same special behaviour that `JSON.stringify` gives them.) ## 9.0.0 diff --git a/src/diff/json.ts b/src/diff/json.ts index 20fe8c84..f0207779 100644 --- a/src/diff/json.ts +++ b/src/diff/json.ts @@ -97,7 +97,7 @@ export function canonicalize( return canonicalizedObj; } - if (obj && obj.toJSON) { + if (obj && typeof obj.toJSON === 'function') { obj = obj.toJSON(); } diff --git a/test/diff/json.js b/test/diff/json.js index 7c744cb0..d7f2de7c 100644 --- a/test/diff/json.js +++ b/test/diff/json.js @@ -127,6 +127,38 @@ describe('diff/json', function() { { count: 1, value: '}', removed: false, added: false } ]); }); + + it('handles custom toJSON methods like JSON.stringify does', function() { + const x = { + toJSON: () => 'aaa' + }; + const y = { + toJSON: () => 'bbb' + }; + + expect(diffJson({ foo: x }, {foo: y})).to.eql([ + { count: 1, value: '{\n', removed: false, added: false }, + { count: 1, value: ' "foo": "aaa"\n', added: false, removed: true }, + { count: 1, value: ' "foo": "bbb"\n', added: true, removed: false }, + { count: 1, value: '}', removed: false, added: false } + ]); + }); + + it('treats non-callable toJSON properties as normal properties (like JSON.stringify does)', function() { + const x = { + toJSON: 'aaa' + }; + const y = { + toJSON: 'bbb' + }; + + expect(diffJson(x, y)).to.eql([ + { count: 1, value: '{\n', removed: false, added: false }, + { count: 1, value: ' "toJSON": "aaa"\n', added: false, removed: true }, + { count: 1, value: ' "toJSON": "bbb"\n', added: true, removed: false }, + { count: 1, value: '}', removed: false, added: false } + ]); + }); }); describe('#canonicalize', function() {