@augment-vir/common
Version:
A collection of augments, helpers types, functions, and classes for any JavaScript environment.
150 lines (149 loc) • 5.21 kB
JavaScript
import { check } from '@augment-vir/assert';
import { getObjectTypedKeys } from '@augment-vir/core';
/**
* Extract all nested object keys and values that are different between the two given objects.
*
* @category Object
* @category Package : @augment-vir/common
* @returns An empty tuple if the values are equal. Otherwise, the first tuple entry contains the
* changes in the first value, second entry contains the changes in the second value.
* @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common)
*/
export function diffObjects(object0, object1) {
const allObjectKeys = Array.from(new Set([
...getObjectTypedKeys(object0),
...getObjectTypedKeys(object1),
]));
const diffOutput = allObjectKeys.reduce((accum, objectKey) => {
const value0 = object0[objectKey];
const value1 = object1[objectKey];
const diffOutput = diffValues(value0, value1);
if (!diffOutput.length) {
return accum;
}
if (!(objectKey in object0)) {
accum[1][objectKey] = diffOutput[1];
}
else if (objectKey in object1) {
accum[0][objectKey] = diffOutput[0];
accum[1][objectKey] = diffOutput[1];
}
else {
accum[0][objectKey] = diffOutput[0];
}
return accum;
}, [
{},
{},
]);
if (!Object.keys(diffOutput[0]).length && !Object.keys(diffOutput[1]).length) {
return [];
}
else {
return diffOutput;
}
}
/**
* Extract all entries in the given arrays that are not equal.
*
* @category Object
* @category Package : @augment-vir/common
* @returns An empty tuple if the values are equal. Otherwise, the first tuple entry contains the
* changes in the first value, second entry contains the changes in the second value.
* @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common)
*/
export function diffArrays(array0, array1) {
const allArrayIndexes = Array.from(new Set([
...Object.keys(array0),
...Object.keys(array1),
].map((index) => Number(index)))).sort();
const diffArrays = allArrayIndexes.reduce((accum, arrayIndex) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const value0 = array0[arrayIndex];
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const value1 = array1[arrayIndex];
const diffOutput = diffValues(value0, value1);
if (diffOutput.length) {
if (arrayIndex in array0) {
accum[0].push(diffOutput[0]);
}
if (arrayIndex in array1) {
accum[1].push(diffOutput[1]);
}
}
return accum;
}, [
[],
[],
]);
if (!diffArrays[0].length && !diffArrays[1].length) {
return [];
}
else {
return diffArrays;
}
}
/**
* Simple diff check that is useful simply to return the same format as the other diff functions.
*
* @category Object
* @category Package : @augment-vir/common
* @returns An empty tuple if the values are equal. Otherwise, the first tuple entry contains the
* changes in the first value, second entry contains the changes in the second value.
* @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common)
*/
export function diffBasic(value0, value1,
/** A custom equality checker. Defaults to a strict equality check (`===`). */
areEqual = (value0, value1) => value0 === value1) {
if (areEqual(value0, value1)) {
return [];
}
else {
return [
value0,
value1,
];
}
}
const orderedValueDiffs = [
(value0, value1) => {
if (!check.isArray(value0) || !check.isArray(value1)) {
return undefined;
}
return diffArrays(value0, value1);
},
(value0, value1) => {
if (!check.instanceOf(value0, RegExp) || !check.instanceOf(value1, RegExp)) {
return undefined;
}
/** Special case RegExps because they should be checked for equality as strings. */
return diffBasic(value0, value1, (a, b) => String(a) === String(b));
},
(value0, value1) => {
if (!check.isObject(value0) || !check.isObject(value1)) {
return undefined;
}
return diffObjects(value0, value1);
},
];
/**
* Diff any values. For diffing objects, use `diffObjects` to get better types.
*
* @category Object
* @category Package : @augment-vir/common
* @returns An empty tuple if the values are equal. Otherwise, the first tuple entry contains the
* changes in the first value, second entry contains the changes in the second value.
* @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common)
*/
export function diffValues(value0, value1) {
let diffOutput = undefined;
orderedValueDiffs.some((differ) => {
diffOutput = differ(value0, value1);
return !!diffOutput;
});
if (diffOutput) {
return diffOutput;
}
/** Fallback to the basic diff. */
return diffBasic(value0, value1);
}