UNPKG

@infinite-canvas-tutorial/webcomponents

Version:
149 lines 5.84 kB
"use strict"; /** * Borrow from https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/change.ts#L62 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.isShallowEqual = exports.Delta = void 0; /** * Represents the difference between two objects of the same type. * * Both `deleted` and `inserted` partials represent the same set of added, removed or updated properties, where: * - `deleted` is a set of all the deleted values * - `inserted` is a set of all the inserted (added, updated) values * * Keeping it as pure object (without transient state, side-effects, etc.), so we won't have to instantiate it on load. */ class Delta { constructor(deleted, inserted) { this.deleted = deleted; this.inserted = inserted; } static create(deleted, inserted, modifier, modifierOptions) { const modifiedDeleted = modifier && modifierOptions !== 'inserted' ? modifier(deleted) : deleted; const modifiedInserted = modifier && modifierOptions !== 'deleted' ? modifier(inserted) : inserted; return new Delta(modifiedDeleted, modifiedInserted); } /** * Calculates the delta between two objects. * * @param prevObject - The previous state of the object. * @param nextObject - The next state of the object. * * @returns new delta instance. */ static calculate(prevObject, nextObject, modifier, postProcess) { if (prevObject === nextObject) { return Delta.empty(); } const deleted = {}; const inserted = {}; // O(n^3) here for elements, but it's not as bad as it looks: // - we do this only on store recordings, not on every frame (not for ephemerals) // - we do this only on previously detected changed elements // - we do shallow compare only on the first level of properties (not going any deeper) // - # of properties is reasonably small for (const key of this.distinctKeysIterator('full', prevObject, nextObject)) { deleted[key] = prevObject[key]; inserted[key] = nextObject[key]; } const [processedDeleted, processedInserted] = postProcess ? postProcess(deleted, inserted) : [deleted, inserted]; return Delta.create(processedDeleted, processedInserted, modifier); } static empty() { return new Delta({}, {}); } static isEmpty(delta) { return (!Object.keys(delta.deleted).length && !Object.keys(delta.inserted).length); } /** * Iterator comparing values of object properties based on the passed joining strategy. * * @yields keys of properties with different values * * WARN: it's based on shallow compare performed only on the first level and doesn't go deeper than that. */ static *distinctKeysIterator(join, object1, object2, skipShallowCompare = false) { if (object1 === object2) { return; } let keys = []; if (join === 'left') { keys = Object.keys(object1); } else if (join === 'right') { keys = Object.keys(object2); } else if (join === 'full') { keys = Array.from(new Set([...Object.keys(object1), ...Object.keys(object2)])); } for (const key of keys) { const object1Value = object1[key]; const object2Value = object2[key]; if (object1Value !== object2Value) { if (!skipShallowCompare && typeof object1Value === 'object' && typeof object2Value === 'object' && object1Value !== null && object2Value !== null && (0, exports.isShallowEqual)(object1Value, object2Value)) { continue; } yield key; } } } } exports.Delta = Delta; /** * Returns whether object/array is shallow equal. * Considers empty object/arrays as equal (whether top-level or second-level). */ const isShallowEqual = (objA, objB, comparators, debug = false) => { const aKeys = Object.keys(objA); const bKeys = Object.keys(objB); if (aKeys.length !== bKeys.length) { if (debug) { console.warn(`%cisShallowEqual: objects don't have same properties ->`, 'color: #8B4000', objA, objB); } return false; } if (comparators && Array.isArray(comparators)) { for (const key of comparators) { const ret = objA[key] === objB[key] || _defaultIsShallowComparatorFallback(objA[key], objB[key]); if (!ret) { if (debug) { console.warn(`%cisShallowEqual: ${key} not equal ->`, 'color: #8B4000', objA[key], objB[key]); } return false; } } return true; } return aKeys.every((key) => { const comparator = comparators === null || comparators === void 0 ? void 0 : comparators[key]; const ret = comparator ? comparator(objA[key], objB[key]) : objA[key] === objB[key] || _defaultIsShallowComparatorFallback(objA[key], objB[key]); if (!ret && debug) { console.warn(`%cisShallowEqual: ${key} not equal ->`, 'color: #8B4000', objA[key], objB[key]); } return ret; }); }; exports.isShallowEqual = isShallowEqual; /** use as a fallback after identity check (for perf reasons) */ const _defaultIsShallowComparatorFallback = (a, b) => { // consider two empty arrays equal if (Array.isArray(a) && Array.isArray(b) && a.length === 0 && b.length === 0) { return true; } return a === b; }; //# sourceMappingURL=Delta.js.map