npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

sermat

v0.1.1

Published

Sermat is a serialization format, similar to JSON.

Downloads

38

Readme

Sermat.js

Sermat is a serialization and data exchange format, similar to JSON. It is meant to be used when dealing with heavily marshalled interfaces separating the application being developed. Examples of this include the communtication between web workers or those and the rendering thread in browsers, or between iframes.

Format

Sermat goals are the following:

  • Extend JSON: All valid JSON strings must be also valid Sermat strings, although the viceversa may not be true.

  • Allow custom types: Sermat must be able to deal with instances of types other than the basic Javascript types (booleans, numbers, strings, arrays and object literals). Users must be able to register types to be used (like Date or user defined classes), in order to serialize them properly and obtain an equivalent instance after parsing.

  • Handle structures with complicated references: Users must be able to serialize (and afterwards properly materialize) data structures that are not strictly trees; i.e. values may be referenced more than once, even if that means a cycle of references.

Minor changes

Sermat addresses some minor quirks of JSON. Firstly, serializing undefined values will raise an error by default. The modifier onUndefined can be set to transform undefined values in a consistent manner.

JSON.stringify(undefined)
// Results in undefined
Sermat.serialize(undefined)
// Throws TypeError("Sermat.serialize: Cannot serialize undefined value!")
Sermat.serialize(undefined, { onUndefined: null })
// Results in "null"
Sermat.serialize(undefined, { onUndefined: MyErrorType })
// Throws MyErrorType("Sermat.serialize: Cannot serialize undefined value!")
Sermat.serialize(undefined, { onUndefined: (void 0) })
// Results in "undefined".

JSON.stringify({ a: undefined })
// Results in "{}"
Sermat.serialize({ a: undefined }, { onUndefined: null })
// Results in "{a:null}"
JSON.stringify([undefined])
// Results in "[null]"
Sermat.serialize([undefined], { onUndefined: null })
// Results in "[null]"

Infinity and NaN values are allowed, as well as comments, using the block comment syntax of Javascript. Keys in object literals don't have to be between double quotes if they comply with Javascript's rules for identifiers and if all characters are in the range [\x00-\x7F] (dots and dashes are also allowed).

JSON.stringify(-Infinity)
// Results in 'null'.
Sermat.ser(Infinity)
// Results in '-Infinity'.
JSON.stringify(NaN)
// Results in 'null'.
Sermat.ser(NaN)
// Results in 'NaN'.
JSON.stringify({x:1,"y.z":2,"@":3});
// Results in '{"x":1,"y.z":2,"@":3}'.
Sermat.ser({x:1,"y.z":2,"@":3});
// Results in '{x:1,y.z:2,"@":3}'.

Constructions

One of the more important aspects of Sermat are constructions: a way of customizing serialization and materialization for particular types. The user may register custom methods for serializing and materializing objects built with a given constructor (e.g. Date). These objects will be written in text form in a similar way a function call is written in Javascript.

Sermat.serialize(new Date());
// Results like this: 'Date(2015,6,5,6,33,47,123)'.
Sermat.serialize(/\d+/g);
// Results in: 'RegExp("\\\\d+","g")'.

When parsed, the result will be a properly initialized instance of the corresponding type. Some Javascript base types are implemented out-of-the-box. Implementations for custom types can be defined with Sermat.register or adding a __SERMAT__ member to the constructor. In the following example the identifier is defined to be mylib.Point2D, instead of the default Point2D.

function Point2D(x, y) {
	this.x = +x;
	this.y = +y;
}
Sermat.serialize(new Point2D(44, 173)); // Raises "Sermat.record: Unknown type \"Point2D\"!"
Point2D.__SERMAT__ = {
	identifier: "mylib.Point2D",
	serializer: function serialize_Point2D(obj) {
		return [obj.x, obj.y];
	},
	materializer: function materialize_Point2D(obj, args) {
		return args && (new Point2D(+args[0], +args[1]));
	}
};
Sermat.include(Point2D);
Sermat.serialize(new Point2D(44, 173)); // Results in: 'mylib.Point2D(44,173)'.

The serializer function must return the list of values to put between parenthesis. The materializer function will rebuild the instance using these values. Further details are explained later on.

Constructions are also used in some situations for native Javascript. For example when values like true, 12 or [1,2,3] are treated as objects.

Sermat.ser(Object(true));
// Results in "Boolean(true)"
Sermat.ser(Object.assign(Object(true), {x:1}));
// Results in "Boolean(true,{x:1})".
Sermat.serialize(Object.assign([1,2,3], {x:1}));
// Results like this: 'Array([1,2,3],{x:1})'.

References

Sermat by default does not allow objects to be serialized more than once. Having the same object as a component in more than one place causes an error. For example:

