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

@arborjs/json

v0.0.1-alpha.7

Published

A JSON serializer with support to custom types focused on @arborjs/store use-cases

Downloads

89

Readme

@arborjs/json

"Buy Me A Coffee"

Type-preserving serialization/deserialization for user-defined types via an API similar to JSON.stringify and JSON.parse + some decorator "magic".

Installation

npm

npm install @arborjs/json

yarn

yarn add @arborjs/json

Usage

For most use cases, the usage is extremely simple, with very little boilerplate:

  1. Decorate your class with the serializable decorator;
  2. Use the stringify function to serialize instances of the decorated class;
  3. Use the parse function to deserialize data strings representing instances of the decorated class.
import { serializable, stringify, parse } from "@arborjs/json"

@serializable
class Todo {
  constructor(readonly uuid: string, public text: string) {}
}

const todo = new Todo("my-uuid", "Clean the house")

const serialized = stringify(todo)
=> '{"$value":{"uuid":"my-uuid","text":"Clean the house"},"$type":"Todo"}'

const deserialized = parse(serialized)
expect(deserialized).toEqual(todo)
expect(deserialized).toBeInstanceOf(Todo)
=> true

Managing multiple serializers

In case you need to manage multiple instances of the Json serializer in your app, you can:

  1. Create an instance of the Json class;
  2. Decorate your classes with the decorators provided by the Json instance;
  3. Leverage the Json#stringify to serialize your object;
  4. And Json#parse to deserialize the string data back into an instance of your serialized type.

Example:

  1. Instantiate the Json class:
import { Json } from `@arborjs/json`

// NOTE: we'll be referencing this variable in the following snippets
const json = new Json()
  1. Decorate your class so it can be known by the Json instance:
@json.serializable
class Todo {
  constructor(readonly uuid: string, public text: string) {}
}
  1. Serialize the object:
const todo = new Todo("my-uuid", "Clean the house")

const serialized = json.stringify(todo)
=> '{"$value":{"uuid":"my-uuid","text":"Clean the house"},"$type":"Todo"}'
  1. Deserialize the string data back into an instance of the Todo class:
const deserialized = json.parse(serialized)

expect(deserialized).toEqual(todo)
=> true

Custom serialization/deserialization logic

In certain situations, you will want to provide your own serialization/deserialization logic, here's how to achieve that:

@json.serializable
class TodoList extends Map<string, Todo> {
  constructor(...todos: Todo[]) {
    super(todos.map((todo) => [todo.uuid, todo]))
  }

  /*
   * Provide your own deserialization logic
   */
  static fromJSON(value: SerializedBy<TodoList>) {
    return new TodoList(...value)
  }

  /*
   * Provide your own serialization logic
   */
  toJSON() {
    return Array.from(this.values())
  }
}

Handling type name clashes

In case you end up with different types sharing the same name in your application, you can tell @arborjs/json which serialization keys to use to identify each type:

// models/users/Settings.ts
@json.serializableAs("UserSettings")
class Settings {
  constructor(
    readonly uuid: string,
    readonly userId: string,
    public active: boolean
  ) {}
}

// models/projects/Settings.ts
@json.serializableAs("ProjectSettings")
class Settings {
  constructor(
    readonly uuid: string,
    readonly projectId: string,
    public status: ProjectStatus
  ) {}
}

The serializableAs decorator instructs @arborjs/json to use the provided key to identify the decorated type so that it can differentiate different types with the same name in its registry, ultimatelly allowing proper serialization/deserialization of these types:

const userSettings = new UserSettings("user-settings-uuid", "user-id", true)
const projectSettings = new ProjectSettings("project-settings-uuid", "project-id", "in progress")

const serializedUserSettings = json.stringify(userSettings)
=> '{"$value":{"uuid":"user-settings-uuid","userId":"user-id","active":true},"$type":"UserSettings"}'

const serializedProjectSettings = json.stringify(projectSettings)
=> '{"$value":{"uuid":"project-settings-uuid","projectId":"project-id","status":"in progress"},"$type":"ProjectSettings"}'

Reducing boilerplate

You may choose to move the Json serializer setup into different modules to make its usage a little more friendly and with less boilerplate to the final user:

// src/json1.ts
import { Json } from "@arborjs/json"

const json = new Json()
export const parse = json.parse.bind(json)
export const stringify = json.stringify.bind(json)
export const serializable = json.serializable.bind(json)
export const serializableAs = json.serializableAs.bind(json)

// src/json2.ts
import { Json } from "@arborjs/json"

const json = new Json()
export const parse = json.parse.bind(json)
export const stringify = json.stringify.bind(json)
export const serializable = json.serializable.bind(json)
export const serializableAs = json.serializableAs.bind(json)

License

All packages in this monorepo are MIT licensed.