UNPKG

@nitrogenbuilder/client-core

Version:

Nitrogen Builder Core Client

316 lines (275 loc) 8.28 kB
import type { BuilderModule, ComponentSettings, ComponentSettingsToProps, PropArray, } from '@nitrogenbuilder/types'; import { nitrogen } from '../index.js'; import { getDefault } from './getDefault.js'; import { resolve } from './resolve.js'; import { set } from './set.js'; type UpdateWithDefaultPropsInput = { page: BuilderModule[]; dynamicData?: any; requestedData?: any; }; type ProcessedModule = { id: string; module: string | { name: string }; props: Record<string, any>; children?: ProcessedModule[] | Record<string, ProcessedModule[]>; requestedData?: any; }; function processChildren( mod: BuilderModule, dynamicData: any = {}, requestedData: any = {} ): ProcessedModule[] | Record<string, ProcessedModule[]> | undefined { if (!mod.props.children) return undefined; if (Array.isArray(mod.props.children)) { return mod.props.children.map((child: any) => { return processModule(child, dynamicData, requestedData); }); } else if (typeof mod.props.children === 'object') { return Object.keys(mod.props.children).reduce((acc, slot) => { if (Array.isArray(mod.props.children[slot])) { return { ...acc, [slot]: mod.props.children[slot].map((child: any) => { return processModule(child, dynamicData, requestedData); }), }; } return acc; }, {}); } return undefined; } type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]>; } : T; export function renderModuleProps<T extends ComponentSettings | string>( props: T extends ComponentSettings ? DeepPartial<ComponentSettingsToProps<T>> : Record<string, any>, settings: T, dynamicData: any = {}, requestedData: any = {} ): T extends ComponentSettings ? ComponentSettingsToProps<T> : any { let _settings: ComponentSettings; if (typeof settings === 'string') { const module = nitrogen.getModule(settings); if (!module) return {} as any; _settings = { categories: module.categories, options: module.options, } as ComponentSettings; } else { _settings = settings; } let spreadProps = { ...(props ?? {}) } as any; delete spreadProps.children; function recursiveArrayPropDefault(prop: PropArray, keys: string[]) { if (prop.props) { Object.entries(prop.props).forEach(([subPropK, subPropV]) => { if (subPropV.type === 'array') { let indexes = Object.keys(resolve(keys.join('.'), spreadProps) ?? {}); for (let i = 0; i < indexes.length; i++) { recursiveArrayPropDefault(subPropV as PropArray, [ ...keys, `${indexes[i]}`, subPropK, ]); } } else { let indexes = Object.keys(resolve(keys.join('.'), spreadProps) ?? {}); for (let i = 0; i < indexes.length; i++) { set( spreadProps, getDefault( resolve( [...keys, `${indexes[i]}`, subPropK].join('.'), spreadProps ), subPropV ), [...keys, `${indexes[i]}`, subPropK] ); } } }); } } Object.values(_settings.categories).forEach((category) => { Object.entries(category.groups).forEach(([groupK, group]) => { Object.entries(group.props).forEach(([propK, propV]) => { if (spreadProps[groupK] === undefined) { spreadProps[groupK] = {}; } if (propV.type === 'array') { recursiveArrayPropDefault(propV as PropArray, [groupK, propK]); } else { spreadProps[groupK][propK] = getDefault( spreadProps[groupK][propK], propV ); } }); }); }); function recursiveDynamicProps(keys: string[]) { let props = resolve(keys.join('.'), spreadProps); if (!props) return; let propChildrenKeys = Object.keys(props); for (let j = 0; j < propChildrenKeys.length; j++) { let propChildrenKey = propChildrenKeys[j]; let propChild = props[propChildrenKey]; if (propChildrenKey.endsWith('___dynamic')) { const dynamicVal = resolve(propChild.key, dynamicData) || propChild.fallback || ''; props[propChildrenKey.replace('___dynamic', '')] = typeof dynamicVal === 'boolean' ? dynamicVal : (propChild.before || '') + dynamicVal + (propChild.after || ''); } else if (typeof props[propChildrenKey] === 'object') { recursiveDynamicProps([...keys, propChildrenKey]); } } } let groupKeys = Object.keys(spreadProps); for (let i = 0; i < groupKeys.length; i++) { let groupKey = groupKeys[i]; if (typeof groupKey === 'string') { if (typeof spreadProps[groupKey] === 'object') { // check children properties for if the end in ___dynamic recursiveDynamicProps([groupKey]); } } } return spreadProps as any; } function processModule( mod: BuilderModule, dynamicData: any = {}, requestedData: any = {}, includeChildren: boolean = true ): ProcessedModule { const module = typeof mod.module === 'object' ? mod.module : nitrogen.getModule(mod.module); let spreadProps = { ...(mod?.props ?? {}) }; delete spreadProps.children; if (typeof module === 'object') { function recursiveArrayPropDefault(prop: PropArray, keys: string[]) { if (prop.props) { Object.entries(prop.props).forEach(([subPropK, subPropV]) => { if (subPropV.type === 'array') { let indexes = Object.keys( resolve(keys.join('.'), spreadProps) ?? {} ); for (let i = 0; i < indexes.length; i++) { recursiveArrayPropDefault(subPropV as PropArray, [ ...keys, `${indexes[i]}`, subPropK, ]); } } else { let indexes = Object.keys( resolve(keys.join('.'), spreadProps) ?? {} ); for (let i = 0; i < indexes.length; i++) { set( spreadProps, getDefault( resolve( [...keys, `${indexes[i]}`, subPropK].join('.'), spreadProps ), subPropV ), [...keys, `${indexes[i]}`, subPropK] ); } } }); } } Object.values(module.categories).forEach((category) => { Object.entries(category.groups).forEach(([groupK, group]) => { Object.entries(group.props).forEach(([propK, propV]) => { if (spreadProps[groupK] === undefined) { spreadProps[groupK] = {}; } if (propV.type === 'array') { recursiveArrayPropDefault(propV as PropArray, [groupK, propK]); } else { spreadProps[groupK][propK] = getDefault( spreadProps[groupK][propK], propV ); } }); }); }); } function recursiveDynamicProps(keys: string[]) { let props = resolve(keys.join('.'), spreadProps); if (!props) return; let propChildrenKeys = Object.keys(props); for (let j = 0; j < propChildrenKeys.length; j++) { let propChildrenKey = propChildrenKeys[j]; let propChild = props[propChildrenKey]; if (propChildrenKey.endsWith('___dynamic')) { const dynamicVal = resolve(propChild.key, dynamicData) || propChild.fallback || ''; props[propChildrenKey.replace('___dynamic', '')] = typeof dynamicVal === 'boolean' ? dynamicVal : (propChild.before || '') + dynamicVal + (propChild.after || ''); } else if (typeof props[propChildrenKey] === 'object') { recursiveDynamicProps([...keys, propChildrenKey]); } } } let groupKeys = Object.keys(spreadProps); for (let i = 0; i < groupKeys.length; i++) { let groupKey = groupKeys[i]; if (typeof groupKey === 'string') { if (typeof spreadProps[groupKey] === 'object') { // check children properties for if the end in ___dynamic recursiveDynamicProps([groupKey]); } } } const children = includeChildren ? processChildren(mod, dynamicData, requestedData) : undefined; return { id: mod.id, module: mod.module, props: spreadProps, ...(children && { children }), ...(requestedData[mod.id] && { requestedData: requestedData[mod.id] }), }; } export function updateWithDefaultProps({ page, dynamicData, requestedData, }: UpdateWithDefaultPropsInput): ProcessedModule[] { return page.map((block: BuilderModule) => { return processModule(block, dynamicData, requestedData); }); } export function updateModuleProps( module: BuilderModule, dynamicData: any = {}, requestedData: any = {}, includeChildren: boolean = false ): ProcessedModule { return processModule(module, dynamicData, requestedData, includeChildren); }