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

xcmp

v0.0.0-prealpha

Published

Extremely Exact Object Comparator

Downloads

4

Readme

XCMP: eXtremely accurate object Comparison!

Ever tried to compare two JS variables for equality? Something like this:

var apples = ['apple', 'avocado'];
var oranges = 'lemon';
if (apples === oranges)
  console.log("Hadn't I told you?");
else
  console.log("Not the same?! But they are both blue!")

See? It's just as simple as using a === between the variables we want to compare!

But wait.

What about this one?

var applesHere = ['apple', 'apple'];
var applesThere = ['apple', 'apple'];

if (applesHere === applesThere)
  spareHumankind();
else
  annuhilatePlanetEarth();

In the rather sad example above, applesHere and applesThere are referentially distinct (i.e., they refer to different memory addresses), but structurally equivalent, that is, they have the exact same shape and content; they would have been equal if they were compared the right way.

The moral of the snippet above, of course, is that using === indiscriminately can have really tragic consequences. :(

Had we used the structural-comparison-superpowers of xcmp, though, our little blue mudball of a planet might have survived unannihilated:

npm install xcmp
var xcmp = require('xcmp');

var applesHere = ['apple', 'apple'];
var applesThere = ['apple', 'apple'];

if (xcmp.xcmpEqual(applesHere, applesThere))
  spareHumankind();
else
  annihilatePlanetEarth();

It's not even that! xcmp can handle even more complex cases like this:

var xcmp = require('xcmp');

var a = []; a.push(a);

var b = []; b.push(b);

console.log(xcmp.xcmpEqual(a,b)); // True!

... or this:

var xcmp = require('xcmp');

var a = []; a.push([a]);

var b = []; b.push([[b]]);

console.log(xcmp.xcmpEqual(a,b)); // True!

... or even this: (on which even node's very own assert.deepEqual fails!)

var xcmp = require('xcmp');

var a = []; a.push(a);

var b = []; b.push([b]);

console.log(xcmp.xcmpEqual(a,b)); // True! 

... And don't worry, a typo in the call to the annihilation function, above, resulted in a run-time error before the annihilation was launched.

But please be very careful next time! :)

Advanced Usage

Even though it is perfectly fine to call xcmpEqual as xcmpEqual(someObj, someOtherObj), xcmp has quite more to provide -- it can receive extra parameters that can, to a reasonable extent, modify the way xcmp works.

The full signature of xcmp.xcmpEqual is as follows: (N.B. none of the parameters below are mandatory)

function xcmpEqual(
  left: any,
  right: any, 
  extras: {
    notEq:
      function(reason: String, leftV: any, rightV: any, uncommonKey: string): void,
      // this is called whenever a difference between  has been found.
      // reason can hold the following values:
      //   'notEqValues': left is not structurally equavalent to right because
      //                leftV and rightV do not have equal types or they are not
      //                structurally comparable (i.e., one is an object while the
      //                other isn't, or both are value-types but have inequal
      //                values
      //   'notEqStruct': left is not structurally equivalent to right because
      //               even though they are structurally comparable, leftV and
      //               rightV have either inequivalent recursive substructures
      //               or they have at least one uncommon key; in the case of
      //               recursive inequality, `uncommonKey` has value `undefined`
      
    objEq:
      function(a: Object, b: Object): bool,
      // test whether a and b are equal; the default function provided would
      // just check whether `a === b`

    sort:
      function(arr: Array<any>): Array<any>,
      // when comparing a pair of objects, sorts their keys before comparing them
      // the default function is a simple acending quick-sort

    enterKey:
      function(keyName: string|int) void,
      // if `keyTrack` option is true, `enterKey` can be used to track
      // child objects listed under a container object.
      // it can be used to pin the exact path of inequality in `left` and `right`.

    exitKey:
      function() void
      // if `keyTrack` option is true, `exitKey` exits the latest entered key

    failFast:
      bool,
      // if this switch is false, object comparison would traverse *every*
      // in the `left` and `right` values before actually returning false.
      // otherwise it would report the objects as inequal on encountering the first
      // uncommon key
      // default: true


    keyTrack:
      bool,
      // track the key names; e.g., given `{'a': {'b': 40 }}` and `{'a': {'b': 55}}`, if `keyTrack` is true,
      // `enterKey` and `exitKey` are called like this:
      // <start traversing {'a': {'b': 40 } }
      // enterKey('a');
      // <start traversing {'b': 40}
      // enterKey('b')
      // exitKey()
      // exitKey()
      //
      // default: false
  }
)