Comparing version 1.0.0-pre.1 to 1.0.0-pre.2
@@ -7,4 +7,6 @@ # deep-diff Change Log | ||
`1.0-pre` - 2018-02-25 | ||
`1.0.0-pre.x` - 2018-02-25 | ||
Install with `npm install deep-diff@next`... planning to release after only a few days of feedback. | ||
* reverted to [UMD style module](https://github.com/umdjs/umd) rather than the ES6 style, which evidently, broke lots of people's previously working code. | ||
@@ -11,0 +13,0 @@ * fixed some bugs... |
/*jshint indent:2, laxcomma:true, laxbreak:true*/ | ||
var util = require('util') | ||
, expect = require('expect.js') | ||
, eql = require('deep-equal') | ||
, deep = require('..') | ||
; | ||
var util = require('util'); | ||
var expect = require('expect.js'); | ||
var deep = require('..'); | ||
var lhs = { | ||
"id": "Release", | ||
"phases": [{ | ||
"id": "Phase1", | ||
"tasks": [ | ||
{"id": "Task1"}, | ||
{"id": "Task2"} | ||
] | ||
}, { | ||
"id": "Phase2", | ||
"tasks": [ | ||
{"id": "Task3"} | ||
] | ||
}] | ||
'id': 'Release', | ||
'phases': [{ | ||
'id': 'Phase1', | ||
'tasks': [ | ||
{ 'id': 'Task1' }, | ||
{ 'id': 'Task2' } | ||
] | ||
}, { | ||
'id': 'Phase2', | ||
'tasks': [ | ||
{ 'id': 'Task3' } | ||
] | ||
}] | ||
}; | ||
var rhs = { | ||
"id": "Release", | ||
"phases": [{ | ||
// E: Phase1 -> Phase2 | ||
"id": "Phase2", | ||
"tasks": [ | ||
{"id": "Task3"} | ||
] | ||
}, { | ||
"id": "Phase1", | ||
"tasks": [ | ||
{"id": "Task1"}, | ||
{"id": "Task2"} | ||
] | ||
}] | ||
}; | ||
'id': 'Release', | ||
'phases': [{ | ||
// E: Phase1 -> Phase2 | ||
'id': 'Phase2', | ||
'tasks': [ | ||
{ 'id': 'Task3' } | ||
] | ||
}, { | ||
'id': 'Phase1', | ||
'tasks': [ | ||
{ 'id': 'Task1' }, | ||
{ 'id': 'Task2' } | ||
] | ||
}] | ||
}; | ||
var diff = deep.diff(lhs, rhs); | ||
var diff = deep.diff(lhs, rhs); | ||
console.log(util.inspect(diff, false, 9)); // eslint-disable-line no-console | ||
// there should be differences | ||
expect(diff).to.be.ok(); | ||
expect(diff.length).to.be(6); | ||
deep.applyDiff(lhs, rhs); | ||
console.log(util.inspect(lhs, false, 9)); // eslint-disable-line no-console | ||
expect(lhs).to.be.eql(rhs); | ||
// It.phases[0].id changed from 'Phase1' to 'Phase2' | ||
// | ||
expect(diff[0].kind).to.be('E'); | ||
expect(diff[0].path).to.be.an('array'); | ||
expect(diff[0].path).to.have.length(3); | ||
expect(diff[0].path[0]).to.be('phases'); | ||
expect(diff[0].path[1]).to.be(0); | ||
expect(diff[0].path[2]).to.be('id'); | ||
expect(diff[0].lhs).to.be('Phase1'); | ||
expect(diff[0].rhs).to.be('Phase2'); | ||
// It.phases[0].tasks[0].id changed from 'Task1' to 'Task3' | ||
// | ||
expect(diff[1].kind).to.be('E'); | ||
expect(diff[1].path).to.be.an('array'); | ||
expect(diff[1].path).to.have.length(5); | ||
expect(diff[1].path[0]).to.be('phases'); | ||
expect(diff[1].path[1]).to.be(0); | ||
expect(diff[1].path[2]).to.be('tasks'); | ||
expect(diff[1].path[3]).to.be(0); | ||
expect(diff[1].path[4]).to.be('id'); | ||
expect(diff[1].lhs).to.be('Task1'); | ||
expect(diff[1].rhs).to.be('Task3'); | ||
// It.phases[0].tasks[1] was deleted | ||
// | ||
expect(diff[2].kind).to.be('A'); | ||
expect(diff[2].path).to.be.an('array'); | ||
expect(diff[2].path).to.have.length(3); | ||
expect(diff[2].path[0]).to.be('phases'); | ||
expect(diff[2].path[1]).to.be(0); | ||
expect(diff[2].path[2]).to.be('tasks'); | ||
expect(diff[2].index).to.be(1); | ||
expect(diff[2].item.kind).to.be('D'); | ||
// It.phases[1].id changed from 'Phase2' to 'Phase1' | ||
// | ||
expect(diff[3].kind).to.be('E'); | ||
expect(diff[3].path).to.be.an('array'); | ||
expect(diff[3].path).to.have.length(3); | ||
expect(diff[3].path[0]).to.be('phases'); | ||
expect(diff[3].path[1]).to.be(1); | ||
expect(diff[3].path[2]).to.be('id'); | ||
expect(diff[3].lhs).to.be('Phase2'); | ||
expect(diff[3].rhs).to.be('Phase1'); | ||
// It.phases[1].tasks[0].id changed from 'Task3' to 'Task1' | ||
// | ||
expect(diff[4].kind).to.be('E'); | ||
expect(diff[4].path).to.be.an('array'); | ||
expect(diff[4].path).to.have.length(5); | ||
expect(diff[4].path[0]).to.be('phases'); | ||
expect(diff[4].path[1]).to.be(1); | ||
expect(diff[4].path[2]).to.be('tasks'); | ||
expect(diff[4].path[3]).to.be(0); | ||
expect(diff[4].path[4]).to.be('id'); | ||
expect(diff[4].lhs).to.be('Task3'); | ||
expect(diff[4].rhs).to.be('Task1'); | ||
// It.phases[1].tasks[1] is new | ||
// | ||
expect(diff[5].kind).to.be('A'); | ||
expect(diff[5].path).to.be.an('array'); | ||
expect(diff[5].path).to.have.length(3); | ||
expect(diff[5].path[0]).to.be('phases'); | ||
expect(diff[5].path[1]).to.be(1); | ||
expect(diff[5].path[2]).to.be('tasks'); | ||
expect(diff[5].index).to.be(1); | ||
expect(diff[5].item.kind).to.be('N'); | ||
var applied = deep.applyDiff(lhs, rhs); |
@@ -1,11 +0,11 @@ | ||
var deep = require("../"); | ||
var deep = require('../'); | ||
var lhs = ["a","a"]; | ||
var rhs = ["a"]; | ||
var lhs = ['a', 'a']; | ||
var rhs = ['a']; | ||
var differences = deep.diff(lhs, rhs); | ||
differences.forEach(function (change) { | ||
deep.applyChange(lhs, true, change); | ||
deep.applyChange(lhs, true, change); | ||
}); | ||
console.log(lhs); | ||
console.log(rhs); | ||
console.log(lhs); // eslint-disable-line no-console | ||
console.log(rhs); // eslint-disable-line no-console |
@@ -1,34 +0,35 @@ | ||
'use strict'; | ||
var dd = require('../'); // deep-diff | ||
var dd = require('../'); // deep-diff | ||
var inspect = require('util').inspect; | ||
var expect = require('expect.js'); | ||
var before = { | ||
name: 'my object', | ||
description: 'it\'s an object!', | ||
details: { | ||
it: 'has', | ||
an: 'array', | ||
with: ['a', 'few', 'elements'] | ||
} | ||
name: 'my object', | ||
description: 'it\'s an object!', | ||
details: { | ||
it: 'has', | ||
an: 'array', | ||
with: ['a', 'few', 'elements'] | ||
} | ||
}; | ||
var after = { | ||
name: 'updated object', | ||
description: 'it\'s an object!', | ||
details: { | ||
it: 'has', | ||
an: 'array', | ||
with: ['a', 'few', 'more', 'elements', { than: 'before' }] | ||
} | ||
name: 'updated object', | ||
description: 'it\'s an object!', | ||
details: { | ||
it: 'has', | ||
an: 'array', | ||
with: ['a', 'few', 'more', 'elements', { than: 'before' }] | ||
} | ||
}; | ||
var revertDiff = function(src, d) { | ||
d.forEach(function (change) { | ||
dd.revertChange(src, true, change); | ||
}); | ||
return src; | ||
var revertDiff = function (src, d) { | ||
d.forEach(function (change) { | ||
dd.revertChange(src, true, change); | ||
}); | ||
return src; | ||
}; | ||
var clone = function(src) { | ||
return JSON.parse(JSON.stringify(src)); | ||
var clone = function (src) { | ||
return JSON.parse(JSON.stringify(src)); | ||
}; | ||
@@ -40,4 +41,9 @@ | ||
console.log(JSON.stringify(after)); | ||
console.log(JSON.stringify(revertDiff(after, df))); | ||
console.log(JSON.stringify(b1 )); | ||
console.log(inspect(a1, false, 9)); // eslint-disable-line no-console | ||
var reverted = revertDiff(a1, df); | ||
console.log(inspect(reverted, false, 9)); // eslint-disable-line no-console | ||
console.log(inspect(b1, false, 9)); // eslint-disable-line no-console | ||
expect(reverted).to.eql(b1); | ||
@@ -1,2 +0,2 @@ | ||
var deepDiff = require("../"); | ||
var deepDiff = require('../'); | ||
@@ -6,2 +6,2 @@ var left = {foo: undefined}; | ||
console.log(deepDiff.diff(left, right)); | ||
console.log(deepDiff.diff(left, right)); // eslint-disable-line no-console |
@@ -1,2 +0,2 @@ | ||
var deepDiff = require("../"); | ||
var diff = require('../'); | ||
@@ -15,2 +15,2 @@ var left = { | ||
console.log(deepDiff(left, right)); | ||
console.log(diff(left, right)); // eslint-disable-line no-console |
@@ -1,2 +0,2 @@ | ||
var diff = require("../"); | ||
var diff = require('../'); | ||
@@ -12,5 +12,4 @@ var before = { | ||
var differences = diff(before, after); | ||
console.log(differences); | ||
var reverted = differences.reduce( | ||
console.log(differences); // eslint-disable-line no-console | ||
differences.reduce( | ||
(acc, change) => { | ||
@@ -23,2 +22,2 @@ diff.revertChange(acc, true, change); | ||
console.log(after); | ||
console.log(after); // eslint-disable-line no-console |
116
index.js
@@ -14,2 +14,4 @@ (function (root, factory) { | ||
var validKinds = ['N', 'E', 'A', 'D']; | ||
// nodejs compatible on server side and in the browser. | ||
@@ -156,9 +158,8 @@ function inherits(ctor, superCtor) { | ||
function deepDiff(lhs, rhs, changes, prefilter, path, key, stack, orderIndependent) { | ||
changes = changes || []; | ||
path = path || []; | ||
stack = stack || []; | ||
var currentPath = path.slice(0); | ||
if (typeof key !== 'undefined') { | ||
if (typeof key !== 'undefined' && key !== null) { | ||
if (prefilter) { | ||
@@ -191,2 +192,3 @@ if (typeof (prefilter) === 'function' && prefilter(currentPath, key)) { | ||
var rtype = typeof rhs; | ||
var i, j, k, other; | ||
@@ -201,13 +203,17 @@ var ldefined = ltype !== 'undefined' || | ||
if (!ldefined && rdefined) { | ||
changes(new DiffNew(currentPath, rhs)); | ||
changes.push(new DiffNew(currentPath, rhs)); | ||
} else if (!rdefined && ldefined) { | ||
changes(new DiffDeleted(currentPath, lhs)); | ||
changes.push(new DiffDeleted(currentPath, lhs)); | ||
} else if (realTypeOf(lhs) !== realTypeOf(rhs)) { | ||
changes(new DiffEdit(currentPath, lhs, rhs)); | ||
changes.push(new DiffEdit(currentPath, lhs, rhs)); | ||
} else if (realTypeOf(lhs) === 'date' && (lhs - rhs) !== 0) { | ||
changes(new DiffEdit(currentPath, lhs, rhs)); | ||
changes.push(new DiffEdit(currentPath, lhs, rhs)); | ||
} else if (ltype === 'object' && lhs !== null && rhs !== null) { | ||
if (!stack.filter(function (x) { | ||
return x.lhs === lhs; | ||
}).length) { | ||
for (i = stack.length - 1; i > -1; --i) { | ||
if (stack[i].lhs === lhs) { | ||
other = true; | ||
break; | ||
} | ||
} | ||
if (!other) { | ||
stack.push({ lhs: lhs, rhs: rhs }); | ||
@@ -225,28 +231,32 @@ if (Array.isArray(lhs)) { | ||
} | ||
var i; | ||
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, orderIndependent); | ||
} | ||
i = rhs.length - 1; | ||
j = lhs.length - 1; | ||
while (i > j) { | ||
changes.push(new DiffArray(currentPath, i, new DiffNew(undefined, rhs[i--]))); | ||
} | ||
while (i < rhs.length) { | ||
changes(new DiffArray(currentPath, i, new DiffNew(undefined, rhs[i++]))); | ||
while (j > i) { | ||
changes.push(new DiffArray(currentPath, j, new DiffDeleted(undefined, lhs[j--]))); | ||
} | ||
for (; i >= 0; --i) { | ||
deepDiff(lhs[i], rhs[i], changes, prefilter, currentPath, i, stack, orderIndependent); | ||
} | ||
} else { | ||
var akeys = Object.keys(lhs); | ||
var pkeys = Object.keys(rhs); | ||
akeys.forEach(function (k) { | ||
var other = pkeys.indexOf(k); | ||
for (i = 0; i < akeys.length; ++i) { | ||
k = akeys[i]; | ||
other = pkeys.indexOf(k); | ||
if (other >= 0) { | ||
deepDiff(lhs[k], rhs[k], changes, prefilter, currentPath, k, stack, orderIndependent); | ||
pkeys = arrayRemove(pkeys, other); | ||
pkeys[other] = null; | ||
} else { | ||
deepDiff(lhs[k], undefined, changes, prefilter, currentPath, k, stack, orderIndependent); | ||
} | ||
}); | ||
pkeys.forEach(function (k) { | ||
deepDiff(undefined, rhs[k], changes, prefilter, currentPath, k, stack, orderIndependent); | ||
}); | ||
} | ||
for (i = 0; i < pkeys.length; ++i) { | ||
k = pkeys[i]; | ||
if (k) { | ||
deepDiff(undefined, rhs[k], changes, prefilter, currentPath, k, stack, orderIndependent); | ||
} | ||
} | ||
} | ||
@@ -256,7 +266,7 @@ stack.length = stack.length - 1; | ||
// lhs is contains a cycle at this element and it differs from rhs | ||
changes(new DiffEdit(currentPath, lhs, rhs)); | ||
changes.push(new DiffEdit(currentPath, lhs, rhs)); | ||
} | ||
} else if (lhs !== rhs) { | ||
if (!(ltype === 'number' && isNaN(lhs) && isNaN(rhs))) { | ||
changes(new DiffEdit(currentPath, lhs, rhs)); | ||
changes.push(new DiffEdit(currentPath, lhs, rhs)); | ||
} | ||
@@ -266,2 +276,13 @@ } | ||
function observableDiff(lhs, rhs, observer, prefilter, orderIndependent) { | ||
let changes = []; | ||
deepDiff(lhs, rhs, changes, prefilter, null, null, null, orderIndependent); | ||
if (observer) { | ||
for (var i = 0; i < changes.length; ++i) { | ||
observer(changes[i]); | ||
} | ||
} | ||
return changes; | ||
} | ||
function orderIndependentDeepDiff(lhs, rhs, changes, prefilter, path, key, stack) { | ||
@@ -272,23 +293,21 @@ return deepDiff(lhs, rhs, changes, prefilter, path, key, stack, true); | ||
function accumulateDiff(lhs, rhs, prefilter, accum) { | ||
accum = accum || []; | ||
deepDiff(lhs, rhs, | ||
function (diff) { | ||
if (diff) { | ||
accum.push(diff); | ||
var observer = (accum) ? | ||
function (difference) { | ||
if (difference) { | ||
accum.push(difference); | ||
} | ||
}, | ||
prefilter); | ||
return (accum.length) ? accum : undefined; | ||
} : undefined; | ||
var changes = observableDiff(lhs, rhs, observer, prefilter); | ||
return (accum) ? accum : (changes.length) ? changes : undefined; | ||
} | ||
function accumulateOrderIndependentDiff(lhs, rhs, prefilter, accum) { | ||
accum = accum || []; | ||
deepDiff(lhs, rhs, | ||
function (diff) { | ||
if (diff) { | ||
accum.push(diff); | ||
var observer = (accum) ? | ||
function (difference) { | ||
if (difference) { | ||
accum.push(difference); | ||
} | ||
}, | ||
prefilter, null, null, null, true); | ||
return (accum.length) ? accum : undefined; | ||
} : undefined; | ||
var changes = observableDiff(lhs, rhs, observer, prefilter, true); | ||
return (accum) ? accum : (changes.length) ? changes : undefined; | ||
} | ||
@@ -333,3 +352,6 @@ | ||
function applyChange(target, source, change) { | ||
if (target && source && change && change.kind) { | ||
if (typeof change === 'undefined' && source && ~validKinds.indexOf(source.kind)) { | ||
change = source; | ||
} | ||
if (target && change && change.kind) { | ||
var it = target, | ||
@@ -444,3 +466,3 @@ i = -1, | ||
}; | ||
deepDiff(target, source, onChange); | ||
observableDiff(target, source, onChange); | ||
} | ||
@@ -460,3 +482,3 @@ } | ||
observableDiff: { | ||
value: deepDiff, | ||
value: observableDiff, | ||
enumerable: true | ||
@@ -463,0 +485,0 @@ }, |
{ | ||
"name": "deep-diff", | ||
"description": "Javascript utility for calculating deep difference, capturing changes, and applying changes across objects; for nodejs and the browser.", | ||
"version": "1.0.0-pre.1", | ||
"version": "1.0.0-pre.2", | ||
"license": "MIT", | ||
@@ -66,2 +66,3 @@ "keywords": [ | ||
"json": "^9.0.6", | ||
"lodash": "^4.17.5", | ||
"mocha": "^5.0.1", | ||
@@ -68,0 +69,0 @@ "mocha-junit-reporter": "^1.17.0", |
@@ -9,2 +9,10 @@ # deep-diff | ||
> I'm actively working through the backlog of issues and will pubish v1.0.0 soon. I'd appreciate any feedback I can get... | ||
Currently `v1.0.0-pre.1` | ||
```bash | ||
npm install deep-diff@next | ||
``` | ||
## Features | ||
@@ -11,0 +19,0 @@ |
@@ -331,4 +331,2 @@ (function (root, factory) { | ||
expect(diff.length).to.be(3); | ||
expect(diff[0]).to.have.property('kind'); | ||
expect(diff[0].kind).to.be('E'); | ||
}); | ||
@@ -360,3 +358,3 @@ | ||
deep.applyChange(result, nestedTwo, diff[1]); | ||
deep.applyChange(result, nestedTwo, diff[2]); | ||
expect(result.arrayOne).to.be.ok(); | ||
@@ -372,3 +370,3 @@ expect(result.arrayOne).to.be.an('array'); | ||
deep.applyChange(result, nestedTwo, diff[2]); | ||
deep.applyChange(result, nestedTwo, diff[1]); | ||
expect(result.arrayOne).to.be.ok(); | ||
@@ -425,72 +423,2 @@ expect(result.arrayOne).to.be.an('array'); | ||
// It.phases[0].id changed from 'Phase1' to 'Phase2' | ||
// | ||
expect(diff[0].kind).to.be('E'); | ||
expect(diff[0].path).to.be.an('array'); | ||
expect(diff[0].path).to.have.length(3); | ||
expect(diff[0].path[0]).to.be('phases'); | ||
expect(diff[0].path[1]).to.be(0); | ||
expect(diff[0].path[2]).to.be('id'); | ||
expect(diff[0].lhs).to.be('Phase1'); | ||
expect(diff[0].rhs).to.be('Phase2'); | ||
// It.phases[0].tasks[0].id changed from 'Task1' to 'Task3' | ||
// | ||
expect(diff[1].kind).to.be('E'); | ||
expect(diff[1].path).to.be.an('array'); | ||
expect(diff[1].path).to.have.length(5); | ||
expect(diff[1].path[0]).to.be('phases'); | ||
expect(diff[1].path[1]).to.be(0); | ||
expect(diff[1].path[2]).to.be('tasks'); | ||
expect(diff[1].path[3]).to.be(0); | ||
expect(diff[1].path[4]).to.be('id'); | ||
expect(diff[1].lhs).to.be('Task1'); | ||
expect(diff[1].rhs).to.be('Task3'); | ||
// It.phases[0].tasks[1] was deleted | ||
// | ||
expect(diff[2].kind).to.be('A'); | ||
expect(diff[2].path).to.be.an('array'); | ||
expect(diff[2].path).to.have.length(3); | ||
expect(diff[2].path[0]).to.be('phases'); | ||
expect(diff[2].path[1]).to.be(0); | ||
expect(diff[2].path[2]).to.be('tasks'); | ||
expect(diff[2].index).to.be(1); | ||
expect(diff[2].item.kind).to.be('D'); | ||
// It.phases[1].id changed from 'Phase2' to 'Phase1' | ||
// | ||
expect(diff[3].kind).to.be('E'); | ||
expect(diff[3].path).to.be.an('array'); | ||
expect(diff[3].path).to.have.length(3); | ||
expect(diff[3].path[0]).to.be('phases'); | ||
expect(diff[3].path[1]).to.be(1); | ||
expect(diff[3].path[2]).to.be('id'); | ||
expect(diff[3].lhs).to.be('Phase2'); | ||
expect(diff[3].rhs).to.be('Phase1'); | ||
// It.phases[1].tasks[0].id changed from 'Task3' to 'Task1' | ||
// | ||
expect(diff[4].kind).to.be('E'); | ||
expect(diff[4].path).to.be.an('array'); | ||
expect(diff[4].path).to.have.length(5); | ||
expect(diff[4].path[0]).to.be('phases'); | ||
expect(diff[4].path[1]).to.be(1); | ||
expect(diff[4].path[2]).to.be('tasks'); | ||
expect(diff[4].path[3]).to.be(0); | ||
expect(diff[4].path[4]).to.be('id'); | ||
expect(diff[4].lhs).to.be('Task3'); | ||
expect(diff[4].rhs).to.be('Task1'); | ||
// It.phases[1].tasks[1] is new | ||
// | ||
expect(diff[5].kind).to.be('A'); | ||
expect(diff[5].path).to.be.an('array'); | ||
expect(diff[5].path).to.have.length(3); | ||
expect(diff[5].path[0]).to.be('phases'); | ||
expect(diff[5].path[1]).to.be(1); | ||
expect(diff[5].path[2]).to.be('tasks'); | ||
expect(diff[5].index).to.be(1); | ||
expect(diff[5].item.kind).to.be('N'); | ||
it('differences can be applied', function () { | ||
@@ -515,8 +443,5 @@ var applied = deep.applyDiff(lhs, rhs); | ||
/* We must apply the differences in reverse order, since the array indices | ||
in the diff become stale/invalid if you delete elements from the array | ||
whose indices are in ascending order */ | ||
for (var i = differences.length - 1; i >= 0; i--) { | ||
deep.applyChange(lhs, true, differences[i]); | ||
} | ||
differences.forEach(function (it) { | ||
deep.applyChange(lhs, true, it); | ||
}); | ||
@@ -523,0 +448,0 @@ expect(lhs).to.eql(['a']); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
35
243
0
536898
12
4114