jsondiffpatch
jsondiffpatch.com
Diff & patch JavaScript objects
- min+gzipped ~ 16KB
- browser and server (ESM-only)
- deep diff, use delta to patch
- smart array diffing using LCS, IMPORTANT NOTE: to match objects inside an array you must provide an
objectHash function (this is how objects are matched, otherwise a dumb match by position is used). For more details, check Array diff documentation
- (optionally) text diffing of long strings powered by google-diff-match-patch (diff at character level)
- reverse a delta, unpatch (eg. revert object to its original state using a delta)
- multiple output formats:
- pure JSON, low footprint delta format
- visual diff (html), see demo
- annotated JSON (html), to help explain the delta format with annotations
- JSON Patch (RFC 6902), can generate patches, and also apply them
- console (colored), try running
./node_modules/.bin/jsondiffpatch left.json right.json
- write your own! check Formatters documentation
- BONUS:
jsondiffpatch.clone(obj) (deep clone)
Supported platforms
Usage
on your terminal:
npx jsondiffpatch --help

or as a library:
const country = {
name: 'Argentina',
capital: 'Buenos Aires',
independence: new Date(1816, 6, 9),
};
const country2 = JSON.parse(JSON.stringify(country), jsondiffpatch.dateReviver);
country2.name = 'Republica Argentina';
country2.population = 41324992;
delete country2.capital;
const delta = jsondiffpatch.diff(country, country2);
assertSame(delta, {
name: ['Argentina', 'Republica Argentina'],
population: ['41324992'],
capital: ['Buenos Aires', 0, 0],
});
jsondiffpatch.patch(country, delta);
const reverseDelta = jsondiffpatch.reverse(delta);
const delta2 = jsondiffpatch.diff(country, country2);
assert(delta2 === undefined);
Array diffing:
const country = {
name: 'Argentina',
cities: [
{
name: 'Buenos Aires',
population: 13028000,
},
{
name: 'Cordoba',
population: 1430023,
},
{
name: 'Rosario',
population: 1136286,
},
{
name: 'Mendoza',
population: 901126,
},
{
name: 'San Miguel de Tucuman',
population: 800000,
},
],
};
const country2 = JSON.parse(JSON.stringify(country));
country.cities.splice(1, 1);
country.cities.splice(4, 0, {
name: 'La Plata',
});
const rosario = country.cities.splice(1, 1)[0];
rosario.population += 1234;
country.cities.push(rosario);
const diffpatcher = jsondiffpatch.create({
objectHash: function (obj) {
return obj.name;
},
});
const delta = diffpatcher.diff(country, country2);
assertSame(delta, {
cities: {
_t: 'a',
1: [
{
name: 'Cordoba',
population: 1430023,
},
],
2: {
population: [1137520, 1136286],
},
_3: [
{
name: 'La Plata',
},
0,
0,
],
_4: [
'',
2,
3,
],
},
});
For more example cases (nested objects or arrays, long text diffs) check packages/jsondiffpatch/test/examples/
If you want to understand deltas, see delta format documentation
Installing
NPM
This works for node, or in browsers if you already do bundling on your app
npm install jsondiffpatch
import {* as jsondiffpatch} from 'jsondiffpatch';
const jsondiffpatchInstance = jsondiffpatch.create(options);
browser
In a browser, you can load a bundle using a tool like esm.sh or Skypack.
Options
import * as jsondiffpatch from 'jsondiffpatch';
import { diff_match_patch } from '@dmsnell/diff-match-patch';
const jsondiffpatchInstance = jsondiffpatch.create({
objectHash: function (obj) {
return obj._id || obj.id;
},
arrays: {
detectMove: true,
includeValueOnMove: false,
},
textDiff: {
diffMatchPatch: diff_match_patch,
minLength: 60,
},
propertyFilter: function (name, context) {
return name.slice(0, 1) !== '$';
},
cloneDiffValues: false
omitRemovedValues: false ,
});
Visual Diff
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="./style.css" type="text/css" />
<link
rel="stylesheet"
href="https://esm.sh/jsondiffpatch@0.6.0/lib/formatters/styles/html.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://esm.sh/jsondiffpatch@0.6.0/lib/formatters/styles/annotated.css"
type="text/css"
/>
</head>
<body>
<div id="visual"></div>
<hr />
<div id="annotated"></div>
<script type="module">
import * as jsondiffpatch from 'https://esm.sh/jsondiffpatch@0.6.0';
import * as annotatedFormatter from 'https://esm.sh/jsondiffpatch@0.6.0/formatters/annotated';
import * as htmlFormatter from 'https://esm.sh/jsondiffpatch@0.6.0/formatters/html';
const left = { a: 3, b: 4 };
const right = { a: 5, c: 9 };
const delta = jsondiffpatch.diff(left, right);
document.getElementById('visual').innerHTML = htmlFormatter.format(
delta,
left,
);
document.getElementById('annotated').innerHTML =
annotatedFormatter.format(delta, left);
</script>
</body>
</html>
To see formatters in action check the Live Demo.
For more details check Formatters documentation
Plugins
diff(), patch() and reverse() functions are implemented using Pipes & Filters pattern, making it extremely customizable by adding or replacing filters on a pipe.
Check Plugins documentation for details.
Related Projects
All contributors ✨