mirror of
https://github.com/barsdeveloper/ueblueprint.git
synced 2026-02-27 18:54:44 +08:00
Grammar refactoring
* Grammar refactoring WIP * ISerializer.grammar * Fixing various bugs in the grammar * Small touch that improoves performance * Fix unknown values grammar * Various fixes * Serialization refactoring to drop suboject logic * Details fixed * Entity attributes initialization refactoring * JSDoc error fixed * Rename value key to default * Remove useless default * Revert string keys
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import GeneralSerializer from "./GeneralSerializer.js"
|
||||
|
||||
/**
|
||||
* @typedef {import("../entity/IEntity").default} IEntity
|
||||
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
|
||||
* @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor
|
||||
*/
|
||||
@@ -24,12 +23,12 @@ export default class CustomSerializer extends GeneralSerializer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} object
|
||||
* @param {T} entity
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
write(entity, object, insideString = false) {
|
||||
let result = this.#objectWriter(object, insideString)
|
||||
write(entity, insideString = false) {
|
||||
let result = this.#objectWriter(entity, insideString)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,7 @@ export default class GeneralSerializer extends ISerializer {
|
||||
* @returns {T}
|
||||
*/
|
||||
read(value) {
|
||||
// @ts-expect-error
|
||||
let grammar = Grammar.getGrammarForType(ISerializer.grammar, this.entityType)
|
||||
let grammar = Grammar.grammarFor(undefined, this.entityType)
|
||||
const parseResult = grammar.parse(value)
|
||||
if (!parseResult.status) {
|
||||
throw new Error(`Error when trying to parse the entity ${this.entityType.prototype.constructor.name}.`)
|
||||
@@ -38,12 +37,12 @@ export default class GeneralSerializer extends ISerializer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} object
|
||||
* @param {T} entity
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
write(entity, object, insideString = false) {
|
||||
let result = this.wrap(this.subWrite(entity, [], object, insideString), object)
|
||||
write(entity, insideString = false) {
|
||||
let result = this.wrap(super.write(entity, insideString), entity)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,5 @@
|
||||
import Grammar from "./Grammar.js"
|
||||
import Parsimmon from "parsimmon"
|
||||
import SerializerFactory from "./SerializerFactory.js"
|
||||
import Utility from "../Utility.js"
|
||||
import IEntity from "../entity/IEntity.js"
|
||||
|
||||
/**
|
||||
* @typedef {import("../entity/IEntity").EntityConstructor} EntityConstructor
|
||||
@@ -13,8 +10,6 @@ import IEntity from "../entity/IEntity.js"
|
||||
/** @template {AnyValue} T */
|
||||
export default class ISerializer {
|
||||
|
||||
static grammar = Parsimmon.createLanguage(new Grammar())
|
||||
|
||||
/** @param {AnyValueConstructor} entityType */
|
||||
constructor(
|
||||
entityType,
|
||||
@@ -22,7 +17,7 @@ export default class ISerializer {
|
||||
attributeSeparator = ",",
|
||||
trailingSeparator = false,
|
||||
attributeValueConjunctionSign = "=",
|
||||
attributeKeyPrinter = k => k.join(".")
|
||||
attributeKeyPrinter = k => k
|
||||
) {
|
||||
this.entityType = entityType
|
||||
this.attributePrefix = attributePrefix
|
||||
@@ -40,9 +35,9 @@ export default class ISerializer {
|
||||
return this.read(value)
|
||||
}
|
||||
|
||||
/** @param {T} object */
|
||||
serialize(object, insideString = false, entity = object) {
|
||||
return this.write(entity, object, insideString)
|
||||
/** @param {T} value */
|
||||
serialize(value, insideString = false) {
|
||||
return this.write(value, insideString)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,21 +51,46 @@ export default class ISerializer {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @param {T} object
|
||||
* @param {T} entity
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
write(entity, object, insideString) {
|
||||
throw new Error("Not implemented")
|
||||
write(entity, insideString) {
|
||||
let result = ""
|
||||
const attributes = /** @type {EntityConstructor} */(entity.constructor).attributes ?? {}
|
||||
const keys = Utility.mergeArrays(
|
||||
Object.keys(attributes),
|
||||
Object.keys(entity)
|
||||
)
|
||||
for (const key of keys) {
|
||||
const value = entity[key]
|
||||
if (value !== undefined && this.showProperty(entity, key)) {
|
||||
const isSerialized = Utility.isSerialized(entity, key)
|
||||
result += (result.length ? this.attributeSeparator : "")
|
||||
+ this.attributePrefix
|
||||
+ Utility.decodeKeyName(this.attributeKeyPrinter(key))
|
||||
+ this.attributeValueConjunctionSign
|
||||
+ (
|
||||
isSerialized
|
||||
? `"${this.writeValue(entity, key, true)}"`
|
||||
: this.writeValue(entity, key, insideString)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (this.trailingSeparator && result.length) {
|
||||
// append separator at the end if asked and there was printed content
|
||||
result += this.attributeSeparator
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @param {AnyValue} value
|
||||
* @param {String[]} fullKey
|
||||
* @param {String} key
|
||||
* @param {Boolean} insideString
|
||||
*/
|
||||
writeValue(entity, value, fullKey, insideString) {
|
||||
writeValue(entity, key, insideString) {
|
||||
const value = entity[key]
|
||||
const type = Utility.getType(value)
|
||||
// @ts-expect-error
|
||||
const serializer = SerializerFactory.getSerializer(type)
|
||||
@@ -78,65 +98,20 @@ export default class ISerializer {
|
||||
throw new Error(`Unknown value type "${type.name}", a serializer must be registered in the SerializerFactory class, check initializeSerializerFactory.js`)
|
||||
}
|
||||
return serializer.write(
|
||||
value instanceof IEntity ? value : entity,
|
||||
value,
|
||||
entity[key],
|
||||
insideString
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @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
|
||||
const attributes = /** @type {EntityConstructor} */(object.constructor).attributes
|
||||
const keys = attributes
|
||||
? Utility.mergeArrays(
|
||||
Object.keys(attributes),
|
||||
Object.keys(object)
|
||||
)
|
||||
: Object.keys(object)
|
||||
for (const property of keys) {
|
||||
fullKey[last] = property
|
||||
const value = object[property]
|
||||
if (value?.constructor === Object) {
|
||||
// Recursive call when finding an object
|
||||
result += (result.length ? this.attributeSeparator : "")
|
||||
+ 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.attributeSeparator : "")
|
||||
+ this.attributePrefix
|
||||
+ 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.attributeSeparator
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
showProperty(entity, object, attributeKey, attributeValue) {
|
||||
showProperty(entity, key) {
|
||||
const attributes = /** @type {EntityConstructor} */(this.entityType).attributes
|
||||
const attribute = Utility.objectGet(attributes, attributeKey)
|
||||
const attribute = attributes[key]
|
||||
const value = entity[key]
|
||||
if (attribute?.constructor === Object) {
|
||||
if (attribute.ignored) {
|
||||
return false
|
||||
}
|
||||
return !Utility.equals(attribute.value, attributeValue) || attribute.showDefault
|
||||
return !Utility.equals(attribute.value, value) || attribute.showDefault
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Grammar from "./Grammar.js"
|
||||
import ISerializer from "./ISerializer.js"
|
||||
import ObjectEntity from "../entity/ObjectEntity.js"
|
||||
import PinEntity from "../entity/PinEntity.js"
|
||||
@@ -9,20 +10,20 @@ export default class ObjectSerializer extends ISerializer {
|
||||
super(ObjectEntity, " ", "\n", false)
|
||||
}
|
||||
|
||||
showProperty(entity, object, attributeKey, attributeValue) {
|
||||
switch (attributeKey.toString()) {
|
||||
showProperty(entity, key) {
|
||||
switch (key) {
|
||||
case "Class":
|
||||
case "Name":
|
||||
case "CustomProperties":
|
||||
// Serielized separately
|
||||
// Serielized separately, check write()
|
||||
return false
|
||||
}
|
||||
return super.showProperty(entity, object, attributeKey, attributeValue)
|
||||
return super.showProperty(entity, key)
|
||||
}
|
||||
|
||||
/** @param {String} value */
|
||||
read(value) {
|
||||
const parseResult = ISerializer.grammar.Object.parse(value)
|
||||
const parseResult = Grammar.objectEntity.parse(value)
|
||||
if (!parseResult.status) {
|
||||
throw new Error("Error when trying to parse the object.")
|
||||
}
|
||||
@@ -34,7 +35,7 @@ export default class ObjectSerializer extends ISerializer {
|
||||
* @returns {ObjectEntity[]}
|
||||
*/
|
||||
readMultiple(value) {
|
||||
const parseResult = ISerializer.grammar.MultipleObject.parse(value)
|
||||
const parseResult = Grammar.multipleObject.parse(value)
|
||||
if (!parseResult.status) {
|
||||
throw new Error("Error when trying to parse the object.")
|
||||
}
|
||||
@@ -42,21 +43,20 @@ export default class ObjectSerializer extends ISerializer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectEntity} object
|
||||
* @param {ObjectEntity} entity
|
||||
* @param {Boolean} 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.attributeSeparator
|
||||
+ this.attributePrefix
|
||||
+ "CustomProperties "
|
||||
+ SerializerFactory.getSerializer(PinEntity).serialize(pin)
|
||||
)
|
||||
.join("")}
|
||||
End Object\n`
|
||||
write(entity, insideString) {
|
||||
let result = `Begin Object Class=${entity.Class.path} Name=${this.writeValue(entity, "Name", insideString)}\n`
|
||||
+ super.write(entity, insideString)
|
||||
+ entity.CustomProperties.map(pin =>
|
||||
this.attributeSeparator
|
||||
+ this.attributePrefix
|
||||
+ "CustomProperties "
|
||||
+ SerializerFactory.getSerializer(PinEntity).serialize(pin)
|
||||
)
|
||||
.join("")
|
||||
+ "\nEnd Object\n"
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Utility from "../Utility.js"
|
||||
import GeneralSerializer from "./GeneralSerializer.js"
|
||||
|
||||
/**
|
||||
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
|
||||
/**
|
||||
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
|
||||
* @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor
|
||||
*/
|
||||
|
||||
@@ -18,12 +18,12 @@ export default class ToStringSerializer extends GeneralSerializer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} object
|
||||
* @param {T} entity
|
||||
* @param {Boolean} insideString
|
||||
*/
|
||||
write(entity, object, insideString) {
|
||||
return !insideString && object.constructor === String
|
||||
? `"${Utility.escapeString(object.toString())}"` // String will have quotes if not inside a string already
|
||||
: Utility.escapeString(object.toString())
|
||||
write(entity, insideString) {
|
||||
return !insideString && entity.constructor === String
|
||||
? `"${Utility.escapeString(entity.toString())}"` // String will have quotes if not inside a string already
|
||||
: Utility.escapeString(entity.toString())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user