mirror of
https://github.com/barsdeveloper/ueblueprint.git
synced 2026-02-04 08:50:33 +08:00
Calculated serialization type
This commit is contained in:
@@ -5,16 +5,19 @@ import GeneralSerializer from "./GeneralSerializer"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {IEntity} T
|
||||
* @template {IEntity | Boolean | Number | String} T
|
||||
*/
|
||||
export default class CustomSerializer extends GeneralSerializer {
|
||||
|
||||
#objectWriter
|
||||
|
||||
/**
|
||||
* @param {(v: T, insideString: Boolean) => String} objectWriter
|
||||
* @param {new () => T} entityType
|
||||
*/
|
||||
constructor(objectWriter, entityType) {
|
||||
super(undefined, entityType)
|
||||
this.objectWriter = objectWriter
|
||||
this.#objectWriter = objectWriter
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,8 +25,8 @@ export default class CustomSerializer extends GeneralSerializer {
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
write(object, insideString = false) {
|
||||
let result = this.objectWriter(object, insideString)
|
||||
write(entity, object, insideString = false) {
|
||||
let result = this.#objectWriter(object, insideString)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ export default class GeneralSerializer extends ISerializer {
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
write(object, insideString = false) {
|
||||
let result = this.wrap(this.subWrite([], object, insideString))
|
||||
write(entity, object, insideString = false) {
|
||||
let result = this.wrap(this.subWrite(entity, [], object, insideString))
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import SerializedType from "../entity/SerializedType"
|
||||
import TypeInitialization from "../entity/TypeInitialization"
|
||||
import Utility from "../Utility"
|
||||
import VectorEntity from "../entity/VectorEntity"
|
||||
import CalculatedType from "../entity/CalculatedType"
|
||||
|
||||
/**
|
||||
* @typedef {import("../entity/IEntity").default} IEntity
|
||||
@@ -30,32 +29,9 @@ export default class Grammar {
|
||||
|
||||
static getGrammarForType(r, attributeType, defaultGrammar) {
|
||||
if (attributeType instanceof TypeInitialization) {
|
||||
// Unpack TypeInitialization
|
||||
attributeType = attributeType.type
|
||||
return Grammar.getGrammarForType(r, attributeType, defaultGrammar)
|
||||
}
|
||||
if (attributeType instanceof SerializedType) {
|
||||
const nonStringTypes = attributeType.types.filter(t => t !== String)
|
||||
let result = P.alt(
|
||||
...nonStringTypes.map(t =>
|
||||
Grammar.getGrammarForType(r, t).wrap(P.string('"'), P.string('"')).map(
|
||||
/**
|
||||
* @param {IEntity} entity
|
||||
*/
|
||||
entity => {
|
||||
entity.setShowAsString(true) // Showing as string because it is inside a SerializedType
|
||||
return entity
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
if (nonStringTypes.length < attributeType.types.length) {
|
||||
result = result.or(r.String/*.map(v => {
|
||||
if (attributeType.stringFallback) {
|
||||
console.log("Unrecognized value, fallback on String")
|
||||
}
|
||||
return v
|
||||
})*/) // Separated because it cannot be wrapped into " and "
|
||||
let result = Grammar.getGrammarForType(r, attributeType.type, defaultGrammar)
|
||||
if (attributeType.serialized && !(attributeType.type instanceof String)) {
|
||||
result = result.wrap(P.string('"'), P.string('"'))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -149,7 +125,12 @@ export default class Grammar {
|
||||
|
||||
Null = r => P.seq(P.string("("), r.InlineOptWhitespace, P.string(")")).map(_ => null).desc("null: ()")
|
||||
|
||||
Boolean = r => P.alt(P.string("True"), P.string("False")).map(v => v === "True" ? true : false)
|
||||
Boolean = r => P.alt(
|
||||
P.string("True"),
|
||||
P.string("true"),
|
||||
P.string("False"),
|
||||
P.string("false"),
|
||||
).map(v => v.toLocaleLowerCase() === "true" ? true : false)
|
||||
.desc("either True or False")
|
||||
|
||||
HexDigit = r => P.regex(/[0-9a-fA-f]/).desc("hexadecimal digit")
|
||||
|
||||
@@ -34,13 +34,8 @@ export default class ISerializer {
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
serialize(object, insideString) {
|
||||
insideString ||= object.isShownAsString()
|
||||
let result = this.write(object, insideString)
|
||||
if (object.isShownAsString()) {
|
||||
result = `"${result}"`
|
||||
}
|
||||
return result
|
||||
serialize(object, insideString, entity = object) {
|
||||
return this.write(entity, object, insideString)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +51,7 @@ export default class ISerializer {
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
write(object, insideString) {
|
||||
write(entity, object, insideString) {
|
||||
throw new Error("Not implemented")
|
||||
}
|
||||
|
||||
@@ -64,30 +59,12 @@ export default class ISerializer {
|
||||
* @param {String[]} fullKey
|
||||
* @param {Boolean} insideString
|
||||
*/
|
||||
writeValue(value, fullKey, insideString) {
|
||||
if (value === null) {
|
||||
return "()"
|
||||
}
|
||||
const serialize = v => SerializerFactory.getSerializer(Utility.getType(v)).serialize(v)
|
||||
// This is an exact match (and not instanceof) to hit also primitive types (by accessing value.constructor they are converted to objects automatically)
|
||||
switch (value?.constructor) {
|
||||
case Function:
|
||||
return this.writeValue(value(), fullKey, insideString)
|
||||
case Boolean:
|
||||
return Utility.firstCapital(value.toString())
|
||||
case Number:
|
||||
return value.toString()
|
||||
case String:
|
||||
return insideString
|
||||
? `\\"${Utility.encodeString(value)}\\"`
|
||||
: `"${Utility.encodeString(value)}"`
|
||||
}
|
||||
if (value instanceof Array) {
|
||||
return `(${value.map(v => serialize(v) + ",").join("")})`
|
||||
}
|
||||
if (value instanceof IEntity) {
|
||||
return serialize(value)
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,7 +73,7 @@ export default class ISerializer {
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
subWrite(key, object, insideString) {
|
||||
subWrite(entity, key, object, insideString) {
|
||||
let result = ""
|
||||
let fullKey = key.concat("")
|
||||
const last = fullKey.length - 1
|
||||
@@ -106,13 +83,18 @@ export default class ISerializer {
|
||||
if (value?.constructor === Object) {
|
||||
// Recursive call when finding an object
|
||||
result += (result.length ? this.separator : "")
|
||||
+ this.subWrite(fullKey, value, insideString)
|
||||
} else if (value !== undefined && this.showProperty(object, fullKey, value)) {
|
||||
+ 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
|
||||
+ this.writeValue(value, fullKey, insideString)
|
||||
+ (
|
||||
isSerialized
|
||||
? `"${this.writeValue(entity, value, fullKey, true)}"`
|
||||
: this.writeValue(entity, value, fullKey, insideString)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (this.trailingSeparator && result.length && fullKey.length === 1) {
|
||||
@@ -122,7 +104,7 @@ export default class ISerializer {
|
||||
return result
|
||||
}
|
||||
|
||||
showProperty(object, attributeKey, attributeValue) {
|
||||
showProperty(entity, object, attributeKey, attributeValue) {
|
||||
const attributes = this.entityType.attributes
|
||||
const attribute = Utility.objectGet(attributes, attributeKey)
|
||||
if (attribute instanceof TypeInitialization) {
|
||||
|
||||
@@ -9,7 +9,7 @@ export default class ObjectSerializer extends ISerializer {
|
||||
super(ObjectEntity, " ", "\n", false)
|
||||
}
|
||||
|
||||
showProperty(object, attributeKey, attributeValue) {
|
||||
showProperty(entity, object, attributeKey, attributeValue) {
|
||||
switch (attributeKey.toString()) {
|
||||
case "Class":
|
||||
case "Name":
|
||||
@@ -17,7 +17,7 @@ export default class ObjectSerializer extends ISerializer {
|
||||
// Serielized separately
|
||||
return false
|
||||
}
|
||||
return super.showProperty(object, attributeKey, attributeValue)
|
||||
return super.showProperty(entity, object, attributeKey, attributeValue)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,9 +46,9 @@ export default class ObjectSerializer extends ISerializer {
|
||||
* @param {ObjectEntity} object
|
||||
* @param {Boolean} insideString
|
||||
*/
|
||||
write(object, insideString) {
|
||||
let result = `Begin Object Class=${object.Class.path} Name=${this.writeValue(object.Name, ["Name"], insideString)}
|
||||
${this.subWrite([], object, insideString)
|
||||
write(entity, object, insideString) {
|
||||
let result = `Begin Object Class=${object.Class.path} Name=${this.writeValue(entity, object.Name, ["Name"], insideString)}
|
||||
${this.subWrite(entity, [], object, insideString)
|
||||
+ object
|
||||
.CustomProperties.map(pin =>
|
||||
this.separator
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import PinEntity from "../entity/PinEntity"
|
||||
import Utility from "../Utility"
|
||||
import GeneralSerializer from "./GeneralSerializer"
|
||||
|
||||
export default class PinSerializer extends GeneralSerializer {
|
||||
|
||||
constructor() {
|
||||
super(v => `${PinEntity.lookbehind} (${v})`, PinEntity, "", ",", true)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String[]} fullKey
|
||||
* @param {Boolean} insideString
|
||||
*/
|
||||
writeValue(value, fullKey, insideString) {
|
||||
if (value?.constructor === String && fullKey.length == 1 && fullKey[0] == "DefaultValue") {
|
||||
return `"${Utility.encodeInputString(value)}"`
|
||||
}
|
||||
return super.writeValue(value, fullKey, insideString)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,25 @@
|
||||
import Utility from "../Utility"
|
||||
|
||||
/** @typedef {import("../entity/IEntity").default} IEntity */
|
||||
/**
|
||||
* @template {IEntity} T
|
||||
* @typedef {import("./ISerializer").default<T>} ISerializer
|
||||
*/
|
||||
|
||||
export default class SerializerFactory {
|
||||
|
||||
/** @type {Map<T, ISerializer<T>>} */
|
||||
static #serializers = new Map()
|
||||
|
||||
static registerSerializer(entity, object) {
|
||||
SerializerFactory.#serializers.set(entity, object)
|
||||
}
|
||||
|
||||
/**
|
||||
* @template {IEntity} T
|
||||
* @param {T} entity
|
||||
*/
|
||||
static getSerializer(entity) {
|
||||
return SerializerFactory.#serializers.get(Utility.getType(entity))
|
||||
return SerializerFactory.#serializers.get(entity)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Utility from "../Utility"
|
||||
import GeneralSerializer from "./GeneralSerializer"
|
||||
|
||||
/**
|
||||
@@ -20,10 +21,9 @@ export default class ToStringSerializer extends GeneralSerializer {
|
||||
* @param {T} object
|
||||
* @param {Boolean} insideString
|
||||
*/
|
||||
write(object, insideString) {
|
||||
let result = insideString || object.isShownAsString()
|
||||
? `"${object.toString().replaceAll('"', '\\"')}"`
|
||||
: object.toString()
|
||||
return result
|
||||
write(entity, object, insideString) {
|
||||
return !insideString && object.constructor === String
|
||||
? `"${Utility.encodeString(object.toString())}"` // String will have quotes if not inside a string already
|
||||
: Utility.encodeString(object.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,52 @@ import ObjectSerializer from "./ObjectSerializer"
|
||||
import PathSymbolEntity from "../entity/PathSymbolEntity"
|
||||
import PinEntity from "../entity/PinEntity"
|
||||
import PinReferenceEntity from "../entity/PinReferenceEntity"
|
||||
import PinSerializer from "./PinSerializer"
|
||||
import SerializerFactory from "./SerializerFactory"
|
||||
import ToStringSerializer from "./ToStringSerializer"
|
||||
import Utility from "../Utility"
|
||||
|
||||
export default function initializeSerializerFactory() {
|
||||
|
||||
const bracketsWrapped = v => `(${v})`
|
||||
|
||||
SerializerFactory.registerSerializer(
|
||||
null,
|
||||
new CustomSerializer(
|
||||
(nullValue, insideString) => "()",
|
||||
null
|
||||
)
|
||||
)
|
||||
|
||||
SerializerFactory.registerSerializer(
|
||||
Array,
|
||||
new CustomSerializer(
|
||||
/** @param {Array} array */
|
||||
(array, insideString) =>
|
||||
`(${array
|
||||
.map(v =>
|
||||
SerializerFactory.getSerializer(Utility.getType(v)).serialize(v, insideString) + ","
|
||||
)
|
||||
.join("")
|
||||
})`,
|
||||
Array
|
||||
)
|
||||
)
|
||||
|
||||
SerializerFactory.registerSerializer(
|
||||
Boolean,
|
||||
new CustomSerializer(
|
||||
/** @param {Boolean} boolean */
|
||||
(boolean, insideString) => boolean
|
||||
? insideString
|
||||
? "true"
|
||||
: "True"
|
||||
: insideString
|
||||
? "false"
|
||||
: "False",
|
||||
Boolean
|
||||
)
|
||||
)
|
||||
|
||||
SerializerFactory.registerSerializer(
|
||||
FunctionReferenceEntity,
|
||||
new GeneralSerializer(bracketsWrapped, FunctionReferenceEntity)
|
||||
@@ -53,6 +91,15 @@ export default function initializeSerializerFactory() {
|
||||
new GeneralSerializer(v => `${LocalizedTextEntity.lookbehind}(${v})`, LocalizedTextEntity, "", ", ", false, "", _ => "")
|
||||
)
|
||||
|
||||
SerializerFactory.registerSerializer(
|
||||
Number,
|
||||
new CustomSerializer(
|
||||
/** @param {Number} value */
|
||||
value => value.toString(),
|
||||
Number
|
||||
)
|
||||
)
|
||||
|
||||
SerializerFactory.registerSerializer(
|
||||
ObjectEntity,
|
||||
new ObjectSerializer()
|
||||
@@ -73,13 +120,23 @@ export default function initializeSerializerFactory() {
|
||||
|
||||
SerializerFactory.registerSerializer(PathSymbolEntity, new ToStringSerializer(PathSymbolEntity))
|
||||
|
||||
SerializerFactory.registerSerializer(
|
||||
PinEntity,
|
||||
new GeneralSerializer(v => `${PinEntity.lookbehind} (${v})`, PinEntity, "", ",", true)
|
||||
)
|
||||
|
||||
SerializerFactory.registerSerializer(
|
||||
PinReferenceEntity,
|
||||
new GeneralSerializer(v => v, PinReferenceEntity, "", " ", false, "", _ => "")
|
||||
)
|
||||
|
||||
SerializerFactory.registerSerializer(
|
||||
PinEntity,
|
||||
new PinSerializer()
|
||||
String,
|
||||
new CustomSerializer(
|
||||
(value, insideString) => insideString
|
||||
? Utility.encodeString(value)
|
||||
: `"${Utility.encodeString(value)}"`,
|
||||
String
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user