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

deep-copy-diagnostics

v1.0.2

Published

Ultra-fast definitive testing for deep copies and deep copy algorithms

Downloads

8

Readme

Introduction to deep-copy-diagnostics 1.0.2

Stop using deep-strict-equal algorithms to verify deep copies because they don't detect deep equivalency. Deep-equivalency, not deep-strict-equality, describes deep-copies. This package's deepEquivalent() function should be your tool for testing deep copies and debugging deep copying algorithms.

The reason you want this package is for its correctness, as proven by extensive testing, its speed, and its concise reporting of why deep-equivalency fails when it does. deepEquivalent(), has no peers on NPM as far as I can tell. deepEquivalent() is 3-5 times faster than some deep-strict-equal algorithms, including assert.deepStrictEqual(), which don't have as much work to do, while the deep-strict-equal algorithms that go faster tend to be very incorrect, having cut too many corners.

deepEquivalent(x,y) catches every possible way in which x and y may not be deep copies of each other. It takes into account internal prototypes, circular references, duplicate references, functions, getters/setters, property descriptors, and frozen/sealed/extensible states.

Some deep copiers on NPM will copy functions, Booleans, etc., as is. deepEquivalent(x,y) can handle that: see Usage below.

Usage

npm install deep-equal-diagnostics
const {deepEquivalent} = require('deep-copy-diagnostics');

if(deepEquivalent(x,y))
{
    // statement that x and y are deeply equivalent
    // (that x and y are deep copies of each other)
    
    console.log(deepEquivalent.message); 
    
    // x and y are deep copies of each other.
    // By the way, corresponding functions must not be 
    // reference equal because deep copies don't share
    // state. But read below to see how to relax this
    // requirement.
}
else
{
    // Very clear and precise reason why x and y are 
    // not deeply equivalent.
    
    console.log(deepEquivalent.message); 
    
    // Examine the two subobjects that were
    // not equivalent if you want.
    
    const {source, target} = deepEquivalent.pair;    
}

if(deepEquivalent(x,y, new Set([Function, Boolean])
{
    console.log(deepEquivalent.message); 
    
    // statement that x and y are deeply equivalent
    // except that corresponding functions are expected to
    // be reference-equal, and corresponding Booleans are 
    // expected to be reference-equal. 
}
else
{
     // Very clear and precise reason why x and y are not 
     // deeply equivalent, with above noted exceptions 
     // enforced.
    
    console.log(deepEquivalent.message);  
    
    // Examine the two subobjects that were
    // not equivalent or the two subobjects that 
    // were expected to be reference-equal but 
    // were not.
    
    const {source, target} = deepEquivalent.pair;       
}

Exports

|export|description| |---|---| | deepEquivalent(x,y, primitives) | tests for deep equivalence. primitives is a set of classes whose instances are to be reference equal: see Usage|

Testing is Extensive

See the Tests folder.

Deep-Strict-Equal Algorithms are Bad for Detecting Deep Copies

Two objects can pass the deep-strict-equal test yet not be deep copies of each other. This can happen in at least two ways as demonstrated below.

Example 1
    const A = new Date();
    const x = {a:A};
    const y = {a:A}
    assert.deepStrictEqual(x,y); // Says all is good 
    // No exception thrown.
    
    x and y are not deep copies because they share the 'a' 
    property, even though it passes the deepStrictEqual
    test.
    
Example 2
    const x = {a:{b:{c:1}}}
    const y = {a:{b:{c:1}}}
    x.a.b.d = x
    y.a.b.d = x     
    assert.deepStrictEqual(A,B); // Says all is good 
    // No exception thrown.
    
    x and y are not deep copies because they have a 
    circular reference in different parts of the object 
    trees, even though it passes the deepStrictEqual
    test.       

Definition of Deep Equivalence

Read this section only if you want.

The elements x and y are deeply equivalent if the elements in their trees are in a one-one correspondence that meets the following conditions.

  1. x corresponds to y
  2. Corresponding elements must have the same type (*).
  3. Corresponding objects must have the same internal prototype.
  4. Corresponding primitives must have the same value.
  5. Corresponding WeakMaps or WeakSets must be reference equal.
  6. Corresponding Booleans, Numbers, Strings, Dates, RegExps must have the same internal state, i.e., valueOfs() or toStrings() must be the same.
  7. Corresponding Functions as strings must be the same.
  8. Corresponding objects are never reference equal (except for WeakSets and WeakMaps).
  9. Corresponding objects must have the same frozen/sealed/extensible states.
  10. If p and q are corresponding objects
    1. if either p.a or q.a exist then both exist, and they correspond. Moreover, the property descriptors must be the same.
    2. if p is a Set (we know by 2 that q is a Set) then insertion order defines the one-one correspondence between their members.
    3. if p is a Map (we know by 2 that q is a Map) then insertion order defines the one-one correspondences between their keys and their values.

It would be easy for deepEquivalent() to use the theoretical definition that says insertion order does not matter for Sets and Maps. However, it would be perverse for a deep copier to jumble the insertion order up. For example, when copying a Set, a deep copier will read its members in insertion order, and then copy them in insertion order.

(*) As determined by the dtype(x) function of the type-quickly package.

Version History

|Version|Published|| |---|---|---| |1.0.0|4-27-2022|deep copy diagnostic testing| |1.0.1|4-28-2022|corrected typo $path[mapKey[${n}]] --> ${path}[mapKey[${n}]]| |1.0.2|5-4-2022|Fixed: did not examine buffer properties of Typed Arrays for circularity/duplicity. New tests added to show its now correct.|