Tixit / odiff

Gets a list of differences between two javascript values.
MIT License
88 stars 13 forks source link

odiff

A value difference generator that can generate a list of differences between one javascript value and another. It recursively finds differences within arrays and objects.

Example

var a = [{a:1,b:2,c:3},              {x:1,y: 2, z:3},              {w:9,q:8,r:7}]
var b = [{a:1,b:2,c:3},{t:4,y:5,u:6},{x:1,y:'3',z:3},{t:9,y:9,u:9},{w:9,q:8,r:7}]

var diffs = odiff(a,b)

/* diffs now contains:
[{type: 'add', path:[], index: 2, vals: [{t:9,y:9,u:9}]},
 {type: 'set', path:[1,'y'], val: '3'},
 {type: 'add', path:[], index: 1, vals: [{t:4,y:5,u:6}]}
]
*/

Motivation

This differencing algorithm is intended to make object differences easy to manage when you need to update an object in a way other than simply copying the reference. An example is if you need to create a database query to update a record based on the changes between two objects. It also works in a basic way on primitives (no string differencing tho).

While this algorithm puts in some effort to make the number of change records minimal, it by no means generates an absolutely minimal set of changes. It also doesn't handle compressing string differences in any way. For these reasons, this algorithm is not ideal for use in sending changes over the wire, especially if your data contains lots of small changes to large strings.

Other algorithms I found either had undesirable behavior when dealing with array inserts ( flitbit/diff, cosmicanant/recursive-diff, ackrause/ObjectCompare, thomseddon/docdiff ), had weird nested difference formats that make things harder ( NV/objectDiff.js ), didn't describe their behavior at all ( aogriffiths/jsondiff-js, benjamine/JsonDiffPatch ), or all three. Also some only work on objects (not arrays) ( Evaw/objectDiff, omgaz/js-diff ).

Install

npm install odiff

Usage

Accessing odiff:

// typescript
import odiff from "odiff";

// node.js
var odiff = require('odiff')

// amd
require.config({paths: {odiff: '../generatedBuilds/odiff.umd.js'}})
require(['odiff'], function(odiff) { /* your code */ })

// global variable
<script src="https://github.com/Tixit/odiff/raw/master/odiff.umd.js"></script>
odiff; // odiff.umd.js can define odiff globally if you really
       //   want to shun module-based design

Using odiff:

odiff(valueA, valueB) - Returns an array of changes that, when applied to valueA, will turn that value into valueB. The results are also build such that you can pick and choose what changes to do, and as long as you do them (selectively) in order, the changes will work properly. Each element in the resulting array has the following members:

Odiff also exposes two functions used internally:

odiff.equal(a,b) - Returns true if the two values are equal, false otherwise. NaN is treated as equal to itself.

odiff.similar(a,b) - Returns true if the two values are similar, false otherwise. "Similar" is defined as having less than two shallow inner values different (as long as not 100% of the values are different) or having fewer than 10% of its shallow values different. NaN is treated as equal to itself.

Algorithm behavior

The differencing algorithm is intended to run well on values that are pretty similar. Some properties of the algorithm:

Design Decisions

Why not use JSONPatch format?

Todo

How to Contribute!

Anything helps:

How to submit pull requests:

  1. Please create an issue and get my input before spending too much time creating a feature. Work with me to ensure your feature or addition is optimal and fits with the purpose of the project.
  2. Fork the repository
  3. clone your forked repo onto your machine and run npm install at its root
  4. If you're gonna work on multiple separate things, its best to create a separate branch for each of them
  5. edit!
  6. If it's a code change, please add to the unit tests (at test/odiffTest.js) to verify that your change
  7. When you're done, run the unit tests and ensure they all pass
  8. Commit and push your changes
  9. Submit a pull request: https://help.github.com/articles/creating-a-pull-request

Change Log

License

Released under the MIT license: http://opensource.org/licenses/MIT