import type { RenderedLeanSchemaFields, RenderedLeanSchema, } from '@wix/metro-public-utils'; import { parseLeanSchemaRef } from '../index.js'; import { ConverterType, Payload, TypeToConverterSet } from './domain.js'; export function schemaSerializer( rootSchema: RenderedLeanSchemaFields, depSchemas: RenderedLeanSchema = {}, converterSets: TypeToConverterSet, ) { return function serialize( json: Payload = {}, converterType: ConverterType, ): Payload { return typeof json === 'string' ? json : transformSchema(rootSchema, json); function transformSchema( schema: RenderedLeanSchemaFields, payload: any, ): Payload { const result = {} as Payload; if ([null, undefined].includes(payload)) { return payload; } Object.entries(payload).forEach(([key, val]) => { const renderedSchemaName = schema[key]; const { schemaName, schemaType } = parseLeanSchemaRef(renderedSchemaName); const isMap = schemaType === 'Map'; const isRepeatable = getConverter(schemaName)?.checkRepetable?.(val) ?? Array.isArray(val); let parsedValue; if (isRepeatable) { parsedValue = (val as any[]).map((v) => applyField(v, schemaName)); } else if (isMap) { parsedValue = applyFieldOnMap(val, schemaName); } else { parsedValue = applyField(val, schemaName); } result[key] = parsedValue; }); return result; } function applyField(val: unknown, schemaOrSerializer?: string) { if (!schemaOrSerializer) { return val; } const maybeSchema = depSchemas[schemaOrSerializer]; const maybeConverter = getConverter(schemaOrSerializer); if (maybeConverter) { return getConverter(schemaOrSerializer).transform(val); } else if (maybeSchema) { return transformSchema(maybeSchema, val); } throw new Error( `${schemaOrSerializer} is neither schema nor serializable type`, ); } function getConverter(name: string) { return converterSets[name]?.[converterType]; } function applyFieldOnMap(val: any, sanitizedSchemaOrSerializer: string) { return Object.entries(val).reduce>( (acc, [propertyName, value]) => { acc[propertyName] = applyField(value, sanitizedSchemaOrSerializer); return acc; }, {}, ); } }; }