Home

Awesome

lave Build Status

lave is eval in reverse; it does for JavaScript what JSON.stringify does for JSON, turning an arbitrary object in memory into the expression, function, or ES6 module needed to create it.

Why not just use JSON.stringify?

JSON is great data transport, but can only handle a subset of the objects expressible in a JavaScript runtime. This usually results in lossy serializations at best, and TypeError: Converting circular structure to JSON at worst. While we can get around such issues by writing JavaScript code to parse this JSON back into the structures we want, now we have to ship that code out of band, which can be a headache.

Instead of writing a parser for a new language that can represent arbitrary JavaScript runtime values, I built lave to use the best language for the job: JavaScript itself. This allows it to handle the following structures that JSON can't.

TypeJavaScriptJSON.stringifylave
Circular referencesa={}; a.self=a:x: TypeError:white_check_mark: var a={};a.self=a;a
Repeated referencesa={}; [a, a]:warning: [{}, {}]:white_check_mark: var a={};[a,a]
Global objectglobal:x: TypeError:white_check_mark: (0,eval)('this') ?
Built-in objectsArray.prototype:warning: []:white_check_mark: Array.prototype
Boxed primitivesObject('abc'):warning: "abc":white_check_mark: Object('abc')
Functions[function(){}]:warning: [null]:white_check_mark: [function(){}]
Datesnew Date(1e12):warning: "2001-09-09T01:46:40.000Z":white_check_mark: new Date(1000000000000)
NaNNaN:warning: null:white_check_mark: NaN
InfinityInfinity:warning: null:white_check_mark: Infinity
Sets and Mapsnew Set([1,2,3]):warning: {}:white_check_mark: new Set([1,2,3])
Sparse arraysa=[]; a[2]=0; a:warning: [null,null,0]:white_check_mark: var a=[];a[2]=0;a
Object propertiesa=[0,1]; a.b=2; a:warning: [0,1]:white_check_mark: var a=[0,1];a.b=2;a
Custom prototypesObject.create(null):warning: {}:white_check_mark: Object.create(null)

Keep in mind that there are some things that not even lave can stringify, such as function closures, or built-in native functions.

Example

This command...

node << EOF
  var generate = require('escodegen').generate
  var lave = require('lave')

  var a = [function(){}, new Date, new Buffer('A'), global]
  a.splice(2, 0, a)

  var js = lave(a, {generate, format: 'module'})
  console.log(js)
EOF

...outputs the following JavaScript:

var a = [
    function (){},
    new Date(1456522677247),
    null,
    Buffer('QQ==', 'base64'),
    (0, eval)('this')
];
a[2] = a;
export default a;

When would I want to use this?

How does lave work?

lave uses all of the syntax available in JavaScript to build the most concise representation of an object, such as by preferring literals ([1,2]) over assignment (var a=[];a[0]=1;a[1]=2). Here's how it works:

Installation

Please run the following command to install lave:

$ npm install lave

The library has been tested on Node 4.x and 5.x.

API

ast = lave(object, [options])

By default, lave takes an object and returns an abstract syntax tree (AST) representing the generated JavaScript. Any of the following options can also be specified:

Addenda