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

json-normalize

v1.1.2

Published

Utility library for generating normalized JSON strings

Downloads

3,913

Readme

JSON Normalize

Stringifies objects in a normalized way for use in caching or comparing JSON.

Why?

Key ordering is rendered "as is" when using JSON.stringify.
This makes it impractical to use stringified values for hashing or caching.

// Using JSON.stringify
JSON.stringify({ foo: 'bar', hello: 'world' }); // => {"foo":"bar","hello":"world"}
JSON.stringify({ hello: 'world', foo: 'bar' }); // => {"hello":"world","foo":"bar"}

JSONNormalize stringifies objects in a "normalized" way by sorting object keys to produce the same JSON string every time.

// Using JSON Normalize
const JSONNormalize = require('json-normalize'); 

JSONNormalize.stringify({ foo: 'bar', hello: 'world' }, (err, results) => {
  // results === {"foo":"bar","hello":"world"}
});

JSONNormalize.stringify({ hello: 'world', foo: 'bar' }, (err, results) => {
  // results === {"foo":"bar","hello":"world"}
});

API

JSONNormalize.stringify

Stringifies objects in a normalized way.
Given an object with any key order, the same string will be returned if the objects are the "equivalent".

JSONNormalize.stringify(value[, replacer], callback)

Parameters

value {any}
The value to "stringify".

replacer {function=}
Eqivalent to the replacer parameter JSON.stringify has.

callback {function}
Invoked with two arguments: error and results.

Returns

{undefined}

Example

const JSONNormalize = require('json-normalize'); 

JSONNormalize.stringify([{ x: 4, y: 3 }, { x: 5, y: 7 }, { y: 2, x: 4 }], (err, results) => {
  console.log(results); // Prints: [{"x":4,"y":3},{"x":5,"y":7},{"x":4,"y":2}]
});

JSONNormalize.stringify([{ y: 3, x: 4 }, { y: 7, x: 5 }, { y: 2, x: 4 }], (err, results) => {
  console.log(results); // Prints: [{"x":4,"y":3},{"x":5,"y":7},{"x":4,"y":2}]
});

JSONNormalize.stringifySync

Syncronous version of JSONNormalize.stringify

JSONNormalize.stringify(value[, replacer], callback)

Parameters

value {any}
The value to "stringify".

replacer {function=}
Eqivalent to the replacer parameter JSON.stringify has.

Returns

{string} A valid JSON string.

Example

const JSONNormalize = require('json-normalize'); 

const results = JSONNormalize.stringifySync([{ x: 4, y: 3 }, { x: 5, y: 7 }, { y: 2, x: 4 }]);
console.log(results); // Prints: [{"x":4,"y":3},{"x":5,"y":7},{"x":4,"y":2}]

const results = JSONNormalize.stringifySync([{ y: 3, x: 4 }, { y: 7, x: 5 }, { y: 2, x: 4 }]);
console.log(results); // Prints: [{"x":4,"y":3},{"x":5,"y":7},{"x":4,"y":2}]

JSONNormalize.normalize

An alias for JSONNormalize.stringify.

JSONNormalize.normalize(value[, replacer], callback)

Parameters

value {any}
The value to "stringify".

replacer {function=}
Eqivalent to the replacer parameter JSON.stringify has.

callback {function}
Invoked with two arguments: error and results.

Returns

{undefined}

Example

const JSONNormalize = require('json-normalize'); 

JSONNormalize.normalize(
  {
    a: [{ c: 'cat', b: 'bat' }, { z: 'zebra', a: 'apple' }],
    b: [{ c: 'cheeta', b: 'balloon' }, { z: 'zephyr', a: 'alligator' }],
  },
  (err, results) => {
    // Do something...
  });

JSONNormalize.normalizeSync

An alias for JSONNormalize.stringifySync.

JSONNormalize.normalize(value[, replacer], callback)

Parameters

value {any}
The value to "stringify".

replacer {function=}
Eqivalent to the replacer parameter JSON.stringify has.

callback {function}
Invoked with two arguments: error and results.

Returns

{string} A valid JSON string.

Example

const JSONNormalize = require('json-normalize'); 
const results = JSONNormalize.normalizeSync({
    a: [{ c: 'cat', b: 'bat' }, { z: 'zebra', a: 'apple' }],
    b: [{ c: 'cheeta', b: 'balloon' }, { z: 'zephyr', a: 'alligator' }],
});

// Do something with results...

Note: The rest of the functions are convenience functions!
They're wrappers around node's crypto module that take the given object, JSONNormalize.normalize it, and then pipe it to crypto.createHash.


JSONNormalize.md5

Gets the md5 hash for the given object.

JSONNormalize.md5(value, callback)

Parameters

value {any}
The value to get the md5 hash of.

callback {function}
Invoked with two arguments: error and results.

Returns

{undefined}

Example

