revised the docs and notes + changed cr/lf format to unix...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-07-19 04:38:51 +03:00
parent 28de14211d
commit 867e51842a

93
diff.js
View File

@ -21,7 +21,7 @@
// zip(func, array, array, ...) // zip(func, array, array, ...)
// -> [func(i, [item, item, ...]), ...] // -> [func(i, [item, item, ...]), ...]
// //
// XXX revise... // XXX revise -- is this too complicated...
var zip = function(func, ...arrays){ var zip = function(func, ...arrays){
var i = arrays[0] instanceof Array ? 0 : arrays.shift() var i = arrays[0] instanceof Array ? 0 : arrays.shift()
if(func instanceof Array){ if(func instanceof Array){
@ -182,6 +182,12 @@ var getDiffSections = function(A, B, cmp, min_chunk){
// Make a proxy method... // Make a proxy method...
// //
// proxy('path.to.attr')
// -> method
//
// proxy('path.to.attr', function)
// -> method
//
var proxy = function(path, func){ var proxy = function(path, func){
path = path instanceof Array ? path = path instanceof Array ?
path.slice() path.slice()
@ -236,7 +242,7 @@ var proxy = function(path, func){
// ... // ...
// ], // ],
// // only for non-index keys... // // only for non-index keys...
// // XXX unused... // // XXX not implemented...
// item_order: <array-diff>, // item_order: <array-diff>,
// } // }
// //
@ -247,11 +253,11 @@ var proxy = function(path, func){
// items: [ // items: [
// [<key>, <diff>], // [<key>, <diff>],
// //
// // XXX unused.... // // XXX not implemented....
// [<key-a>, <key-b>, <diff>], // [<key-a>, <key-b>, <diff>],
// ... // ...
// ], // ],
// // XXX unused... // // XXX not implemented...
// item_order: <array-diff>, // item_order: <array-diff>,
// } // }
// //
@ -272,6 +278,9 @@ var proxy = function(path, func){
// // // //
// // If not present then the change is simple item insertion // // If not present then the change is simple item insertion
// // or splicing... // // or splicing...
// //
// // NOTE: insertion vs. splicing depends on the values of .A,
// // .B and/or .path, see docs for those...
// type: <change-type>, // type: <change-type>,
// //
// // The path to the item in the object tree... // // The path to the item in the object tree...
@ -309,12 +318,27 @@ var proxy = function(path, func){
// like the type information which is not needed for patching but // like the type information which is not needed for patching but
// may be useful for a more thorough compatibility check. // may be useful for a more thorough compatibility check.
var Types = { var Types = {
// Object-level utilities...
clone: function(){
var res = Object.create(this)
res.handlers = new Map(this.handlers.entries())
return res
},
clear: function(){
// XXX should we instead this.handlers.clear() ???
this.handlers = new Map()
return this
},
// Placeholder objects... // Placeholder objects...
// //
// Inseted when an item exists on one side and does not on the other. // Inseted when an item exists on one side and does not on the other.
// //
// NOTE: for Array items this does not shift positions of other item // NOTE: for Array items this does not shift positions of other item
// positions nor does it affect the the array lengths. // positions nor does it affect the the array lengths.
// NOTE: these are compared by identity while diffing but are compared
// by value when patching...
NONE: NONE, NONE: NONE,
EMPTY: EMPTY, EMPTY: EMPTY,
get DIFF_TYPES(){ get DIFF_TYPES(){
@ -448,6 +472,9 @@ var Types = {
return type return type
}, },
// Handle the difference between A and B...
//
handle: function(type, obj, diff, A, B, options){ handle: function(type, obj, diff, A, B, options){
// set .type // set .type
type = type == null ? this.detect(A, B, options) : type type = type == null ? this.detect(A, B, options) : type
@ -478,9 +505,12 @@ var Types = {
// XXX does change order matter here??? // XXX does change order matter here???
// ...some changes can affect changes after them (like splicing // ...some changes can affect changes after them (like splicing
// with arrays), this ultimately affects how patching is done... // with arrays), this ultimately affects how patching is done...
// ...or is this a quastion of how we treat indexes and the patching // ...or is this a question of how we treat indexes and the patching
// algorithm??? // algorithm???
// XXX we should be able to provide "fuzz" (context) to the changes... // XXX we should be able to provide "fuzz" (context, horizontal) to
// the changes in ordered containers...
// ...it might also be possible to provide vertical/topological
// "fuzz", need to think about this...
// XXX TEST: the format should survive JSON.parse(JSON.stringify(..))... // XXX TEST: the format should survive JSON.parse(JSON.stringify(..))...
flatten: function(diff, res, path, options){ flatten: function(diff, res, path, options){
res = res || [] res = res || []
@ -509,20 +539,20 @@ var Types = {
// NOTE: for format info see doc for Types... // NOTE: for format info see doc for Types...
// //
// XXX special case: empty sections do not need to be inserted... // XXX special case: empty sections do not need to be inserted...
// // ...splice in a sparse array and store an Array diff with only
// length changed...
// XXX do we need to differentiate things like: new Number(123) vs. 123??? // XXX do we need to differentiate things like: new Number(123) vs. 123???
// XXX check seen -- avoid recursion... // XXX might be a god idea to mix in default options (different
// defaults per mode)...
// XXX TEST: the format should survive JSON.parse(JSON.stringify(..))... // XXX TEST: the format should survive JSON.parse(JSON.stringify(..))...
diff: function(A, B, options, cache){ diff: function(A, B, options, cache){
var that = this var that = this
// XXX might be a god idea to mix in default options (different
// defaults per mode)...
options = options ? Object.create(options) : {} options = options ? Object.create(options) : {}
options.cmp = options.cmp || function(a, b){ options.cmp = options.cmp || function(a, b){
return a === b return a === b
|| a == b || a == b
// NOTE: diff(..) is in closure, see cache setup below...
|| (diff(a, b) == null) } || (diff(a, b) == null) }
// XXX update this depending on mode...
options.as_object = options.as_object || [] options.as_object = options.as_object || []
@ -539,7 +569,6 @@ var Types = {
// cache... // cache...
// XXX check seen -- avoid recursion...
cache = cache || new Map() cache = cache || new Map()
var diff = cache.diff = cache.diff || function(a, b){ var diff = cache.diff = cache.diff || function(a, b){
var l2 = cache.get(a) || new Map() var l2 = cache.get(a) || new Map()
@ -679,6 +708,7 @@ Types.set(Object, {
priority: -50, priority: -50,
handle: function(obj, diff, A, B, options){ handle: function(obj, diff, A, B, options){
// attrebutes/items...
obj.items = (obj.items || []) obj.items = (obj.items || [])
.concat(this.get(Object).attributes.call(this, diff, A, B, options)) .concat(this.get(Object).attributes.call(this, diff, A, B, options))
@ -901,6 +931,10 @@ Types.set('Text', {
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Diff interface function...
//
// This is a front-end to Types.diff(..), adding a metadata wrapper to
// the format, and optionally handling the topology of the output...
// //
// //
// Options format: // Options format:
@ -950,6 +984,11 @@ Types.set('Text', {
// format: 'object-diff', // format: 'object-diff',
// version: '0.0.0', // version: '0.0.0',
// structure: 'flat' | 'tree', // structure: 'flat' | 'tree',
// // NOTE: these are stored in the diff to make the diff independent
// // of future changes to the values of the placeholder, both
// // in spec and as means to avoid data collisions...
// // NOTE: these are compared by identity while diffing but are
// // compared by value when patching...
// placeholders: { // placeholders: {
// ... // ...
// }, // },
@ -960,15 +999,20 @@ Types.set('Text', {
// } // }
// //
// //
// NOTE: the format itself is JSON compatible (XXX) but the data in the // NOTE: the format itself is JSON compatible but the data in the changes
// changes may not be, so if JSON compatibility is desired, the // may not be, so if JSON compatibility is desired, the inputs or
// inputs or at least the differences between them must be JSON // at least the differences between them must be JSON compatible.
// compatible.
// NOTE: recursive inputs will result in recursive diff objects. // NOTE: recursive inputs will result in recursive diff objects.
//
// XXX should we instantiate Types here so as to make all the caching
// call-specific???
// XXX revise how the types can be passed in...
var diff = var diff =
module.diff = module.diff =
function(A, B, options){ function(A, B, options, types){
options = options || {} options = options || {}
types = types || Types.clone()
return { return {
// system meta information... // system meta information...
format: 'object-diff', format: 'object-diff',
@ -983,18 +1027,23 @@ function(A, B, options){
options: Object.assign({}, options), options: Object.assign({}, options),
diff: options.tree_diff ? diff: options.tree_diff ?
Types.diff(A, B, options) types.diff(A, B, options)
: Types.flatten(Types.diff(A, B, options), null, null, options) : types.flatten(Types.diff(A, B, options), null, null, options)
}} }}
// Apply diff (patch) to obj...
//
// This is a front-end to Types.patch(..), handling loading the options
// from the diff...
//
var patch = var patch =
module.patch = module.patch =
function(diff, obj){ function(diff, obj, options, types){
var t = Object.create(Types) var t = Object.create(types || Types)
diff.placeholders diff.placeholders
&& Object.assign(t, diff.placeholders) && Object.assign(t, diff.placeholders)
return t.patch(diff, obj) return t.patch(diff, obj, options)
} }