mirror of
https://github.com/flynx/diff.js.git
synced 2025-10-29 11:00:12 +00:00
basics done, ready to refactor...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
5823b7b944
commit
e4997c1d52
162
diff.js
162
diff.js
@ -34,20 +34,26 @@
|
|||||||
// positions nor does it affect the the array lengths.
|
// positions nor does it affect the the array lengths.
|
||||||
var EMPTY = {type: 'EMPTY'}
|
var EMPTY = {type: 'EMPTY'}
|
||||||
|
|
||||||
|
var NONE = {type: 'NONE'}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
// XXX should we handle properties???
|
// XXX should we handle properties???
|
||||||
var _diff_items = function(diff, A, B, options, filter){
|
var _diff_items = function(diff, res, A, B, options, filter){
|
||||||
// JSON mode -> ignore attr order...
|
// JSON mode -> ignore attr order...
|
||||||
var kA = Object.keys(A)
|
var kA = Object.keys(A)
|
||||||
var kB = Object.keys(B)
|
var kB = Object.keys(B)
|
||||||
|
|
||||||
if(filter){
|
if(filter){
|
||||||
kA = kA.filter(filter)
|
kA = filter instanceof Array ?
|
||||||
kB = kB.filter(filter)
|
filter.slice()
|
||||||
|
: kA.filter(filter)
|
||||||
|
kB = filter instanceof Array ?
|
||||||
|
filter.slice()
|
||||||
|
: kB.filter(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
var B_index = kB.reduce(function(res, k){
|
var B_index = kB.reduce(function(res, k){
|
||||||
@ -60,7 +66,7 @@ var _diff_items = function(diff, A, B, options, filter){
|
|||||||
// A keys...
|
// A keys...
|
||||||
.map(function(ka){
|
.map(function(ka){
|
||||||
var res = [ka,
|
var res = [ka,
|
||||||
_diff(
|
diff(
|
||||||
A[ka],
|
A[ka],
|
||||||
ka in B_index ? B[ka] : EMPTY,
|
ka in B_index ? B[ka] : EMPTY,
|
||||||
options)]
|
options)]
|
||||||
@ -72,7 +78,7 @@ var _diff_items = function(diff, A, B, options, filter){
|
|||||||
.concat(Object.keys(B_index)
|
.concat(Object.keys(B_index)
|
||||||
.map(function(kb){
|
.map(function(kb){
|
||||||
return [kb,
|
return [kb,
|
||||||
_diff(
|
diff(
|
||||||
EMPTY,
|
EMPTY,
|
||||||
B[kb],
|
B[kb],
|
||||||
options)]}))
|
options)]}))
|
||||||
@ -80,24 +86,28 @@ var _diff_items = function(diff, A, B, options, filter){
|
|||||||
.filter(function(e){
|
.filter(function(e){
|
||||||
return e[1] !== null })
|
return e[1] !== null })
|
||||||
items.length > 0
|
items.length > 0
|
||||||
&& (diff.items = (diff.items || []).concat(items))
|
&& (res.items = (res.items || []).concat(items))
|
||||||
|
|
||||||
return diff
|
return res
|
||||||
}
|
}
|
||||||
var _diff_item_order = function(diff, A, B, options, filter){
|
var _diff_item_order = function(diff, res, A, B, options, filter){
|
||||||
var kA = Object.keys(A)
|
var kA = Object.keys(A)
|
||||||
var kB = Object.keys(B)
|
var kB = Object.keys(B)
|
||||||
|
|
||||||
if(filter){
|
if(filter){
|
||||||
kA = kA.filter(filter)
|
kA = filter instanceof Array ?
|
||||||
kB = kB.filter(filter)
|
filter.slice()
|
||||||
|
: kA.filter(filter)
|
||||||
|
kB = filter instanceof Array ?
|
||||||
|
filter.slice()
|
||||||
|
: kB.filter(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
var item_order = _diff(kA, kB, {mode: 'JSON'})
|
var item_order = diff(kA, kB, {mode: 'JSON'})
|
||||||
item_order != null
|
item_order != null
|
||||||
&& (diff.item_order = item_order)
|
&& (res.item_order = item_order)
|
||||||
|
|
||||||
return diff
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -170,6 +180,48 @@ var getCommonSections = function(A, B, cmp, min_chunk){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Format:
|
||||||
|
// [
|
||||||
|
// [
|
||||||
|
// [<gap-offset-A>,
|
||||||
|
// [ item, ... ]],
|
||||||
|
// [<gap-offset-B>,
|
||||||
|
// [ item, ... ]],
|
||||||
|
// ],
|
||||||
|
// ...
|
||||||
|
// ]
|
||||||
|
var getDiffSections = function(A, B, cmp, min_chunk){
|
||||||
|
// find the common sections...
|
||||||
|
var common_sections = getCommonSections(A, B, cmp, min_chunk)
|
||||||
|
common_sections.shift()
|
||||||
|
|
||||||
|
// collect gaps between common sections...
|
||||||
|
var a = 0
|
||||||
|
var b = 0
|
||||||
|
var gaps = []
|
||||||
|
common_sections
|
||||||
|
// make this consider the tail gap...
|
||||||
|
.concat({
|
||||||
|
A: A.length,
|
||||||
|
B: B.length,
|
||||||
|
length: 0,
|
||||||
|
})
|
||||||
|
.forEach(function(e){
|
||||||
|
// store the gap...
|
||||||
|
;(a != e.A || b != e.B)
|
||||||
|
&& gaps.push([
|
||||||
|
[a, A.slice(a, e.A)],
|
||||||
|
[b, B.slice(b, e.B)],
|
||||||
|
])
|
||||||
|
// go to next gap...
|
||||||
|
a = e.A + e.length
|
||||||
|
b = e.B + e.length
|
||||||
|
})
|
||||||
|
|
||||||
|
return gaps
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
@ -197,11 +249,7 @@ var getCommonSections = function(A, B, cmp, min_chunk){
|
|||||||
// [<key>, <diff>],
|
// [<key>, <diff>],
|
||||||
//
|
//
|
||||||
// // [S]plice section starting at key...
|
// // [S]plice section starting at key...
|
||||||
// // The <diff> should contain two array sections.
|
// [<key-a>, <key-b>, <diff>],
|
||||||
// // The section is treated as a seporate array, diffed
|
|
||||||
// // and spliced into the target array at <key>.
|
|
||||||
// // XXX is this too complicated???
|
|
||||||
// ['S', <key>, <diff>],
|
|
||||||
//
|
//
|
||||||
// ...
|
// ...
|
||||||
// ],
|
// ],
|
||||||
@ -226,7 +274,7 @@ var getCommonSections = function(A, B, cmp, min_chunk){
|
|||||||
// XXX revise format...
|
// XXX revise format...
|
||||||
// XXX support Map(..) and other new-style types...
|
// XXX support Map(..) and other new-style types...
|
||||||
var _diff =
|
var _diff =
|
||||||
function(A, B, options){
|
function(A, B, options, cache){
|
||||||
options = options || {}
|
options = options || {}
|
||||||
|
|
||||||
// same object...
|
// same object...
|
||||||
@ -249,13 +297,18 @@ function(A, B, options){
|
|||||||
|
|
||||||
// cache...
|
// cache...
|
||||||
// XXX use this everywhere we use _diff...
|
// XXX use this everywhere we use _diff...
|
||||||
var cache = new Map()
|
cache = cache || new Map()
|
||||||
var cacheDiff = function(a, b){
|
var cacheDiff = cache.diff = cache.diff || function(a, b){
|
||||||
var l2 = cache.get(a) || new Map()
|
var l2 = cache.get(a) || new Map()
|
||||||
var d = l2.get(b) || _diff(a, b)
|
var d = l2.get(b) || _diff(a, b, options, cache)
|
||||||
cache.set(a, l2.set(b, d))
|
cache.set(a, l2.set(b, d))
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
var cmp = function(a, b){
|
||||||
|
return a === b
|
||||||
|
|| a == b
|
||||||
|
|| (cacheDiff(a, b) == null)
|
||||||
|
}
|
||||||
|
|
||||||
// Array...
|
// Array...
|
||||||
// XXX check seen -- avoid recursion...
|
// XXX check seen -- avoid recursion...
|
||||||
@ -265,52 +318,47 @@ function(A, B, options){
|
|||||||
length: [A.length, B.length],
|
length: [A.length, B.length],
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the common sections...
|
|
||||||
// XXX cache _diff(..) results...
|
|
||||||
var common_sections = getCommonSections(A, B,
|
|
||||||
function(a, b){
|
|
||||||
return a === b || a == b || cacheDiff(a, b) })
|
|
||||||
// collect gaps between common sections...
|
|
||||||
common_sections.shift()
|
|
||||||
var a = 0
|
|
||||||
var b = 0
|
|
||||||
var gaps = []
|
|
||||||
common_sections
|
|
||||||
// make this consider the tail gap...
|
|
||||||
.concat({
|
|
||||||
A: A.length,
|
|
||||||
B: B.length,
|
|
||||||
length: 0,
|
|
||||||
})
|
|
||||||
.forEach(function(e){
|
|
||||||
// store the gap...
|
|
||||||
a != e.A && b != e.B
|
|
||||||
&& gaps.push([
|
|
||||||
[a, A.slice(a, e.A)],
|
|
||||||
[b: B.slice(b, e.B)],
|
|
||||||
])
|
|
||||||
// go to next gap...
|
|
||||||
a = e.A + e.length
|
|
||||||
b = e.B + e.length
|
|
||||||
})
|
|
||||||
|
|
||||||
// XXX diff the gaps...
|
// XXX diff the gaps...
|
||||||
// XXX
|
res.items = getDiffSections(A, B, cmp)
|
||||||
|
.map(function(gap){
|
||||||
|
var a = gap[0][1]
|
||||||
|
var b = gap[1][1]
|
||||||
|
|
||||||
|
var i = gap[0][0]
|
||||||
|
var j = gap[1][0]
|
||||||
|
|
||||||
|
return a
|
||||||
|
.map(function(e, n){
|
||||||
|
return {
|
||||||
|
A: i+n,
|
||||||
|
B: j+n,
|
||||||
|
diff: cacheDiff(e, b.length > n ? b[n] : NONE)
|
||||||
|
} })
|
||||||
|
.concat(b.slice(a.length)
|
||||||
|
.map(function(e, n){
|
||||||
|
return {
|
||||||
|
A: a.length + i+n,
|
||||||
|
B: a.length + j+n,
|
||||||
|
diff: cacheDiff(a.length > n ? a[n] : NONE, e)
|
||||||
|
} }))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* XXX
|
||||||
// indexed items...
|
// indexed items...
|
||||||
_diff_items(res, A, B, options,
|
_diff_items(cacheDiff, res, A, B, options,
|
||||||
function(e){ return e == 0 || !!(e*1) })
|
function(e){ return e == 0 || !!(e*1) })
|
||||||
|
|
||||||
// attributes...
|
// attributes...
|
||||||
// XXX make this more configurable... (order needs to be optional in JSON)
|
// XXX make this more configurable... (order needs to be optional in JSON)
|
||||||
options.mode != 'JSON'
|
options.mode != 'JSON'
|
||||||
&& _diff_items(res, A, B, options,
|
&& _diff_items(cacheDiff, res, A, B, options,
|
||||||
function(e){ return !(e == 0 || !!(e*1)) })
|
function(e){ return !(e == 0 || !!(e*1)) })
|
||||||
// attributes order...
|
// attributes order...
|
||||||
&& _diff_item_order(res, A, B, options,
|
&& _diff_item_order(cacheDiff, res, A, B, options,
|
||||||
function(e){ return !(e == 0 || !!(e*1)) })
|
function(e){ return !(e == 0 || !!(e*1)) })
|
||||||
|
//*/
|
||||||
|
|
||||||
return (res.items || []).length > 0 ? res : null
|
return (res.items || []).length > 0 ? res : null
|
||||||
|
|
||||||
@ -323,11 +371,11 @@ function(A, B, options){
|
|||||||
type: 'Object',
|
type: 'Object',
|
||||||
}
|
}
|
||||||
|
|
||||||
_diff_items(res, A, B, options)
|
_diff_items(cacheDiff, res, A, B, options)
|
||||||
|
|
||||||
// XXX this should be applicable to JSON too...
|
// XXX this should be applicable to JSON too...
|
||||||
options.mode != 'JSON'
|
options.mode != 'JSON'
|
||||||
&& _diff_item_order(res, A, B, options)
|
&& _diff_item_order(cacheDiff, res, A, B, options)
|
||||||
|
|
||||||
// .constructor...
|
// .constructor...
|
||||||
if(options.mode != 'JSON'){
|
if(options.mode != 'JSON'){
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user