mirror of
https://github.com/barsdeveloper/ueblueprint.git
synced 2026-02-03 23:55:04 +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:
@@ -6,59 +6,65 @@ import SimpleObject from "./SimpleObject"
|
||||
export default class ComplexEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
alpha: 32,
|
||||
alpha: {
|
||||
default: 32,
|
||||
},
|
||||
bravo: {
|
||||
type: Number,
|
||||
value: 78,
|
||||
default: 78,
|
||||
},
|
||||
charlie: {
|
||||
type: String,
|
||||
value: "Charlie",
|
||||
default: "Charlie",
|
||||
},
|
||||
delta: {
|
||||
type: String,
|
||||
value: null,
|
||||
default: null,
|
||||
},
|
||||
echo: {
|
||||
default: "echo",
|
||||
},
|
||||
echo: "echo",
|
||||
foxtrot: {
|
||||
value: false,
|
||||
default: false,
|
||||
},
|
||||
golf: {
|
||||
type: Array,
|
||||
},
|
||||
hotel: {
|
||||
type: Array,
|
||||
value: null,
|
||||
default: null,
|
||||
},
|
||||
india: {
|
||||
type: [Number]
|
||||
type: [Number],
|
||||
},
|
||||
juliett: {
|
||||
type: [String],
|
||||
value: ["a", "b", "c", "d", "e"],
|
||||
default: ["a", "b", "c", "d", "e"],
|
||||
},
|
||||
kilo: {
|
||||
type: [Boolean],
|
||||
value: () => [true, false, false, true, true],
|
||||
default: () => [true, false, false, true, true],
|
||||
},
|
||||
lima: {
|
||||
type: String,
|
||||
value: "Foo",
|
||||
default: "Foo",
|
||||
showDefault: false,
|
||||
},
|
||||
mike: {
|
||||
type: new UnionType(Number, String, Array),
|
||||
value: "Bar",
|
||||
default: "Bar",
|
||||
},
|
||||
november: {
|
||||
type: new UnionType(Number, String, Array),
|
||||
},
|
||||
oscar: {
|
||||
type: SimpleObject
|
||||
type: SimpleObject,
|
||||
},
|
||||
papa: {
|
||||
default: () => new SimpleObject(12, 13),
|
||||
},
|
||||
papa: () => new SimpleObject(12, 13),
|
||||
quebec: {
|
||||
value: 0, // will assign undefined because it does not satisfy the predicate
|
||||
default: 0, // will assign undefined because it does not satisfy the predicate
|
||||
predicate: v => v >= 1 && v <= 10,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -3,14 +3,30 @@ import IEntity from "../../js/entity/IEntity"
|
||||
export default class SimpleEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
someNumber: 567,
|
||||
someString: "alpha",
|
||||
someString2: "beta",
|
||||
someBoolean: true,
|
||||
someBoolean2: false,
|
||||
someObjectString: new String("gamma"),
|
||||
someArray: [400, 500, 600, 700, 800],
|
||||
someSet: new Set([10, 20, 30, 40, 50, 60, 70]),
|
||||
someNumber: {
|
||||
default: 567,
|
||||
},
|
||||
someString: {
|
||||
default: "alpha",
|
||||
},
|
||||
someString2: {
|
||||
default: "beta",
|
||||
},
|
||||
someBoolean: {
|
||||
default: true,
|
||||
},
|
||||
someBoolean2: {
|
||||
default: false,
|
||||
},
|
||||
someObjectString: {
|
||||
default: new String("gamma"),
|
||||
},
|
||||
someArray: {
|
||||
default: [400, 500, 600, 700, 800],
|
||||
},
|
||||
someSet: {
|
||||
default: new Set([10, 20, 30, 40, 50, 60, 70]),
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
10718
dist/ueblueprint.js
vendored
10718
dist/ueblueprint.js
vendored
File diff suppressed because one or more lines are too long
8
dist/ueblueprint.min.js
vendored
8
dist/ueblueprint.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -51,6 +51,15 @@ export default class Configuration {
|
||||
static linkCurveHeight = 15 // px
|
||||
static linkCurveWidth = 80 // px
|
||||
static linkMinWidth = 100 // px
|
||||
static nameRegexSpaceReplacement = new RegExp(
|
||||
"^K2(?:[Nn]ode)?_"
|
||||
+ "|(?<=[a-z])(?=[A-Z0-9])" // ("Alpha2", "AlphaBravo") => ("Alpha 2", "Alpha Bravo")
|
||||
+ "|(?<=[A-Z])(?=[A-Z][a-z]|[0-9])" // ("ALPHABravo", "ALPHA2") => ("ALPHA Bravo", "ALPHA 2")
|
||||
+ "|(?<=[014-9]|[23](?!D(?:[^a-z]|$)))(?=[a-zA-Z])" // ("3Times", "3D", "3Delta") => ("3 Times", "3D", "3 Delta")
|
||||
+ "|\\s*_+\\s*" // "Alpha__Bravo" => "Alpha Bravo"
|
||||
+ "|\\s{2,}",
|
||||
"g"
|
||||
)
|
||||
/**
|
||||
* @param {Number} start
|
||||
* @param {Number} c1
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import SubAttributesDeclaration from "./entity/SubObject.js"
|
||||
import Configuration from "./Configuration.js"
|
||||
import ComputedType from "./entity/ComputedType.js"
|
||||
import UnionType from "./entity/UnionType.js"
|
||||
|
||||
/**
|
||||
@@ -48,10 +49,7 @@ export default class Utility {
|
||||
/** @param {HTMLElement} element */
|
||||
static getScale(element) {
|
||||
// @ts-expect-error
|
||||
const scale = element.blueprint
|
||||
// @ts-expect-error
|
||||
? element.blueprint.getScale()
|
||||
: getComputedStyle(element).getPropertyValue("--ueb-scale")
|
||||
const scale = element.blueprint?.getScale() ?? getComputedStyle(element).getPropertyValue("--ueb-scale")
|
||||
return scale != "" ? parseFloat(scale) : 1
|
||||
}
|
||||
|
||||
@@ -118,13 +116,13 @@ export default class Utility {
|
||||
|
||||
/**
|
||||
* @param {IEntity} entity
|
||||
* @param {String[]} keys
|
||||
* @param {String} key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
static isSerialized(
|
||||
entity,
|
||||
keys,
|
||||
attribute = Utility.objectGet(/** @type {EntityConstructor} */(entity.constructor).attributes, keys)
|
||||
key,
|
||||
attribute = /** @type {EntityConstructor} */(entity.constructor).attributes?.[key]
|
||||
) {
|
||||
if (attribute?.constructor === Object) {
|
||||
return /** @type {TypeInformation} */(attribute).serialized
|
||||
@@ -140,9 +138,6 @@ export default class Utility {
|
||||
if (!(keys instanceof Array)) {
|
||||
throw new TypeError("UEBlueprint: Expected keys to be an array")
|
||||
}
|
||||
if (target instanceof SubAttributesDeclaration) {
|
||||
target = target.attributes
|
||||
}
|
||||
if (keys.length == 0 || !(keys[0] in target) || target[keys[0]] === undefined) {
|
||||
return defaultValue
|
||||
}
|
||||
@@ -181,7 +176,10 @@ export default class Utility {
|
||||
*/
|
||||
static equals(a, b) {
|
||||
// Here we cannot check both instanceof IEntity because this would introduce a circular include dependency
|
||||
if (/** @type {IEntity?} */(a)?.equals && /** @type {IEntity?} */(b)?.equals) {
|
||||
if (
|
||||
/** @type {IEntity?} */(a)?.equals
|
||||
&& /** @type {IEntity?} */(b)?.equals
|
||||
) {
|
||||
return /** @type {IEntity} */(a).equals(/** @type {IEntity} */(b))
|
||||
}
|
||||
a = Utility.sanitize(a)
|
||||
@@ -224,6 +222,12 @@ export default class Utility {
|
||||
|
||||
/** @param {AnyValue} value */
|
||||
static sanitize(value, targetType = /** @type {AnyValueConstructor} */(value?.constructor)) {
|
||||
if (targetType instanceof Array) {
|
||||
targetType = targetType[0]
|
||||
}
|
||||
if (targetType instanceof ComputedType) {
|
||||
return value // The type is computed, can't say anything about it
|
||||
}
|
||||
if (targetType instanceof UnionType) {
|
||||
let type = targetType.types.find(t => Utility.isValueOfType(value, t, false))
|
||||
if (!type) {
|
||||
@@ -332,16 +336,23 @@ export default class Utility {
|
||||
// Remove leading b (for boolean values) or newlines
|
||||
.replace(/^\s*b/, "")
|
||||
// Insert a space where needed, possibly removing unnecessary elading characters
|
||||
.replaceAll(
|
||||
/^K2(?:Node|node)?_|(?<=[a-z])(?=[A-Z0-9])|(?<=[A-Z])(?=[A-Z][a-z]|[0-9])|(?<=[014-9]|(?:2|3)(?!D(?:[^a-z]|$)))(?=[a-zA-Z])|\s*_+\s*|\s{2,}/g,
|
||||
" "
|
||||
)
|
||||
.replaceAll(Configuration.nameRegexSpaceReplacement, " ")
|
||||
.split(" ")
|
||||
.map(v => Utility.capitalFirstLetter(v))
|
||||
.join(" ")
|
||||
.trim()
|
||||
}
|
||||
|
||||
/** @param {String} value */
|
||||
static encodeKeyName(value) {
|
||||
return value.replaceAll(".", "$")
|
||||
}
|
||||
|
||||
/** @param {String} value */
|
||||
static decodeKeyName(value) {
|
||||
return value.replaceAll("$", ".")
|
||||
}
|
||||
|
||||
/** @param {String} value */
|
||||
static getIdFromReference(value) {
|
||||
return value
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import BoolPinTemplate from "../template/pin/BoolPinTemplate.js"
|
||||
import ElementFactory from "./ElementFactory.js"
|
||||
import ExecPinTemplate from "../template/pin/ExecPinTemplate.js"
|
||||
import Grammar from "../serialization/Grammar.js"
|
||||
import GuidEntity from "../entity/GuidEntity.js"
|
||||
import IElement from "./IElement.js"
|
||||
import Int64PinTemplate from "../template/pin/Int64PinTemplate.js"
|
||||
import IntPinTemplate from "../template/pin/IntPinTemplate.js"
|
||||
import ISerializer from "../serialization/ISerializer.js"
|
||||
import LinearColorEntity from "../entity/LinearColorEntity.js"
|
||||
import LinearColorPinTemplate from "../template/pin/LinearColorPinTemplate.js"
|
||||
import NamePinTemplate from "../template/pin/NamePinTemplate.js"
|
||||
@@ -27,6 +27,10 @@ import VectorPinTemplate from "../template/pin/VectorPinTemplate.js"
|
||||
* @typedef {import("lit").CSSResult} CSSResult
|
||||
* @typedef {typeof PinElement} PinElementConstructor
|
||||
*/
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {import("parsimmon").Success<T>} Success
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {AnyValue} T
|
||||
@@ -54,7 +58,7 @@ export default class PinElement extends IElement {
|
||||
type: GuidEntity,
|
||||
converter: {
|
||||
fromAttribute: (value, type) => value
|
||||
? ISerializer.grammar.Guid.parse(value).value
|
||||
? /** @type {Success<GuidEntity>} */(Grammar.guidEntity.parse(value)).value
|
||||
: null,
|
||||
toAttribute: (value, type) => value?.toString(),
|
||||
},
|
||||
@@ -75,7 +79,7 @@ export default class PinElement extends IElement {
|
||||
type: LinearColorEntity,
|
||||
converter: {
|
||||
fromAttribute: (value, type) => value
|
||||
? ISerializer.grammar.LinearColorFromAnyColor.parse(value).value
|
||||
? /** @type {Success<LinearColorEntity>} */(Grammar.linearColorFromAnyFormat.parse(value)).value
|
||||
: null,
|
||||
toAttribute: (value, type) => value ? Utility.printLinearColor(value) : null,
|
||||
},
|
||||
@@ -107,7 +111,7 @@ export default class PinElement extends IElement {
|
||||
* @return {new () => PinTemplate}
|
||||
*/
|
||||
static getTypeTemplate(pinEntity) {
|
||||
if (pinEntity.PinType.bIsReference && !pinEntity.PinType.bIsConst) {
|
||||
if (pinEntity.PinType$bIsReference && !pinEntity.PinType$bIsConst) {
|
||||
return PinElement.#inputPinTemplates["MUTABLE_REFERENCE"]
|
||||
}
|
||||
if (pinEntity.getType() === "exec") {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/** @typedef {import("./IEntity").default} IEntity */
|
||||
|
||||
export default class CalculatedType {
|
||||
export default class ComputedType {
|
||||
|
||||
#f
|
||||
|
||||
@@ -10,7 +10,7 @@ export default class CalculatedType {
|
||||
}
|
||||
|
||||
/** @param {IEntity} entity */
|
||||
calculate(entity) {
|
||||
compute(entity) {
|
||||
return this.#f(entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ export default class FormatTextEntity extends IEntity {
|
||||
static lookbehind = "LOCGEN_FORMAT_NAMED"
|
||||
static attributes = {
|
||||
value: {
|
||||
type: [new UnionType(LocalizedTextEntity, InvariantTextEntity, FormatTextEntity)]
|
||||
type: [new UnionType(LocalizedTextEntity, InvariantTextEntity, FormatTextEntity)],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -27,5 +27,6 @@ export default class FunctionReferenceEntity extends IEntity {
|
||||
super(values)
|
||||
/** @type {ObjectReferenceEntity} */ this.MemberParent
|
||||
/** @type {String} */ this.MemberName
|
||||
/** @type {GuidEntity} */ this.MemberGuid
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ import IEntity from "./IEntity.js"
|
||||
export default class GuidEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
value: "",
|
||||
value: {
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import ComputedType from "./ComputedType.js"
|
||||
import SerializerFactory from "../serialization/SerializerFactory.js"
|
||||
import SubAttributesDeclaration from "./SubObject.js"
|
||||
import UnionType from "./UnionType.js"
|
||||
import Utility from "../Utility.js"
|
||||
|
||||
/**
|
||||
* @typedef {(entity: IEntity) => AnyValue} ValueSupplier
|
||||
* @typedef {(entity: IEntity) => AnyValueConstructor<AnyValue>} TypeSupplier
|
||||
* @typedef {IEntity | String | Number | BigInt | Boolean} AnySimpleValue
|
||||
* @typedef {AnySimpleValue | AnySimpleValue[]} AnyValue
|
||||
* @typedef {{
|
||||
* [key: String]: AttributeInformation | AnyValue | SubAttributesDeclaration
|
||||
* [key: String]: AttributeInformation
|
||||
* }} AttributeDeclarations
|
||||
* @typedef {typeof IEntity} EntityConstructor
|
||||
* @typedef {{
|
||||
* type?: AnyValueConstructor<AnyValue> | AnyValueConstructor<AnyValue>[] | UnionType | TypeSupplier,
|
||||
* value?: AnyValue | ValueSupplier,
|
||||
* type?: AnyValueConstructor<AnyValue> | AnyValueConstructor<AnyValue>[] | UnionType | ComputedType,
|
||||
* default?: AnyValue | ValueSupplier,
|
||||
* showDefault?: Boolean,
|
||||
* nullable?: Boolean,
|
||||
* ignored?: Boolean,
|
||||
@@ -32,6 +31,7 @@ import Utility from "../Utility.js"
|
||||
|
||||
export default class IEntity {
|
||||
|
||||
static lookbehind = ""
|
||||
/** @type {AttributeDeclarations} */
|
||||
static attributes = {}
|
||||
static defaultAttribute = {
|
||||
@@ -43,138 +43,6 @@ export default class IEntity {
|
||||
}
|
||||
|
||||
constructor(values = {}, suppressWarns = false) {
|
||||
/**
|
||||
* @param {Object} target
|
||||
* @param {Object} attributes
|
||||
* @param {Object} values
|
||||
* @param {String} prefix
|
||||
*/
|
||||
const defineAllAttributes = (target, attributes, values = {}, prefix = "") => {
|
||||
const valuesNames = Object.keys(values)
|
||||
const attributesNames = Object.keys(attributes)
|
||||
const allAttributesNames = Utility.mergeArrays(attributesNames, valuesNames)
|
||||
for (let attributeName of allAttributesNames) {
|
||||
let value = Utility.objectGet(values, [attributeName])
|
||||
/** @type {AttributeInformation} */
|
||||
let attribute = attributes[attributeName]
|
||||
|
||||
if (attribute instanceof SubAttributesDeclaration) {
|
||||
target[attributeName] = {}
|
||||
defineAllAttributes(
|
||||
target[attributeName],
|
||||
attribute.attributes,
|
||||
values[attributeName],
|
||||
attributeName + "."
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!suppressWarns) {
|
||||
if (!(attributeName in attributes)) {
|
||||
console.warn(
|
||||
`UEBlueprint: Attribute ${prefix}${attributeName} in the serialized data is not defined in `
|
||||
+ `${this.constructor.name}.attributes`
|
||||
)
|
||||
} else if (
|
||||
valuesNames.length > 0
|
||||
&& !(attributeName in values)
|
||||
&& !(!attribute.showDefault || attribute.ignored)
|
||||
) {
|
||||
console.warn(
|
||||
`UEBlueprint: ${this.constructor.name} will add attribute ${prefix}${attributeName} not `
|
||||
+ "defined in the serialized data"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!attribute) {
|
||||
// Remember attributeName can come from the values and be not defined in the attributes
|
||||
target[attributeName] = value
|
||||
continue
|
||||
}
|
||||
|
||||
let defaultValue = attribute.value
|
||||
let defaultType = attribute.type
|
||||
if (attribute.serialized && defaultType instanceof Function) {
|
||||
// If the attribute is serialized, the type must contain a function providing the type
|
||||
defaultType = /** @type {TypeSupplier} */(defaultType)(this)
|
||||
}
|
||||
if (defaultType instanceof Array) {
|
||||
defaultType = Array
|
||||
}
|
||||
if (defaultValue instanceof Function) {
|
||||
defaultValue = defaultValue(this)
|
||||
}
|
||||
if (defaultType === undefined) {
|
||||
defaultType = Utility.getType(defaultValue)
|
||||
}
|
||||
const assignAttribute = !attribute.predicate
|
||||
? v => target[attributeName] = v
|
||||
: v => {
|
||||
Object.defineProperties(target, {
|
||||
["#" + attributeName]: {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
},
|
||||
[attributeName]: {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return this["#" + attributeName]
|
||||
},
|
||||
set(v) {
|
||||
if (!attribute.predicate?.(v)) {
|
||||
console.warn(
|
||||
`UEBlueprint: Tried to assign attribute ${prefix}${attributeName} to `
|
||||
+ `${this.constructor.name} not satisfying the predicate`
|
||||
)
|
||||
return
|
||||
}
|
||||
this["#" + attributeName] = v
|
||||
}
|
||||
},
|
||||
})
|
||||
this[attributeName] = v
|
||||
}
|
||||
|
||||
if (value !== undefined) {
|
||||
// Remember value can still be null
|
||||
if (value?.constructor === String && attribute.serialized && defaultType !== String) {
|
||||
value = SerializerFactory
|
||||
.getSerializer(/** @type {AnyValueConstructor<*>} */(defaultType))
|
||||
.deserialize(/** @type {String} */(value))
|
||||
}
|
||||
assignAttribute(Utility.sanitize(value, /** @type {AnyValueConstructor<*>} */(defaultType)))
|
||||
continue // We have a value, need nothing more
|
||||
}
|
||||
if (defaultType instanceof UnionType) {
|
||||
if (defaultValue != undefined) {
|
||||
defaultType = defaultType.types.find(
|
||||
type => defaultValue instanceof type || defaultValue.constructor == type
|
||||
) ?? defaultType.getFirstType()
|
||||
} else {
|
||||
defaultType = defaultType.getFirstType()
|
||||
}
|
||||
}
|
||||
if (defaultValue === undefined) {
|
||||
defaultValue = Utility.sanitize(new /** @type {AnyValueConstructor<*>} */(defaultType)())
|
||||
}
|
||||
if (!attribute.showDefault) {
|
||||
assignAttribute(undefined) // Declare undefined to preserve the order of attributes
|
||||
continue
|
||||
}
|
||||
if (attribute.serialized) {
|
||||
if (defaultType !== String && defaultValue.constructor === String) {
|
||||
defaultValue = SerializerFactory
|
||||
.getSerializer(/** @type {AnyValueConstructor<*>} */(defaultType))
|
||||
.deserialize(defaultValue)
|
||||
}
|
||||
}
|
||||
assignAttribute(Utility.sanitize(
|
||||
/** @type {AnyValue} */(defaultValue),
|
||||
/** @type {AnyValueConstructor<AnyValue>} */(defaultType)
|
||||
))
|
||||
}
|
||||
}
|
||||
const attributes = /** @type {typeof IEntity} */(this.constructor).attributes
|
||||
if (values.constructor !== Object && Object.keys(attributes).length === 1) {
|
||||
// Where there is just one attribute, option can be the value of that attribute
|
||||
@@ -182,39 +50,141 @@ export default class IEntity {
|
||||
[Object.keys(attributes)[0]]: values
|
||||
}
|
||||
}
|
||||
defineAllAttributes(this, attributes, values)
|
||||
const valuesNames = Object.keys(values)
|
||||
const attributesNames = Object.keys(attributes)
|
||||
const allAttributesNames = Utility.mergeArrays(attributesNames, valuesNames)
|
||||
for (let attributeName of allAttributesNames) {
|
||||
let value = values[attributeName]
|
||||
let attribute = /** @type {AttributeInformation} */(attributes[attributeName])
|
||||
|
||||
if (!suppressWarns) {
|
||||
if (!(attributeName in attributes)) {
|
||||
console.warn(
|
||||
`UEBlueprint: Attribute ${attributeName} in the serialized data is not defined in `
|
||||
+ `${this.constructor.name}.attributes`
|
||||
)
|
||||
} else if (
|
||||
valuesNames.length > 0
|
||||
&& !(attributeName in values)
|
||||
&& !(!attribute.showDefault || attribute.ignored)
|
||||
) {
|
||||
console.warn(
|
||||
`UEBlueprint: ${this.constructor.name} will add attribute ${attributeName} not `
|
||||
+ "defined in the serialized data"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!attribute) {
|
||||
// Remember attributeName can come from the values and be not defined in the attributes
|
||||
// In that case just assign it and skip the rest
|
||||
this[attributeName] = value
|
||||
continue
|
||||
}
|
||||
|
||||
let defaultValue = attribute.default
|
||||
let defaultType = attribute.type
|
||||
if (defaultType instanceof ComputedType) {
|
||||
defaultType = defaultType.compute(this)
|
||||
}
|
||||
if (defaultType instanceof Array) {
|
||||
defaultType = Array
|
||||
}
|
||||
if (defaultValue instanceof Function) {
|
||||
defaultValue = defaultValue(this)
|
||||
}
|
||||
if (defaultType === undefined) {
|
||||
defaultType = Utility.getType(defaultValue)
|
||||
}
|
||||
const assignAttribute = !attribute.predicate
|
||||
? v => this[attributeName] = v
|
||||
: v => {
|
||||
Object.defineProperties(this, {
|
||||
["#" + attributeName]: {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
},
|
||||
[attributeName]: {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return this["#" + attributeName]
|
||||
},
|
||||
set(v) {
|
||||
if (!attribute.predicate?.(v)) {
|
||||
console.warn(
|
||||
`UEBlueprint: Tried to assign attribute ${attributeName} to `
|
||||
+ `${this.constructor.name} not satisfying the predicate`
|
||||
)
|
||||
return
|
||||
}
|
||||
this["#" + attributeName] = v
|
||||
}
|
||||
},
|
||||
})
|
||||
this[attributeName] = v
|
||||
}
|
||||
|
||||
if (value !== undefined) {
|
||||
// Remember value can still be null
|
||||
if (value?.constructor === String && attribute.serialized && defaultType !== String) {
|
||||
value = SerializerFactory
|
||||
.getSerializer(/** @type {AnyValueConstructor<*>} */(defaultType))
|
||||
.deserialize(/** @type {String} */(value))
|
||||
}
|
||||
assignAttribute(Utility.sanitize(value, /** @type {AnyValueConstructor<*>} */(defaultType)))
|
||||
continue // We have a value, need nothing more
|
||||
}
|
||||
if (defaultType instanceof UnionType) {
|
||||
if (defaultValue != undefined) {
|
||||
defaultType = defaultType.types.find(
|
||||
type => defaultValue instanceof type || defaultValue.constructor == type
|
||||
) ?? defaultType.getFirstType()
|
||||
} else {
|
||||
defaultType = defaultType.getFirstType()
|
||||
}
|
||||
}
|
||||
if (defaultValue === undefined) {
|
||||
defaultValue = Utility.sanitize(new /** @type {AnyValueConstructor<*>} */(defaultType)())
|
||||
}
|
||||
if (!attribute.showDefault) {
|
||||
assignAttribute(undefined) // Declare undefined to preserve the order of attributes
|
||||
continue
|
||||
}
|
||||
if (attribute.serialized) {
|
||||
if (defaultType !== String && defaultValue.constructor === String) {
|
||||
defaultValue = SerializerFactory
|
||||
.getSerializer(/** @type {AnyValueConstructor<*>} */(defaultType))
|
||||
.deserialize(defaultValue)
|
||||
}
|
||||
}
|
||||
assignAttribute(Utility.sanitize(
|
||||
/** @type {AnyValue} */(defaultValue),
|
||||
/** @type {AnyValueConstructor<AnyValue>} */(defaultType)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {AttributeDeclarations} attributes */
|
||||
static cleanupAttributes(attributes, prefix = "") {
|
||||
for (const attributeName in attributes) {
|
||||
if (attributes[attributeName] instanceof SubAttributesDeclaration) {
|
||||
this.cleanupAttributes(
|
||||
/** @type {SubAttributesDeclaration} */(attributes[attributeName]).attributes,
|
||||
prefix + "." + attributeName
|
||||
)
|
||||
continue
|
||||
}
|
||||
if (attributes[attributeName].constructor !== Object) {
|
||||
attributes[attributeName] = {
|
||||
value: attributes[attributeName],
|
||||
}
|
||||
}
|
||||
const attribute = /** @type {AttributeInformation} */(attributes[attributeName])
|
||||
if (attribute.type === undefined && !(attribute.value instanceof Function)) {
|
||||
attribute.type = Utility.getType(attribute.value)
|
||||
if (attribute.type === undefined && !(attribute.default instanceof Function)) {
|
||||
attribute.type = Utility.getType(attribute.default)
|
||||
}
|
||||
attributes[attributeName] = {
|
||||
...IEntity.defaultAttribute,
|
||||
...attribute,
|
||||
}
|
||||
if (attribute.value === undefined && attribute.type === undefined) {
|
||||
throw new Error(
|
||||
`UEBlueprint: Expected either "type" or "value" property in ${this.name} attribute ${prefix}`
|
||||
+ attributeName
|
||||
)
|
||||
if (attribute.default === undefined) {
|
||||
if (attribute.type === undefined) {
|
||||
throw new Error(
|
||||
`UEBlueprint: Expected either "type" or "value" property in ${this.name} attribute ${prefix}`
|
||||
+ attributeName
|
||||
)
|
||||
}
|
||||
attribute[attributeName] = Utility.sanitize(undefined, attribute.type)
|
||||
}
|
||||
if (attribute.value === null) {
|
||||
if (attribute.default === null) {
|
||||
attributes[attributeName].nullable = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ import IEntity from "./IEntity.js"
|
||||
export default class IdentifierEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
value: "",
|
||||
value: {
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -5,7 +5,7 @@ export default class Integer64Entity extends IEntity {
|
||||
static attributes = {
|
||||
...super.attributes,
|
||||
value: {
|
||||
value: 0n,
|
||||
default: 0n,
|
||||
predicate: v => v >= -(1n << 63n) && v < 1n << 63n,
|
||||
},
|
||||
}
|
||||
@@ -14,9 +14,10 @@ export default class Integer64Entity extends IEntity {
|
||||
this.cleanupAttributes(this.attributes)
|
||||
}
|
||||
|
||||
/** @param {BigInt | Number} value */
|
||||
constructor(value = 0) {
|
||||
super(value)
|
||||
/** @type {Number} */ this.value
|
||||
/** @type {BigInt | Number} */ this.value
|
||||
}
|
||||
|
||||
valueOf() {
|
||||
|
||||
@@ -5,7 +5,7 @@ export default class IntegerEntity extends IEntity {
|
||||
static attributes = {
|
||||
...super.attributes,
|
||||
value: {
|
||||
value: 0,
|
||||
default: 0,
|
||||
predicate: v => v % 1 == 0 && v > 1 << 31 && v < -(1 << 31),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ export default class InvariantTextEntity extends IEntity {
|
||||
|
||||
static lookbehind = "INVTEXT"
|
||||
static attributes = {
|
||||
value: "",
|
||||
value: {
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -4,13 +4,23 @@ import IEntity from "./IEntity.js"
|
||||
export default class KeyBindingEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
ActionName: "",
|
||||
bShift: false,
|
||||
bCtrl: false,
|
||||
bAlt: false,
|
||||
bCmd: false,
|
||||
ActionName: {
|
||||
default: "",
|
||||
},
|
||||
bShift: {
|
||||
default: false,
|
||||
},
|
||||
bCtrl: {
|
||||
default: false,
|
||||
},
|
||||
bAlt: {
|
||||
default: false,
|
||||
},
|
||||
bCmd: {
|
||||
default: false,
|
||||
},
|
||||
Key: {
|
||||
type: IdentifierEntity
|
||||
type: IdentifierEntity,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -19,11 +29,6 @@ export default class KeyBindingEntity extends IEntity {
|
||||
}
|
||||
|
||||
constructor(values = {}) {
|
||||
values.ActionName = values.ActionName ?? ""
|
||||
values.bShift = values.bShift ?? false
|
||||
values.bCtrl = values.bCtrl ?? false
|
||||
values.bAlt = values.bAlt ?? false
|
||||
values.bCmd = values.bCmd ?? false
|
||||
super(values)
|
||||
/** @type {String} */ this.ActionName
|
||||
/** @type {Boolean} */ this.bShift
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class LinearColorEntity extends IEntity {
|
||||
},
|
||||
A: {
|
||||
type: RealUnitEntity,
|
||||
value: () => new RealUnitEntity(1),
|
||||
default: () => new RealUnitEntity(1),
|
||||
},
|
||||
H: {
|
||||
type: RealUnitEntity,
|
||||
|
||||
@@ -5,9 +5,15 @@ export default class LocalizedTextEntity extends IEntity {
|
||||
|
||||
static lookbehind = "NSLOCTEXT"
|
||||
static attributes = {
|
||||
namespace: "",
|
||||
key: "",
|
||||
value: "",
|
||||
namespace: {
|
||||
default: "",
|
||||
},
|
||||
key: {
|
||||
default: "",
|
||||
},
|
||||
value: {
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -3,7 +3,7 @@ import Utility from "../Utility.js"
|
||||
|
||||
export default class NaturalNumberEntity extends IntegerEntity {
|
||||
|
||||
constructor(values) {
|
||||
constructor(values = 0) {
|
||||
super(values)
|
||||
this.value = Math.round(Utility.clamp(this.value, 0))
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@ export default class ObjectEntity extends IEntity {
|
||||
Class: {
|
||||
type: ObjectReferenceEntity,
|
||||
},
|
||||
Name: "",
|
||||
Name: {
|
||||
default: "",
|
||||
},
|
||||
AxisKey: {
|
||||
type: SymbolEntity,
|
||||
showDefault: false,
|
||||
@@ -29,21 +31,21 @@ export default class ObjectEntity extends IEntity {
|
||||
showDefault: false,
|
||||
},
|
||||
bIsPureFunc: {
|
||||
value: false,
|
||||
default: false,
|
||||
showDefault: false,
|
||||
},
|
||||
bIsConstFunc: {
|
||||
value: false,
|
||||
default: false,
|
||||
showDefault: false,
|
||||
},
|
||||
VariableReference: {
|
||||
type: VariableReferenceEntity,
|
||||
value: null,
|
||||
default: null,
|
||||
showDefault: false,
|
||||
},
|
||||
SelfContextInfo: {
|
||||
type: SymbolEntity,
|
||||
value: null,
|
||||
default: null,
|
||||
showDefault: false,
|
||||
},
|
||||
DelegatePropertyName: {
|
||||
@@ -60,12 +62,12 @@ export default class ObjectEntity extends IEntity {
|
||||
},
|
||||
EventReference: {
|
||||
type: FunctionReferenceEntity,
|
||||
value: null,
|
||||
default: null,
|
||||
showDefault: false,
|
||||
},
|
||||
FunctionReference: {
|
||||
type: FunctionReferenceEntity,
|
||||
value: null,
|
||||
default: null,
|
||||
showDefault: false,
|
||||
},
|
||||
CustomFunctionName: {
|
||||
@@ -74,12 +76,12 @@ export default class ObjectEntity extends IEntity {
|
||||
},
|
||||
TargetType: {
|
||||
type: ObjectReferenceEntity,
|
||||
value: null,
|
||||
default: null,
|
||||
showDefault: false,
|
||||
},
|
||||
MacroGraphReference: {
|
||||
type: MacroGraphReferenceEntity,
|
||||
value: null,
|
||||
default: null,
|
||||
showDefault: false,
|
||||
},
|
||||
Enum: {
|
||||
@@ -136,7 +138,7 @@ export default class ObjectEntity extends IEntity {
|
||||
},
|
||||
bColorCommentBubble: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
default: false,
|
||||
showDefault: false,
|
||||
},
|
||||
MoveMode: {
|
||||
@@ -173,12 +175,12 @@ export default class ObjectEntity extends IEntity {
|
||||
},
|
||||
AdvancedPinDisplay: {
|
||||
type: IdentifierEntity,
|
||||
value: null,
|
||||
default: null,
|
||||
showDefault: false,
|
||||
},
|
||||
EnabledState: {
|
||||
type: IdentifierEntity,
|
||||
value: null,
|
||||
default: null,
|
||||
showDefault: false,
|
||||
},
|
||||
NodeGuid: {
|
||||
@@ -190,7 +192,7 @@ export default class ObjectEntity extends IEntity {
|
||||
},
|
||||
ErrorMsg: {
|
||||
type: String,
|
||||
value: "",
|
||||
default: "",
|
||||
showDefault: false,
|
||||
},
|
||||
CustomProperties: {
|
||||
@@ -412,7 +414,7 @@ export default class ObjectEntity extends IEntity {
|
||||
}
|
||||
|
||||
getDelegatePin() {
|
||||
return this.CustomProperties?.find(pin => pin.PinType.PinCategory === "delegate")
|
||||
return this.CustomProperties?.find(pin => pin.PinType$PinCategory === "delegate")
|
||||
}
|
||||
|
||||
nodeDisplayName() {
|
||||
|
||||
@@ -3,8 +3,12 @@ import IEntity from "./IEntity.js"
|
||||
export default class ObjectReferenceEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
type: "",
|
||||
path: "",
|
||||
type: {
|
||||
default: "",
|
||||
},
|
||||
path: {
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -3,7 +3,9 @@ import IEntity from "./IEntity.js"
|
||||
export default class PathSymbolEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
value: "",
|
||||
value: {
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ByteEntity from "./ByteEntity.js"
|
||||
import ComputedType from "./ComputedType.js"
|
||||
import Configuration from "../Configuration.js"
|
||||
import EnumEntity from "./EnumEntity.js"
|
||||
import FormatTextEntity from "./FormatTextEntity.js"
|
||||
@@ -17,7 +18,6 @@ import RotatorEntity from "./RotatorEntity.js"
|
||||
import SimpleSerializationRotatorEntity from "./SimpleSerializationRotatorEntity.js"
|
||||
import SimpleSerializationVector2DEntity from "./SimpleSerializationVector2DEntity.js"
|
||||
import SimpleSerializationVectorEntity from "./SimpleSerializationVectorEntity.js"
|
||||
import SubAttributesDeclaration from "./SubObject.js"
|
||||
import UnionType from "./UnionType.js"
|
||||
import Utility from "../Utility.js"
|
||||
import Vector2DEntity from "./Vector2DEntity.js"
|
||||
@@ -56,7 +56,9 @@ export default class PinEntity extends IEntity {
|
||||
PinId: {
|
||||
type: GuidEntity,
|
||||
},
|
||||
PinName: "",
|
||||
PinName: {
|
||||
default: "",
|
||||
},
|
||||
PinFriendlyName: {
|
||||
type: new UnionType(LocalizedTextEntity, FormatTextEntity, String),
|
||||
showDefault: false,
|
||||
@@ -69,36 +71,48 @@ export default class PinEntity extends IEntity {
|
||||
type: String,
|
||||
showDefault: false,
|
||||
},
|
||||
PinType: new SubAttributesDeclaration({
|
||||
PinCategory: "",
|
||||
PinSubCategory: "",
|
||||
PinSubCategoryObject: {
|
||||
type: ObjectReferenceEntity,
|
||||
},
|
||||
PinSubCategoryMemberReference: {
|
||||
type: FunctionReferenceEntity,
|
||||
value: null,
|
||||
},
|
||||
PinValueType: {
|
||||
type: PinTypeEntity,
|
||||
value: null,
|
||||
},
|
||||
ContainerType: {
|
||||
type: PathSymbolEntity,
|
||||
},
|
||||
bIsReference: false,
|
||||
bIsConst: false,
|
||||
bIsWeakPointer: false,
|
||||
bIsUObjectWrapper: false,
|
||||
bSerializeAsSinglePrecisionFloat: false,
|
||||
}),
|
||||
PinType$PinCategory: {
|
||||
default: "",
|
||||
},
|
||||
PinType$PinSubCategory: {
|
||||
default: "",
|
||||
},
|
||||
PinType$PinSubCategoryObject: {
|
||||
type: ObjectReferenceEntity,
|
||||
},
|
||||
PinType$PinSubCategoryMemberReference: {
|
||||
type: FunctionReferenceEntity,
|
||||
default: null,
|
||||
},
|
||||
PinType$PinValueType: {
|
||||
type: PinTypeEntity,
|
||||
default: null,
|
||||
},
|
||||
PinType$ContainerType: {
|
||||
type: PathSymbolEntity,
|
||||
},
|
||||
PinType$bIsReference: {
|
||||
default: false,
|
||||
},
|
||||
PinType$bIsConst: {
|
||||
default: false,
|
||||
},
|
||||
PinType$bIsWeakPointer: {
|
||||
default: false,
|
||||
},
|
||||
PinType$bIsUObjectWrapper: {
|
||||
default: false,
|
||||
},
|
||||
PinType$bSerializeAsSinglePrecisionFloat: {
|
||||
default: false,
|
||||
},
|
||||
LinkedTo: {
|
||||
type: [PinReferenceEntity],
|
||||
showDefault: false,
|
||||
},
|
||||
DefaultValue: {
|
||||
/** @param {PinEntity} pinEntity */
|
||||
type: pinEntity => pinEntity.getEntityType(true) ?? String,
|
||||
type: new ComputedType(pinEntity => pinEntity.getEntityType(true) ?? String),
|
||||
serialized: true,
|
||||
showDefault: false,
|
||||
},
|
||||
@@ -109,17 +123,29 @@ export default class PinEntity extends IEntity {
|
||||
DefaultObject: {
|
||||
type: ObjectReferenceEntity,
|
||||
showDefault: false,
|
||||
value: null,
|
||||
default: null,
|
||||
},
|
||||
PersistentGuid: {
|
||||
type: GuidEntity,
|
||||
},
|
||||
bHidden: false,
|
||||
bNotConnectable: false,
|
||||
bDefaultValueIsReadOnly: false,
|
||||
bDefaultValueIsIgnored: false,
|
||||
bAdvancedView: false,
|
||||
bOrphanedPin: false,
|
||||
bHidden: {
|
||||
default: false,
|
||||
},
|
||||
bNotConnectable: {
|
||||
default: false,
|
||||
},
|
||||
bDefaultValueIsReadOnly: {
|
||||
default: false,
|
||||
},
|
||||
bDefaultValueIsIgnored: {
|
||||
default: false,
|
||||
},
|
||||
bAdvancedView: {
|
||||
default: false,
|
||||
},
|
||||
bOrphanedPin: {
|
||||
default: false,
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
@@ -133,21 +159,17 @@ export default class PinEntity extends IEntity {
|
||||
/** @type {LocalizedTextEntity | String} */ this.PinFriendlyName
|
||||
/** @type {String} */ this.PinToolTip
|
||||
/** @type {String} */ this.Direction
|
||||
/**
|
||||
* @type {{
|
||||
* PinCategory: String,
|
||||
* PinSubCategory: String,
|
||||
* PinSubCategoryObject: ObjectReferenceEntity,
|
||||
* PinSubCategoryMemberReference: FunctionReferenceEntity,
|
||||
* PinValueType: PinTypeEntity,
|
||||
* ContainerType: PathSymbolEntity,
|
||||
* bIsReference: Boolean,
|
||||
* bIsConst: Boolean,
|
||||
* bIsWeakPointer: Boolean,
|
||||
* bIsUObjectWrapper: Boolean,
|
||||
* bSerializeAsSinglePrecisionFloat: Boolean,
|
||||
* }}
|
||||
*/ this.PinType
|
||||
/** @type {String} */ this.PinType$PinCategory
|
||||
/** @type {String} */ this.PinType$PinSubCategory
|
||||
/** @type {ObjectReferenceEntity} */ this.PinType$PinSubCategoryObject
|
||||
/** @type {FunctionReferenceEntity} */ this.PinType$PinSubCategoryMemberReference
|
||||
/** @type {PinTypeEntity} */ this.PinType$PinValueType
|
||||
/** @type {PathSymbolEntity} */ this.PinType$ContainerType
|
||||
/** @type {Boolean} */ this.PinType$bIsReference
|
||||
/** @type {Boolean} */ this.PinType$bIsConst
|
||||
/** @type {Boolean} */ this.PinType$bIsWeakPointer
|
||||
/** @type {Boolean} */ this.PinType$bIsUObjectWrapper
|
||||
/** @type {Boolean} */ this.PinType$bIsUObjectWrapper
|
||||
/** @type {PinReferenceEntity[]} */ this.LinkedTo
|
||||
/** @type {T} */ this.DefaultValue
|
||||
/** @type {String} */ this.AutogeneratedDefaultValue
|
||||
@@ -162,12 +184,12 @@ export default class PinEntity extends IEntity {
|
||||
}
|
||||
|
||||
getType() {
|
||||
const subCategory = this.PinType.PinSubCategoryObject
|
||||
if (this.PinType.PinCategory === "struct" || this.PinType.PinCategory === "object") {
|
||||
const subCategory = this.PinType$PinSubCategoryObject
|
||||
if (this.PinType$PinCategory === "struct" || this.PinType$PinCategory === "object") {
|
||||
return subCategory.path
|
||||
}
|
||||
if (
|
||||
this.PinType.PinCategory === "byte"
|
||||
this.PinType$PinCategory === "byte"
|
||||
&& (
|
||||
subCategory.type === Configuration.nodeType.enum
|
||||
|| subCategory.type === Configuration.nodeType.userDefinedEnum
|
||||
@@ -175,7 +197,7 @@ export default class PinEntity extends IEntity {
|
||||
) {
|
||||
return "enum"
|
||||
}
|
||||
return this.PinType.PinCategory
|
||||
return this.PinType$PinCategory
|
||||
}
|
||||
|
||||
getEntityType(alternative = false) {
|
||||
@@ -201,17 +223,17 @@ export default class PinEntity extends IEntity {
|
||||
|
||||
/** @param {PinEntity} other */
|
||||
copyTypeFrom(other) {
|
||||
this.PinType.PinCategory = other.PinType.PinCategory
|
||||
this.PinType.PinSubCategory = other.PinType.PinSubCategory
|
||||
this.PinType.PinSubCategoryObject = other.PinType.PinSubCategoryObject
|
||||
this.PinType.PinSubCategoryMemberReference = other.PinType.PinSubCategoryMemberReference
|
||||
this.PinType.PinValueType = other.PinType.PinValueType
|
||||
this.PinType.ContainerType = other.PinType.ContainerType
|
||||
this.PinType.bIsReference = other.PinType.bIsReference
|
||||
this.PinType.bIsConst = other.PinType.bIsConst
|
||||
this.PinType.bIsWeakPointer = other.PinType.bIsWeakPointer
|
||||
this.PinType.bIsUObjectWrapper = other.PinType.bIsUObjectWrapper
|
||||
this.PinType.bSerializeAsSinglePrecisionFloat = other.PinType.bSerializeAsSinglePrecisionFloat
|
||||
this.PinType$PinCategory = other.PinType$PinCategory
|
||||
this.PinType$PinSubCategory = other.PinType$PinSubCategory
|
||||
this.PinType$PinSubCategoryObject = other.PinType$PinSubCategoryObject
|
||||
this.PinType$PinSubCategoryMemberReference = other.PinType$PinSubCategoryMemberReference
|
||||
this.PinType$PinValueType = other.PinType$PinValueType
|
||||
this.PinType$ContainerType = other.PinType$ContainerType
|
||||
this.PinType$bIsReference = other.PinType$bIsReference
|
||||
this.PinType$bIsConst = other.PinType$bIsConst
|
||||
this.PinType$bIsWeakPointer = other.PinType$bIsWeakPointer
|
||||
this.PinType$bIsUObjectWrapper = other.PinType$bIsUObjectWrapper
|
||||
this.PinType$bSerializeAsSinglePrecisionFloat = other.PinType$bSerializeAsSinglePrecisionFloat
|
||||
}
|
||||
|
||||
getDefaultValue(maybeCreate = false) {
|
||||
@@ -222,7 +244,7 @@ export default class PinEntity extends IEntity {
|
||||
}
|
||||
|
||||
isExecution() {
|
||||
return this.PinType.PinCategory === "exec"
|
||||
return this.PinType$PinCategory === "exec"
|
||||
}
|
||||
|
||||
isHidden() {
|
||||
@@ -280,13 +302,13 @@ export default class PinEntity extends IEntity {
|
||||
}
|
||||
|
||||
getSubCategory() {
|
||||
return this.PinType.PinSubCategoryObject.path
|
||||
return this.PinType$PinSubCategoryObject.path
|
||||
}
|
||||
|
||||
/** @return {CSSResult} */
|
||||
pinColor() {
|
||||
return Configuration.pinColor[this.getType()]
|
||||
?? Configuration.pinColor[this.PinType.PinCategory]
|
||||
?? Configuration.pinColor[this.PinType$PinCategory]
|
||||
?? Configuration.pinColor["default"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,23 +4,23 @@ export default class PinTypeEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
TerminalCategory: {
|
||||
value: "",
|
||||
default: "",
|
||||
showDefault: false,
|
||||
},
|
||||
TerminalSubCategory: {
|
||||
value: "",
|
||||
default: "",
|
||||
showDefault: false,
|
||||
},
|
||||
bTerminalIsConst: {
|
||||
value: false,
|
||||
default: false,
|
||||
showDefault: false,
|
||||
},
|
||||
bTerminalIsWeakPointer: {
|
||||
value: false,
|
||||
default: false,
|
||||
showDefault: false,
|
||||
},
|
||||
bTerminalIsUObjectWrapper: {
|
||||
value: false,
|
||||
default: false,
|
||||
showDefault: false,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ export default class RotatorEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
R: {
|
||||
value: 0,
|
||||
default: 0,
|
||||
},
|
||||
P: {
|
||||
value: 0,
|
||||
default: 0,
|
||||
},
|
||||
Y: {
|
||||
value: 0,
|
||||
default: 0,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
export default class SerializedType {
|
||||
|
||||
#types
|
||||
get types() {
|
||||
return this.#types
|
||||
}
|
||||
set types(v) {
|
||||
this.#types = v
|
||||
}
|
||||
|
||||
#stringFallback
|
||||
get stringFallback() {
|
||||
return this.#stringFallback
|
||||
}
|
||||
set stringFallback(v) {
|
||||
this.#stringFallback = v
|
||||
}
|
||||
|
||||
constructor([...acceptedTypes], stringFallback = true) {
|
||||
this.#types = [...new Set([
|
||||
...acceptedTypes,
|
||||
...(stringFallback ? [String] : [])
|
||||
])]
|
||||
this.#stringFallback = stringFallback
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
/** @typedef {import("./IEntity").AttributeDeclarations} AttributeDeclarations */
|
||||
|
||||
export default class SubAttributesDeclaration {
|
||||
|
||||
/** @param {AttributeDeclarations} attributes */
|
||||
constructor(attributes) {
|
||||
this.attributes = attributes
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ import IEntity from "./IEntity.js"
|
||||
export default class SymbolEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
value: "",
|
||||
value: {
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -4,7 +4,9 @@ import Utility from "../Utility.js"
|
||||
export default class RealUnitEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
value: 0,
|
||||
value: {
|
||||
default: 0,
|
||||
},
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -3,9 +3,8 @@ import IEntity from "./IEntity.js"
|
||||
export default class UnknownKeysEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
lookbehind:
|
||||
{
|
||||
value: "",
|
||||
lookbehind: {
|
||||
default: "",
|
||||
showDefault: false,
|
||||
ignore: true,
|
||||
},
|
||||
@@ -16,7 +15,7 @@ export default class UnknownKeysEntity extends IEntity {
|
||||
}
|
||||
|
||||
constructor(values) {
|
||||
super(values)
|
||||
super(values, true)
|
||||
/** @type {String} */ this.lookbehind
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,17 @@ export default class VariableReferenceEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
MemberScope: {
|
||||
value: "",
|
||||
default: "",
|
||||
showDefault: false,
|
||||
},
|
||||
MemberName: "",
|
||||
MemberName: {
|
||||
default: "",
|
||||
},
|
||||
MemberGuid: {
|
||||
type: GuidEntity,
|
||||
},
|
||||
bSelfContext: {
|
||||
value: false,
|
||||
default: false,
|
||||
showDefault: false,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ export default class Vector2DEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
X: {
|
||||
value: 0,
|
||||
default: 0,
|
||||
expected: true,
|
||||
},
|
||||
Y: {
|
||||
value: 0,
|
||||
default: 0,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@ export default class VectorEntity extends IEntity {
|
||||
|
||||
static attributes = {
|
||||
X: {
|
||||
value: 0,
|
||||
default: 0,
|
||||
expected: true,
|
||||
},
|
||||
Y: {
|
||||
value: 0,
|
||||
default: 0,
|
||||
expected: true,
|
||||
},
|
||||
Z: {
|
||||
value: 0,
|
||||
default: 0,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Configuration from "../../Configuration.js"
|
||||
import Grammar from "../../serialization/Grammar.js"
|
||||
import IInput from "../IInput.js"
|
||||
import ISerializer from "../../serialization/ISerializer.js"
|
||||
import KeyBindingEntity from "../../entity/KeyBindingEntity.js"
|
||||
|
||||
/** @typedef {import("../../Blueprint").default} Blueprint */
|
||||
@@ -32,8 +32,8 @@ export default class IKeyboardShortcut extends IInput {
|
||||
if (v instanceof KeyBindingEntity) {
|
||||
return v
|
||||
}
|
||||
if (v.constructor === String) {
|
||||
const parsed = ISerializer.grammar.KeyBinding.parse(v)
|
||||
if (typeof v === "string") {
|
||||
const parsed = Grammar.keyBindingEntity.parse(v)
|
||||
if (parsed.status) {
|
||||
return parsed.value
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export default class EventNodeTemplate extends NodeTemplate {
|
||||
|
||||
createDelegatePinElement() {
|
||||
const pin = /** @type {PinElementConstructor} */(ElementFactory.getConstructor("ueb-pin")).newObject(
|
||||
this.element.getPinEntities().find(v => !v.isHidden() && v.PinType.PinCategory === "delegate"),
|
||||
this.element.getPinEntities().find(v => !v.isHidden() && v.PinType$PinCategory === "delegate"),
|
||||
new MinimalPinTemplate(),
|
||||
this.element
|
||||
)
|
||||
@@ -52,7 +52,7 @@ export default class EventNodeTemplate extends NodeTemplate {
|
||||
|
||||
createPinElements() {
|
||||
return this.element.getPinEntities()
|
||||
.filter(v => !v.isHidden() && v.PinType.PinCategory !== "delegate")
|
||||
.filter(v => !v.isHidden() && v.PinType$PinCategory !== "delegate")
|
||||
.map(pinEntity => /** @type {PinElementConstructor} */(ElementFactory.getConstructor("ueb-pin"))
|
||||
.newObject(pinEntity, undefined, this.element)
|
||||
)
|
||||
|
||||
@@ -124,7 +124,8 @@ export default class NodeTemplate extends ISelectableDraggableTemplate {
|
||||
return this.element.getPinEntities()
|
||||
.filter(v => !v.isHidden())
|
||||
.map(pinEntity => {
|
||||
this.hasSubtitle = this.hasSubtitle || pinEntity.PinName === "self" && pinEntity.getDisplayName() === "Target"
|
||||
this.hasSubtitle = this.hasSubtitle
|
||||
|| pinEntity.PinName === "self" && pinEntity.getDisplayName() === "Target"
|
||||
let pinElement = /** @type {PinElementConstructor} */(ElementFactory.getConstructor("ueb-pin"))
|
||||
.newObject(pinEntity, undefined, this.element)
|
||||
return pinElement
|
||||
|
||||
@@ -76,12 +76,12 @@ export default class PinTemplate extends ITemplate {
|
||||
}
|
||||
|
||||
renderIcon() {
|
||||
switch (this.element.entity.PinType.ContainerType.toString()) {
|
||||
switch (this.element.entity.PinType$ContainerType.toString()) {
|
||||
case "Array": return SVGIcon.array
|
||||
case "Set": return SVGIcon.set
|
||||
case "Map": return SVGIcon.map
|
||||
}
|
||||
if (this.element.entity.PinType.PinCategory === "delegate") {
|
||||
if (this.element.entity.PinType$PinCategory === "delegate") {
|
||||
return SVGIcon.delegate
|
||||
}
|
||||
return SVGIcon.genericPin
|
||||
|
||||
Reference in New Issue
Block a user