flitbit/diff — pull request #33 by elad (2014-12-25 03:19:53+00:00)
Title: Feature: Add support for normalizing values before diffing.

Hello,

This is a pull request to initiate discussion about a potential feature, specifically allowing values to be "normalized" (or transformed) before diffing. Backwards compatibility is maintained.

My use case: I'm saving object history for MongoDB documents. Some objects refer to other objects, and those fields have an ObjectID type. When diffing such objects, I get diffs for fields like `binId` and `offset` which are internal ObjectID fields, while I'm actually interested in the `.toString()` value to see if the referred object has changed or not.

I'd like to be able to tell deep-diff that for ObjectID objects, it should use the result of `.tosString()`. This is implemented by allowing `prefilter` to be either a function (in which case backwards compatibility is maintained) or an object. In the latter case, it can have a `prefilter` property for the existing functionality and also a new `normalize` property which is a `function (path, key, lhs, rhs)` that returns either a falsey value (no action) or an array of `[lhs, rhs]` that replaces the original `lhs` and `rhs` values.

Code demonstrating usage:
```js
var assert = require('assert'),
mongodb = require('mongodb'),
deep_diff = require('deep-diff');

mongodb.MongoClient.connect('mongodb://localhost/test', function (err, db) {
var collection = db.collection('example');

// Insert a document to generate an ObjectID for it.
collection.insert({}, function (err, doc) {
doc = doc[0];

// Get the same document so we have two instances.
collection.findOne({ _id: doc._id }, function (err, doc2) {
// Both ObjectIDs are the same.
assert(doc._id.toString() === doc2._id.toString());

// Create two objects with the same id.
var lhs = { object_id: doc._id.toString() },
rhs = { object_id: doc2._id };

// This will show a diff because obviously a string
// isn't equivalent to an object.
assert(!!deep_diff.diff(lhs, rhs));

// Proposed feature: Pass a normalize function that
// compares and produces a diff based on a normalized
// value.
var filter = {
normalize: function (path, key, lhs, rhs) {
lhs = (lhs.constructor.name === 'ObjectID') ? lhs.toString() : lhs;
rhs = (rhs.constructor.name === 'ObjectID') ? rhs.toString() : rhs;
return [lhs, rhs];
}
};
assert(!deep_diff.diff(lhs, rhs, filter));

db.close();
});
});
});
```

Thoughts? Ideas on better ways to achieve the same thing? If not, any chance this will make it to the distribution?