boogy

Compare objects and check if they are equal according to a recursive equality algorithm. Similiar to NodeJS core module deepEqual in loose mode

Usage no npm install needed!

<script type="module">
  import boogy from 'https://cdn.skypack.dev/boogy';
</script>

README

Boogy

Build Status npm downloads

Boogy is a module which you can use to determine if two objects are equal - either shallow or deep - to each others.

It offers two modes - loose and strict, and the loose mode is somewhat similar to the deepEqual algoithm found in the NodeJS core assert module.

This module is designed to fix all known bugs found in various deepEqual algorithms online, and support everything that is possible to support. ES2015 and ES2016 included.

ES2017 is still at the draft stage, but will be supported continuously.

It's safe to use this module in production - over 380 tests (not included subtests) proves that Boogy is battle tested.

Features

  • 100% reliable
  • 100% NodeJS core assert module compatible in loose mode
  • ES2016 and ES2017 (still draft) support in strict mode
  • Equal support for NodeJS 4.x and NodeJS 6.x - unlike NodeJS core assert module
  • Follows ECMA standards
  • Handle complex datasets
  • Supports 2 different modes - loose and strict
  • RegExp equality checks are extended to also support sticky and unicode.
  • High performance
  • 37% faster then native NodejS solution.

Compatibility

  • NodeJS 4.0+

Install

$ npm install --save boogy

Then in your project...


// Node 5.x or newer.
var { strict, loose } = require('boogy');

or

import { strict, loose } from 'boogy';

API

Boogy let you import two different functions, so you can choose between either strict and loose mode when you include this module into your project. Each of the functions takes two arguments of any type, and returns a boolean result. Primitive types are equal if they are ===. While composite types, i.e. Objects and Arrays, are considered equal if they have both the same structure and each sub-value is also equal. Circular references in composite structures are supported.

loose(actual, expected)

  • actual - Value to compare against actual
  • expected - Value to compare against expected

Returns: Boolean indicating whether or not actual is the same as expected.

Same for strict mode.

Differences between loose and strict mode

The differences between loose and strict mode are mainly the use of tripple equals. And also that the strict mode does a deeply nested sameValue equality between two objects of any type, and performs a SameValueZero comparison between two values to determine if they are equivalent.

loose({}, []) // => true

strict({}, []) // => false

loose({ 0: 'a', 1: 'b' }, ['a', 'b']) // => true

strict({ 0: 'a', 1: 'b' }, ['a', 'b'])  // => false

loose(1, '1') // => true

strict(1, '1') // => false

Differences between Boogy and NodejS core assert module

The core assert module are basicly using == for all equality checks, wich include a complicated logic for type conversion that often can lead to bugs, or give you results you wouldn't expect.

Boogy's loose mode is approximately 100% compatible with the NodejS core assert module except there is a small deviation in some areas where current code is either enhanced or extended.

This is done to avoid giving you unexpected results, or encounter bugs. The loose mode also supports Features that isn't supported in the core assert module, and some features that only works for NodeJS 6.x such as TypedArray.prototype.subarray() is also working with NodeJS 4.x with Boogy.

Here are a few strange results that is kept as is in Boogy:


loose([1], true)  // => true
loose('0', false)  // => true
loose([[]], false)  // => true
loose([], false)  // => true
loose([], {})  // => true
loose(new Buffer('abc'), new Buffer('xyz'))  // => true
loose('\r\n\t', 0)  // => true

With Boogys strict mode this strange behaviour are non-existent - one of the main purposes with the strict mode.

Boogy vs. other deepEqual algorithms

The differences between Boogy and other similiar algorithms are too many that I can list them all here, but basicly Boogy is a better algorithm that fixes all flaws in similar algorithms, and also have build in support for the new ES2015 collection. And ES2016 support soon to come.

Around 37% of all tests for this module will fail with other algorithms.

The bugs found in similar modules are mostly related to circular references - and RegExp. Or [] === {} wich returns true. However this is what the NodejS Core assert module does as well. And the same behaviour have Boogy adopted in loose mode.

AVA wich using the not-so-shallow module doesn't have the mentioned issues, but still have it's own issues. One obvious issue is this:

  Error('a') === Error('b') // => true

And the Chai library have some "really nice bugs" related to circular references, and also this strange behavior:


  var symbol1 = Symbol('x');

  expect(symbol1, Object(symbol1)).to.be.false; // => TypeError: Cannot convert a Symbol value to a string

  vs. Boogy

  loose(symbol1, Object(symbol1); // => false

Some examples

Same structure:

loose({ a : [ 2, 3 ], b : [ 4 ] }, { a : [ 2, 3 ], b : [ 4 ] }) // => true
strict({ a : [ 2, 3 ], b : [ 4 ] }, { a : [ 2, 3 ], b : [ 4 ] }) // => true

Different structure:

loose({ x : 2016, y : [2017] }, { x : 2016}) // => false
struct({ x : 2016, y : [2017] }, { x : 2016}) // => false

Same structure, different values:

loose( { x : 2016, y : [6] }, { x : 2017}) // => false
strict( { x : 2016, y : [6] }, { x : 2017}) // => false

Primitives:

loose({ x : 5, y : [6] },{ x : 5}) // => false
strict({ x : 5, y : [6] },{ x : 5}) // => false

ECMA:

loose(function() {}, () => {}) // => false
strict(function() {}, () => {}) // => false

Mixed


loose(a, 'b') // false
loose({a: 0}, {a: '0'}, 'strict') // false
loose({a: 1}, {a: 1}) // true
loose({a: 1, b: 2}, {b: 2, a: 1}) // true

// Both of this will return true in the NodejS core module
loose(Error('a'), Error('a')) // true
loose(Error('a'), Error('b')) // false
strict(Error('a'), Error('b')) // false

let s = Symbol();

loose(s, s); // true

Bugs?

If you find any bugs, feel free to open an issue ticket.

Contribution

You are welcome to contribute at any time :)