1.0.5 • Published 3 years ago

robust-serialization v1.0.5

Weekly downloads
-
License
ISC
Repository
-
Last release
3 years ago

Introduction to Robust Serialization and Deserialization.

  • Human-readability is a main consideration.
    • Stringifications and Serializations are very nicely formatted.
  • Programmer defined ES5 and ES6 classes supported
  • Circular/Duplicate references supported
  • Property descriptors supported.
  • Functions supported (but you need to know about evaluators).
  • Getter/Setters supported (but you need to know about evaluators).
  • All data types supported (*)
    • All Primitives
    • Boolean
    • Number
    • String
    • Date
    • RegExp
    • Array
    • All Typed Arrays
    • All Error Classes
    • Map
    • Set
    • DataView
    • ArrayBuffer
    • Buffer
    • Infinite Complexity Supported
      • E.g., Sets whose members are Maps whose keys are ArrayBuffers and values are typed arrays. The Set can also have properties that are DataViews whose properties are Maps whose properties are Sets.
      • Circular and duplicate references can have ends in the members of a Set, or the keys and values of a Map.

(*) OK! So the caveat is that symbols, WeakMaps, and WeakSets can not be serialized because their internal states can not be read by the programmer.

Installation and Usage

npm install robust-serialization

const{stringify, serializeSimpleData, serializeFData, serializeClassData, 
deserialize, compareObjects} = require('robust-serialization')

Exports

ExportDescription
stringify(x)very nicely formatted display or dump of x
serializeSimpleData(x)wrapper around stringify for serializing simple data x
serializeFData(x)wrapper around stringify for serializing Fdata x
serializeClassData(x)wrapper around stringify for serializing class data. used to serialize programmer defined classes
compareObjects(x,y)uses stringify to verify that various stringifications of x and y are the same. If true, it is highly likely that x and y are deep copies of each other
deserializecall on result of serializeSimpleData, serializeFData, or serializeClassData

How to Serialize/Deserialize Programmer Defined ES5 classes

The following is just an outline. It's not complicated so just follow it. For a super wild example with lots of circular references go to node_modules/robust-serialization/Tests/2-test-ES5-Class

function Foo(x,y)
{
    //The variables could be functions. 
    var a = ...;
    const b = ...;
    let c = ...;

    (function nestedFunction(x,y,z)
    {
        // No class methods defined inside nestedFunction.
        // Changes to variables of the class allowed.
        // Well it's actually OK if the method is 
        // context equivalent to a method written
        // outside. E.g., a method here is ok as
        // long as it doesn't depend on the local x,y,z. 
    })(5,7);

    this.serialize = function()
    {
        // all variables report to the context object. $this should come first.
        var cleanContextObject = {this$:this, a:a, b:b, c:c, x:x, y:y};
        return serializeClassData(cleanContextObject);

    }
}

    // write deserialization function immediately after constructor
    // so both have the same outer context.  

    Foo.deserialize(str)
    {
        return (function ()
        {
            this.evaluator = function(){return eval('('+ arguments[0] +')');};
            this.contextObject = deserialize(str, this.evaluator,
                Object.create(Foo.prototype), "Foo");
            var a = this.contextObject.a;
            const b = this.contextObject.b;
            let c = this.contextObject.c;
            var x = this.contextObject.x;
            var y = this.contextObject.y;
            return this.contextObject.this$
        }).call({});
    } 
    
    const x = new Foo(5,7)
	const y = x.serialize();
	const z = Foo.deserialize(y);
	log.console(compareObjects(x,z)); // true. z is a deep copy of x.

Serialize/Deserialize Programmer Defined ES6 classes

The following is just an outline. For a super wild example with lots of circular references go to node_modules/robust-serialization/Tests/3-test-ES6-Class

class Foo
{
	#F;        // defined in #initialize
	#G = ...; // depends on variables outside the class definition
	#H = ...; // doesn't depend on variables in constructor/initializer, and
	          // doesn't depend on variables outside the class definition.
			
