UNPKG

differify-js

Version:

Differify allows you to get the diff between two entities (objects diff, arrays diff, date diff, functions diff, number diff, etc) very easily, quickly and in a friendly way.

245 lines 9.08 kB
/*! * Copyright(c) 2020 Fabian Roberto Orue <fabianorue@gmail.com> * BSD Licensed */ import PROPERTY_STATUS from './enums/property-status'; import { buildDiff, buildDeepDiff } from './property-diff-model'; import { has } from './utils/validations'; export function valueRefEqualityComparator(a, b) { if (a === b) { return buildDiff(a, b, PROPERTY_STATUS.EQUAL); } return buildDiff(a, b, PROPERTY_STATUS.MODIFIED, 1); } export function dateComparator(aDate, bDate) { if (aDate.getTime() === bDate.getTime()) { return buildDiff(aDate, bDate, PROPERTY_STATUS.EQUAL); } return buildDiff(aDate, bDate, PROPERTY_STATUS.MODIFIED, 1); } export function arraySimpleComparator(aArr, bArr) { if (aArr.length === bArr.length) { if (JSON.stringify(aArr) === JSON.stringify(bArr)) { return buildDiff(aArr, bArr, PROPERTY_STATUS.EQUAL); } } return buildDiff(aArr, bArr, PROPERTY_STATUS.MODIFIED, 1); } export function JSONStringComparator(a, b) { if (JSON.stringify(a) === JSON.stringify(b)) { return buildDiff(a, b, PROPERTY_STATUS.EQUAL); } return buildDiff(a, b, PROPERTY_STATUS.MODIFIED, 1); } export function toStringComparator(a, b) { if (a.toString() === b.toString()) { return buildDiff(a, b, PROPERTY_STATUS.EQUAL); } return buildDiff(a, b, PROPERTY_STATUS.MODIFIED, 1); } /** * Compare each element keeping the order of each one. * @param {*} aArr * @param {*} bArr */ export function getConfiguredOrderedDeepArrayComparator(multipleComparator) { function orderedDeepArrayComparator(aArr, bArr) { let maxArr; let minArr; let listALargerThanB = 0; // 0 equal \ -1 a major | 1 b major if (aArr.length > bArr.length || aArr.length === bArr.length) { maxArr = aArr; minArr = bArr; listALargerThanB = -1; } else { maxArr = bArr; minArr = aArr; listALargerThanB = 1; } const ret = []; let changes = 0; let i; for (i = 0; i < minArr.length; ++i) { ret.push(multipleComparator(aArr[i], bArr[i])); changes += ret[i].changes || 0; } if (listALargerThanB === -1) { for (i; i < maxArr.length; ++i) { ret.push(buildDiff(aArr[i], null, PROPERTY_STATUS.DELETED, 1)); ++changes; } } else if (listALargerThanB === 1) { for (i; i < maxArr.length; ++i) { ret.push(buildDiff(null, bArr[i], PROPERTY_STATUS.ADDED, 1)); ++changes; } } return buildDeepDiff(ret, changes > 0 ? PROPERTY_STATUS.MODIFIED : PROPERTY_STATUS.EQUAL, changes); } return orderedDeepArrayComparator; } /** * Compare the array in an unordered way, without having in mind the * order of each element. It will look for equality if not, the element * is treated as a difference. * @param {*} multipleComparator */ export function getConfiguredUnorderedDeepArrayComparator(multipleComparator) { function deepUnorderedArrayComparator(aArr, bArr) { let maxArr; if (aArr.length >= bArr.length) { maxArr = aArr; } else { maxArr = bArr; } let changes = 0; let i; const ret = []; let key; let comparatorRes; let currElement; let currMapElement; let keyList; const comparisonPairsMap = Object.create(null); for (i = 0; i < maxArr.length; ++i) { if (i < aArr.length) { currElement = aArr[i]; key = JSON.stringify(currElement); keyList = comparisonPairsMap[key]; if (keyList !== undefined && keyList.length > 0) { currMapElement = keyList[keyList.length - 1]; if (currMapElement.b !== null) { comparatorRes = multipleComparator(currElement, currMapElement.b); ret.push(comparatorRes); keyList.pop(); if (keyList.length === 0) { delete comparisonPairsMap[key]; } } else { keyList.unshift({ a: currElement, b: null, }); } } else { comparisonPairsMap[key] = [ { a: currElement, b: null, }, ]; } } if (i < bArr.length) { currElement = bArr[i]; key = JSON.stringify(currElement); keyList = comparisonPairsMap[key]; if (keyList !== undefined && keyList.length > 0) { currMapElement = keyList[keyList.length - 1]; if (currMapElement.a !== null) { comparatorRes = multipleComparator(currMapElement.a, currElement); ret.push(comparatorRes); keyList.pop(); if (keyList.length === 0) { delete comparisonPairsMap[key]; } } else { keyList.unshift({ a: null, b: currElement, }); } } else { comparisonPairsMap[key] = [ { a: null, b: currElement, }, ]; } } } //matchAll let uncomparedPair = Object.create(null); uncomparedPair.a = []; uncomparedPair.b = []; for (let key in comparisonPairsMap) { keyList = comparisonPairsMap[key]; for (let i = 0; i < keyList.length; ++i) { currMapElement = keyList[i]; if (currMapElement.a) { if (uncomparedPair.b.length > 0) { comparatorRes = multipleComparator(currMapElement.a, uncomparedPair.b.pop()); changes += comparatorRes.changes; ret.push(comparatorRes); } else { uncomparedPair.a.unshift(currMapElement.a); } } else if (currMapElement.b) { if (uncomparedPair.a.length > 0) { comparatorRes = multipleComparator(uncomparedPair.a.pop(), currMapElement.b); changes += comparatorRes.changes; ret.push(comparatorRes); } else { uncomparedPair.b.unshift(currMapElement.b); } } } } for (let i = uncomparedPair.a.length - 1; i > -1; --i) { ret.push(buildDiff(uncomparedPair.a[i], null, PROPERTY_STATUS.DELETED, 1)); ++changes; } for (let i = uncomparedPair.b.length - 1; i > -1; --i) { ret.push(buildDiff(null, uncomparedPair.b[i], PROPERTY_STATUS.ADDED, 1)); ++changes; } return buildDeepDiff(ret, changes > 0 ? PROPERTY_STATUS.MODIFIED : PROPERTY_STATUS.EQUAL, changes); } return deepUnorderedArrayComparator; } export function getConfiguredDeepObjectComparator(multipleComparator) { function deepObjectComparator(a, b) { const ret = {}; let aLength = 0; let bLength = 0; let changes = 0; for (const propA in a) { if (has(a, propA)) { ++aLength; if (has(b, propA)) { ret[propA] = multipleComparator(a[propA], b[propA]); } else { ret[propA] = buildDiff(a[propA], null, PROPERTY_STATUS.DELETED, 1); } changes += ret[propA].changes; } } for (const propB in b) { if (has(b, propB)) { ++bLength; if (!has(a, propB)) { //TODO: avoid multiple indirections. ret[propB] = buildDiff(null, b[propB], PROPERTY_STATUS.ADDED, 1); changes += ret[propB].changes; } } } return aLength === 0 && bLength === 0 ? buildDeepDiff(null, PROPERTY_STATUS.EQUAL, changes) : buildDeepDiff(ret, changes > 0 ? PROPERTY_STATUS.MODIFIED : PROPERTY_STATUS.EQUAL, changes); } return deepObjectComparator; } //# sourceMappingURL=comparators.js.map