mirror of
https://github.com/flynx/diff.js.git
synced 2025-10-28 18:40:09 +00:00
added base code...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
b3d26a3f40
commit
5673ecad97
275
diff.js
Normal file
275
diff.js
Normal 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 })
|
||||
Loading…
x
Reference in New Issue
Block a user