import {cloneObjDeep, hasKey} from "../../common/utils"; import { WithContext } from "../../common/types"; export class APBase { public fields: T; protected constructor(fields: T) { this.fields = { ...cloneObjDeep(fields), }; } protected static _create(fields: T) { const data = new APBase(fields); return new Proxy(data, { get(target: APBase, p: keyof APBase & keyof T) { return hasKey(target, p) ? target[p] : target.fields[p]; }, set(target: APBase, p: keyof APBase & keyof T, newValue: any): boolean { target.fields[p] = newValue; return true; } }) as APBase & T & WithContext; } protected parseValue(value: any): any { return value instanceof APBase ? value.toPlain() : value.valueOf(); } public toPlain(): Record { const result = {} as Record; if ('@context' in this.fields) { result['@context'] = this.fields['@context']; } for (const [key, value] of Object.entries(this.fields)) { if (key === '@context') continue; const isFunction = typeof value === 'function'; const isArray = Array.isArray(value); const isNull = value === null; const isUndefined = value === undefined; const isObject = !isArray && !isNull && typeof value === 'object'; const isPlain = !isArray && !isNull && !isUndefined && !isObject && !isFunction; if (isArray) { result[key] = value.map(v => this.parseValue(v)); } else if (isNull || isUndefined) { result[key] = null; } else if (isObject) { result[key] = {}; Object.entries(value).forEach(([k, v]) => result[key][k] = this.parseValue(v)); } else if (isPlain) { result[key] = this.parseValue(value); } else { throw new Error(`Unable to convert key ${key} with value ${value}. Type of value: ${typeof value}`); } } return result; } public toJSON(): string { return JSON.stringify(this.toPlain()); } }