Files
ueblueprint/js/serialization/ISerializer.js
2022-10-22 23:06:37 +02:00

131 lines
4.2 KiB
JavaScript

import Grammar from "./Grammar"
import Parsimmon from "parsimmon"
import SerializerFactory from "./SerializerFactory"
import TypeInitialization from "../entity/TypeInitialization"
import Utility from "../Utility"
/**
* @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue
*/
/**
* @template {AnyValue} T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
*/
/** @template {AnyValue} T */
export default class ISerializer {
// @ts-expect-error
static grammar = Parsimmon.createLanguage(new Grammar())
/** @param {AnyValueConstructor<T>} entityType */
constructor(
entityType,
prefix = "",
separator = ",",
trailingSeparator = false,
attributeValueConjunctionSign = "=",
attributeKeyPrinter = k => k.join(".")
) {
this.entityType = entityType
this.prefix = prefix
this.separator = separator
this.trailingSeparator = trailingSeparator
this.attributeValueConjunctionSign = attributeValueConjunctionSign
this.attributeKeyPrinter = attributeKeyPrinter
}
/**
* @param {String} value
* @returns {T}
*/
deserialize(value) {
return this.read(value)
}
/** @param {T} object */
serialize(object, insideString = false, entity = object) {
return this.write(entity, object, insideString)
}
/**
* @param {String} value
* @returns {T}
*/
read(value) {
throw new Error("Not implemented")
}
/**
* @param {T} object
* @param {Boolean} insideString
* @returns {String}
*/
write(entity, object, insideString) {
throw new Error("Not implemented")
}
/**
* @param {AnyValue} value
* @param {String[]} fullKey
* @param {Boolean} insideString
*/
writeValue(entity, value, fullKey, insideString) {
const serializer = SerializerFactory.getSerializer(Utility.getType(value))
if (!serializer) {
throw new Error("Unknown value type, a serializer must be registered in the SerializerFactory class")
}
return serializer.write(entity, value, insideString)
}
/**
* @param {String[]} key
* @param {Object} object
* @param {Boolean} insideString
* @returns {String}
*/
subWrite(entity, key, object, insideString) {
let result = ""
let fullKey = key.concat("")
const last = fullKey.length - 1
for (const property of Object.getOwnPropertyNames(object)) {
fullKey[last] = property
const value = object[property]
if (value?.constructor === Object) {
// Recursive call when finding an object
result += (result.length ? this.separator : "")
+ this.subWrite(entity, fullKey, value, insideString)
} else if (value !== undefined && this.showProperty(entity, object, fullKey, value)) {
const isSerialized = Utility.isSerialized(entity, fullKey)
result += (result.length ? this.separator : "")
+ this.prefix
+ this.attributeKeyPrinter(fullKey)
+ this.attributeValueConjunctionSign
+ (
isSerialized
? `"${this.writeValue(entity, value, fullKey, true)}"`
: this.writeValue(entity, value, fullKey, insideString)
)
}
}
if (this.trailingSeparator && result.length && fullKey.length === 1) {
// append separator at the end if asked and there was printed content
result += this.separator
}
return result
}
showProperty(entity, object, attributeKey, attributeValue) {
// @ts-expect-error
const attributes = this.entityType.attributes
const attribute = Utility.objectGet(attributes, attributeKey)
if (attribute instanceof TypeInitialization) {
if (attribute.ignored) {
return false
}
return !Utility.equals(attribute.value, attributeValue) || attribute.showDefault
}
return true
}
}