Skip to content

fix: verify recent changes fixes issue #102 - #135

Closed
jedluhmann wants to merge 23 commits into
andreyvit:masterfrom
jedluhmann:jl-verify-recent-changes-fixes-issue-102
Closed

fix: verify recent changes fixes issue #102#135
jedluhmann wants to merge 23 commits into
andreyvit:masterfrom
jedluhmann:jl-verify-recent-changes-fixes-issue-102

Conversation

@jedluhmann

@jedluhmann jedluhmann commented Sep 5, 2026

Copy link
Copy Markdown

Verified that the recent changes fix #102.

@andreyvit, this will also allow you to close PR #125

Upgrades include bun, eslint, prettier, mocha, chai, and c8.
…tringify for array equality)

Some comments are left in this commit to help clarify what is being optimized. These comments will be removed in the next commit.

Changes:
- Cache changes calculated in findMatchingObject() for later use in arrayDiff where op is 'equal'
- Use JSON.stringify() to bypass diff logic when arrays are equal
- findMatchingObject: Switched the order of arguments when calling this.diff() for consistency (candidate is the original value) and to allow caching (reuse change values calculated here in later fuzzy matching)
…condition immediately above for truthy values
…for failed tests

Note: signature for deepEqual is assert.deepEqual(actual, expected, message)
Objective: Simplify the logic by giving each property a maximum possible score of 100

- Matching property: 50 points
- Matching value: 50 points
- Added/Deleted  property: -50 points
This updates the README with a simple diagram that provides a high level overview of how json-diff works.
Added an incredibly useful debug feature that ouputs a pivot table that displays the fuzzy scores that are computed when diffing arrays. When combined with the -v flag, the raw data that the pivot table is derived from is displayed as well.

This feature also adds a debug property to the change object, which is incredibly powerful in providing insight into the object and array indices being compared in other methods like arrayDiff() and diff().

Output for test case, it 'should correctly pick best match based on similarity during scalarize, i.e. class obj2[2] should not be selected as best match for obj1[0], instead order should remain unchanged with added class property for obj1[0]' See: https://github.com/jedluhmann/json-diff/blob/b6500e9d5669d9f31ebe51d26670dcbab2129bf3/test/json-diff.spec.js#L187:

FUZZY SCORES for new obj B compared to candidate A

     A0    A1    A2
-----------------------
B0   250   0     100
B1   0     200   -
B2   50    0     400

 [
   {
+    class: "prose"
   }
   ...
   ...
 ]

In this example, we see a "dash" displayed for the result of the comparison between B1 and A2. This shows one of the recent optimizations in action. B1 and A1 are an exact match both in value and position. Because of this, there is no need to compare B1 with A2 and we simply break out of the loop and continue evaluating the remainder of the array elements.

Here is the additional output with the addition of the verbose option (-dv):

FUZZY MATCH Records

B    A    score  depth  key          path
---  ---  -----  -----  -----------  -----------
0    0    250    0      __$!SCALAR1  $[0]
0    1    0      0      __$!SCALAR2  $[0]
0    0    0      1      __$!SCALAR1  $[0].data[0]
0    2    100    0      __$!SCALAR3  $[0]
1    0    0      0      __$!SCALAR1  $[1]
1    1    200    0      __$!SCALAR2  $[1]
0    0    0      1      __$!SCALAR1  $[2].data[0]
2    0    50     0      __$!SCALAR1  $[2]
2    1    0      0      __$!SCALAR2  $[2]
2    2    400    0      __$!SCALAR3  $[2]

Dealing with large datasets can be nearly impossible to debug and reason about. The benefits of this new feature become readily apparent when dealing with arrays containing many objects:

FUZZY SCORES for new obj B compared to candidate A

      A0    A1    A2   A3    A4   A5    A6    A7   A8    A9    A10   A11   A12   A13
---------------------------------------------------------------------------------------
B0    500   -     -    -     -    -     -     -    -     -     -     -     -     -
B1    0     250   0    150   0    0     155   0    0     150   0     210   0     210
B2    0     0     0    0     0    0     0     0    0     0     0     0     0     0
B3    0     150   0    250   0    0     165   0    0     180   0     200   0     200
B4    0     0     0    0     0    0     0     0    0     0     0     0     0     0
B5    210   0     0    0     0    500   -     -    -     -     -     -     -     -
B6    0     155   0    165   0    0     250   0    0     165   0     205   0     205
B7    0     0     0    0     0    0     0     0    0     0     0     0     0     0
B8    210   0     0    0     0    210   0     0    500   -     -     -     -     -
B9    0     150   0    180   0    0     165   0    0     250   0     200   0     200
B10   0     0     0    0     0    0     0     0    0     0     0     0     0     0
B11   0     160   0    150   0    0     155   0    0     150   0     300   0     210
B12   0     0     0    0     0    0     0     0    0     0     0     0     0     0
B13   0     160   0    150   0    0     155   0    0     150   0     210   0     300

