Skip to content

feat: allow referenceProperty for object comparison in lists #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions .github/workflows/superdiff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,18 @@ jobs:

strategy:
matrix:
node-version: [16.x, 18.x]
node-version: [18.x]

steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
cache: "npm"
- name: Install dependencies
uses: borales/actions-yarn@v4
with:
cmd: install
run: npm install
- name: Build app
uses: borales/actions-yarn@v4
with:
cmd: build
run: npm run build
- name: Test app
uses: borales/actions-yarn@v4
with:
cmd: test
run: npm test
34 changes: 18 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

# SUPERDIFF

This library compares two arrays or objects and return a complete diff of their differences.
This library compares two arrays or objects and returns a full diff of their differences.

[![Superdiff CI](https://github.com/DoneDeal0/superdiff/actions/workflows/superdiff.yml/badge.svg)](https://github.com/DoneDeal0/superdiff/actions/workflows/superdiff.yml)

## WHY YOU SHOULD USE THIS LIB
## WHY YOU SHOULD USE THIS LIBRARY

All other existing solutions return a weird diff format which often require an 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 <u>and</u> objects with a very readable format. Last but not least, it's battled tested and super fast. Import. Enjoy. 👍
**Superdiff** gives you a complete diff for both array <u>and</u> objects in a very readable format. Last but not least, it's battle-tested and super fast. Import. Enjoy. 👍

## DIFF FORMAT COMPARISON

Expand Down Expand Up @@ -173,27 +173,27 @@ You can add a third `options` parameter to `getObjectDiff`.
}
```

- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be considered as `equal`, because the two arrays have the same value, just not in the same order.
- `showOnly`: only returns the values whose status interest you. It has two parameters:
- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be treated as `equal`, 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 (ex: `["added", "equal"]`)
- `statuses`: status you want to see in the output (e.g. `["added", "equal"]`)
- `granularity`:
- `basic` only returns the main properties whose status match your request.
- `deep` can return main properties if some of their subproperties' status match your request. The subproperties will be filtered accordingly.
- `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()

```js
import { getListDiff } from "@donedeal0/superdiff";
```

Compares two arrays and return a diff for each value:
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 duplicated values
- supports arrays with duplicate values

format:

Expand All @@ -218,18 +218,20 @@ You can add a third `options` parameter to `getListDiff`.
```ts
{
showOnly?: ("added" | "deleted" | "moved" | "updated" | "equal")[], // [] by default
referenceProperty?: string; // "" by default
}
```

- `showOnly` gives you the option to only return the values whose status interest you (ex: `["added", "equal"]`).
- `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 its `id`. This option has no effect on other datatypes.

### isEqual()

```js
import { isEqual } from "@donedeal0/superdiff";
```

Checks if two values are equal.
Tests whether two values are equal.

**Options**

Expand All @@ -241,15 +243,15 @@ You can add a third `options` parameter to `isEqual`.
}
```

- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be considered as `equal`, because the two arrays have the same value, just not in the same order.
- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be treated as `equal`, because the two arrays have the same value, just not in the same order.

### isObject()

```js
import { isObject } from "@donedeal0/superdiff";
```

Checks if a value is an object.
Tests whether a value is an object.

## EXAMPLES

Expand Down Expand Up @@ -431,7 +433,7 @@ output
false;
```

More examples are available in the tests of the source code.
More examples are available in the source code tests.

<hr/>

Expand Down
93 changes: 93 additions & 0 deletions dist/index.d.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
declare const GRANULARITY: Record<string, "basic" | "deep">;
type ListDiffStatus = "added" | "equal" | "moved" | "deleted" | "updated";
type ObjectDiffStatus = "added" | "equal" | "deleted" | "updated";
type ObjectData = Record<string, any> | undefined | null;
type ListData = any;
type ObjectStatusTuple = readonly [
"added",
"equal",
"deleted",
"updated"
];
type ListStatusTuple = readonly [
"added",
"equal",
"deleted",
"moved",
"updated"
];
type isEqualOptions = {
ignoreArrayOrder?: boolean;
};
type ObjectOptions = {
ignoreArrayOrder?: boolean;
showOnly?: {
statuses: Array<ObjectStatusTuple[number]>;
granularity?: (typeof GRANULARITY)[keyof typeof GRANULARITY];
};
};
type ListOptions = {
showOnly?: Array<ListStatusTuple[number]>;
referenceProperty?: string;
};
type ListDiff = {
type: "list";
status: ListDiffStatus;
diff: {
value: ListData;
prevIndex: number | null;
newIndex: number | null;
indexDiff: number | null;
status: ListDiffStatus;
}[];
};
type SubProperties = {
property: string;
previousValue: any;
currentValue: any;
status: ObjectDiffStatus;
subPropertiesDiff?: SubProperties[];
};
type ObjectDiff = {
type: "object";
status: ObjectDiffStatus;
diff: {
property: string;
previousValue: any;
currentValue: any;
status: ObjectDiffStatus;
subPropertiesDiff?: SubProperties[];
}[];
};

/**
* Returns the diff between two objects
* @param {Record<string, any>} prevData - The original object.
* @param {Record<string, any>} nextData - The new object.
* @returns ObjectDiff
*/
declare function getObjectDiff(prevData: ObjectData, nextData: ObjectData, options?: ObjectOptions): ObjectDiff;

/**
* Returns the diff between two arrays
* @param {Array<T>} prevList - The original array.
* @param {Array<T>} nextList - The new array.
* @returns ListDiff
*/
declare const getListDiff: <T>(prevList: T[] | null | undefined, nextList: T[] | null | undefined, options?: ListOptions) => ListDiff;

/**
* Returns true if two data are equal
* @param {any} a - The original data.
* @param {any} b- The data to compare.
* @returns boolean
*/
declare function isEqual(a: any, b: any, options?: isEqualOptions): boolean;
/**
* Returns true if the provided value is an object
* @param {any} value - The data to check.
* @returns value is Record<string, any>
*/
declare function isObject(value: any): value is Record<string, any>;

export { getListDiff, getObjectDiff, isEqual, isObject };
28 changes: 26 additions & 2 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ type ObjectOptions = {
ignoreArrayOrder?: boolean;
showOnly?: {
statuses: Array<ObjectStatusTuple[number]>;
granularity?: typeof GRANULARITY[keyof typeof GRANULARITY];
granularity?: (typeof GRANULARITY)[keyof typeof GRANULARITY];
};
};
type ListOptions = {
showOnly?: Array<ListStatusTuple[number]>;
referenceProperty?: string;
};
type ListDiff = {
type: "list";
Expand Down Expand Up @@ -59,11 +60,34 @@ type ObjectDiff = {
}[];
};

/**
* Returns the diff between two objects
* @param {Record<string, any>} prevData - The original object.
* @param {Record<string, any>} nextData - The new object.
* @returns ObjectDiff
*/
declare function getObjectDiff(prevData: ObjectData, nextData: ObjectData, options?: ObjectOptions): ObjectDiff;

declare const getListDiff: (prevList: ListData[] | undefined | null, nextList: ListData[] | undefined | null, options?: ListOptions) => ListDiff;
/**
* Returns the diff between two arrays
* @param {Array<T>} prevList - The original array.
* @param {Array<T>} nextList - The new array.
* @returns ListDiff
*/
declare const getListDiff: <T>(prevList: T[] | null | undefined, nextList: T[] | null | undefined, options?: ListOptions) => ListDiff;

/**
* Returns true if two data are equal
* @param {any} a - The original data.
* @param {any} b- The data to compare.
* @returns boolean
*/
declare function isEqual(a: any, b: any, options?: isEqualOptions): boolean;
/**
* Returns true if the provided value is an object
* @param {any} value - The data to check.
* @returns value is Record<string, any>
*/
declare function isObject(value: any): value is Record<string, any>;

export { getListDiff, getObjectDiff, isEqual, isObject };
10 changes: 5 additions & 5 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading