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

tupleson

v0.23.1

Published

A hackable JSON serializer/deserializer

Downloads

3,327

Readme


Customizable serialization & deserialization. Serialize almost[^1] anything!

[^1]: 🌀 Circular references not your thing? We agree & we don't support it. But hey, feel free to make a PR add opt-in support for that if you need it!

🎯 Project Goals

  • 💡 JSON-compatible output
  • 📖 Human-readable output
  • 🔧 Customizable behavior – tailor it to your exact needs
  • 🌊 Serialize & stream things like Promises or async iterators

[!IMPORTANT]
Though well-tested, this package might undergo big changes and does not follow semver whilst on 0.x.y-version, stay tuned!

👀 Example

/* eslint-disable @typescript-eslint/no-unused-vars, n/no-missing-import */

import {
	// Create serializer / deserializer
	createTson,
	// Serialize `bigint`
	tsonBigint,
	// Serialize `Date`
	tsonDate,
	// Serialize `Map`s
	tsonMap,
	// **throws** when encountering Infinity or NaN
	tsonNumberGuard,
	// Serialize regular expression
	tsonRegExp,
	// Serialize `Set`s
	tsonSet,
	// serialize a Symbol
	tsonSymbol,
	// Serialize `URL`s
	tsonURL,
	// Serialize `undefined`
	tsonUndefined,
	// **throws** when encountering non-registered complex objects (like class instances)
	tsonUnknownObjectGuard,
} from "tupleson";

const tson = createTson({
	/**
	 * The nonce function every time we start serializing a new object
	 * Should return a unique value every time it's called
	 * @default `${crypto.randomUUID} if available, otherwise a random string generated by Math.random`
	 */
	// nonce: () => "__tson",
	types: [
		// Pick which types you want to support
		tsonSet,
	],
});

const myObj = {
	foo: "bar",
	set: new Set([1, 2, 3]),
};

const str = tson.stringify(myObj, 2);
console.log(str);
// (👀 All non-JSON values are replaced with a tuple, hence the name)

// ->
// {
//   "json": {
//     "foo": "bar",
//     "set": [
//       "Set",
//       [
//         1,
//         2,
//         3
//       ],
//       "__tson"
//     ]
//   },
//   "nonce": "__tson"
// }

const obj = tson.parse(str);

// ✨ Retains type integrity
type Obj = typeof obj;
//   ^?
// -> type Obj = { foo: string; set: Set<number>; }

🤯 Streaming Promises and AsyncIterables

🧩 Extend with a custom serializer

[!IMPORTANT] When defining custom serializers, the array order matters! If a value passes the test for more than one custom serializer, the first wins.

⌚️ Temporal

See test reference in ./src/extend/temporal.test.ts

/* eslint-disable @typescript-eslint/no-unused-vars, n/no-missing-import, n/no-unpublished-import */
import { Temporal } from "@js-temporal/polyfill";
import { TsonType, createTson } from "tupleson";

const plainDate: TsonType<Temporal.PlainDate, string> = {
	deserialize: (v) => Temporal.PlainDate.from(v),
	key: "PlainDate",
	serialize: (v) => v.toJSON(),
	test: (v) => v instanceof Temporal.PlainDate,
};

const instant: TsonType<Temporal.Instant, string> = {
	deserialize: (v) => Temporal.Instant.from(v),
	key: "Instant",
	serialize: (v) => v.toJSON(),
	test: (v) => v instanceof Temporal.Instant,
};

const tson = createTson({
	types: [plainDate, instant],
});

🧮 Decimal.js

See test reference in ./src/extend/decimal.test.ts

/* eslint-disable @typescript-eslint/no-unused-vars, n/no-missing-import, n/no-unpublished-import */
import { Decimal } from "decimal.js";

const decimalJs: TsonType<Decimal, string> = {
	deserialize: (v) => new Decimal(v),
	key: "Decimal",
	serialize: (v) => v.toJSON(),
	test: (v) => v instanceof Decimal,
};

const tson = createTson({
	types: [decimalJs],
});

💙 This package is based on @JoshuaKGoldberg's create-typescript-app.