updeep-remeda/lib/update.js

86 lines
2.0 KiB
JavaScript
Raw Normal View History

import wrap from './wrap';
2016-01-14 16:02:59 +00:00
import isPlainObject from 'lodash/isPlainObject';
function isEmpty(object) {
return !Object.keys(object).length;
}
function reduce(object, callback, initialValue) {
return Object.keys(object).reduce((acc, key) => {
return callback(acc, object[key], key);
}, initialValue);
}
function resolveUpdates(updates, object) {
return reduce(updates, (acc, value, key) => {
2015-08-02 06:25:08 +00:00
let updatedValue = value;
2015-08-05 04:33:27 +00:00
if (!Array.isArray(value) && value !== null && typeof value === 'object') {
2016-01-13 16:19:43 +00:00
updatedValue = update(value, object[key]); // eslint-disable-line no-use-before-define
} else if (typeof value === 'function') {
2015-08-05 07:27:56 +00:00
updatedValue = value(object[key]);
}
2015-08-05 07:27:56 +00:00
if (object[key] !== updatedValue) {
2016-01-13 16:19:43 +00:00
acc[key] = updatedValue; // eslint-disable-line no-param-reassign
}
return acc;
}, {});
}
2015-08-05 07:27:56 +00:00
function updateArray(updates, object) {
const newArray = [...object];
Object.keys(updates).forEach((key) => {
newArray[key] = updates[key];
});
return newArray;
}
/**
* Recursively update an object or array.
*
* Can update with values:
* update({ foo: 3 }, { foo: 1, bar: 2 });
* // => { foo: 3, bar: 2 }
*
* Or with a function:
* update({ foo: x => (x + 1) }, { foo: 2 });
* // => { foo: 3 }
2015-08-02 06:38:27 +00:00
*
2015-08-19 14:29:06 +00:00
* @function
* @name update
2015-08-02 06:38:27 +00:00
* @param {Object|Function} updates
* @param {Object|Array} object to update
* @return {Object|Array} new object with modifications
*/
function update(updates, object, ...args) {
if (typeof updates === 'function') {
return updates(object, ...args);
}
if (!isPlainObject(updates)) {
return updates;
}
const defaultedObject = (typeof object === 'undefined' || object === null) ?
{} :
object;
const resolvedUpdates = resolveUpdates(updates, defaultedObject);
if (isEmpty(resolvedUpdates)) {
return defaultedObject;
}
if (Array.isArray(defaultedObject)) {
return updateArray(resolvedUpdates, defaultedObject);
}
return { ...defaultedObject, ...resolvedUpdates };
}
export default wrap(update, 2);