mirror of
https://github.com/barsdeveloper/ueblueprint.git
synced 2026-04-14 19:17:36 +08:00
Arrays elements can now be inlined
This commit is contained in:
66
cypress/e2e/legacyNodes.cy.js
Normal file
66
cypress/e2e/legacyNodes.cy.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import { generateNodeTest } from "../fixtures/testUtilities.js"
|
||||
|
||||
const tests = [
|
||||
{
|
||||
name: "ROS Change Element",
|
||||
value: String.raw`
|
||||
Begin Object Class=/Script/BlueprintGraph.K2Node_CustomEvent Name="K2Node_CustomEvent_13465"
|
||||
Begin Object Class=/Script/Engine.EdGraphPin_Deprecated Name="EdGraphPin_2859957"
|
||||
End Object
|
||||
Begin Object Class=/Script/Engine.EdGraphPin_Deprecated Name="EdGraphPin_2859956"
|
||||
End Object
|
||||
Begin Object Class=/Script/Engine.EdGraphPin_Deprecated Name="EdGraphPin_2859955"
|
||||
End Object
|
||||
Begin Object Name="EdGraphPin_2859957"
|
||||
PinName="Element"
|
||||
Direction=EGPD_Output
|
||||
PinType=(PinCategory="int")
|
||||
LinkedTo(0)=None
|
||||
LinkedTo(1)=None
|
||||
End Object
|
||||
Begin Object Name="EdGraphPin_2859956"
|
||||
PinName="then"
|
||||
Direction=EGPD_Output
|
||||
PinType=(PinCategory="exec")
|
||||
LinkedTo(0)=None
|
||||
End Object
|
||||
Begin Object Name="EdGraphPin_2859955"
|
||||
PinName="OutputDelegate"
|
||||
Direction=EGPD_Output
|
||||
PinType=(PinCategory="delegate")
|
||||
End Object
|
||||
CustomFunctionName="ROS Change Element"
|
||||
FunctionFlags=2097344
|
||||
NodePosX=-3696
|
||||
NodePosY=-128
|
||||
ErrorType=1
|
||||
NodeGuid=A7AFBC3557734BFDA0D1E917569CA6A1
|
||||
CustomProperties Pin (PinId=989B6502AF0240A28DE51122C9F3F5D7,PinName="OutputDelegate",Direction="EGPD_Output",PinType.PinCategory="delegate",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(MemberParent=/Script/Engine.BlueprintGeneratedClass'"/Temp/Untitled_1.Untitled_1_C"',MemberName="ROS Change Element",MemberGuid=A7AFBC3557734BFDA0D1E917569CA6A1),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PinType.bSerializeAsSinglePrecisionFloat=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
|
||||
CustomProperties Pin (PinId=385BD405C63F4EC5B7D55D902D37A6CE,PinName="then",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PinType.bSerializeAsSinglePrecisionFloat=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
|
||||
CustomProperties UserDefinedPin ()
|
||||
End Object
|
||||
`,
|
||||
pins: 2,
|
||||
delegate: false,
|
||||
development: false,
|
||||
},
|
||||
]
|
||||
|
||||
/** @type {Blueprint} */
|
||||
let blueprint
|
||||
|
||||
before(() => {
|
||||
cy.visit(`http://127.0.0.1:${Cypress.env("UEBLUEPRINT_TEST_SERVER_PORT")}/empty.html`, {
|
||||
onLoad: () => {
|
||||
cy.get("ueb-blueprint")
|
||||
.then(b => blueprint = b[0])
|
||||
.click(100, 300)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
tests.forEach(
|
||||
testObject => generateNodeTest(testObject, () => blueprint)
|
||||
)
|
||||
@@ -308,6 +308,11 @@ describe("Serializer", () => {
|
||||
expect(parser.parse(`Class'"/Script/Engine.KismetSystemLibrary"'`).value.constructor)
|
||||
.equals(ObjectReferenceEntity)
|
||||
)
|
||||
it("Parses ObjectReferenceEntity 2", () =>
|
||||
expect(parser.parse(`Function'"/Game/Mods/CrazyDinos/ElementalDragon/CDElementalDragon_Character_BP.SKEL_CDElementalDragon_Character_BP_C:ROS Change Element"'`)
|
||||
.value.constructor)
|
||||
.equals(ObjectReferenceEntity)
|
||||
)
|
||||
it("Parses Numbers array", () =>
|
||||
expect(parser.parse("(1,2,3,4,5,6,7,8,9)").value).to.be.deep.equal([1, 2, 3, 4, 5, 6, 7, 8, 9])
|
||||
)
|
||||
|
||||
@@ -15,6 +15,15 @@ export default class Entity4 extends IEntity {
|
||||
},
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
IEntity.defineAttributes(this.second, {
|
||||
0: {
|
||||
inlined: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
static {
|
||||
this.cleanupAttributes(this.attributes)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export default `Begin
|
||||
\${first.sierra.someObjectString} => "gamma"
|
||||
\${first.sierra.someArray} => (400,500,600,700,800,)
|
||||
\${first.sierra.someEntity} => Entity1(a=8, b=9)
|
||||
\${second(0)} => Entity1(a=1, b=2)
|
||||
\${second(0).a} => 1
|
||||
\${second(0).b} => 2
|
||||
\${second(1)} => Entity1(a=11, b=22)
|
||||
End`
|
||||
|
||||
63
dist/ueblueprint.js
vendored
63
dist/ueblueprint.js
vendored
@@ -880,8 +880,9 @@ class Utility {
|
||||
* @typedef {IEntity | String | Number | BigInt | Boolean} AnySimpleValue
|
||||
* @typedef {AnySimpleValue | AnySimpleValue[]} AnyValue
|
||||
* @typedef {(entity: IEntity) => AnyValue} ValueSupplier
|
||||
* @typedef {AnyValueConstructor<AnyValue> | AnyValueConstructor<AnyValue>[] | UnionType | UnionType[] | ComputedType} AttributeType
|
||||
* @typedef {{
|
||||
* type?: AnyValueConstructor<AnyValue> | AnyValueConstructor<AnyValue>[] | UnionType | ComputedType,
|
||||
* type?: AttributeType,
|
||||
* default?: AnyValue | ValueSupplier,
|
||||
* showDefault?: Boolean,
|
||||
* nullable?: Boolean,
|
||||
@@ -919,7 +920,16 @@ class IEntity {
|
||||
|
||||
constructor(values = {}, suppressWarns = false) {
|
||||
const Self = /** @type {EntityConstructor} */(this.constructor);
|
||||
const attributes = Self.attributes;
|
||||
let attributes = Self.attributes;
|
||||
if (values.attributes) {
|
||||
Utility.mergeArrays(Object.keys(attributes), Object.keys(values.attributes))
|
||||
.forEach(k => attributes[k] = {
|
||||
...attributes[k],
|
||||
...values.attributes[k]
|
||||
});
|
||||
IEntity.defineAttributes(this, attributes);
|
||||
}
|
||||
/** @type {AttributeDeclarations?} */ this.attributes;
|
||||
if (values.constructor !== Object && Object.keys(attributes).length === 1) {
|
||||
// Where there is just one attribute, option can be the value of that attribute
|
||||
values = {
|
||||
@@ -1078,6 +1088,22 @@ class IEntity {
|
||||
.some(/** @param {AttributeInformation} attribute */attribute => !attribute.expected)
|
||||
}
|
||||
|
||||
static getAttribute(object, attribute) {
|
||||
return this.getAttributes(object)[attribute]
|
||||
}
|
||||
|
||||
static getAttributes(object) {
|
||||
return object.attributes ?? object.constructor?.attributes ?? {}
|
||||
}
|
||||
|
||||
static defineAttributes(object, attributes) {
|
||||
Object.defineProperty(object, "attributes", {
|
||||
writable: true,
|
||||
configurable: false,
|
||||
});
|
||||
object.attributes = attributes;
|
||||
}
|
||||
|
||||
unexpectedKeys() {
|
||||
return Object.keys(this).length
|
||||
- Object.keys(/** @type {typeof IEntity} */(this.constructor).attributes).length
|
||||
@@ -3294,11 +3320,13 @@ class UnknownKeysEntity extends IEntity {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {import ("../entity/IEntity").AnyValue} AnyValue
|
||||
* @typedef {import ("../entity/IEntity").AttributeType} AttributeType
|
||||
* @typedef {import ("../entity/IEntity").AttributeInformation} AttributeInformation
|
||||
* @typedef {import ("../entity/IEntity").EntityConstructor} EntityConstructor
|
||||
*/
|
||||
/**
|
||||
* @template T
|
||||
* @template {AnyValue} T
|
||||
* @typedef {import ("../entity/IEntity").AnyValueConstructor<T>} AnyValueConstructor
|
||||
*/
|
||||
|
||||
@@ -3391,7 +3419,7 @@ class Grammar {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AnyValueConstructor<any>} type
|
||||
* @param {AttributeType} type
|
||||
* @returns {Parsimmon.Parser<any>}
|
||||
*/
|
||||
static grammarFor(
|
||||
@@ -3855,8 +3883,8 @@ class Grammar {
|
||||
})
|
||||
)
|
||||
|
||||
static inlinedArrayEntry = P.lazy(() => {
|
||||
return P.seq(
|
||||
static inlinedArrayEntry = P.lazy(() =>
|
||||
P.seq(
|
||||
this.symbol,
|
||||
this.regexMap(
|
||||
new RegExp(`\\s*\\(\\s*(\\d+)\\s*\\)\\s*\\=\\s*`),
|
||||
@@ -3869,8 +3897,16 @@ class Grammar {
|
||||
values => (values[symbol] ??= []).push(currentValue)
|
||||
)
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
static subObjectEntity = P.lazy(() =>
|
||||
this.objectEntity
|
||||
.map(object =>
|
||||
values => values["SubObject_" + object.Name] = object
|
||||
)
|
||||
)
|
||||
|
||||
/** @type {Parsimmon.Parser<ObjectEntity>} */
|
||||
static objectEntity = P.lazy(() =>
|
||||
P.seq(
|
||||
P.regex(/Begin\s+Object/),
|
||||
@@ -3879,7 +3915,9 @@ class Grammar {
|
||||
P.alt(
|
||||
this.customProperty,
|
||||
this.createAttributeGrammar(ObjectEntity),
|
||||
this.inlinedArrayEntry
|
||||
this.inlinedArrayEntry,
|
||||
// Legacy subobject
|
||||
this.subObjectEntity
|
||||
)
|
||||
)
|
||||
.map(([_0, entry]) => entry)
|
||||
@@ -4043,7 +4081,7 @@ class Serializer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} entity
|
||||
* @param {T & IEntity} entity
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
@@ -4057,7 +4095,7 @@ class Serializer {
|
||||
attributeKeyPrinter = this.attributeKeyPrinter
|
||||
) {
|
||||
let result = "";
|
||||
const attributes = /** @type {EntityConstructor} */(entity.constructor).attributes ?? {};
|
||||
const attributes = IEntity.getAttributes(entity);
|
||||
const keys = Utility.mergeArrays(
|
||||
Object.keys(attributes),
|
||||
Object.keys(entity)
|
||||
@@ -4073,6 +4111,7 @@ class Serializer {
|
||||
result += attributeSeparator;
|
||||
}
|
||||
if (attributes[key]?.inlined) {
|
||||
const keyValue = entity instanceof Array ? `(${key})` : key;
|
||||
result += this.doWrite(
|
||||
value,
|
||||
insideString,
|
||||
@@ -4081,8 +4120,8 @@ class Serializer {
|
||||
false,
|
||||
attributeValueConjunctionSign,
|
||||
attributes[key].type instanceof Array
|
||||
? k => attributeKeyPrinter(`${key}(${k})`)
|
||||
: k => attributeKeyPrinter(`${key}.${k}`),
|
||||
? k => attributeKeyPrinter(`${keyValue}${k}`)
|
||||
: k => attributeKeyPrinter(`${keyValue}.${k}`)
|
||||
);
|
||||
continue
|
||||
}
|
||||
|
||||
6
dist/ueblueprint.min.js
vendored
6
dist/ueblueprint.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -7,8 +7,9 @@ import Utility from "../Utility.js"
|
||||
* @typedef {IEntity | String | Number | BigInt | Boolean} AnySimpleValue
|
||||
* @typedef {AnySimpleValue | AnySimpleValue[]} AnyValue
|
||||
* @typedef {(entity: IEntity) => AnyValue} ValueSupplier
|
||||
* @typedef {AnyValueConstructor<AnyValue> | AnyValueConstructor<AnyValue>[] | UnionType | UnionType[] | ComputedType} AttributeType
|
||||
* @typedef {{
|
||||
* type?: AnyValueConstructor<AnyValue> | AnyValueConstructor<AnyValue>[] | UnionType | ComputedType,
|
||||
* type?: AttributeType,
|
||||
* default?: AnyValue | ValueSupplier,
|
||||
* showDefault?: Boolean,
|
||||
* nullable?: Boolean,
|
||||
@@ -46,7 +47,16 @@ export default class IEntity {
|
||||
|
||||
constructor(values = {}, suppressWarns = false) {
|
||||
const Self = /** @type {EntityConstructor} */(this.constructor)
|
||||
const attributes = Self.attributes
|
||||
let attributes = Self.attributes
|
||||
if (values.attributes) {
|
||||
Utility.mergeArrays(Object.keys(attributes), Object.keys(values.attributes))
|
||||
.forEach(k => attributes[k] = {
|
||||
...attributes[k],
|
||||
...values.attributes[k]
|
||||
})
|
||||
IEntity.defineAttributes(this, attributes)
|
||||
}
|
||||
/** @type {AttributeDeclarations?} */ this.attributes
|
||||
if (values.constructor !== Object && Object.keys(attributes).length === 1) {
|
||||
// Where there is just one attribute, option can be the value of that attribute
|
||||
values = {
|
||||
@@ -205,6 +215,22 @@ export default class IEntity {
|
||||
.some(/** @param {AttributeInformation} attribute */attribute => !attribute.expected)
|
||||
}
|
||||
|
||||
static getAttribute(object, attribute) {
|
||||
return this.getAttributes(object)[attribute]
|
||||
}
|
||||
|
||||
static getAttributes(object) {
|
||||
return object.attributes ?? object.constructor?.attributes ?? {}
|
||||
}
|
||||
|
||||
static defineAttributes(object, attributes) {
|
||||
Object.defineProperty(object, "attributes", {
|
||||
writable: true,
|
||||
configurable: false,
|
||||
})
|
||||
object.attributes = attributes
|
||||
}
|
||||
|
||||
unexpectedKeys() {
|
||||
return Object.keys(this).length
|
||||
- Object.keys(/** @type {typeof IEntity} */(this.constructor).attributes).length
|
||||
|
||||
@@ -36,11 +36,13 @@ import Vector2DEntity from "../entity/Vector2DEntity.js"
|
||||
import VectorEntity from "../entity/VectorEntity.js"
|
||||
|
||||
/**
|
||||
* @typedef {import ("../entity/IEntity").AnyValue} AnyValue
|
||||
* @typedef {import ("../entity/IEntity").AttributeType} AttributeType
|
||||
* @typedef {import ("../entity/IEntity").AttributeInformation} AttributeInformation
|
||||
* @typedef {import ("../entity/IEntity").EntityConstructor} EntityConstructor
|
||||
*/
|
||||
/**
|
||||
* @template T
|
||||
* @template {AnyValue} T
|
||||
* @typedef {import ("../entity/IEntity").AnyValueConstructor<T>} AnyValueConstructor
|
||||
*/
|
||||
|
||||
@@ -133,7 +135,7 @@ export default class Grammar {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AnyValueConstructor<any>} type
|
||||
* @param {AttributeType} type
|
||||
* @returns {Parsimmon.Parser<any>}
|
||||
*/
|
||||
static grammarFor(
|
||||
@@ -597,8 +599,8 @@ export default class Grammar {
|
||||
})
|
||||
)
|
||||
|
||||
static inlinedArrayEntry = P.lazy(() => {
|
||||
return P.seq(
|
||||
static inlinedArrayEntry = P.lazy(() =>
|
||||
P.seq(
|
||||
this.symbol,
|
||||
this.regexMap(
|
||||
new RegExp(`\\s*\\(\\s*(\\d+)\\s*\\)\\s*\\=\\s*`),
|
||||
@@ -611,8 +613,16 @@ export default class Grammar {
|
||||
values => (values[symbol] ??= []).push(currentValue)
|
||||
)
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
static subObjectEntity = P.lazy(() =>
|
||||
this.objectEntity
|
||||
.map(object =>
|
||||
values => values["SubObject_" + object.Name] = object
|
||||
)
|
||||
)
|
||||
|
||||
/** @type {Parsimmon.Parser<ObjectEntity>} */
|
||||
static objectEntity = P.lazy(() =>
|
||||
P.seq(
|
||||
P.regex(/Begin\s+Object/),
|
||||
@@ -621,7 +631,9 @@ export default class Grammar {
|
||||
P.alt(
|
||||
this.customProperty,
|
||||
this.createAttributeGrammar(ObjectEntity),
|
||||
this.inlinedArrayEntry
|
||||
this.inlinedArrayEntry,
|
||||
// Legacy subobject
|
||||
this.subObjectEntity
|
||||
)
|
||||
)
|
||||
.map(([_0, entry]) => entry)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Grammar from "./Grammar.js"
|
||||
import IEntity from "../entity/IEntity.js"
|
||||
import SerializerFactory from "./SerializerFactory.js"
|
||||
import Utility from "../Utility.js"
|
||||
|
||||
@@ -60,7 +61,7 @@ export default class Serializer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} entity
|
||||
* @param {T & IEntity} entity
|
||||
* @param {Boolean} insideString
|
||||
* @returns {String}
|
||||
*/
|
||||
@@ -74,7 +75,7 @@ export default class Serializer {
|
||||
attributeKeyPrinter = this.attributeKeyPrinter
|
||||
) {
|
||||
let result = ""
|
||||
const attributes = /** @type {EntityConstructor} */(entity.constructor).attributes ?? {}
|
||||
const attributes = IEntity.getAttributes(entity)
|
||||
const keys = Utility.mergeArrays(
|
||||
Object.keys(attributes),
|
||||
Object.keys(entity)
|
||||
@@ -83,6 +84,7 @@ export default class Serializer {
|
||||
for (const key of keys) {
|
||||
const value = entity[key]
|
||||
if (value !== undefined && this.showProperty(entity, key)) {
|
||||
const keyValue = entity instanceof Array ? `(${key})` : key
|
||||
const isSerialized = Utility.isSerialized(entity, key)
|
||||
if (first) {
|
||||
first = false
|
||||
@@ -98,13 +100,13 @@ export default class Serializer {
|
||||
false,
|
||||
attributeValueConjunctionSign,
|
||||
attributes[key].type instanceof Array
|
||||
? k => attributeKeyPrinter(`${key}(${k})`)
|
||||
: k => attributeKeyPrinter(`${key}.${k}`),
|
||||
? k => attributeKeyPrinter(`${keyValue}${k}`)
|
||||
: k => attributeKeyPrinter(`${keyValue}.${k}`)
|
||||
)
|
||||
continue
|
||||
}
|
||||
result +=
|
||||
attributeKeyPrinter(key)
|
||||
attributeKeyPrinter(keyValue)
|
||||
+ this.attributeValueConjunctionSign
|
||||
+ (
|
||||
isSerialized
|
||||
|
||||
Reference in New Issue
Block a user