UNPKG

@obsidize/rx-map

Version:

ES6 Map with rxjs extensions for change detection

80 lines (79 loc) 3.09 kB
import { transform, isEqual, merge, cloneDeep } from 'lodash'; import { ChangeDetectionResultType } from '../events/change-detection-event'; export function identity(value, ..._args) { return value; } export function isNull(value) { return typeof value === null; } export function isUndefined(value) { return typeof value === 'undefined'; } export function isFunction(value) { return typeof value === 'function'; } export function isObject(value) { return typeof value === 'object' && !isNull(value); } export function castArray(v) { return isObject(v) && Array.isArray(v) ? v : [v]; } export function mergeObjects(a, b) { return merge(a, b); } export function cloneObject(v) { return cloneDeep(v); } // Shamelessly stolen from here: // https://gist.github.com/Yimiprod/7ee176597fef230d1451#gistcomment-2565071 export function deepDifferenceBetween(current, previous) { return transform(current, (result, currentValue, key) => { const previousValue = previous[key]; if (isEqual(currentValue, previousValue)) return; const recurse = (isObject(currentValue) && isObject(previousValue)); result[key] = recurse ? deepDifferenceBetween(currentValue, previousValue) : currentValue; }); } /** * Evaluates changes between the two given values, * and constructs a change detection event instance based on the evaluation output. * * The output in the "changes" object will consist of all the values that have changed * when transitioning from 'baseObj' to 'obj', and the plucked values will match the ones in 'obj'. */ export function detectChanges(current, previous) { const withType = (type, changes) => { const result = { type }; if (changes) result.changes = changes; return result; }; if (isEqual(current, previous)) return withType(ChangeDetectionResultType.NO_CHANGE); if (current && !previous) return withType(ChangeDetectionResultType.CREATE); if (!current && previous) return withType(ChangeDetectionResultType.DELETE); return withType(ChangeDetectionResultType.UPDATE, deepDifferenceBetween(current, previous)); } /** * Convenience for running change detection on a map state change event and storing the results in the event. * This is implemented as an optional utility since change detection might not be necessary in some cases, * and can be quite expensive to run. */ export function extractChanges(ev) { const { value, previousValue } = ev; const result = detectChanges(value, previousValue); ev.changes = result.changes; ev.changeType = result.type; return ev; } /** * Special variant of change detection that compares against an accumulated state. */ export function detectAccumulatedChanges(acc, current) { const previous = acc ? acc.current : undefined; const changeDetectionResult = detectChanges(current, previous); return Object.assign({ current, previous }, changeDetectionResult); }