import { SerializePropertyOptionsMap } from "./serialize_property_options_map.ts";import { defaultToJson } from "./to_json/default.ts";import { recursiveToJson } from "./to_json/recursive.ts";
export declare interface TransformKey { tsTransformKey(key: string): string;}
export abstract class Serializable { public tsTransformKey?(key: string): string { return key; } public toJson(): string { return toJson(this); } public fromJson(): this; public fromJson(json: string): this; public fromJson(json: Record<string, any>): this; public fromJson(json: string | Record<string, any> = {}): this { return fromJson(this, json); }}
export type FromJsonStrategy = (value: any) => any;
export type ToJsonStrategy = (value: any) => any;
export class SerializePropertyOptions { public fromJsonStrategy?: FromJsonStrategy; public toJsonStrategy?: ToJsonStrategy;
constructor( public propertyKey: string | symbol, public serializedKey: string, fromJsonStrategy?: | FromJsonStrategy | (FromJsonStrategy | FromJsonStrategy[])[], toJsonStrategy?: | ToJsonStrategy | (ToJsonStrategy | ToJsonStrategy[])[], ) { if (Array.isArray(fromJsonStrategy)) { this.fromJsonStrategy = composeStrategy(...fromJsonStrategy); } else if (fromJsonStrategy) { this.fromJsonStrategy = fromJsonStrategy; }
if (Array.isArray(toJsonStrategy)) { this.toJsonStrategy = composeStrategy(...toJsonStrategy); } else if (toJsonStrategy) { this.toJsonStrategy = toJsonStrategy; } }}
export function composeStrategy( ...fns: | (FromJsonStrategy | FromJsonStrategy[])[] | (ToJsonStrategy | ToJsonStrategy[])[]): FromJsonStrategy | ToJsonStrategy { return (val: unknown): unknown => fns.flat().reduce( (acc: unknown, f: FromJsonStrategy | ToJsonStrategy) => f(acc), val, );}
export type SerializableMap = Map<unknown, SerializePropertyOptionsMap>;
export const SERIALIZABLE_CLASS_MAP: SerializableMap = new Map< unknown, SerializePropertyOptionsMap>();
const ERROR_MESSAGE_MISSING_PROPERTIES_MAP = "Unable to load serializer properties for the given context";
export function toPojo( context: any,): Record<string, unknown> { const serializablePropertyMap = SERIALIZABLE_CLASS_MAP.get( context?.constructor?.prototype, );
if (!serializablePropertyMap) { throw new Error( `${ERROR_MESSAGE_MISSING_PROPERTIES_MAP}: ${context?.constructor ?.prototype}`, ); } const record: Record<string, unknown> = {}; for ( let { propertyKey, serializedKey, toJsonStrategy = defaultToJson, } of serializablePropertyMap.propertyOptions() ) { const value = context[propertyKey as string];
if ( SERIALIZABLE_CLASS_MAP.get( (value as Serializable)?.constructor?.prototype, ) ) { toJsonStrategy = recursiveToJson; }
if (Array.isArray(value)) { record[serializedKey] = value.map((item: any) => { if (item instanceof Serializable) { return toPojo(item); } return toJsonStrategy(item); }); } else if (value !== undefined) { record[serializedKey] = toJsonStrategy(value); } } return record;}
function toJson<T>(context: T): string { return JSON.stringify(toPojo(context));}
function fromJson<T>(context: Serializable, json: string): T;
function fromJson<T>(context: Serializable, json: Record<string, any>): T;
function fromJson<T>( context: Serializable, json: string | Record<string, any>,): T;
function fromJson<T>( context: Serializable, json: string | Record<string, any>,): T { const serializablePropertyMap = SERIALIZABLE_CLASS_MAP.get( context?.constructor?.prototype, ); if (!serializablePropertyMap) { throw new Error( `${ERROR_MESSAGE_MISSING_PROPERTIES_MAP}: ${context?.constructor ?.prototype}`, ); }
const _json = typeof json === "string" ? json : JSON.stringify(json);
return Object.assign( context, JSON.parse( _json, function revive(key: string, value: unknown): unknown { if (key === "") { return value; }
const { propertyKey, fromJsonStrategy = (v: unknown) => v, } = serializablePropertyMap.getBySerializedKey(key) || {};
const processedValue: unknown = Array.isArray(value) ? value.map((v) => fromJsonStrategy(v)) : fromJsonStrategy(value);
if (propertyKey) { context[propertyKey as keyof Serializable] = processedValue as any; return; } return processedValue; }, ), );}