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 interface JSONArray extends Array<JSONValue> {}
export type JSONValue = | string | number | boolean | null | JSONObject | JSONArray;
export declare interface TransformKey { tsTransformKey(key: string): string;}
export declare interface ToJSON { toJSON(): string;}
export declare interface FromJSON { fromJSON(json: string | JSONValue | Object): this;}
export declare interface Serialize { tsSerialize(): JSONObject;}
function getOrInitializeDefaultSerializerLogicForParents( targetPrototype: any, ): 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 | JSONValue | Object): this { return fromJSON(this, json); } public tsSerialize(): JSONObject { return toPojo(this); }}
export type SerializableMap = Map<unknown, SerializePropertyOptionsMap>;
export const SERIALIZABLE_CLASS_MAP: SerializableMap = new Map< unknown, SerializePropertyOptionsMap>();
export function toPojo( context: any,): 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 string];
if ( SERIALIZABLE_CLASS_MAP.get( (value as Serializable)?.constructor?.prototype, ) ) { toJSONStrategy = toJSONRecursive; }
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 | Object,): T { const _json = typeof json === "string" ? JSON.parse(json) : json; const accumulator: Partial<T> = {};
for (const [key, value] of Object.entries(_json)) { const { propertyKey, fromJSONStrategy = fromJSONDefault, } = (SERIALIZABLE_CLASS_MAP.get( context?.constructor?.prototype, ) as SerializePropertyOptionsMap).getBySerializedKey(key) || {};
if (!propertyKey) { continue; }
accumulator[propertyKey as keyof T] = Array.isArray(value) ? value.map((v) => fromJSONStrategy(v)) : fromJSONStrategy(value as JSONValue); }
return Object.assign( context, accumulator as T, );}