Skip to content
/ arson Public

Efficient encoder and decoder for arbitrary objects

License

Notifications You must be signed in to change notification settings

benjamn/arson

Folders and files

NameName
Last commit message
Last commit date
Jan 30, 2018
Jan 28, 2016
Feb 26, 2016
May 9, 2018
Jan 28, 2016
Mar 18, 2017
May 11, 2016
Mar 18, 2017
Nov 2, 2018

Repository files navigation

arson Build Status Greenkeeper badge

ARbitrary Structured Object Notation

Not to be confused with the criminal act of deliberately setting fire to property!

JSON is great until you need to encode an object with circular references:

var obj = {};
obj.self = obj;
JSON.stringify(obj); // throws

Throwing an exception is lame, but even worse is muddling along as if everything is ok:

var a = {};
var b = { foo: 42 };
a.x = a.y = b;
var c = JSON.parse(JSON.stringify(a));
assert.strictEqual(c.x, c.y); // fails

We need an object notation that supports circular and repeated references.

That's where ARSON comes in:

var a = {};
var b = { foo: 42 };
a.x = a.y = b;
var c = ARSON.parse(ARSON.stringify(a));
assert.strictEqual(c.x, c.y); // no problem!

ARSON is compact, often even more compact than JSON, because repeated objects are defined only once:

var a = {};
var b = { foo: 42 };
a.x = a.y = b;
ARSON.stringify(a); // [{"x":1,"y":1},{"foo":2},42] vs.
                    // {"x":{"foo":42},"y":{"foo":42}}

But that's not all! ARSON can also encode undefined, thanks to the fact that [][-1] is always undefined:

> ARSON.encode({foo:undefined})
'[{"foo":-1}]'
> ARSON.decode(_)
{ foo: undefined }

It can also encode array holes:

> ARSON.encode(Array(3).concat([4, 5]))
'[[-2,-2,-2,1,2],4,5]'
> ARSON.decode(_)
[ , , , 4, 5 ]

Buffers:

> ARSON.encode(new Buffer("asdf"))
'[["Buffer","YXNkZg==","base64"]]'
> ARSON.decode(_)
<Buffer 61 73 64 66>

Dates:

> ARSON.encode(new Date)
'[["Date","2016-02-02T00:25:36.886Z"]]'
> ARSON.decode(_)
Mon Feb 01 2016 19:25:36 GMT-0500 (EST)

RegExps:

> ARSON.encode(/asdf/img)
'[["RegExp","asdf","img"]]'
> ARSON.decode(_)
/asdf/gim

Sets:

> s = new Set
Set {}
> s.add(s)
Set { Set { Set { [Object] } } }
> ARSON.encode(s)
'[["Set",0]]'
> ARSON.decode(_)
Set { Set { Set { [Object] } } }
> _.has(_)
true

and Maps:

> m = new Map
Map {}
> m.set(1234, m)
Map { 1234 => Map { 1234 => Map { 1234 => [Object] } } }
> m.set(m, 5678)
Map {
  1234 => Map {
    1234 => Map {
      1234 => [Object],
      [Object] => 5678
    },
    Map {
      1234 => [Object],
      [Object] => 5678
    } => 5678
  },
  Map {
    1234 => Map {
      1234 => [Object],
      [Object] => 5678
    },
    Map {
      1234 => [Object],
      [Object] => 5678
    } => 5678
  } => 5678
}
> ARSON.encode(m)
'[["Map",1,2],[3,0],[0,4],1234,5678]'
> ARSON.decode(_)
Map {
  1234 => Map {
    1234 => Map {
      1234 => [Object],
      [Object] => 5678
    },
    Map {
      1234 => [Object],
      [Object] => 5678
    } => 5678
  },
  Map {
    1234 => Map {
      1234 => [Object],
      [Object] => 5678
    },
    Map {
      1234 => [Object],
      [Object] => 5678
    } => 5678
  } => 5678
}
> _.get(_.get(1234)) === 5678
true