var obj1 = {a: 7};
Sermat.serialize([obj1, obj1]);
// Raises "Sermat.serialize: Repeated reference detected!"

This behaviour can be changed in two ways. The first one is simply to allow values to be serialized more than once, like JSON does.

JSON.stringify([obj1, obj1]);
// Results in '[{"a":7},{"a":7}]'.
Sermat.serialize([obj1, obj1], { mode: Sermat.REPEAT_MODE });
// Results in '[{a:7},{a:7}]'.

The second one is part of another important feature called bindings. This is a syntax that allows to bind values to identifiers (starting with $) so they can be reused in another place. When parsed the resulting data structure is an acyclic graph instead of a tree.

Sermat.serialize([obj1, obj1], { mode: Sermat.BINDING_MODE });
// Results in '$0=[$1={a:7},$1]'.

Circular references are not supported by only allowing bindings. To make this work, circular references have to be allowed explicitly.

obj1.b = obj1;
Sermat.serialize([obj1, obj1], { mode: Sermat.BINDING_MODE });
// Raises "Sermat.serialize: Circular reference detected!"
Sermat.serialize([obj1, obj1], { mode: Sermat.CIRCULAR_MODE });
// Results in '$0=[$1={a:7,b:$1},$1]'.

Circular reference support in constructions requires the materializer functions to follow this protocol. If a new instance must be built the obj argument will be null, else it will have an instance already built to initialize. If an empty instance must be built the args argument will be null, else it will have the arguments for the objects constructor (either with or without new).

When a construction is being parsed (after the identifier and before its arguments) the corresponding materializer is called without arguments (obj and args both equal to null). If a new empty instance can be built it must be returned. The materializer will be called again later (after the arguments have been parsed) with obj equal to this result, so the new instance can be properly initialized. If the materializer cannot build an empty instance, it must returns null. This defers building the new object to after the arguments have been parsed, but then circular references cannot be properly parsed.

This example show both cases. It uses the sermat function, which basically serializes a value and then materializes it back, effectively cloning it.

function Refs(refs) {
	this.refs = Array.isArray(refs) ? refs : refs ? [refs] : [];
}
Refs.ALLOW_EMPTY_INSTANCES = false;
Sermat.register({
	type: Refs, 
	serializer: function serialize_Refs(obj) {
		return obj.refs;
	},
	materializer: function materialize_Refs(obj, args) {
		if (args === null) {
			return Refs.ALLOW_EMPTY_INSTANCES ? (new Refs()) : null; 
		} else if (obj !== null) {
			Refs.call(obj, args);
			return obj;
		} else {
			return new Refs(args);
		}
	}
});
var refs1 = new Refs(obj1);
refs1.refs.push(refs1);
Sermat.mode = Sermat.CIRCULAR_MODE;
Sermat.sermat(refs1); // Raises "Sermat.materialize: '$xx' is not bound at ...!".
Refs.ALLOW_EMPTY_INSTANCES = true;
Sermat.sermat(refs1); // Returns a copy of refs1.

Library

The library has many versions available for browsers, node, AMD and UMD. Sermat is the module, a singleton and a constructor of serializers and materializers.

Definitions

Sermat objects have a serialize or ser method to serialize values, which is the equivalent to JSON.stringify. The materialize or mat method is used to parse and rebuild a serialized value, which is equivalent to JSON.parse. The Sermat objects have a set of modifiers to the behaviours of these methods:

  • onUndefined=TypeError: If it is a constructor for a subtype of Error, it is used to throw an exception when an undefined is found. If it is other type function, it is used as a callback. Else the value of this modifier is serialized as in place of the undefined value, and if it is undefined itself the undefined string is used.

  • autoInclude: If true forces the registration of types found during the serialization, but not in the construction registry.

  • useConstructions=true: If false constructions (i.e. custom serializations) are not used, and all objects are treated as literals (the same way JSON does). It is true by default.

  • climbPrototypes=true: If true, every time an object's constructor is not an own property of its prototype, its prototype will be serialized as the __proto__ property.

  • pretty=false: If true the serialization is formatted with whitespace to make it more readable.

Modifiers can also be overriden in the second argument of the methods.

Pretty printing

The serializer by default produces the text in a compressed form. A more human friendly version of this text can be generated with the pretty option. Calling Sermat.ser({a:[1,2,3],b:/\w+/i}) results like this:

{a:[1,2,3],b:RegExp("\\w+","i")}

while Sermat.ser({a:[1,2,3],b:/\w+/i}, { pretty: true }) into this:

{
	a : [
		1,
		2,
		3
	],
	b : RegExp(
		"\\w+",
		"i"
	)
}

Still, the whitespace used to format the output cannot be customized, as with JSON.stringify.

License

Sermat is open source software, licenced under an MIT license (see LICENSE.md).

Contact

Suggestions and comments are always welcome at [email protected].