Install from npm:
$ npm install --save @effectful/serialization
import * as S from "@effectful/serialization" const json = S.stringify(value) // .... const value = S.parse(str)
S.write takes JS objects and returns it encoded as
serializable value. It can deal with multiple references to same values,
including recursive references.
The root value must always be a plain object. Its properties values may have any type if there is its format description registered.
The library contains descriptors for Array/Set/Map/Symbol types and can be extended to support any other type if can be serialized.
S.stringify function is a
write followed by
The reverse direction is done by
S.read function. It takes a serializable object
write and returns its original value.
JSON.parse followed by
There is a descriptor structure used to specify how to write and read values.
When writing, the descriptor is looked up in
property or in the library's internal map. The write routine is responsible to
output a string for type's name in
"#type" property of output object. It is
used to lookup corresponding descriptor for reading.
The descriptor is registered using
The library will generate unique names based on the name property in descriptor if there are collisions. This means sending and receiving sides must call the register function in the same order if there are names collisions chances.
More information in API docs.
Some values cannot be serialized, e.g.
They may be registered as opaque values. This way if there is a reference to
such opaque value in serialized value the library outputs the reference name
rather than the value. This works if same (corresponding) objects registered
with the same name on sending and receiving sides. Typically they are module's
top-level variables with functions or classes declarations.
To register opaque values call
their first argument is the value, and the second argument is its name. The name
may be omitted for
S.regOpaqueObject the library will try to guess it. If it
is a function declaration, it will use its name, for example.
The third argument specifies additional options (see
in the API).
By default the output will contain properties set or changed in object after
S.regOpaqueObject call. This can be disabled by setting
the third argument to disable any property output. Or
to disable storing the original values snapshot (thus all properties will be
output). Reads mutate the registered objects.
S.regOpaqueObject will set
[S.descriptorSymbol] property in the
S.regOpaquePrim will store the value in a library's internal map.
S.regConstructor to make objects with JS prototype inheritance
serializable. It gets constructor function as its first argument and optional
name as the second. The constructor function's name will be used if the name
argument isn't specified.
It will register the constructor's prototype as an opaque object. This way if all the method are only referenced in prototype and all the data referenced in the object is serializable the object is serializable.
The function's source code in JS is simple to write to a string (with
method) and simple to read (using
Function constructor), however, there are two
De-serializing functions by calling
new Function(...) is apparently very
dangerous. Developers must be absolutely sure there is absolutely no data
received from outside. And it is quite difficult to guarantee.
Even if the security isn't a concern for the project, this way of
reading/writing function will lose all information about closure captured
variables. It is not even possible to serialize a result of
Function.prototype.bind. This way the function can only get state data either
from global variables (obviously not an option) or using
this reference if the
function is some object's method.
If these limitations are too heavy, there is
closure conversion transform pass. It
converts closures into objects with
call method. This may solve all the
limitations. There are no needs to store function's text. Some unique
identifier, say SHA1 is enough. And since there are no closures after
conversions object's translation will work well.
The transform is in Proof Of Concept state name, but will be moved into a separate library SOON.
The package contains proof-of-concept DOM serialization. It is disabled by default. To enable:
import * as SDOM "@effectful/serialization/dom" SDOM.track()
It is very limited for now, requires deeper wrapping. It will
store/restore elements, events and
document with all children,
attributes, and properties of DOM values with some limitations. Events
will keep only their initialization options with calculated properties
target) not initialized.
Distributed under the terms of The MIT License (MIT).