mirror of
https://github.com/flynx/diff.js.git
synced 2025-10-29 02:50:10 +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...
|
||||
//
|
||||
//
|
||||
// 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):
|
||||
// <diff> ::=
|
||||
// // no difference...
|
||||
@ -377,7 +388,6 @@ object.makeConstructor('AND', Object.assign(new LogicType(), {
|
||||
//
|
||||
// // Slice change, the <diff> is treated as two arrays that
|
||||
// // must be sliced in/out of the targets...
|
||||
// // XXX not implemented -- need to think about this...
|
||||
// [[<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???
|
||||
var Types =
|
||||
module.Types = {
|
||||
__cache: null,
|
||||
// system meta information...
|
||||
format: FORMAT_NAME,
|
||||
version: FORMAT_VERSION,
|
||||
|
||||
// Object-level utilities...
|
||||
clone: function(){
|
||||
var res = Object.create(this)
|
||||
res.__cache = null
|
||||
//res.__cache = null
|
||||
res.handlers = new Map(this.handlers.entries())
|
||||
return res
|
||||
},
|
||||
clear: function(){
|
||||
// XXX should we instead this.handlers.clear() ???
|
||||
this.handlers = new Map()
|
||||
//this.handlers = new Map()
|
||||
this.handlers.clear()
|
||||
return this
|
||||
},
|
||||
|
||||
@ -563,14 +576,14 @@ module.Types = {
|
||||
: order.get(a) - order.get(b)
|
||||
})
|
||||
},
|
||||
get typeNames(){
|
||||
return this.typeKeys.map(function(e){ return e.name || e }) },
|
||||
get types(){
|
||||
var that = this
|
||||
return this.typeKeys
|
||||
.map(function(e){
|
||||
return that.get(e) })
|
||||
},
|
||||
get typeNames(){
|
||||
return this.typeKeys.map(function(e){ return e.name || e }) },
|
||||
|
||||
|
||||
// Detect handler type...
|
||||
@ -773,7 +786,8 @@ module.Types = {
|
||||
|| (diff(a, b) == null) }
|
||||
|
||||
// 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 l2 = cache.get(a) || new Map()
|
||||
var d = l2.get(b) || that.diff(a, b, options, cache)
|
||||
@ -826,6 +840,11 @@ module.Types = {
|
||||
|
||||
// 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){
|
||||
return this.diff(A, B, options) == null },
|
||||
|
||||
@ -1308,7 +1327,14 @@ Types.set(Array, {
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 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...
|
||||
@ -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
|
||||
// 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...
|
||||
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...
|
||||
// Create a diff...
|
||||
// Diff(A, B[, options])
|
||||
// new Diff(A, B[, options])
|
||||
// -> diff
|
||||
//
|
||||
//
|
||||
// Options format:
|
||||
@ -1473,71 +1488,61 @@ function(A, B){
|
||||
// at least the differences between them must be JSON compatible.
|
||||
// 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 =
|
||||
module.patch =
|
||||
function(diff, obj, options, types){
|
||||
var types = types || Types.clone()
|
||||
diff.placeholders
|
||||
&& Object.assign(types, diff.placeholders)
|
||||
return types.patch(diff, obj, options)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// XXX EXPERIMENTAL...
|
||||
|
||||
// XXX make this an instance of Types...
|
||||
// XXX
|
||||
// Extending Diff...
|
||||
//
|
||||
// // create a new diff constructor...
|
||||
// var ExtendedDiff = Diff.clone('ExtendedDiff')
|
||||
//
|
||||
// // add a new type...
|
||||
// ExtendedDiff.types.set(SomeType, {
|
||||
// ...
|
||||
// })
|
||||
//
|
||||
// // add a new synthetic type...
|
||||
// ExtendedDiff.types.set('SomeOtherType', {
|
||||
// check: function(..){ .. },
|
||||
// ...
|
||||
// })
|
||||
//
|
||||
// // remove an existing type...
|
||||
// ExtendedDiff.types.delete('Text')
|
||||
//
|
||||
//
|
||||
var DiffClassPrototype = {
|
||||
// system meta information...
|
||||
format: FORMAT_NAME,
|
||||
version: FORMAT_VERSION,
|
||||
// encapsulate the low-level types...
|
||||
types: Types,
|
||||
|
||||
// XXX PROTOTYPE -- uses Types...
|
||||
cmp: function(A, B){
|
||||
return Types.clone().cmp(A, B) },
|
||||
// create a new diff constructor with a detached handler set...
|
||||
clone: function(name){
|
||||
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){
|
||||
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 = {
|
||||
// system meta information...
|
||||
get format(){
|
||||
@ -1550,24 +1555,25 @@ var DiffPrototype = {
|
||||
options: null,
|
||||
diff: null,
|
||||
|
||||
// XXX PROTOTYPE -- uses Types...
|
||||
__init__: function(A, B, options){
|
||||
// XXX should we add a default options as prototype???
|
||||
options = this.options = options || {}
|
||||
this.structure = options.tree_diff ? 'tree' : 'flat'
|
||||
this.placeholders = {
|
||||
NONE: options.NONE || Types.NONE,
|
||||
EMPTY: options.NONE || Types.EMPTY,
|
||||
NONE: options.NONE
|
||||
|| 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???
|
||||
this.diff = arguments.length == 0 ?
|
||||
null
|
||||
: options.tree_diff ?
|
||||
types.diff(A, B, options)
|
||||
: types.flatten(Types.diff(A, B, options), options)
|
||||
diff.diff(A, B, options)
|
||||
: diff.flatten(diff.diff(A, B, options), options)
|
||||
},
|
||||
|
||||
// XXX should this be a deep copy???
|
||||
@ -1587,19 +1593,16 @@ var DiffPrototype = {
|
||||
},
|
||||
|
||||
// NOTE: this will not mutate this...
|
||||
// XXX PROTOTYPE -- uses Types...
|
||||
reverse: function(obj){
|
||||
var res = this.clone()
|
||||
res.diff = Types.reverse(this.diff)
|
||||
res.diff = this.constructor.types.reverse(this.diff)
|
||||
return res
|
||||
},
|
||||
|
||||
// XXX PROTOTYPE -- uses Types...
|
||||
check: function(obj){
|
||||
Types.clone().check(this.diff, obj) },
|
||||
// XXX PROTOTYPE -- uses Types...
|
||||
return this.constructor.types.check(this.diff, obj) },
|
||||
patch: function(obj){
|
||||
return Types.patch(this, obj) },
|
||||
return this.constructor.types.patch(this, obj) },
|
||||
unpatch: function(obj){
|
||||
return this.reverse().patch(obj) },
|
||||
|
||||
@ -1625,6 +1628,30 @@ object.makeConstructor('Diff',
|
||||
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