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

equally

v0.4.4

Published

Method to deeply compare two Javascript Objects for equality.

Downloads

23

Readme

Equally

Build Status

This project is a simple method to deeply compare two Javascript values for equality.

Testing

Testing with npm

Execute the following command:

npm test

Testing with docker

Execute the following command:

. ./test.sh

Instalation and usage

You only have to install equally using the regular procedure with npm:

npm install equally

In any file you want to use it, the only thing needed is to import it like this:

const { equals } = require('equally');

And after that, you can use it to compare two values:

const object1 = { a: 1, b: "one", c: /.?/, d: new Date("2020-02-20") };
const object2 = { b: "one", d: new Date("2020-02-20"), c: /.?/, a: 1 };

console.log(equals(object1, object2));
// true

equals(value1, value2 [, options])

This method compares two values for equality. It returns true if the objects are equal and false otherwise. This method considers equal as in the Object.is() method when primitive values are considered. For Date and RegExp objects, it first transforms them to its String representation using toISOString() and toString() expressions respectively and compare these strings. With Object and Array values, it compares its values at any level of depth, considering by default Object properties in any order and Array values in enumeration order. It is possible to change some defaults to make the comparison behave slightly different (see options below).

  • value1: the first value to be compared for equality. It can be of any type.
  • value2: the second value to compare. Also, it can be of any type.
  • options: optional object to configure the way values are compared. By default, objects are compared regardles of the order of its properties, array elements must be in the same order, and the comparison of strings is case-sensitive. If you want to change this behavior, you can set the following options:
    • orderedObjectProperties: the properties of the objects to be compared must be traversed in the same order. The order must be the same as the given by the Object.keys() function. Default value is false.
    • unorderedArrays: elements in an array do not need to be in order to match. Default value is false.
    • caseInsensitive: to make string comparison case-insensitive, set this option to true. Default value is false.

equals examples

Primitive values are compared as expected:

equals(NaN, NaN); // true
equals(null, undefined); // false
equals(Infinity, Number.POSITIVE_INFINITY); // true
equals("one", "One"); // false

By default, the object properties order is irrelevant:

equals({ a: 1, b: 2 }, { b: 2, a: 1 }); // true

On the other hand, order of arrays is important:

equals([ 1, 2 ], [ 2, 1 ]); // false

You can configure the equals method to take into consideration the order of the properties in an object using an optional configuration object with the orderedObjectProperties property set to true:

equals({ a: 1, b: 2 }, { b: 2, a: 1 }, { orderedObjectProperties: true }); // false
equals({ a: 1, b: 2 }, { a: 1, b: 2 }, { orderedObjectProperties: true }); // true

You can also configure the equals method to consider arrays as unordered sets of values using an optional configuration object with the unorderedArrays property set to true:

equals([ 1, 2 ], [ 2, 1 ], { unorderedArrays: true }); // true

You can also compare complex objects of any depth:

const object1 = {
    a : new Date("2020-02-02"),
    b : {
        c : null,
        d : [
            {},
            { n: 1 }
        ]
    }
};

const object2 = {
    b : {
        c : null,
        d : [
            {},
            { n: 1 }eE
        ]
    },
    a : new Date("2020-02-02")
};

equals(object1, object2); // true

And you can can use any combination in the options object:

let object1 = { a : 1, b : [ 1, 2 ] };
let object2 = { a : 1, b : [ 2, 1 ] };
let options = {
    unorderedArrays: true,
    orderedObjectProperties: false // default is false
};

equals(object1, object2, options); // true

let object1 = { a : 1, b : [ 1, 2 ] };
let object2 = { b : [ 2, 1 ], a : 1 };
let options = {
    unorderedArrays: true,
    orderedObjectProperties: true
};

equals(object1, object2, options); // false

differs(value1, value2)

This method returns an object with the differences between the two values. If the arguments are equal, it returns an empty object {}. If at any level of depth the objects differ, it returns an object that tells us exactly what is different between both.

  • value1: the first value to be compared. It can be a primitive value, a Date, a RegExp, an Array or an Object.
  • value2: the second value to compare. It can hold the same types than value1.

