diff --git a/.eslintcache b/.eslintcache
deleted file mode 100644
index 1ab57e8..0000000
--- a/.eslintcache
+++ /dev/null
@@ -1 +0,0 @@
-[{"/Users/antoine/Desktop/superdiff/eslint.config.mjs":"1","/Users/antoine/Desktop/superdiff/index.ts":"2","/Users/antoine/Desktop/superdiff/tsup.config.ts":"3","/Users/antoine/Desktop/superdiff/src/index.ts":"4","/Users/antoine/Desktop/superdiff/src/list-diff.ts":"5","/Users/antoine/Desktop/superdiff/src/model.ts":"6","/Users/antoine/Desktop/superdiff/src/object-diff.ts":"7","/Users/antoine/Desktop/superdiff/src/utils.ts":"8","/Users/antoine/Desktop/superdiff/test/list-diff.test.ts":"9","/Users/antoine/Desktop/superdiff/test/object-diff.test.ts":"10","/Users/antoine/Desktop/superdiff/test/utils.test.ts":"11"},{"size":426,"mtime":1727602294779,"results":"12","hashOfConfig":"13"},{"size":0,"mtime":1727601340027,"results":"14","hashOfConfig":"15"},{"size":222,"mtime":1727601767512,"results":"16","hashOfConfig":"15"},{"size":160,"mtime":1727601340028,"results":"17","hashOfConfig":"15"},{"size":4697,"mtime":1727601897826,"results":"18","hashOfConfig":"15"},{"size":1903,"mtime":1727601897832,"results":"19","hashOfConfig":"15"},{"size":9363,"mtime":1727602282176,"results":"20","hashOfConfig":"15"},{"size":1150,"mtime":1727601897855,"results":"21","hashOfConfig":"15"},{"size":18523,"mtime":1727601897889,"results":"22","hashOfConfig":"15"},{"size":23198,"mtime":1727601897918,"results":"23","hashOfConfig":"15"},{"size":3560,"mtime":1727601897925,"results":"24","hashOfConfig":"15"},{"filePath":"25","messages":"26","suppressedMessages":"27","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"13i3tau",{"filePath":"28","messages":"29","suppressedMessages":"30","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"a3qfx6",{"filePath":"31","messages":"32","suppressedMessages":"33","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"34","messages":"35","suppressedMessages":"36","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"37","messages":"38","suppressedMessages":"39","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"40","messages":"41","suppressedMessages":"42","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"43","messages":"44","suppressedMessages":"45","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"46","messages":"47","suppressedMessages":"48","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"49","messages":"50","suppressedMessages":"51","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"52","messages":"53","suppressedMessages":"54","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"55","messages":"56","suppressedMessages":"57","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/antoine/Desktop/superdiff/eslint.config.mjs",[],[],"/Users/antoine/Desktop/superdiff/index.ts",[],[],"/Users/antoine/Desktop/superdiff/tsup.config.ts",[],[],"/Users/antoine/Desktop/superdiff/src/index.ts",[],[],"/Users/antoine/Desktop/superdiff/src/list-diff.ts",[],[],"/Users/antoine/Desktop/superdiff/src/model.ts",[],[],"/Users/antoine/Desktop/superdiff/src/object-diff.ts",[],[],"/Users/antoine/Desktop/superdiff/src/utils.ts",[],[],"/Users/antoine/Desktop/superdiff/test/list-diff.test.ts",[],[],"/Users/antoine/Desktop/superdiff/test/object-diff.test.ts",[],[],"/Users/antoine/Desktop/superdiff/test/utils.test.ts",[],[]]
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index e507da3..19e6239 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/node_modules
-dist
\ No newline at end of file
+dist
+.eslintcache
\ No newline at end of file
diff --git a/README.md b/README.md
index f902834..255351d 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,27 @@
-# SUPERDIFF
-
-This library compares two arrays or objects and returns a full diff of their differences.
[](https://github.com/DoneDeal0/superdiff/actions/workflows/ci.yml)
[](https://github.com/DoneDeal0/superdiff/actions/workflows/cd.yml)


+
+
+# WHAT IS IT?
+
+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. 👎
+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**!
@@ -27,111 +34,7 @@ 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:
-
-```diff
-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:
-
-```js
-[
- {
- kind: "E",
- path: ["user", "member"],
- lhs: true,
- rhs: false,
- },
- {
- kind: "E",
- path: ["user", "hobbies", 1],
- lhs: "football",
- rhs: "chess",
- },
-];
-```
-
-**SuperDiff** output:
-
-```diff
-{
- 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
@@ -158,17 +61,17 @@ type ObjectDiff = {
status: "added" | "deleted" | "equal" | "updated";
diff: {
property: string;
- previousValue: any;
- currentValue: any;
+ previousValue: unknown;
+ currentValue: unknow;
status: "added" | "deleted" | "equal" | "updated";
// only appears if some subproperties have been added/deleted/updated
- subPropertiesDiff?: {
+ diff?: {
property: string;
- previousValue: any;
- currentValue: any;
+ previousValue: unknown;
+ currentValue: unknown;
status: "added" | "deleted" | "equal" | "updated";
- // subDiff is a recursive diff in case of nested subproperties
- subDiff?: SubProperties[];
+ // recursive diff in case of subproperties
+ diff?: SubDiff[];
}[];
}[];
};
@@ -217,7 +120,7 @@ type ListDiff = {
type: "list";
status: "added" | "deleted" | "equal" | "moved" | "updated";
diff: {
- value: any;
+ value: unknown;
prevIndex: number | null;
newIndex: number | null;
indexDiff: number | null;
@@ -270,6 +173,8 @@ import { isObject } from "@donedeal0/superdiff";
Tests whether a value is an object.
+
+
## EXAMPLES
### getListDiff()
@@ -384,7 +289,7 @@ output
age: 66,
},
+ status: "updated",
- subPropertiesDiff: [
+ diff: [
{
property: "name",
previousValue: "joe",
diff --git a/eslint.config.mjs b/eslint.config.mjs
index b8b52ab..769dd55 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -7,10 +7,4 @@ export default [
{ settings: { react: { version: "detect" } } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
- {
- rules: {
- "@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/ban-ts-comment": "off"
- },
- },
];
diff --git a/package.json b/package.json
index 5defdb4..d1be0f4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@donedeal0/superdiff",
- "version": "1.1.3",
+ "version": "2.0.0",
"description": "SuperDiff checks the changes between two objects or arrays. It returns a complete diff with relevant information for each property or piece of data",
"main": "dist/index.js",
"module": "dist/index.mjs",
diff --git a/src/index.ts b/src/index.ts
index 59898d6..8eba074 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,5 @@
export { getObjectDiff } from "./object-diff";
export { getListDiff } from "./list-diff";
export { isEqual, isObject } from "./utils";
-export * from "./model";
+export * from "./models/list";
+export * from "./models/object";
diff --git a/src/list-diff.ts b/src/list-diff.ts
index 143ec3f..0675938 100644
--- a/src/list-diff.ts
+++ b/src/list-diff.ts
@@ -1,17 +1,22 @@
-import { LIST_STATUS, ListDiff, ListDiffStatus, ListOptions } from "./model";
+import {
+ DEFAULT_LIST_DIFF_OPTIONS,
+ LIST_STATUS,
+ ListDiff,
+ ListDiffOptions,
+} from "./models/list";
import { isEqual, isObject } from "./utils";
function getLeanDiff(
diff: ListDiff["diff"],
- showOnly = [] as ListOptions["showOnly"],
+ showOnly = [] as ListDiffOptions["showOnly"],
): ListDiff["diff"] {
return diff.filter((value) => showOnly?.includes(value.status));
}
function formatSingleListDiff(
listData: T[],
- status: ListDiffStatus,
- options: ListOptions = { showOnly: [] },
+ status: LIST_STATUS,
+ options: ListDiffOptions = { showOnly: [] },
): ListDiff {
const diff = listData.map((data, i) => ({
value: data,
@@ -34,16 +39,16 @@ function formatSingleListDiff(
};
}
-function getListStatus(listDiff: ListDiff["diff"]): ListDiffStatus {
+function getListStatus(listDiff: ListDiff["diff"]): LIST_STATUS {
return listDiff.some((value) => value.status !== LIST_STATUS.EQUAL)
? LIST_STATUS.UPDATED
: LIST_STATUS.EQUAL;
}
function isReferencedObject(
- value: any,
- referenceProperty: ListOptions["referenceProperty"],
-): value is Record {
+ value: unknown,
+ referenceProperty: ListDiffOptions["referenceProperty"],
+): value is Record {
if (isObject(value) && !!referenceProperty) {
return Object.hasOwn(value, referenceProperty);
}
@@ -62,12 +67,7 @@ function isReferencedObject(
export const getListDiff = (
prevList: T[] | undefined | null,
nextList: T[] | undefined | null,
- options: ListOptions = {
- showOnly: [],
- referenceProperty: undefined,
- considerMoveAsUpdate: false,
- ignoreArrayOrder: false,
- },
+ options: ListDiffOptions = DEFAULT_LIST_DIFF_OPTIONS,
): ListDiff => {
if (!prevList && !nextList) {
return {
diff --git a/src/model.ts b/src/model.ts
deleted file mode 100644
index 55abfbd..0000000
--- a/src/model.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-export const STATUS: Record = {
- ADDED: "added",
- EQUAL: "equal",
- DELETED: "deleted",
- UPDATED: "updated",
-};
-
-export const LIST_STATUS: Record = {
- ...STATUS,
- MOVED: "moved",
-};
-
-export const GRANULARITY: Record = {
- BASIC: "basic",
- DEEP: "deep",
-};
-
-export type ListDiffStatus =
- | "added"
- | "equal"
- | "moved"
- | "deleted"
- | "updated";
-export type ObjectDiffStatus = "added" | "equal" | "deleted" | "updated";
-export type ObjectData = Record | undefined | null;
-export type ListData = any;
-
-export type ObjectStatusTuple = readonly [
- "added",
- "equal",
- "deleted",
- "updated",
-];
-export type ListStatusTuple = readonly [
- "added",
- "equal",
- "deleted",
- "moved",
- "updated",
-];
-
-export type isEqualOptions = {
- ignoreArrayOrder?: boolean;
-};
-
-export type ObjectOptions = {
- ignoreArrayOrder?: boolean;
- showOnly?: {
- statuses: Array;
- granularity?: (typeof GRANULARITY)[keyof typeof GRANULARITY];
- };
-};
-
-export type ListOptions = {
- showOnly?: Array;
- referenceProperty?: string;
- considerMoveAsUpdate?: boolean;
- ignoreArrayOrder?: boolean;
-};
-
-export type ListDiff = {
- type: "list";
- status: ListDiffStatus;
- diff: {
- value: ListData;
- prevIndex: number | null;
- newIndex: number | null;
- indexDiff: number | null;
- status: ListDiffStatus;
- }[];
-};
-
-export type SubProperties = {
- property: string;
- previousValue: any;
- currentValue: any;
- status: ObjectDiffStatus;
- subPropertiesDiff?: SubProperties[];
-};
-
-export type ObjectDiff = {
- type: "object";
- status: ObjectDiffStatus;
- diff: {
- property: string;
- previousValue: any;
- currentValue: any;
- status: ObjectDiffStatus;
- subPropertiesDiff?: SubProperties[];
- }[];
-};
-
-export type DataDiff = ListDiff | ObjectDiff;
diff --git a/src/models/list.ts b/src/models/list.ts
new file mode 100644
index 0000000..79fc9ba
--- /dev/null
+++ b/src/models/list.ts
@@ -0,0 +1,35 @@
+export enum LIST_STATUS {
+ ADDED = "added",
+ EQUAL = "equal",
+ DELETED = "deleted",
+ UPDATED = "updated",
+ MOVED = "moved",
+}
+
+export type ListData = unknown;
+
+export type ListDiffOptions = {
+ showOnly?: `${LIST_STATUS}`[];
+ referenceProperty?: string;
+ considerMoveAsUpdate?: boolean;
+ ignoreArrayOrder?: boolean;
+};
+
+export const DEFAULT_LIST_DIFF_OPTIONS = {
+ showOnly: [],
+ referenceProperty: undefined,
+ considerMoveAsUpdate: false,
+ ignoreArrayOrder: false,
+};
+
+export type ListDiff = {
+ type: "list";
+ status: LIST_STATUS;
+ diff: {
+ value: ListData;
+ prevIndex: number | null;
+ newIndex: number | null;
+ indexDiff: number | null;
+ status: LIST_STATUS;
+ }[];
+};
diff --git a/src/models/object.ts b/src/models/object.ts
new file mode 100644
index 0000000..86fa19e
--- /dev/null
+++ b/src/models/object.ts
@@ -0,0 +1,41 @@
+export enum OBJECT_STATUS {
+ ADDED = "added",
+ EQUAL = "equal",
+ DELETED = "deleted",
+ UPDATED = "updated",
+}
+
+export enum GRANULARITY {
+ BASIC = "basic",
+ DEEP = "deep",
+}
+
+export type ObjectData = Record | undefined | null;
+
+export type ObjectDiffOptions = {
+ ignoreArrayOrder?: boolean;
+ showOnly?: {
+ statuses: `${OBJECT_STATUS}`[];
+ granularity?: `${GRANULARITY}`;
+ };
+};
+
+export const DEFAULT_OBJECT_DIFF_OPTIONS = {
+ ignoreArrayOrder: false,
+ showOnly: { statuses: [], granularity: GRANULARITY.BASIC },
+};
+
+/** recursive diff in case of subproperties */
+export type Diff = {
+ property: string;
+ previousValue: unknown;
+ currentValue: unknown;
+ status: OBJECT_STATUS;
+ diff?: Diff[];
+};
+
+export type ObjectDiff = {
+ type: "object";
+ status: OBJECT_STATUS;
+ diff: Diff[];
+};
diff --git a/src/models/utils.ts b/src/models/utils.ts
new file mode 100644
index 0000000..f8f0e86
--- /dev/null
+++ b/src/models/utils.ts
@@ -0,0 +1,3 @@
+export type isEqualOptions = {
+ ignoreArrayOrder?: boolean;
+};
diff --git a/src/object-diff.ts b/src/object-diff.ts
index 2c4cd63..1eb02ec 100644
--- a/src/object-diff.ts
+++ b/src/object-diff.ts
@@ -1,42 +1,25 @@
import {
GRANULARITY,
- STATUS,
+ OBJECT_STATUS,
ObjectData,
ObjectDiff,
- ObjectDiffStatus,
- ObjectOptions,
- SubProperties,
-} from "./model";
+ ObjectDiffOptions,
+ Diff,
+ DEFAULT_OBJECT_DIFF_OPTIONS,
+} from "./models/object";
import { isEqual, isObject } from "./utils";
function getLeanDiff(
diff: ObjectDiff["diff"],
- showOnly: ObjectOptions["showOnly"] = {
- statuses: [],
- granularity: GRANULARITY.BASIC,
- },
+ showOnly: ObjectDiffOptions["showOnly"] = DEFAULT_OBJECT_DIFF_OPTIONS.showOnly,
): ObjectDiff["diff"] {
const { statuses, granularity } = showOnly;
return diff.reduce(
(acc, value) => {
- if (granularity === GRANULARITY.DEEP && value.subPropertiesDiff) {
- const cleanSubPropertiesDiff = getLeanDiff(
- value.subPropertiesDiff,
- showOnly,
- );
- if (cleanSubPropertiesDiff.length > 0) {
- return [
- ...acc,
- { ...value, subPropertiesDiff: cleanSubPropertiesDiff },
- ];
- }
- }
- // @ts-ignore
- if (granularity === GRANULARITY.DEEP && value.subDiff) {
- // @ts-ignore
- const cleanSubDiff = getLeanDiff(value.subDiff, showOnly);
- if (cleanSubDiff.length > 0) {
- return [...acc, { ...value, subDiff: cleanSubDiff }];
+ if (granularity === GRANULARITY.DEEP && value.diff) {
+ const leanDiff = getLeanDiff(value.diff, showOnly);
+ if (leanDiff.length > 0) {
+ return [...acc, { ...value, diff: leanDiff }];
}
}
if (statuses.includes(value.status)) {
@@ -48,51 +31,50 @@ function getLeanDiff(
);
}
-function getObjectStatus(diff: ObjectDiff["diff"]): ObjectDiffStatus {
- return diff.some((property) => property.status !== STATUS.EQUAL)
- ? STATUS.UPDATED
- : STATUS.EQUAL;
+function getObjectStatus(diff: ObjectDiff["diff"]): OBJECT_STATUS {
+ return diff.some((property) => property.status !== OBJECT_STATUS.EQUAL)
+ ? OBJECT_STATUS.UPDATED
+ : OBJECT_STATUS.EQUAL;
}
function formatSingleObjectDiff(
data: ObjectData,
- status: ObjectDiffStatus,
- options: ObjectOptions = {
- ignoreArrayOrder: false,
- showOnly: { statuses: [], granularity: GRANULARITY.BASIC },
- },
+ status: OBJECT_STATUS,
+ options: ObjectDiffOptions = DEFAULT_OBJECT_DIFF_OPTIONS,
): ObjectDiff {
if (!data) {
return {
type: "object",
- status: STATUS.EQUAL,
+ status: OBJECT_STATUS.EQUAL,
diff: [],
};
}
const diff: ObjectDiff["diff"] = [];
Object.entries(data).forEach(([property, value]) => {
if (isObject(value)) {
- const subPropertiesDiff: SubProperties[] = [];
+ const subPropertiesDiff: Diff[] = [];
Object.entries(value).forEach(([subProperty, subValue]) => {
subPropertiesDiff.push({
property: subProperty,
- previousValue: status === STATUS.ADDED ? undefined : subValue,
- currentValue: status === STATUS.ADDED ? subValue : undefined,
+ previousValue: status === OBJECT_STATUS.ADDED ? undefined : subValue,
+ currentValue: status === OBJECT_STATUS.ADDED ? subValue : undefined,
status,
});
});
return diff.push({
- property: property,
- previousValue: status === STATUS.ADDED ? undefined : data[property],
- currentValue: status === STATUS.ADDED ? value : undefined,
+ property,
+ previousValue:
+ status === OBJECT_STATUS.ADDED ? undefined : data[property],
+ currentValue: status === OBJECT_STATUS.ADDED ? value : undefined,
status,
- subPropertiesDiff,
+ diff: subPropertiesDiff,
});
}
return diff.push({
property,
- previousValue: status === STATUS.ADDED ? undefined : data[property],
- currentValue: status === STATUS.ADDED ? value : undefined,
+ previousValue:
+ status === OBJECT_STATUS.ADDED ? undefined : data[property],
+ currentValue: status === OBJECT_STATUS.ADDED ? value : undefined,
status,
});
});
@@ -111,10 +93,10 @@ function formatSingleObjectDiff(
}
function getPreviousMatch(
- previousValue: any | undefined,
- nextSubProperty: any,
- options?: ObjectOptions,
-): any | undefined {
+ previousValue: unknown | undefined,
+ nextSubProperty: unknown,
+ options?: ObjectDiffOptions,
+): unknown | undefined {
if (!previousValue) {
return undefined;
}
@@ -125,28 +107,28 @@ function getPreviousMatch(
}
function getValueStatus(
- previousValue: any,
- nextValue: any,
- options?: ObjectOptions,
-): ObjectDiffStatus {
+ previousValue: unknown,
+ nextValue: unknown,
+ options?: ObjectDiffOptions,
+): OBJECT_STATUS {
if (isEqual(previousValue, nextValue, options)) {
- return STATUS.EQUAL;
+ return OBJECT_STATUS.EQUAL;
}
- return STATUS.UPDATED;
+ return OBJECT_STATUS.UPDATED;
}
-function getPropertyStatus(
- subPropertiesDiff: SubProperties[],
-): ObjectDiffStatus {
- return subPropertiesDiff.some((property) => property.status !== STATUS.EQUAL)
- ? STATUS.UPDATED
- : STATUS.EQUAL;
+function getPropertyStatus(subPropertiesDiff: Diff[]): OBJECT_STATUS {
+ return subPropertiesDiff.some(
+ (property) => property.status !== OBJECT_STATUS.EQUAL,
+ )
+ ? OBJECT_STATUS.UPDATED
+ : OBJECT_STATUS.EQUAL;
}
function getDeletedProperties(
- previousValue: Record | undefined,
- nextValue: Record,
-): { property: string; value: any }[] | undefined {
+ previousValue: Record | undefined,
+ nextValue: Record,
+): { property: string; value: unknown }[] | undefined {
if (!previousValue) return undefined;
const prevKeys = Object.keys(previousValue);
const nextKeys = Object.keys(nextValue);
@@ -161,12 +143,12 @@ function getDeletedProperties(
}
function getSubPropertiesDiff(
- previousValue: Record | undefined,
- nextValue: Record,
- options?: ObjectOptions,
-): SubProperties[] {
- const subPropertiesDiff: SubProperties[] = [];
- let subDiff: SubProperties[];
+ previousValue: Record | undefined,
+ nextValue: Record,
+ options?: ObjectDiffOptions,
+): Diff[] {
+ const subPropertiesDiff: Diff[] = [];
+ let subDiff: Diff[];
const deletedMainSubProperties = getDeletedProperties(
previousValue,
nextValue,
@@ -177,7 +159,7 @@ function getSubPropertiesDiff(
property: deletedProperty.property,
previousValue: deletedProperty.value,
currentValue: undefined,
- status: STATUS.DELETED,
+ status: OBJECT_STATUS.DELETED,
});
});
}
@@ -194,15 +176,15 @@ function getSubPropertiesDiff(
currentValue: nextSubValue,
status:
!previousValue || !(nextSubProperty in previousValue)
- ? STATUS.ADDED
+ ? OBJECT_STATUS.ADDED
: previousMatch === nextSubValue
- ? STATUS.EQUAL
- : STATUS.UPDATED,
+ ? OBJECT_STATUS.EQUAL
+ : OBJECT_STATUS.UPDATED,
});
}
if (isObject(nextSubValue)) {
- const data: SubProperties[] = getSubPropertiesDiff(
- previousMatch,
+ const data: Diff[] = getSubPropertiesDiff(
+ previousMatch as Record,
nextSubValue,
options,
);
@@ -216,7 +198,7 @@ function getSubPropertiesDiff(
previousValue: previousMatch,
currentValue: nextSubValue,
status: getValueStatus(previousMatch, nextSubValue, options),
- ...(!!subDiff && { subDiff }),
+ ...(!!subDiff && { diff: subDiff }),
});
}
});
@@ -225,9 +207,9 @@ function getSubPropertiesDiff(
/**
* Returns the diff between two objects
- * @param {Record} prevData - The original object.
- * @param {Record} nextData - The new object.
- * * @param {ListOptions} options - Options to refine your output.
+ * @param {ObjectData} prevData - The original object.
+ * @param {ObjectData} nextData - The new object.
+ * * @param {ObjectOptions} options - Options to refine your output.
- `showOnly`: returns only the values whose status you are interested in. It takes two parameters: `statuses` and `granularity`
`statuses` are the status you want to see in the output (e.g. `["added", "equal"]`)
`granularity` can be either `basic` (to return only the main properties whose status matches your query) or `deep` (to return the main properties if some of their subproperties' status match your request. The subproperties are filtered accordingly).
@@ -237,23 +219,20 @@ function getSubPropertiesDiff(
export function getObjectDiff(
prevData: ObjectData,
nextData: ObjectData,
- options: ObjectOptions = {
- ignoreArrayOrder: false,
- showOnly: { statuses: [], granularity: GRANULARITY.BASIC },
- },
+ options: ObjectDiffOptions = DEFAULT_OBJECT_DIFF_OPTIONS,
): ObjectDiff {
if (!prevData && !nextData) {
return {
type: "object",
- status: STATUS.EQUAL,
+ status: OBJECT_STATUS.EQUAL,
diff: [],
};
}
if (!prevData) {
- return formatSingleObjectDiff(nextData, STATUS.ADDED, options);
+ return formatSingleObjectDiff(nextData, OBJECT_STATUS.ADDED, options);
}
if (!nextData) {
- return formatSingleObjectDiff(prevData, STATUS.DELETED, options);
+ return formatSingleObjectDiff(prevData, OBJECT_STATUS.DELETED, options);
}
const diff: ObjectDiff["diff"] = [];
Object.entries(nextData).forEach(([nextProperty, nextValue]) => {
@@ -264,15 +243,15 @@ export function getObjectDiff(
previousValue,
currentValue: nextValue,
status: !(nextProperty in prevData)
- ? STATUS.ADDED
+ ? OBJECT_STATUS.ADDED
: previousValue === nextValue
- ? STATUS.EQUAL
- : STATUS.UPDATED,
+ ? OBJECT_STATUS.EQUAL
+ : OBJECT_STATUS.UPDATED,
});
}
if (isObject(nextValue)) {
- const subPropertiesDiff: SubProperties[] = getSubPropertiesDiff(
- previousValue,
+ const subPropertiesDiff: Diff[] = getSubPropertiesDiff(
+ previousValue as Record,
nextValue,
options,
);
@@ -282,7 +261,9 @@ export function getObjectDiff(
previousValue,
currentValue: nextValue,
status: subPropertyStatus,
- ...(subPropertyStatus !== STATUS.EQUAL && { subPropertiesDiff }),
+ ...(subPropertyStatus !== OBJECT_STATUS.EQUAL && {
+ diff: subPropertiesDiff,
+ }),
});
}
return diff.push({
@@ -299,7 +280,7 @@ export function getObjectDiff(
property: deletedProperty.property,
previousValue: deletedProperty.value,
currentValue: undefined,
- status: STATUS.DELETED,
+ status: OBJECT_STATUS.DELETED,
});
});
}
diff --git a/src/utils.ts b/src/utils.ts
index e5945c4..b0662bd 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -1,15 +1,15 @@
-import { isEqualOptions } from "./model";
+import { isEqualOptions } from "./models/utils";
/**
* Returns true if two data are equal
- * @param {any} a - The original data.
- * @param {any} b - The data to compare.
+ * @param {unknown} a - The original data.
+ * @param {unknown} b - The data to compare.
* @param {isEqualOptions} options - The options to compare the data.
* @returns boolean
*/
export function isEqual(
- a: any,
- b: any,
+ a: unknown,
+ b: unknown,
options: isEqualOptions = { ignoreArrayOrder: false },
): boolean {
if (typeof a !== typeof b) return false;
@@ -19,7 +19,7 @@ export function isEqual(
}
if (options.ignoreArrayOrder) {
return a.every((v) =>
- b.some((nextV: any) => JSON.stringify(nextV) === JSON.stringify(v)),
+ b.some((nextV) => JSON.stringify(nextV) === JSON.stringify(v)),
);
}
return a.every((v, i) => JSON.stringify(v) === JSON.stringify(b[i]));
@@ -32,9 +32,9 @@ export function isEqual(
/**
* Returns true if the provided value is an object
- * @param {any} value - The data to check.
- * @returns value is Record
+ * @param {unknown} value - The data to check.
+ * @returns value is Record
*/
-export function isObject(value: any): value is Record {
+export function isObject(value: unknown): value is Record {
return !!value && typeof value === "object" && !Array.isArray(value);
}
diff --git a/test/list-diff.test.ts b/test/list-diff.test.ts
index f526528..6826d9a 100644
--- a/test/list-diff.test.ts
+++ b/test/list-diff.test.ts
@@ -1,4 +1,5 @@
import { getListDiff } from "../src/list-diff";
+import { LIST_STATUS } from "../src/models/list";
describe("getListDiff", () => {
it("returns an empty diff if no lists are provided", () => {
@@ -416,7 +417,7 @@ describe("getListDiff", () => {
false,
{ name: "joe", age: 88 },
],
- { showOnly: ["added", "deleted"] },
+ { showOnly: [LIST_STATUS.ADDED, LIST_STATUS.DELETED] },
),
).toStrictEqual({
type: "list",
@@ -461,7 +462,7 @@ describe("getListDiff", () => {
});
expect(
getListDiff(["mbappe", "mendes", "verratti", "ruiz"], null, {
- showOnly: ["moved", "updated"],
+ showOnly: [LIST_STATUS.MOVED, LIST_STATUS.UPDATED],
}),
).toStrictEqual({
type: "list",
@@ -472,7 +473,7 @@ describe("getListDiff", () => {
it("returns all values if their status match the required statuses", () => {
expect(
getListDiff(null, ["mbappe", "mendes", "verratti", "ruiz"], {
- showOnly: ["added"],
+ showOnly: [LIST_STATUS.ADDED],
}),
).toStrictEqual({
type: "list",
diff --git a/test/object-diff.test.ts b/test/object-diff.test.ts
index 8673ffc..bb3c0c7 100644
--- a/test/object-diff.test.ts
+++ b/test/object-diff.test.ts
@@ -1,3 +1,4 @@
+import { GRANULARITY, OBJECT_STATUS } from "../src/models/object";
import { getObjectDiff } from "../src/object-diff";
describe("getObjectDiff", () => {
@@ -189,7 +190,7 @@ describe("getObjectDiff", () => {
nickname: "super joe",
},
status: "updated",
- subPropertiesDiff: [
+ diff: [
{
property: "age",
previousValue: 66,
@@ -294,7 +295,7 @@ describe("getObjectDiff", () => {
},
},
status: "updated",
- subPropertiesDiff: [
+ diff: [
{
property: "name",
previousValue: "joe",
@@ -318,7 +319,7 @@ describe("getObjectDiff", () => {
},
},
status: "updated",
- subDiff: [
+ diff: [
{
property: "member",
previousValue: true,
@@ -336,7 +337,7 @@ describe("getObjectDiff", () => {
golf: ["st andrews"],
},
status: "updated",
- subDiff: [
+ diff: [
{
property: "rugby",
previousValue: ["france"],
@@ -420,7 +421,7 @@ describe("getObjectDiff", () => {
nickname: "super joe",
},
status: "updated",
- subPropertiesDiff: [
+ diff: [
{
property: "age",
previousValue: 66,
@@ -485,7 +486,7 @@ describe("getObjectDiff", () => {
nickname: "super joe",
},
},
- { showOnly: { statuses: ["added"] } },
+ { showOnly: { statuses: [OBJECT_STATUS.ADDED] } },
),
).toStrictEqual({
type: "object",
@@ -523,7 +524,12 @@ describe("getObjectDiff", () => {
nickname: "super joe",
},
},
- { showOnly: { statuses: ["added", "deleted"], granularity: "deep" } },
+ {
+ showOnly: {
+ statuses: [OBJECT_STATUS.ADDED, OBJECT_STATUS.DELETED],
+ granularity: GRANULARITY.DEEP,
+ },
+ },
),
).toStrictEqual({
type: "object",
@@ -550,7 +556,7 @@ describe("getObjectDiff", () => {
nickname: "super joe",
},
status: "updated",
- subPropertiesDiff: [
+ diff: [
{
property: "age",
previousValue: 66,
@@ -605,8 +611,8 @@ describe("getObjectDiff", () => {
},
{
showOnly: {
- statuses: ["updated"],
- granularity: "deep",
+ statuses: [OBJECT_STATUS.UPDATED],
+ granularity: GRANULARITY.DEEP,
},
},
),
@@ -637,7 +643,7 @@ describe("getObjectDiff", () => {
},
},
status: "updated",
- subPropertiesDiff: [
+ diff: [
{
property: "data",
previousValue: {
@@ -655,7 +661,7 @@ describe("getObjectDiff", () => {
},
},
status: "updated",
- subDiff: [
+ diff: [
{
property: "hobbies",
previousValue: {
@@ -667,7 +673,7 @@ describe("getObjectDiff", () => {
golf: ["st andrews"],
},
status: "updated",
- subDiff: [
+ diff: [
{
property: "football",
previousValue: ["psg"],
@@ -713,8 +719,8 @@ describe("getObjectDiff", () => {
},
{
showOnly: {
- statuses: ["added"],
- granularity: "deep",
+ statuses: [OBJECT_STATUS.ADDED],
+ granularity: GRANULARITY.DEEP,
},
},
),
@@ -744,7 +750,7 @@ describe("getObjectDiff", () => {
},
},
status: "updated",
- subPropertiesDiff: [
+ diff: [
{
property: "data",
previousValue: {
@@ -761,7 +767,7 @@ describe("getObjectDiff", () => {
},
},
status: "updated",
- subDiff: [
+ diff: [
{
property: "hobbies",
previousValue: {
@@ -772,7 +778,7 @@ describe("getObjectDiff", () => {
golf: ["st andrews"],
},
status: "updated",
- subDiff: [
+ diff: [
{
property: "football",
previousValue: undefined,
@@ -803,7 +809,12 @@ describe("getObjectDiff", () => {
age: 54,
hobbies: ["golf", "football"],
},
- { showOnly: { statuses: ["deleted"], granularity: "deep" } },
+ {
+ showOnly: {
+ statuses: [OBJECT_STATUS.DELETED],
+ granularity: GRANULARITY.DEEP,
+ },
+ },
),
).toStrictEqual({
type: "object",
@@ -819,7 +830,12 @@ describe("getObjectDiff", () => {
hobbies: ["golf", "football"],
},
null,
- { showOnly: { statuses: ["added"], granularity: "deep" } },
+ {
+ showOnly: {
+ statuses: [OBJECT_STATUS.ADDED],
+ granularity: GRANULARITY.DEEP,
+ },
+ },
),
).toStrictEqual({
type: "object",
@@ -831,7 +847,7 @@ describe("getObjectDiff", () => {
getObjectDiff(
{ name: "joe", age: 54, hobbies: ["golf", "football"] },
null,
- { showOnly: { statuses: ["deleted"] } },
+ { showOnly: { statuses: [OBJECT_STATUS.DELETED] } },
),
).toStrictEqual({
type: "object",