From fc0e850b4bfb2edb677a2d0eefea8417588ffec2 Mon Sep 17 00:00:00 2001 From: barsdeveloper Date: Mon, 25 Apr 2022 19:59:54 +0200 Subject: [PATCH] String encode/decode --- dist/ueblueprint.js | 62 +++++++++++++++---- js/Utility.js | 23 ++++++- js/element/NodeElement.js | 4 ++ js/export.js | 3 +- js/serialization/ISerializer.js | 8 +-- js/serialization/ObjectSerializer.js | 2 +- js/serialization/PinSerializer.js | 20 ++++++ .../initializeSerializerFactory.js | 7 ++- js/template/IInputPinTemplate.js | 4 +- 9 files changed, 108 insertions(+), 25 deletions(-) create mode 100755 js/serialization/PinSerializer.js diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js index 89eafb6..04cf737 100755 --- a/dist/ueblueprint.js +++ b/dist/ueblueprint.js @@ -431,22 +431,41 @@ class Utility { /** * @param {String} value */ - static sanitizeString(value, input = false) { + static encodeInputString(value) { return value .replace(/\n$/, "") // Remove trailing newline .replaceAll("\u00A0", " ") // Replace special space symbol + .replaceAll("\r\n", String.raw`\r\n`) // Replace newline with \r\n .replaceAll("\n", String.raw`\r\n`) // Replace newline with \r\n } /** * @param {String} value */ - static renderInputString(value) { + static decodeInputString(value) { return value .replaceAll(" ", "\u00A0") // Replace special space symbol .replaceAll(String.raw`\r\n`, "
\n") // Replace newline with \r\n } + /** + * @param {String} value + */ + static encodeString(value, input = false) { + return value + .replaceAll("\u00A0", " ") // Replace special space symbol + .replaceAll("\n", String.raw`\n`) // Replace newline with \n + } + + /** + * @param {String} value + */ + static decodeString(value, input = false) { + return value + .replaceAll(" ", "\u00A0") // Replace special space symbol + .replaceAll(String.raw`\n`, "\n") // Replace newline with \n + } + /** * @param {String} value */ @@ -1263,7 +1282,7 @@ class ISerializer { this.attributeKeyPrinter = attributeKeyPrinter ?? (k => k.join(".")); } - writeValue(value) { + writeValue(value, fullKey = undefined) { if (value === null) { return "()" } @@ -1271,13 +1290,13 @@ class ISerializer { // This is an exact match (and not instanceof) to hit also primitive types (by accessing value.constructor they are converted to objects automatically) switch (value?.constructor) { case Function: - return this.writeValue(value()) + return this.writeValue(value(), fullKey) case Boolean: return Utility.FirstCapital(value.toString()) case Number: return value.toString() case String: - return `"${value}"` + return `"${Utility.encodeString(value)}"` } if (value instanceof Array) { return `(${value.map(v => serialize(v) + ",").join("")})` @@ -1308,7 +1327,7 @@ class ISerializer { + this.prefix + this.attributeKeyPrinter(fullKey) + this.attributeValueConjunctionSign - + this.writeValue(value); + + this.writeValue(value, fullKey); } } if (this.trailingSeparator && result.length && fullKey.length === 1) { @@ -1371,7 +1390,7 @@ class ObjectSerializer extends ISerializer { * @param {ObjectEntity} object */ write(object) { - let result = `Begin Object Class=${object.Class.path} Name=${this.writeValue(object.Name)} + let result = `Begin Object Class=${object.Class.path} Name=${this.writeValue(object.Name, "Name")} ${this.subWrite([], object) + object .CustomProperties.map(pin => @@ -3007,7 +3026,7 @@ class IInputPinTemplate extends PinTemplate { * @param {PinElement} pin */ getInput(pin) { - return Utility.sanitizeString( + return Utility.encodeInputString( /** @type {HTMLElement} */(pin.querySelector(".ueb-pin-input-content")).innerText ) } @@ -3027,7 +3046,7 @@ class IInputPinTemplate extends PinTemplate { return html`
- ${Utility.renderInputString(sanitizeText(pin.entity.getDefaultValue()))} + ${Utility.decodeInputString(sanitizeText(pin.entity.getDefaultValue()))}
` @@ -3464,7 +3483,11 @@ class NodeElement extends ISelectableDraggableElement { super.setLocation([this.entity.NodePosX.value, this.entity.NodePosY.value]); } + /** + * @param {String} str + */ static fromSerializedObject(str) { + str = str.trim(); let entity = SerializerFactory.getSerializer(ObjectEntity).read(str); return new NodeElement(entity) } @@ -4735,6 +4758,23 @@ class CustomSerializer extends GeneralSerializer { // @ts-check +class PinSerializer extends GeneralSerializer { + + constructor() { + super(v => `${PinEntity.lookbehind} (${v})`, PinEntity, "", ",", true); + } + + writeValue(value, fullKey) { + if (value?.constructor === String && fullKey == "DefaultValue") { + // @ts-expect-error + return `"${Utility.encodeInputString(value)}"` + } + return super.writeValue(value, fullKey) + } +} + +// @ts-check + class ToStringSerializer extends GeneralSerializer { constructor(entityType) { @@ -4757,8 +4797,8 @@ function initializeSerializerFactory() { ); SerializerFactory.registerSerializer( - PinEntity, - new GeneralSerializer(v => `${PinEntity.lookbehind} (${v})`, PinEntity, "", ",", true) + PinEntity, + new PinSerializer() ); SerializerFactory.registerSerializer( diff --git a/js/Utility.js b/js/Utility.js index a5bb1a8..a6a0a50 100755 --- a/js/Utility.js +++ b/js/Utility.js @@ -149,22 +149,41 @@ export default class Utility { /** * @param {String} value */ - static sanitizeString(value, input = false) { + static encodeInputString(value) { return value .replace(/\n$/, "") // Remove trailing newline .replaceAll("\u00A0", " ") // Replace special space symbol + .replaceAll("\r\n", String.raw`\r\n`) // Replace newline with \r\n .replaceAll("\n", String.raw`\r\n`) // Replace newline with \r\n } /** * @param {String} value */ - static renderInputString(value) { + static decodeInputString(value) { return value .replaceAll(" ", "\u00A0") // Replace special space symbol .replaceAll(String.raw`\r\n`, "
\n") // Replace newline with \r\n } + /** + * @param {String} value + */ + static encodeString(value, input = false) { + return value + .replaceAll("\u00A0", " ") // Replace special space symbol + .replaceAll("\n", String.raw`\n`) // Replace newline with \n + } + + /** + * @param {String} value + */ + static decodeString(value, input = false) { + return value + .replaceAll(" ", "\u00A0") // Replace special space symbol + .replaceAll(String.raw`\n`, "\n") // Replace newline with \n + } + /** * @param {String} value */ diff --git a/js/element/NodeElement.js b/js/element/NodeElement.js index fc4508a..5b799c6 100644 --- a/js/element/NodeElement.js +++ b/js/element/NodeElement.js @@ -23,7 +23,11 @@ export default class NodeElement extends ISelectableDraggableElement { super.setLocation([this.entity.NodePosX.value, this.entity.NodePosY.value]) } + /** + * @param {String} str + */ static fromSerializedObject(str) { + str = str.trim() let entity = SerializerFactory.getSerializer(ObjectEntity).read(str) return new NodeElement(entity) } diff --git a/js/export.js b/js/export.js index d7e83a2..bf2a8f5 100755 --- a/js/export.js +++ b/js/export.js @@ -2,11 +2,10 @@ import Blueprint from "./Blueprint" import Configuration from "./Configuration" +import initializeSerializerFactory from "./serialization/initializeSerializerFactory" import LinkElement from "./element/LinkElement" import NodeElement from "./element/NodeElement" -import initializeSerializerFactory from "./serialization/initializeSerializerFactory" - initializeSerializerFactory() export { Blueprint as Blueprint, NodeElement as NodeElement, LinkElement as LinkElement, Configuration as Configuration } diff --git a/js/serialization/ISerializer.js b/js/serialization/ISerializer.js index 266eee4..96777c5 100644 --- a/js/serialization/ISerializer.js +++ b/js/serialization/ISerializer.js @@ -20,7 +20,7 @@ export default class ISerializer { this.attributeKeyPrinter = attributeKeyPrinter ?? (k => k.join(".")) } - writeValue(value) { + writeValue(value, fullKey = undefined) { if (value === null) { return "()" } @@ -28,13 +28,13 @@ export default class ISerializer { // This is an exact match (and not instanceof) to hit also primitive types (by accessing value.constructor they are converted to objects automatically) switch (value?.constructor) { case Function: - return this.writeValue(value()) + return this.writeValue(value(), fullKey) case Boolean: return Utility.FirstCapital(value.toString()) case Number: return value.toString() case String: - return `"${value}"` + return `"${Utility.encodeString(value)}"` } if (value instanceof Array) { return `(${value.map(v => serialize(v) + ",").join("")})` @@ -65,7 +65,7 @@ export default class ISerializer { + this.prefix + this.attributeKeyPrinter(fullKey) + this.attributeValueConjunctionSign - + this.writeValue(value) + + this.writeValue(value, fullKey) } } if (this.trailingSeparator && result.length && fullKey.length === 1) { diff --git a/js/serialization/ObjectSerializer.js b/js/serialization/ObjectSerializer.js index 49a1164..884bae8 100755 --- a/js/serialization/ObjectSerializer.js +++ b/js/serialization/ObjectSerializer.js @@ -46,7 +46,7 @@ export default class ObjectSerializer extends ISerializer { * @param {ObjectEntity} object */ write(object) { - let result = `Begin Object Class=${object.Class.path} Name=${this.writeValue(object.Name)} + let result = `Begin Object Class=${object.Class.path} Name=${this.writeValue(object.Name, "Name")} ${this.subWrite([], object) + object .CustomProperties.map(pin => diff --git a/js/serialization/PinSerializer.js b/js/serialization/PinSerializer.js new file mode 100755 index 0000000..7c4f6c4 --- /dev/null +++ b/js/serialization/PinSerializer.js @@ -0,0 +1,20 @@ +// @ts-check + +import PinEntity from "../entity/PinEntity" +import Utility from "../Utility" +import GeneralSerializer from "./GeneralSerializer" + +export default class PinSerializer extends GeneralSerializer { + + constructor() { + super(v => `${PinEntity.lookbehind} (${v})`, PinEntity, "", ",", true) + } + + writeValue(value, fullKey) { + if (value?.constructor === String && fullKey == "DefaultValue") { + // @ts-expect-error + return `"${Utility.encodeInputString(value)}"` + } + return super.writeValue(value, fullKey) + } +} diff --git a/js/serialization/initializeSerializerFactory.js b/js/serialization/initializeSerializerFactory.js index 0e6c35c..d14a6b4 100755 --- a/js/serialization/initializeSerializerFactory.js +++ b/js/serialization/initializeSerializerFactory.js @@ -6,6 +6,7 @@ import GeneralSerializer from "./GeneralSerializer" import GuidEntity from "../entity/GuidEntity" import IdentifierEntity from "../entity/IdentifierEntity" import IntegerEntity from "../entity/IntegerEntity" +import InvariantTextEntity from "../entity/InvariantTextEntity" import KeyBindingEntity from "../entity/KeyBindingEntity" import LocalizedTextEntity from "../entity/LocalizedTextEntity" import ObjectEntity from "../entity/ObjectEntity" @@ -14,9 +15,9 @@ import ObjectSerializer from "./ObjectSerializer" import PathSymbolEntity from "../entity/PathSymbolEntity" import PinEntity from "../entity/PinEntity" import PinReferenceEntity from "../entity/PinReferenceEntity" +import PinSerializer from "./PinSerializer" import SerializerFactory from "./SerializerFactory" import ToStringSerializer from "./ToStringSerializer" -import InvariantTextEntity from "../entity/InvariantTextEntity" export default function initializeSerializerFactory() { @@ -26,8 +27,8 @@ export default function initializeSerializerFactory() { ) SerializerFactory.registerSerializer( - PinEntity, - new GeneralSerializer(v => `${PinEntity.lookbehind} (${v})`, PinEntity, "", ",", true) + PinEntity, + new PinSerializer() ) SerializerFactory.registerSerializer( diff --git a/js/template/IInputPinTemplate.js b/js/template/IInputPinTemplate.js index 4d0b02e..f3a2757 100644 --- a/js/template/IInputPinTemplate.js +++ b/js/template/IInputPinTemplate.js @@ -65,7 +65,7 @@ export default class IInputPinTemplate extends PinTemplate { * @param {PinElement} pin */ getInput(pin) { - return Utility.sanitizeString( + return Utility.encodeInputString( /** @type {HTMLElement} */(pin.querySelector(".ueb-pin-input-content")).innerText ) } @@ -85,7 +85,7 @@ export default class IInputPinTemplate extends PinTemplate { return html`
- ${Utility.renderInputString(sanitizeText(pin.entity.getDefaultValue()))} + ${Utility.decodeInputString(sanitizeText(pin.entity.getDefaultValue()))}
`