|
10 months ago | |
---|---|---|
.github | 1 year ago | |
dist | 10 months ago | |
src | 10 months ago | |
test | 1 year ago | |
.gitignore | 2 years ago | |
README.md | 11 months ago | |
index.ts | 2 years ago | |
jest.config.js | 2 years ago | |
package-lock.json | 1 year ago | |
package.json | 1 year ago | |
tsconfig.json | 2 years ago | |
tsup.config.ts | 2 years ago |
README.md

SUPERDIFF
This library compares two arrays or objects and returns a full diff of their differences.
WHY YOU SHOULD USE THIS LIBRARY
All other existing solutions return a strange diff format that often requires additional parsing. They are also limited to object comparison. 👎
Superdiff gives you a complete diff for both array and objects in a very readable format. Last but not least, it's battle-tested and super fast. Import. Enjoy. 👍
DONORS
I am grateful to the generous donors of Superdiff!
DIFF FORMAT COMPARISON
Let's compare the diff format of Superdiff and Deep-diff, the most popular diff lib on npm:
input:
const objectA = {
id: 54,
user: {
name: "joe",
- member: true,
- hobbies: ["golf", "football"],
age: 66,
},
}
const objectB = {
id: 54,
user: {
name: "joe",
+ member: false,
+ hobbies: ["golf", "chess"],
age: 66,
},
}
Deep-Diff output:
[
{
kind: "E",
path: ["user", "member"],
lhs: true,
rhs: false,
},
{
kind: "E",
path: ["user", "hobbies", 1],
lhs: "football",
rhs: "chess",
},
];
SuperDiff output:
{
type: "object",
+ status: "updated",
diff: [
{
property: "id",
previousValue: 54,
currentValue: 54,
status: "equal",
},
{
property: "user",
previousValue: {
name: "joe",
member: true,
hobbies: ["golf", "football"],
age: 66,
},
currentValue: {
name: "joe",
member: false,
hobbies: ["golf", "chess"],
age: 66,
},
+ status: "updated",
subPropertiesDiff: [
{
property: "name",
previousValue: "joe",
currentValue: "joe",
status: "equal",
},
+ {
+ property: "member",
+ previousValue: true,
+ currentValue: false,
+ status: "updated",
+ },
+ {
+ property: "hobbies",
+ previousValue: ["golf", "football"],
+ currentValue: ["golf", "chess"],
+ status: "updated",
+ },
{
property: "age",
previousValue: 66,
currentValue: 66,
status: "equal",
},
],
},
],
}
FEATURES
Superdiff exports 4 functions:
getObjectDiff()
import { getObjectDiff } from "@donedeal0/superdiff";
Compares two objects and return a diff for each value and their potential subvalues:
- property name
- status:
added
,deleted
,equal
,updated
- previous value, current value
- supports deeply nested objects with any kind of values
format:
type ObjectDiff = {
type: "object";
status: "added" | "deleted" | "equal" | "updated";
diff: {
property: string;
previousValue: any;
currentValue: any;
status: "added" | "deleted" | "equal" | "updated";
// only appears if some subproperties have been added/deleted/updated
subPropertiesDiff?: {
property: string;
previousValue: any;
currentValue: any;
status: "added" | "deleted" | "equal" | "updated";
// subDiff is a recursive diff in case of nested subproperties
subDiff?: SubProperties[];
}[];
}[];
};
Options
You can add a third options
parameter to getObjectDiff
.
{
ignoreArrayOrder?: boolean // false by default,
showOnly?: {
statuses: ("added" | "deleted" | "updated" | "equal")[], // [] by default
granularity?: "basic" | "deep" // "basic" by default
}
}
-
ignoreArrayOrder
: if set totrue
,["hello", "world"]
and["world", "hello"]
will be treated asequal
, because the two arrays have the same value, just not in the same order. -
showOnly
: returns only the values whose status you are interested in. It takes two parameters:statuses
: status you want to see in the output (e.g.["added", "equal"]
)granularity
:basic
returns only the main properties whose status matches your query.deep
can return main properties if some of their subproperties' status match your request. The subproperties are filtered accordingly.
getListDiff()
import { getListDiff } from "@donedeal0/superdiff";
Compares two arrays and returns a diff for each value:
- index change:
prevIndex
,newIndex
,indexDiff
- status:
added
,deleted
,equal
,moved
,updated
- value
- supports arrays of primitive values and objects
- supports arrays with duplicate values
format:
type ListDiff = {
type: "list";
status: "added" | "deleted" | "equal" | "moved" | "updated";
diff: {
value: any;
prevIndex: number | null;
newIndex: number | null;
indexDiff: number | null;
status: "added" | "deleted" | "equal" | "moved" | "updated";
}[];
};
Options
You can add a third options
parameter to getListDiff
.
{
showOnly?: ("added" | "deleted" | "moved" | "updated" | "equal")[], // [] by default
referenceProperty?: string; // "" by default
}
showOnly
gives you the option to return only the values whose status you are interested in (e.g.["added", "equal"]
).referenceProperty
will consider an object to be updated instead of added or deleted if one of its properties remains stable, such as itsid
. This option has no effect on other datatypes.
isEqual()
import { isEqual } from "@donedeal0/superdiff";
Tests whether two values are equal.
Options
You can add a third options
parameter to isEqual
.
{
ignoreArrayOrder?: boolean // false by default,
}
ignoreArrayOrder
: if set totrue
,["hello", "world"]
and["world", "hello"]
will be treated asequal
, because the two arrays have the same value, just not in the same order.
isObject()
import { isObject } from "@donedeal0/superdiff";
Tests whether a value is an object.
EXAMPLES
getListDiff()
input
getListDiff(
- ["mbappe", "mendes", "verratti", "ruiz"],
+ ["mbappe", "messi", "ruiz"]
);
output
{
type: "list",
+ status: "updated",
diff: [
{
value: "mbappe",
prevIndex: 0,
newIndex: 0,
indexDiff: 0,
status: "equal",
},
- {
- value: "mendes",
- prevIndex: 1,
- newIndex: null,
- indexDiff: null,
- status: "deleted",
- },
- {
- value: "verratti",
- prevIndex: 2,
- newIndex: null,
- indexDiff: null,
- status: "deleted",
- },
+ {
+ value: "messi",
+ prevIndex: null,
+ newIndex: 1,
+ indexDiff: null,
+ status: "added",
+ },
+ {
+ value: "ruiz",
+ prevIndex: 3,
+ newIndex: 2,
+ indexDiff: -1,
+ status: "moved",
},
],
}
getObjectDiff()
input
getObjectDiff(
{
id: 54,
user: {
name: "joe",
- member: true,
- hobbies: ["golf", "football"],
age: 66,
},
},
{
id: 54,
user: {
name: "joe",
+ member: false,
+ hobbies: ["golf", "chess"],
age: 66,
},
}
);
output
{
type: "object",
+ status: "updated",
diff: [
{
property: "id",
previousValue: 54,
currentValue: 54,
status: "equal",
},
{
property: "user",
previousValue: {
name: "joe",
member: true,
hobbies: ["golf", "football"],
age: 66,
},
currentValue: {
name: "joe",
member: false,
hobbies: ["golf", "chess"],
age: 66,
},
+ status: "updated",
subPropertiesDiff: [
{
property: "name",
previousValue: "joe",
currentValue: "joe",
status: "equal",
},
+ {
+ property: "member",
+ previousValue: true,
+ currentValue: false,
+ status: "updated",
+ },
+ {
+ property: "hobbies",
+ previousValue: ["golf", "football"],
+ currentValue: ["golf", "chess"],
+ status: "updated",
+ },
{
property: "age",
previousValue: 66,
currentValue: 66,
status: "equal",
},
],
},
],
}
isEqual()
isEqual(
[
{ name: "joe", age: 99 },
{ name: "nina", age: 23 },
],
[
{ name: "joe", age: 98 },
{ name: "nina", age: 23 },
]
);
output
false;
isObject()
input
isObject(["hello", "world"]);
output
false;
More examples are available in the source code tests.
CREDITS
DoneDeal0
SUPPORT
If you or your company uses Superdiff, please show your support by becoming a sponsor! Your name and company logo will be displayed on the README.md
. https://github.com/sponsors/DoneDeal0
CONTRIBUTING
Pull requests are welcome!