/* eslint-disable no-dupe-class-members */ import { maps } from '@/maps' // eslint-disable-next-line @typescript-eslint/no-explicit-any type Map = (...args: any) => any type Maps = Record> type MapsMember = T[S][keyof T[S]] type Mappers = Extract, Map> type MapperSourceType = Parameters>[0] type MapperDestinationType = ReturnType export class Mapper { private readonly mapperFunctions: T public constructor(mapperFunctions: T) { this.mapperFunctions = mapperFunctions } public map(source: S, value: MapperSourceType, destination: D): MapperDestinationType public map(source: S, value: MapperSourceType | null, destination: D): MapperDestinationType | null public map(source: S, value: MapperSourceType | undefined, destination: D): MapperDestinationType | undefined public map(source: S, value: MapperSourceType | null | undefined, destination: D): MapperDestinationType | null | undefined public map(source: S, value: MapperSourceType[], destination: D): MapperDestinationType[] public map(source: S, value: MapperSourceType | MapperSourceType[] | null | undefined, destination: D): MapperDestinationType | MapperDestinationType[] | null | undefined { if (value === null || value === undefined) { return value } const mapper = this.bindMapper(this.mapperFunctions[source][destination]) if (Array.isArray(value)) { return value.map(mapper) } return mapper(value) } public mapEntries(source: S, value: Record>, destination: D): Record> public mapEntries(source: S, value: Record> | null, destination: D): Record> | null public mapEntries(source: S, value: Record> | undefined, destination: D): Record> | undefined public mapEntries(source: S, value: Record> | null | undefined, destination: D): Record> | null | undefined public mapEntries(source: S, value: Record[]>, destination: D): Record[]> public mapEntries(source: S, value: Record[]> | null, destination: D): Record[]> | null public mapEntries(source: S, value: Record[]> | undefined, destination: D): Record[]> | undefined public mapEntries(source: S, value: Record[]> | null | undefined, destination: D): Record[]> | null | undefined public mapEntries(source: S, value: Record | MapperSourceType[]> | null | undefined, destination: D): Record | MapperDestinationType[]> | null | undefined { if (value === null || value === undefined) { return value } const response = {} as Record> return Object.entries(value).reduce>>((mapped, [key, value]) => { mapped[key] = this.map(source, value, destination) return mapped }, response) } private bindMapper(mapper: MapsMember): (source: MapperSourceType) => MapperDestinationType { return mapper.bind(this) } } export const mapper = new Mapper(maps) export type MapFunction = (this: typeof mapper, source: S) => D