@safejs/serializer
Version:
Serializer is a superset of JSON that includes recursive objects, dates, regular expressions, functions and others which you also can expand by yourself
76 lines (71 loc) • 3.41 kB
text/typescript
import { refs } from "../refs";
import { ExtraSerializersPreset, isConstantExtraSerializer, isRecursiveExtraSerializer } from "../types";
export class BaseDeserializer {
static deserialize(str: string, extraSerializers: ExtraSerializersPreset = {}) {
const [value, ...refsList] = JSON.parse(str);
const resRefs = BaseDeserializer.replaceRefsRefs(refsList, extraSerializers);
return BaseDeserializer.replaceRefs(value, resRefs, extraSerializers);
}
private static replaceRefsRefs(refsList: any[], extraSerializers: ExtraSerializersPreset) {
const resRefs = new Map<string, any>(refsList.map((ref, idx) => [refs.create(idx), ref]));
const prevRefs = new Map<string, any>();
const refsInitilizes = new Map<string, any>();
// prepare ref links (deserialize without initialize)
for (const [refId, ref] of resRefs.entries()) {
const serializerId = resRefs.get(ref?.[0]);
if (serializerId) {
const serializer = extraSerializers[serializerId];
if (serializer) {
resRefs.set(refId, serializer.deserialize(ref?.[1]));
if (isRecursiveExtraSerializer(serializer)) {
refsInitilizes.set(refId, serializer);
prevRefs.set(refId, ref?.[1]);
}
} else {
console.warn("Serilizer not found");
}
}
}
// replace refs
for (const [refId, ref] of resRefs.entries()) {
if (refsInitilizes.has(refId)) {
refsInitilizes
.get(refId)
.initialize(ref, BaseDeserializer.replaceRefs(prevRefs.get(refId), resRefs, extraSerializers));
} else {
resRefs.set(refId, BaseDeserializer.replaceRefs(ref, resRefs, extraSerializers));
}
}
return resRefs;
}
private static replaceRefs(value: any, known: Map<string, any>, serialziers: ExtraSerializersPreset) {
const knownValue = known.get(value);
if (knownValue) {
if (serialziers[knownValue] && isConstantExtraSerializer(serialziers[knownValue])) {
return serialziers[knownValue].deserialize(value);
}
return knownValue;
}
if (typeof value === "object" && value !== null) {
if (Array.isArray(value)) {
const serializerId = known.get(value?.[0]);
if (
serializerId &&
serialziers.hasOwnProperty(serializerId) &&
!isConstantExtraSerializer(serialziers[serializerId])
) {
const serializer = serialziers[serializerId];
const rs = serializer.deserialize(value?.[1]);
if (isRecursiveExtraSerializer(serializer)) {
serializer.initialize(rs, BaseDeserializer.replaceRefs(value?.[1], known, serialziers));
}
return rs;
}
}
for (const [key, v] of Object.entries(value)) {
value[key] = BaseDeserializer.replaceRefs(v, known, serialziers);
}
}
return value;
}
}