mirror of
https://github.com/flynx/diff.js.git
synced 2025-10-28 10:30:09 +00:00
rethinking the implementation...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
2f87b20612
commit
2b6442088c
179
diff2.js
Normal file
179
diff2.js
Normal file
@ -0,0 +1,179 @@
|
||||
/**********************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
**********************************************/ /* c8 ignore next 2 */
|
||||
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
||||
(function(require){ var module={} // make module AMD/node compatible...
|
||||
/*********************************************************************/
|
||||
|
||||
var types = require('ig-types')
|
||||
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
var HANDLERS =
|
||||
module.HANDLERS = {
|
||||
/*/ XXX
|
||||
// XXX need to be able to stop processing handlers...
|
||||
// for example when handling 'text' we do not need to also call
|
||||
// 'value' too...
|
||||
// this can be done via:
|
||||
// - a-la evt.preventDefault()
|
||||
// - handler.final
|
||||
// - callback...
|
||||
example: {
|
||||
match: function(obj){
|
||||
return true },
|
||||
handle: function(obj){
|
||||
...
|
||||
return [key, value, next] },
|
||||
},
|
||||
//*/
|
||||
|
||||
value: {
|
||||
match: function(obj){
|
||||
return typeof(obj) != 'object' },
|
||||
handle: function(obj){
|
||||
return [[], obj] },
|
||||
},
|
||||
|
||||
object: {
|
||||
match: function(obj){
|
||||
return typeof(obj) == 'object' },
|
||||
handle: function(obj){
|
||||
return [[], {
|
||||
// XXX revise...
|
||||
type: obj.constructor.name,
|
||||
// XXX
|
||||
}] },
|
||||
},
|
||||
|
||||
// XXX do we need to also traverse/index the keys???
|
||||
// ...if yes then we'll need to somehow indicate a path to a key...
|
||||
// one way to do this is to add virtual paths and link to them...
|
||||
// ...i.e. a virtual path is any path starting from a virtual root
|
||||
// that can be linked from within the tree...
|
||||
containerEntries: {
|
||||
containers: [
|
||||
Set,
|
||||
Map,
|
||||
],
|
||||
// XXX should this be more generic and just check for .entries(..) ???
|
||||
match: function(obj){
|
||||
for(var type of this.containers){
|
||||
if(obj instanceof type){
|
||||
return true } } },
|
||||
handle: function(obj){
|
||||
// XXX for some reason the .entries() iterator does not have
|
||||
// the generaator methods -- we can't call obj.entries().map(..)...
|
||||
return [ [...obj.entries()]
|
||||
.map(function([k, v]){
|
||||
return [[k], v] }), ] },
|
||||
},
|
||||
|
||||
// XXX do we need to treat array keys as a special case???
|
||||
// XXX need to optionally treat special attributes...
|
||||
keys: {
|
||||
match: function(obj){
|
||||
return typeof(obj) == 'object' },
|
||||
handle: function(obj){
|
||||
return [ Object.entries(obj)
|
||||
.map(function([k, v]){
|
||||
return [[k], v] }), ] },
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
var getType =
|
||||
module.getType =
|
||||
function*(obj){
|
||||
// XXX
|
||||
}
|
||||
|
||||
|
||||
var getHandlers =
|
||||
module.getHandlers =
|
||||
function(obj, handlers=module.HANDLERS){
|
||||
return Object.entries(handlers)
|
||||
.filter(function([k, v]){
|
||||
return v.match(obj) })
|
||||
.map(function([k, v]){
|
||||
return v }) }
|
||||
|
||||
|
||||
|
||||
// XXX need a way to index the path...
|
||||
// ...and to filter paths by pattern...
|
||||
var handle =
|
||||
module.handle =
|
||||
function*(obj, path=[], options={}){
|
||||
// handle recursive structures...
|
||||
// XXX would be nice to index paths to make them unique...
|
||||
var seen = options.seen =
|
||||
options.seen || new Map()
|
||||
if(seen.has(obj)){
|
||||
// XXX revise format...
|
||||
yield ['LINK', seen.get(obj)]
|
||||
return }
|
||||
typeof(obj) == 'object'
|
||||
&& seen.set(obj, path)
|
||||
|
||||
// get compatible handler list...
|
||||
var cache = options.cache =
|
||||
options.cache || new Map()
|
||||
var type = getType(obj)
|
||||
var handlers =
|
||||
(type && cache.get(type))
|
||||
|| module.getHandlers(obj, options.handlers || module.HANDLERS)
|
||||
type
|
||||
&& cache.set(type, handlers)
|
||||
|
||||
// XXX might be a good idea to move this up (or into options) so as
|
||||
// not to define this on each call...
|
||||
// ...we'll need to somehow curry in the path which is now passed
|
||||
// via a closure...
|
||||
var subtree = function*(data){
|
||||
// a handler just returned a list of next objects to handle...
|
||||
if(data.length == 1){
|
||||
var next = data.pop()
|
||||
var p = path
|
||||
// a normal handler...
|
||||
} else {
|
||||
var [k, v, next] = data
|
||||
var p = path.concat(k)
|
||||
yield [p, v] }
|
||||
// process queued/next objects...
|
||||
yield* (next || [])
|
||||
.iter()
|
||||
.map(function*([k, v]){
|
||||
yield* handle(v, p.concat(k), options) }) }
|
||||
|
||||
// apply the handlers...
|
||||
yield* handlers
|
||||
.iter()
|
||||
.map(function*(handler){
|
||||
yield* handler.handle instanceof types.Generator ?
|
||||
handler.handle(obj, path, options)
|
||||
.map(subtree)
|
||||
: subtree(handler.handle(obj, path, options)) }) }
|
||||
|
||||
|
||||
// XXX need a better way to serialize the path...
|
||||
var shandle =
|
||||
module.shandle =
|
||||
handle
|
||||
.map(function([p, v]){
|
||||
return (
|
||||
// XXX revise...
|
||||
p == 'LINK' ?
|
||||
['LINK', '/'+ v.join('/')]
|
||||
: ['/'+ p.join('/'), v] ) })
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* vim:set ts=4 sw=4 : */ return module })
|
||||
Loading…
x
Reference in New Issue
Block a user