Plato on Github
Report Home
node_modules/json-diff-patch/jsondiff.js
Maintainability
57.23
Lines of code
230
Difficulty
102.68
Estimated Errors
2.26
Function weight
By Complexity
By SLOC
// Generated by CoffeeScript 1.4.0 (function() { (function(root, factory) { if (typeof exports !== 'undefined') { return factory(root, exports); } else if (typeof define === 'function' && define.amd) { return define(['exports'], function(exports) { return root.jsondiff = factory(root, exports); }); } else { return root.jsondiff = factory(root, {}); } })(this, function(root) { var diff, eq, flattenObject, getParent, has, hasOwnProperty, isArray, isContainer, isEqual, isFunction, isObject, isSameContainer, isString, toString; toString = Object.prototype.toString; hasOwnProperty = Object.prototype.hasOwnProperty; isArray = function(obj) { return toString.call(obj) === '[object Array]'; }; isObject = function(obj) { return toString.call(obj) === '[object Object]'; }; isString = function(obj) { return toString.call(obj) === '[object String]'; }; isFunction = function(obj) { return toString.call(obj) === '[object Function]'; }; has = function(obj, key) { return hasOwnProperty.call(obj, key); }; isEqual = function(a, b) { return eq(a, b, [], []); }; eq = function(a, b, aStack, bStack) { var aCtor, bCtor, className, key, length, result, size; if (a === b) { return a !== 0 || 1 / a === 1 / b; } if (!(a != null) || !(b != null)) { return a === b; } className = toString.call(a); if (className !== toString.call(b)) { return false; } switch (className) { case "[object String]": return a === String(b); case "[object Number]": return (a !== +a ? b !== +b : (a === 0 ? 1 / a === 1 / b : a === +b)); case "[object Date]": case "[object Boolean]": return +a === +b; case "[object RegExp]": return a.source === b.source && a.global === b.global && a.multiline === b.multiline && a.ignoreCase === b.ignoreCase; } if (typeof a !== "object" || typeof b !== "object") { return false; } length = aStack.length; if ((function() { var _results; _results = []; while (length--) { _results.push(aStack[length] === a); } return _results; })()) { return bStack[length] === b; } aStack.push(a); bStack.push(b); size = 0; result = true; if (className === "[object Array]") { size = a.length; result = size === b.length; if (result) { while (size--) { if (!(result = eq(a[size], b[size], aStack, bStack))) { break; } } } } else { aCtor = a.constructor; bCtor = b.constructor; if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) && isFunction(bCtor) && (bCtor instanceof bCtor))) { return false; } for (key in a) { if (has(a, key)) { size++; if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack))) { break; } } } if (result) { for (key in b) { if (has(b, key) && !(size--)) { break; } } result = !size; } } aStack.pop(); bStack.pop(); return result; }; getParent = function(paths, path) { return paths[path.substr(0, path.match(/\//g).length)]; }; isContainer = function(obj) { return isArray(obj) || isObject(obj); }; isSameContainer = function(obj1, obj2) { return (isArray(obj1) && isArray(obj2)) || (isObject(obj1) && isObject(obj2)); }; flattenObject = function(obj, prefix, paths) { var i, key, o, _i, _len; if (prefix == null) { prefix = "/"; } if (paths == null) { paths = {}; } paths[prefix] = { path: prefix, value: obj }; if (prefix !== '/') { prefix = prefix + '/'; } if (isArray(obj)) { for (i = _i = 0, _len = obj.length; _i < _len; i = ++_i) { o = obj[i]; flattenObject(o, prefix + i, paths); } } else if (isObject(obj)) { for (key in obj) { o = obj[key]; flattenObject(o, prefix + key, paths); } } return paths; }; diff = function(obj1, obj2) { var add, doc, doc1, doc2, key, key1, key2, keyfrom, keyto, move, patch, paths1, paths2, remove, replace; if (!isSameContainer(obj1, obj2)) { throw new Error('Patches can only be derived from objects or arrays'); } paths1 = flattenObject(obj1); paths2 = flattenObject(obj2); add = {}; remove = {}; replace = {}; move = {}; for (key in paths1) { doc1 = paths1[key]; doc2 = paths2[key]; if (!getParent(paths2, key)) { continue; } else if (!doc2) { remove[key] = doc1; } else if (isSameContainer(doc1.value, doc2.value)) { continue; } else if (!isEqual(doc1.value, doc2.value)) { replace[key] = doc2; } } for (key in paths2) { doc1 = paths1[key]; doc2 = paths2[key]; if (!doc1 && isSameContainer(getParent(paths1, key), getParent(paths2, key))) { add[key] = doc2; } } for (key1 in remove) { doc1 = remove[key1]; for (key2 in add) { doc2 = add[key2]; if (isEqual(doc2.value, doc1.value)) { delete remove[key1]; delete add[key2]; move[key2] = key1; break; } } } patch = []; for (key in add) { doc = add[key]; patch.push({ op: 'add', path: key, value: doc.value }); } for (key in remove) { patch.push({ op: 'remove', path: key }); } for (key in replace) { doc = replace[key]; patch.push({ op: 'replace', path: key, value: doc.value }); } for (keyto in move) { keyfrom = move[keyto]; patch.push({ op: 'move', from: keyfrom, path: keyto }); } return patch; }; root.diff = diff; return root; }); }).call(this);