UNPKG

@augment-vir/common

Version:

A collection of augments, helpers types, functions, and classes for any JavaScript environment.

150 lines (149 loc) 5.21 kB
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); }