UNPKG

chain-able

Version:

interfaces that describe their intentions.

138 lines (124 loc) 3.93 kB
const isObjStrict = require('../is/objStrict') const isArray = require('../is/array') const isTrue = require('../is/true') const ObjectKeys = require('../util/keys') const ObjectAssign = require('../util/assign') const isUndefined = require('../is/undefined') const isRegExp = require('../is/regexp') const isDate = require('../is/date') const isBoolean = require('../is/boolean') const isString = require('../is/string') const simpleKindOf = require('../util/simpleKindOf') const includes = require('../conditional/includes') // 1: not null object // 2: object toString is not a date or regex function isMergeableObj(val) { return isObjStrict(val) && !isRegExp(val) && !isDate(val) } function emptyTarget(val) { return isArray(val) ? [] : {} } function cloneIfNeeded(value, optsArg) { return isTrue(optsArg.clone) && isMergeableObj(value) ? deepmerge(emptyTarget(value), value, optsArg) : value } /* prettier-ignore */ function defaultArrayMerge(target, source, optsArg) { var destination = target.slice() for (var i = 0; i < source.length; i++) { var v = source[i] if (isUndefined(destination[i])) { destination[i] = cloneIfNeeded(v, optsArg) } else if (isMergeableObj(v)) { destination[i] = deepmerge(target[i], v, optsArg) } // @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT // === -1 // eslint-disable-next-line prefer-includes/prefer-includes else if (!~target.indexOf(v)) { destination.push(cloneIfNeeded(v, optsArg)) } } return destination } function mergeObj(target, source, optsArg) { var destination = {} if (isMergeableObj(target)) { var targetKeys = ObjectKeys(target) for (var k = 0; k < targetKeys.length; k++) { destination[targetKeys[k]] = cloneIfNeeded(target[targetKeys[k]], optsArg) } } var sourceKeys = ObjectKeys(source) for (var s = 0; s < sourceKeys.length; s++) { var key = sourceKeys[s] if (!isMergeableObj(source[key]) || !target[key]) { destination[key] = cloneIfNeeded(source[key], optsArg) } else { destination[key] = deepmerge(target[key], source[key], optsArg) } } return destination } function deepmerge(target, source, optsArg) { if (isArray(source)) { const {arrayMerge} = optsArg return isArray(target) ? arrayMerge(target, source, optsArg) : cloneIfNeeded(source, optsArg) } // else return mergeObj(target, source, optsArg) } /* prettier-ignore */ // eslint-disable-next-line complexity function dopemerge(obj1, obj2, opts) { // if they are identical, fastest === check if (obj1 === obj2) { return obj1 } // setup options const options = ObjectAssign( { arrayMerge: defaultArrayMerge, stringToArray: true, boolToArray: false, ignoreTypes: ['null', 'undefined'], // debug: true, }, opts || {} ) const {ignoreTypes, stringToArray, boolToArray, clone} = options // @NOTE: much better size but oh well // const ignoreTypes = ['null', 'undefined'] // const stringToArray = true // const boolToArray = false // const clone = true // check one then check the other if (isTrue(includes(ignoreTypes, simpleKindOf(obj1)))) { return obj2 } else if (isTrue(includes(ignoreTypes, simpleKindOf(obj2)))) { return obj1 } // @NOTE uglifier optimizes into a wicked ternary else if (isBoolean(obj1) && isBoolean(obj2)) { return boolToArray ? [obj1, obj2] : obj2 } else if (isString(obj1) && isString(obj2)) { return stringToArray ? [obj1, obj2] : obj1 + obj2 } else if (isArray(obj1) && isString(obj2)) { return (clone ? obj1.slice(0) : obj1).concat([obj2]) } else if (isString(obj1) && isArray(obj2)) { return (clone ? obj2.slice(0) : obj2).concat([obj1]) } else { return deepmerge(obj1, obj2, options) } } module.exports = dopemerge