JavaScript serialization library that can handle cycles and strives to preserve user-defined classes.
npm install yaserializerJSON.stringify(), and the much less well-known HTML Structured Clone algorithm that's used to pass object graphs between Workers.
Object.prototype.toString accessing the inaccessible [[Class]] property is particularly awesome, for example), and they require some finesse to replicate. I want to support classes but without requiring a no-args constructor to give me an empty object to populate. Object graphs need to be preserved, including cycles. I want to support the new datatypes where it makes sense to (WeakMap and WeakSet don't make sense to deserialize), and properly handle extensions of any built-in types (not just Object!).
# prefix on property names. There are hooks provided to set custom serializers for this very scenario.
Reflect metadata API. With this, you can write self-registering classes that can mark fields as non-serialized, plumb in custom serialization methods, and set up post-deserialization functions.
use_packed_format to true.
javascript
class ExcludedMembers {
constructor() {
this.name = 'always included';
this.$invocation_ignored = 'excluded by invocation options';
this.$class_ignored = 'excluded by class options';
this.$global_ignored = 'excluded by global options';
this._cache = [];
this.$someOtherStuff = 0;
}
}
const global_options = { ignore: '$global_ignored' };
const ser = new yas.yaserializer([], global_options);
const class_options = { ignore: /\$class.*/ };
ser.make_class_serializable(ExcludedMembers, class_options);
const obj = new ExcludedMembers();
obj._cache = [1, 2, 3];
const invocation_options = { ignore: '$invocation_ignored' };
const serialized_form = ser.serialize(obj, invocation_options);
const reconstructed = ser.deserialize(serialized_form);
`
Decorators, custom serialization methods, in TypeScript:
`typescript
@yas.serializable
class Test {
field: string;
@yas.unserializable
cache: any[];
@yas.unserializable
version: number;
constructor() {
this.field = 'Hello, world!';
this.cache = [];
this.version = 1;
}
// serializer method returns a pair. the first element
// contains the custom serialized data.
// the second is 'true' to augment the custom serialization
// with the usual brute force property-by-property
// serialization, 'false' to skip it and rely only on
// the custom serialized data.
@yas.serializer
static serialize(obj) {
return [obj.field + ' serialized form', false];
}
// structured is a hollowed out object of the right type
// but without any of its members. destructured is the
// custom serialized data created by the serializer method.
// return true to also use built-in propery-by-property
// deserialization; false to skip it.
@yas.deserializer
static deserialize(structured, destructured) {
structured.field = destructured + ' reconstituted';
return false;
}
// executed after the entire object graph is deserialized.
@yas.deserialize_action
rebuild() {
this.cache = ['rebuilt'];
this.version = 20;
}
};
``