const objectMD5 = require('json-normalize').md5;
objectMD5({ id: 0, name: 'john doe', permissions: ['create', 'delete'] }, (err, md5) => {
  console.log(md5) // Prints: 5520bfd66f9b4a90a0ec08966bc23e6c
});

objectMD5({ permissions: ['create', 'delete'], name: 'john doe', id: 0 }, (err, md5) => {
  console.log(md5); // Prints: 5520bfd66f9b4a90a0ec08966bc23e6c
});

JSONNormalize.sha256

Gets the sha256 hash for the given object.

JSONNormalize.sha256(value, callback)

Parameters

value {any}
The value to get the sha256 hash of.

callback {function}
Invoked with two arguments: error and results.

Returns

{undefined}

Example

const objectSHA256 = require('json-normalize').sha256;

objectSHA256({ id: 0, name: 'john doe', permissions: ['create', 'delete'] }, (err, sha256) => {
  console.log(sha256); // Prints: d1a29dbf32dc7781cd8f0e47cc7b6f625a293cb0e1357c62df1836ad0f934ad7
});

objectSHA256({ permissions: ['create', 'delete'], name: 'john doe', id: 0 }, (err, sha256) => {
  console.log(sha256); // Prints: d1a29dbf32dc7781cd8f0e47cc7b6f625a293cb0e1357c62df1836ad0f934ad7
});

JSONNormalize.sha512

Gets the sha512 hash for the given object.

JSONNormalize.sha512(value, callback)

Parameters

value {any}
The value to get the sha512 hash of.

callback {function}
Invoked with two arguments: error and results.

Returns

{undefined}

Example

const objectSHA512 = require('json-normalize').sha512;

objectSHA512({ id: 0, name: 'john doe', permissions: ['create', 'delete'] }, (err, sha512) => {
  console.log(sha256); // Prints: d99768bd03fbc865944c6045e1c530bbbd0a10bc74cc39faceda4fdc4...
});

objectSHA512({ permissions: ['create', 'delete'], name: 'john doe', id: 0 }, (err, sha512) => {
  console.log(sha256); // Prints: d99768bd03fbc865944c6045e1c530bbbd0a10bc74cc39faceda4fdc4...
});

JSONNormalize.md5Sync

Syncronous version of JSONNormalize.md5

JSONNormalize.sha256Sync

Syncronous version of JSONNormalize.sha256

JSONNormalize.sha512Sync

Syncronous version of JSONNormalize.md5

All methods have an async equivalent that returns a promise (via Bluebird)

For example, JSONNormalize.stringify's promisified version is JSONNormalize.stringifyAsync

const stringifyAsync = require('json-normalize').stringifyAsync;
cosnt myObject = { foo: 'bar' };

// Using promises
stringifyAsync(myObject)
  .then((results) => { ... })
  .catch((error) => { ... });
                     
// Even better with async/await
(async () => {
  const results = await stringifyAsync(myObject);
})();

A Practical Use Case

Using objects as cache keys

import db from 'my-database-library';
import { md5 } from 'json-normalize';

/**
 * Stores database records for quick lookup.
 * @type {object<any>}
 */
const cache = {};

/**
 * Gets a user record from the database with the properties provided in the object "data".
 * @param {object} data The data to use to lookup the user with.
 * @returns {object|undefined} The user's record, if it exists.
 */
async function getUserWithProperties(data = {}) {
  // Argument for data could contain id, name, username, etc.
  const key = await md5(data);
  const cached = cache[key];
  
  // Cached user record found, return it.
  if (cached) return cached;
  
  // No cache found, do some time expensive database lookup
  const results = await db.getUserWithProperties(data);

  cache[key] = results;
  return results;
}

A (not so) Practical Use Case

Comparing JSON files

foo.json

{
  "alpha": "beta",
  "foo": "bar"
}

bar.json

{
  "foo": "bar",
  "alpha": "beta"
}
import { normalizeAsync } from 'json-normalize';
import fs from 'fs-extra-promise';

/**
 * Compares the list of object arguments and checks for equivalency (===).
 * @param {...object} objects The object to compare.
 * @returns {boolean} True if every object === every other object.
 */
async function compareObjects(...objects) {
  const normalized = await Promise.all(objects.map(obj => normalizeAsync(obj)));
  return normalized.every(json => json === normalized[0]);
}

/**
 * Checks that the given list of filepath arguments contain "equivalent" json.
 * @param {...string} paths The list of filepaths to read and compare.
 * @returns {boolean} True if all files contain the same JSON.
 */
async function filesContainEquivalentObjects(...paths) {
  const objects = await Promise.all(paths.map(path => fs.readJsonAsync(path)));
  return await compareObjects(...objects);
}

(async () => {
  const filesAreEqual = await filesContainEquivalentObjects('./foo.json', './bar.json');
  console.log(filesAreEqual); // Prints: true
})();