2017-04-19 00:55:46 +00:00
|
|
|
import isPlainObject from 'lodash/isPlainObject'
|
2018-11-28 00:56:13 +00:00
|
|
|
import _omitBy from 'lodash/omitBy'
|
|
|
|
|
2017-04-19 00:55:46 +00:00
|
|
|
import wrap from './wrap'
|
2018-11-28 00:56:13 +00:00
|
|
|
import constant from './constant'
|
|
|
|
|
|
|
|
const innerOmitted = { __omitted: true }
|
|
|
|
export const omitted = constant(innerOmitted)
|
2015-08-09 06:32:52 +00:00
|
|
|
|
2015-11-16 16:13:01 +00:00
|
|
|
function isEmpty(object) {
|
2017-04-19 00:55:46 +00:00
|
|
|
return !Object.keys(object).length
|
2015-11-16 16:13:01 +00:00
|
|
|
}
|
|
|
|
|
2015-08-09 06:32:52 +00:00
|
|
|
function reduce(object, callback, initialValue) {
|
2017-04-19 00:55:46 +00:00
|
|
|
return Object.keys(object).reduce(
|
|
|
|
(acc, key) => callback(acc, object[key], key),
|
|
|
|
initialValue
|
|
|
|
)
|
2015-08-09 06:32:52 +00:00
|
|
|
}
|
|
|
|
|
2015-08-13 05:04:31 +00:00
|
|
|
function resolveUpdates(updates, object) {
|
2017-04-19 00:55:46 +00:00
|
|
|
return reduce(
|
|
|
|
updates,
|
|
|
|
(acc, value, key) => {
|
|
|
|
let updatedValue = value
|
|
|
|
|
|
|
|
if (
|
2018-11-27 17:32:22 +00:00
|
|
|
!Array.isArray(value) &&
|
|
|
|
value !== null &&
|
|
|
|
typeof value === 'object'
|
2017-04-19 00:55:46 +00:00
|
|
|
) {
|
|
|
|
updatedValue = update(value, object[key]) // eslint-disable-line no-use-before-define
|
|
|
|
} else if (typeof value === 'function') {
|
|
|
|
updatedValue = value(object[key])
|
|
|
|
}
|
|
|
|
|
|
|
|
if (object[key] !== updatedValue) {
|
|
|
|
acc[key] = updatedValue // eslint-disable-line no-param-reassign
|
|
|
|
}
|
|
|
|
|
|
|
|
return acc
|
|
|
|
},
|
|
|
|
{}
|
|
|
|
)
|
2015-07-31 16:16:19 +00:00
|
|
|
}
|
|
|
|
|
2015-08-05 07:27:56 +00:00
|
|
|
function updateArray(updates, object) {
|
2017-04-19 00:55:46 +00:00
|
|
|
const newArray = [...object]
|
2015-07-31 16:16:19 +00:00
|
|
|
|
2020-04-02 14:16:13 +00:00
|
|
|
Object.keys(updates).forEach((key) => {
|
2017-04-19 00:55:46 +00:00
|
|
|
newArray[key] = updates[key]
|
|
|
|
})
|
2015-08-09 06:32:52 +00:00
|
|
|
|
2017-04-19 00:55:46 +00:00
|
|
|
return newArray
|
2015-07-31 16:16:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2015-07-31 16:16:19 +00:00
|
|
|
*/
|
2015-08-05 11:29:30 +00:00
|
|
|
function update(updates, object, ...args) {
|
2015-07-31 16:16:19 +00:00
|
|
|
if (typeof updates === 'function') {
|
2017-04-19 00:55:46 +00:00
|
|
|
return updates(object, ...args)
|
2015-07-31 16:16:19 +00:00
|
|
|
}
|
|
|
|
|
2015-09-15 14:50:36 +00:00
|
|
|
if (!isPlainObject(updates)) {
|
2017-04-19 00:55:46 +00:00
|
|
|
return updates
|
2015-08-05 11:28:32 +00:00
|
|
|
}
|
|
|
|
|
2018-11-27 17:32:22 +00:00
|
|
|
const defaultedObject =
|
|
|
|
typeof object === 'undefined' || object === null ? {} : object
|
2015-08-13 05:04:31 +00:00
|
|
|
|
2017-04-19 00:55:46 +00:00
|
|
|
const resolvedUpdates = resolveUpdates(updates, defaultedObject)
|
2015-07-31 16:16:19 +00:00
|
|
|
|
|
|
|
if (isEmpty(resolvedUpdates)) {
|
2017-04-19 00:55:46 +00:00
|
|
|
return defaultedObject
|
2015-07-31 16:16:19 +00:00
|
|
|
}
|
|
|
|
|
2015-08-13 05:04:31 +00:00
|
|
|
if (Array.isArray(defaultedObject)) {
|
2018-11-28 00:56:13 +00:00
|
|
|
return updateArray(resolvedUpdates, defaultedObject).filter(
|
2020-04-02 14:16:13 +00:00
|
|
|
(value) => value !== innerOmitted
|
2018-11-28 00:56:13 +00:00
|
|
|
)
|
2015-07-31 16:16:19 +00:00
|
|
|
}
|
|
|
|
|
2018-11-28 00:56:13 +00:00
|
|
|
return _omitBy(
|
|
|
|
{ ...defaultedObject, ...resolvedUpdates },
|
2020-04-02 14:16:13 +00:00
|
|
|
(value) => value === innerOmitted
|
2018-11-28 00:56:13 +00:00
|
|
|
)
|
2015-07-31 16:16:19 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 00:55:46 +00:00
|
|
|
export default wrap(update, 2)
|