added base code...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-07-07 03:02:41 +03:00
parent b3d26a3f40
commit 5673ecad97

275
diff.js Normal file
View File

@ -0,0 +1,275 @@
/**********************************************************************
*
*
*
**********************************************************************/
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
(function(require){ var module={} // make module AMD/node compatible...
/*********************************************************************/
/*********************************************************************/
// Diff base format:
// {
// varsion: '1.0',
// options: {
// },
//
// diff: <diff-format>,
// }
//
// Diff format:
// [
// ]
//
//
//
/*********************************************************************/
var EMPTY = {type: 'EMPTY'}
// Helpers...
// XXX should we handle properties???
var _diff_items = function(diff, A, B, options, filter){
// JSON mode -> ignore attr order...
var kA = Object.keys(A)
var kB = Object.keys(B)
if(filter){
kA = kA.filter(filter)
kB = kB.filter(filter)
}
var B_index = kB.reduce(function(res, k){
res[k] = null
return res
}, {})
// items...
var items = kA
// A keys...
.map(function(ka){
var res = [ka,
_diff(
A[ka],
ka in B_index ? B[ka] : EMPTY,
options)]
// remove seen keys...
delete B_index[ka]
return res
})
// keys present only in B...
.concat(Object.keys(B_index)
.map(function(kb){
return [kb,
_diff(
EMPTY,
B[kb],
options)]}))
// cleanup...
.filter(function(e){
return e[1] !== null })
items.length > 0
&& (diff.items = (diff.items || []).concat(items))
return diff
}
var _diff_item_order = function(diff, A, B, options, filter){
var kA = Object.keys(A)
var kB = Object.keys(B)
if(filter){
kA = kA.filter(filter)
kB = kB.filter(filter)
}
var item_order = _diff(kA, kB, {mode: 'JSON'})
item_order != null
&& (diff.item_order = item_order)
return diff
}
// Format:
// - no difference...
// null
//
// - A and/or B is a basic value...
// {
// type: 'Basic',
//
// A: <value>,
// B: <value>,
// }
//
// - A and B are arrays...
// {
// type: 'Array',
// // holds both index and attribute keys (mode-dependant)...
//
// items: [
// [<key>, <diff>],
// ...
// ],
// // only for non-index keys...
// item_order: <array-diff>,
// }
//
// - A and B are objects...
// {
// type: 'Object',
//
// items: [
// [<key>, <diff>],
// ...
// ],
// item_order: <array-diff>,
// }
//
//
// NOTE: this will include direct links to items.
// XXX check seen -- avoid recursion...
// XXX revise format...
var _diff =
function(A, B, options){
options = options || {}
// same object...
// XXX this will miss things like:
// new Number(123) vs. 123
// ...would need to also include .value (i.e. .valueOf()) and
// treat the thing as object...
if(A === B || A == B){
//if(A === B || (options.mode == 'JSON' && A == B)){
return null
}
// basic types...
if(typeof(A) != 'object' || typeof(B) != 'object'){
return {
type: 'Basic',
//values: [A, B],
A: A,
B: B,
}
}
// Array...
// XXX check seen -- avoid recursion...
if(A instanceof Array && B instanceof Array){
var res = {
type: 'Array',
}
// indexed items...
_diff_items(res, A, B, options,
function(e){ return e == 0 || !!(e*1) })
// attributes...
options.mode != 'JSON'
&& _diff_items(res, A, B, options,
function(e){ return !(e == 0 || !!(e*1)) })
// attributes order...
&& _diff_item_order(res, A, B, options,
function(e){ return !(e == 0 || !!(e*1)) })
return (res.items || []).length > 0 ? res : null
// Object...
// NOTE: this will handle ONLY own keys...
// XXX check seen -- avoid recursion...
// XXX handle prototyping... (???)
} else {
var res = {
type: 'Object',
}
_diff_items(res, A, B, options)
// XXX this should be applicable to JSON too...
options.mode != 'JSON'
&& _diff_item_order(res, A, B, options)
// .constructor...
if(options.mode != 'JSON'){
A.constructor !== B.constructor
&& (res.constructors = [A.constructor, B.constructor])
// XXX should we diff constructors???
// XXX .__proto___ (???)
}
return ((res.item_order || []).length + (res.items || []).length) == 0 ? null : res
}
}
// XXX need to track order very carefully here... (???)
var flatten =
function(diff, res, path){
res = res || []
path = path || []
// no difference...
if(diff == null){
return res
// Basic...
} else if(diff.type == 'Basic'){
res.push({
path: path,
A: diff.A,
B: diff.B,
})
// Array...
} else if(diff.type == 'Array'){
diff.items.forEach(function(e){
var i = e[0]
var v = e[1]
var p = path.concat([i])
flatten(v, res, p)
})
// Object...
} else if(diff.type == 'Object'){
diff.items.forEach(function(e){
var i = e[0]
var v = e[1]
var p = path.concat([i])
flatten(v, res, p)
})
// Other...
// XXX revise this...
} else {
throw new TypeError('Unknown diff type: '+ diff.type)
}
return res
}
var diff =
module.diff =
function(A, B, options){
}
var patch =
module.patch =
function(diff, obj){
}
/**********************************************************************
* vim:set ts=4 sw=4 : */ return module })