added object path writer/reader...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2021-06-08 19:26:33 +03:00
parent 1013af0e47
commit 1ad987190d

142
diff2.js
View File

@ -34,6 +34,12 @@ var types = require('ig-types')
// //
/*********************************************************************/ /*********************************************************************/
var EMPTY =
module.EMPTY =
//Symbol.EMPTY =
Symbol('EMPTY')
// XXX need a way to uniquely serilaize this to a string path... // XXX need a way to uniquely serilaize this to a string path...
// ...or some other way to use it in a convinient manner... // ...or some other way to use it in a convinient manner...
var CONTENT = var CONTENT =
@ -344,7 +350,9 @@ var serializePathElem = function(p, i, l){
: typeof(p) == 'string' ? : typeof(p) == 'string' ?
p.replace(/([\/:])/g, '\\$1') p.replace(/([\/:])/g, '\\$1')
: p } : p }
var serializePath = function(p){ var path2str =
module.path2str =
function(p){
return '/'+ p return '/'+ p
.map(serializePathElem) .map(serializePathElem)
.reduce(function(res, e){ .reduce(function(res, e){
@ -354,34 +362,35 @@ var serializePath = function(p){
res.push(e) res.push(e)
return res }, []) return res }, [])
.join('/') } .join('/') }
/*/ XXX might also be a good idea to serialize the path into an
// arbitrary length as we always have exactly one value, e.g.:
// [ '/path/to/map', 'CONTENT', 'path/in/content', 123] // XXX do we handle @key here???
var serializePathElem = function(p, i, l){ var deserializePathElem = function(p){
return typeof(p) == 'object' ? return /[^\\]:CONTENT$/.test(p) ?
JSON.stringify(p) [p.replace(/(?<!\\):CONTENT$/, ''), module.CONTENT]
// quote special chars... : [p] }
: typeof(p) == 'string' ? // XXX should we hanve relative paths????
p.replace(/([\/])/g, '\\$1') var str2path =
: p } module.str2path =
var serializePath = function(p){ function(str){
return p return str instanceof Array ?
.map(serializePathElem) str
.reduce(function(res, e){ : (str
e === module.CONTENT ? .replace(/^\//, '')
res.splice(res.length, 0, 'CONTENT', '') .split(/\//g)
: (res[res.length-1] += '/'+ e) .map(deserializePathElem)
return res }, ['']) } .flat()) }
//*/
var serializePaths = var serializePaths =
module.serializePaths = module.serializePaths =
types.generator.iter types.generator.iter
.map(function([p, v]){ .map(function([p, v]){
return v instanceof Array && v[0] == 'LINK' ? return v instanceof Array && v[0] == 'LINK' ?
// link... // link...
[serializePath(p), [path2str(p),
'LINK', serializePath(v[1])] 'LINK', path2str(v[1])]
: [serializePath(p), v] }) : [path2str(p), v] })
// remove attributes from object metadata... // remove attributes from object metadata...
@ -414,6 +423,93 @@ function(...attrs){
// XXX construct... // XXX construct...
//
// atPath(root, path)
// -> value
//
// atPath(root, path, value)
// -> value
//
// NOTE: to set this needs the full basepath to exist...
//
// XXX overcomplicated...
// XXX add support for deleting / writeing EMPTY
var atPath =
module.atPath =
function(root, path, value){
path = str2path(path)
// get value at path...
var content = false
var base
var target = path
.reduce(function(cur, p){
// CONTENT...
if(p === module.CONTENT){
// NOTE: indicate to the next iteration that we'll need
// to use map/set API to get/set the value...
content = true
base = cur
return cur }
// value in content...
if(content){
return cur instanceof Set ?
[...cur][p]
// map key...
: p.slice(-4) == '@key' ?
[...cur][p.slice(0, -4)][0]
// map value...
: [...cur][p][1] }
content = false
base = cur
return cur[p] }, root)
// get...
if(arguments.length <= 2){
return target }
// write attr...
if(!content){
value === module.EMPTY ?
(delete base[path.last()])
: (base[path.last()] = value)
// XXX should we return value or base???
// ...should we return target when writing EMPTY
return value}
var index = path.last()
// write set item...
if(base instanceof Set){
value === module.EMPTY ?
base.delete(target)
:index == base.size ?
base.add(value)
: base.replaceAt(index, value)
// XXX should we return value or base???
// ...should we return target when writing EMPTY
return value }
// write map item/key...
var isKey = index.slice(-4) == '@key'
index = isKey ?
index.slice(0, -4)
: index
var key = atPath(root,
path
.slice(0,-1)
.concat([index +'@key']))
value === module.EMPTY ?
base.delete(key)
: isKey ?
base.replaceKey(key, value)
: base.set(key, value)
// XXX should we return value or base???
// ...should we return target when writing EMPTY
return value }