Skip to content

Commit

Permalink
Add merge()
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed Mar 20, 2022
1 parent fab8e99 commit 9dafb90
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/config/normalize/lib/wild_wild_utils/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { find } from './find.js'
export { pick, include, exclude } from './include/main.js'
export { map } from './map.js'
export { push, unshift } from './merge.js'
export { push, unshift, merge } from './merge.js'
55 changes: 52 additions & 3 deletions src/config/normalize/lib/wild_wild_utils/merge.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import deepmerge from 'deepmerge'
import isPlainObj from 'is-plain-obj'

import { map } from './map.js'

// eslint-disable-next-line max-params
const pushUnshift = function (mapFunc, target, query, newValues, opts = {}) {
return map(target, query, (value) => mapFunc(value, newValues, opts.mutate), {
return map(target, query, (value) => mapFunc(value, newValues, opts), {
...opts,
entries: false,
})
}

const pushValue = function (value, newValues, mutate) {
const pushValue = function (value, newValues, { mutate }) {
if (!Array.isArray(value)) {
return newValues
}
Expand All @@ -27,7 +30,7 @@ const pushValue = function (value, newValues, mutate) {
// Like `set()` but push an array of values to the target array instead
export const push = pushUnshift.bind(undefined, pushValue)

const unshiftValue = function (value, newValues, mutate) {
const unshiftValue = function (value, newValues, { mutate }) {
if (!Array.isArray(value)) {
return newValues
}
Expand All @@ -45,3 +48,49 @@ const unshiftValue = function (value, newValues, mutate) {

// Like `push()` but from the beginning
export const unshift = pushUnshift.bind(undefined, unshiftValue)

// Only own properties are currently merged, even if `inherited` is `true`.
// Non-enumerable properties are ignored.
const mergeValue = function (value, newValue, { mutate, classes, deep }) {
const isMergeableObject = getIsMergeableObject(classes)
return deep
? deepmerge(value, newValue, { clone: !mutate, isMergeableObject })
: shallowMergeValue({ value, newValue, mutate, isMergeableObject })
}

const shallowMergeValue = function ({
value,
newValue,
mutate,
isMergeableObject,
}) {
if (!isMergeableObject(value)) {
return newValue
}

if (!mutate) {
return { ...value, ...newValue }
}

Object.keys(newValue).forEach((key) => {
// eslint-disable-next-line no-param-reassign, fp/no-mutation
value[key] = newValue[key]
})
return value
}

// Use similar recursion logic as `iterate()` depending on `classes`
const getIsMergeableObject = function (classes) {
return classes ? isObjArr : isPlainObjArr
}

const isObjArr = function (value) {
return typeof value === 'object' && value !== null
}

const isPlainObjArr = function (value) {
return isPlainObj(value) || Array.isArray(value)
}

// Merge object values
export const merge = pushUnshift.bind(undefined, mergeValue)

0 comments on commit 9dafb90

Please sign in to comment.