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

deserted

v1.0.3

Published

A simple and lonely serialization library for JS

Downloads

6

Readme

deserted

A simple and lonely serialization library for JS

Installation

yarn add deserted

API Documenttation

Generated by Typedoc: https://vitoke.github.io/deserted/globals.html

Usage

Simple

import { deserted } from 'deserted'

const myObject = {
  value: 523,
  nested: {
    text: 'foo',
    bar: false
  },
  date: new Date(1990, 1, 1)
}

const asString = deserted.serialize(myObject)

const backToObject = deserted.deserialize(asString)

const quickCloneObject = deserted.clone(myObject)

Advanced

import { deserted, Converters } from 'deserted'

class Test {
  constructor() {
    this.foo = 1
    this.bar = true
  }
}
const test = new Test()
test.bar = false

const testSerializer = deserted.withConverters(Converters.allProps(Test))

const shared = { value: 123, { nested: test: 'foo' } }

const someObject = [shared, { value: shared }, new Map([1, shared])]

const asString = testSerializer.serialize(someObject)

const backToObject = testSerializer.deserialize(asString)

const quickCloneObject = testSerializer.clone(someObject)

Motivation

Serialization is important in any system dealing with data that should be saved or sent over a wire. It is also useful for deep cloning of objects. In a quick search for a simple to use but powerful library, I could not find anything that matches these requirements.

The deserted library can serialize complex object-graphs with circular references without configuration.

Things that are serializable out of the box:

  • primitives: number, string, boolean, undefined, null, Symbol
  • boxed primitives: Number, String, Boolean
  • objects
  • collections: Array, Map, Set
  • Date
  • Error

Things that require some configuration:

  • serializing custom class instances
  • serializing functions/code (limited, not the goal of this library)
  • serializing non-global Symbols, if they need to be reconnected to existing Symbols

Things that are not serializable:

  • Promises
  • any classes that have some hidden state

In-depth

(De)Normalization

The deserted library uses a two-phase approach to perform serialization. First, JS objects are 'normalized' to a JSON-like format. Basically, it creates a JSON object with object shapes based on primitive values that match the basic needed cases, like primitives, objects, class instances, references etc.

The normalize function on Deserted instances does exactly this.

For example, calling deserted.normalize({ test: 1 }) results in { obj: { test: { val: 1 } } }. This indicates that the serialized item is an object, is has a property called test, and the value of this property is the primitive value 1.

The resulting object can easily be fed to JSON.stringify. While this is also true for the source object, JSON.stringify easily breaks down when circular references are encountered.

Deserted also has the denormalize function that does exactly the inverse. Calling it on the result of the above example would return an object that is exactly the same as the provided object. But it is not the same in terms of references. Thus, it is a clone.

Cloning

Often it is necessary to copy or clone some input value, especially when dealing with functional frameworks. Redux is a common example for this, where state should be immutable, and thus the original object should not be modified. While except for small states, it is probably not a good idea to use this library for cloning, if cloning needs to be done occasionally, this library is a good fit.

I've seen examples of people using JSON.parse( JSON.stringify( someObject ) ) to do cloning. While that works, it has terrible performance, and does not handle circular references and also has no means to deal with custom classes.

Especially for this use case, Deserted provides the .clone method. All this does is perform denormalize( normalize ( someObject ) ), having the same effect but much faster. This is because there is no conversion to a String, and thus no parsing needed.

Configuration

Options

Deserted supports the following options, which can be supplied to Deserted.empty(options) Deserted.default(options) and .withOptions(options) on an existing instance:

  • noRefs: if true, the serializer will throw an exception if a circular reference is encountered.
  • functionConverter: a custom converter to serialize functions. By default they are replaced by a string.
  • symbolConverter: a custom converter to serialize Symbols. Useful if non-global symbols are used, and they need to be linked back.
  • stringifier: a custom converter that converts objects to strings and back. By default this is JSON.stringify/parse.

Custom converters

Deserted can also serialize custom class instances. However, you will need to configure how you want them to be serialized. The Converters object provides a number of common converters, but it's also possible to create your own.

Imagine we have the following class that we want to serialize:

class CounterState {
  constructor(initialCount = 0) {
    this.state = {
      count: initialCount,
      modifications: 0
    }
  }

  increase() {
    this.state.count++
    this.state.modifications++
  }

  decrease() {
    this.state.count--
    this.state.modifications++
  }
}

The class would only require its properties (the state property) to be serialized. Deserted can be configured to do that as follows:

import { deserted, Converters } from 'deserted'

const serializer = deserted.withConverters(Converters.allProps(CounterState))

const counter = new CounterState(10)
counter.increase()

const counterAsString = serializer.serialize(counter)

If you have a lot of custom classes that need the same type of converter, you can specify that as follows:

const serializer = deserted.withConverters(
  Converters.pick(SomeClass, 'prop1', 'prop2'),
  Converters.all(Converters.allProps, Class1, Class2, Class3)
)

Conclusion

The Deserted library is simple yet powerful, and allows to serialize complex object graphs with circular references with little effort. And it also makes deep cloning of objects a breeze.

Have fun!