Comparing version
140
index.js
@@ -1,7 +0,7 @@ | ||
module.exports = diff; | ||
module.exports = { | ||
diff: diff, | ||
jsonPatchPathConverter: jsonPatchPathConverter | ||
}; | ||
/* | ||
Diffs represented as objects (not JSON) in JSON Patch format | ||
See http://jsonpatch.com | ||
const obj1 = {a: 4, b: 5}; | ||
@@ -13,18 +13,28 @@ const obj2 = {a: 3, b: 5}; | ||
[ | ||
{ "op": "replace", "path": "/a", "value": 3 } | ||
{ "op": "replace", "path": ['a'], "value": 3 } | ||
] | ||
diff(obj1, obj3); | ||
diff(obj2, obj3); | ||
[ | ||
{ "op": "remove", "path": "/b" }, | ||
{ "op": "add", "path": "/c", "value": 5 } | ||
{ "op": "remove", "path": ['b'] }, | ||
{ "op": "replace", "path": ['a'], "value": 4 } | ||
{ "op": "add", "path": ['c'], "value": 5 } | ||
] | ||
diff(obj2, obj3); | ||
// using converter to generate jsPatch standard paths | ||
// see http://jsonpatch.com | ||
import {diff, jsonPatchPathConverter} from 'just-diff' | ||
diff(obj1, obj2, jsonPatchPathConverter); | ||
[ | ||
{ "op": "remove", "path": "/b" }, | ||
{ "op": "replace", "path": "/a", "value": 4 } | ||
{ "op": "add", "path": "/c", "value": 5 } | ||
{ "op": "replace", "path": '/a', "value": 3 } | ||
] | ||
diff(obj2, obj3, jsonPatchPathConverter); | ||
[ | ||
{ "op": "remove", "path": '/b' }, | ||
{ "op": "replace", "path": '/a', "value": 4 } | ||
{ "op": "add", "path": '/c', "value": 5 } | ||
] | ||
// arrays | ||
const obj4 = {a: 4, b: [1, 2, 3]}; | ||
@@ -36,4 +46,4 @@ const obj5 = {a: 3, b: [1, 2, 4]}; | ||
[ | ||
{ "op": "replace", "path": "/a", "value": 3 } | ||
{ "op": "replace", "path": "/b/2", "value": 4 } | ||
{ "op": "replace", "path": ['a'], "value": 3 } | ||
{ "op": "replace", "path": ['b', '2'], "value": 4 } | ||
] | ||
@@ -43,5 +53,6 @@ | ||
[ | ||
{ "op": "add", "path": "/b/3", "value": 5 } | ||
{ "op": "add", "path": ['b', '3'], "value": 5 } | ||
] | ||
// nested paths | ||
const obj7 = {a: 4, b: {c: 3}}; | ||
@@ -53,3 +64,3 @@ const obj8 = {a: 4, b: {c: 4}}; | ||
[ | ||
{ "op": "replace", "path": "/b/c", "value": 4 } | ||
{ "op": "replace", "path": ['b', 'c'], "value": 4 } | ||
] | ||
@@ -59,22 +70,9 @@ | ||
[ | ||
{ "op": "replace", "path": "/a", "value": 5 } | ||
{ "op": "remove", "path": "/b/c" } | ||
{ "op": "add", "path": "/b/d", "value": 4 } | ||
{ "op": "replace", "path": ['a'], "value": 5 } | ||
{ "op": "remove", "path": ['b', 'c']} | ||
{ "op": "add", "path": ['b', 'd'], "value": 4 } | ||
] | ||
const obj10 = {a: 4}; | ||
const obj11 = {a: 4, b: {c: 4}}; | ||
diff(obj10, obj11); | ||
[ | ||
{ "op": "add", "path": "/b", "value": {c: 4} } | ||
] | ||
diff(obj11, obj10); | ||
[ | ||
{ "op": "remove", "path": "/b" } | ||
] | ||
*/ | ||
function diff(obj1, obj2, path, diffs) { | ||
function diff(obj1, obj2, pathConverter) { | ||
if (!obj1 || typeof obj1 != 'object' || !obj2 || typeof obj2 != 'object') { | ||
@@ -84,44 +82,52 @@ throw new Error('both arguments must be objects or arrays'); | ||
!path && (path = ''); | ||
!diffs && (diffs = {remove: [], replace: [], add: []}); | ||
var obj1Keys = Object.keys(obj1); | ||
var obj1KeysLength = obj1Keys.length; | ||
var obj2Keys = Object.keys(obj2); | ||
var obj2KeysLength = obj2Keys.length; | ||
function getDiff(obj1, obj2, basePath, diffs) { | ||
var obj1Keys = Object.keys(obj1); | ||
var obj1KeysLength = obj1Keys.length; | ||
var obj2Keys = Object.keys(obj2); | ||
var obj2KeysLength = obj2Keys.length; | ||
var path; | ||
for (var i = 0; i < obj1KeysLength; i++) { | ||
var key = obj1Keys[i]; | ||
var removePath = path + '/' + key; | ||
if (!obj2[key]) { | ||
diffs.remove.push({ | ||
op: 'remove', | ||
path: removePath | ||
}); | ||
for (var i = 0; i < obj1KeysLength; i++) { | ||
var key = obj1Keys[i]; | ||
if (!obj2[key]) { | ||
path = basePath.concat(key); | ||
diffs.remove.push({ | ||
op: 'remove', | ||
path: pathConverter ? pathConverter(path) : path | ||
}); | ||
} | ||
} | ||
} | ||
for (var i = 0; i < obj2KeysLength; i++) { | ||
var key = obj2Keys[i]; | ||
var updatePath = path + '/' + key; | ||
if (!obj1[key]) { | ||
var obj2Value = obj2[key]; | ||
diffs.add.push({ | ||
op: 'add', | ||
path: updatePath, | ||
value: obj2Value | ||
}); | ||
} else if (obj1[key] != obj2[key]) { | ||
if (Object(obj2[key]) !== obj2[key]) { | ||
diffs.replace.push({ | ||
op: 'replace', | ||
path: updatePath, | ||
value: obj2[key] | ||
for (var i = 0; i < obj2KeysLength; i++) { | ||
var key = obj2Keys[i]; | ||
if (!obj1[key]) { | ||
path = basePath.concat(key); | ||
var obj2Value = obj2[key]; | ||
diffs.add.push({ | ||
op: 'add', | ||
path: pathConverter ? pathConverter(path) : path, | ||
value: obj2Value | ||
}); | ||
} else { | ||
diff(obj1[key], obj2[key], updatePath, diffs); | ||
} else if (obj1[key] != obj2[key]) { | ||
if (Object(obj2[key]) !== obj2[key]) { | ||
path = basePath.concat(key); | ||
diffs.replace.push({ | ||
op: 'replace', | ||
path: pathConverter ? pathConverter(path) : path, | ||
value: obj2[key] | ||
}); | ||
} else { | ||
getDiff(obj1[key], obj2[key], basePath.concat(key), diffs); | ||
} | ||
} | ||
} | ||
return diffs.remove.concat(diffs.replace).concat(diffs.add); | ||
} | ||
return diffs.remove.concat(diffs.replace).concat(diffs.add); | ||
return getDiff(obj1, obj2, [], {remove: [], replace: [], add: []}); | ||
} | ||
function jsonPatchPathConverter(arrayPath) { | ||
return [''].concat(arrayPath).join('/'); | ||
} |
{ | ||
"name": "just-diff", | ||
"version": "1.0.0", | ||
"description": "return a JSON patch formatted object representing the diffs between two objects", | ||
"version": "2.0.0", | ||
"description": "Return an object representing the diffs between two objects. Supports jsonPatch protocol", | ||
"main": "index.js", | ||
@@ -13,2 +13,3 @@ "scripts": { | ||
"diff", | ||
"jsonPatch", | ||
"no-dependencies", | ||
@@ -15,0 +16,0 @@ "just" |
@@ -12,3 +12,3 @@ ## just-diff | ||
```js | ||
import diff from 'just-diff'; | ||
import {diff} from 'just-diff'; | ||
@@ -21,18 +21,28 @@ const obj1 = {a: 4, b: 5}; | ||
[ | ||
{ "op": "replace", "path": "/a", "value": 3 } | ||
{ "op": "replace", "path": ['a'], "value": 3 } | ||
] | ||
diff(obj1, obj3); | ||
diff(obj2, obj3); | ||
[ | ||
{ "op": "remove", "path": "/b" }, | ||
{ "op": "add", "path": "/c", "value": 5 } | ||
{ "op": "remove", "path": ['b'] }, | ||
{ "op": "replace", "path": ['a'], "value": 4 } | ||
{ "op": "add", "path": ['c'], "value": 5 } | ||
] | ||
diff(obj2, obj3); | ||
// using converter to generate jsPatch standard paths | ||
// see http://jsonpatch.com | ||
import {diff, jsonPatchPathConverter} from 'just-diff' | ||
diff(obj1, obj2, jsonPatchPathConverter); | ||
[ | ||
{ "op": "remove", "path": "/b" }, | ||
{ "op": "replace", "path": "/a", "value": 4 } | ||
{ "op": "add", "path": "/c", "value": 5 } | ||
{ "op": "replace", "path": '/a', "value": 3 } | ||
] | ||
diff(obj2, obj3, jsonPatchPathConverter); | ||
[ | ||
{ "op": "remove", "path": '/b' }, | ||
{ "op": "replace", "path": '/a', "value": 4 } | ||
{ "op": "add", "path": '/c', "value": 5 } | ||
] | ||
// arrays | ||
const obj4 = {a: 4, b: [1, 2, 3]}; | ||
@@ -44,4 +54,4 @@ const obj5 = {a: 3, b: [1, 2, 4]}; | ||
[ | ||
{ "op": "replace", "path": "/a", "value": 3 } | ||
{ "op": "replace", "path": "/b/2", "value": 4 } | ||
{ "op": "replace", "path": ['a'], "value": 3 } | ||
{ "op": "replace", "path": ['b', '2'], "value": 4 } | ||
] | ||
@@ -51,5 +61,6 @@ | ||
[ | ||
{ "op": "add", "path": "/b/3", "value": 5 } | ||
{ "op": "add", "path": ['b', '3'], "value": 5 } | ||
] | ||
// nested paths | ||
const obj7 = {a: 4, b: {c: 3}}; | ||
@@ -61,3 +72,3 @@ const obj8 = {a: 4, b: {c: 4}}; | ||
[ | ||
{ "op": "replace", "path": "/b/c", "value": 4 } | ||
{ "op": "replace", "path": ['b', 'c'], "value": 4 } | ||
] | ||
@@ -67,19 +78,6 @@ | ||
[ | ||
{ "op": "remove", "path": "/b/c" } | ||
{ "op": "replace", "path": "/a", "value": 5 } | ||
{ "op": "add", "path": "/b/d", "value": 4 } | ||
{ "op": "replace", "path": ['a'], "value": 5 } | ||
{ "op": "remove", "path": ['b', 'c']} | ||
{ "op": "add", "path": ['b', 'd'], "value": 4 } | ||
] | ||
const obj10 = {a: 4}; | ||
const obj11 = {a: 4, b: {c: 4}}; | ||
diff(obj10, obj11); | ||
[ | ||
{ "op": "add", "path": "/b", "value": {c: 4} } | ||
] | ||
diff(obj11, obj10); | ||
[ | ||
{ "op": "remove", "path": "/b" } | ||
] | ||
``` |
5466
14.47%109
6.86%78
-2.5%