FUZZY MATCH Records

B    A    score  depth  key           path
---  ---  -----  -----  -----------   -----------
0    0    500    0      __$!SCALAR1   $[0]
0    0    0      1      __$!SCALAR1   $[1].data[0]
1    0    0      0      __$!SCALAR1   $[1]
1    1    250    0      __$!SCALAR2   $[1]
0    0    0      1      __$!SCALAR1   $[1].data[0]
1    2    0      0      __$!SCALAR3   $[1]
0    0    0      2      __$!SCALAR1   $[1].data[0].data[0]
0    1    0      2      __$!SCALAR2   $[1].data[0].data[0]
1    0    0      2      __$!SCALAR1   $[1].data[0].data[1]
1    1    300    2      __$!SCALAR2   $[1].data[0].data[1]
0    0    120    1      __$!SCALAR1   $[1].data[0]
0    0    0      2      __$!SCALAR1   $[1].data[0].data[0]
0    1    0      2      __$!SCALAR2   $[1].data[0].data[0]
1    0    0      2      __$!SCALAR1   $[1].data[0].data[1]
1    1    300    2      __$!SCALAR2   $[1].data[0].data[1]
0    1    120    1      __$!SCALAR2   $[1].data[0]
0    0    0      2      __$!SCALAR1   $[1].data[0].data[0]
0    1    0      2      __$!SCALAR2   $[1].data[0].data[0]
1    0    0      2      __$!SCALAR1   $[1].data[0].data[1]
1    1    300    2      __$!SCALAR2   $[1].data[0].data[1]
0    2    120    1      __$!SCALAR3   $[1].data[0]
1    3    150    0      __$!SCALAR4   $[1]
0    0    0      1      __$!SCALAR1   $[1].data[0]
1    4    0      0      __$!SCALAR5   $[1]
0    0    0      1      __$!SCALAR1   $[1].data[0]
... (+748 rows)
For an object with multiple child objects containing arrays, the output now includes the fuzzy scores pivot table for top most array in each child.

For example, given 2 objects with the following shape:

{
  "abc": "xyz",
  "foo1": {
    "bar1": {
      "data": [...(8 items)]
    },
    "bar2": {
      "data": [...(2 items)]
    },
    "bar3": {
      "data": [...(4 items)]
    }
  },
  "foo2": {
    "bar4": {
      "bar5": {
        "bar6": {
          "baz": {
            "data": [...(11 items)]
          }
        }
      }
    }
  }
}

The debug output will now include 4 pivot tables and look something like:

path: $.foo.bar1.data
FUZZY SCORES for new obj B compared to candidate A

     A0    A1    A2   A3    A4   A5    A6   A7
--------------------------------------------------
B0   500   -     -    -     -    -     -    -
B1   0     250   0    155   0    150   0    170
B2   0     0     0    0     0    0     0    0
B3   0     155   0    250   0    155   0    155
B4   0     0     0    0     0    0     0    0
B5   0     170   0    155   0    250   0    170
B6   0     0     0    0     0    0     0    0
B7   0     170   0    155   0    150   0    250

path: $.foo.bar2.data
FUZZY SCORES for new obj B compared to candidate A

     A0    A1
-----------------
B0   500   -
B1   0     250

path: $.foo.bar3.data
FUZZY SCORES for new obj B compared to candidate A

     A0    A1    A2   A3
----------------------------
B0   500   -     -    -
B1   0     250   0    150
B2   0     0     0    0
B3   0     150   0    250

path: $.foo2.bar4.bar5.bar6.baz.data
FUZZY SCORES for new obj B compared to candidate A

      A0    A1   A2    A3   A4    A5   A6    A7   A8    A9   A10
-------------------------------------------------------------------
B0    250   0    160   0    160   0    160   0    160   0    160
B1    0     0    0     0    0     0    0     0    0     0    0
B2    160   0    250   0    160   0    160   0    160   0    160
B3    0     0    0     0    0     0    0     0    0     0    0
B4    160   0    160   0    250   0    160   0    160   0    160
B5    0     0    0     0    0     0    0     0    0     0    0
B6    160   0    160   0    160   0    250   0    160   0    160
B7    0     0    0     0    0     0    0     0    0     0    0
B8    160   0    160   0    160   0    160   0    250   0    160
B9    0     0    0     0    0     0    0     0    0     0    0
B10   160   0    160   0    160   0    160   0    160   0    250
@andreyvit

Copy link
Copy Markdown
Owner

Hey, thanks! But reviewing a patch set of this size is not realistic. Sorry, to get this merged, please send the changes one by one, and explain each one, and exclude unrelated changes, and format the code and commits in the style of the rest of the codebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The returned result is not as expected

2 participants