Skip to content

Commit

Permalink
Tweak patch context docs. Clean up jiff/lib/context, add jsdoc
Browse files Browse the repository at this point in the history
  • Loading branch information
briancavalier committed Jul 11, 2014
1 parent c833fb3 commit 3041443
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 12 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,19 @@ As of v0.2, `jiff.diff` and `jiff.patch` support [patch contexts](http://en.wiki

Using patch contexts can greatly improve patch accuracy for arrays, at the cost of increasing the size of patches.

Patch contexts are supported via a pair of closely related functions: `makeContext` and `findContext`.
Patch contexts are entirely opt-in. To use them, you must provide a pair of closely related functions: `makeContext` and `findContext`. An API for creating default `makeContext` and `findContext` functions is provided in [`jiff/lib/context`](#jifflibcontext), or you can implement your own.

If you supply the optional `makeContext` function to `jiff.diff`, it will be used to generated a context for each change to an array.
When you supply the optional `makeContext` function to `jiff.diff`, it will be used to generated a context for each change to an array.

Likewise, if you supply the optional `findContext` function to `jiff.patch` (or `jiff.patchInPlace`), it will be used to find adjusted array indices where patches should actually be applied.
Likewise, when you supply the optional `findContext` function to `jiff.patch` (or `jiff.patchInPlace`), it will be used to find adjusted array indices where patches should actually be applied.

The context is opaque, and jiff will not attempt to inspect or use it: `jiff.diff` will simply add whatever is returned by `makeContext` to patch operations, and `jiff.patch` will simply hand it to `findContext` when it sees a context in a patch operation.
The context is opaque, and jiff itself will not attempt to inspect or interpret it: `jiff.diff` will simply add whatever is returned by `makeContext` to patch operations, and `jiff.patch` will simply hand it to `findContext` when it sees a context in a patch operation.

An API for creating default `makeContext` and `findContext` functions is provided in [`jiff/lib/context`](#jifflibcontext).

## Experimental APIs

These APIs are still considered experimental, signatures may change.

### jiff/lib/context

```js
Expand Down
31 changes: 24 additions & 7 deletions lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,39 @@ exports.matchContext = matchContext;
exports.makeContextFinder = makeContextFinder;
exports.makeContext = makeContext;

/**
* Creates a findContext function that expects a context
* { before: [...], after: [...] } containing some number of items before
* and after the change. Uses the provided equals function to compare
* array itesm and find the best fit position in the array to
* apply the patch. Uses a similar algorithm to GNU patch.
* @param {function(a:*, b:*):boolean} equals return truthy if a and b are equal
* @returns {Function} a findContext function that can be passed to jiff.patch
*/
function makeContextFinder(equals) {
return function(index, array, context) {
return findPosition(equals, index, array, context);
};
}

/**
* Creates a makeContext function that will generate patch contexts
* { before: [...], after: [...] } containing `size` number of items
* before and after the change.
* @param {number} size max number of items before/after the change to include
* @returns {Function} a makeContext function that can be passed to jiff.diff
*/
function makeContext(size) {
return function (index, array) {
return {
before: array.slice(Math.max(0, index - size), index),
after: array.slice(Math.min(array.length, index), index + size)
after: array.slice(Math.min(array.length, index + 1), index + size + 1)
};
};
}

// TODO: Include removed items in the patch context when patch is a remove

function findPosition (equals, start, array, context) {
var index;
var before = context.before;
Expand All @@ -27,9 +45,9 @@ function findPosition (equals, start, array, context) {
var amax = after.length;

while(amax > 0 || bmax < blen) {
index = findPositionWith(equals, array,
index = findPositionWith(equals, array, start,
before.slice(bmax),
after.slice(0, amax), start);
after.slice(0, amax));

if(index >= 0) {
return index;
Expand All @@ -42,16 +60,15 @@ function findPosition (equals, start, array, context) {
return start;
}

function findPositionWith(equals, array, before, after, start) {
function findPositionWith(equals, array, start, before, after, patch) {
var blen = before.length;
var b = start-blen;

var bspan = blen;
var found = false;
var i = b;

while(i >= 0 && !found) {
found = matchContext(equals, array, i, i+blen, before, after);
found = matchContext(equals, array, i, i+blen+1, before, after);
if(found) {
return i + blen;
}
Expand All @@ -61,7 +78,7 @@ function findPositionWith(equals, array, before, after, start) {

i = start;
while(i < array.length && !found) {
found = matchContext(equals, array, i-bspan, i, before, after);
found = matchContext(equals, array, i-blen, i+1, before, after);
if(found) {
return i;
}
Expand Down

0 comments on commit 3041443

Please sign in to comment.