serilize.js: Extended JSON serilization
This extends the default JSON serialization adding the following:
- Recursive data structure serialization
undefined/NaNserialization- Serialization of
BigInt's,Set's,Map's - Function serialization (off by default)
- Deep and partial-deep cleen object copy
Possible differences to JSON output:
- Repeating long strings and BigInts are referenced by default instead of being reincluded in the output.
Motivation
This was originally built as a companion to a testing module for a programming class, illustrating several concepts, including: guaranteed clean isolation of data structures via serialization, instrumenting code and tooling design, basic parsing, among others.
Installation
For basic use:
$ npm install ig-serilaize
Or just download and drop serialize.js into your code.
serialize = require('ig-serialize')
Introduction
Serializing functions
Due to how JavaScript is designed it is not possible to trivially and
fully clone a function with all of it's references, .serilaize(..) will
not attempt to clone any state a function may have, this will lead to
loosing:
- Function closure
- Attributes set on the function or any of it's prototypes, including the
.__proto__value if it was changed.
Thus, care must be taken when serializing structures containing function.
API
serialize(..) / eJSON.stringify(..)
Serialize a JavaScript value into a JSON/eJSON string.
serialize(<value>)
eJSON.stringify(<value>)
-> <string>
More control:
serialize(obj, options){
serialize(obj, indent, depth=0, options){
-> <string>
Options format:
{
// pretty-printing indent...
// (default: undefined)
indent: undefined,
// outout root indent...
// (default: 0)
depth: 0,
// minimal referenced string/bigint length...
// (default: MIN_LENGTH_REF)
min_length_ref: MIN_LENGTH_REF,
// functions list...
// (default: undefined)
functions: undefined,
}
Supported options:
indentcontrols formatting and nested value indent, if set to a number that number of spaces will be used to indent nested values if given a string that string is used for indenting, note that only whitespace is supported currently. Default:undefined(disabled)depthif given is a number ofindent's, used to set top level indent depth of the returned string, this can be useful when pretty-printing or nesting the output. Default:0min_length_refsets the minimal length of a string or big-int value for referencing when encountered repeatedly. If set to0orInfinityreferencing of strings and big-ints will be is disabled. Default: 'MIN_LENGTH_REF'functionsif passed an array, encounterd functions will be pushed to it and stored in the output by index. Default:undefined
deserialize(..) / eJSON.parse(..)
Deserialize a JSON/eJSON into a value.
deserialize(<string>)
eJSON.parse(<string>)
-> <value>
Deserializing function is disabled by default as it can be a security risk if the eJSON came from an untrusted source.
Enable function deserialization:
deserialize(<string>, true)
eJSON.parse(<string>, true)
deserialize(<string>, {functions: true})
eJSON.parse(<string>, {functions: true})
-> <value>
Passing a function list (generated by serialize(<value>, {functions: <functions>}))
for deserialization:
deserialize(<string>, {functions: <functions>})
eJSON.parse(<string>, {functions: <functions>})
-> <value>
deepCopy(..)
deepCopy(<value>)
-> <value>
partialDeepCopy(..)
partialDeepCopy(<value>)
-> <value>
MIN_LENGTH_REF / <options>.min_length_ref
Defines the default minimum length of repeating string or bin-int to include as a reference in the output.
If set to 0, referencing will be disabled.
Default: 96
DEBUG
Format
The output of .serialize(..) is a strict superset of standard JSON,
while the input format is a bit more relaxed than in several details.
Extensions to JSON:
- Recursion
- undefined / NaN
- BigInt
- Map / Set
- Function
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:
<ref> ::=
'<REF' <path> '>'
<path> ::=
'[' <path-items> ']'
<path-items> ::=
<item>
| <item> ',' <path-items>
<item> ::=
<number>
| <string>
Example: '''javascript var o = [] o.o = o
// root object reference... serialize(o) // -> '[<REF[]>]'
// array item... serialize([o]) // -> '<REF[0]>'
// 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(<REF[0]>)'
// map key... serialize(new Map(o, 'value')) // -> 'Map([<REF[0,0]>],"value")'
// map value... serialize(new Map('key', o)) // -> 'Map("key",[<REF[0,1]>])' '''
null types
BigInt
Map / Set
Functions
Running tests
Get the development dependencies:
$ npm install -D
Run the tests:
$ npm test
To run the tests directly:
$ node ./test.js