	#initialize(x,y)
	{
		var a = ...;
		const b = ...;
		let c = ...;
		this.#F = ...;
			
        (function nestedFunction(x,y)
        {
            // no class methods defined/modified inside any 
            // nestedFunction. changes to variables of the class allowed
        })(5,7);
	}
			
	constructor(x,y)
	{
		if(arguments[0] === defaultConstructorSymbol) return;
		this.#initialize(x,y); 		
		
		// Don't write constructor code here instead of using #initialize.
		// Variable declarations and function definitions are hoisted, 
		// which might cause a memory leak, when the default constructor 
		// is used. 		
	}		
		
	this.serialize = function()
	{
		var cleanContextObject = {this$:this, a:a, b:b, c:c, x:x, y:y, 
		"F":this.#F, "#G":this.#G}; // Include "#H":this.#H if you want.
		
		return serializeClassData(cleanContextObject);
	} 	
		
	static deserialize = function(str)
	{
		return (function ()				
		{					
			this.evaluator = function(){return eval('('+ arguments[0] +')');};
			
			this.contextObject = deserialize(str, this.evaluator, 
			new foo(defaultConstructorSymbol), "Foo");
			
			var a = this.contextObject.a;
			const b = this.contextObject.b;
			let c = this.contextObject.c;
			var x = this.contextObject.x;
			var y = this.contextObject.y;
			
			this.contextObject.this$.#F = this.contextObject['#F'];
			this.contextObject.this$.#G = this.contextObject['#G'];
			
			return this.contextObject.this$
		}).call({});	
	}		
}	
	
const x = new Foo(5,7)
const y = x.serialize();
const z = deserialize(y);
log.console(compareObjects(x,z)); // true

Serialize/Deserialize Simple Data

An element is simple data if every node in its object tree including internal nodes of Sets (members) and Maps (keys and values) are one of the following.

  • a primitive, excluding symbols
  • a class instance of a built-in data class excluding WeakSets, WeakMaps and Functions
  • an object x one degree away from Object.prototype or one degree away from null
    • That is Object.getPrototypeOf(x) is Object.prototype or null.
let x = {q:100}, y = {q:101};
x.a = y;
y.b = x;
let z = {M:x, N:y};

// Dump z: stringify(z) is the following string 
// (quotes not included) 

Object
{
        M:Object
        {
                q:100,
                a:Object
                {
                        q:101,
                        b:@(2)Object(top.M) // circular reference detected
                }
        },
        N:#Object(top.M.a)  // duplicate reference detected
}

// serialize z: serializeSimpleData(z) is the string 
// (property descriptors are encoded within <>)

Object
{
        M:Object <15>
        {
                q:100 <15>,
                a:Object <15>
                {
                        q:101 <15>,
                        b:@(2)Object(top.M) <15>
                }
        },
        N:#Object(top.M.a) <15>
}

// deep copy z through serialization/deserialization

let cz = deserialize(serializeSimpleData(z));

// verify cz is a deep copy of z.

console.log(compareObjects(z,cz)); // true

Dump the Window

To see a nicely formatted dump/stringification of the browser window with the stringify function go to https://meouzer.github.io/

Serializaiton/Deserialization of FData

We will not go over serialization/deserialization of Fdata since the programmer will have no to little use for it. If the reader is curious, go to meouzer.github.io and do your own research. See the articles JavaScript Stringification of Objects and Copying Functions with Evaluators part I and II.

Testing (is extensive)

Navigate to node_modules/robust-serialization/Tests and run the n_test.xxx files in the IDE. Or cd to node-modules/robust-serialization/Tests and npm the test files.

Patches

1.0.0 to 1.0.5 are patches because of newbie publishing mistakes.

1.0.5

3 years ago

1.0.4

3 years ago

1.0.3

3 years ago

1.0.2

3 years ago

1.0.1

3 years ago

1.0.0

3 years ago