mirror of
https://github.com/flynx/diff.js.git
synced 2025-10-29 19:10:11 +00:00
refactoring...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
2ba1c5331d
commit
7ba88235d4
211
diff.js
211
diff.js
@ -346,6 +346,17 @@ object.makeConstructor('AND', Object.assign(new LogicType(), {
|
|||||||
// Diff framework...
|
// Diff framework...
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
// General architecture:
|
||||||
|
// Types
|
||||||
|
// Low-level diff routines.
|
||||||
|
// Diff
|
||||||
|
// User interface to Types.
|
||||||
|
// XXX should this encapsulate or inherit (current) or do a mix of two??
|
||||||
|
// ...a mix of the two seems logical as we might need access to
|
||||||
|
// the type handlers (proxy) and the rest of the low-level stuff
|
||||||
|
// can be hidden apart for very specific things (.cmp(..))...
|
||||||
|
//
|
||||||
|
//
|
||||||
// Format (tree):
|
// Format (tree):
|
||||||
// <diff> ::=
|
// <diff> ::=
|
||||||
// // no difference...
|
// // no difference...
|
||||||
@ -377,7 +388,6 @@ object.makeConstructor('AND', Object.assign(new LogicType(), {
|
|||||||
//
|
//
|
||||||
// // Slice change, the <diff> is treated as two arrays that
|
// // Slice change, the <diff> is treated as two arrays that
|
||||||
// // must be sliced in/out of the targets...
|
// // must be sliced in/out of the targets...
|
||||||
// // XXX not implemented -- need to think about this...
|
|
||||||
// [[<key-a>], [<key-b>], <diff>],
|
// [[<key-a>], [<key-b>], <diff>],
|
||||||
//
|
//
|
||||||
// ...
|
// ...
|
||||||
@ -469,18 +479,21 @@ object.makeConstructor('AND', Object.assign(new LogicType(), {
|
|||||||
// XXX Q: do we need to support both the flat and tree diff formats???
|
// XXX Q: do we need to support both the flat and tree diff formats???
|
||||||
var Types =
|
var Types =
|
||||||
module.Types = {
|
module.Types = {
|
||||||
__cache: null,
|
// system meta information...
|
||||||
|
format: FORMAT_NAME,
|
||||||
|
version: FORMAT_VERSION,
|
||||||
|
|
||||||
// Object-level utilities...
|
// Object-level utilities...
|
||||||
clone: function(){
|
clone: function(){
|
||||||
var res = Object.create(this)
|
var res = Object.create(this)
|
||||||
res.__cache = null
|
//res.__cache = null
|
||||||
res.handlers = new Map(this.handlers.entries())
|
res.handlers = new Map(this.handlers.entries())
|
||||||
return res
|
return res
|
||||||
},
|
},
|
||||||
clear: function(){
|
clear: function(){
|
||||||
// XXX should we instead this.handlers.clear() ???
|
// XXX should we instead this.handlers.clear() ???
|
||||||
this.handlers = new Map()
|
//this.handlers = new Map()
|
||||||
|
this.handlers.clear()
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -563,14 +576,14 @@ module.Types = {
|
|||||||
: order.get(a) - order.get(b)
|
: order.get(a) - order.get(b)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
get typeNames(){
|
||||||
|
return this.typeKeys.map(function(e){ return e.name || e }) },
|
||||||
get types(){
|
get types(){
|
||||||
var that = this
|
var that = this
|
||||||
return this.typeKeys
|
return this.typeKeys
|
||||||
.map(function(e){
|
.map(function(e){
|
||||||
return that.get(e) })
|
return that.get(e) })
|
||||||
},
|
},
|
||||||
get typeNames(){
|
|
||||||
return this.typeKeys.map(function(e){ return e.name || e }) },
|
|
||||||
|
|
||||||
|
|
||||||
// Detect handler type...
|
// Detect handler type...
|
||||||
@ -773,7 +786,8 @@ module.Types = {
|
|||||||
|| (diff(a, b) == null) }
|
|| (diff(a, b) == null) }
|
||||||
|
|
||||||
// cache...
|
// cache...
|
||||||
cache = this.__cache = cache || this.__cache || new Map()
|
//cache = this.__cache = cache || this.__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()
|
||||||
var d = l2.get(b) || that.diff(a, b, options, cache)
|
var d = l2.get(b) || that.diff(a, b, options, cache)
|
||||||
@ -826,6 +840,11 @@ module.Types = {
|
|||||||
|
|
||||||
// Deep-compare A and B...
|
// Deep-compare A and B...
|
||||||
//
|
//
|
||||||
|
// XXX would be nice to do a fast fail version of this, i.e. fail on
|
||||||
|
// first mismatch and do not waste time compiling a full diff we
|
||||||
|
// are going to throw away anyway...
|
||||||
|
// ...this would be possible with a live .walk(..) that would
|
||||||
|
// report changes as it finds them...
|
||||||
cmp: function(A, B, options){
|
cmp: function(A, B, options){
|
||||||
return this.diff(A, B, options) == null },
|
return this.diff(A, B, options) == null },
|
||||||
|
|
||||||
@ -1308,7 +1327,14 @@ Types.set(Array, {
|
|||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// XXX add JS types like Map, Set, ...
|
// XXX add JS types like Map, Set, ...
|
||||||
// XXX
|
/*/ XXX for now unsupported types will be treated as basic changes...
|
||||||
|
Types.set(Map, {
|
||||||
|
handle: function(obj, diff, A, B, options){
|
||||||
|
throw new TypeError('Map handling not implemented.')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
//*/
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// Text...
|
// Text...
|
||||||
@ -1387,23 +1413,12 @@ Types.set(LogicType, {
|
|||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Deep-compare objects...
|
// The diff object...
|
||||||
//
|
//
|
||||||
// XXX would be nice to do a fast fail version of this, i.e. fail on
|
// Create a diff...
|
||||||
// first mismatch and do not waste time compiling a full diff we
|
// Diff(A, B[, options])
|
||||||
// are going to throw away anyway...
|
// new Diff(A, B[, options])
|
||||||
// ...this would be possible with a live .walk(..) that would
|
// -> diff
|
||||||
// report changes as it finds them...
|
|
||||||
var cmp =
|
|
||||||
module.cmp =
|
|
||||||
function(A, B){
|
|
||||||
return Types.clone().cmp(A, B) }
|
|
||||||
|
|
||||||
|
|
||||||
// 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:
|
||||||
@ -1473,71 +1488,61 @@ function(A, B){
|
|||||||
// at least the differences between them must be JSON compatible.
|
// at least the differences between them must be JSON compatible.
|
||||||
// NOTE: recursive inputs will result in recursive diff objects.
|
// NOTE: recursive inputs will result in recursive diff objects.
|
||||||
//
|
//
|
||||||
// XXX revise how the types can be passed in...
|
|
||||||
var diff =
|
|
||||||
module.diff =
|
|
||||||
function(A, B, options, types){
|
|
||||||
options = options || {}
|
|
||||||
types = types || Types.clone()
|
|
||||||
|
|
||||||
return {
|
|
||||||
// system meta information...
|
|
||||||
format: FORMAT_NAME,
|
|
||||||
varsion: FORMAT_VERSION,
|
|
||||||
structure: options.tree_diff ? 'tree' : 'flat',
|
|
||||||
placeholders: {
|
|
||||||
NONE: options.NONE || Types.NONE,
|
|
||||||
EMPTY: options.NONE || Types.EMPTY,
|
|
||||||
},
|
|
||||||
|
|
||||||
// user data...
|
|
||||||
options: Object.assign({}, options),
|
|
||||||
|
|
||||||
diff: options.tree_diff ?
|
|
||||||
types.diff(A, B, options)
|
|
||||||
//: types.flatten(Types.diff(A, B, options), null, null, options)
|
|
||||||
: types.flatten(Types.diff(A, B, options), options)
|
|
||||||
}}
|
|
||||||
|
|
||||||
|
|
||||||
// Apply diff (patch) to obj...
|
|
||||||
//
|
//
|
||||||
// This is a front-end to Types.patch(..), handling loading the options
|
|
||||||
// from the diff...
|
|
||||||
//
|
//
|
||||||
var patch =
|
// Extending Diff...
|
||||||
module.patch =
|
//
|
||||||
function(diff, obj, options, types){
|
// // create a new diff constructor...
|
||||||
var types = types || Types.clone()
|
// var ExtendedDiff = Diff.clone('ExtendedDiff')
|
||||||
diff.placeholders
|
//
|
||||||
&& Object.assign(types, diff.placeholders)
|
// // add a new type...
|
||||||
return types.patch(diff, obj, options)
|
// ExtendedDiff.types.set(SomeType, {
|
||||||
}
|
// ...
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // add a new synthetic type...
|
||||||
//---------------------------------------------------------------------
|
// ExtendedDiff.types.set('SomeOtherType', {
|
||||||
// XXX EXPERIMENTAL...
|
// check: function(..){ .. },
|
||||||
|
// ...
|
||||||
// XXX make this an instance of Types...
|
// })
|
||||||
// XXX
|
//
|
||||||
|
// // remove an existing type...
|
||||||
|
// ExtendedDiff.types.delete('Text')
|
||||||
|
//
|
||||||
|
//
|
||||||
var DiffClassPrototype = {
|
var DiffClassPrototype = {
|
||||||
// system meta information...
|
// encapsulate the low-level types...
|
||||||
format: FORMAT_NAME,
|
types: Types,
|
||||||
version: FORMAT_VERSION,
|
|
||||||
|
|
||||||
// XXX PROTOTYPE -- uses Types...
|
// create a new diff constructor with a detached handler set...
|
||||||
cmp: function(A, B){
|
clone: function(name){
|
||||||
return Types.clone().cmp(A, B) },
|
var cls = Object.create(this.__proto__)
|
||||||
|
cls.types = this.types.clone()
|
||||||
|
return object.makeConstructor(name || 'EDiff', cls, this())
|
||||||
|
},
|
||||||
|
|
||||||
// XXX
|
// proxy generic stuff to .types...
|
||||||
|
cmp: proxy('types.cmp'),
|
||||||
|
|
||||||
|
// XXX do format/version conversion...
|
||||||
fromJSON: function(json){
|
fromJSON: function(json){
|
||||||
|
var diff = new this()
|
||||||
|
|
||||||
|
if(json.format == diff.format
|
||||||
|
&& json.version == diff.version){
|
||||||
|
// XXX do a deep copy...
|
||||||
|
diff.options = JSON.parse(JSON.stringify(json.options))
|
||||||
|
diff.placeholders = JSON.parse(JSON.stringify(json.placeholders))
|
||||||
|
diff.diff = JSON.parse(JSON.stringify(json.diff))
|
||||||
|
|
||||||
|
return diff
|
||||||
|
|
||||||
|
// XXX do format conversion...
|
||||||
|
} else {
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// XXX hack...
|
|
||||||
//DiffClassPrototype.__proto__ = Types.clone()
|
|
||||||
|
|
||||||
// XXX
|
|
||||||
var DiffPrototype = {
|
var DiffPrototype = {
|
||||||
// system meta information...
|
// system meta information...
|
||||||
get format(){
|
get format(){
|
||||||
@ -1550,24 +1555,25 @@ var DiffPrototype = {
|
|||||||
options: null,
|
options: null,
|
||||||
diff: null,
|
diff: null,
|
||||||
|
|
||||||
// XXX PROTOTYPE -- uses Types...
|
|
||||||
__init__: function(A, B, options){
|
__init__: function(A, B, options){
|
||||||
// XXX should we add a default options as prototype???
|
// XXX should we add a default options as prototype???
|
||||||
options = this.options = options || {}
|
options = this.options = options || {}
|
||||||
this.structure = options.tree_diff ? 'tree' : 'flat'
|
this.structure = options.tree_diff ? 'tree' : 'flat'
|
||||||
this.placeholders = {
|
this.placeholders = {
|
||||||
NONE: options.NONE || Types.NONE,
|
NONE: options.NONE
|
||||||
EMPTY: options.NONE || Types.EMPTY,
|
|| this.constructor.types.NONE,
|
||||||
|
EMPTY: options.NONE
|
||||||
|
|| this.constructor.types.EMPTY,
|
||||||
}
|
}
|
||||||
|
|
||||||
var types = types || Types.clone()
|
var diff = this.constructor.types
|
||||||
|
|
||||||
// XXX should the Types instance be stored/cached here???
|
// XXX should the Types instance be stored/cached here???
|
||||||
this.diff = arguments.length == 0 ?
|
this.diff = arguments.length == 0 ?
|
||||||
null
|
null
|
||||||
: options.tree_diff ?
|
: options.tree_diff ?
|
||||||
types.diff(A, B, options)
|
diff.diff(A, B, options)
|
||||||
: types.flatten(Types.diff(A, B, options), options)
|
: diff.flatten(diff.diff(A, B, options), options)
|
||||||
},
|
},
|
||||||
|
|
||||||
// XXX should this be a deep copy???
|
// XXX should this be a deep copy???
|
||||||
@ -1587,19 +1593,16 @@ var DiffPrototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// NOTE: this will not mutate this...
|
// NOTE: this will not mutate this...
|
||||||
// XXX PROTOTYPE -- uses Types...
|
|
||||||
reverse: function(obj){
|
reverse: function(obj){
|
||||||
var res = this.clone()
|
var res = this.clone()
|
||||||
res.diff = Types.reverse(this.diff)
|
res.diff = this.constructor.types.reverse(this.diff)
|
||||||
return res
|
return res
|
||||||
},
|
},
|
||||||
|
|
||||||
// XXX PROTOTYPE -- uses Types...
|
|
||||||
check: function(obj){
|
check: function(obj){
|
||||||
Types.clone().check(this.diff, obj) },
|
return this.constructor.types.check(this.diff, obj) },
|
||||||
// XXX PROTOTYPE -- uses Types...
|
|
||||||
patch: function(obj){
|
patch: function(obj){
|
||||||
return Types.patch(this, obj) },
|
return this.constructor.types.patch(this, obj) },
|
||||||
unpatch: function(obj){
|
unpatch: function(obj){
|
||||||
return this.reverse().patch(obj) },
|
return this.reverse().patch(obj) },
|
||||||
|
|
||||||
@ -1625,6 +1628,30 @@ object.makeConstructor('Diff',
|
|||||||
DiffPrototype)
|
DiffPrototype)
|
||||||
|
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// Short hands...
|
||||||
|
|
||||||
|
// Deep-compare objects...
|
||||||
|
//
|
||||||
|
var cmp =
|
||||||
|
module.cmp =
|
||||||
|
function(A, B){
|
||||||
|
return Diff.cmp(A, B) }
|
||||||
|
|
||||||
|
|
||||||
|
// Apply diff (patch) to obj...
|
||||||
|
//
|
||||||
|
// This is a front-end to Types.patch(..), handling loading the options
|
||||||
|
// from the diff...
|
||||||
|
var patch =
|
||||||
|
module.patch =
|
||||||
|
function(diff, obj, options, types){
|
||||||
|
return (diff instanceof Diff ?
|
||||||
|
diff
|
||||||
|
: Diff.fromJSON(diff))
|
||||||
|
.patch(obj, options) }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user