Inlineable objects

This commit is contained in:
barsdeveloper
2023-04-06 19:23:20 +02:00
parent 323d3dd040
commit ba3e9fa592
11 changed files with 212 additions and 212 deletions

View File

@@ -1,11 +1,11 @@
/// <reference types="cypress" /> /// <reference types="cypress" />
import ComplexEntity from "../fixtures/ComplexEntity" import ComplexEntity from "../fixtures/ComplexEntity"
import GeneralSerializer from "../../js/serialization/GeneralSerializer.js"
import initializeSerializerFactory from "../../js/serialization/initializeSerializerFactory.js" import initializeSerializerFactory from "../../js/serialization/initializeSerializerFactory.js"
import SerializerFactory from "../../js/serialization/SerializerFactory.js" import SerializerFactory from "../../js/serialization/SerializerFactory.js"
import SimpleEntity from "../fixtures/SimpleEntity" import SimpleEntity from "../fixtures/SimpleEntity"
import SimpleObject from "../fixtures/SimpleObject" import SimpleObject from "../fixtures/SimpleObject"
import ISerializer from "../../js/serialization/ISerializer.js"
describe("Entity initialization", () => { describe("Entity initialization", () => {
before(() => { before(() => {
@@ -19,9 +19,9 @@ describe("Entity initialization", () => {
initializeSerializerFactory() initializeSerializerFactory()
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
SimpleEntity, SimpleEntity,
new GeneralSerializer( new ISerializer(
v => `{\n${v}\n}`,
SimpleEntity, SimpleEntity,
v => `{\n${v}\n}`,
" ", " ",
"\n", "\n",
false, false,
@@ -137,9 +137,9 @@ describe("Entity initialization", () => {
initializeSerializerFactory() initializeSerializerFactory()
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
ComplexEntity, ComplexEntity,
new GeneralSerializer( new ISerializer(
v => `[[\n${v}\n]]`,
ComplexEntity, ComplexEntity,
v => `[[\n${v}\n]]`,
" ", " ",
"\n", "\n",
false, false,
@@ -149,9 +149,9 @@ describe("Entity initialization", () => {
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
SimpleObject, SimpleObject,
new GeneralSerializer( new ISerializer(
v => `SimpleObject(${v})`,
SimpleObject, SimpleObject,
v => `SimpleObject(${v})`,
"", "",
", ", ", ",
false, false,

View File

@@ -68,7 +68,7 @@ export default class ComplexEntity extends IEntity {
}, },
romeo: { romeo: {
type: SimpleObject, type: SimpleObject,
inline: true, inlined: true,
}, },
} }

217
dist/ueblueprint.js vendored
View File

@@ -896,6 +896,7 @@ class Utility {
* ignored?: Boolean, * ignored?: Boolean,
* serialized?: Boolean, * serialized?: Boolean,
* expected?: Boolean, * expected?: Boolean,
* inlined?: Boolean,
* predicate?: (value: AnyValue) => Boolean, * predicate?: (value: AnyValue) => Boolean,
* }} AttributeInformation * }} AttributeInformation
*/ */
@@ -917,6 +918,7 @@ class IEntity {
ignored: false, ignored: false,
serialized: false, serialized: false,
expected: false, expected: false,
inlined: false,
} }
constructor(values = {}, suppressWarns = false) { constructor(values = {}, suppressWarns = false) {
@@ -1007,7 +1009,7 @@ class IEntity {
if (value?.constructor === String && attribute.serialized && defaultType !== String) { if (value?.constructor === String && attribute.serialized && defaultType !== String) {
value = SerializerFactory value = SerializerFactory
.getSerializer(/** @type {AnyValueConstructor<*>} */(defaultType)) .getSerializer(/** @type {AnyValueConstructor<*>} */(defaultType))
.deserialize(/** @type {String} */(value)); .read(/** @type {String} */(value));
} }
assignAttribute(Utility.sanitize(value, /** @type {AnyValueConstructor<*>} */(defaultType))); assignAttribute(Utility.sanitize(value, /** @type {AnyValueConstructor<*>} */(defaultType)));
continue // We have a value, need nothing more continue // We have a value, need nothing more
@@ -1032,7 +1034,7 @@ class IEntity {
if (defaultType !== String && defaultValue.constructor === String) { if (defaultType !== String && defaultValue.constructor === String) {
defaultValue = SerializerFactory defaultValue = SerializerFactory
.getSerializer(/** @type {AnyValueConstructor<*>} */(defaultType)) .getSerializer(/** @type {AnyValueConstructor<*>} */(defaultType))
.deserialize(defaultValue); .read(defaultValue);
} }
} }
assignAttribute(Utility.sanitize( assignAttribute(Utility.sanitize(
@@ -3925,9 +3927,15 @@ class Grammar {
/** @template {AnyValue} T */ /** @template {AnyValue} T */
class ISerializer { class ISerializer {
/** @type {(v: String, entityType: AnyValueConstructor) => String} */
static bracketsWrapped = ((v, entityType) => `(${v})`)
/** @type {(v: String, entityType: AnyValueConstructor) => String} */
static notWrapped = ((v, entityType) => v)
/** @param {AnyValueConstructor} entityType */ /** @param {AnyValueConstructor} entityType */
constructor( constructor(
entityType, entityType,
wrap = ISerializer.bracketsWrapped,
attributePrefix = "", attributePrefix = "",
attributeSeparator = ",", attributeSeparator = ",",
trailingSeparator = false, trailingSeparator = false,
@@ -3935,6 +3943,7 @@ class ISerializer {
attributeKeyPrinter = k => k attributeKeyPrinter = k => k
) { ) {
this.entityType = entityType; this.entityType = entityType;
this.wrap = wrap;
this.attributePrefix = attributePrefix; this.attributePrefix = attributePrefix;
this.attributeSeparator = attributeSeparator; this.attributeSeparator = attributeSeparator;
this.trailingSeparator = trailingSeparator; this.trailingSeparator = trailingSeparator;
@@ -3946,13 +3955,13 @@ class ISerializer {
* @param {String} value * @param {String} value
* @returns {T} * @returns {T}
*/ */
deserialize(value) { read(value) {
return this.read(value) return this.doRead(value)
} }
/** @param {T} value */ /** @param {T} value */
serialize(value, insideString = false) { write(value, insideString = false) {
return this.write(value, insideString) return this.doWrite(value, insideString)
} }
/** /**
@@ -3960,8 +3969,13 @@ class ISerializer {
* @param {String} value * @param {String} value
* @returns {T} * @returns {T}
*/ */
read(value) { doRead(value) {
throw new Error("Not implemented") 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}.`)
}
return parseResult.value
} }
/** /**
@@ -3970,7 +3984,16 @@ class ISerializer {
* @param {Boolean} insideString * @param {Boolean} insideString
* @returns {String} * @returns {String}
*/ */
write(entity, insideString) { doWrite(
entity,
insideString,
wrap = this.wrap,
attributePrefix = this.attributePrefix,
attributeSeparator = this.attributeSeparator,
trailingSeparator = this.trailingSeparator,
attributeValueConjunctionSign = this.attributeValueConjunctionSign,
attributeKeyPrinter = this.attributeKeyPrinter
) {
let result = ""; let result = "";
const attributes = /** @type {EntityConstructor} */(entity.constructor).attributes ?? {}; const attributes = /** @type {EntityConstructor} */(entity.constructor).attributes ?? {};
const keys = Utility.mergeArrays( const keys = Utility.mergeArrays(
@@ -3981,29 +4004,41 @@ class ISerializer {
const value = entity[key]; const value = entity[key];
if (value !== undefined && this.showProperty(entity, key)) { if (value !== undefined && this.showProperty(entity, key)) {
const isSerialized = Utility.isSerialized(entity, key); const isSerialized = Utility.isSerialized(entity, key);
if (value instanceof IndexedArray) { result += (result.length ? attributeSeparator : "");
value.value.forEach((value, i) => if (attributes[key]?.inlined) {
result += (result.length ? this.attributeSeparator : "") result += this.doWrite(
+ this.attributePrefix value,
+ Utility.decodeKeyName(this.attributeKeyPrinter(key)) insideString,
+ `(${i})` ISerializer.notWrapped,
+ this.attributeValueConjunctionSign `${attributePrefix}${key}.`,
+ ( attributeSeparator,
isSerialized trailingSeparator,
? `"${this.writeValue(value, true)}"` attributeValueConjunctionSign,
: this.writeValue(value, insideString) attributeKeyPrinter
)
); );
continue continue
} }
result += (result.length ? this.attributeSeparator : "") if (value instanceof IndexedArray) {
+ this.attributePrefix result += this.doWrite(
value,
insideString,
wrap,
attributePrefix,
attributeSeparator,
trailingSeparator,
attributeValueConjunctionSign,
index => `(${index})`
);
continue
}
result +=
attributePrefix
+ Utility.decodeKeyName(this.attributeKeyPrinter(key)) + Utility.decodeKeyName(this.attributeKeyPrinter(key))
+ this.attributeValueConjunctionSign + this.attributeValueConjunctionSign
+ ( + (
isSerialized isSerialized
? `"${this.writeValue(value, true)}"` ? `"${this.doWriteValue(value, true)}"`
: this.writeValue(value, insideString) : this.doWriteValue(value, insideString)
); );
} }
} }
@@ -4011,14 +4046,14 @@ class ISerializer {
// append separator at the end if asked and there was printed content // append separator at the end if asked and there was printed content
result += this.attributeSeparator; result += this.attributeSeparator;
} }
return result return wrap(result, entity.constructor)
} }
/** /**
* @protected * @protected
* @param {Boolean} insideString * @param {Boolean} insideString
*/ */
writeValue(value, insideString) { doWriteValue(value, insideString) {
const type = Utility.getType(value); const type = Utility.getType(value);
// @ts-expect-error // @ts-expect-error
const serializer = SerializerFactory.getSerializer(type); const serializer = SerializerFactory.getSerializer(type);
@@ -4028,7 +4063,7 @@ class ISerializer {
+ "check initializeSerializerFactory.js" + "check initializeSerializerFactory.js"
) )
} }
return serializer.write( return serializer.doWrite(
value, value,
insideString insideString
) )
@@ -4051,7 +4086,7 @@ class ISerializer {
class ObjectSerializer extends ISerializer { class ObjectSerializer extends ISerializer {
constructor() { constructor() {
super(ObjectEntity, " ", "\n", false); super(ObjectEntity, undefined, " ", "\n", false);
} }
showProperty(entity, key) { showProperty(entity, key) {
@@ -4059,14 +4094,14 @@ class ObjectSerializer extends ISerializer {
case "Class": case "Class":
case "Name": case "Name":
case "CustomProperties": case "CustomProperties":
// Serielized separately, check write() // Serielized separately, check doWrite()
return false return false
} }
return super.showProperty(entity, key) return super.showProperty(entity, key)
} }
/** @param {String} value */ /** @param {String} value */
read(value) { doRead(value) {
const parseResult = Grammar.objectEntity.parse(value); const parseResult = Grammar.objectEntity.parse(value);
if (!parseResult.status) { if (!parseResult.status) {
throw new Error("Error when trying to parse the object.") throw new Error("Error when trying to parse the object.")
@@ -4087,17 +4122,31 @@ class ObjectSerializer extends ISerializer {
} }
/** /**
* @protected
* @param {ObjectEntity} entity * @param {ObjectEntity} entity
* @param {Boolean} insideString * @param {Boolean} insideString
* @returns {String}
*/ */
write(entity, insideString) { doWrite(
let result = `Begin Object Class=${entity.Class.path} Name=${this.writeValue(entity.Name, insideString)}\n` entity,
+ super.write(entity, insideString) insideString,
wrap = this.wrap,
attributePrefix = this.attributePrefix,
attributeSeparator = this.attributeSeparator,
trailingSeparator = this.trailingSeparator,
attributeValueConjunctionSign = this.attributeValueConjunctionSign,
attributeKeyPrinter = this.attributeKeyPrinter
) {
if (!(entity instanceof ObjectEntity)) {
return super.doWrite(entity, insideString)
}
let result = `Begin Object Class=${entity.Class.path} Name=${this.doWriteValue(entity.Name, insideString)}\n`
+ super.doWrite(entity, insideString)
+ entity.CustomProperties.map(pin => + entity.CustomProperties.map(pin =>
this.attributeSeparator this.attributeSeparator
+ this.attributePrefix + this.attributePrefix
+ "CustomProperties " + "CustomProperties "
+ SerializerFactory.getSerializer(PinEntity).serialize(pin) + SerializerFactory.getSerializer(PinEntity).write(pin)
) )
.join("") .join("")
+ "\nEnd Object\n"; + "\nEnd Object\n";
@@ -4131,7 +4180,7 @@ class Copy extends IInput {
getSerializedText() { getSerializedText() {
return this.blueprint return this.blueprint
.getNodes(true) .getNodes(true)
.map(node => Copy.#serializer.serialize(node.entity, false)) .map(node => Copy.#serializer.write(node.entity, false))
.join("") .join("")
} }
@@ -7496,7 +7545,7 @@ class NodeElement extends ISelectableDraggableElement {
/** @param {String} str */ /** @param {String} str */
static fromSerializedObject(str) { static fromSerializedObject(str) {
str = str.trim(); str = str.trim();
let entity = SerializerFactory.getSerializer(ObjectEntity).deserialize(str); let entity = SerializerFactory.getSerializer(ObjectEntity).read(str);
return NodeElement.newObject(/** @type {ObjectEntity} */(entity)) return NodeElement.newObject(/** @type {ObjectEntity} */(entity))
} }
@@ -9992,61 +10041,15 @@ function defineElements() {
} }
/** /**
* @typedef {import("../entity/IEntity").default} IEntity
* @typedef {import("../entity/IEntity").AnyValue} AnyValue * @typedef {import("../entity/IEntity").AnyValue} AnyValue
* @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor * @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor
*/ */
/** /**
* @template {AnyValue} T * @template {AnyValue} T
* @extends ISerializer<T> * @extends {ISerializer<T>}
*/ */
class GeneralSerializer extends ISerializer { class CustomSerializer extends ISerializer {
/**
* @param {(value: String, entity: T) => String} wrap
* @param {AnyValueConstructor} entityType
*/
constructor(wrap, entityType, attributePrefix, attributeSeparator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) {
wrap = wrap ?? (v => `(${v})`);
super(entityType, attributePrefix, attributeSeparator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter);
this.wrap = wrap;
}
/**
* @param {String} value
* @returns {T}
*/
read(value) {
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}.`)
}
return parseResult.value
}
/**
* @param {T} entity
* @param {Boolean} insideString
* @returns {String}
*/
write(entity, insideString = false) {
let result = this.wrap(super.write(entity, insideString), entity);
return result
}
}
/**
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
* @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor
*/
/**
* @template {AnyValue} T
* @extends {GeneralSerializer<T>}
*/
class CustomSerializer extends GeneralSerializer {
#objectWriter #objectWriter
@@ -10055,7 +10058,7 @@ class CustomSerializer extends GeneralSerializer {
* @param {AnyValueConstructor} entityType * @param {AnyValueConstructor} entityType
*/ */
constructor(objectWriter, entityType) { constructor(objectWriter, entityType) {
super(undefined, entityType); super(entityType);
this.#objectWriter = objectWriter; this.#objectWriter = objectWriter;
} }
@@ -10064,7 +10067,7 @@ class CustomSerializer extends GeneralSerializer {
* @param {Boolean} insideString * @param {Boolean} insideString
* @returns {String} * @returns {String}
*/ */
write(entity, insideString = false) { doWrite(entity, insideString = false) {
let result = this.#objectWriter(entity, insideString); let result = this.#objectWriter(entity, insideString);
return result return result
} }
@@ -10077,20 +10080,20 @@ class CustomSerializer extends GeneralSerializer {
/** /**
* @template {AnyValue} T * @template {AnyValue} T
* @extends {GeneralSerializer<T>} * @extends {ISerializer<T>}
*/ */
class ToStringSerializer extends GeneralSerializer { class ToStringSerializer extends ISerializer {
/** @param {AnyValueConstructor} entityType */ /** @param {AnyValueConstructor} entityType */
constructor(entityType) { constructor(entityType) {
super(undefined, entityType); super(entityType);
} }
/** /**
* @param {T} entity * @param {T} entity
* @param {Boolean} insideString * @param {Boolean} insideString
*/ */
write(entity, insideString) { doWrite(entity, insideString) {
return !insideString && entity.constructor === String return !insideString && entity.constructor === String
? `"${Utility.escapeString(entity.toString())}"` // String will have quotes if not inside a string already ? `"${Utility.escapeString(entity.toString())}"` // String will have quotes if not inside a string already
: Utility.escapeString(entity.toString()) : Utility.escapeString(entity.toString())
@@ -10104,8 +10107,6 @@ class ToStringSerializer extends GeneralSerializer {
function initializeSerializerFactory() { function initializeSerializerFactory() {
const bracketsWrapped = v => `(${v})`;
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
null, null,
new CustomSerializer( new CustomSerializer(
@@ -10122,7 +10123,7 @@ function initializeSerializerFactory() {
`(${array `(${array
.map(v => .map(v =>
// @ts-expect-error // @ts-expect-error
SerializerFactory.getSerializer(Utility.getType(v)).serialize(v, insideString) + "," SerializerFactory.getSerializer(Utility.getType(v)).write(v, insideString) + ","
) )
.join("") .join("")
})`, })`,
@@ -10162,7 +10163,7 @@ function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
FunctionReferenceEntity, FunctionReferenceEntity,
new GeneralSerializer(bracketsWrapped, FunctionReferenceEntity) new ISerializer(FunctionReferenceEntity, ISerializer.bracketsWrapped)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
@@ -10187,27 +10188,27 @@ function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
InvariantTextEntity, InvariantTextEntity,
new GeneralSerializer(v => `${InvariantTextEntity.lookbehind}(${v})`, InvariantTextEntity, "", ", ", false, "", _ => "") new ISerializer(InvariantTextEntity, v => `${InvariantTextEntity.lookbehind}(${v})`, "", ", ", false, "", _ => "")
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
KeyBindingEntity, KeyBindingEntity,
new GeneralSerializer(bracketsWrapped, KeyBindingEntity) new ISerializer(KeyBindingEntity, ISerializer.bracketsWrapped)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
LinearColorEntity, LinearColorEntity,
new GeneralSerializer(bracketsWrapped, LinearColorEntity) new ISerializer(LinearColorEntity, ISerializer.bracketsWrapped)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
LocalizedTextEntity, LocalizedTextEntity,
new GeneralSerializer(v => `${LocalizedTextEntity.lookbehind}(${v})`, LocalizedTextEntity, "", ", ", false, "", _ => "") new ISerializer(LocalizedTextEntity, v => `${LocalizedTextEntity.lookbehind}(${v})`, "", ", ", false, "", _ => "")
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
MacroGraphReferenceEntity, MacroGraphReferenceEntity,
new GeneralSerializer(bracketsWrapped, MacroGraphReferenceEntity) new ISerializer(MacroGraphReferenceEntity, ISerializer.bracketsWrapped)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
@@ -10239,17 +10240,17 @@ function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
PinEntity, PinEntity,
new GeneralSerializer(v => `${PinEntity.lookbehind} (${v})`, PinEntity, "", ",", true) new ISerializer(PinEntity, v => `${PinEntity.lookbehind} (${v})`, "", ",", true)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
PinReferenceEntity, PinReferenceEntity,
new GeneralSerializer(v => v, PinReferenceEntity, "", " ", false, "", _ => "") new ISerializer(PinReferenceEntity, v => v, "", " ", false, "", _ => "")
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
TerminalTypeEntity, TerminalTypeEntity,
new GeneralSerializer(bracketsWrapped, TerminalTypeEntity) new ISerializer(TerminalTypeEntity, ISerializer.bracketsWrapped)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
@@ -10259,7 +10260,7 @@ function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
RotatorEntity, RotatorEntity,
new GeneralSerializer(bracketsWrapped, RotatorEntity) new ISerializer(RotatorEntity, ISerializer.bracketsWrapped)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
@@ -10305,22 +10306,22 @@ function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
UnknownKeysEntity, UnknownKeysEntity,
new GeneralSerializer((string, entity) => `${entity.lookbehind ?? ""}(${string})`, UnknownKeysEntity) new ISerializer(UnknownKeysEntity, (string, entity) => `${entity.lookbehind ?? ""}(${string})`)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
VariableReferenceEntity, VariableReferenceEntity,
new GeneralSerializer(bracketsWrapped, VariableReferenceEntity) new ISerializer(VariableReferenceEntity, ISerializer.bracketsWrapped)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
Vector2DEntity, Vector2DEntity,
new GeneralSerializer(bracketsWrapped, Vector2DEntity) new ISerializer(Vector2DEntity, ISerializer.bracketsWrapped)
); );
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
VectorEntity, VectorEntity,
new GeneralSerializer(bracketsWrapped, VectorEntity) new ISerializer(VectorEntity, ISerializer.bracketsWrapped)
); );
} }

File diff suppressed because one or more lines are too long

View File

@@ -19,6 +19,7 @@ import Utility from "../Utility.js"
* ignored?: Boolean, * ignored?: Boolean,
* serialized?: Boolean, * serialized?: Boolean,
* expected?: Boolean, * expected?: Boolean,
* inlined?: Boolean,
* predicate?: (value: AnyValue) => Boolean, * predicate?: (value: AnyValue) => Boolean,
* }} AttributeInformation * }} AttributeInformation
*/ */
@@ -40,7 +41,7 @@ export default class IEntity {
ignored: false, ignored: false,
serialized: false, serialized: false,
expected: false, expected: false,
inline: false, inlined: false,
} }
constructor(values = {}, suppressWarns = false) { constructor(values = {}, suppressWarns = false) {

View File

@@ -1,4 +1,4 @@
import GeneralSerializer from "./GeneralSerializer.js" import ISerializer from "./ISerializer.js"
/** /**
* @typedef {import("../entity/IEntity").AnyValue} AnyValue * @typedef {import("../entity/IEntity").AnyValue} AnyValue
@@ -7,9 +7,9 @@ import GeneralSerializer from "./GeneralSerializer.js"
/** /**
* @template {AnyValue} T * @template {AnyValue} T
* @extends {GeneralSerializer<T>} * @extends {ISerializer<T>}
*/ */
export default class CustomSerializer extends GeneralSerializer { export default class CustomSerializer extends ISerializer {
#objectWriter #objectWriter
@@ -18,7 +18,7 @@ export default class CustomSerializer extends GeneralSerializer {
* @param {AnyValueConstructor} entityType * @param {AnyValueConstructor} entityType
*/ */
constructor(objectWriter, entityType) { constructor(objectWriter, entityType) {
super(undefined, entityType) super(entityType)
this.#objectWriter = objectWriter this.#objectWriter = objectWriter
} }

View File

@@ -1,48 +0,0 @@
import Grammar from "./Grammar.js"
import ISerializer from "./ISerializer.js"
/**
* @typedef {import("../entity/IEntity").default} IEntity
* @typedef {import("../entity/IEntity").AnyValue} AnyValue
* @typedef {import("../entity/IEntity").AnyValueConstructor<*>} AnyValueConstructor
*/
/**
* @template {AnyValue} T
* @extends ISerializer<T>
*/
export default class GeneralSerializer extends ISerializer {
/**
* @param {(value: String, entity: T) => String} wrap
* @param {AnyValueConstructor} entityType
*/
constructor(wrap, entityType, attributePrefix, attributeSeparator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) {
wrap = wrap ?? (v => `(${v})`)
super(entityType, attributePrefix, attributeSeparator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter)
this.wrap = wrap
}
/**
* @param {String} value
* @returns {T}
*/
doRead(value) {
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}.`)
}
return parseResult.value
}
/**
* @param {T} entity
* @param {Boolean} insideString
* @returns {String}
*/
doWrite(entity, insideString = false) {
let result = this.wrap(super.doWrite(entity, insideString), entity)
return result
}
}

View File

@@ -1,3 +1,4 @@
import Grammar from "./Grammar.js"
import IndexedArray from "../entity/IndexedArray.js" import IndexedArray from "../entity/IndexedArray.js"
import SerializerFactory from "./SerializerFactory.js" import SerializerFactory from "./SerializerFactory.js"
import Utility from "../Utility.js" import Utility from "../Utility.js"
@@ -11,9 +12,15 @@ import Utility from "../Utility.js"
/** @template {AnyValue} T */ /** @template {AnyValue} T */
export default class ISerializer { export default class ISerializer {
/** @type {(v: String, entityType: AnyValueConstructor) => String} */
static bracketsWrapped = ((v, entityType) => `(${v})`)
/** @type {(v: String, entityType: AnyValueConstructor) => String} */
static notWrapped = ((v, entityType) => v)
/** @param {AnyValueConstructor} entityType */ /** @param {AnyValueConstructor} entityType */
constructor( constructor(
entityType, entityType,
wrap = ISerializer.bracketsWrapped,
attributePrefix = "", attributePrefix = "",
attributeSeparator = ",", attributeSeparator = ",",
trailingSeparator = false, trailingSeparator = false,
@@ -21,6 +28,7 @@ export default class ISerializer {
attributeKeyPrinter = k => k attributeKeyPrinter = k => k
) { ) {
this.entityType = entityType this.entityType = entityType
this.wrap = wrap
this.attributePrefix = attributePrefix this.attributePrefix = attributePrefix
this.attributeSeparator = attributeSeparator this.attributeSeparator = attributeSeparator
this.trailingSeparator = trailingSeparator this.trailingSeparator = trailingSeparator
@@ -47,7 +55,12 @@ export default class ISerializer {
* @returns {T} * @returns {T}
*/ */
doRead(value) { doRead(value) {
throw new Error("Not implemented") 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}.`)
}
return parseResult.value
} }
/** /**
@@ -56,7 +69,16 @@ export default class ISerializer {
* @param {Boolean} insideString * @param {Boolean} insideString
* @returns {String} * @returns {String}
*/ */
doWrite(entity, insideString) { doWrite(
entity,
insideString,
wrap = this.wrap,
attributePrefix = this.attributePrefix,
attributeSeparator = this.attributeSeparator,
trailingSeparator = this.trailingSeparator,
attributeValueConjunctionSign = this.attributeValueConjunctionSign,
attributeKeyPrinter = this.attributeKeyPrinter
) {
let result = "" let result = ""
const attributes = /** @type {EntityConstructor} */(entity.constructor).attributes ?? {} const attributes = /** @type {EntityConstructor} */(entity.constructor).attributes ?? {}
const keys = Utility.mergeArrays( const keys = Utility.mergeArrays(
@@ -67,23 +89,35 @@ export default class ISerializer {
const value = entity[key] const value = entity[key]
if (value !== undefined && this.showProperty(entity, key)) { if (value !== undefined && this.showProperty(entity, key)) {
const isSerialized = Utility.isSerialized(entity, key) const isSerialized = Utility.isSerialized(entity, key)
if (value instanceof IndexedArray) { result += (result.length ? attributeSeparator : "")
value.value.forEach((value, i) => if (attributes[key]?.inlined) {
result += (result.length ? this.attributeSeparator : "") result += this.doWrite(
+ this.attributePrefix value,
+ Utility.decodeKeyName(this.attributeKeyPrinter(key)) insideString,
+ `(${i})` ISerializer.notWrapped,
+ this.attributeValueConjunctionSign `${attributePrefix}${key}.`,
+ ( attributeSeparator,
isSerialized trailingSeparator,
? `"${this.doWriteValue(value, true)}"` attributeValueConjunctionSign,
: this.doWriteValue(value, insideString) attributeKeyPrinter
)
) )
continue continue
} }
result += (result.length ? this.attributeSeparator : "") if (value instanceof IndexedArray) {
+ this.attributePrefix result += this.doWrite(
value,
insideString,
wrap,
attributePrefix,
attributeSeparator,
trailingSeparator,
attributeValueConjunctionSign,
index => `(${index})`
)
continue
}
result +=
attributePrefix
+ Utility.decodeKeyName(this.attributeKeyPrinter(key)) + Utility.decodeKeyName(this.attributeKeyPrinter(key))
+ this.attributeValueConjunctionSign + this.attributeValueConjunctionSign
+ ( + (
@@ -97,7 +131,7 @@ export default class ISerializer {
// append separator at the end if asked and there was printed content // append separator at the end if asked and there was printed content
result += this.attributeSeparator result += this.attributeSeparator
} }
return result return wrap(result, entity.constructor)
} }
/** /**

View File

@@ -7,7 +7,7 @@ import SerializerFactory from "./SerializerFactory.js"
export default class ObjectSerializer extends ISerializer { export default class ObjectSerializer extends ISerializer {
constructor() { constructor() {
super(ObjectEntity, " ", "\n", false) super(ObjectEntity, undefined, " ", "\n", false)
} }
showProperty(entity, key) { showProperty(entity, key) {
@@ -43,10 +43,24 @@ export default class ObjectSerializer extends ISerializer {
} }
/** /**
* @protected
* @param {ObjectEntity} entity * @param {ObjectEntity} entity
* @param {Boolean} insideString * @param {Boolean} insideString
* @returns {String}
*/ */
doWrite(entity, insideString) { doWrite(
entity,
insideString,
wrap = this.wrap,
attributePrefix = this.attributePrefix,
attributeSeparator = this.attributeSeparator,
trailingSeparator = this.trailingSeparator,
attributeValueConjunctionSign = this.attributeValueConjunctionSign,
attributeKeyPrinter = this.attributeKeyPrinter
) {
if (!(entity instanceof ObjectEntity)) {
return super.doWrite(entity, insideString)
}
let result = `Begin Object Class=${entity.Class.path} Name=${this.doWriteValue(entity.Name, insideString)}\n` let result = `Begin Object Class=${entity.Class.path} Name=${this.doWriteValue(entity.Name, insideString)}\n`
+ super.doWrite(entity, insideString) + super.doWrite(entity, insideString)
+ entity.CustomProperties.map(pin => + entity.CustomProperties.map(pin =>

View File

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

View File

@@ -2,12 +2,12 @@ import ByteEntity from "../entity/ByteEntity.js"
import CustomSerializer from "./CustomSerializer.js" import CustomSerializer from "./CustomSerializer.js"
import EnumEntity from "../entity/EnumEntity.js" import EnumEntity from "../entity/EnumEntity.js"
import FunctionReferenceEntity from "../entity/FunctionReferenceEntity.js" import FunctionReferenceEntity from "../entity/FunctionReferenceEntity.js"
import GeneralSerializer from "./GeneralSerializer.js"
import GuidEntity from "../entity/GuidEntity.js" import GuidEntity from "../entity/GuidEntity.js"
import IdentifierEntity from "../entity/IdentifierEntity.js" import IdentifierEntity from "../entity/IdentifierEntity.js"
import Integer64Entity from "../entity/Integer64Entity.js" import Integer64Entity from "../entity/Integer64Entity.js"
import IntegerEntity from "../entity/IntegerEntity.js" import IntegerEntity from "../entity/IntegerEntity.js"
import InvariantTextEntity from "../entity/InvariantTextEntity.js" import InvariantTextEntity from "../entity/InvariantTextEntity.js"
import ISerializer from "./ISerializer.js"
import KeyBindingEntity from "../entity/KeyBindingEntity.js" import KeyBindingEntity from "../entity/KeyBindingEntity.js"
import LinearColorEntity from "../entity/LinearColorEntity.js" import LinearColorEntity from "../entity/LinearColorEntity.js"
import LocalizedTextEntity from "../entity/LocalizedTextEntity.js" import LocalizedTextEntity from "../entity/LocalizedTextEntity.js"
@@ -40,8 +40,6 @@ import VectorEntity from "../entity/VectorEntity.js"
export default function initializeSerializerFactory() { export default function initializeSerializerFactory() {
const bracketsWrapped = v => `(${v})`
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
null, null,
new CustomSerializer( new CustomSerializer(
@@ -98,7 +96,7 @@ export default function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
FunctionReferenceEntity, FunctionReferenceEntity,
new GeneralSerializer(bracketsWrapped, FunctionReferenceEntity) new ISerializer(FunctionReferenceEntity, ISerializer.bracketsWrapped)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
@@ -123,27 +121,27 @@ export default function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
InvariantTextEntity, InvariantTextEntity,
new GeneralSerializer(v => `${InvariantTextEntity.lookbehind}(${v})`, InvariantTextEntity, "", ", ", false, "", _ => "") new ISerializer(InvariantTextEntity, v => `${InvariantTextEntity.lookbehind}(${v})`, "", ", ", false, "", _ => "")
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
KeyBindingEntity, KeyBindingEntity,
new GeneralSerializer(bracketsWrapped, KeyBindingEntity) new ISerializer(KeyBindingEntity, ISerializer.bracketsWrapped)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
LinearColorEntity, LinearColorEntity,
new GeneralSerializer(bracketsWrapped, LinearColorEntity) new ISerializer(LinearColorEntity, ISerializer.bracketsWrapped)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
LocalizedTextEntity, LocalizedTextEntity,
new GeneralSerializer(v => `${LocalizedTextEntity.lookbehind}(${v})`, LocalizedTextEntity, "", ", ", false, "", _ => "") new ISerializer(LocalizedTextEntity, v => `${LocalizedTextEntity.lookbehind}(${v})`, "", ", ", false, "", _ => "")
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
MacroGraphReferenceEntity, MacroGraphReferenceEntity,
new GeneralSerializer(bracketsWrapped, MacroGraphReferenceEntity) new ISerializer(MacroGraphReferenceEntity, ISerializer.bracketsWrapped)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
@@ -175,17 +173,17 @@ export default function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
PinEntity, PinEntity,
new GeneralSerializer(v => `${PinEntity.lookbehind} (${v})`, PinEntity, "", ",", true) new ISerializer(PinEntity, v => `${PinEntity.lookbehind} (${v})`, "", ",", true)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
PinReferenceEntity, PinReferenceEntity,
new GeneralSerializer(v => v, PinReferenceEntity, "", " ", false, "", _ => "") new ISerializer(PinReferenceEntity, v => v, "", " ", false, "", _ => "")
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
TerminalTypeEntity, TerminalTypeEntity,
new GeneralSerializer(bracketsWrapped, TerminalTypeEntity) new ISerializer(TerminalTypeEntity, ISerializer.bracketsWrapped)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
@@ -195,7 +193,7 @@ export default function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
RotatorEntity, RotatorEntity,
new GeneralSerializer(bracketsWrapped, RotatorEntity) new ISerializer(RotatorEntity, ISerializer.bracketsWrapped)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
@@ -241,21 +239,21 @@ export default function initializeSerializerFactory() {
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
UnknownKeysEntity, UnknownKeysEntity,
new GeneralSerializer((string, entity) => `${entity.lookbehind ?? ""}(${string})`, UnknownKeysEntity) new ISerializer(UnknownKeysEntity, (string, entity) => `${entity.lookbehind ?? ""}(${string})`)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
VariableReferenceEntity, VariableReferenceEntity,
new GeneralSerializer(bracketsWrapped, VariableReferenceEntity) new ISerializer(VariableReferenceEntity, ISerializer.bracketsWrapped)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
Vector2DEntity, Vector2DEntity,
new GeneralSerializer(bracketsWrapped, Vector2DEntity) new ISerializer(Vector2DEntity, ISerializer.bracketsWrapped)
) )
SerializerFactory.registerSerializer( SerializerFactory.registerSerializer(
VectorEntity, VectorEntity,
new GeneralSerializer(bracketsWrapped, VectorEntity) new ISerializer(VectorEntity, ISerializer.bracketsWrapped)
) )
} }