import { SerializePropertyOptionsMap } from "./serialize_property_options_map.ts";import { defaultToJson } from "./to_json/default.ts";import { defaultFromJson } from "./from_json/default.ts";import { recursiveToJson } from "./to_json/recursive.ts";
export type JsonObject = { [Key in string]?: JsonValue };
export interface JsonArray extends Array<JsonValue> {}
export type JsonValue = | string | number | boolean | null | JsonObject | JsonArray;
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(json: string | JsonValue): this { return fromJson(this, json); }}
export type FromJsonStrategy = (value: JsonValue) => any;export type FromJsonStrategyArgument = (FromJsonStrategy | FromJsonStrategy[])[];
export type ToJsonStrategy = (value: any) => JsonValue;export type ToJsonStrategyArgument = (ToJsonStrategy | ToJsonStrategy[])[];
export class SerializePropertyOptions { public fromJsonStrategy?: FromJsonStrategy; public toJsonStrategy?: ToJsonStrategy;
constructor( public propertyKey: string | symbol, public serializedKey: string, fromJsonStrategy?: FromJsonStrategy | FromJsonStrategyArgument, toJsonStrategy?: ToJsonStrategy | ToJsonStrategyArgument, ) { 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: FromJsonStrategyArgument): FromJsonStrategy;
export function composeStrategy( ...fns: ToJsonStrategyArgument): ToJsonStrategy;
export function composeStrategy( ...fns: | FromJsonStrategyArgument | ToJsonStrategyArgument): FromJsonStrategy | ToJsonStrategy { return function _composeStrategy(val: any): any { return fns.flat().reduce( (acc: any, fn: FromJsonStrategy | ToJsonStrategy) => fn(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,): JsonObject { const serializablePropertyMap = SERIALIZABLE_CLASS_MAP.get( context?.constructor?.prototype, );
if (!serializablePropertyMap) { throw new Error( `${ERROR_MESSAGE_MISSING_PROPERTIES_MAP}: ${context?.constructor ?.prototype}`, ); } const record: JsonObject = {}; 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 | JsonValue,): 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: JsonValue): unknown { if (key === "") { return value; }
const { propertyKey, fromJsonStrategy = defaultFromJson, } = 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; }, ), );}