Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow identity option for diff #174 #175

Merged
merged 4 commits into from
Jan 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions js/diff/diff-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,19 @@ QUnit.test("basics", function(){
insert: []
}]);

// identity:
patches = diff([{id:1},{id:2}], [{id:1},{id:1.5},{id:3}], function(a,b){ return a.id === b.id; });
deepEqual(patches, [{
index: 1,
deleteCount: 1,
insert: [{id:1.5},{id:3}]
}], 'identity works');

// identity for a single middle insertion:
patches = diff([{id:1},{id:2}], [{id:1},{id:3},{id:2}], function(a,b){ return a.id === b.id; });
deepEqual(patches, [{
index: 1,
deleteCount: 0,
insert: [{id:3}]
}], 'identity for a single middle insertion');
});
31 changes: 26 additions & 5 deletions js/diff/diff.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ var slice = [].slice;
// a b c
// a b c d
// [[2,0, d]]

var defaultIdentity = function(a, b){ return a === b; };

/**
* @module {function} can-util/js/diff/diff diff
* @parent can-util/js
* @signature `diff(oldList, newList)`
* @signature `diff( oldList, newList, [identity] )`
*
* @param {ArrayLike} oldList the array to diff from
* @param {ArrayLike} newList the array to diff to
* @param {function} identity an optional identity function for comparing elements
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@typdef {function(*,*)} can-util/diff/diff/typedefs.identity identify(a, b)

@param {*} a This is something.
@param  {can-util/diff/diff/typedefs.identity} identity(a, b)
  @option {*} a

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a TODO for now.

* @return {Array} a list of Patch objects representing the differences
*
* Returns the difference between two ArrayLike objects (that have nonnegative
Expand All @@ -24,9 +28,26 @@ var slice = [].slice;
*
* console.log(diff([1], [1, 2])); // -> [{index: 1, deleteCount: 0, insert: [2]}]
* console.log(diff([1, 2], [1])); // -> [{index: 1, deleteCount: 1, insert: []}]
*
* // with an optional identity function:
* diff(
* [{id:1},{id:2}],
* [{id:1},{id:3}],
* (a,b) => a.id === b.id
* ); // -> [{index: 1, deleteCount: 1, insert: [{id:3}]}]
* ```
*/
module.exports = exports = function(oldList, newList){

// TODO: update for a better type reference. E.g.:
// @typdef {function(*,*)} can-util/diff/diff/typedefs.identity identify(a, b)
//
// @param {*} a This is something.
// @param {can-util/diff/diff/typedefs.identity} identity(a, b)
// @option {*} a

module.exports = exports = function(oldList, newList, identity){
identity = identity || defaultIdentity;

var oldIndex = 0,
newIndex = 0,
oldLength = oldList.length,
Expand All @@ -37,15 +58,15 @@ module.exports = exports = function(oldList, newList){
var oldItem = oldList[oldIndex],
newItem = newList[newIndex];

if( oldItem === newItem ) {
if( identity( oldItem, newItem ) ) {
oldIndex++;
newIndex++;
continue;
}
// look for single insert, does the next newList item equal the current oldList.
// 1 2 3
// 1 2 4 3
if( newIndex+1 < newLength && newList[newIndex+1] === oldItem) {
if( newIndex+1 < newLength && identity( oldItem, newList[newIndex+1] ) ) {
patches.push({index: newIndex, deleteCount: 0, insert: [ newList[newIndex] ]});
oldIndex++;
newIndex += 2;
Expand All @@ -54,7 +75,7 @@ module.exports = exports = function(oldList, newList){
// look for single removal, does the next item in the oldList equal the current newList item.
// 1 2 3
// 1 3
else if( oldIndex+1 < oldLength && oldList[oldIndex+1] === newItem ) {
else if( oldIndex+1 < oldLength && identity( oldList[oldIndex+1], newItem ) ) {
patches.push({index: newIndex, deleteCount: 1, insert: []});
oldIndex += 2;
newIndex++;
Expand Down