From d7b97eb277924d784161297cc26d8d78d3d73044 Mon Sep 17 00:00:00 2001 From: Graham Higgins Date: Wed, 4 Dec 2024 15:46:31 -0500 Subject: [PATCH 1/4] Replace `deepAccess` with optional chaining Closes #12543 --- libraries/appnexusUtils/anKeywords.js | 2 +- libraries/fpdUtils/pageInfo.js | 4 +-- libraries/ortbConverter/processors/banner.js | 3 +- libraries/ortbConverter/processors/video.js | 6 ++-- modules/criteoBidAdapter.js | 34 +++++++++---------- modules/dfpAdServerVideo.js | 7 ++-- modules/prebidServerBidAdapter/index.js | 5 ++- .../prebidServerBidAdapter/ortbConverter.js | 6 ++-- modules/taboolaBidAdapter.js | 4 +-- modules/teadsBidAdapter.js | 28 +++++++-------- modules/userId/index.js | 3 +- src/Renderer.js | 6 ++-- src/adRendering.js | 5 ++- src/adapterManager.js | 3 +- src/auction.js | 24 ++++++------- src/bidderSettings.js | 4 +-- src/native.js | 24 ++++++------- src/prebid.js | 3 +- src/utils/gdpr.js | 4 +-- src/video.js | 8 ++--- 20 files changed, 82 insertions(+), 101 deletions(-) diff --git a/libraries/appnexusUtils/anKeywords.js b/libraries/appnexusUtils/anKeywords.js index a6fa8d7a21e..4a0da18024e 100644 --- a/libraries/appnexusUtils/anKeywords.js +++ b/libraries/appnexusUtils/anKeywords.js @@ -136,7 +136,7 @@ export function getANMapFromOrtbSegments(ortb2) { let ortbSegsArrObj = deepAccess(ortb2, path) || []; ortbSegsArrObj.forEach(segObj => { // only read segment data from known sources - const segtax = ORTB_SEGTAX_KEY_MAP[deepAccess(segObj, 'ext.segtax')]; + const segtax = ORTB_SEGTAX_KEY_MAP[segObj?.ext?.segtax]; if (segtax) { segObj.segment.forEach(seg => { // if source was in multiple locations of ortb or had multiple segments in same area, stack them together into an array diff --git a/libraries/fpdUtils/pageInfo.js b/libraries/fpdUtils/pageInfo.js index dcf172d96c8..8e02134e070 100644 --- a/libraries/fpdUtils/pageInfo.js +++ b/libraries/fpdUtils/pageInfo.js @@ -1,5 +1,3 @@ -import * as utils from '../../src/utils.js'; - /** * get page title * @returns {string} @@ -67,7 +65,7 @@ export function getReferrer(bidRequest = {}, bidderRequest = {}) { if (bidRequest.params && bidRequest.params.referrer) { pageUrl = bidRequest.params.referrer; } else { - pageUrl = utils.deepAccess(bidderRequest, 'refererInfo.page'); + pageUrl = bidderRequest?.refererInfo?.page; } return pageUrl; } diff --git a/libraries/ortbConverter/processors/banner.js b/libraries/ortbConverter/processors/banner.js index fca9598022b..877a8b9081b 100644 --- a/libraries/ortbConverter/processors/banner.js +++ b/libraries/ortbConverter/processors/banner.js @@ -1,6 +1,5 @@ import { createTrackPixelHtml, - deepAccess, inIframe, mergeDeep, sizesToSizeTuples, @@ -15,7 +14,7 @@ import {BANNER} from '../../../src/mediaTypes.js'; export function fillBannerImp(imp, bidRequest, context) { if (context.mediaType && context.mediaType !== BANNER) return; - const bannerParams = deepAccess(bidRequest, 'mediaTypes.banner'); + const bannerParams = bidRequest?.mediaTypes?.banner; if (bannerParams) { const banner = { topframe: inIframe() === true ? 0 : 1 diff --git a/libraries/ortbConverter/processors/video.js b/libraries/ortbConverter/processors/video.js index 85ab1cd6ecf..3bb4e69e24d 100644 --- a/libraries/ortbConverter/processors/video.js +++ b/libraries/ortbConverter/processors/video.js @@ -1,4 +1,4 @@ -import {deepAccess, isEmpty, logWarn, mergeDeep, sizesToSizeTuples, sizeTupleToRtbSize} from '../../../src/utils.js'; +import {isEmpty, logWarn, mergeDeep, sizesToSizeTuples, sizeTupleToRtbSize} from '../../../src/utils.js'; import {VIDEO} from '../../../src/mediaTypes.js'; import {ORTB_VIDEO_PARAMS} from '../../../src/video.js'; @@ -6,7 +6,7 @@ import {ORTB_VIDEO_PARAMS} from '../../../src/video.js'; export function fillVideoImp(imp, bidRequest, context) { if (context.mediaType && context.mediaType !== VIDEO) return; - const videoParams = deepAccess(bidRequest, 'mediaTypes.video'); + const videoParams = bidRequest?.mediaTypes?.video; if (!isEmpty(videoParams)) { const video = Object.fromEntries( // Parameters that share the same name & semantics between pbjs adUnits and imp.video @@ -27,7 +27,7 @@ export function fillVideoImp(imp, bidRequest, context) { export function fillVideoResponse(bidResponse, seatbid, context) { if (bidResponse.mediaType === VIDEO) { - if (deepAccess(context.imp, 'video.w') && deepAccess(context.imp, 'video.h')) { + if (context?.imp?.video?.w && context?.imp?.video?.h) { [bidResponse.playerWidth, bidResponse.playerHeight] = [context.imp.video.w, context.imp.video.h]; } diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index d44f947dd3e..b01e7361e3f 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -1,4 +1,4 @@ -import {deepAccess, deepSetValue, isArray, logError, logWarn, parseUrl, triggerPixel} from '../src/utils.js'; +import {deepSetValue, isArray, logError, logWarn, parseUrl, triggerPixel} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; @@ -92,7 +92,7 @@ function imp(buildImp, bidRequest, context) { } deepSetValue(imp, 'video.ext', { context: bidRequest.mediaTypes.video.context, - playersizes: parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize'), parseSize), + playersizes: parseSizes(bidRequest?.mediaTypes?.video?.playerSize, parseSize), plcmt: bidRequest.mediaTypes.video.plcmt, poddur: bidRequest.mediaTypes.video.adPodDurationSec, rqddurs: bidRequest.mediaTypes.video.durationRangeSec, @@ -156,7 +156,7 @@ function request(buildRequest, imps, bidderRequest, context) { * @returns {*} */ function bidResponse(buildBidResponse, bid, context) { - context.mediaType = deepAccess(bid, 'ext.mediatype'); + context.mediaType = bid?.ext?.mediatype; if (context.mediaType === NATIVE && typeof bid.adm_native !== 'undefined') { bid.adm = bid.adm_native; delete bid.adm_native; @@ -165,22 +165,22 @@ function bidResponse(buildBidResponse, bid, context) { let bidResponse = buildBidResponse(bid, context); const {bidRequest} = context; - bidResponse.currency = deepAccess(bid, 'ext.cur') + bidResponse.currency = bid?.ext?.cur; - if (typeof deepAccess(bid, 'ext.meta') !== 'undefined') { + if (typeof bid?.ext?.meta !== 'undefined') { deepSetValue(bidResponse, 'meta', { ...bidResponse.meta, ...bid.ext.meta }); } - if (typeof deepAccess(bid, 'ext.paf.content_id') !== 'undefined') { + if (typeof bid?.ext?.paf?.content_id !== 'undefined') { deepSetValue(bidResponse, 'meta.paf.content_id', bid.ext.paf.content_id) } if (bidResponse.mediaType === VIDEO) { bidResponse.vastUrl = bid.ext?.displayurl; // if outstream video, add a default render for it. - if (deepAccess(bidRequest, 'mediaTypes.video.context') === OUTSTREAM) { + if (bidRequest?.mediaTypes?.video?.context === OUTSTREAM) { bidResponse.renderer = createOutstreamVideoRenderer(bid); } } @@ -200,9 +200,9 @@ function bidResponse(buildBidResponse, bid, context) { function response(buildResponse, bidResponses, ortbResponse, context) { let response = buildResponse(bidResponses, ortbResponse, context); - const pafTransmission = deepAccess(ortbResponse, 'ext.paf.transmission'); + const pafTransmission = ortbResponse?.ext?.paf?.transmission; response.bids.forEach(bid => { - if (typeof pafTransmission !== 'undefined' && typeof deepAccess(bid, 'meta.paf.content_id') !== 'undefined') { + if (typeof pafTransmission !== 'undefined' && typeof bid?.meta?.paf?.content_id !== 'undefined') { deepSetValue(bid, 'meta.paf.transmission', pafTransmission); } else { delete bid.meta.paf; @@ -362,7 +362,7 @@ export const spec = { // We support native request without assets requirements because we can fill them later on. // This is a trick to fool oRTB converter isOpenRTBBidRequestValid(ortb) fn because it needs // nativeOrtbRequest.assets to be non-empty. - if (deepAccess(bidRequest, 'nativeOrtbRequest.assets') == null) { + if (bidRequest?.nativeOrtbRequest?.assets == null) { logWarn(LOG_PREFIX + 'native asset requirements are missing'); deepSetValue(bidRequest, 'nativeOrtbRequest.assets', [{}]); } @@ -391,7 +391,7 @@ export const spec = { const interpretedResponse = CONVERTER.fromORTB({response: response.body, request: request.data}); const bids = interpretedResponse.bids || []; - const fledgeAuctionConfigs = deepAccess(response.body, 'ext.igi')?.filter(igi => isArray(igi?.igs)) + const fledgeAuctionConfigs = response.body?.ext?.igi?.filter(igi => isArray(igi?.igs)) .flatMap(igi => igi.igs); if (fledgeAuctionConfigs?.length) { return { @@ -548,11 +548,11 @@ function parseSize(size) { } function hasVideoMediaType(bidRequest) { - return deepAccess(bidRequest, 'mediaTypes.video') !== undefined; + return bidRequest?.mediaTypes?.video !== undefined; } function hasNativeMediaType(bidRequest) { - return deepAccess(bidRequest, 'mediaTypes.native') !== undefined; + return bidRequest?.mediaTypes?.native !== undefined; } function hasValidVideoMediaType(bidRequest) { @@ -562,12 +562,12 @@ function hasValidVideoMediaType(bidRequest) { requiredMediaTypesParams.forEach(function (param) { if (param === 'placement') { - if (deepAccess(bidRequest, 'mediaTypes.video.' + param) === undefined && deepAccess(bidRequest, 'params.video.' + param) === undefined && deepAccess(bidRequest, 'mediaTypes.video.plcmt') === undefined && deepAccess(bidRequest, 'params.video.plcmt') === undefined) { + if (bidRequest?.mediaTypes?.video?.[param] === undefined && bidRequest?.params?.video?.[param] === undefined && bidRequest?.mediaTypes?.video?.plcmt === undefined && bidRequest?.params?.video?.plcmt === undefined) { isValid = false; logError('Criteo Bid Adapter: mediaTypes.video.' + param + ' or mediaTypes.video.plcmt is required'); } } else { - if (deepAccess(bidRequest, 'mediaTypes.video.' + param) === undefined && deepAccess(bidRequest, 'params.video.' + param) === undefined) { + if (bidRequest?.mediaTypes?.video?.[param] === undefined && bidRequest?.params?.video?.[param] === undefined) { isValid = false; logError('Criteo Bid Adapter: mediaTypes.video.' + param + ' is required'); } @@ -604,13 +604,13 @@ function getFloors(bidRequest) { if (getFloor) { if (bidRequest.mediaTypes?.banner) { floors.banner = {}; - const bannerSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')) + const bannerSizes = parseSizes(bidRequest?.mediaTypes?.banner?.sizes) bannerSizes.forEach(bannerSize => floors.banner[parseSize(bannerSize).toString()] = getFloor.call(bidRequest, { size: bannerSize, mediaType: BANNER })); } if (bidRequest.mediaTypes?.video) { floors.video = {}; - const videoSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize')) + const videoSizes = parseSizes(bidRequest?.mediaTypes?.video?.playerSize) videoSizes.forEach(videoSize => floors.video[parseSize(videoSize).toString()] = getFloor.call(bidRequest, { size: videoSize, mediaType: VIDEO })); } diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js index 3e1a716d8e7..87ead9fe980 100644 --- a/modules/dfpAdServerVideo.js +++ b/modules/dfpAdServerVideo.js @@ -14,7 +14,6 @@ import { getRefererInfo } from '../src/refererDetection.js'; import { targeting } from '../src/targeting.js'; import { buildUrl, - deepAccess, formatQS, isEmpty, isNumber, @@ -90,7 +89,7 @@ export function buildDfpVideoUrl(options) { const derivedParams = { correlator: Date.now(), - sz: parseSizesInput(deepAccess(adUnit, 'mediaTypes.video.playerSize')).join('|'), + sz: parseSizesInput(adUnit?.mediaTypes?.video?.playerSize).join('|'), url: encodeURIComponent(location.href), }; @@ -208,7 +207,7 @@ function buildUrlFromAdserverUrlComponents(components, bid, options) { * @return {string | undefined} The encoded vast url if it exists, or undefined */ function getDescriptionUrl(bid, components, prop) { - return deepAccess(components, `${prop}.description_url`) || encodeURIComponent(dep.ri().page); + return components?.[prop]?.description_url || encodeURIComponent(dep.ri().page); } /** @@ -240,7 +239,7 @@ function getCustParams(bid, options, urlCustParams) { events.emit(EVENTS.SET_TARGETING, {[adUnit.code]: prebidTargetingSet}); // merge the prebid + publisher targeting sets - const publisherTargetingSet = deepAccess(options, 'params.cust_params'); + const publisherTargetingSet = options?.params?.cust_params; const targetingSet = Object.assign({}, prebidTargetingSet, publisherTargetingSet); let encodedParams = encodeURIComponent(formatQS(targetingSet)); if (urlCustParams) { diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 33ddb9847fa..673e92f709b 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -1,6 +1,5 @@ import Adapter from '../../src/adapter.js'; import { - deepAccess, deepClone, flatten, generateUUID, @@ -450,7 +449,7 @@ export function PrebidServer() { /* Prebid executes this function when the page asks to send out bid requests */ baseAdapter.callBids = function(s2sBidRequest, bidRequests, addBidResponse, done, ajax) { - const adapterMetrics = s2sBidRequest.metrics = useMetrics(deepAccess(bidRequests, '0.metrics')) + const adapterMetrics = s2sBidRequest.metrics = useMetrics(bidRequests?.[0]?.metrics) .newMetrics() .renameWith((n) => [`adapter.s2s.${n}`, `adapters.s2s.${s2sBidRequest.s2sConfig.defaultVendor}.${n}`]) done = adapterMetrics.startTiming('total').stopBefore(done); @@ -568,7 +567,7 @@ export const processPBSRequest = hook('sync', function (s2sBidRequest, bidReques const requestJson = request && JSON.stringify(request); logInfo('BidRequest: ' + requestJson); const endpointUrl = getMatchingConsentUrl(s2sBidRequest.s2sConfig.endpoint, gdprConsent); - const customHeaders = deepAccess(s2sBidRequest, 's2sConfig.customHeaders', {}); + const customHeaders = s2sBidRequest?.s2sConfig?.customHeaders ?? {}; if (request && requestJson && endpointUrl) { const networkDone = s2sBidRequest.metrics.startTiming('net'); ajax( diff --git a/modules/prebidServerBidAdapter/ortbConverter.js b/modules/prebidServerBidAdapter/ortbConverter.js index 67cc5a372cf..9de7d3f05c9 100644 --- a/modules/prebidServerBidAdapter/ortbConverter.js +++ b/modules/prebidServerBidAdapter/ortbConverter.js @@ -1,5 +1,5 @@ import {ortbConverter} from '../../libraries/ortbConverter/converter.js'; -import {deepAccess, deepSetValue, getBidRequest, logError, logWarn, mergeDeep, timestamp} from '../../src/utils.js'; +import {deepSetValue, getBidRequest, logError, logWarn, mergeDeep, timestamp} from '../../src/utils.js'; import {config} from '../../src/config.js'; import {S2S, STATUS} from '../../src/constants.js'; import {createBid} from '../../src/bidfactory.js'; @@ -183,7 +183,7 @@ const PBS_CONVERTER = ortbConverter({ }, sourceExtSchain(orig, ortbRequest, proxyBidderRequest, context) { // pass schains in ext.prebid.schains - let chains = (deepAccess(ortbRequest, 'ext.prebid.schains') || []); + let chains = ortbRequest?.ext?.prebid?.schains || []; const chainBidders = new Set(chains.flatMap((item) => item.bidders)); chains = Object.values( @@ -192,7 +192,7 @@ const PBS_CONVERTER = ortbConverter({ .filter((req) => !chainBidders.has(req.bidderCode)) // schain defined in s2sConfig.extPrebid takes precedence .map((req) => ({ bidders: [req.bidderCode], - schain: deepAccess(req, 'bids.0.schain') + schain: req?.bids?.[0]?.schain }))) .filter(({bidders, schain}) => bidders?.length > 0 && schain) .reduce((chains, {bidders, schain}) => { diff --git a/modules/taboolaBidAdapter.js b/modules/taboolaBidAdapter.js index da7559ef144..7d1c58bcdcf 100644 --- a/modules/taboolaBidAdapter.js +++ b/modules/taboolaBidAdapter.js @@ -3,7 +3,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; -import {deepAccess, deepSetValue, getWindowSelf, replaceAuctionPrice, isArray, safeJSONParse, isPlainObject} from '../src/utils.js'; +import {deepSetValue, getWindowSelf, replaceAuctionPrice, isArray, safeJSONParse, isPlainObject} from '../src/utils.js'; import {getStorageManager} from '../src/storageManager.js'; import {ajax} from '../src/ajax.js'; import {ortbConverter} from '../libraries/ortbConverter/converter.js'; @@ -347,7 +347,7 @@ function fillTaboolaImpData(bid, imp) { imp.bidfloor = bidfloor; imp.bidfloorcur = bidfloorcur; } - deepSetValue(imp, 'ext.gpid', deepAccess(bid, 'ortb2Imp.ext.gpid')); + deepSetValue(imp, 'ext.gpid', bid?.ortb2Imp?.ext?.gpid); } function getBanners(bid, pos) { diff --git a/modules/teadsBidAdapter.js b/modules/teadsBidAdapter.js index d7b9ef9be2b..684eb679d05 100644 --- a/modules/teadsBidAdapter.js +++ b/modules/teadsBidAdapter.js @@ -1,4 +1,4 @@ -import {getValue, logError, deepAccess, parseSizesInput, isArray, getBidIdParameter} from '../src/utils.js'; +import {logError, parseSizesInput, isArray, getBidIdParameter} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {getStorageManager} from '../src/storageManager.js'; import {isAutoplayEnabled} from '../libraries/autoplayDetection/autoplay.js'; @@ -34,8 +34,8 @@ export const spec = { isBidRequestValid: function(bid) { let isValid = false; if (typeof bid.params !== 'undefined') { - let isValidPlacementId = _validateId(getValue(bid.params, 'placementId')); - let isValidPageId = _validateId(getValue(bid.params, 'pageId')); + let isValidPlacementId = _validateId(bid.params.placementId); + let isValidPageId = _validateId(bid.params.pageId); isValid = isValidPlacementId && isValidPageId; } @@ -113,12 +113,12 @@ export const spec = { payload.us_privacy = bidderRequest.uspConsent; } - const userAgentClientHints = deepAccess(firstBidRequest, 'ortb2.device.sua'); + const userAgentClientHints = firstBidRequest?.ortb2?.device?.sua; if (userAgentClientHints) { payload.userAgentClientHints = userAgentClientHints; } - const dsa = deepAccess(bidderRequest, 'ortb2.regs.ext.dsa'); + const dsa = bidderRequest?.ortb2?.regs?.ext?.dsa; if (dsa) { payload.dsa = dsa; } @@ -198,7 +198,7 @@ function getSharedViewerIdParameters(validBidRequests) { let sharedViewerIdObject = {}; for (const sharedViewerId in sharedViewerIdMapping) { const key = sharedViewerIdMapping[sharedViewerId]; - const value = deepAccess(validBidRequests, `0.userId.${key}`); + const value = validBidRequests?.[0]?.userId?.[key]; if (value) { sharedViewerIdObject[sharedViewerId] = value; } @@ -287,10 +287,10 @@ function findGdprStatus(gdprApplies, gdprData) { function buildRequestObject(bid) { const reqObj = {}; - let placementId = getValue(bid.params, 'placementId'); - let pageId = getValue(bid.params, 'pageId'); - const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid'); - const videoPlcmt = deepAccess(bid, 'mediaTypes.video.plcmt'); + let placementId = bid.params.placementId; + let pageId = bid.params.pageId; + const gpid = bid?.ortb2Imp?.ext?.gpid; + const videoPlcmt = bid?.mediaTypes?.video?.plcmt; reqObj.sizes = getSizes(bid); reqObj.bidId = getBidIdParameter('bidId', bid); @@ -309,9 +309,9 @@ function getSizes(bid) { } function concatSizes(bid) { - let playerSize = deepAccess(bid, 'mediaTypes.video.playerSize'); - let videoSizes = deepAccess(bid, 'mediaTypes.video.sizes'); - let bannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes'); + let playerSize = bid?.mediaTypes?.video?.playerSize; + let videoSizes = bid?.mediaTypes?.video?.sizes; + let bannerSizes = bid?.mediaTypes?.banner?.sizes; if (isArray(bannerSizes) || isArray(playerSize) || isArray(videoSizes)) { let mediaTypesSizes = [bannerSizes, videoSizes, playerSize]; @@ -343,7 +343,7 @@ function _validateId(id) { * @returns `{} | {firstPartyCookieTeadsId: string}` */ function getFirstPartyTeadsIdParameter(validBidRequests) { - const firstPartyTeadsIdFromUserIdModule = deepAccess(validBidRequests, '0.userId.teadsId'); + const firstPartyTeadsIdFromUserIdModule = validBidRequests?.[0]?.userId?.teadsId; if (firstPartyTeadsIdFromUserIdModule) { return {firstPartyCookieTeadsId: firstPartyTeadsIdFromUserIdModule}; diff --git a/modules/userId/index.js b/modules/userId/index.js index 2a9d1f27072..69988e00f3b 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -131,7 +131,6 @@ import { STORAGE_TYPE_LOCALSTORAGE } from '../../src/storageManager.js'; import { - deepAccess, deepSetValue, delayExecution, isArray, @@ -659,7 +658,7 @@ let initIdSystem; function getPPID(eids = getUserIdsAsEids() || []) { // userSync.ppid should be one of the 'source' values in getUserIdsAsEids() eg pubcid.org or id5-sync.com const matchingUserId = ppidSource && eids.find(userID => userID.source === ppidSource); - if (matchingUserId && typeof deepAccess(matchingUserId, 'uids.0.id') === 'string') { + if (matchingUserId && typeof matchingUserId?.uids?.[0]?.id === 'string') { const ppidValue = matchingUserId.uids[0].id.replace(/[\W_]/g, ''); if (ppidValue.length >= 32 && ppidValue.length <= 150) { return ppidValue; diff --git a/src/Renderer.js b/src/Renderer.js index 912259206c4..772d8d93655 100644 --- a/src/Renderer.js +++ b/src/Renderer.js @@ -1,6 +1,6 @@ import { loadExternalScript } from './adloader.js'; import { - logError, logWarn, logMessage, deepAccess + logError, logWarn, logMessage } from './utils.js'; import {find} from './polyfill.js'; import {getGlobal} from './prebidGlobal.js'; @@ -144,11 +144,11 @@ function isRendererPreferredFromAdUnit(adUnitCode) { } // renderer defined at adUnit level - const adUnitRenderer = deepAccess(adUnit, 'renderer'); + const adUnitRenderer = adUnit?.renderer; const hasValidAdUnitRenderer = !!(adUnitRenderer && adUnitRenderer.url && adUnitRenderer.render); // renderer defined at adUnit.mediaTypes level - const mediaTypeRenderer = deepAccess(adUnit, 'mediaTypes.video.renderer'); + const mediaTypeRenderer = adUnit?.mediaTypes?.video?.renderer; const hasValidMediaTypeRenderer = !!(mediaTypeRenderer && mediaTypeRenderer.url && mediaTypeRenderer.render) return !!( diff --git a/src/adRendering.js b/src/adRendering.js index 130ee74278d..502721dea38 100644 --- a/src/adRendering.js +++ b/src/adRendering.js @@ -1,7 +1,6 @@ import { createIframe, createInvisibleIframe, - deepAccess, inIframe, insertElement, logError, @@ -182,14 +181,14 @@ export function handleRender({renderFn, resizeFn, adId, options, bidResponse, do if (bidResponse.status === BID_STATUS.RENDERED) { logWarn(`Ad id ${adId} has been rendered before`); events.emit(STALE_RENDER, bidResponse); - if (deepAccess(config.getConfig('auctionOptions'), 'suppressStaleRender')) { + if (config.getConfig('auctionOptions')?.suppressStaleRender) { return; } } if (!filters.isBidNotExpired(bidResponse)) { logWarn(`Ad id ${adId} has been expired`); events.emit(EXPIRED_RENDER, bidResponse); - if (deepAccess(config.getConfig('auctionOptions'), 'suppressExpiredRender')) { + if (config.getConfig('auctionOptions')?.suppressExpiredRender) { return; } } diff --git a/src/adapterManager.js b/src/adapterManager.js index c39ef039af3..fb396d8d794 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -1,7 +1,6 @@ /** @module adaptermanger */ import { - deepAccess, deepClone, flatten, generateUUID, @@ -128,7 +127,7 @@ function getBids({bidderCode, auctionId, bidderRequestId, adUnits, src, metrics} adUnitCode: adUnit.code, transactionId: adUnit.transactionId, adUnitId: adUnit.adUnitId, - sizes: deepAccess(mediaTypes, 'banner.sizes') || deepAccess(mediaTypes, 'video.playerSize') || [], + sizes: mediaTypes?.banner?.sizes || mediaTypes?.video?.playerSize || [], bidId: bid.bid_id || getUniqueIdentifierStr(), bidderRequestId, auctionId, diff --git a/src/auction.js b/src/auction.js index 759397275d5..52a37743a0a 100644 --- a/src/auction.js +++ b/src/auction.js @@ -66,9 +66,7 @@ */ import { - deepAccess, generateUUID, - getValue, isEmpty, isEmptyStr, isFn, @@ -559,13 +557,12 @@ export function addBidToAuction(auctionInstance, bidResponse) { function tryAddVideoBid(auctionInstance, bidResponse, afterBidAdded, {index = auctionManager.index} = {}) { let addBid = true; - const videoMediaType = deepAccess( - index.getMediaTypes({ - requestId: bidResponse.originalRequestId || bidResponse.requestId, - adUnitId: bidResponse.adUnitId - }), 'video'); - const context = videoMediaType && deepAccess(videoMediaType, 'context'); - const useCacheKey = videoMediaType && deepAccess(videoMediaType, 'useCacheKey'); + const videoMediaType = index.getMediaTypes({ + requestId: bidResponse.originalRequestId || bidResponse.requestId, + adUnitId: bidResponse.adUnitId + })?.video; + const context = videoMediaType && videoMediaType?.context; + const useCacheKey = videoMediaType && videoMediaType?.useCacheKey; if (config.getConfig('cache.url') && (useCacheKey || context !== OUTSTREAM)) { if (!bidResponse.videoCacheKey || config.getConfig('cache.ignoreBidderCacheKey')) { @@ -684,7 +681,7 @@ function setupBidTargeting(bidObject) { export function getMediaTypeGranularity(mediaType, mediaTypes, mediaTypePriceGranularity) { if (mediaType && mediaTypePriceGranularity) { if (FEATURES.VIDEO && mediaType === VIDEO) { - const context = deepAccess(mediaTypes, `${VIDEO}.context`, 'instream'); + const context = mediaTypes?.[VIDEO]?.context ?? 'instream'; if (mediaTypePriceGranularity[`${VIDEO}-${context}`]) { return mediaTypePriceGranularity[`${VIDEO}-${context}`]; } @@ -757,7 +754,7 @@ export const getAdvertiserDomain = () => { */ export const getDSP = () => { return (bid) => { - return (bid.meta && (bid.meta.networkId || bid.meta.networkName)) ? deepAccess(bid, 'meta.networkName') || deepAccess(bid, 'meta.networkId') : ''; + return (bid.meta && (bid.meta.networkId || bid.meta.networkName)) ? bid?.meta?.networkName || bid?.meta?.networkId : ''; } } @@ -780,7 +777,7 @@ function createKeyVal(key, value) { return value(bidResponse, bidReq); } : function (bidResponse) { - return getValue(bidResponse, value); + return bidResponse[value]; } }; } @@ -829,8 +826,7 @@ export function getStandardBidderSettings(mediaType, bidderCode) { if (typeof find(adserverTargeting, targetingKeyVal => targetingKeyVal.key === TARGETING_KEYS.CACHE_HOST) === 'undefined') { adserverTargeting.push(createKeyVal(TARGETING_KEYS.CACHE_HOST, function(bidResponse) { - return deepAccess(bidResponse, `adserverTargeting.${TARGETING_KEYS.CACHE_HOST}`) - ? bidResponse.adserverTargeting[TARGETING_KEYS.CACHE_HOST] : urlInfo.hostname; + return bidResponse?.adserverTargeting?.[TARGETING_KEYS.CACHE_HOST] || urlInfo.hostname; })); } } diff --git a/src/bidderSettings.js b/src/bidderSettings.js index 4d97ed2b95e..a2687822e1e 100644 --- a/src/bidderSettings.js +++ b/src/bidderSettings.js @@ -1,4 +1,4 @@ -import {deepAccess, mergeDeep} from './utils.js'; +import {mergeDeep} from './utils.js'; import {getGlobal} from './prebidGlobal.js'; import { JSON_MAPPING } from './constants.js'; @@ -31,7 +31,7 @@ export class ScopedSettings { */ getOwn(scope, path) { scope = this.#resolveScope(scope); - return deepAccess(this.getSettings(), `${scope}.${path}`) + return this.getSettings()?.[scope]?.[path]; } /** diff --git a/src/native.js b/src/native.js index a641beb71d5..8c36e8c66f2 100644 --- a/src/native.js +++ b/src/native.js @@ -1,5 +1,4 @@ import { - deepAccess, deepClone, getDefinedParams, insertHtmlIntoIframe, isArray, @@ -129,7 +128,7 @@ export function processNativeAdUnitParams(params) { export function decorateAdUnitsWithNativeParams(adUnits) { adUnits.forEach(adUnit => { const nativeParams = - adUnit.nativeParams || deepAccess(adUnit, 'mediaTypes.native'); + adUnit.nativeParams || adUnit?.mediaTypes?.native; if (nativeParams) { adUnit.nativeParams = processNativeAdUnitParams(nativeParams); } @@ -213,7 +212,7 @@ function typeIsSupported(type) { */ export const nativeAdUnit = adUnit => { const mediaType = adUnit.mediaType === 'native'; - const mediaTypes = deepAccess(adUnit, 'mediaTypes.native'); + const mediaTypes = adUnit?.mediaTypes?.native; return mediaType || mediaTypes; } export const nativeBidder = bid => includes(nativeAdapters, bid.bidder); @@ -236,7 +235,7 @@ export function nativeBidIsValid(bid, {index = auctionManager.index} = {}) { } export function isNativeOpenRTBBidValid(bidORTB, bidRequestORTB) { - if (!deepAccess(bidORTB, 'link.url')) { + if (!bidORTB?.link?.url) { logError(`native response doesn't have 'link' property. Ortb response: `, bidORTB); return false; } @@ -364,10 +363,7 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { let keyValues = {}; const adUnit = index.getAdUnit(bid); - const globalSendTargetingKeys = adUnit?.nativeParams?.ortb == null && deepAccess( - adUnit, - `nativeParams.sendTargetingKeys` - ) !== false; + const globalSendTargetingKeys = adUnit?.nativeParams?.ortb == null && adUnit?.nativeParams?.sendTargetingKeys !== false; const nativeKeys = getNativeKeys(adUnit); @@ -376,15 +372,15 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { Object.keys(flatBidNativeKeys).forEach(asset => { const key = nativeKeys[asset]; - let value = getAssetValue(bid.native[asset]) || getAssetValue(deepAccess(bid, `native.ext.${asset}`)); + let value = getAssetValue(bid.native[asset]) || getAssetValue(bid?.native?.ext?.[asset]); if (asset === 'adTemplate' || !key || !value) { return; } - let sendPlaceholder = deepAccess(adUnit, `nativeParams.${asset}.sendId`); + let sendPlaceholder = adUnit?.nativeParams?.[asset]?.sendId; if (typeof sendPlaceholder !== 'boolean') { - sendPlaceholder = deepAccess(adUnit, `nativeParams.ext.${asset}.sendId`); + sendPlaceholder = adUnit?.nativeParams?.ext?.[asset].sendId; } if (sendPlaceholder) { @@ -392,9 +388,9 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { value = placeholder; } - let assetSendTargetingKeys = deepAccess(adUnit, `nativeParams.${asset}.sendTargetingKeys`); + let assetSendTargetingKeys = adUnit?.nativeParams?.[asset]?.sendTargetingKeys; if (typeof assetSendTargetingKeys !== 'boolean') { - assetSendTargetingKeys = deepAccess(adUnit, `nativeParams.ext.${asset}.sendTargetingKeys`); + assetSendTargetingKeys = adUnit?.nativeParams?.ext?.[asset]?.sendTargetingKeys; } const sendTargeting = typeof assetSendTargetingKeys === 'boolean' ? assetSendTargetingKeys : globalSendTargetingKeys; @@ -482,7 +478,7 @@ function getAssetValue(value) { function getNativeKeys(adUnit) { const extraNativeKeys = {} - if (deepAccess(adUnit, 'nativeParams.ext')) { + if (adUnit?.nativeParams?.ext) { Object.keys(adUnit.nativeParams.ext).forEach(extKey => { extraNativeKeys[extKey] = `hb_native_${extKey}`; }) diff --git a/src/prebid.js b/src/prebid.js index 2a9b88cd47d..37d37acfee7 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -2,7 +2,6 @@ import {getGlobal} from './prebidGlobal.js'; import { - deepAccess, deepClone, deepSetValue, flatten, @@ -213,7 +212,7 @@ function validateNativeMediaType(adUnit) { } function validateAdUnitPos(adUnit, mediaType) { - let pos = deepAccess(adUnit, `mediaTypes.${mediaType}.pos`); + let pos = adUnit?.mediaTypes?.[mediaType]?.pos; if (!isNumber(pos) || isNaN(pos) || !isFinite(pos)) { let warning = `Value of property 'pos' on ad unit ${adUnit.code} should be of type: Number`; diff --git a/src/utils/gdpr.js b/src/utils/gdpr.js index 19c7126b7d7..6151861a67b 100644 --- a/src/utils/gdpr.js +++ b/src/utils/gdpr.js @@ -1,5 +1,3 @@ -import {deepAccess} from '../utils.js'; - /** * Check if GDPR purpose 1 consent was given. * @@ -8,7 +6,7 @@ import {deepAccess} from '../utils.js'; */ export function hasPurpose1Consent(gdprConsent) { if (gdprConsent?.gdprApplies) { - return deepAccess(gdprConsent, 'vendorData.purpose.consents.1') === true; + return gdprConsent?.vendorData?.purpose?.consents?.[1] === true; } return true; } diff --git a/src/video.js b/src/video.js index 9be9adec4c5..a859fcb17bd 100644 --- a/src/video.js +++ b/src/video.js @@ -1,4 +1,4 @@ -import {deepAccess, isArrayOfNums, isInteger, isNumber, isPlainObject, isStr, logError, logWarn} from './utils.js'; +import {isArrayOfNums, isInteger, isNumber, isPlainObject, isStr, logError, logWarn} from './utils.js'; import {config} from '../src/config.js'; import {hook} from './hook.js'; import {auctionManager} from './auctionManager.js'; @@ -107,9 +107,9 @@ export function validateOrtbVideoFields(adUnit, onInvalidParam) { * @return {Boolean} If object is valid */ export function isValidVideoBid(bid, {index = auctionManager.index} = {}) { - const videoMediaType = deepAccess(index.getMediaTypes(bid), 'video'); - const context = videoMediaType && deepAccess(videoMediaType, 'context'); - const useCacheKey = videoMediaType && deepAccess(videoMediaType, 'useCacheKey'); + const videoMediaType = index.getMediaTypes(bid)?.video; + const context = videoMediaType && videoMediaType?.context; + const useCacheKey = videoMediaType && videoMediaType?.useCacheKey; const adUnit = index.getAdUnit(bid); // if context not defined assume default 'instream' for video bids From d67ddf24f68f1eafd68b668230940a327f5f070b Mon Sep 17 00:00:00 2001 From: Graham Higgins Date: Thu, 5 Dec 2024 11:30:54 -0500 Subject: [PATCH 2/4] Revert changes containing variable lookups that may dynamically contain "." --- modules/teadsBidAdapter.js | 4 ++-- src/native.js | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/teadsBidAdapter.js b/modules/teadsBidAdapter.js index 684eb679d05..cbf7a989e91 100644 --- a/modules/teadsBidAdapter.js +++ b/modules/teadsBidAdapter.js @@ -1,4 +1,4 @@ -import {logError, parseSizesInput, isArray, getBidIdParameter} from '../src/utils.js'; +import {logError, deepAccess, parseSizesInput, isArray, getBidIdParameter} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {getStorageManager} from '../src/storageManager.js'; import {isAutoplayEnabled} from '../libraries/autoplayDetection/autoplay.js'; @@ -198,7 +198,7 @@ function getSharedViewerIdParameters(validBidRequests) { let sharedViewerIdObject = {}; for (const sharedViewerId in sharedViewerIdMapping) { const key = sharedViewerIdMapping[sharedViewerId]; - const value = validBidRequests?.[0]?.userId?.[key]; + const value = deepAccess(validBidRequests, `0.userId.${key}`); if (value) { sharedViewerIdObject[sharedViewerId] = value; } diff --git a/src/native.js b/src/native.js index 8c36e8c66f2..959ac491e6a 100644 --- a/src/native.js +++ b/src/native.js @@ -1,4 +1,5 @@ import { + deepAccess, deepClone, getDefinedParams, insertHtmlIntoIframe, isArray, @@ -372,15 +373,15 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { Object.keys(flatBidNativeKeys).forEach(asset => { const key = nativeKeys[asset]; - let value = getAssetValue(bid.native[asset]) || getAssetValue(bid?.native?.ext?.[asset]); + let value = getAssetValue(bid.native[asset]) || getAssetValue(deepAccess(bid, `native.ext.${asset}`)); if (asset === 'adTemplate' || !key || !value) { return; } - let sendPlaceholder = adUnit?.nativeParams?.[asset]?.sendId; + let sendPlaceholder = deepAccess(adUnit, `nativeParams.${asset}.sendId`); if (typeof sendPlaceholder !== 'boolean') { - sendPlaceholder = adUnit?.nativeParams?.ext?.[asset].sendId; + sendPlaceholder = deepAccess(adUnit, `nativeParams.ext.${asset}.sendId`); } if (sendPlaceholder) { @@ -388,9 +389,9 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { value = placeholder; } - let assetSendTargetingKeys = adUnit?.nativeParams?.[asset]?.sendTargetingKeys; + let assetSendTargetingKeys = deepAccess(adUnit, `nativeParams.${asset}.sendTargetingKeys`); if (typeof assetSendTargetingKeys !== 'boolean') { - assetSendTargetingKeys = adUnit?.nativeParams?.ext?.[asset]?.sendTargetingKeys; + assetSendTargetingKeys = deepAccess(adUnit, `nativeParams.ext.${asset}.sendTargetingKeys`); } const sendTargeting = typeof assetSendTargetingKeys === 'boolean' ? assetSendTargetingKeys : globalSendTargetingKeys; From 9b21ad1bd8d5c01ac940da6b38ce66627cd939c2 Mon Sep 17 00:00:00 2001 From: Graham Higgins Date: Thu, 5 Dec 2024 11:55:52 -0500 Subject: [PATCH 3/4] Use optional chaining Adding these changes back after review discovered the missing optional chain which was causing test failure in a previous commit. --- src/native.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/native.js b/src/native.js index 959ac491e6a..19833406451 100644 --- a/src/native.js +++ b/src/native.js @@ -1,5 +1,4 @@ import { - deepAccess, deepClone, getDefinedParams, insertHtmlIntoIframe, isArray, @@ -373,15 +372,15 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { Object.keys(flatBidNativeKeys).forEach(asset => { const key = nativeKeys[asset]; - let value = getAssetValue(bid.native[asset]) || getAssetValue(deepAccess(bid, `native.ext.${asset}`)); + let value = getAssetValue(bid.native[asset]) || getAssetValue(bid?.native?.ext?.[asset]); if (asset === 'adTemplate' || !key || !value) { return; } - let sendPlaceholder = deepAccess(adUnit, `nativeParams.${asset}.sendId`); + let sendPlaceholder = adUnit?.nativeParams?.[asset]?.sendId; if (typeof sendPlaceholder !== 'boolean') { - sendPlaceholder = deepAccess(adUnit, `nativeParams.ext.${asset}.sendId`); + sendPlaceholder = adUnit?.nativeParams?.ext?.[asset]?.sendId; } if (sendPlaceholder) { @@ -389,9 +388,9 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { value = placeholder; } - let assetSendTargetingKeys = deepAccess(adUnit, `nativeParams.${asset}.sendTargetingKeys`); + let assetSendTargetingKeys = adUnit?.nativeParams?.[asset]?.sendTargetingKeys; if (typeof assetSendTargetingKeys !== 'boolean') { - assetSendTargetingKeys = deepAccess(adUnit, `nativeParams.ext.${asset}.sendTargetingKeys`); + assetSendTargetingKeys = adUnit?.nativeParams?.ext?.[asset]?.sendTargetingKeys; } const sendTargeting = typeof assetSendTargetingKeys === 'boolean' ? assetSendTargetingKeys : globalSendTargetingKeys; From 1dc9e7136c7d7b501f546742e9758f374ac882ac Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 5 Dec 2024 09:06:25 -0800 Subject: [PATCH 4/4] revert bidderSettings & add test case --- src/bidderSettings.js | 4 ++-- test/spec/unit/core/bidderSettings_spec.js | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/bidderSettings.js b/src/bidderSettings.js index a2687822e1e..4d97ed2b95e 100644 --- a/src/bidderSettings.js +++ b/src/bidderSettings.js @@ -1,4 +1,4 @@ -import {mergeDeep} from './utils.js'; +import {deepAccess, mergeDeep} from './utils.js'; import {getGlobal} from './prebidGlobal.js'; import { JSON_MAPPING } from './constants.js'; @@ -31,7 +31,7 @@ export class ScopedSettings { */ getOwn(scope, path) { scope = this.#resolveScope(scope); - return this.getSettings()?.[scope]?.[path]; + return deepAccess(this.getSettings(), `${scope}.${path}`) } /** diff --git a/test/spec/unit/core/bidderSettings_spec.js b/test/spec/unit/core/bidderSettings_spec.js index ece18040d1e..7e6446b456b 100644 --- a/test/spec/unit/core/bidderSettings_spec.js +++ b/test/spec/unit/core/bidderSettings_spec.js @@ -19,6 +19,13 @@ describe('ScopedSettings', () => { expect(settings.get('scope', 'key')).to.equal('value'); }); + it('can retrieve nested settings', () => { + data = { + scope: {outer: {key: 'value'}} + } + expect(settings.get('scope', 'outer.key')).to.equal('value'); + }) + it('should fallback to fallback scope', () => { data = { fallback: {