Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Diff & patch for JavaScript objects

branch: master
Octocat-spinner-32 bin adding console demo March 01, 2014
Octocat-spinner-32 build v0.1.5 March 05, 2014
Octocat-spinner-32 demo repo rename March 02, 2014
Octocat-spinner-32 docs Update deltas.md March 02, 2014
Octocat-spinner-32 external more gulping February 15, 2014
Octocat-spinner-32 src removing obsolete files April 01, 2014
Octocat-spinner-32 test-external v0.1.2 March 02, 2014
Octocat-spinner-32 test more ie8 fun March 02, 2014
Octocat-spinner-32 .gitignore including build output March 02, 2014
Octocat-spinner-32 .jshintrc annotated json February 25, 2014
Octocat-spinner-32 .travis.yml more gulping February 15, 2014
Octocat-spinner-32 MIT-LICENSE.txt big refactoring February 05, 2014
Octocat-spinner-32 Makefile gulp February 14, 2014
Octocat-spinner-32 README.md Update README.md March 16, 2014
Octocat-spinner-32 bower.json fixing bower.json March 05, 2014
Octocat-spinner-32 gulpfile.js clean test externals March 02, 2014
Octocat-spinner-32 karma.conf.js v0.1.2 March 02, 2014
Octocat-spinner-32 package.json fixing bower.json March 05, 2014
README.md

jsondiffpatch

Build Status NPM version NPM dependencies Bower version

Diff & patch JavaScript objects


Live Demo

  • min+gzipped < 6KB
  • browser (/build/bundle.js) and server (eg. node.js)
  • includes google-diff-match-patch for long text diffs (diff at character level)
  • smart array diffing using LCS, IMPORTANT NOTE: to match objects inside an array you must provide an objectHash function, check Array diff documentation
  • reverse a delta
  • unpatch (eg. revert object to its original state using a delta)
  • simplistic, pure JSON, low footprint delta format
  • multiple output formatters:
    • html (check it at the Live Demo)
    • annotated json (html), makes the JSON delta format self-explained
    • console (colored), try running ./node_modules/.bin/jsondiffpatch left.json right.json
    • write your own! check Formatters documentation

Supported platforms

  • Any modern browser and IE8+

Testling Status

And you can test your current browser visiting the test page.

  • Node.js Build Status

If you want to run tests locally:

npm i
# will test in node.js and phantomjs (headless browser)
npm test
# or test on specific browsers (using karma.js)
BROWSERS=chrome,phantomjs npm test

Usage

    // sample data
    var country = {
        name: "Argentina",
        capital: "Buenos Aires",
        independence: new Date(1816, 6, 9),
        unasur: true
    };

    // clone country, using dateReviver for Date objects
    var country2 = JSON.parse(JSON.stringify(country), jsondiffpatch.dateReviver);

    // make some changes
    country2.name = "Republica Argentina";
    country2.population = 41324992;
    delete country2.capital;

    var delta = jsondiffpatch.diff(country, country2);

    assertSame(delta, {
        "name":["Argentina","Republica Argentina"], // old value, new value
        "population":["41324992"], // new value
        "capital":["Buenos Aires", 0, 0] // deleted
    });

    // patch original
    jsondiffpatch.patch(country, delta);

    // reverse diff
    var reverseDelta = jsondiffpatch.reverse(delta);
    // also country2 can be return to original value with: jsondiffpatch.unpatch(country2, delta);

    var delta2 = jsondiffpatch.diff(country, country2);
    assert(delta2 === undefined)
    // undefined => no difference

Array diffing:

    // sample data
    var 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,
        }
        ]
    };

    // clone country
    var country2 = JSON.parse(JSON.stringify(country));

    // delete Cordoba
    country.cities.splice(1, 1);

    // add La Plata
    country.cities.splice(4, 0, {
        name: 'La Plata'
        });

    // modify Rosario, and move it
    var rosario = country.cities.splice(1, 1)[0];
    rosario.population += 1234;
    country.cities.push(rosario);

    // create a configured instance, match objects by name
    var diffpatcher = jsondiffpatch.create({
        objectHash: function(obj) {
            return obj.name;
        }
    });

    var delta = diffpatcher.diff(country, country2);

    assertSame(delta, {
        "cities": {
            "_t": "a", // indicates this node is an array (not an object)
            "1": [
                // inserted at index 1
                {
                    "name": "Cordoba",
                    "population": 1430023
                }]
            ,
            "2": {
                // population modified at index 2 (Rosario)
                "population": [
                    1137520,
                    1136286
                ]
            },
            "_3": [
                // removed from index 3
                {
                    "name": "La Plata"
                }, 0, 0],
            "_4": [
                // move from index 4 to index 2
                '', 2, 3]
        }
    });

For more example cases (nested objects or arrays, long text diffs) check test/examples/

If you want to understand deltas, see delta format documentation

Installing

npm (node.js)

npm install jsondiffpatch
var jsondiffpatch = require('jsondiffpatch').create(options);

bower (browser)

bower install jsondiffpatch

browser bundles are in the /build folder (run make or gulp to generate these):

  • bundle.js main bundle
  • bundle.full.js main bundle + google-diff-match-patch library for text diffs
  • formatters.js builtin formatters (only those useful in a browser)

(all these come in minified versions: .min.js)

Options

var jsondiffpatch = require('jsondiffpatch').create({
    // used to match objects when diffing arrays, by default only === operator is used
    objectHash: function(obj) {
        // this function is used only to when objects are not equal by ref
        return obj._id || obj.id;
    },
    arrays: {
        // default true, detect items moved inside the array (otherwise they will be registered as remove+add)
        detectMove: true,
        // default false, the value of items moved is not included in deltas
        includeValueOnMove: false
    },
    textDiff: {
        // default 60, minimum string length (left and right sides) to use text diff algorythm: google-diff-match-patch
        minLength: 60
    }
});

Visual Diff

<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="build/bundle.min.js"></script>
        <script type="text/javascript" src="build/formatters.min.js"></script>
        <link rel="stylesheet" href="src/formatters/html.css" type="text/css" />
        <link rel="stylesheet" href="src/formatters/annotated.css" type="text/css" />
    </head>
    <body>
        <div id="visual"></div>
        <hr/>
        <div id="annotated"></div>
        <script>
            var left = { a: 3, b: 4 };
            var right = { a: 5, c: 9 };
            var delta = jsondiffpatch.diff(left, right);

            // beautiful html diff
            document.getElementById('visual').innerHTML = jsondiffpatch.formatters.html.format(delta, left);

            // self-explained json
            document.getElementById('annotated').innerHTML = jsondiffpatch.formatters.annotated.format(delta, left);
        </script>
    </body>
</html>

To see formatters in action check the Live Demo.

For more details check Formatters documentation

Console

# diff two json files, colored output (using chalk lib)
./node_modules/.bin/jsondiffpatch ./left.json ./right.json

# or install globally
npm install -g jsondiffpatch

jsondiffpatch ./demo/left.json ./demo/right.json

console_demo!

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.

Something went wrong with that request. Please try again.