UNPKG

@rimbu/deep

Version:

Tools to use handle plain JS objects as immutable objects

132 lines 5.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.patch = patch; var tslib_1 = require("tslib"); var base_1 = require("@rimbu/base"); /** * Returns an immutably updated version of the given `value` where the given `patchItems` have been * applied to the result. * The Rimbu patch notation is as follows: * - if the target is a simple value or array, the patch can be the same type or a function returning the same type * - if the target is a tuple (array of fixed length), the patch be the same type or an object containing numeric keys with patches indicating the tuple index to patch * - if the target is an object, the patch can be the same type, or an array containing partial keys with their patches for the object * @typeparam T - the type of the value to patch * @typeparam TE - a utility type * @typeparam TT - a utility type * @param value - the input value to patch * @param patchItem - the `Patch` value to apply to the input value * @example * ```ts * const input = { a: 1, b: { c: true, d: 'a' } } * patch(input, [{ a: 2 }]) // => { a: 2, b: { c: true, d: 'a' } } * patch(input, [{ b: [{ c: (v) => !v }] }] ) * // => { a: 1, b: { c: false, d: 'a' } } * patch(input: [{ a: (v) => v + 1, b: [{ d: 'q' }] }] ) * // => { a: 2, b: { c: true, d: 'q' } } * ``` */ function patch(value, patchItem) { return patchEntry(value, value, value, patchItem); } function patchEntry(value, parent, root, patchItem) { if (Object.is(value, patchItem)) { // patching a value with itself never changes the value return value; } if (typeof value === 'function') { // function input, directly return patch return patchItem; } if (typeof patchItem === 'function') { // function patch always needs to be resolved first var item = patchItem(value, parent, root); return patchEntry(value, parent, root, item); } if ((0, base_1.isPlainObj)(value)) { // value is plain object return patchPlainObj(value, root, patchItem); } if (Array.isArray(value)) { // value is tuple or array return patchArr(value, root, patchItem); } // value is primitive type or complex object return patchItem; } function patchPlainObj(value, root, patchItem) { var e_1, _a; if (!Array.isArray(patchItem)) { // the patch is a complete replacement of the current value return patchItem; } // patch is an array of partial updates // copy the input value var result = tslib_1.__assign({}, value); var anyChange = false; try { // loop over patches in array for (var patchItem_1 = tslib_1.__values(patchItem), patchItem_1_1 = patchItem_1.next(); !patchItem_1_1.done; patchItem_1_1 = patchItem_1.next()) { var entry = patchItem_1_1.value; // update root if needed var currentRoot = value === root ? tslib_1.__assign({}, result) : root; // keep current updated result as parent var parent = tslib_1.__assign({}, result); // loop over all the patch keys for (var key in entry) { // patch the value at the given key with the patch at that key var currentValue = result[key]; var newValue = patchEntry(currentValue, parent, currentRoot, entry[key]); if (!Object.is(currentValue, newValue)) { // if value changed, set it in result and mark change anyChange = true; result[key] = newValue; } } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (patchItem_1_1 && !patchItem_1_1.done && (_a = patchItem_1.return)) _a.call(patchItem_1); } finally { if (e_1) throw e_1.error; } } if (anyChange) { // something changed, return new value return result; } // nothing changed, return old value return value; } function patchArr(value, root, patchItem) { if (Array.isArray(patchItem)) { // value is a normal array // patch is a complete replacement of current array return patchItem; } // value is a tuple // patch is an object containing numeric keys with function values // that update the tuple at the given indices // copy the tuple var result = tslib_1.__spreadArray([], tslib_1.__read(value), false); var anyChange = false; // loop over all index keys in object for (var index in patchItem) { var numIndex = index; // patch the tuple at the given index var currentValue = result[numIndex]; var newValue = patchEntry(currentValue, value, root, patchItem[index]); if (!Object.is(newValue, currentValue)) { // if value changed, set it in result and mark change anyChange = true; result[numIndex] = newValue; } } if (anyChange) { // something changed, return new value return result; } // nothing changed, return old value return value; } //# sourceMappingURL=patch.cjs.map