import { SerializePropertyOptionsMap } from "./serialize_property_options_map.ts";import { toJSONDefault } from "./strategy/to_json/default.ts";import { fromJSONDefault } from "./strategy/from_json/default.ts";import { toJSONRecursive } from "./strategy/to_json/recursive.ts";import { ERROR_MISSING_PROPERTIES_MAP } from "./error_messages.ts";
export type JSONObject = { [key: string]: JSONValue;};
export type JSONValue = | string | number | boolean | null | JSONObject | JSONValue[];
export declare interface TransformKey { tsTransformKey(key: string): string;}
export declare interface ToJSON { toJSON(): string;}
export declare interface FromJSON { fromJSON(json: string | JSONObject): this;}
export declare interface Serialize { tsSerialize(): JSONObject;}
export declare interface Clone { clone(jsonObject: Partial<this>): this;}
function getOrInitializeDefaultSerializerLogicForParents( targetPrototype: Serializable,): SerializePropertyOptionsMap | undefined { if (targetPrototype === Serializable.prototype) { return undefined; }
if (!SERIALIZABLE_CLASS_MAP.has(targetPrototype)) { let parentMap = SERIALIZABLE_CLASS_MAP.get( Object.getPrototypeOf(targetPrototype), );
if (!parentMap) { parentMap = getOrInitializeDefaultSerializerLogicForParents( Object.getPrototypeOf(targetPrototype), ); }
return SERIALIZABLE_CLASS_MAP.set( targetPrototype, new SerializePropertyOptionsMap(parentMap), ).get( targetPrototype, ); }
return SERIALIZABLE_CLASS_MAP.get(targetPrototype);}
export abstract class Serializable { constructor() { getOrInitializeDefaultSerializerLogicForParents(this.constructor.prototype); } public tsTransformKey(key: string): string { return key; } public toJSON(): string { return toJSON(this); } public fromJSON(json: string | JSONObject): this { return fromJSON(this, json); } public tsSerialize(): JSONObject { return toPojo(this); } public clone(jsonObject: Partial<this> = {}): this { const copy = Object.getPrototypeOf(this).constructor; return Object.assign( new copy().fromJSON( this.tsSerialize(), ), jsonObject, ); }}
export type SerializableMap = Map<unknown, SerializePropertyOptionsMap>;
export const SERIALIZABLE_CLASS_MAP: SerializableMap = new Map< unknown, SerializePropertyOptionsMap>();
export function toPojo( context: Serializable,): JSONObject { const serializablePropertyMap = SERIALIZABLE_CLASS_MAP.get( context?.constructor?.prototype, );
if (!serializablePropertyMap) { throw new Error( `${ERROR_MISSING_PROPERTIES_MAP}: ${context?.constructor ?.prototype}`, ); } const record: JSONObject = {}; for ( let { propertyKey, serializedKey, toJSONStrategy = toJSONDefault, } of serializablePropertyMap.propertyOptions() ) { const value = context[propertyKey as keyof Serializable];
if ( SERIALIZABLE_CLASS_MAP.get( value?.constructor?.prototype, ) ) { toJSONStrategy = toJSONRecursive; } if (value !== undefined) { record[serializedKey] = toJSONStrategy(value); } } return record;}
function toJSON(context: Serializable): string { return JSON.stringify(toPojo(context));}
function fromJSON<T>( context: Serializable, json: JSONValue,): T { const _json = typeof json === "string" ? JSON.parse(json) : json; const accumulator: Partial<T> = {}; const map = SERIALIZABLE_CLASS_MAP.get(context?.constructor?.prototype); for (const [key, value] of Object.entries(_json) as [string, JSONValue][]) { const { propertyKey, fromJSONStrategy = fromJSONDefault, } = map?.getBySerializedKey(key) || {};
if (!propertyKey) { continue; }
accumulator[propertyKey as keyof T] = fromJSONStrategy(value); }
return Object.assign( context, accumulator as T, );}