Prevent error from unexpected attribute

This commit is contained in:
barsdeveloper
2023-01-04 22:16:51 +01:00
parent 3c5017de91
commit af44de4539
10 changed files with 65 additions and 39 deletions

45
dist/ueblueprint.js vendored
View File

@@ -521,7 +521,7 @@ class Utility {
keys,
attribute = Utility.objectGet(/** @type {EntityConstructor} */(entity.constructor).attributes, keys)
) {
if (attribute.constructor === Object) {
if (attribute?.constructor === Object) {
return /** @type {TypeInformation} */(attribute).serialized
}
return false
@@ -834,7 +834,8 @@ class Utility {
/**
* @template {AnyValue} T
* @typedef {(new () => T) | EntityConstructor | StringConstructor | NumberConstructor | BigIntConstructor | BooleanConstructor | ArrayConstructor} AnyValueConstructor
* @typedef {(new () => T) | EntityConstructor | StringConstructor | NumberConstructor | BigIntConstructor
* | BooleanConstructor | ArrayConstructor} AnyValueConstructor
*/
class IEntity {
@@ -863,6 +864,12 @@ class IEntity {
/** @type {AttributeInformation} */
let attribute = attributes[attributeName];
if (!attribute) {
// Remember attributeName can come from the values and be not defined in the attributes
target[attributeName] = value;
continue
}
if (attribute instanceof SubAttributesDeclaration) {
target[attributeName] = {};
defineAllAttributes(
@@ -1794,6 +1801,7 @@ class PinEntity extends IEntity {
DefaultValue: {
/** @param {PinEntity} pinEntity */
type: pinEntity => pinEntity.getEntityType(true) ?? String,
nullable: true,
serialized: true,
showDefault: false,
},
@@ -2271,7 +2279,10 @@ class UnknownKeysEntity extends IEntity {
// @ts-nocheck
/** @typedef {import ("../entity/IEntity").AttributeInformation} AttributeInformation */
/**
* @typedef {import ("../entity/IEntity").AttributeInformation} AttributeInformation
* @typedef {import ("../entity/IEntity").EntityConstructor} EntityConstructor
*/
let P = Parsimmon;
@@ -2392,17 +2403,21 @@ class Grammar {
// Once the attribute name is known, look into entityType.attributes to get its type
const attributeKey = attributeName.split(".");
const attribute = Utility.objectGet(entityType.attributes, attributeKey);
let attributeValueGrammar =
attribute.constructor === Object && /** @type {AttributeInformation} */(attribute).serialized
const attributeValueGrammar = attribute // Remember attributeKey can not correspond to any attribute
? attribute.constructor === Object && /** @type {AttributeInformation} */(attribute).serialized
? r.String
: Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue);
: Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue)
: r.AttributeAnyValue;
// Returns a setter function for the attribute
return attributeValueGrammar.map(attributeValue =>
entity => Utility.objectSet(entity, attributeKey, attributeValue, true)
)
})
/** @param {Grammar} r */
/**
* @param {Grammar} r
* @param {EntityConstructor}
*/
static createEntityGrammar = (r, entityType, limitUnknownKeys = false) =>
P.seqMap(
entityType.lookbehind
@@ -2423,10 +2438,9 @@ class Grammar {
.chain(values => {
if (limitUnknownKeys) {
let unexpectedKeysCount = 0;
let totalKeys = 0;
let totalKeys = Object.keys(values);
for (const key in values) {
unexpectedKeysCount += key in entityType.attributes ? 0 : 1;
++totalKeys;
}
if (unexpectedKeysCount + 0.5 > Math.sqrt(totalKeys)) {
return P.fail()
@@ -2918,7 +2932,7 @@ class ISerializer {
showProperty(entity, object, attributeKey, attributeValue) {
const attributes = /** @type {EntityConstructor} */(this.entityType).attributes;
const attribute = Utility.objectGet(attributes, attributeKey);
if (attribute.constructor === Object) {
if (attribute?.constructor === Object) {
if (attribute.ignored) {
return false
}
@@ -2928,8 +2942,6 @@ class ISerializer {
}
}
/** @typedef {import("../element/NodeElement").default} NodeElement */
class ObjectSerializer extends ISerializer {
constructor() {
@@ -2958,7 +2970,7 @@ class ObjectSerializer extends ISerializer {
/**
* @param {String} value
* @returns {NodeElement[]}
* @returns {ObjectEntity[]}
*/
readMultiple(value) {
const parseResult = ISerializer.grammar.MultipleObject.parse(value);
@@ -3914,7 +3926,7 @@ class ElementFactory {
}
/**
* @typedef {import("../../element/NodeElement").default} NodeElement
* @typedef {import("../../entity/ObjectEntity").default} ObjectEntity
* @typedef {import("../../element/NodeElement").NodeElementConstructor} NodeElementConstructor
*/
@@ -3947,7 +3959,6 @@ class Paste extends IInput {
let left = 0;
let count = 0;
let nodes = Paste.#serializer.readMultiple(value).map(entity => {
/** @type {NodeElement} */
let node = /** @type {NodeElementConstructor} */(ElementFactory.getConstructor("ueb-node"))
.newObject(entity);
top += node.locationY;
@@ -5011,8 +5022,8 @@ class LinkElement extends IFromToPositionedElement {
}
removeMessage() {
this.linkMessageIcon = "";
this.linkMessageText = "";
this.linkMessageIcon = b;
this.linkMessageText = b;
}
setMessageConvertType() {

File diff suppressed because one or more lines are too long

View File

@@ -105,7 +105,7 @@ export default class Utility {
keys,
attribute = Utility.objectGet(/** @type {EntityConstructor} */(entity.constructor).attributes, keys)
) {
if (attribute.constructor === Object) {
if (attribute?.constructor === Object) {
return /** @type {TypeInformation} */(attribute).serialized
}
return false

View File

@@ -230,8 +230,8 @@ export default class LinkElement extends IFromToPositionedElement {
}
removeMessage() {
this.linkMessageIcon = ""
this.linkMessageText = ""
this.linkMessageIcon = nothing
this.linkMessageText = nothing
}
setMessageConvertType() {

8
js/entity/EnumEntity.js Executable file
View File

@@ -0,0 +1,8 @@
import ByteEntity from "./ByteEntity"
export default class EnumEntity extends ByteEntity {
constructor(values = 0) {
super(values)
}
}

View File

@@ -25,7 +25,8 @@ import Utility from "../Utility"
/**
* @template {AnyValue} T
* @typedef {(new () => T) | EntityConstructor | StringConstructor | NumberConstructor | BigIntConstructor | BooleanConstructor | ArrayConstructor} AnyValueConstructor
* @typedef {(new () => T) | EntityConstructor | StringConstructor | NumberConstructor | BigIntConstructor
* | BooleanConstructor | ArrayConstructor} AnyValueConstructor
*/
export default class IEntity {
@@ -54,6 +55,12 @@ export default class IEntity {
/** @type {AttributeInformation} */
let attribute = attributes[attributeName]
if (!attribute) {
// Remember attributeName can come from the values and be not defined in the attributes
target[attributeName] = value
continue
}
if (attribute instanceof SubAttributesDeclaration) {
target[attributeName] = {}
defineAllAttributes(

View File

@@ -2,10 +2,7 @@ import ElementFactory from "../../element/ElementFactory"
import IInput from "../IInput"
import ObjectSerializer from "../../serialization/ObjectSerializer"
/**
* @typedef {import("../../element/NodeElement").default} NodeElement
* @typedef {import("../../element/NodeElement").NodeElementConstructor} NodeElementConstructor
*/
/** @typedef {import("../../element/NodeElement").NodeElementConstructor} NodeElementConstructor */
export default class Paste extends IInput {
@@ -36,7 +33,6 @@ export default class Paste extends IInput {
let left = 0
let count = 0
let nodes = Paste.#serializer.readMultiple(value).map(entity => {
/** @type {NodeElement} */
let node = /** @type {NodeElementConstructor} */(ElementFactory.getConstructor("ueb-node"))
.newObject(entity)
top += node.locationY

View File

@@ -29,7 +29,10 @@ import VariableReferenceEntity from "../entity/VariableReferenceEntity"
import Vector2DEntity from "../entity/Vector2DEntity"
import VectorEntity from "../entity/VectorEntity"
/** @typedef {import ("../entity/IEntity").AttributeInformation} AttributeInformation */
/**
* @typedef {import ("../entity/IEntity").AttributeInformation} AttributeInformation
* @typedef {import ("../entity/IEntity").EntityConstructor} EntityConstructor
*/
let P = Parsimmon
@@ -150,17 +153,21 @@ export default class Grammar {
// Once the attribute name is known, look into entityType.attributes to get its type
const attributeKey = attributeName.split(".")
const attribute = Utility.objectGet(entityType.attributes, attributeKey)
let attributeValueGrammar =
attribute.constructor === Object && /** @type {AttributeInformation} */(attribute).serialized
const attributeValueGrammar = attribute // Remember attributeKey can not correspond to any attribute
? attribute.constructor === Object && /** @type {AttributeInformation} */(attribute).serialized
? r.String
: Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue)
: r.AttributeAnyValue
// Returns a setter function for the attribute
return attributeValueGrammar.map(attributeValue =>
entity => Utility.objectSet(entity, attributeKey, attributeValue, true)
)
})
/** @param {Grammar} r */
/**
* @param {Grammar} r
* @param {EntityConstructor}
*/
static createEntityGrammar = (r, entityType, limitUnknownKeys = false) =>
P.seqMap(
entityType.lookbehind
@@ -181,10 +188,9 @@ export default class Grammar {
.chain(values => {
if (limitUnknownKeys) {
let unexpectedKeysCount = 0
let totalKeys = 0
let totalKeys = Object.keys(values)
for (const key in values) {
unexpectedKeysCount += key in entityType.attributes ? 0 : 1
++totalKeys
}
if (unexpectedKeysCount + 0.5 > Math.sqrt(totalKeys)) {
return P.fail()

View File

@@ -127,7 +127,7 @@ export default class ISerializer {
showProperty(entity, object, attributeKey, attributeValue) {
const attributes = /** @type {EntityConstructor} */(this.entityType).attributes
const attribute = Utility.objectGet(attributes, attributeKey)
if (attribute.constructor === Object) {
if (attribute?.constructor === Object) {
if (attribute.ignored) {
return false
}

View File

@@ -3,8 +3,6 @@ import ObjectEntity from "../entity/ObjectEntity"
import PinEntity from "../entity/PinEntity"
import SerializerFactory from "./SerializerFactory"
/** @typedef {import("../element/NodeElement").default} NodeElement */
export default class ObjectSerializer extends ISerializer {
constructor() {
@@ -33,7 +31,7 @@ export default class ObjectSerializer extends ISerializer {
/**
* @param {String} value
* @returns {NodeElement[]}
* @returns {ObjectEntity[]}
*/
readMultiple(value) {
const parseResult = ISerializer.grammar.MultipleObject.parse(value)