function accumulateDiff(lhs, rhs, prefilter, accum) { accum = accum || []; deepDiff(lhs, rhs, function(diff) { if (diff) { accum.push(diff); } }, prefilter); return (accum.length) ? accum : undefined; }
n/a
function applyChange(target, source, change) { if (target && source && change && change.kind) { var it = target, i = -1, last = change.path ? change.path.length - 1 : 0; while (++i < last) { if (typeof it[change.path[i]] === 'undefined') { it[change.path[i]] = (typeof change.path[i] === 'number') ? [] : {}; } it = it[change.path[i]]; } switch (change.kind) { case 'A': applyArrayChange(change.path ? it[change.path[i]] : it, change.index, change.item); break; case 'D': delete it[change.path[i]]; break; case 'E': case 'N': it[change.path[i]] = change.rhs; break; } } }
n/a
function applyDiff(target, source, filter) { if (target && source) { var onChange = function(change) { if (!filter || filter(target, source, change)) { applyChange(target, source, change); } }; deepDiff(target, source, onChange); } }
n/a
function accumulateDiff(lhs, rhs, prefilter, accum) { accum = accum || []; deepDiff(lhs, rhs, function(diff) { if (diff) { accum.push(diff); } }, prefilter); return (accum.length) ? accum : undefined; }
n/a
isConflict = function () { return 'undefined' !== typeof conflict; }
n/a
noConflict = function () { if (conflictResolution) { conflictResolution.forEach(function(it) { it(); }); conflictResolution = null; } return accumulateDiff; }
...
```
**browser**
```html
<script src="deep-diff-0.3.1.min.js"></script>
```
> Minified, browser release of the current version of the module is under the `releases` folder.
> In a browser, `deep-diff` defines a global variable `DeepDiff`. If there is a conflict in the global namespace you can restore
the conflicting definition and assign `deep-diff` to another variable like this: `var deep = DeepDiff.noConflict();`.
## Simple Examples
In order to describe differences, change revolves around an `origin` object. For consistency, the `origin` object is always the
operand on the `left-hand-side` of operations. The `comparand`, which may contain changes, is always on the `right-hand-side` of
operations.
``` javascript
var diff = require('deep-diff').diff;
...
function deepDiff(lhs, rhs, changes, prefilter, path, key, stack) { path = path || []; var currentPath = path.slice(0); if (typeof key !== 'undefined') { if (prefilter) { if (typeof(prefilter) === 'function' && prefilter(currentPath, key)) { return; } else if (typeof(prefilter) === 'object') { if (prefilter.prefilter && prefilter.prefilter(currentPath, key)) { return; } if (prefilter.normalize) { var alt = prefilter.normalize(currentPath, key, lhs, rhs); if (alt) { lhs = alt[0]; rhs = alt[1]; } } } } currentPath.push(key); } // Use string comparison for regexes if (realTypeOf(lhs) === 'regexp' && realTypeOf(rhs) === 'regexp') { lhs = lhs.toString(); rhs = rhs.toString(); } var ltype = typeof lhs; var rtype = typeof rhs; if (ltype === 'undefined') { if (rtype !== 'undefined') { changes(new DiffNew(currentPath, rhs)); } else { changes(new DiffDeleted(currentPath, lhs)); } } else if (rtype === 'undefined') { changes(new DiffDeleted(currentPath, lhs)); } else if (realTypeOf(lhs) !== realTypeOf(rhs)) { changes(new DiffEdit(currentPath, lhs, rhs)); } else if (realTypeOf(lhs) === 'date' && (lhs - rhs) !== 0) { changes(new DiffEdit(currentPath, lhs, rhs)); } else if (ltype === 'object' && lhs !== null && rhs !== null) { stack = stack || []; if (stack.indexOf(lhs) < 0) { stack.push(lhs); if (Array.isArray(lhs)) { var i, len = lhs.length; for (i = 0; i < lhs.length; i++) { if (i >= rhs.length) { changes(new DiffArray(currentPath, i, new DiffDeleted(undefined, lhs[i]))); } else { deepDiff(lhs[i], rhs[i], changes, prefilter, currentPath, i, stack); } } while (i < rhs.length) { changes(new DiffArray(currentPath, i, new DiffNew(undefined, rhs[i++]))); } } else { var akeys = Object.keys(lhs); var pkeys = Object.keys(rhs); akeys.forEach(function(k, i) { var other = pkeys.indexOf(k); if (other >= 0) { deepDiff(lhs[k], rhs[k], changes, prefilter, currentPath, k, stack); pkeys = arrayRemove(pkeys, other); } else { deepDiff(lhs[k], undefined, changes, prefilter, currentPath, k, stack); } }); pkeys.forEach(function(k) { deepDiff(undefined, rhs[k], changes, prefilter, currentPath, k, stack); }); } stack.length = stack.length - 1; } else if (lhs !== rhs) { // lhs is contains a cycle at this element and it differs from rhs changes(new DiffEdit(currentPath, lhs, rhs)); } } else if (lhs !== rhs) { if (!(ltype === 'number' && isNaN(lhs) && isNaN(rhs))) { changes(new DiffEdit(currentPath, lhs, rhs)); } } }
n/a
function revertChange(target, source, change) { if (target && source && change && change.kind) { var it = target, i, u; u = change.path.length - 1; for (i = 0; i < u; i++) { if (typeof it[change.path[i]] === 'undefined') { it[change.path[i]] = {}; } it = it[change.path[i]]; } switch (change.kind) { case 'A': // Array was modified... // it will be an array... revertArrayChange(it[change.path[i]], change.index, change.item); break; case 'D': // Item was deleted... it[change.path[i]] = change.lhs; break; case 'E': // Item was edited... it[change.path[i]] = change.lhs; break; case 'N': // Item is new... delete it[change.path[i]]; break; } } }
n/a
function accumulateDiff(lhs, rhs, prefilter, accum) { accum = accum || []; deepDiff(lhs, rhs, function(diff) { if (diff) { accum.push(diff); } }, prefilter); return (accum.length) ? accum : undefined; }
n/a
function applyChange(target, source, change) { if (target && source && change && change.kind) { var it = target, i = -1, last = change.path ? change.path.length - 1 : 0; while (++i < last) { if (typeof it[change.path[i]] === 'undefined') { it[change.path[i]] = (typeof change.path[i] === 'number') ? [] : {}; } it = it[change.path[i]]; } switch (change.kind) { case 'A': applyArrayChange(change.path ? it[change.path[i]] : it, change.index, change.item); break; case 'D': delete it[change.path[i]]; break; case 'E': case 'N': it[change.path[i]] = change.rhs; break; } } }
n/a
function applyDiff(target, source, filter) { if (target && source) { var onChange = function(change) { if (!filter || filter(target, source, change)) { applyChange(target, source, change); } }; deepDiff(target, source, onChange); } }
n/a
isConflict = function () { return 'undefined' !== typeof conflict; }
n/a
noConflict = function () { if (conflictResolution) { conflictResolution.forEach(function(it) { it(); }); conflictResolution = null; } return accumulateDiff; }
...
```
**browser**
```html
<script src="deep-diff-0.3.1.min.js"></script>
```
> Minified, browser release of the current version of the module is under the `releases` folder.
> In a browser, `deep-diff` defines a global variable `DeepDiff`. If there is a conflict in the global namespace you can restore
the conflicting definition and assign `deep-diff` to another variable like this: `var deep = DeepDiff.noConflict();`.
## Simple Examples
In order to describe differences, change revolves around an `origin` object. For consistency, the `origin` object is always the
operand on the `left-hand-side` of operations. The `comparand`, which may contain changes, is always on the `right-hand-side` of
operations.
``` javascript
var diff = require('deep-diff').diff;
...
function deepDiff(lhs, rhs, changes, prefilter, path, key, stack) { path = path || []; var currentPath = path.slice(0); if (typeof key !== 'undefined') { if (prefilter) { if (typeof(prefilter) === 'function' && prefilter(currentPath, key)) { return; } else if (typeof(prefilter) === 'object') { if (prefilter.prefilter && prefilter.prefilter(currentPath, key)) { return; } if (prefilter.normalize) { var alt = prefilter.normalize(currentPath, key, lhs, rhs); if (alt) { lhs = alt[0]; rhs = alt[1]; } } } } currentPath.push(key); } // Use string comparison for regexes if (realTypeOf(lhs) === 'regexp' && realTypeOf(rhs) === 'regexp') { lhs = lhs.toString(); rhs = rhs.toString(); } var ltype = typeof lhs; var rtype = typeof rhs; if (ltype === 'undefined') { if (rtype !== 'undefined') { changes(new DiffNew(currentPath, rhs)); } else { changes(new DiffDeleted(currentPath, lhs)); } } else if (rtype === 'undefined') { changes(new DiffDeleted(currentPath, lhs)); } else if (realTypeOf(lhs) !== realTypeOf(rhs)) { changes(new DiffEdit(currentPath, lhs, rhs)); } else if (realTypeOf(lhs) === 'date' && (lhs - rhs) !== 0) { changes(new DiffEdit(currentPath, lhs, rhs)); } else if (ltype === 'object' && lhs !== null && rhs !== null) { stack = stack || []; if (stack.indexOf(lhs) < 0) { stack.push(lhs); if (Array.isArray(lhs)) { var i, len = lhs.length; for (i = 0; i < lhs.length; i++) { if (i >= rhs.length) { changes(new DiffArray(currentPath, i, new DiffDeleted(undefined, lhs[i]))); } else { deepDiff(lhs[i], rhs[i], changes, prefilter, currentPath, i, stack); } } while (i < rhs.length) { changes(new DiffArray(currentPath, i, new DiffNew(undefined, rhs[i++]))); } } else { var akeys = Object.keys(lhs); var pkeys = Object.keys(rhs); akeys.forEach(function(k, i) { var other = pkeys.indexOf(k); if (other >= 0) { deepDiff(lhs[k], rhs[k], changes, prefilter, currentPath, k, stack); pkeys = arrayRemove(pkeys, other); } else { deepDiff(lhs[k], undefined, changes, prefilter, currentPath, k, stack); } }); pkeys.forEach(function(k) { deepDiff(undefined, rhs[k], changes, prefilter, currentPath, k, stack); }); } stack.length = stack.length - 1; } else if (lhs !== rhs) { // lhs is contains a cycle at this element and it differs from rhs changes(new DiffEdit(currentPath, lhs, rhs)); } } else if (lhs !== rhs) { if (!(ltype === 'number' && isNaN(lhs) && isNaN(rhs))) { changes(new DiffEdit(currentPath, lhs, rhs)); } } }
n/a
function revertChange(target, source, change) { if (target && source && change && change.kind) { var it = target, i, u; u = change.path.length - 1; for (i = 0; i < u; i++) { if (typeof it[change.path[i]] === 'undefined') { it[change.path[i]] = {}; } it = it[change.path[i]]; } switch (change.kind) { case 'A': // Array was modified... // it will be an array... revertArrayChange(it[change.path[i]], change.index, change.item); break; case 'D': // Item was deleted... it[change.path[i]] = change.lhs; break; case 'E': // Item was edited... it[change.path[i]] = change.lhs; break; case 'N': // Item is new... delete it[change.path[i]]; break; } } }
n/a