https://github.com/open-tech-foundation/obj-diff
π The Fast, Accurate, JavaScript Objects Diffing & Patching Library.
https://github.com/open-tech-foundation/obj-diff
deep diff javascript library objects patching typescript
Last synced: 3 months ago
JSON representation
π The Fast, Accurate, JavaScript Objects Diffing & Patching Library.
- Host: GitHub
- URL: https://github.com/open-tech-foundation/obj-diff
- Owner: Open-Tech-Foundation
- License: mit
- Created: 2024-04-23T19:12:52.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-05-09T09:37:57.000Z (over 1 year ago)
- Last Synced: 2025-09-04T11:42:28.831Z (4 months ago)
- Topics: deep, diff, javascript, library, objects, patching, typescript
- Language: TypeScript
- Homepage: https://obj-diff.pages.dev/
- Size: 204 KB
- Stars: 10
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README

Β [OPEN TECH FOUNDATION](https://open-tech-foundation.pages.dev/)
# obj-diff
[](https://github.com/Open-Tech-Foundation/obj-diff/actions/workflows/build.yml) Β [](https://jsr.io/@opentf/obj-diff)

> The Fast, Accurate, JavaScript Objects Diffing & Patching Library.
**[LIVE DEMO](https://obj-diff.pages.dev/)**
## Features
- Deep Objects Diffing
- Patching
- Supports comparing custom object types
- TypeScript Support
- Cross-Platform
## Supported Types
- Primitives
- Undefined
- Null
- Number
- String
- Boolean
- BigInt
- Objects
- Plain Objects, eg: `{}`
- Array
- Date
- Map
- Set
## Installation
Install it using your favourite package manager.
```sh
npm install @opentf/obj-diff
```
```sh
yarn add @opentf/obj-diff
```
```sh
pnpm add @opentf/obj-diff
```
```sh
bun add @opentf/obj-diff
```
```sh
deno add @opentf/obj-diff
```
## Usage
```js
import { diff } from '@opentf/obj-diff';
diff(obj1: object, obj2: object): Array
```
```ts
type DiffResult = {
t: 0 | 1 | 2; // The type of diff, 0 - Deleted, 1 - Created, 2 - Updated
p: Array; // The object path
v?: unknown; // The current value
};
```
## Examples
1. Diff two simple objects.
```js
const a = { a: 1, b: 2 };
const b = { a: 2, c: 3 };
diff(a, b);
/*
[
{
t: 2,
p: ["a"],
v: 2,
},
{
t: 0,
p: ["b"],
},
{
t: 1,
p: ["c"],
v: 5,
},
]
*/
```
2. Diff two arrays.
```js
const a = [1, 2, 3, 4, 5];
const b = [1, 3, 5];
diff(a, b);
/*
[
{
t: 2,
p: [1],
v: 3,
},
{
t: 2,
p: [2],
v: 5,
},
{
t: 0,
p: [3],
},
{
t: 0,
p: [4],
},
]
*/
```
3. Deep diff two objects.
```js
const a = {
foo: {
bar: {
a: ["a", "b"],
b: 2,
c: ["x", "y"],
e: 100,
},
},
buzz: "world",
};
const b = {
foo: {
bar: {
a: ["a"],
b: 2,
c: ["x", "y", "z"],
d: "Hello, world!",
},
},
buzz: "fizz",
};
diff(a, b);
/*
[
{
t: 0,
p: ["foo", "bar", "a", 1],
},
{
t: 1,
p: ["foo", "bar", "c", 2],
v: "z",
},
{
t: 0,
p: ["foo", "bar", "e"],
},
{
t: 1,
p: ["foo", "bar", "d"],
v: "Hello, world!",
},
{
t: 2,
p: ["buzz"],
v: "fizz",
},
]
*/
```
## Patching
You can apply the diff result onto the original object to get the modified object.
```js
import { diff, patch } from "@opentf/obj-diff";
const a = { a: 1, b: 2 };
const b = { a: 2, c: 3 };
const out = patch(a, diff(a, b));
assert.deepStrictEqual(out, b); // ok
```
## Comparing Custom Types
By default, the `diff` function cannot compare every object types other than the supported list above.
You can extend the default `diff` function using the `diffWith` function.
Now you can compare any object types of your own.
### Usage - diffWith()
```js
import { diffWith } from '@opentf/obj-diff';
diffWith(
obj1: object,
obj2: object,
fn: (a: object, b: object) => boolean | undefined
): Array
```
### Examples
Let us compare the `MongoDB` bson `ObjectId` objects.
```js
import { ObjectId } from "bson";
import { diffWith } from "@opentf/obj-diff";
const record1 = {
_id: new ObjectId(),
title: "Article 1",
desc: "The article description.",
};
const record2 = {
_id: new ObjectId(),
title: "Article 1",
desc: "The new article description.",
};
const result = diffWith(record1, record2, (a, b) => {
if (a instanceof ObjectId && b instanceof ObjectId) {
return a.toString() !== b.toString();
}
});
console.log(result);
/*
[
{
t: 2,
p: [ "_id" ],
v: new ObjectId('663088b877dd3c9aaec482d4'),
},
{
t: 2,
p: [ "desc" ],
v: "The new article description.",
}
]
*/
```
## FAQs
### 1. **Why the standard JSON Patch protocol is not supported?**
The `JSON Patch` protocol is complicated in nature. And simply we don't want use it as our existing solution works for most of the projects.
### 2. What is the meaning of empty array `{p: []}` in path property?
The empty path denotes `Root` path, and it simply means the entire object was replaced.
For Eg:
```js
diff({}, null); //=> [{t: 2, p: [], v: null}]
```
## Benchmark
```diff
βββββ¬βββββββββββββββββββ¬ββββββββββ¬ββββββββββββββββββββ¬βββββββββ¬ββββββββββ
β β Task Name β ops/sec β Average Time (ns) β Margin β Samples β
βββββΌβββββββββββββββββββΌββββββββββΌββββββββββββββββββββΌβββββββββΌββββββββββ€
+ 0 β diff β 252,694 β 3957.346814404028 β Β±1.60% β 25270 β
β 1 β microdiff β 218,441 β 4577.892286564301 β Β±0.92% β 21845 β
β 2 β deep-object-diff β 121,385 β 8238.188318642591 β Β±1.66% β 12139 β
β 3 β just-diff β 105,292 β 9497.35384615396 β Β±1.66% β 10530 β
β 4 β deep-diff β 160,802 β 6218.820533549017 β Β±1.59% β 16081 β
βββββ΄βββββββββββββββββββ΄ββββββββββ΄ββββββββββββββββββββ΄βββββββββ΄ββββββββββ
```
### Running benchmarks
```sh
$ bun run build
$ bun benchmark.js
```
## Articles
Please read our important articles:
- [Introducing Our New JavaScript Standard Library](https://ganapathy.hashnode.dev/introducing-our-new-javascript-standard-library)
- [You Donβt Need JavaScript Native Methods](https://ganapathy.hashnode.dev/you-dont-need-javascript-native-methods)
## License
Copyright (c) [Thanga Ganapathy](https://github.com/Thanga-Ganapathy) ([MIT License](./LICENSE)).