diff --git a/src/config.js b/src/config.js index 521171cbf7d..af0fd12de88 100644 --- a/src/config.js +++ b/src/config.js @@ -16,6 +16,7 @@ import { isValidPriceConfig } from './cpmBucketManager.js'; import find from 'core-js/library/fn/array/find.js'; import includes from 'core-js/library/fn/array/includes.js'; import Set from 'core-js/library/fn/set.js'; +import { mergeDeep } from './utils.js'; const from = require('core-js/library/fn/array/from.js'); const utils = require('./utils.js'); @@ -254,7 +255,7 @@ export function newConfig() { memo[topic] = currBidderConfig[topic]; } else { if (utils.isPlainObject(currBidderConfig[topic])) { - memo[topic] = Object.assign({}, config[topic], currBidderConfig[topic]); + memo[topic] = mergeDeep({}, config[topic], currBidderConfig[topic]); } else { memo[topic] = currBidderConfig[topic]; } diff --git a/src/utils.js b/src/utils.js index 0fe924510e0..e7b937a970d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -265,6 +265,10 @@ function decorateLog(args, prefix) { return args; } +export function hasConsoleLogger() { + return consoleLogExists; +} + export function debugTurnedOn() { return !!config.getConfig('debug'); } @@ -1166,3 +1170,27 @@ export function buildUrl(obj) { export function deepEqual(obj1, obj2) { return deepequal(obj1, obj2); } + +export function mergeDeep(target, ...sources) { + if (!sources.length) return target; + const source = sources.shift(); + + if (isPlainObject(target) && isPlainObject(source)) { + for (const key in source) { + if (isPlainObject(source[key])) { + if (!target[key]) Object.assign(target, { [key]: {} }); + mergeDeep(target[key], source[key]); + } else if (isArray(source[key])) { + if (!target[key]) { + Object.assign(target, { [key]: source[key] }); + } else if (isArray(target[key])) { + target[key] = target[key].concat(source[key]); + } + } else { + Object.assign(target, { [key]: source[key] }); + } + } + } + + return mergeDeep(target, ...sources); +} diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index 29bba0ec0a0..8ee345166e1 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -216,7 +216,7 @@ describe('adapterManager tests', function () { buildRequests: { data: 1 }, - test1: { speedy: true }, + test1: { speedy: true, fun: { test: true } }, interpretResponse: 'baseInterpret', afterInterpretResponse: 'anotherBaseInterpret' }); @@ -253,7 +253,7 @@ describe('adapterManager tests', function () { data: 1, test: 2 }, - { fun: { safe: true, cheap: false }, speedy: true }, + { fun: { safe: true, cheap: false, test: true }, speedy: true }, { amazing: true }, 'appnexusInterpret', 'anotherBaseInterpret' @@ -262,14 +262,14 @@ describe('adapterManager tests', function () { { data: 1 }, - { speedy: true }, + { fun: { test: true }, speedy: true }, undefined, 'baseInterpret', 'anotherBaseInterpret' ], 'rubicon': [ 'rubiconBuild', - { speedy: true }, + { fun: { test: true }, speedy: true }, { amazing: true }, null, 'anotherBaseInterpret' diff --git a/test/spec/utils_spec.js b/test/spec/utils_spec.js index 2c29877f724..96df3cf996c 100644 --- a/test/spec/utils_spec.js +++ b/test/spec/utils_spec.js @@ -1018,4 +1018,101 @@ describe('Utils', function () { expect(utils.isSafariBrowser()).to.equal(false); }); }); + + describe('mergeDeep', function() { + it('properly merge objects that share same property names', function() { + const object1 = { + propA: { + subPropA: 'abc' + } + }; + const object2 = { + propA: { + subPropB: 'def' + } + }; + + const resultWithoutMergeDeep = Object.assign({}, object1, object2); + expect(resultWithoutMergeDeep).to.deep.equal({ + propA: { + subPropB: 'def' + } + }); + + const resultWithMergeDeep = utils.mergeDeep({}, object1, object2); + expect(resultWithMergeDeep).to.deep.equal({ + propA: { + subPropA: 'abc', + subPropB: 'def' + } + }); + }); + + it('properly merge objects that have different depths', function() { + const object1 = { + depth0_A: { + depth1_A: { + depth2_A: 123 + } + } + }; + const object2 = { + depth0_A: { + depth1_A: { + depth2_B: { + depth3_A: { + depth4_A: 'def' + } + } + }, + depth1_B: 'abc' + } + }; + const object3 = { + depth0_B: 456 + }; + + const result = utils.mergeDeep({}, object1, object2, object3); + expect(result).to.deep.equal({ + depth0_A: { + depth1_A: { + depth2_A: 123, + depth2_B: { + depth3_A: { + depth4_A: 'def' + } + } + }, + depth1_B: 'abc' + }, + depth0_B: 456 + }); + }); + + it('properly merge objects with various property types', function() { + const object1 = { + depth0_A: { + depth1_A: ['a', 'b', 'c'], + depth1_B: 'abc', + depth1_C: 123 + } + }; + const object2 = { + depth0_A: { + depth1_A: ['d', 'e', 'f'], + depth1_D: true, + } + }; + + const result = utils.mergeDeep({}, object1, object2); + expect(result).to.deep.equal({ + depth0_A: { + depth1_A: ['a', 'b', 'c', 'd', 'e', 'f'], + depth1_B: 'abc', + depth1_C: 123, + depth1_D: true, + } + }); + }); + }); });