diff --git a/README.md b/README.md index 56f8751..d50cadb 100644 --- a/README.md +++ b/README.md @@ -188,8 +188,70 @@ Extensions to JSON: ### Structural paths +Paths are used for internal references in cases when objects are +encountered multiple times, e.g. in recursion. + +A path is an array of keys, the meaning of each key depends on the data +structure traversed: +- array -> number +- object -> string +- set -> number -- item order in set +- map -> pair of numbers -- the first indicates item order the second + if 0 selects the key, if 1 selects the value. + +Note that string path items are unambiguous and are always treated as +attributes. + +For examples see next section. + + ### Recursion and internal linking +If an object is encountered for a second time it will be serialized as +a reference by path to the first occurrence. + +An empty path indicates the root object. + +Format: +```bnf + ::= + ' '>' + + ::= + '[' ']' + + ::= + + | ',' + + ::= + + | +``` + +Example: +'''javascript +var o = [] +o.o = o + +// root object reference... +serialize(o) // -> '[]' + +// array item... +serialize([o]) // -> '[[]]' + +// set item... +// NOTE: the path here is the same as in the above example -- since we +// use ordered topology for paths sets do not differ from arrays. +serialize(new Set([o])) // -> 'Set([[]])' + +// map key... +serialize(new Map([[o, 'value']])) // -> 'Map([[[],"value"]])' + +// map value... +serialize(new Map([['key', o]])) // -> 'Map([["key",[]]])' +''' + ### null types diff --git a/serialize.js b/serialize.js index e44e8af..3dba9a0 100644 --- a/serialize.js +++ b/serialize.js @@ -380,8 +380,13 @@ module.eJSON = { && i == path.length-1){ return [path.slice(0, -1), obj] } - obj = obj instanceof Set ? + obj = + // special case: string key -> attribute... + typeof(k) == 'string' ? + obj[k] + : obj instanceof Set ? [...obj][k] + // takes two items off the path -- [intex, key/value]... : obj instanceof Map ? [...obj][k][path[++i]] : obj[k] } @@ -405,6 +410,12 @@ module.eJSON = { setItem: function(obj, path, value){ var [p, parent] = this._getItem(obj, path.slice(0, -1)) var k = path.at(-1) + + // special case: string kye -> attr... + if(typeof(k) == 'string'){ + parent[k] = value + return value } + if(parent instanceof Set){ var elems = [...parent] elems[k] = value