Skip to content

Instantly share code, notes, and snippets.

@aaronshaf
Created May 20, 2014 21:02
Show Gist options
  • Select an option

  • Save aaronshaf/66e6220e1d8efa529804 to your computer and use it in GitHub Desktop.

Select an option

Save aaronshaf/66e6220e1d8efa529804 to your computer and use it in GitHub Desktop.
requirebin sketch
const jiff = require('jiff')
const wrap = require('wordwrap')(15)
document.body.innerHTML = ""
function log(text) {
document.body.innerHTML += '<pre>' + JSON.stringify(text,null,2) + '</pre>';
}
var a = wrap("I think that the cow jumped over the moon").split("\n")
var b = wrap("I know that the dog jumped over the moon").split("\n")
var c = wrap("I think that the cow jumped over the cheese").split("\n")
var patch1 = jiff.diff(a, b)
var patch2 = jiff.diff(a, c)
log(patch1)
log(patch2)
require=function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({p7N6Hq:[function(require,module,exports){var lcs=require("./lib/lcs");var patch=require("./lib/jsonPatch");var inverse=require("./lib/inverse");var jsonPointer=require("./lib/jsonPointer");var encodeSegment=jsonPointer.encodeSegment;exports.diff=diff;exports.patch=patch.apply;exports.patchInPlace=patch.applyInPlace;exports.inverse=inverse;exports.clone=patch.clone;exports.InvalidPatchOperationError=require("./lib/InvalidPatchOperationError");exports.TestFailedError=require("./lib/TestFailedError");exports.PatchNotInvertibleError=require("./lib/PatchNotInvertibleError");function diff(a,b,hasher){var hash=typeof hasher==="function"?hasher:defaultHash;var state={patch:[],hash:hash};return appendChanges(a,b,"",state).patch.reverse()}function appendChanges(a,b,path,state){if(Array.isArray(a)&&Array.isArray(b)){return appendListChanges(a,b,path,state)}if(isValidObject(a)&&isValidObject(b)){return appendObjectChanges(a,b,path,state)}return appendValueChanges(a,b,path,state)}function appendObjectChanges(o1,o2,path,state){state=Object.keys(o2).reduceRight(function(state,key){var keyPath=path+"/"+encodeSegment(key);if(key in o1){appendChanges(o1[key],o2[key],keyPath,state)}else{state.patch.push({op:"add",path:keyPath,value:o2[key]})}return state},state);return Object.keys(o1).reduceRight(function(state,key){if(!(key in o2)){var p=path+"/"+encodeSegment(key);state.patch.push({op:"remove",path:p,value:void 0});state.patch.push({op:"test",path:p,value:o1[key]})}return state},state)}function appendListChanges(a1,a2,path,state){var a1hash=a1.map(state.hash);var a2hash=a2.map(state.hash);var lcsMatrix=lcs.compare(a1hash,a2hash);return lcsToJsonPatch(a1,a2,path,state,lcsMatrix)}function lcsToJsonPatch(a1,a2,path,state,lcsMatrix){return lcs.reduce(function(state,op,i,j){var last,p;if(op==lcs.REMOVE){p=path+"/"+j;last=state.patch[state.patch.length-1];if(last!==void 0&&last.op==="add"&&last.path===p){last.op="replace"}else{state.patch.push({op:"remove",path:p,value:void 0})}state.patch.push({op:"test",path:p,value:a1[j]})}else if(op==lcs.ADD){state.patch.push({op:"add",path:path+"/"+j,value:a2[i]})}else{appendChanges(a1[j],a2[i],path+"/"+j,state)}return state},state,lcsMatrix)}function appendValueChanges(a,b,path,state){if(a!==b){state.patch.push({op:"replace",path:path,value:b});state.patch.push({op:"test",path:path,value:a})}return state}function defaultHash(x){return JSON.stringify(x)}function isValidObject(x){return x!==null&&typeof x==="object"}},{"./lib/InvalidPatchOperationError":3,"./lib/PatchNotInvertibleError":4,"./lib/TestFailedError":5,"./lib/inverse":9,"./lib/jsonPatch":10,"./lib/jsonPointer":11,"./lib/lcs":12}],jiff:[function(require,module,exports){module.exports=require("p7N6Hq")},{}],3:[function(require,module,exports){module.exports=InvalidPatchOperationError;function InvalidPatchOperationError(message){Error.call(this);this.name=this.constructor.name;this.message=message;if(typeof Error.captureStackTrace==="function"){Error.captureStackTrace(this,this.constructor)}}InvalidPatchOperationError.prototype=Object.create(Error.prototype);InvalidPatchOperationError.prototype.constructor=InvalidPatchOperationError},{}],4:[function(require,module,exports){module.exports=PatchNotInvertibleError;function PatchNotInvertibleError(message){Error.call(this);this.name=this.constructor.name;this.message=message;if(typeof Error.captureStackTrace==="function"){Error.captureStackTrace(this,this.constructor)}}PatchNotInvertibleError.prototype=Object.create(Error.prototype);PatchNotInvertibleError.prototype.constructor=PatchNotInvertibleError},{}],5:[function(require,module,exports){module.exports=TestFailedError;function TestFailedError(message){Error.call(this);this.name=this.constructor.name;this.message=message;if(typeof Error.captureStackTrace==="function"){Error.captureStackTrace(this,this.constructor)}}TestFailedError.prototype=Object.create(Error.prototype);TestFailedError.prototype.constructor=TestFailedError},{}],6:[function(require,module,exports){var jsonDateRx=/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)(Z|([+\-])(\d{2}):(\d{2}))$/;module.exports=function clone(x){return JSON.parse(JSON.stringify(x),dateReviver)};function dateReviver(_,value){var match;if(typeof value==="string"){match=jsonDateRx.exec(value);if(match){return new Date(Date.UTC(+match[1],+match[2]-1,+match[3],+match[4],+match[5],+match[6]))}}return value}},{}],7:[function(require,module,exports){var jsonPointer=require("./jsonPointer");var arrayIndexRx=/^(0|[1-9]\d*)$/;module.exports=function commutePaths(a,b){var left=jsonPointer.parse(a.path);var right=jsonPointer.parse(b.path);var prefix=getCommonPathPrefix(left,right);var isArray=isArrayPath(left,right,prefix.length);var ac=copyPatch(a);var bc=copyPatch(b);if(prefix.length===0&&!isArray){return[bc,ac]}if(isArray){return commuteArrayPaths(ac,left,bc,right)}else{return commuteTreePaths(ac,left,bc,right)}};function commuteTreePaths(a,left,b,right){if(a.path===b.path){throw new TypeError("cannot commute "+a.op+","+b.op+" with identical object paths")}return[b,a]}function commuteArrayPaths(a,left,b,right){if(right.length===left.length){return commuteArraySiblings(a,left,b,right)}if(right.length<left.length){left=commuteArrayAncestor(b,right,a,left,-1);a.path=jsonPointer.absolute(jsonPointer.join(left))}else{right=commuteArrayAncestor(a,left,b,right,1);b.path=jsonPointer.absolute(jsonPointer.join(right))}return[b,a]}function isArrayPath(left,right,index){return arrayIndexRx.test(left[index])&&arrayIndexRx.test(right[index])}function commuteArraySiblings(l,lpath,r,rpath){var target=lpath.length-1;var lindex=+lpath[target];var rindex=+rpath[target];var commuted;if(lindex===rindex){if(r.op==="remove"){throw new TypeError("patches cannot be commuted")}}else if(lindex<=rindex){commuted=rpath.slice();if(l.op==="add"||l.op==="copy"){commuted[target]=Math.max(0,rindex-1);r.path=jsonPointer.absolute(jsonPointer.join(commuted))}else if(l.op==="remove"){commuted[target]=rindex+1;r.path=jsonPointer.absolute(jsonPointer.join(commuted))}}else{commuted=lpath.slice();if(r.op==="add"||r.op==="copy"){commuted[target]=lindex+1;l.path=jsonPointer.absolute(jsonPointer.join(commuted))}else if(r.op==="remove"){commuted[target]=Math.max(0,lindex-1);l.path=jsonPointer.absolute(jsonPointer.join(commuted))}}return[r,l]}function commuteArrayAncestor(l,lpath,r,rpath,direction){var target=lpath.length-1;var lindex=+lpath[target];var rindex=+rpath[target];var rc=rpath.slice();if(lindex>rindex){return rc}if(l.op==="add"||l.op==="copy"){rc[target]=Math.max(0,rindex-direction)}else if(l.op==="remove"){rc[target]=Math.max(0,rindex+direction)}return rc}function getCommonPathPrefix(p1,p2){var l=Math.min(p1.length,p2.length);var i=0;while(i<l&&p1[i]===p2[i]){++i}return p1.slice(0,i)}function copyPatch(p){if(p.op==="remove"){return{op:p.op,path:p.path}}if(p.op==="copy"||p.op==="move"){return{op:p.op,path:p.path,from:p.from}}return{op:p.op,path:p.path,value:p.value}}},{"./jsonPointer":11}],8:[function(require,module,exports){module.exports=deepEquals;function deepEquals(a,b){if(a===b){return true}if(Array.isArray(a)&&Array.isArray(b)){return compareArrays(a,b)}if(typeof a==="object"&&typeof b==="object"){return compareObjects(a,b)}return false}function compareArrays(a,b){if(a.length!==b.length){return false}for(var i=0;i<a.length;++i){if(!deepEquals(a[i],b[i])){return false}}return true}function compareObjects(a,b){var akeys=Object.keys(a);var bkeys=Object.keys(b);if(akeys.length!==bkeys.length){return false}for(var i=0,k;i<akeys.length;++i){k=akeys[i];if(!(k in b&&deepEquals(a[k],b[k]))){return false}}return true}},{}],9:[function(require,module,exports){var patches=require("./patches");module.exports=function inverse(p){var pr=[];var i,skip;for(i=p.length-1;i>=0;i-=skip){skip=invertOp(pr,p[i],i,p)}return pr};function invertOp(patch,c,i,context){var op=patches[c.op];return op!==void 0&&typeof op.inverse==="function"?op.inverse(patch,c,i,context):1}},{"./patches":13}],10:[function(require,module,exports){var patches=require("./patches");var clone=require("./clone");var InvalidPatchOperationError=require("./InvalidPatchOperationError");exports.apply=patch;exports.applyInPlace=patchInPlace;exports.clone=clone;function patch(changes,x){return patchInPlace(changes,clone(x))}function patchInPlace(changes,x){if(!Array.isArray(changes)){return x}return changes.reduce(function(x,change){var patch=patches[change.op];if(patch===void 0){throw new InvalidPatchOperationError("invalid op "+change.op)}return patch.apply(x,change)},x)}},{"./InvalidPatchOperationError":3,"./clone":6,"./patches":13}],11:[function(require,module,exports){exports.find=find;exports.join=join;exports.absolute=absolute;exports.parse=parse;exports.contains=contains;exports.encodeSegment=encodeSegment;exports.decodeSegment=decodeSegment;exports.parseArrayIndex=parseArrayIndex;var separator="/";var separatorRx=/\//g;var encodedSeparator="~1";var encodedSeparatorRx=/~1/g;var escapeChar="~";var escapeRx=/~/g;var encodedEscape="~0";var encodedEscapeRx=/~0/g;function find(x,path){if(typeof path!=="string"){return}if(path===""){return{target:x,key:void 0}}if(path==="/"){return{target:x,key:""}}path=split(path);var i=0;var len=path.length-1;for(;i<len;++i){x=x[decodeSegment(path[i])];if(x==null){return}}return{target:x,key:decodeSegment(path[len])}}function absolute(path){return path[0]==="/"?path:"/"+path}function join(segments){return segments.join(separator)}function parse(path){return split(path).map(decodeSegment)}function contains(a,b){return b.indexOf(a)===0&&b[a.length]===separator}function decodeSegment(s){return s.replace(encodedSeparatorRx,separator).replace(encodedEscapeRx,escapeChar)}function encodeSegment(s){return s.replace(escapeRx,encodedEscape).replace(separatorRx,encodedSeparator)}function split(path){if(path[0]===separator){path=path.slice(1)}return path.split(separator)}var arrayIndexRx=/^(0|[1-9]\d*)$/;function parseArrayIndex(s){if(!arrayIndexRx.test(s)){throw new SyntaxError("invalid array index "+s)}return+s}},{}],12:[function(require,module,exports){exports.compare=compare;exports.reduce=reduce;var REMOVE,RIGHT,ADD,DOWN,SKIP;exports.REMOVE=REMOVE=RIGHT=-1;exports.ADD=ADD=DOWN=1;exports.EQUAL=SKIP=0;var skip={value:1,type:SKIP};function compare(a,b){var cols=a.length;var rows=b.length;var prefix=findPrefix(a,b);var suffix=prefix<cols&&prefix<rows?findSuffix(a,b,prefix):0;var remove=suffix+prefix-1;cols-=remove;rows-=remove;var matrix=createMatrix(cols,rows);for(var j=cols-1;j>=0;--j){for(var i=rows-1;i>=0;--i){matrix[i][j]=backtrack(matrix,a,b,prefix,j,i)}}return{prefix:prefix,matrix:matrix,suffix:suffix}}function reduce(f,r,lcs){var i,j,k,op;var m=lcs.matrix;var l=lcs.prefix;for(i=0;i<l;++i){r=f(r,SKIP,i,i)}k=i;l=m.length;i=0;j=0;while(i<l){op=m[i][j].type;r=f(r,op,i+k,j+k);switch(op){case SKIP:++i;++j;break;case RIGHT:++j;break;case DOWN:++i;break}}i+=k;j+=k;l=lcs.suffix;for(k=0;k<l;++k){r=f(r,SKIP,i+k,j+k)}return r}function findPrefix(a,b){var i=0;var l=Math.min(a.length,b.length);while(i<l&&a[i]===b[i]){++i}return i}function findSuffix(a,b){var al=a.length-1;var bl=b.length-1;var l=Math.min(al,bl);var i=0;while(i<l&&a[al-i]===b[bl-i]){++i}return i}function backtrack(matrix,a,b,start,j,i){if(a[j+start]===b[i+start]){return{value:matrix[i+1][j+1].value,type:SKIP}}if(matrix[i][j+1].value<matrix[i+1][j].value){return{value:matrix[i][j+1].value+1,type:RIGHT}}return{value:matrix[i+1][j].value+1,type:DOWN}}function createMatrix(cols,rows){var m=[],i,j,lastrow;lastrow=m[rows]=[];for(j=0;j<cols;++j){lastrow[j]={value:cols-j,type:RIGHT}}for(i=0;i<rows;++i){m[i]=[];m[i][cols]={value:rows-i,type:DOWN}}m[rows][cols]={value:0,type:SKIP};return m}},{}],13:[function(require,module,exports){var jsonPointer=require("./jsonPointer");var clone=require("./clone");var deepEquals=require("./deepEquals");var commutePaths=require("./commutePaths");var TestFailedError=require("./TestFailedError");var InvalidPatchOperationError=require("./InvalidPatchOperationError");var PatchNotInvertibleError=require("./PatchNotInvertibleError");var find=jsonPointer.find;var parseArrayIndex=jsonPointer.parseArrayIndex;exports.test={apply:applyTest,inverse:invertTest,commute:commuteTest};exports.add={apply:applyAdd,inverse:invertAdd,commute:commuteAddOrCopy};exports.remove={apply:applyRemove,inverse:invertRemove,commute:commuteRemove};exports.replace={apply:applyReplace,inverse:invertReplace,commute:commuteReplace};exports.move={apply:applyMove,inverse:invertMove,commute:commuteMove};exports.copy={apply:applyCopy,inverse:notInvertible,commute:commuteAddOrCopy};function applyTest(x,test){var pointer=find(x,test.path);if(!deepEquals(pointer.target[pointer.key],test.value)){throw new TestFailedError("test failed "+JSON.stringify(test))}return x}function invertTest(pr,test){pr.push(test);return 1}function commuteTest(test,b){if(test.path===b.path&&b.op==="remove"){throw new TypeError("Can't commute test,remove -> remove,test for same path")}if(b.op==="test"||b.op==="replace"){return[b,test]}return commutePaths(test,b)}function applyAdd(x,change){var pointer=find(x,change.path);if(notFound(pointer)){throw new InvalidPatchOperationError("path does not exist "+change.path)}var val=typeof change.value==="object"?clone(change.value):change.value;if(pointer.key===void 0){return val}_add(pointer,val);return x}function _add(pointer,value){var target=pointer.target;var index;if(Array.isArray(target)){if(pointer.key==="-"){target.push(value)}else{index=parseArrayIndex(pointer.key);if(index<0||index>target.length){throw new InvalidPatchOperationError("array index out of bounds "+index)}target.splice(index,0,value)}}else if(isValidObject(target)){target[pointer.key]=value}else{throw new InvalidPatchOperationError("target of add must be an object or array "+pointer.key)}}function invertAdd(pr,add){pr.push({op:"test",path:add.path,value:add.value});pr.push({op:"remove",path:add.path});return 1}function commuteAddOrCopy(add,b){if(add.path===b.path&&b.op==="remove"){throw new TypeError("Can't commute add,remove -> remove,add for same path")}return commutePaths(add,b)}function applyReplace(x,change){var pointer=find(x,change.path);if(notFound(pointer)||missingValue(pointer)){throw new InvalidPatchOperationError("path does not exist "+change.path)}var value=typeof change.value==="object"?clone(change.value):change.value;if(pointer.key===void 0){return value}var target=pointer.target;if(Array.isArray(target)){target[parseArrayIndex(pointer.key)]=value}else{target[pointer.key]=value}return x}function invertReplace(pr,c,i,context){var prev=context[i-1];if(prev===void 0||prev.op!=="test"||prev.path!==c.path){throw new PatchNotInvertibleError("cannot invert replace w/o test")}pr.push({op:"test",path:prev.path,value:c.value});pr.push({op:"replace",path:prev.path,value:prev.value});return 2}function commuteReplace(replace,b){if(replace.path===b.path&&b.op==="remove"){throw new TypeError("Can't commute replace,remove -> remove,replace for same path")}if(b.op==="test"||b.op==="replace"){return[b,test]}return commutePaths(replace,b)}function applyRemove(x,change){var pointer=find(x,change.path);if(notFound(pointer)||pointer.target[pointer.key]===void 0){throw new InvalidPatchOperationError("path does not exist "+change.path)}_remove(pointer);return x}function _remove(pointer){var target=pointer.target;var removed;if(Array.isArray(target)){removed=target.splice(parseArrayIndex(pointer.key),1);return removed[0]}else if(isValidObject(target)){removed=target[pointer.key];delete target[pointer.key];return removed}else{throw new InvalidPatchOperationError("target of remove must be an object or array")}}function invertRemove(pr,c,i,context){var prev=context[i-1];if(prev===void 0||prev.op!=="test"||prev.path!==c.path){throw new PatchNotInvertibleError("cannot invert remove w/o test")}pr.push({op:"add",path:prev.path,value:prev.value});return 2}function commuteRemove(remove,b){if(remove.path===b.path&&b.op==="remove"){return[b,remove]}return commutePaths(remove,b)}function applyMove(x,change){if(jsonPointer.contains(change.path,change.from)){throw new InvalidPatchOperationError("move.from cannot be ancestor of move.path")}var pto=find(x,change.path);var pfrom=find(x,change.from);_add(pto,_remove(pfrom));return x}function invertMove(pr,c){pr.push({op:"move",path:c.from,from:c.path});return 1}function commuteMove(move,b){if(move.path===b.path&&b.op==="remove"){throw new TypeError("Can't commute move,remove -> move,replace for same path")}return commutePaths(move,b)}function applyCopy(x,change){var pto=find(x,change.path,true);var pfrom=find(x,change.from);_add(pto,clone(pfrom.target[pfrom.key]));return x}function notInvertible(_,c){throw new PatchNotInvertibleError("cannot invert "+c.op)}function notFound(pointer){return pointer===void 0||pointer.target==null&&pointer.key!==void 0}function missingValue(pointer){return pointer.key!==void 0&&pointer.target[pointer.key]===void 0}function isValidObject(x){return x!==null&&typeof x==="object"}},{"./InvalidPatchOperationError":3,"./PatchNotInvertibleError":4,"./TestFailedError":5,"./clone":6,"./commutePaths":7,"./deepEquals":8,"./jsonPointer":11}]},{},[]);require=function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({"5XKofN":[function(require,module,exports){var wordwrap=module.exports=function(start,stop,params){if(typeof start==="object"){params=start;start=params.start;stop=params.stop}if(typeof stop==="object"){params=stop;start=start||params.start;stop=undefined}if(!stop){stop=start;start=0}if(!params)params={};var mode=params.mode||"soft";var re=mode==="hard"?/\b/:/(\S+\s+)/;return function(text){var chunks=text.toString().split(re).reduce(function(acc,x){if(mode==="hard"){for(var i=0;i<x.length;i+=stop-start){acc.push(x.slice(i,i+stop-start))}}else acc.push(x);return acc},[]);return chunks.reduce(function(lines,rawChunk){if(rawChunk==="")return lines;var chunk=rawChunk.replace(/\t/g," ");var i=lines.length-1;if(lines[i].length+chunk.length>stop){lines[i]=lines[i].replace(/\s+$/,"");chunk.split(/\n/).forEach(function(c){lines.push(new Array(start+1).join(" ")+c.replace(/^\s+/,""))})}else if(chunk.match(/\n/)){var xs=chunk.split(/\n/);lines[i]+=xs.shift();xs.forEach(function(c){lines.push(new Array(start+1).join(" ")+c.replace(/^\s+/,""))})}else{lines[i]+=chunk}return lines},[new Array(start+1).join(" ")]).join("\n")}};wordwrap.soft=wordwrap;wordwrap.hard=function(start,stop){return wordwrap(start,stop,{mode:"hard"})}},{}],wordwrap:[function(require,module,exports){module.exports=require("5XKofN")},{}]},{},[]);const jiff=require("jiff");const wrap=require("wordwrap")(15);document.body.innerHTML="";function log(text){document.body.innerHTML+="<pre>"+JSON.stringify(text,null,2)+"</pre>"}var a=wrap("I think that the cow jumped over the moon").split("\n");var b=wrap("I know that the dog jumped over the moon").split("\n");var c=wrap("I think that the cow jumped over the cheese").split("\n");var patch1=jiff.diff(a,b);var patch2=jiff.diff(a,c);log(patch1);log(patch2);
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"jiff": "0.5.3",
"wordwrap": "0.0.2"
}
}
<style type='text/css'>html, body { margin: 0; padding: 0; border: 0; }
body, html { height: 100%; width: 100%; }</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment