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 🙏

© 2025 – Pkg Stats / Ryan Hefner

super-stringify

v1.0.0

Published

JavaScript's JSON.stringify done right

Downloads

19

Readme

super-stringify

Introduction

super-stringify is like JSON.stringify's superhero cousin. It converts a JavaScript object to a string, but unlike JSON.stringify it is not limited to things that can be represented in JSON, which makes it much more useful.

Usage:

const superStringify = require('super-stringify');
console.log(superStringify(anyObject));

The superStringify function takes one input argument - a JavaScript object - plus an optional space formatter, that's treated the same way as the space formatter argument to JSON.stringify. If that object can be represented as JSON, then it produces identical output to JSON.stringify. For example:

> let obj = { a: 1, b: 'two', c: [1, 2, 3] };
> JSON.stringify(obj)
"{"a":1,"b":"two","c":[1,2,3]}"
> superStringify(obj)
"{"a":1,"b":"two","c":[1,2,3]}"

But unlike JSON.stringify, we can super-stringify any JavaScript object:

> let obj = { a: 1 }; obj.b = obj; let c = [true, 2, () => { }]; delete c[1]; c.push(c[2]); obj.c = c;
> superStringify(obj, 2)
{
  "a": 1,
  "b": [ReferenceTo this],
  "c": [
    true,
    [Empty],
    [Function],
    [ReferenceTo this.c[2]]
  ]
}
> JSON.stringify(obj, null, 2)
Error

Yes, really anything! Try in your browser for example:

> superStringify(window, 2)

JSON.stringify can go wrong in many subtle ways - super-stringify saves you

JSON.stringify is kind of a JavaScript Swiss Army knife. Use it to pretty-print objects for debugging:

> console.log(JSON.stringify(obj, null, 2));

Very commonly, it's used to clone objects:

> let obj2 = JSON.parse(JSON.stringify(obj));

The problem with using it to clone objects is that it does unexpected things without telling you sometimes. For example, suppose we have obj as follows:

> let obj = { a: { b: 1 } };
> obj.b = obj.a;

Then we clone it, and check in two ways the clone represents the same data:

> let obj2 = JSON.parse(JSON.stringify(obj));
> obj
{ a: { b: 1 }, b: { b: 1 } }
> obj2
{ a: { b: 1 }, b: { b: 1 } }
> JSON.stringify(obj) === JSON.stringify(obj2)
true

So far so good. But then surprising stuff happens:

> obj.a.b = 2;    // Change something in obj
> obj2.a.b = 2;   // Make the same change on obj2
> JSON.stringify(obj) === JSON.stringify(obj2)
false   <-- huh?
> obj
{ a: { b: 2 }, b: { b: 2 } }
> obj2
{ a: { b: 2 }, b: { b: 1 } }

Of course, we can see why this happens, because we modified obj ourselves to include a reference to the same object twice. But when we're using objects created in other people's modules, we usually don't know whether object properties that are themselves objects are uniquely referenced or not. And because JavaScript doesn't give us an easy way to tell, it's very easy to introduce bugs which are nearly impossible to find when things like this happen, and values in objects are not what you expect.

Whereas just looking at obj and obj2 at this point leaves us mystified, super-stringify explains to us exactly why what happened, happened:

> superStringify(obj)
{"a":{"b":2},"b":[ReferenceTo this.a]}
> superStringify(obj2)
{"a":{"b":2},"b":{"b":1}}

Another problem: JSON.stringify usually errors out if the input is not JSON - but not always! For example:

> let obj = [null, null];  // this object is valid JSON
> let obj2 = Array(2);     // this object is not valid JSON
> JSON.stringify(obj)
[null,null]   <-- OK
> JSON.stringify(obj2)
[null,null]   <-- huh?

But again super-stringify actually tells you what's going on:

> superStringify(obj)
[null,null]
> superStringify(obj2)
[[Empty],[Empty]]