serialize.js/README.md
Alex A. Naanou 7b994416cd docs...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2026-01-17 14:43:29 +03:00

5.8 KiB

serilize.js: Extended JSON serilization

This extends the default JSON serialization adding the following:

  • Recursive data structure serialization
  • undefined/NaN serialization
  • 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:

  • indent controls 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)
  • depth if given is a number of indent's, used to set top level indent depth of the returned string, this can be useful when pretty-printing or nesting the output. Default: 0
  • min_length_ref sets the minimal length of a string or big-int value for referencing when encountered repeatedly. If set to 0 or Infinity referencing of strings and big-ints will be is disabled. Default: 'MIN_LENGTH_REF'
  • functions if 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