UNPKG

payload

Version:

Node, React, Headless CMS and Application Framework built on Next.js

330 lines (329 loc) • 13 kB
// @ts-strict-ignore import { fieldHasSubFields, fieldShouldBeLocalized } from '../fields/config/types.js'; const traverseArrayOrBlocksField = ({ callback, callbackStack, config, data, field, fillEmpty, leavesFirst, parentIsLocalized, parentRef })=>{ if (fillEmpty) { if (field.type === 'array') { traverseFields({ callback, callbackStack, config, fields: field.fields, isTopLevel: false, leavesFirst, parentIsLocalized: parentIsLocalized || field.localized, parentRef }); } if (field.type === 'blocks') { for (const _block of field.blockReferences ?? field.blocks){ // TODO: iterate over blocks mapped to block slug in v4, or pass through payload.blocks const block = typeof _block === 'string' ? config?.blocks?.find((b)=>b.slug === _block) : _block; if (block) { traverseFields({ callback, callbackStack, config, fields: block.fields, isTopLevel: false, leavesFirst, parentIsLocalized: parentIsLocalized || field.localized, parentRef }); } } } return; } for (const ref of data){ let fields; if (field.type === 'blocks' && typeof ref?.blockType === 'string') { // TODO: iterate over blocks mapped to block slug in v4, or pass through payload.blocks const block = field.blockReferences ? config?.blocks?.find((b)=>b.slug === ref.blockType) ?? field.blockReferences.find((b)=>typeof b !== 'string' && b.slug === ref.blockType) : field.blocks.find((b)=>b.slug === ref.blockType); fields = block?.fields; } else if (field.type === 'array') { fields = field.fields; } if (fields) { traverseFields({ callback, callbackStack, config, fields, fillEmpty, isTopLevel: false, leavesFirst, parentIsLocalized: parentIsLocalized || field.localized, parentRef, ref }); } } }; /** * Iterate a recurse an array of fields, calling a callback for each field * * @param fields * @param callback callback called for each field, discontinue looping if callback returns truthy * @param fillEmpty fill empty properties to use this without data * @param ref the data or any artifacts assigned in the callback during field recursion * @param parentRef the data or any artifacts assigned in the callback during field recursion one level up */ export const traverseFields = ({ callback, callbackStack: _callbackStack = [], config, fields, fillEmpty = true, isTopLevel = true, leavesFirst = false, parentIsLocalized, parentRef = {}, ref = {} })=>{ fields.some((field)=>{ let callbackStack = []; if (!isTopLevel) { callbackStack = _callbackStack; } let skip = false; const next = ()=>{ skip = true; }; if (!ref || typeof ref !== 'object') { return; } if (!leavesFirst && callback && callback({ field, next, parentIsLocalized, parentRef, ref })) { return true; } else if (leavesFirst) { callbackStack.push(()=>callback({ field, next, parentIsLocalized, parentRef, ref })); } if (skip) { return false; } // avoid mutation of ref for all fields let currentRef = ref; let currentParentRef = parentRef; if (field.type === 'tabs' && 'tabs' in field) { for (const tab of field.tabs){ let tabRef = ref; if (skip) { return false; } if ('name' in tab && tab.name) { if (!ref[tab.name] || typeof ref[tab.name] !== 'object') { if (fillEmpty) { if (tab.localized) { ref[tab.name] = { en: {} }; } else { ref[tab.name] = {}; } } else { continue; } } if (callback && !leavesFirst && callback({ field: { ...tab, type: 'tab' }, next, parentIsLocalized, parentRef: currentParentRef, ref: tabRef })) { return true; } else if (leavesFirst) { callbackStack.push(()=>callback({ field: { ...tab, type: 'tab' }, next, parentIsLocalized, parentRef: currentParentRef, ref: tabRef })); } tabRef = tabRef[tab.name]; if (tab.localized) { for(const key in tabRef){ if (tabRef[key] && typeof tabRef[key] === 'object') { traverseFields({ callback, callbackStack, config, fields: tab.fields, fillEmpty, isTopLevel: false, leavesFirst, parentIsLocalized: true, parentRef: currentParentRef, ref: tabRef[key] }); } } } } else { if (callback && !leavesFirst && callback({ field: { ...tab, type: 'tab' }, next, parentIsLocalized, parentRef: currentParentRef, ref: tabRef })) { return true; } else if (leavesFirst) { callbackStack.push(()=>callback({ field: { ...tab, type: 'tab' }, next, parentIsLocalized, parentRef: currentParentRef, ref: tabRef })); } } if (!tab.localized) { traverseFields({ callback, callbackStack, config, fields: tab.fields, fillEmpty, isTopLevel: false, leavesFirst, parentIsLocalized: false, parentRef: currentParentRef, ref: tabRef }); } if (skip) { return false; } } return; } if (field.type !== 'tab' && (fieldHasSubFields(field) || field.type === 'blocks')) { if ('name' in field && field.name) { currentParentRef = currentRef; if (!ref[field.name]) { if (fillEmpty) { if (field.type === 'group') { if (fieldShouldBeLocalized({ field, parentIsLocalized })) { ref[field.name] = { en: {} }; } else { ref[field.name] = {}; } } else if (field.type === 'array' || field.type === 'blocks') { if (fieldShouldBeLocalized({ field, parentIsLocalized })) { ref[field.name] = { en: [] }; } else { ref[field.name] = []; } } } else { return; } } currentRef = ref[field.name]; } if (field.type === 'group' && fieldShouldBeLocalized({ field, parentIsLocalized }) && currentRef && typeof currentRef === 'object') { for(const key in currentRef){ if (currentRef[key]) { traverseFields({ callback, callbackStack, config, fields: field.fields, fillEmpty, isTopLevel: false, leavesFirst, parentIsLocalized: true, parentRef: currentParentRef, ref: currentRef[key] }); } } return; } if ((field.type === 'blocks' || field.type === 'array') && currentRef && typeof currentRef === 'object') { if (fieldShouldBeLocalized({ field, parentIsLocalized })) { if (Array.isArray(currentRef)) { return; } for(const key in currentRef){ const localeData = currentRef[key]; if (!Array.isArray(localeData)) { continue; } traverseArrayOrBlocksField({ callback, callbackStack, config, data: localeData, field, fillEmpty, leavesFirst, parentIsLocalized: true, parentRef: currentParentRef }); } } else if (Array.isArray(currentRef)) { traverseArrayOrBlocksField({ callback, callbackStack, config, data: currentRef, field, fillEmpty, leavesFirst, parentIsLocalized, parentRef: currentParentRef }); } } else if (currentRef && typeof currentRef === 'object' && 'fields' in field) { traverseFields({ callback, callbackStack, config, fields: field.fields, fillEmpty, isTopLevel: false, leavesFirst, parentIsLocalized, parentRef: currentParentRef, ref: currentRef }); } } if (isTopLevel) { callbackStack.reverse().forEach((cb)=>{ cb(); }); } }); }; //# sourceMappingURL=traverseFields.js.map