Skip to content

Instantly share code, notes, and snippets.

@jonfriesen
Created December 10, 2021 00:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonfriesen/ae8254bfaa4655d1873580ae1dc1b6ce to your computer and use it in GitHub Desktop.
Save jonfriesen/ae8254bfaa4655d1873580ae1dc1b6ce to your computer and use it in GitHub Desktop.
Opinionated deepmerge
/**
* deepMerge takes two objects and overwrites the values with
* incoming values, if they are empty, undefined, or missing,
* the default values will be used.
*
* In the case of arrays, the first value in the object set
* will be used as the template and applied to all values
* in the incoming set.
*/
function deepMerge(defaultSet, incomingSet) {
const isObject = obj => obj && typeof obj === 'object'
if (!isObject(defaultSet) || !isObject(incomingSet)) {
return incomingSet
}
let keys = Object.keys(incomingSet)
for (let i = 0; i < keys.length; i++) {
let key = keys[i]
const targetValue = defaultSet[key]
const sourceValue = incomingSet[key]
if (Array.isArray(targetValue) && sourceValue === undefined || Array.isArray(sourceValue)) {
// if the source is not set or empty, use whatever the default is
if (sourceValue == undefined || sourceValue.length < 1) {
// if sourceValue is empty, use the default array
continue;
}
// we expect the first value in the default object array to be
// the template, no other values will be considered.
let templatedArrayDefault = targetValue[0]
// create a buffer array
let filledInArray = []
sourceValue.forEach(v => {
// Do a deep clone if possible, so we don't overwrite
// any reference type variables.
let clonedTemplateValue = templatedArrayDefault
if (
templatedArrayDefault instanceof Object &&
!(templatedArrayDefault instanceof Date) &&
!(templatedArrayDefault instanceof String)
) {
clonedTemplateValue = deepClone(templatedArrayDefault) // deepClone(targetValue[0])
}
filledInArray.push(deepMerge(clonedTemplateValue, v))
})
defaultSet[key] = filledInArray
} else if (isObject(targetValue) && isObject(sourceValue)) {
defaultSet[key] = deepMerge(Object.assign({}, targetValue), sourceValue)
} else {
defaultSet[key] = sourceValue
}
}
return defaultSet
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment