JSFiddle - React, Tailwind, and code Playground

by bruth

HTML

<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="https://raw.github.com/bruth/jsonpatch-js/master/jsonpatch.js"></script>

JavaScript

var obj1 = {
    4: 'e',
    1: ['a', 'c', 5]
};

var obj2 = {
    5: ['a', 'c', 5],
    2: {
        4: 'e'
    },
    3: 'b',
};

toString = Object.prototype.toString;

function objType(obj) {
    if (obj === null) {
        return 'null';
    } else if (obj === undefined) {
        return 'undefined';
    } else {
        return toString.call(obj).match(/\[object (.*)\]/)[1].toLowerCase();
    }
}

function flatten(obj, prefix, paths) {
    prefix || (prefix = '');
    paths || (paths = {});

    paths[prefix || '/'] = {path: prefix || '/', value: obj, type: objType(obj)};
    
    if (_.isArray(obj)) {
        flattenArray(obj, prefix + '/', paths);
    } else if (_.isObject(obj)) {
        flattenObject(obj, prefix + '/', paths);
    }
    return paths;
}

function flattenArray(obj, prefix, paths) {
    for (var i = 0, l = obj.length; i < l; i++) {
        flatten(obj[i], prefix + i, paths);
    }
}       
            
function flattenObject(obj, prefix, paths) {
    for (var key in obj) {
        flatten(obj[key], prefix + key, paths);
    }
}

function parentPath(path) {
    return path.substr(0, path.match(/\//g).length);
}

function compare(obj1, obj2) {
    if (obj1 == null || obj2 == null) {
        throw new Error('Patches can only be derived from objects');
    }
    
    var paths1 = flatten(obj1),
        paths2 = flatten(obj2),
        key1,
        key2,
        doc1,
        doc2,
        parent,
        diff = [],
        add = {},
        remove = {},
        replace = {},
        move = {};

    for (key1 in paths1) {
        doc1 = paths1[key1], doc2 = paths2[key1];
        // Missing in second object, thus we mark it to be removed for now.
        // Ensure the parent is present, otherwise we will be attempting to
        // remove a member from a non-existent object
        if (paths2[parentPath(key1)] !== undefined) {
            if (!doc2) {
                remove[key1] = doc1;
            // If both members have existing values, this...