simple-diff
Advanced tools
Comparing version 1.2.0 to 1.3.0
{ | ||
"name": "backbone-dom-view", | ||
"main": "backbone-dom-view.js", | ||
"version": "1.2.0", | ||
"name": "simple-diff", | ||
"main": "simple-diff.js", | ||
"version": "1.3.0", | ||
"homepage": "https://github.com/redexp/simple-diff", | ||
@@ -6,0 +6,0 @@ "authors": [ |
{ | ||
"name": "simple-diff", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "simple diff for object and arrays with options", | ||
@@ -5,0 +5,0 @@ "main": "simple-diff.js", |
simple-diff | ||
=========== | ||
Lib for simple diff with moved items in array detection | ||
Lib for simple diff with detection of moved items in array | ||
@@ -131,11 +131,37 @@ [![Build Status](https://travis-ci.org/redexp/simple-diff.svg?branch=master)](https://travis-ci.org/redexp/simple-diff) | ||
* `idProp` - id property for all arrays items. Default value: `id` | ||
* `idProps` - hash where key is path to array and value is id property. Path examples: `users.list`, `user.list.1.friends`, `users.list.*.friends` | ||
* `callback` - function which will be called for each event. Useful for memory management because in this case diff will not create array of all events. | ||
* `addEvent` - name of event when new property added to object. Default value: `add` | ||
* `changeEvent` - name of event when property value changed. Default value: `change` | ||
* `removeEvent` - name of event when property removed from object. Default value: `remove` | ||
* `addItemEvent` - name of event when new item added to array. Default value: `add-item` | ||
* `removeItemEvent` - name of event when item removed from array. Default value: `remove-item` | ||
* `moveItemEvent` - name of event when item changed it index in array. Default value: `move-item` | ||
## `idProp: 'id' || '*'` | ||
Property name with unique value in it array. Default value is `id`. If your arrays do not have unique properties then you should set this option as `*` and lib will compare items one by one without trying to find moved items. | ||
## `idProps: {'path': 'propName' || '*'}` | ||
Hash where key is path to array and value is id property. Path examples: `users.list`, `user.list.1.friends`, `users.list.*.friends` | ||
## `callback: function (event)` | ||
Function which will be called for each event. If callback is passed then lib will not create array of all changes. | ||
## `addEvent: 'add'` | ||
Name of event when new property added to object. Default value is `add` | ||
## `changeEvent: 'change'` | ||
Name of event when property value changed. Default value is `change` | ||
## `removeEvent: 'remove'` | ||
Name of event when property removed from object. Default value is `remove` | ||
## `addItemEvent: 'add-item'` | ||
Name of event when new item added to array. Default value is `add-item` | ||
## `removeItemEvent: 'remove-item'` | ||
Name of event when item removed from array. Default value is `remove-item` | ||
## `moveItemEvent: 'move-item'` | ||
Name of event when item changed it index in array. Default value is `move-item` | ||
@@ -54,2 +54,47 @@ (function (root, factory) { | ||
var idProp = | ||
(ops.idProps && | ||
( | ||
ops.idProps[oldPath.map(numberToAsterisk).join('.')] || | ||
ops.idProps[oldPath.join('.')] | ||
)) || ID_PROP; | ||
if (idProp === '*') { | ||
var oldLength = oldObj.length, | ||
newLength = newObj.length; | ||
for (i = 0, len = oldLength > newLength ? oldLength : newLength; i < len; i++) { | ||
if (i < oldLength && i < newLength) { | ||
diff(oldObj[i], newObj[i], extend({}, ops, { | ||
callback: callback, | ||
oldPath: oldPath.concat(i), | ||
newPath: newPath.concat(i) | ||
})); | ||
} | ||
else if (i >= oldLength) { | ||
callback({ | ||
oldPath: oldPath, | ||
newPath: newPath, | ||
type: ADD_ITEM_EVENT, | ||
oldIndex: -1, | ||
curIndex: -1, | ||
newIndex: i, | ||
newValue: newObj[i] | ||
}); | ||
} | ||
else if (i >= newLength) { | ||
callback({ | ||
oldPath: oldPath, | ||
newPath: newPath, | ||
type: REMOVE_ITEM_EVENT, | ||
oldIndex: i, | ||
curIndex: newLength, | ||
newIndex: -1 | ||
}); | ||
} | ||
} | ||
return changes; | ||
} | ||
var sample = oldObj.length > 0 ? oldObj[0] : newObj[0]; | ||
@@ -61,9 +106,3 @@ | ||
var idProp = | ||
(objective && ops.idProps && | ||
( | ||
ops.idProps[oldPath.map(numberToAsterisk).join('.')] || | ||
ops.idProps[oldPath.join('.')] | ||
)) || ID_PROP, | ||
oldHash = objective ? indexBy(oldObj, idProp) : hashOf(oldObj), | ||
var oldHash = objective ? indexBy(oldObj, idProp) : hashOf(oldObj), | ||
newHash = objective ? indexBy(newObj, idProp) : hashOf(newObj), | ||
@@ -70,0 +109,0 @@ curArray = [].concat(oldObj), |
@@ -1,1 +0,1 @@ | ||
!function(root,factory){"function"==typeof define&&define.amd?define([],factory):"object"==typeof exports?module.exports=factory():root.simpleDiff=factory()}(this,function(){function diff(oldObj,newObj,ops){ops=ops||{};var i,len,prop,id,changes=[],oldPath=ops.oldPath||[],newPath=ops.newPath||[],ID_PROP=ops.idProp||"id",ADD_EVENT=ops.addEvent||"add",REMOVE_EVENT=ops.removeEvent||"remove",CHANGE_EVENT=ops.changeEvent||"change",ADD_ITEM_EVENT=ops.addItemEvent||"add-item",REMOVE_ITEM_EVENT=ops.removeItemEvent||"remove-item",MOVE_ITEM_EVENT=ops.moveItemEvent||"move-item",callback=ops.callback||function(item){changes.push(item)};if(!(isObject(oldObj)&&isObject(newObj)||oldObj===newObj))return callback({oldPath:oldPath,newPath:newPath,type:CHANGE_EVENT,oldValue:oldObj,newValue:newObj}),changes;if(isArray(oldObj)){var sample=oldObj.length>0?oldObj[0]:newObj[0];if(sample===UNDEFINED)return changes;var curIndex,oldIndex,objective="object"==typeof sample,idProp=objective&&ops.idProps&&(ops.idProps[oldPath.map(numberToAsterisk).join(".")]||ops.idProps[oldPath.join(".")])||ID_PROP,oldHash=objective?indexBy(oldObj,idProp):hashOf(oldObj),newHash=objective?indexBy(newObj,idProp):hashOf(newObj),curArray=[].concat(oldObj);for(i=0,len=oldObj.length;i<len;i++)id=objective?oldObj[i][idProp]:oldObj[i],newHash.hasOwnProperty(id)||(curIndex=curArray.indexOf(oldObj[i]),curArray.splice(curIndex,1),callback({oldPath:oldPath,newPath:newPath,type:REMOVE_ITEM_EVENT,oldIndex:i,curIndex:curIndex,newIndex:-1}));for(i=0,len=newObj.length;i<len;i++)id=objective?newObj[i][idProp]:newObj[i],oldHash.hasOwnProperty(id)||(callback({oldPath:oldPath,newPath:newPath,type:ADD_ITEM_EVENT,oldIndex:-1,curIndex:-1,newIndex:i,newValue:newObj[i]}),i>=curArray.length?curArray.push(newObj[i]):curArray.splice(i,0,newObj[i]));for(i=0,len=newObj.length;i<len;i++)id=objective?newObj[i][idProp]:newObj[i],oldHash.hasOwnProperty(id)&&(oldIndex=oldObj.indexOf(oldHash[id]),curIndex=curArray.indexOf(oldHash[id]),i!==curIndex&&(callback({oldPath:oldPath,newPath:newPath,type:MOVE_ITEM_EVENT,oldIndex:oldIndex,curIndex:curIndex,newIndex:i}),curArray.splice(curIndex,1),curArray.splice(i,0,oldHash[id])),diff(oldHash[id],newObj[i],extend({},ops,{callback:callback,oldPath:oldPath.concat(oldIndex),newPath:newPath.concat(i)})))}else{for(prop in oldObj)oldObj.hasOwnProperty(prop)&&(newObj.hasOwnProperty(prop)?isObject(oldObj[prop])&&isObject(newObj[prop])?diff(oldObj[prop],newObj[prop],extend({},ops,{callback:callback,oldPath:oldPath.concat(prop),newPath:newPath.concat(prop)})):oldObj[prop]!==newObj[prop]&&callback({oldPath:oldPath.concat(prop),newPath:newPath.concat(prop),type:CHANGE_EVENT,oldValue:oldObj[prop],newValue:newObj[prop]}):callback({oldPath:oldPath.concat(prop),newPath:newPath.concat(prop),type:REMOVE_EVENT,oldValue:oldObj[prop],newValue:UNDEFINED}));for(prop in newObj)newObj.hasOwnProperty(prop)&&(oldObj.hasOwnProperty(prop)||callback({oldPath:oldPath.concat(prop),newPath:newPath.concat(prop),type:ADD_EVENT,oldValue:UNDEFINED,newValue:newObj[prop]}))}return changes}function isObject(object){return!!object&&"object"==typeof object}function isArray(array){return Array.isArray?Array.isArray(array):"[object Array]"===Object.prototype.toString.call(array)}function indexBy(array,id){for(var hash={},i=0,len=array.length;i<len;i++)hash[array[i][id]]=array[i];return hash}function hashOf(array){for(var hash={},i=0,len=array.length;i<len;i++)hash[array[i]]=array[i];return hash}function extend(target){for(var i=1,len=arguments.length;i<len;i++){var source=arguments[i];for(var prop in source)source.hasOwnProperty(prop)&&(target[prop]=source[prop])}return target}function numberToAsterisk(value){return"number"==typeof value?"*":value}var UNDEFINED;return diff}); | ||
!function(root,factory){"function"==typeof define&&define.amd?define([],factory):"object"==typeof exports?module.exports=factory():root.simpleDiff=factory()}(this,function(){function diff(oldObj,newObj,ops){ops=ops||{};var i,len,prop,id,changes=[],oldPath=ops.oldPath||[],newPath=ops.newPath||[],ID_PROP=ops.idProp||"id",ADD_EVENT=ops.addEvent||"add",REMOVE_EVENT=ops.removeEvent||"remove",CHANGE_EVENT=ops.changeEvent||"change",ADD_ITEM_EVENT=ops.addItemEvent||"add-item",REMOVE_ITEM_EVENT=ops.removeItemEvent||"remove-item",MOVE_ITEM_EVENT=ops.moveItemEvent||"move-item",callback=ops.callback||function(item){changes.push(item)};if(!(isObject(oldObj)&&isObject(newObj)||oldObj===newObj))return callback({oldPath:oldPath,newPath:newPath,type:CHANGE_EVENT,oldValue:oldObj,newValue:newObj}),changes;if(isArray(oldObj)){var idProp=ops.idProps&&(ops.idProps[oldPath.map(numberToAsterisk).join(".")]||ops.idProps[oldPath.join(".")])||ID_PROP;if("*"===idProp){var oldLength=oldObj.length,newLength=newObj.length;for(i=0,len=oldLength>newLength?oldLength:newLength;i<len;i++)i<oldLength&&i<newLength?diff(oldObj[i],newObj[i],extend({},ops,{callback:callback,oldPath:oldPath.concat(i),newPath:newPath.concat(i)})):i>=oldLength?callback({oldPath:oldPath,newPath:newPath,type:ADD_ITEM_EVENT,oldIndex:-1,curIndex:-1,newIndex:i,newValue:newObj[i]}):i>=newLength&&callback({oldPath:oldPath,newPath:newPath,type:REMOVE_ITEM_EVENT,oldIndex:i,curIndex:newLength,newIndex:-1});return changes}var sample=oldObj.length>0?oldObj[0]:newObj[0];if(sample===UNDEFINED)return changes;var curIndex,oldIndex,objective="object"==typeof sample,oldHash=objective?indexBy(oldObj,idProp):hashOf(oldObj),newHash=objective?indexBy(newObj,idProp):hashOf(newObj),curArray=[].concat(oldObj);for(i=0,len=oldObj.length;i<len;i++)id=objective?oldObj[i][idProp]:oldObj[i],newHash.hasOwnProperty(id)||(curIndex=curArray.indexOf(oldObj[i]),curArray.splice(curIndex,1),callback({oldPath:oldPath,newPath:newPath,type:REMOVE_ITEM_EVENT,oldIndex:i,curIndex:curIndex,newIndex:-1}));for(i=0,len=newObj.length;i<len;i++)id=objective?newObj[i][idProp]:newObj[i],oldHash.hasOwnProperty(id)||(callback({oldPath:oldPath,newPath:newPath,type:ADD_ITEM_EVENT,oldIndex:-1,curIndex:-1,newIndex:i,newValue:newObj[i]}),i>=curArray.length?curArray.push(newObj[i]):curArray.splice(i,0,newObj[i]));for(i=0,len=newObj.length;i<len;i++)id=objective?newObj[i][idProp]:newObj[i],oldHash.hasOwnProperty(id)&&(oldIndex=oldObj.indexOf(oldHash[id]),curIndex=curArray.indexOf(oldHash[id]),i!==curIndex&&(callback({oldPath:oldPath,newPath:newPath,type:MOVE_ITEM_EVENT,oldIndex:oldIndex,curIndex:curIndex,newIndex:i}),curArray.splice(curIndex,1),curArray.splice(i,0,oldHash[id])),diff(oldHash[id],newObj[i],extend({},ops,{callback:callback,oldPath:oldPath.concat(oldIndex),newPath:newPath.concat(i)})))}else{for(prop in oldObj)oldObj.hasOwnProperty(prop)&&(newObj.hasOwnProperty(prop)?isObject(oldObj[prop])&&isObject(newObj[prop])?diff(oldObj[prop],newObj[prop],extend({},ops,{callback:callback,oldPath:oldPath.concat(prop),newPath:newPath.concat(prop)})):oldObj[prop]!==newObj[prop]&&callback({oldPath:oldPath.concat(prop),newPath:newPath.concat(prop),type:CHANGE_EVENT,oldValue:oldObj[prop],newValue:newObj[prop]}):callback({oldPath:oldPath.concat(prop),newPath:newPath.concat(prop),type:REMOVE_EVENT,oldValue:oldObj[prop],newValue:UNDEFINED}));for(prop in newObj)newObj.hasOwnProperty(prop)&&(oldObj.hasOwnProperty(prop)||callback({oldPath:oldPath.concat(prop),newPath:newPath.concat(prop),type:ADD_EVENT,oldValue:UNDEFINED,newValue:newObj[prop]}))}return changes}function isObject(object){return!!object&&"object"==typeof object}function isArray(array){return Array.isArray?Array.isArray(array):"[object Array]"===Object.prototype.toString.call(array)}function indexBy(array,id){for(var hash={},i=0,len=array.length;i<len;i++)hash[array[i][id]]=array[i];return hash}function hashOf(array){for(var hash={},i=0,len=array.length;i<len;i++)hash[array[i]]=array[i];return hash}function extend(target){for(var i=1,len=arguments.length;i<len;i++){var source=arguments[i];for(var prop in source)source.hasOwnProperty(prop)&&(target[prop]=source[prop])}return target}function numberToAsterisk(value){return"number"==typeof value?"*":value}var UNDEFINED;return diff}); |
@@ -455,2 +455,90 @@ var expect = require('chai').expect, | ||
}); | ||
it('should handle idProp: * to compare arrays as is', function () { | ||
var changes = diff( | ||
[ | ||
{a: 1}, | ||
{a: 2} | ||
], | ||
[ | ||
{a: 1}, | ||
{a: 2} | ||
], | ||
{idProp: '*'} | ||
); | ||
expect(changes.length).to.equal(0); | ||
changes = diff( | ||
[ | ||
{a: 1}, | ||
{a: 2} | ||
], | ||
[ | ||
{a: 2}, | ||
{a: 1}, | ||
{a: 3} | ||
], | ||
{idProp: '*'} | ||
); | ||
expect(changes).to.deep.equal([ | ||
{ | ||
oldPath: [0, 'a'], | ||
newPath: [0, 'a'], | ||
type: 'change', | ||
oldValue: 1, | ||
newValue: 2 | ||
}, | ||
{ | ||
oldPath: [1, 'a'], | ||
newPath: [1, 'a'], | ||
type: 'change', | ||
oldValue: 2, | ||
newValue: 1 | ||
}, | ||
{ | ||
oldPath: [], | ||
newPath: [], | ||
type: 'add-item', | ||
oldIndex: -1, | ||
curIndex: -1, | ||
newIndex: 2, | ||
newValue: {a: 3} | ||
} | ||
]); | ||
changes = diff( | ||
[ | ||
{a: 1}, | ||
{a: 2}, | ||
{a: 3}, | ||
{a: 4} | ||
], | ||
[ | ||
{a: 1}, | ||
{a: 2} | ||
], | ||
{idProp: '*'} | ||
); | ||
expect(changes).to.deep.equal([ | ||
{ | ||
oldPath: [], | ||
newPath: [], | ||
type: 'remove-item', | ||
oldIndex: 2, | ||
curIndex: 2, | ||
newIndex: -1 | ||
}, | ||
{ | ||
oldPath: [], | ||
newPath: [], | ||
type: 'remove-item', | ||
oldIndex: 3, | ||
curIndex: 2, | ||
newIndex: -1 | ||
} | ||
]); | ||
}); | ||
}); |
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
33530
794
167