From e266acc3e8a3f887ecfdc0d350ceffa0e2fb2716 Mon Sep 17 00:00:00 2001 From: Mark Amery Date: Wed, 12 Aug 2026 14:41:12 +0100 Subject: [PATCH 1/4] Add test showing behaviour reported in https://github.com/kpdecker/jsdiff/issues/699 --- test/diff/json.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) 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() { From c0d740450c6477d522df0bc4d0e54144adc1a7a6 Mon Sep 17 00:00:00 2001 From: Mark Amery Date: Wed, 12 Aug 2026 14:44:25 +0100 Subject: [PATCH 2/4] Fix https://github.com/kpdecker/jsdiff/issues/699 --- src/diff/json.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(); } From 24b545706018ca931285d5c9cd62cbe5239a5ae3 Mon Sep 17 00:00:00 2001 From: Mark Amery Date: Wed, 12 Aug 2026 14:49:45 +0100 Subject: [PATCH 3/4] Add release notes --- release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/release-notes.md b/release-notes.md index 64ddbf75..47410e70 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. (*Callable* `toJSON` properties continue to get the same special behaviour that `JSON.stringify` gives them.) ## 9.0.0 From a6730b83d1b277b8df6fee7b6fe3bcf9cbf30cbc Mon Sep 17 00:00:00 2001 From: Mark Amery Date: Wed, 12 Aug 2026 14:50:18 +0100 Subject: [PATCH 4/4] Release notes --- release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-notes.md b/release-notes.md index 47410e70..c3d1df85 100644 --- a/release-notes.md +++ b/release-notes.md @@ -3,7 +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. (*Callable* `toJSON` properties continue to get the same special behaviour that `JSON.stringify` gives them.) +- [#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