Various fixes

This commit is contained in:
barsdeveloper
2022-09-09 20:39:08 +02:00
parent 9d424809c9
commit 57ef15c943
13 changed files with 349 additions and 100 deletions

226
dist/ueblueprint.js vendored
View File

@@ -362,8 +362,20 @@ class SerializedType {
this.#types = v;
}
constructor(...acceptedTypes) {
this.#types = acceptedTypes;
#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;
}
}
@@ -558,7 +570,7 @@ class Utility {
/**
* @param {String} value
*/
static FirstCapital(value) {
static firstCapital(value) {
return value.charAt(0).toUpperCase() + value.substring(1)
}
@@ -599,7 +611,15 @@ class Utility {
for (let j = 0; j < b.length; ++j) {
for (let i = 0; i < a.length; ++i) {
if (a[i] == b[j]) {
result.push(...a.splice(0, i), ...b.splice(0, j), ...a.splice(0, 1));
// Found a corresponding element in the two arrays
result.push(
// Take and append all the elements skipped from a
...a.splice(0, i),
// Take and append all the elements skippend from b
...b.splice(0, j),
// Take and append the element in common
...a.splice(0, 1)
);
j = 0;
i = 0;
b.shift();
@@ -607,6 +627,7 @@ class Utility {
}
}
}
// Append remaining the elements in the arrays and make it unique
return [...(new Set(result.concat(...a, ...b)))]
}
@@ -662,6 +683,33 @@ class Utility {
static printLinearColor(value) {
return `${Math.round(value.R * 255)}, ${Math.round(value.G * 255)}, ${Math.round(value.B * 255)}`
}
static isFunction(value) {
return value instanceof Function && value.prototype === undefined
}
}
/**
* @typedef {import("./IEntity").default} IEntity
*/
class CalculatedType {
#f
/**
* @param {Function} f
*/
constructor(f) {
this.#f = f;
}
/**
* @param {IEntity} entity
*/
calculate(entity) {
return this.f(entity)
}
}
class IEntity extends Observable {
@@ -682,26 +730,33 @@ class IEntity extends Observable {
Object.getOwnPropertyNames(properties),
Object.getOwnPropertyNames(values ?? {})
)) {
let defaultValue = properties[property];
const defaultType = Utility.getType(defaultValue);
if (!(property in properties)) {
console.warn(`Property ${prefix}${property} is not defined in ${this.constructor.name}`);
console.warn(`Property ${prefix}${property} is not defined in ${this.constructor.name}.attributes`);
} else if (
defaultValue != null
&& !(defaultValue instanceof TypeInitialization && !defaultValue.showDefault)
&& !(property in values)
) {
console.warn(`${this.constructor.name} adds property ${prefix}${property} not defined in the serialized data`);
console.warn(
`${this.constructor.name} adds property ${prefix}${property} not defined in the serialized data`
);
}
// Not instanceof because all objects are instenceof Object, exact match needed
if (defaultType === Object) {
target[property] = {};
defineAllAttributes(target[property], properties[property], values[property], property + ".");
continue
}
/*
* The value can either be:
* - Array: can contain multiple values, its property is assigned multiple times like (X=1, X=4, X="Hello World").
* - Array: can contain multiple values, its property is assigned multiple times like (X=1, X="4").
* - CalculatedType: the exact type depends on the previous attributes assigned to this entity.
* - TypeInitialization: contains the maximum amount of information about the attribute.
* - A type: the default value will be default constructed object without arguments.
* - A proper value.
@@ -712,6 +767,10 @@ class IEntity extends Observable {
// We have a value, need nothing more
continue
}
if (defaultValue instanceof CalculatedType) {
defaultValue = defaultValue.calculate(this);
defaultType = Utility.getType(defaultValue);
}
if (defaultValue instanceof TypeInitialization) {
if (!defaultValue.showDefault) {
target[property] = undefined; // Declare undefined to preserve the order of attributes
@@ -723,9 +782,6 @@ class IEntity extends Observable {
target[property] = [];
continue
}
if (defaultValue instanceof Function) {
defaultValue = TypeInitialization.sanitize(new defaultValue(), defaultType);
}
target[property] = TypeInitialization.sanitize(defaultValue, defaultType);
}
};
@@ -866,7 +922,7 @@ class KeyBindingEntity extends IEntity {
}
}
class LinearColorEntity extends IEntity {
class LinearColorEntity$1 extends IEntity {
static attributes = {
R: Number,
@@ -936,7 +992,12 @@ class PinEntity extends IEntity {
bSerializeAsSinglePrecisionFloat: false,
},
LinkedTo: new TypeInitialization([PinReferenceEntity], false),
DefaultValue: new TypeInitialization(new SerializedType(LinearColorEntity, String), false),
DefaultValue: new TypeInitialization(
new SerializedType([
LinearColorEntity$1,
]),
false
),
AutogeneratedDefaultValue: new TypeInitialization(String, false),
DefaultObject: new TypeInitialization(ObjectReferenceEntity, false, null),
PersistentGuid: GuidEntity,
@@ -1099,6 +1160,15 @@ var parsimmon_umd_min = {exports: {}};
var Parsimmon = /*@__PURE__*/getDefaultExportFromCjs(parsimmon_umd_min.exports);
class LinearColorEntity extends IEntity {
static attributes = {
X: Number,
Y: Number,
Z: Number,
}
}
/**
* @typedef {import("../entity/IEntity").default} IEntity
*/
@@ -1111,13 +1181,14 @@ class Grammar {
static getGrammarForType(r, attributeType, defaultGrammar) {
if (attributeType instanceof TypeInitialization) {
// Unpack TypeInitialization
attributeType = attributeType.type;
return Grammar.getGrammarForType(r, attributeType, defaultGrammar)
}
if (attributeType instanceof SerializedType) {
const noStringTypes = attributeType.types.filter(t => t !== String);
const nonStringTypes = attributeType.types.filter(t => t !== String);
let result = P.alt(
...noStringTypes.map(t =>
...nonStringTypes.map(t =>
Grammar.getGrammarForType(r, t).wrap(P.string('"'), P.string('"')).map(
/**
* @param {IEntity} entity
@@ -1129,8 +1200,13 @@ class Grammar {
)
)
);
if (noStringTypes.length < attributeType.types.length) {
result = result.or(r.String); // Separated because it cannot be wrapped into " and "
if (nonStringTypes.length < attributeType.types.length) {
result = result.or(r.String/*.map(v => {
if (attributeType.stringFallback) {
console.log("Unrecognized value, fallback on String")
}
return v
})*/); // Separated because it cannot be wrapped into " and "
}
return result
}
@@ -1156,6 +1232,8 @@ class Grammar {
case PinReferenceEntity:
return r.PinReference
case LinearColorEntity:
return r.Vector
case LinearColorEntity$1:
return r.LinearColor
case FunctionReferenceEntity:
return r.FunctionReference
@@ -1182,36 +1260,28 @@ class Grammar {
}
}
static createAttributeGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) =>
static createPropertyGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) =>
r.AttributeName.skip(valueSeparator)
.chain(attributeName => {
// Once the property name is known, look into entityType.properties to get its type
const attributeKey = attributeName.split(".");
const attribute = Utility.objectGet(entityType.attributes, attributeKey);
let attributeValueGrammar = Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue);
// Returns attributeSetter: a function called with an object as argument that will set the correct attribute value
// Returns a setter function for the property
return attributeValueGrammar.map(attributeValue =>
entity => Utility.objectSet(entity, attributeKey, attributeValue, true)
)
})
/**
* @template T
* @param {new (values: Object) => T} entityType
* @returns {Parsimmon.Parser<T>}
*/
static createMultiAttributeGrammar = (r, entityType) =>
/**
* Basically this creates a parser that looks for a string like 'Key (A=False,B="Something",)'
* Then it populates an object of type EntityType with the attribute values found inside the parentheses.
*/
static createEntityGrammar = (r, entityType) =>
P.seqMap(
entityType.lookbehind
? P.seq(P.string(entityType.lookbehind), P.optWhitespace, P.string("("))
: P.string("("),
Grammar.createAttributeGrammar(r, entityType)
.trim(P.optWhitespace)
.sepBy(P.string(","))
.skip(P.regex(/,?/).then(P.optWhitespace)), // Optional trailing comma
Grammar.createPropertyGrammar(r, entityType)
.trim(P.optWhitespace) // Drop spaces around a property assignment
.sepBy(P.string(",")) // Assignments are separated by comma
.skip(P.regex(/,?/).then(P.optWhitespace)), // Optional trailing comma and maybe additional space
P.string(')'),
(_, attributes, __) => {
let values = {};
@@ -1266,8 +1336,7 @@ class Grammar {
Integer = r => P.regex(/[\-\+]?[0-9]+/).map(v => new IntegerEntity(v)).desc("an integer")
Guid = r => P.regex(/[0-9a-zA-Z]{32}/).map(v => new GuidEntity({ value: v }))
.desc("32 digit hexadecimal (accepts all the letters for safety) value")
Guid = r => r.HexDigit.times(32).tie().map(v => new GuidEntity({ value: v })).desc("32 digit hexadecimal value")
Identifier = r => P.regex(/\w+/).map(v => new IdentifierEntity(v))
@@ -1323,7 +1392,9 @@ class Grammar {
r.Guid,
r.LocalizedText,
r.InvariantText,
r.Reference
r.Reference,
r.Vector,
r.LinearColor,
)
PinReference = r => P.seqMap(
@@ -1336,18 +1407,20 @@ class Grammar {
})
)
LinearColor = r => Grammar.createMultiAttributeGrammar(r, LinearColorEntity)
Vector = r => Grammar.createEntityGrammar(r, LinearColorEntity)
FunctionReference = r => Grammar.createMultiAttributeGrammar(r, FunctionReferenceEntity)
LinearColor = r => Grammar.createEntityGrammar(r, LinearColorEntity$1)
FunctionReference = r => Grammar.createEntityGrammar(r, FunctionReferenceEntity)
KeyBinding = r => P.alt(
r.Identifier.map(identifier => new KeyBindingEntity({
Key: identifier
})),
Grammar.createMultiAttributeGrammar(r, KeyBindingEntity)
Grammar.createEntityGrammar(r, KeyBindingEntity)
)
Pin = r => Grammar.createMultiAttributeGrammar(r, PinEntity)
Pin = r => Grammar.createEntityGrammar(r, PinEntity)
CustomProperties = r =>
P.string("CustomProperties")
@@ -1366,7 +1439,7 @@ class Grammar {
P
.alt(
r.CustomProperties,
Grammar.createAttributeGrammar(r, ObjectEntity)
Grammar.createPropertyGrammar(r, ObjectEntity)
)
.sepBy1(P.whitespace),
P.seq(r.MultilineWhitespace, P.string("End"), P.whitespace, P.string("Object")),
@@ -1386,7 +1459,7 @@ class Grammar {
.string("#")
.then(r.HexDigit.times(2).tie().times(3, 4))
.trim(P.optWhitespace)
.map(([R, G, B, A]) => new LinearColorEntity({
.map(([R, G, B, A]) => new LinearColorEntity$1({
R: parseInt(R, 16) / 255,
G: parseInt(G, 16) / 255,
B: parseInt(B, 16) / 255,
@@ -1399,12 +1472,12 @@ class Grammar {
r.ColorNumber,
P.string(",").skip(P.optWhitespace),
r.ColorNumber.map(Number),
(R, _, G, __, B) => new LinearColorEntity({
(R, _, G, __, B) => new LinearColorEntity$1({
R: R / 255,
G: G / 255,
B: B / 255,
A: 1,
})
}),
)
LinearColorFromRGB = r => P.string("rgb").then(
@@ -1423,7 +1496,7 @@ class Grammar {
r.ColorNumber.map(Number),
P.string(",").skip(P.optWhitespace),
P.regex(/0?\.\d+|[01]/).map(Number),
(R, _, G, __, B, ___, A) => new LinearColorEntity({
(R, _, G, __, B, ___, A) => new LinearColorEntity$1({
R: R / 255,
G: G / 255,
B: B / 255,
@@ -1439,7 +1512,7 @@ class Grammar {
r.LinearColorFromRGBList,
r.LinearColorFromHex,
r.LinearColorFromRGB,
r.LinearColorFromRGBA
r.LinearColorFromRGBA,
)
}
@@ -1525,7 +1598,7 @@ class ISerializer {
case Function:
return this.writeValue(value(), fullKey, insideString)
case Boolean:
return Utility.FirstCapital(value.toString())
return Utility.firstCapital(value.toString())
case Number:
return value.toString()
case String:
@@ -3508,6 +3581,54 @@ class StringPinTemplate extends IInputPinTemplate {
}
}
/**
* @typedef {import("../element/PinElement").default} PinElement
* @typedef {import("../entity/LinearColorEntity").default} LinearColorEntity}
*/
class VectorPinTemplate extends IInputPinTemplate {
/** @type {HTMLInputElement} */
#input
/**
* @param {PinElement} pin
* @param {Map} changedProperties
*/
firstUpdated(pin, changedProperties) {
super.firstUpdated(pin, changedProperties);
this.#input = pin.querySelector(".ueb-pin-input");
}
/**
* @param {PinElement} pin
*/
getInputs(pin) {
return [this.#input.dataset.linearColor]
}
/**
* @param {PinElement} pin
* @param {String[]} value
*/
setInputs(pin, value = []) {
}
/**
* @param {PinElement} pin
*/
renderInput(pin) {
if (pin.isInput()) {
return $`
<div class="ueb-pin-input">
<span class="ueb-pin-input-x" role="textbox" contenteditable="true" .innerText=${pin.unreactiveDefaultValue}></span>
</div>
`
}
return super.renderInput(pin)
}
}
/**
* @typedef {import("../entity/GuidEntity").default} GuidEntity
* @typedef {import("../entity/PinEntity").default} PinEntity
@@ -3527,6 +3648,7 @@ class PinElement extends IElement {
"real": RealPinTemplate,
"string": StringPinTemplate,
"/Script/CoreUObject.LinearColor": LinearColorPinTemplate,
"/Script/CoreUObject.Vector": VectorPinTemplate,
}
static properties = {
@@ -3536,13 +3658,13 @@ class PinElement extends IElement {
reflect: true,
},
color: {
type: LinearColorEntity,
type: LinearColorEntity$1,
converter: {
fromAttribute: (value, type) => {
return ISerializer.grammar.LinearColorFromAnyColor.parse(value).value
return value ? ISerializer.grammar.LinearColorFromAnyColor.parse(value).value : null
},
toAttribute: (value, type) => {
return Utility.printLinearColor(value)
return value ? Utility.printLinearColor(value) : null
},
},
attribute: "data-color",
@@ -3607,7 +3729,7 @@ class PinElement extends IElement {
this.advancedView = entity.bAdvancedView;
this.unreactiveDefaultValue = entity.getDefaultValue();
this.pinType = this.entity.getType();
this.color = this.constructor.properties.color.converter.fromAttribute(Configuration.pinColor[this.pinType].toString());
this.color = this.constructor.properties.color.converter.fromAttribute(Configuration.pinColor[this.pinType]?.toString());
this.isLinked = false;
this.pinDirection = entity.isInput() ? "input" : entity.isOutput() ? "output" : "hidden";
@@ -5258,8 +5380,8 @@ function initializeSerializerFactory() {
);
SerializerFactory.registerSerializer(
LinearColorEntity,
new GeneralSerializer(bracketsWrapped, LinearColorEntity)
LinearColorEntity$1,
new GeneralSerializer(bracketsWrapped, LinearColorEntity$1)
);
SerializerFactory.registerSerializer(

File diff suppressed because one or more lines are too long

View File

@@ -123,7 +123,7 @@ export default class Utility {
/**
* @param {String} value
*/
static FirstCapital(value) {
static firstCapital(value) {
return value.charAt(0).toUpperCase() + value.substring(1)
}
@@ -164,7 +164,15 @@ export default class Utility {
for (let j = 0; j < b.length; ++j) {
for (let i = 0; i < a.length; ++i) {
if (a[i] == b[j]) {
result.push(...a.splice(0, i), ...b.splice(0, j), ...a.splice(0, 1))
// Found a corresponding element in the two arrays
result.push(
// Take and append all the elements skipped from a
...a.splice(0, i),
// Take and append all the elements skippend from b
...b.splice(0, j),
// Take and append the element in common
...a.splice(0, 1)
)
j = 0
i = 0
b.shift()
@@ -172,6 +180,7 @@ export default class Utility {
}
}
}
// Append remaining the elements in the arrays and make it unique
return [...(new Set(result.concat(...a, ...b)))]
}
@@ -227,4 +236,8 @@ export default class Utility {
static printLinearColor(value) {
return `${Math.round(value.R * 255)}, ${Math.round(value.G * 255)}, ${Math.round(value.B * 255)}`
}
static isFunction(value) {
return value instanceof Function && value.prototype === undefined
}
}

View File

@@ -11,6 +11,7 @@ import PinTemplate from "../template/PinTemplate"
import RealPinTemplate from "../template/RealPinTemplate"
import StringPinTemplate from "../template/StringPinTemplate"
import Utility from "../Utility"
import VectorPinTemplate from "../template/VectorPinTemplate"
/**
* @typedef {import("../entity/GuidEntity").default} GuidEntity
@@ -31,6 +32,7 @@ export default class PinElement extends IElement {
"real": RealPinTemplate,
"string": StringPinTemplate,
"/Script/CoreUObject.LinearColor": LinearColorPinTemplate,
"/Script/CoreUObject.Vector": VectorPinTemplate,
}
static properties = {
@@ -43,10 +45,10 @@ export default class PinElement extends IElement {
type: LinearColorEntity,
converter: {
fromAttribute: (value, type) => {
return ISerializer.grammar.LinearColorFromAnyColor.parse(value).value
return value ? ISerializer.grammar.LinearColorFromAnyColor.parse(value).value : null
},
toAttribute: (value, type) => {
return Utility.printLinearColor(value)
return value ? Utility.printLinearColor(value) : null
},
},
attribute: "data-color",
@@ -111,7 +113,7 @@ export default class PinElement extends IElement {
this.advancedView = entity.bAdvancedView
this.unreactiveDefaultValue = entity.getDefaultValue()
this.pinType = this.entity.getType()
this.color = this.constructor.properties.color.converter.fromAttribute(Configuration.pinColor[this.pinType].toString())
this.color = this.constructor.properties.color.converter.fromAttribute(Configuration.pinColor[this.pinType]?.toString())
this.isLinked = false
this.pinDirection = entity.isInput() ? "input" : entity.isOutput() ? "output" : "hidden"

View File

@@ -0,0 +1,22 @@
/**
* @typedef {import("./IEntity").default} IEntity
*/
export default class CalculatedType {
#f
/**
* @param {Function} f
*/
constructor(f) {
this.#f = f
}
/**
* @param {IEntity} entity
*/
calculate(entity) {
return this.f(entity)
}
}

View File

@@ -1,6 +1,7 @@
import Observable from "../Observable"
import TypeInitialization from "./TypeInitialization"
import Utility from "../Utility"
import CalculatedType from "./CalculatedType"
export default class IEntity extends Observable {
@@ -20,26 +21,33 @@ export default class IEntity extends Observable {
Object.getOwnPropertyNames(properties),
Object.getOwnPropertyNames(values ?? {})
)) {
let defaultValue = properties[property]
const defaultType = Utility.getType(defaultValue)
if (!(property in properties)) {
console.warn(`Property ${prefix}${property} is not defined in ${this.constructor.name}`)
console.warn(`Property ${prefix}${property} is not defined in ${this.constructor.name}.attributes`)
} else if (
defaultValue != null
&& !(defaultValue instanceof TypeInitialization && !defaultValue.showDefault)
&& !(property in values)
) {
console.warn(`${this.constructor.name} adds property ${prefix}${property} not defined in the serialized data`)
console.warn(
`${this.constructor.name} adds property ${prefix}${property} not defined in the serialized data`
)
}
// Not instanceof because all objects are instenceof Object, exact match needed
if (defaultType === Object) {
target[property] = {}
defineAllAttributes(target[property], properties[property], values[property], property + ".")
continue
}
/*
* The value can either be:
* - Array: can contain multiple values, its property is assigned multiple times like (X=1, X=4, X="Hello World").
* - Array: can contain multiple values, its property is assigned multiple times like (X=1, X="4").
* - CalculatedType: the exact type depends on the previous attributes assigned to this entity.
* - TypeInitialization: contains the maximum amount of information about the attribute.
* - A type: the default value will be default constructed object without arguments.
* - A proper value.
@@ -50,6 +58,10 @@ export default class IEntity extends Observable {
// We have a value, need nothing more
continue
}
if (defaultValue instanceof CalculatedType) {
defaultValue = defaultValue.calculate(this)
defaultType = Utility.getType(defaultValue)
}
if (defaultValue instanceof TypeInitialization) {
if (!defaultValue.showDefault) {
target[property] = undefined // Declare undefined to preserve the order of attributes
@@ -61,9 +73,6 @@ export default class IEntity extends Observable {
target[property] = []
continue
}
if (defaultValue instanceof Function) {
defaultValue = TypeInitialization.sanitize(new defaultValue(), defaultType)
}
target[property] = TypeInitialization.sanitize(defaultValue, defaultType)
}
}

View File

@@ -30,7 +30,12 @@ export default class PinEntity extends IEntity {
bSerializeAsSinglePrecisionFloat: false,
},
LinkedTo: new TypeInitialization([PinReferenceEntity], false),
DefaultValue: new TypeInitialization(new SerializedType(LinearColorEntity, String), false),
DefaultValue: new TypeInitialization(
new SerializedType([
LinearColorEntity,
]),
false
),
AutogeneratedDefaultValue: new TypeInitialization(String, false),
DefaultObject: new TypeInitialization(ObjectReferenceEntity, false, null),
PersistentGuid: GuidEntity,

View File

@@ -8,7 +8,19 @@ export default class SerializedType {
this.#types = v
}
constructor(...acceptedTypes) {
this.#types = acceptedTypes
#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
}
}

View File

@@ -35,7 +35,6 @@ export default class TypeInitialization {
if (targetType === undefined) {
targetType = value?.constructor
}
let wrongType = false
if (
targetType
&& targetType !== SerializedType

10
js/entity/VectorEntity.js Normal file
View File

@@ -0,0 +1,10 @@
import IEntity from "./IEntity"
export default class LinearColorEntity extends IEntity {
static attributes = {
X: Number,
Y: Number,
Z: Number,
}
}

View File

@@ -15,6 +15,8 @@ import PinReferenceEntity from "../entity/PinReferenceEntity"
import SerializedType from "../entity/SerializedType"
import TypeInitialization from "../entity/TypeInitialization"
import Utility from "../Utility"
import VectorEntity from "../entity/VectorEntity"
import CalculatedType from "../entity/CalculatedType"
/**
* @typedef {import("../entity/IEntity").default} IEntity
@@ -28,13 +30,14 @@ export default class Grammar {
static getGrammarForType(r, attributeType, defaultGrammar) {
if (attributeType instanceof TypeInitialization) {
// Unpack TypeInitialization
attributeType = attributeType.type
return Grammar.getGrammarForType(r, attributeType, defaultGrammar)
}
if (attributeType instanceof SerializedType) {
const noStringTypes = attributeType.types.filter(t => t !== String)
const nonStringTypes = attributeType.types.filter(t => t !== String)
let result = P.alt(
...noStringTypes.map(t =>
...nonStringTypes.map(t =>
Grammar.getGrammarForType(r, t).wrap(P.string('"'), P.string('"')).map(
/**
* @param {IEntity} entity
@@ -46,8 +49,13 @@ export default class Grammar {
)
)
)
if (noStringTypes.length < attributeType.types.length) {
result = result.or(r.String) // Separated because it cannot be wrapped into " and "
if (nonStringTypes.length < attributeType.types.length) {
result = result.or(r.String/*.map(v => {
if (attributeType.stringFallback) {
console.log("Unrecognized value, fallback on String")
}
return v
})*/) // Separated because it cannot be wrapped into " and "
}
return result
}
@@ -72,6 +80,8 @@ export default class Grammar {
return r.InvariantText
case PinReferenceEntity:
return r.PinReference
case VectorEntity:
return r.Vector
case LinearColorEntity:
return r.LinearColor
case FunctionReferenceEntity:
@@ -99,36 +109,28 @@ export default class Grammar {
}
}
static createAttributeGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) =>
static createPropertyGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) =>
r.AttributeName.skip(valueSeparator)
.chain(attributeName => {
// Once the property name is known, look into entityType.properties to get its type
const attributeKey = attributeName.split(".")
const attribute = Utility.objectGet(entityType.attributes, attributeKey)
let attributeValueGrammar = Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue)
// Returns attributeSetter: a function called with an object as argument that will set the correct attribute value
// Returns a setter function for the property
return attributeValueGrammar.map(attributeValue =>
entity => Utility.objectSet(entity, attributeKey, attributeValue, true)
)
})
/**
* @template T
* @param {new (values: Object) => T} entityType
* @returns {Parsimmon.Parser<T>}
*/
static createMultiAttributeGrammar = (r, entityType) =>
/**
* Basically this creates a parser that looks for a string like 'Key (A=False,B="Something",)'
* Then it populates an object of type EntityType with the attribute values found inside the parentheses.
*/
static createEntityGrammar = (r, entityType) =>
P.seqMap(
entityType.lookbehind
? P.seq(P.string(entityType.lookbehind), P.optWhitespace, P.string("("))
: P.string("("),
Grammar.createAttributeGrammar(r, entityType)
.trim(P.optWhitespace)
.sepBy(P.string(","))
.skip(P.regex(/,?/).then(P.optWhitespace)), // Optional trailing comma
Grammar.createPropertyGrammar(r, entityType)
.trim(P.optWhitespace) // Drop spaces around a property assignment
.sepBy(P.string(",")) // Assignments are separated by comma
.skip(P.regex(/,?/).then(P.optWhitespace)), // Optional trailing comma and maybe additional space
P.string(')'),
(_, attributes, __) => {
let values = {}
@@ -183,8 +185,7 @@ export default class Grammar {
Integer = r => P.regex(/[\-\+]?[0-9]+/).map(v => new IntegerEntity(v)).desc("an integer")
Guid = r => P.regex(/[0-9a-zA-Z]{32}/).map(v => new GuidEntity({ value: v }))
.desc("32 digit hexadecimal (accepts all the letters for safety) value")
Guid = r => r.HexDigit.times(32).tie().map(v => new GuidEntity({ value: v })).desc("32 digit hexadecimal value")
Identifier = r => P.regex(/\w+/).map(v => new IdentifierEntity(v))
@@ -240,7 +241,9 @@ export default class Grammar {
r.Guid,
r.LocalizedText,
r.InvariantText,
r.Reference
r.Reference,
r.Vector,
r.LinearColor,
)
PinReference = r => P.seqMap(
@@ -249,22 +252,24 @@ export default class Grammar {
r.Guid, // Goes into pinGuid
(objectName, _, pinGuid) => new PinReferenceEntity({
objectName: objectName,
pinGuid: pinGuid
pinGuid: pinGuid,
})
)
LinearColor = r => Grammar.createMultiAttributeGrammar(r, LinearColorEntity)
Vector = r => Grammar.createEntityGrammar(r, VectorEntity)
FunctionReference = r => Grammar.createMultiAttributeGrammar(r, FunctionReferenceEntity)
LinearColor = r => Grammar.createEntityGrammar(r, LinearColorEntity)
FunctionReference = r => Grammar.createEntityGrammar(r, FunctionReferenceEntity)
KeyBinding = r => P.alt(
r.Identifier.map(identifier => new KeyBindingEntity({
Key: identifier
})),
Grammar.createMultiAttributeGrammar(r, KeyBindingEntity)
Grammar.createEntityGrammar(r, KeyBindingEntity)
)
Pin = r => Grammar.createMultiAttributeGrammar(r, PinEntity)
Pin = r => Grammar.createEntityGrammar(r, PinEntity)
CustomProperties = r =>
P.string("CustomProperties")
@@ -283,7 +288,7 @@ export default class Grammar {
P
.alt(
r.CustomProperties,
Grammar.createAttributeGrammar(r, ObjectEntity)
Grammar.createPropertyGrammar(r, ObjectEntity)
)
.sepBy1(P.whitespace),
P.seq(r.MultilineWhitespace, P.string("End"), P.whitespace, P.string("Object")),
@@ -356,6 +361,6 @@ export default class Grammar {
r.LinearColorFromRGBList,
r.LinearColorFromHex,
r.LinearColorFromRGB,
r.LinearColorFromRGBA
r.LinearColorFromRGBA,
)
}

View File

@@ -74,7 +74,7 @@ export default class ISerializer {
case Function:
return this.writeValue(value(), fullKey, insideString)
case Boolean:
return Utility.FirstCapital(value.toString())
return Utility.firstCapital(value.toString())
case Number:
return value.toString()
case String:

View File

@@ -0,0 +1,50 @@
import { html } from "lit"
import IInputPinTemplate from "./IInputPinTemplate"
/**
* @typedef {import("../element/PinElement").default} PinElement
* @typedef {import("../entity/LinearColorEntity").default} LinearColorEntity}
*/
export default class VectorPinTemplate extends IInputPinTemplate {
/** @type {HTMLInputElement} */
#input
/**
* @param {PinElement} pin
* @param {Map} changedProperties
*/
firstUpdated(pin, changedProperties) {
super.firstUpdated(pin, changedProperties)
this.#input = pin.querySelector(".ueb-pin-input")
}
/**
* @param {PinElement} pin
*/
getInputs(pin) {
return [this.#input.dataset.linearColor]
}
/**
* @param {PinElement} pin
* @param {String[]} value
*/
setInputs(pin, value = []) {
}
/**
* @param {PinElement} pin
*/
renderInput(pin) {
if (pin.isInput()) {
return html`
<div class="ueb-pin-input">
<span class="ueb-pin-input-x" role="textbox" contenteditable="true" .innerText=${pin.unreactiveDefaultValue}></span>
</div>
`
}
return super.renderInput(pin)
}
}