differs examples

The structure of the returned object is better explained with examples:

Simple values, they are equal:

// The returned value is an object without any differences
// specified inside
const a = "one";
const b = "one";

const res = differs(a, b);
// res = {}

Simple values, they are different:

// Values are different. The result specifies a property, "."
// that represents a path inside the value to get the point where
// both objects differ. In this case, the "." means the root value.
const a = "one";
const b = "two";

const res = differs(a, b);
// res = { ".": { 0: "one", 1: "two" }}

Object values, they are different on key1:

// In this case, the objects differ in the value of the
// "key1" property, so the key specified is "key1".
// The value of the property is an object that holds
// 2 properties, 0 and 1, which represent the value
// in the first and second objects.
const a = { key1: "one", key2: "three" };
const b = { key1: "two", key2: "three" };

const res = differs(a, b);
// res = { ".[\"key1\"]": { 0: "one", 1: "two" }}

Object values, they are different on key1 and key2 exists only in a:

// Here we have 2 differences between the objects.
// The first is in "key1" property, where in the first
// object, 0, the value is "one", while in the second, 1,
// the value is "two".
// In the second difference the first object has
// a property "key2" with value "three", but the second
// object does not have it. That is why this difference
// only has the property 0.
const a = { key1: "one", key2: "three" };
const b = { key1: "two" };

const res = differs(a, b);
// res = {
//    ".[\"key1\"]": { 0: "one", 1: "two" },
//    ".[\"key2\"]": { 0: "three" }
// }

Array values, they are different on index 0:

// The arrays are different at index 0, where
// the first array has the value of "one" while
// the second array has the value "two".
const a = [ "one", "three" ];
const b = [ "two", "three" ];

const res = differs(a, b);
// res = { ".[0]": { 0: "one", 1: "two" } }

Array values, they are different on index 0 and index 1 exists only in b:

// Here, the arrays have 2 differences.
// First, at index 0 in both arrays, ".[0]", the
// first has value "one" while the second has value "two".
// The second difference at index 1, ".[1]", only the
// second array has a value, which is "three".
const a = [ "one" ];
const b = [ "two", "three" ];

const res = differs(a, b);
// res = {
//      ".[0]": { 0: "one", 1: "two" }
//      ".[1]": { 1: "three" }
// }

Complex objects, they differ at different levels of depth:

// Given the previous examples, you could be able
// to deduce the meaning of the 4 differences
// that the differs method gets from the a and b objects.
const a = { x: "one", y: [ 1, 2, 4 ], z: null }
const b = { x: "two", y: [ 1, 3, 4, 5 ] }

const res = differs(a, b);
// res = {
//      ".[\"x\"]": { 0: "one", 1: "two" },
//      ".[\"y\"][1]": { 0: 2, 1: 3 },
//      ".[\"y\"][3]": { 1: 5 },
//      ".[\"z\"]": { 0: null },
// }

You can see that the res object contains key-value pairs where the keys represent the path needed to achieve the difference between the values. The parts that you can see in it are the following:

  • "." represents the initial object. If it appears as the single value of a key, it represents the whole object.
  • "[\"object_key\"]" when the value in the square brackets is wrapped in double quotes, it represents a property in an object.
  • "[num]" when the value is numeric and it is not wrapped with double quotes, it represents an index in an array.

In the last example, the key ".[\"y\"][3] represents the index 3 of an array that is the value of the "y" property of the given object. In the b object, that path represents the b.y[3] value, also achived with b["y"][3], which is 5.

The values of the result entries are objects that can have 1 or 2 keys. The keys could only be 0 and/or 1. If both keys appear in the object, it means that both objects have values that can be reached following the key path. If only one of them is present, it means that only the first object, 0, or the second object, 1, have a value reached by the given key path.

License

This package is under the Apache 2.0 license.

Contact

For any comment or suggestion, you can always reach me here: @jormarma