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

surrial

v2.0.2

Published

Serialize anything. This is surreal!

Downloads

17,044

Readme

Build Status Mutation testing badge

Surrial

Serialize anything. Pretty surreal!

Install

Install using your favorite package manager:

npm install surrial
# OR
yarn add surrial

Usage

const { serialize, deserialize, surrial } = require('surrial');

class Person {
    constructor(name, parent){
        this.name = name;
        this.parent = parent;
    }
}

function identity(thing) { return thing;  }

const stringified = serialize({
    a: 1,
    b: new Date(),
    c: /foo/,
    d: new Set([1, 2, 3]),
    e: new Map([[1, 'one'], [2, 'two']]),
    f: Person,
    g: identity
});

/* => '{ "a": 1, "b": new Date("2018-02-13T20:27:39.073Z"), "c": /foo/, "d": new Set([1, 2, 3]), "e": new Map([[1, "one"], [2, "two"]]), "f": class Person { constructor(name, parent) { this.name = name; this.parent = parent; } }, "g": function identity(thing) { return thing;  } }'      
*/

const output = deserialize(stringified)
/* =>
{ a: 1,
  b: 2018-02-13T20:32:52.218Z,
  c: /foo/,
  d: Set { 1, 2, 3 },
  e: Map { 1 => 'one', 2 => 'two' },
  f: [Function: Person],
  h: [Function: identity] } 
*/

Also supports serializing instances of classes for known classes.

const p = new Person('Foo', new Person('Bar', null));
const knownClasses = [Person];
const personString = serialize(p, knownClasses);
// => 'new Person("Foo", new Person("Bar", null))'

const copy = deserialize(p, knownClasses);
// => Person { name: 'Foo', parent: Person { name: 'Bar', parent: null } }

An example of the surrial tag for template literals:

const decade = [new Date(2010, 1, 1), new Date(2020, 1, 1)];
surrial`new Set(${decade})`;
// => 'new Set([new Date("2010-01-31T23:00:00.000Z"),new Date("2020-01-31T23:00:00.000Z")])'

You can customize the output string using the surrialize() method (comparable to the toJSON method for JSON.stringify).

// A typescript example
class Person implements Surrializable {
    public age: number;
    constructor(ageInMonths: number) {
        this.age = Math.floor(ageInMonths / 12);
    }
    surrialize() {
        return surrial`new Person(${this.age * 12})`;
    }
}

const input = new Person(25);
const actual = serialize(input, [Person]);
const output = deserialize(actual, [Person]);
expect(output).instanceOf(Person);
expect(output).deep.eq(input);

Api

TypeScript typings are included in the library.

/**
 * A surrial template tag, useful for building templates strings while enforcing the values to be serialized using surrial.
 * @param templateLiterals The template literals
 * @param values The values to be serialized using surrial
 */
export function surrial(templateLiterals: TemplateStringsArray, ...values: unknown[]) {

/**
 * Serializes the thing to a javascript string. This is NOT necessarily a JSON string, but will be valid javascript.
 * @param thing The thing to be serialized
 * @param knownClasses the classes of which instances are serialized as constructor calls (for example "new Person('Henry')").
 */
export function serialize(thing: any, knownClasses: ClassConstructor[] = []): string {


/**
 * Deserializes a string into it's javascript equivalent. CAUTION! Evaluates the string in the current javascript engine
 * (`eval` or one of its friends). Be sure the `serializedThing` comes from a trusted source!
 * @param serializedThing The string to deserialize
 * @param knownClasses A list of known classes used to provide as constructor functions
 */
export function deserialize(serializedThing: string, knownClasses: ClassConstructor[] = []): any;

Features

  • Serializes all primitive types
  • Serializes plain objects as JSON
  • Support for build in types: Date, RegExp, Map, Set and Buffer
  • Support for functions and classes using their toString()
  • Support for instances of classes using new MyClass() syntax (see limitations).
  • Support for deeply nested build in types/class instances
  • Has a light footprint (< 200 lines of code).
  • Written in typescript (type definition included).
  • Deserialize using a deserialize convenience method. This uses the new Function(/*...*/) (comparable to eval) (see limitations).
  • Serialize values in a template with a handy surrial tagged template literal.
  • Allow a custom serialize function using surrialize.

Limitations

Surrial, like any serialization library, has some limitations, but supports my personal use case. If you need more functionality, don't hesitate to open an issue. I'm always in for a discussion.

Circular references

Circular references are not supported.

Deserializing is no security feature (you will get hacked!)

When you call the deserialize method, any string will be interpreted as javascript using the new Function(...) constructor. Keep in mind that any arbitrary code will be executed in the global scope of your current javascript engine! Please don't use this library to deserialize strings coming from untrusted sources!

Class instances

Class instances are serialized using their constructor. Any additional properties are ignored.

class Person {
    constructor(name){
        this.name = name;
    }
}

const p = new Person('foo');
p.age = 10; // => ignored
serialize(p, [Person]);
// => 'new Person("foo")'

Both the class syntax and prototype syntax (es5 syntax) are supported here.

When serializing an instance of a class, it is assumed that the constructor parameters are also properties (or attributes) of that class. If not, that parameter will be undefined.

class Person {
    constructor(n, age){
        this.name = n; // => ignored
        this.age = age;
    }
}

const p = new Person('foo', 42);
serialize(p);
// => 'new Person(undefined, 42)'

When serializing a class instance, only classes you specify as knownClasses are actually serialized using new MyClass(), by default it would just have a JSON format.

class Person { constructor(name) { this.name = name; }}
serialize(new Person('Foo'));
// => { "name": "foo" }

serialize(new Person('Foo'), [Person]);
// => new Person("foo")

When deserializing a class instance, you are responsible for providing a class definition (or a class with the same name).

class Person { constructor(name) { this.name = name; }}
deserialize('new Person("Foo")');
// => ReferenceError: Person is not defined

deserialize('new Person("Foo")', [Person]);
// => OK: Person { name: 'Foo' }

Acknowledgements

  • This library is strongly influenced by serialize-javascript. This might be what you're looking for when you don't need the class instance serialization support.
  • A library which supports circular references: circular-json
  • Know the class that you're serializing to? serialize.ts might be for you. This one also looks good: cerialize