Type initialization using objects

This commit is contained in:
barsdeveloper
2023-01-02 00:22:50 +01:00
parent d391480f2c
commit 984bf32b51
43 changed files with 1511 additions and 831 deletions

View File

@@ -2,11 +2,8 @@ import GeneralSerializer from "./GeneralSerializer"
/**
* @typedef {import("../entity/IEntity").default} IEntity
* @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue
*/
/**
* @template {AnyValue} T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
* @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor
*/
/**
@@ -19,7 +16,7 @@ export default class CustomSerializer extends GeneralSerializer {
/**
* @param {(v: T, insideString: Boolean) => String} objectWriter
* @param {AnyValueConstructor<T>} entityType
* @param {AnyValueConstructor} entityType
*/
constructor(objectWriter, entityType) {
super(undefined, entityType)

View File

@@ -3,11 +3,8 @@ import ISerializer from "./ISerializer"
/**
* @typedef {import("../entity/IEntity").default} IEntity
* @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue
*/
/**
* @template {AnyValue} T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
* @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor
*/
/**
@@ -18,7 +15,7 @@ export default class GeneralSerializer extends ISerializer {
/**
* @param {(value: String, entity: T) => String} wrap
* @param {AnyValueConstructor<T>} entityType
* @param {AnyValueConstructor} entityType
*/
constructor(wrap, entityType, attributePrefix, attributeSeparator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) {
wrap = wrap ?? (v => `(${v})`)
@@ -35,7 +32,6 @@ export default class GeneralSerializer extends ISerializer {
let grammar = Grammar.getGrammarForType(ISerializer.grammar, this.entityType)
const parseResult = grammar.parse(value)
if (!parseResult.status) {
// @ts-expect-error
throw new Error(`Error when trying to parse the entity ${this.entityType.prototype.constructor.name}.`)
}
return parseResult.value

View File

@@ -1,4 +1,5 @@
// @ts-nocheck
import ByteEntity from "../entity/ByteEntity"
import FunctionReferenceEntity from "../entity/FunctionReferenceEntity"
import GuidEntity from "../entity/GuidEntity"
import IdentifierEntity from "../entity/IdentifierEntity"
@@ -17,17 +18,17 @@ import PinReferenceEntity from "../entity/PinReferenceEntity"
import RealUnitEntity from "../entity/UnitRealEntity"
import RotatorEntity from "../entity/RotatorEntity"
import SimpleSerializationRotatorEntity from "../entity/SimpleSerializationRotatorEntity"
import SimpleSerializationVector2DEntity from "../entity/SimpleSerializationVector2DEntity"
import SimpleSerializationVectorEntity from "../entity/SimpleSerializationVectorEntity"
import SymbolEntity from "../entity/SymbolEntity"
import TypeInitialization from "../entity/TypeInitialization"
import UnionType from "../entity/UnionType"
import UnknownKeysEntity from "../entity/UnknownKeysEntity"
import Utility from "../Utility"
import VariableReferenceEntity from "../entity/VariableReferenceEntity"
import Vector2DEntity from "../entity/Vector2DEntity"
import VectorEntity from "../entity/VectorEntity"
import SimpleSerializationVector2DEntity from "../entity/SimpleSerializationVector2DEntity"
import ByteEntity from "../entity/ByteEntity"
/** @typedef {import ("../entity/IEntity").AttributeInformation} AttributeInformation */
let P = Parsimmon
@@ -36,30 +37,35 @@ export default class Grammar {
/* --- Factory --- */
/** @param {Grammar} r */
static getGrammarForType(r, attributeType, defaultGrammar = r.AttributeAnyValue) {
if (attributeType instanceof TypeInitialization) {
let result = Grammar.getGrammarForType(r, attributeType.type, defaultGrammar)
if (attributeType.serialized && !(attributeType.type instanceof String)) {
static getGrammarForType(r, attribute, defaultGrammar = r.AttributeAnyValue) {
if (attribute.constructor === Object) {
attribute = /** @type {AttributeInformation} */(attribute)
let type = attribute.type
let result
if (type instanceof Array) {
result = Grammar.getGrammarForType(r, type[0])
.trim(P.optWhitespace)
.sepBy(P.string(","))
.skip(P.regex(/,?\s*/))
.wrap(P.string("("), P.string(")"))
} else if (type instanceof UnionType) {
result = type.types
.map(v => Grammar.getGrammarForType(r, Utility.getType(v)))
.reduce((accum, cur) => !cur || accum === r.AttributeAnyValue
? r.AttributeAnyValue
: accum.or(cur))
} else {
result = Grammar.getGrammarForType(r, type, defaultGrammar)
}
if (attribute.serialized && !(type instanceof String)) {
result = result.wrap(P.string('"'), P.string('"'))
}
if (attribute.nullable) {
result = result.or(r.Null)
}
return result
}
switch (Utility.getType(attributeType)) {
case Array:
return P.seqMap(
P.string("("),
attributeType
.map(v => Grammar.getGrammarForType(r, Utility.getType(v)))
.reduce((accum, cur) => !cur || accum === r.AttributeAnyValue
? r.AttributeAnyValue
: accum.or(cur)
)
.trim(P.optWhitespace)
.sepBy(P.string(","))
.skip(P.regex(/,?\s*/)),
P.string(")"),
(_0, grammar, _2) => grammar
)
switch (attribute) {
case Boolean:
return r.Boolean
case ByteEntity:
@@ -102,12 +108,6 @@ export default class Grammar {
return r.String
case SymbolEntity:
return r.Symbol
case UnionType:
return attributeType.types
.map(v => Grammar.getGrammarForType(r, Utility.getType(v)))
.reduce((accum, cur) => !cur || accum === r.AttributeAnyValue
? r.AttributeAnyValue
: accum.or(cur))
case VariableReferenceEntity:
return r.VariableReference
case Vector2DEntity:
@@ -145,7 +145,10 @@ export default class Grammar {
// Once the attribute name is known, look into entityType.attributes to get its type
const attributeKey = attributeName.split(".")
const attribute = Utility.objectGet(entityType.attributes, attributeKey)
let attributeValueGrammar = Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue)
let attributeValueGrammar =
attribute.constructor === Object && /** @type {AttributeInformation} */(attribute).serialized
? r.String
: Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue)
// Returns a setter function for the attribute
return attributeValueGrammar.map(attributeValue =>
entity => Utility.objectSet(entity, attributeKey, attributeValue, true)

View File

@@ -1,16 +1,13 @@
import Grammar from "./Grammar"
import Parsimmon from "parsimmon"
import SerializerFactory from "./SerializerFactory"
import TypeInitialization from "../entity/TypeInitialization"
import Utility from "../Utility"
import IEntity from "../entity/IEntity"
/**
* @typedef {import("../entity/IEntity").EntityConstructor} EntityConstructor
* @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue
*/
/**
* @template {AnyValue} T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
* @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor
*/
/** @template {AnyValue} T */
@@ -18,7 +15,7 @@ export default class ISerializer {
static grammar = Parsimmon.createLanguage(new Grammar())
/** @param {AnyValueConstructor<T>} entityType */
/** @param {AnyValueConstructor} entityType */
constructor(
entityType,
attributePrefix = "",
@@ -76,7 +73,11 @@ export default class ISerializer {
if (!serializer) {
throw new Error(`Unknown value type "${type.name}", a serializer must be registered in the SerializerFactory class, check initializeSerializerFactory.js`)
}
return serializer.write(entity, value, insideString)
return serializer.write(
value instanceof IEntity ? value : entity,
value,
insideString
)
}
/**
@@ -90,13 +91,12 @@ export default class ISerializer {
let fullKey = key.concat("")
const last = fullKey.length - 1
const attributes = /** @type {EntityConstructor} */(object.constructor).attributes
const keys =
attributes ?
Utility.mergeArrays(
Object.getOwnPropertyNames(attributes),
Object.getOwnPropertyNames(object)
)
: Object.getOwnPropertyNames(object)
const keys = attributes
? Utility.mergeArrays(
Object.getOwnPropertyNames(attributes),
Object.getOwnPropertyNames(object)
)
: Object.getOwnPropertyNames(object)
for (const property of keys) {
fullKey[last] = property
const value = object[property]
@@ -125,10 +125,9 @@ export default class ISerializer {
}
showProperty(entity, object, attributeKey, attributeValue) {
// @ts-expect-error
const attributes = /** @type {EntityConstructor} */(this.entityType).attributes
const attribute = Utility.objectGet(attributes, attributeKey)
if (attribute instanceof TypeInitialization) {
if (attribute.constructor === Object) {
if (attribute.ignored) {
return false
}

View File

@@ -1,10 +1,11 @@
/**
* @typedef {import("../entity/IEntity").default} IEntity
* @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
*/
/**
* @template T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
* @template {AnyValue} T
* @typedef {import("../entity/IEntity").AnyValueConstructor<T>} AnyValueConstructor
*/
/**
* @template {AnyValue} T
@@ -16,6 +17,11 @@ export default class SerializerFactory {
/** @type {Map<AnyValueConstructor<AnyValue>, ISerializer<AnyValue>>} */
static #serializers = new Map()
/**
* @template {AnyValue} T
* @param {AnyValueConstructor<T>} entity
* @param {ISerializer<T>} object
*/
static registerSerializer(entity, object) {
SerializerFactory.#serializers.set(entity, object)
}

View File

@@ -1,18 +1,18 @@
import Utility from "../Utility"
import GeneralSerializer from "./GeneralSerializer"
/** @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue */
/**
* @template {AnyValue} T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
/**
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
* @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor
*/
/**
* @template {AnyValue} T
* @extends {GeneralSerializer<T>}
*/
export default class ToStringSerializer extends GeneralSerializer {
/** @param {AnyValueConstructor<T>} entityType */
/** @param {AnyValueConstructor} entityType */
constructor(entityType) {
super(undefined, entityType)
}

View File

@@ -19,6 +19,7 @@ import RealUnitEntity from "../entity/UnitRealEntity"
import RotatorEntity from "../entity/RotatorEntity"
import SerializerFactory from "./SerializerFactory"
import SimpleSerializationRotatorEntity from "../entity/SimpleSerializationRotatorEntity"
import SimpleSerializationVector2DEntity from "../entity/SimpleSerializationVector2DEntity"
import SimpleSerializationVectorEntity from "../entity/SimpleSerializationVectorEntity"
import SymbolEntity from "../entity/SymbolEntity"
import ToStringSerializer from "./ToStringSerializer"
@@ -27,7 +28,11 @@ import Utility from "../Utility"
import VariableReferenceEntity from "../entity/VariableReferenceEntity"
import Vector2DEntity from "../entity/Vector2DEntity"
import VectorEntity from "../entity/VectorEntity"
import SimpleSerializationVector2DEntity from "../entity/SimpleSerializationVector2DEntity"
/**
* @typedef {import("../entity/IEntity").AnySimpleValue} AnySimpleValue
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
*/
export default function initializeSerializerFactory() {
@@ -44,11 +49,10 @@ export default function initializeSerializerFactory() {
SerializerFactory.registerSerializer(
Array,
new CustomSerializer(
/** @param {Array} array */
/** @param {AnySimpleValue[]} array */
(array, insideString) =>
`(${array
.map(v =>
// @ts-expect-error
SerializerFactory.getSerializer(Utility.getType(v)).serialize(v, insideString) + ","
)
.join("")