From 90400110e2c2085b2d78248da3520e514c6e82bc Mon Sep 17 00:00:00 2001 From: barsdeveloper Date: Wed, 30 Mar 2022 21:59:41 +0200 Subject: [PATCH] JsDoc types fixed and typecheck activated --- dist/ueblueprint.js | 272 ++++++++++++++++------ js/Blueprint.js | 14 +- js/Configuration.js | 2 + js/Utility.js | 2 +- js/element/IElement.js | 4 - js/element/ISelectableDraggableElement.js | 2 +- js/element/NodeElement.js | 4 +- js/element/PinElement.js | 5 +- js/element/SelectorElement.js | 4 +- js/entity/FunctionReferenceEntity.js | 6 + js/entity/GuidEntity.js | 5 + js/entity/IEntity.js | 7 + js/entity/IdentifierEntity.js | 1 + js/entity/IntegerEntity.js | 5 +- js/entity/KeyBindingEntity.js | 7 + js/entity/LocalizedTextEntity.js | 7 + js/entity/ObjectEntity.js | 18 ++ js/entity/ObjectReferenceEntity.js | 10 + js/entity/PathSymbolEntity.js | 9 + js/entity/PinEntity.js | 50 ++-- js/entity/PinReferenceEntity.js | 6 + js/entity/TypeInitialization.js | 9 +- js/entity/VariableReferenceEntity.js | 7 + js/input/IContext.js | 5 +- js/input/common/Paste.js | 2 +- js/input/keybaord/IKeyboardShortcut.js | 2 +- js/input/mouse/IMouseClickDrag.js | 2 +- js/input/mouse/IMouseWheel.js | 1 + js/input/mouse/MouseTracking.js | 22 +- js/serialization/GeneralSerializer.js | 10 + js/serialization/Grammar.js | 37 +-- js/serialization/ObjectSerializer.js | 3 +- js/template/StringPinTemplate.js | 2 + 33 files changed, 391 insertions(+), 151 deletions(-) diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js index cfd7af9..4ad5231 100755 --- a/dist/ueblueprint.js +++ b/dist/ueblueprint.js @@ -1,3 +1,5 @@ +// @ts-check + class Configuration { static deleteNodesKeyboardKey = "Delete" static enableZoomIn = ["LeftControl", "RightControl"] // Button to enable more than 0 (1:1) zoom @@ -517,10 +519,6 @@ class IElement extends HTMLElement { /** @type {IContext[]} */ inputObjects = [] - /** - * @param {IEntity} entity The entity containing blueprint related data for this graph element - * @param {ITemplate} template The template to render this node - */ constructor(entity, template) { super(); this.blueprint = null; @@ -626,7 +624,7 @@ class SelectorElement extends IElement { /** * Create a selection rectangle starting from the specified position - * @param {number[]} initialPosition - Selection rectangle initial position (relative to the .ueb-grid element) + * @param {Number[]} initialPosition - Selection rectangle initial position (relative to the .ueb-grid element) */ startSelecting(initialPosition) { this.template.applyStartSelecting(this, initialPosition); @@ -635,7 +633,7 @@ class SelectorElement extends IElement { /** * Move selection rectagle to the specified final position. The initial position was specified by startSelecting() - * @param {number[]} finalPosition - Selection rectangle final position (relative to the .ueb-grid element) + * @param {Number[]} finalPosition - Selection rectangle final position (relative to the .ueb-grid element) */ doSelecting(finalPosition) { this.template.applyDoSelecting(this, finalPosition); @@ -790,12 +788,15 @@ class BlueprintTemplate extends ITemplate { // @ts-check +/** + * @typedef {import("../Blueprint").default} Blueprint + */ class IContext { /** @type {HTMLElement} */ target - /** @type {import("../Blueprint").default}" */ + /** @type {Blueprint} */ blueprint /** @type {Object} */ @@ -845,6 +846,9 @@ class IContext { // @ts-check +/** + * @template T + */ class TypeInitialization { static sanitize(value) { @@ -858,9 +862,9 @@ class TypeInitialization { } /** - * @param {typeof Object} type - * @param {boolean} showDefault - * @param {*} value + * @param {new () => T} type + * @param {Boolean} showDefault + * @param {any} value */ constructor(type, showDefault = true, value = undefined) { if (value === undefined) { @@ -885,7 +889,7 @@ class Utility { } static getScale(element) { - return getComputedStyle(element).getPropertyValue("--ueb-scale") + return Number(getComputedStyle(element).getPropertyValue("--ueb-scale")) } /** @@ -993,6 +997,8 @@ class Utility { class IEntity { + static attributes = {} + constructor(options = {}) { /** * @param {String[]} prefix @@ -1040,8 +1046,13 @@ class IEntity { target[property] = TypeInitialization.sanitize(defaultValue); } }; + // @ts-expect-error defineAllAttributes([], this, this.constructor.attributes); } + + empty() { + return true + } } // @ts-check @@ -1052,6 +1063,16 @@ class ObjectReferenceEntity extends IEntity { type: String, path: String, } + + constructor(options = {}) { + super(options); + /** @type {String} */ this.type; + /** @type {String} */ this.path; + } + + empty() { + return false + } } // @ts-check @@ -1062,6 +1083,12 @@ class FunctionReferenceEntity extends IEntity { MemberParent: ObjectReferenceEntity, MemberName: "", } + + constructor(options = {}) { + super(options); + /** @type {ObjectReferenceEntity} */ this.MemberParent; + /** @type {String} */ this.MemberName; + } } // @ts-check @@ -1084,6 +1111,11 @@ class GuidEntity extends IEntity { return new GuidEntity({ value: guid }) } + constructor(options = {}) { + super(options); + /** @type {String} */ this.value; + } + valueOf() { return this.value } @@ -1109,6 +1141,7 @@ class IdentifierEntity extends IEntity { }; } super(options); + /** @type {String} */ this.value; } valueOf() { @@ -1128,7 +1161,10 @@ class IntegerEntity extends IEntity { value: Number, } - constructor(options = {}) { + /** + * @param {Object | Number | String} options + */ + constructor(options = 0) { if (options.constructor == Number || options.constructor == String) { options = { value: options, @@ -1159,8 +1195,15 @@ class KeyBindingEntity extends IEntity { bCmd: false, Key: IdentifierEntity, } + constructor(options = {}) { super(options); + /** @type {String} */ this.ActionName; + /** @type {Boolean} */ this.bShift; + /** @type {Boolean} */ this.bCtrl; + /** @type {Boolean} */ this.bAlt; + /** @type {Boolean} */ this.bCmd; + /** @type {IdentifierEntity} */ this.Key; } } @@ -1174,6 +1217,13 @@ class LocalizedTextEntity extends IEntity { key: String, value: String, } + + constructor(options = {}) { + super(options); + /** @type {String} */ this.namespace; + /** @type {String} */ this.key; + /** @type {String} */ this.value; + } } // @ts-check @@ -1184,6 +1234,15 @@ class PathSymbolEntity extends IEntity { value: String, } + constructor(options = {}) { + super(options); + /** @type {String} */ this.value; + } + + valueOf() { + return this.value + } + toString() { return this.value } @@ -1197,24 +1256,16 @@ class PinReferenceEntity extends IEntity { objectName: PathSymbolEntity, pinGuid: GuidEntity, } + + constructor(options = {}) { + super(options); + /** @type {PathSymbolEntity} */ this.objectName; + /** @type {GuidEntity} */ this.pinGuid; + } } // @ts-check -/** - * @typedef {{ - * PinCategory: String, - * PinSubCategory: String, - * PinSubCategoryObject: ObjectReferenceEntity, - * PinSubCategoryMemberReference: *, - * PinValueType: String, - * ContainerType: ObjectReferenceEntity, - * bIsReference: Boolean, - * bIsConst: Boolean, - * bIsWeakPointer: Boolean, - * bIsUObjectWrapper: Boolean, - * }} PinTypeObjectType - */ class PinEntity extends IEntity { static lookbehind = "Pin" @@ -1249,6 +1300,40 @@ class PinEntity extends IEntity { bOrphanedPin: false, } + constructor(options = {}) { + super(options); + /** @type {GuidEntity} */ this.PinId; + /** @type {String} */ this.PinName; + /** @type {LocalizedTextEntity} */ this.PinFriendlyName; + /** @type {String} */ this.PinToolTip; + /** @type {String} */ this.Direction; + /** + * @type {{ + * PinCategory: String, + * PinSubCategory: String, + * PinSubCategoryObject: ObjectReferenceEntity, + * PinSubCategoryMemberReference: any, + * PinValueType: String, + * ContainerType: ObjectReferenceEntity, + * bIsReference: Boolean, + * bIsConst: Boolean, + * bIsWeakPointer: Boolean, + * bIsUObjectWrapper: Boolean, + * }} + */ this.PinType; + /** @type {PinReferenceEntity[]} */ this.LinkedTo; + /** @type {String} */ this.DefaultValue; + /** @type {String} */ this.AutogeneratedDefaultValue; + /** @type {ObjectReferenceEntity} */ this.DefaultObject; + /** @type {GuidEntity} */ this.PersistentGuid; + /** @type {Boolean} */ this.bHidden; + /** @type {Boolean} */ this.bNotConnectable; + /** @type {Boolean} */ this.bDefaultValueIsReadOnly; + /** @type {Boolean} */ this.bDefaultValueIsIgnored; + /** @type {Boolean} */ this.bAdvancedView; + /** @type {Boolean} */ this.bOrphanedPin; + } + isInput() { return !this.bHidden && this.Direction !== "EGPD_Output" } @@ -1269,6 +1354,7 @@ class PinEntity extends IEntity { /** @type {PinReferenceEntity[]} */ this.LinkedTo; const linkFound = this.LinkedTo?.find(pinReferenceEntity => { + // @ts-ignore return pinReferenceEntity.objectName == targetObjectName && pinReferenceEntity.pinGuid.valueOf() == targetPinEntity.PinId.valueOf() }); @@ -1290,6 +1376,7 @@ class PinEntity extends IEntity { /** @type {PinReferenceEntity[]} */ this.LinkedTo; const indexElement = this.LinkedTo.findIndex(pinReferenceEntity => { + // @ts-expect-error return pinReferenceEntity.objectName == targetObjectName && pinReferenceEntity.pinGuid == targetPinEntity.PinId }); @@ -1318,6 +1405,13 @@ class VariableReferenceEntity extends IEntity { MemberGuid: GuidEntity, bSelfContext: false, } + + constructor(options = {}) { + super(options); + /** @type {String} */ this.MemberName; + /** @type {GuidEntity} */ this.MemberGuid; + /** @type {Boolean} */ this.bSelfContext; + } } // @ts-check @@ -1341,6 +1435,24 @@ class ObjectEntity extends IEntity { CustomProperties: [PinEntity], } + constructor(options = {}) { + super(options); + /** @type {ObjectReferenceEntity} */ this.Class; + /** @type {String} */ this.Name; + /** @type {Boolean} */ this.bIsPureFunc; + /** @type {VariableReferenceEntity} */ this.VariableReference; + /** @type {FunctionReferenceEntity} */ this.FunctionReference; + /** @type {FunctionReferenceEntity} */ this.EventReference; + /** @type {ObjectReferenceEntity} */ this.TargetType; + /** @type {IntegerEntity} */ this.NodePosX; + /** @type {IntegerEntity} */ this.NodePosY; + /** @type {IdentifierEntity} */ this.AdvancedPinDisplay; + /** @type {GuidEntity} */ this.NodeGuid; + /** @type {IntegerEntity} */ this.ErrorType; + /** @type {String} */ this.ErrorMsg; + /** @type {PinEntity[]} */ this.CustomProperties; + } + /** * @returns {String} */ @@ -1371,7 +1483,6 @@ class Grammar { /* --- Factory --- */ - /** @param {Grammar} r */ static getGrammarForType(r, attributeType, defaultGrammar) { switch (Utility.getType(attributeType)) { case Boolean: @@ -1417,7 +1528,6 @@ class Grammar { } } - /** @param {Grammar} r */ static createAttributeGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) => r.AttributeName.skip(valueSeparator) .chain(attributeName => { @@ -1430,14 +1540,20 @@ class Grammar { ) }) - /** @param {Grammar} r */ + /** + * @template T + * @param {new () => T} entityType + * @returns {Parsimmon.Parser} + */ 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. */ P.seqMap( + // @ts-expect-error entityType.lookbehind + // @ts-expect-error ? P.seq(P.string(entityType.lookbehind), P.optWhitespace, P.string("(")) : P.string("("), Grammar.createAttributeGrammar(r, entityType) @@ -1453,33 +1569,24 @@ class Grammar { /* --- General --- */ - /** @param {Grammar} r */ InlineWhitespace = r => P.regex(/[^\S\n]+/).desc("inline whitespace") - /** @param {Grammar} r */ InlineOptWhitespace = r => P.regex(/[^\S\n]*/).desc("inline optional whitespace") - /** @param {Grammar} r */ MultilineWhitespace = r => P.regex(/[^\S\n]*\n\s*/).desc("whitespace with at least a newline") - /** @param {Grammar} r */ Null = r => P.seq(P.string("("), r.InlineOptWhitespace, P.string(")")).map(_ => null).desc("null: ()") - /** @param {Grammar} r */ Boolean = r => P.alt(P.string("True"), P.string("False")).map(v => v === "True" ? true : false) .desc("either True or False") - /** @param {Grammar} r */ Number = r => P.regex(/[\-\+]?[0-9]+(?:\.[0-9]+)?/).map(Number).desc("a number") - /** @param {Grammar} r */ Word = r => P.regex(/[a-zA-Z]+/).desc("a word") - /** @param {Grammar} r */ String = r => P.regex(/(?:[^"\\]|\\.)*/).wrap(P.string('"'), P.string('"')) .desc('string (with possibility to escape the quote using \")') - /** @param {Grammar} r */ ReferencePath = r => P.seq( P.string("/"), r.PathSymbol @@ -1492,28 +1599,21 @@ class Grammar { .tie() .desc('a path (words with possibly underscore, separated by ".", separated by "/")') - /** @param {Grammar} r */ AttributeName = r => r.Word.sepBy1(P.string(".")).tieWith(".").desc('words separated by ""') /* --- Entity --- */ - /** @param {Grammar} r */ None = r => P.string("None").map(_ => new ObjectReferenceEntity({ type: "None", path: "" })).desc("none") - /** @param {Grammar} r */ Integer = r => P.regex(/[\-\+]?[0-9]+/).map(v => new IntegerEntity(v)).desc("an integer") - /** @param {Grammar} r */ 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") - /** @param {Grammar} */ Identifier = r => P.regex(/\w+/).map(v => new IdentifierEntity(v)) - /** @param {Grammar} r */ PathSymbol = r => P.regex(/[0-9a-zA-Z_]+/).map(v => new PathSymbolEntity({ value: v })) - /** @param {Grammar} r */ Reference = r => P.alt( r.None, ...[r.ReferencePath.map(path => new ObjectReferenceEntity({ type: "", path: path }))] @@ -1533,7 +1633,6 @@ class Grammar { r.Word.map(type => new ObjectReferenceEntity({ type: type, path: "" })), ) - /** @param {Grammar} r */ LocalizedText = r => P.seqMap( P.string(LocalizedTextEntity.lookbehind).skip(P.optWhitespace).skip(P.string("(")), // Goes into _ (ignored) r.String.trim(P.optWhitespace), // Goes into namespace @@ -1549,7 +1648,6 @@ class Grammar { }) ) - /** @param {Grammar} r */ AttributeAnyValue = r => P.alt( r.Null, r.None, @@ -1561,7 +1659,6 @@ class Grammar { r.Reference, r.LocalizedText) - /** @param {Grammar} r */ PinReference = r => P.seqMap( r.PathSymbol, // Goes into objectNAme P.whitespace, // Goes into _ (ignored) @@ -1572,10 +1669,8 @@ class Grammar { }) ) - /** @param {Grammar} r */ FunctionReference = r => Grammar.createMultiAttributeGrammar(r, FunctionReferenceEntity) - /** @param {Grammar} r */ KeyBinding = r => P.alt( r.Identifier.map(identifier => new KeyBindingEntity({ Key: identifier @@ -1583,10 +1678,8 @@ class Grammar { Grammar.createMultiAttributeGrammar(r, KeyBindingEntity) ) - /** @param {Grammar} r */ Pin = r => Grammar.createMultiAttributeGrammar(r, PinEntity) - /** @param {Grammar} r */ CustomProperties = r => P.string("CustomProperties") .then(P.whitespace) @@ -1598,7 +1691,7 @@ class Grammar { Utility.objectSet(entity, ["CustomProperties"], properties, true); }) - /** @param {Grammar} r */ + /** @returns {Parsimmon.Parser} */ Object = r => P.seqMap( P.seq(P.string("Begin"), P.whitespace, P.string("Object"), P.whitespace), P @@ -1615,7 +1708,7 @@ class Grammar { } ) - /** @param {Grammar} r */ + /** @returns {Parsimmon.Parser} */ MultipleObject = r => r.Object.sepBy1(P.whitespace).trim(P.optWhitespace) } @@ -1749,8 +1842,7 @@ class ObjectSerializer extends ISerializer { readMultiple(value) { const parseResult = ISerializer.grammar.MultipleObject.parse(value); if (!parseResult.status) { - console.error("Error when trying to parse the object."); - return parseResult + throw new Error("Error when trying to parse the object.") } return parseResult.value } @@ -1803,6 +1895,7 @@ class Copy extends IContext { } // @ts-check + class IKeyboardShortcut extends IContext { /** @type {KeyBindingEntity} */ @@ -1860,7 +1953,6 @@ class IKeyboardShortcut extends IContext { || keyEntry.bAlt && e.key == "Alt" || keyEntry.bCmd && e.key == "Meta" // Unsure about this, what key is that? || Configuration.Keys[keyEntry.Key] == e.code - )) { self.unfire(); document.removeEventListener("keyup", this.keyUpHandler); @@ -1951,6 +2043,7 @@ class IMouseWheel extends IPointing { let self = this; this.#mouseWheelHandler = e => { + e.preventDefault(); const location = self.locationFromEvent(e); self.wheel(Math.sign(e.deltaY), location); }; @@ -2513,7 +2606,7 @@ class IMouseClickDrag extends IPointing { const movement = [e.movementX, e.movementY]; self.dragTo(location, movement); if (self.#trackingMouse) { - self.blueprint.entity.mousePosition = self.locationFromEvent(e); + self.blueprint.mousePosition = self.locationFromEvent(e); } }; @@ -2618,11 +2711,13 @@ class MouseTracking extends IPointing { let self = this; this.#mousemoveHandler = e => { - self.blueprint.entity.mousePosition = self.locationFromEvent(e); + e.preventDefault(); + self.blueprint.mousePosition = self.locationFromEvent(e); }; this.#trackingMouseStolenHandler = e => { if (!self.#mouseTracker) { + e.preventDefault(); this.#mouseTracker = e.detail.tracker; self.unlistenMouseMove(); } @@ -2630,6 +2725,7 @@ class MouseTracking extends IPointing { this.#trackingMouseGaveBackHandler = e => { if (self.#mouseTracker == e.detail.tracker) { + e.preventDefault(); self.#mouseTracker = null; self.listenMouseMove(); } @@ -2646,14 +2742,23 @@ class MouseTracking extends IPointing { listenEvents() { this.listenMouseMove(); - this.blueprint.addEventListener(Configuration.trackingMouseEventName.begin, this.#trackingMouseStolenHandler); - this.blueprint.addEventListener(Configuration.trackingMouseEventName.end, this.#trackingMouseGaveBackHandler); + this.blueprint.addEventListener( + Configuration.trackingMouseEventName.begin, + /** @type {(e: Event) => any} */(this.#trackingMouseStolenHandler)); + this.blueprint.addEventListener( + Configuration.trackingMouseEventName.end, + /** @type {(e: Event) => any} */(this.#trackingMouseGaveBackHandler)); } unlistenEvents() { this.unlistenMouseMove(); - this.blueprint.removeEventListener(Configuration.trackingMouseEventName.begin, this.#trackingMouseStolenHandler); - this.blueprint.removeEventListener(Configuration.trackingMouseEventName.end, this.#trackingMouseGaveBackHandler); + this.blueprint.removeEventListener( + Configuration.trackingMouseEventName.begin, + /** @type {(e: Event) => any} */(this.#trackingMouseStolenHandler)); + this.blueprint.removeEventListener( + Configuration.trackingMouseEventName.end, + /** @type {(e: Event) => any} */(this.#trackingMouseGaveBackHandler) + ); } } @@ -2710,11 +2815,11 @@ class MouseMoveNodes extends IMouseClickDrag { /** * @typedef {import("../template/SelectableDraggableTemplate").default} SelectableDraggableTemplate + * @typedef {import("../entity/IntegerEntity").default} IntegerEntity */ class ISelectableDraggableElement extends IElement { constructor(...args) { - // @ts-expect-error super(...args); this.dragObject = null; this.location = [0, 0]; @@ -2835,7 +2940,7 @@ class LinkMessageTemplate extends ITemplate { /** * @typedef {import("./PinElement").default} PinElement * @typedef {import("./LinkElement").default} LinkElement - * @typedef {(sourcePin: PinElement, sourcePin: PinElement) => String} LinkRetrieval + * @typedef {(sourcePin: PinElement, destinationPin: PinElement) => String} LinkRetrieval */ class LinkMessageElement extends IElement { @@ -3111,6 +3216,8 @@ class ExecPinTemplate extends PinTemplate { } } +// @ts-check + /** * @typedef {import("../element/PinElement").default} PinElement */ @@ -3134,8 +3241,9 @@ class StringPinTemplate extends PinTemplate { // @ts-check /** - * @typedef {import("./NodeElement").default} NodeElement * @typedef {import("../entity/GuidEntity").default} GuidEntity + * @typedef {import("../entity/PinEntity").default} PinEntity + * @typedef {import("./NodeElement").default} NodeElement */ class PinElement extends IElement { @@ -3161,7 +3269,7 @@ class PinElement extends IElement { new (PinElement.#typeTemplateMap[entity.getType()] ?? PinTemplate)() ); - /** @type {import("../entity/PinEntity").default} */ + /** @type {PinEntity} */ this.entity; /** @type {PinTemplate} */ @@ -3382,7 +3490,7 @@ class NodeElement extends ISelectableDraggableElement { /** @type {NodeTemplate} */ this.template; this.dragLinkObjects = []; - super.setLocation([this.entity.NodePosX, this.entity.NodePosY]); + super.setLocation([this.entity.NodePosX.value, this.entity.NodePosY.value]); } static fromSerializedObject(str) { @@ -3417,7 +3525,9 @@ class NodeElement extends ISelectableDraggableElement { setLocation(value = [0, 0]) { let nodeType = this.entity.NodePosX.constructor; + // @ts-expect-error this.entity.NodePosX = new nodeType(value[0]); + // @ts-expect-error this.entity.NodePosY = new nodeType(value[1]); super.setLocation(value); } @@ -3471,7 +3581,7 @@ class Paste extends IContext { if (nodes.length > 0) { this.blueprint.unselectAll(); } - let mousePosition = this.blueprint.entity.mousePosition; + let mousePosition = this.blueprint.mousePosition; this.blueprint.addGraphElement(...nodes); nodes.forEach(node => { const locationOffset = [ @@ -3553,6 +3663,8 @@ class Unfocus extends IContext { } } +// @ts-check + /** * @typedef {import("./element/PinElement").default} PinElement * @typedef {import("./entity/GuidEntity").default} GuidEntity @@ -3589,7 +3701,6 @@ class Blueprint extends IElement { /** @type {HTMLElement} */ headerElement = null focused = false - /** @type {(node: NodeElement) => BoundariesInfo} */ nodeBoundariesSupplier = node => { let rect = node.getBoundingClientRect(); let gridRect = this.nodesContainerElement.getBoundingClientRect(); @@ -3602,7 +3713,7 @@ class Blueprint extends IElement { secondarySup: (rect.bottom - gridRect.bottom) * scaleCorrection } } - /** @type {(node: NodeElement, selected: bool) => void}} */ + /** @type {(node: NodeElement, selected: Boolean) => void}} */ nodeSelectToggleFunction = (node, selected) => { node.setSelected(selected); } @@ -3638,7 +3749,7 @@ class Blueprint extends IElement { new Copy(this.getGridDOMElement(), this), new Paste(this.getGridDOMElement(), this), new KeyboardCanc(this.getGridDOMElement(), this), - new KeyboardSelectAll(this.getGridDOMElement, this), + new KeyboardSelectAll(this.getGridDOMElement(), this), new Zoom(this.getGridDOMElement(), this, { looseTarget: true, }), @@ -3666,7 +3777,6 @@ class Blueprint extends IElement { disconnectedCallback() { super.disconnectedCallback(); - setSelected(false); } getScroll() { @@ -3940,8 +4050,8 @@ class Blueprint extends IElement { } }); if (removed) { - this.nodes = [...this.querySelectorAll(NodeElement.tagName)]; - this.links = [...this.querySelectorAll(LinkElement.tagName)]; + this.nodes = /** @type {NodeElement[]} */ ([...this.querySelectorAll(NodeElement.tagName)]); + this.links = /** @type {LinkElement[]} */ ([...this.querySelectorAll(LinkElement.tagName)]); } } @@ -3951,7 +4061,7 @@ class Blueprint extends IElement { } let event = new CustomEvent(value ? "blueprint-focus" : "blueprint-unfocus"); this.focused = value; - this.dataset.focused = this.focused; + this.dataset.focused = this.focused ? "true" : "false"; if (!this.focused) { this.unselectAll(); } @@ -3971,6 +4081,11 @@ class GeneralSerializer extends ISerializer { this.wrap = wrap; } + /** + * @template T + * @param {String} value + * @returns {T} + */ read(value) { let grammar = Grammar.getGrammarForType(ISerializer.grammar, this.entityType); const parseResult = grammar.parse(value); @@ -3981,6 +4096,11 @@ class GeneralSerializer extends ISerializer { return parseResult.value } + /** + * @template T + * @param {T} object + * @returns {String} + */ write(object) { let result = this.wrap(this.subWrite([], object)); return result diff --git a/js/Blueprint.js b/js/Blueprint.js index 33a8d3a..cf318f2 100755 --- a/js/Blueprint.js +++ b/js/Blueprint.js @@ -1,3 +1,5 @@ +// @ts-check + import BlueprintTemplate from "./template/BlueprintTemplate" import Configuration from "./Configuration" import Copy from "./input/common/Copy" @@ -52,7 +54,6 @@ export default class Blueprint extends IElement { /** @type {HTMLElement} */ headerElement = null focused = false - /** @type {(node: NodeElement) => BoundariesInfo} */ nodeBoundariesSupplier = node => { let rect = node.getBoundingClientRect() let gridRect = this.nodesContainerElement.getBoundingClientRect() @@ -65,7 +66,7 @@ export default class Blueprint extends IElement { secondarySup: (rect.bottom - gridRect.bottom) * scaleCorrection } } - /** @type {(node: NodeElement, selected: bool) => void}} */ + /** @type {(node: NodeElement, selected: Boolean) => void}} */ nodeSelectToggleFunction = (node, selected) => { node.setSelected(selected) } @@ -101,7 +102,7 @@ export default class Blueprint extends IElement { new Copy(this.getGridDOMElement(), this), new Paste(this.getGridDOMElement(), this), new KeyboardCanc(this.getGridDOMElement(), this), - new KeyboardSelectAll(this.getGridDOMElement, this), + new KeyboardSelectAll(this.getGridDOMElement(), this), new Zoom(this.getGridDOMElement(), this, { looseTarget: true, }), @@ -129,7 +130,6 @@ export default class Blueprint extends IElement { disconnectedCallback() { super.disconnectedCallback() - setSelected(false) } getScroll() { @@ -403,8 +403,8 @@ export default class Blueprint extends IElement { } }) if (removed) { - this.nodes = [...this.querySelectorAll(NodeElement.tagName)] - this.links = [...this.querySelectorAll(LinkElement.tagName)] + this.nodes = /** @type {NodeElement[]} */ ([...this.querySelectorAll(NodeElement.tagName)]) + this.links = /** @type {LinkElement[]} */ ([...this.querySelectorAll(LinkElement.tagName)]) } } @@ -414,7 +414,7 @@ export default class Blueprint extends IElement { } let event = new CustomEvent(value ? "blueprint-focus" : "blueprint-unfocus") this.focused = value - this.dataset.focused = this.focused + this.dataset.focused = this.focused ? "true" : "false" if (!this.focused) { this.unselectAll() } diff --git a/js/Configuration.js b/js/Configuration.js index 26c2438..44c6dad 100755 --- a/js/Configuration.js +++ b/js/Configuration.js @@ -1,3 +1,5 @@ +// @ts-check + export default class Configuration { static deleteNodesKeyboardKey = "Delete" static enableZoomIn = ["LeftControl", "RightControl"] // Button to enable more than 0 (1:1) zoom diff --git a/js/Utility.js b/js/Utility.js index 2027caf..d8b8ee5 100755 --- a/js/Utility.js +++ b/js/Utility.js @@ -14,7 +14,7 @@ export default class Utility { } static getScale(element) { - return getComputedStyle(element).getPropertyValue("--ueb-scale") + return Number(getComputedStyle(element).getPropertyValue("--ueb-scale")) } /** diff --git a/js/element/IElement.js b/js/element/IElement.js index 8db0c9b..32d9f3c 100644 --- a/js/element/IElement.js +++ b/js/element/IElement.js @@ -23,10 +23,6 @@ export default class IElement extends HTMLElement { /** @type {IContext[]} */ inputObjects = [] - /** - * @param {IEntity} entity The entity containing blueprint related data for this graph element - * @param {ITemplate} template The template to render this node - */ constructor(entity, template) { super() this.blueprint = null diff --git a/js/element/ISelectableDraggableElement.js b/js/element/ISelectableDraggableElement.js index ef1b214..1974ae3 100644 --- a/js/element/ISelectableDraggableElement.js +++ b/js/element/ISelectableDraggableElement.js @@ -6,11 +6,11 @@ import MouseMoveNodes from "../input/mouse/MouseMoveNodes" /** * @typedef {import("../template/SelectableDraggableTemplate").default} SelectableDraggableTemplate + * @typedef {import("../entity/IntegerEntity").default} IntegerEntity */ export default class ISelectableDraggableElement extends IElement { constructor(...args) { - // @ts-expect-error super(...args) this.dragObject = null this.location = [0, 0] diff --git a/js/element/NodeElement.js b/js/element/NodeElement.js index 819b049..ad7686f 100644 --- a/js/element/NodeElement.js +++ b/js/element/NodeElement.js @@ -21,7 +21,7 @@ export default class NodeElement extends ISelectableDraggableElement { /** @type {NodeTemplate} */ this.template this.dragLinkObjects = [] - super.setLocation([this.entity.NodePosX, this.entity.NodePosY]) + super.setLocation([this.entity.NodePosX.value, this.entity.NodePosY.value]) } static fromSerializedObject(str) { @@ -56,7 +56,9 @@ export default class NodeElement extends ISelectableDraggableElement { setLocation(value = [0, 0]) { let nodeType = this.entity.NodePosX.constructor + // @ts-expect-error this.entity.NodePosX = new nodeType(value[0]) + // @ts-expect-error this.entity.NodePosY = new nodeType(value[1]) super.setLocation(value) } diff --git a/js/element/PinElement.js b/js/element/PinElement.js index 7fb0b12..1269d56 100644 --- a/js/element/PinElement.js +++ b/js/element/PinElement.js @@ -7,8 +7,9 @@ import ExecPinTemplate from "../template/ExecPinTemplate" import StringPinTemplate from "../template/StringPinTemplate" /** - * @typedef {import("./NodeElement").default} NodeElement * @typedef {import("../entity/GuidEntity").default} GuidEntity + * @typedef {import("../entity/PinEntity").default} PinEntity + * @typedef {import("./NodeElement").default} NodeElement */ export default class PinElement extends IElement { @@ -34,7 +35,7 @@ export default class PinElement extends IElement { new (PinElement.#typeTemplateMap[entity.getType()] ?? PinTemplate)() ) - /** @type {import("../entity/PinEntity").default} */ + /** @type {PinEntity} */ this.entity /** @type {PinTemplate} */ diff --git a/js/element/SelectorElement.js b/js/element/SelectorElement.js index 6f74cd3..21fb96d 100644 --- a/js/element/SelectorElement.js +++ b/js/element/SelectorElement.js @@ -17,7 +17,7 @@ export default class SelectorElement extends IElement { /** * Create a selection rectangle starting from the specified position - * @param {number[]} initialPosition - Selection rectangle initial position (relative to the .ueb-grid element) + * @param {Number[]} initialPosition - Selection rectangle initial position (relative to the .ueb-grid element) */ startSelecting(initialPosition) { this.template.applyStartSelecting(this, initialPosition) @@ -26,7 +26,7 @@ export default class SelectorElement extends IElement { /** * Move selection rectagle to the specified final position. The initial position was specified by startSelecting() - * @param {number[]} finalPosition - Selection rectangle final position (relative to the .ueb-grid element) + * @param {Number[]} finalPosition - Selection rectangle final position (relative to the .ueb-grid element) */ doSelecting(finalPosition) { this.template.applyDoSelecting(this, finalPosition) diff --git a/js/entity/FunctionReferenceEntity.js b/js/entity/FunctionReferenceEntity.js index b42478d..7c3e91a 100755 --- a/js/entity/FunctionReferenceEntity.js +++ b/js/entity/FunctionReferenceEntity.js @@ -9,4 +9,10 @@ export default class FunctionReferenceEntity extends IEntity { MemberParent: ObjectReferenceEntity, MemberName: "", } + + constructor(options = {}) { + super(options) + /** @type {ObjectReferenceEntity} */ this.MemberParent + /** @type {String} */ this.MemberName + } } diff --git a/js/entity/GuidEntity.js b/js/entity/GuidEntity.js index 77d60f8..e613dce 100755 --- a/js/entity/GuidEntity.js +++ b/js/entity/GuidEntity.js @@ -20,6 +20,11 @@ export default class GuidEntity extends IEntity { return new GuidEntity({ value: guid }) } + constructor(options = {}) { + super(options) + /** @type {String} */ this.value + } + valueOf() { return this.value } diff --git a/js/entity/IEntity.js b/js/entity/IEntity.js index 9cd29c9..7f23e0f 100644 --- a/js/entity/IEntity.js +++ b/js/entity/IEntity.js @@ -5,6 +5,8 @@ import Utility from "../Utility" export default class IEntity { + static attributes = {} + constructor(options = {}) { /** * @param {String[]} prefix @@ -52,6 +54,11 @@ export default class IEntity { target[property] = TypeInitialization.sanitize(defaultValue) } } + // @ts-expect-error defineAllAttributes([], this, this.constructor.attributes) } + + empty() { + return true + } } diff --git a/js/entity/IdentifierEntity.js b/js/entity/IdentifierEntity.js index 0f497a1..3406452 100644 --- a/js/entity/IdentifierEntity.js +++ b/js/entity/IdentifierEntity.js @@ -16,6 +16,7 @@ export default class IdentifierEntity extends IEntity { } } super(options) + /** @type {String} */ this.value } valueOf() { diff --git a/js/entity/IntegerEntity.js b/js/entity/IntegerEntity.js index 31a6d89..ea1cb5e 100755 --- a/js/entity/IntegerEntity.js +++ b/js/entity/IntegerEntity.js @@ -8,7 +8,10 @@ export default class IntegerEntity extends IEntity { value: Number, } - constructor(options = {}) { + /** + * @param {Object | Number | String} options + */ + constructor(options = 0) { if (options.constructor == Number || options.constructor == String) { options = { value: options, diff --git a/js/entity/KeyBindingEntity.js b/js/entity/KeyBindingEntity.js index 9d27404..05c33da 100644 --- a/js/entity/KeyBindingEntity.js +++ b/js/entity/KeyBindingEntity.js @@ -13,7 +13,14 @@ export default class KeyBindingEntity extends IEntity { bCmd: false, Key: IdentifierEntity, } + constructor(options = {}) { super(options) + /** @type {String} */ this.ActionName + /** @type {Boolean} */ this.bShift + /** @type {Boolean} */ this.bCtrl + /** @type {Boolean} */ this.bAlt + /** @type {Boolean} */ this.bCmd + /** @type {IdentifierEntity} */ this.Key } } diff --git a/js/entity/LocalizedTextEntity.js b/js/entity/LocalizedTextEntity.js index 9971580..d55eb6d 100755 --- a/js/entity/LocalizedTextEntity.js +++ b/js/entity/LocalizedTextEntity.js @@ -10,4 +10,11 @@ export default class LocalizedTextEntity extends IEntity { key: String, value: String, } + + constructor(options = {}) { + super(options) + /** @type {String} */ this.namespace + /** @type {String} */ this.key + /** @type {String} */ this.value + } } diff --git a/js/entity/ObjectEntity.js b/js/entity/ObjectEntity.js index 6e2883c..f66c3b2 100755 --- a/js/entity/ObjectEntity.js +++ b/js/entity/ObjectEntity.js @@ -29,6 +29,24 @@ export default class ObjectEntity extends IEntity { CustomProperties: [PinEntity], } + constructor(options = {}) { + super(options) + /** @type {ObjectReferenceEntity} */ this.Class + /** @type {String} */ this.Name + /** @type {Boolean} */ this.bIsPureFunc + /** @type {VariableReferenceEntity} */ this.VariableReference + /** @type {FunctionReferenceEntity} */ this.FunctionReference + /** @type {FunctionReferenceEntity} */ this.EventReference + /** @type {ObjectReferenceEntity} */ this.TargetType + /** @type {IntegerEntity} */ this.NodePosX + /** @type {IntegerEntity} */ this.NodePosY + /** @type {IdentifierEntity} */ this.AdvancedPinDisplay + /** @type {GuidEntity} */ this.NodeGuid + /** @type {IntegerEntity} */ this.ErrorType + /** @type {String} */ this.ErrorMsg + /** @type {PinEntity[]} */ this.CustomProperties + } + /** * @returns {String} */ diff --git a/js/entity/ObjectReferenceEntity.js b/js/entity/ObjectReferenceEntity.js index 5bd1541..7929470 100755 --- a/js/entity/ObjectReferenceEntity.js +++ b/js/entity/ObjectReferenceEntity.js @@ -8,4 +8,14 @@ export default class ObjectReferenceEntity extends IEntity { type: String, path: String, } + + constructor(options = {}) { + super(options) + /** @type {String} */ this.type + /** @type {String} */ this.path + } + + empty() { + return false + } } diff --git a/js/entity/PathSymbolEntity.js b/js/entity/PathSymbolEntity.js index 2625c76..51f9617 100755 --- a/js/entity/PathSymbolEntity.js +++ b/js/entity/PathSymbolEntity.js @@ -8,6 +8,15 @@ export default class PathSymbolEntity extends IEntity { value: String, } + constructor(options = {}) { + super(options) + /** @type {String} */ this.value + } + + valueOf() { + return this.value + } + toString() { return this.value } diff --git a/js/entity/PinEntity.js b/js/entity/PinEntity.js index 84fb7e4..012bf37 100755 --- a/js/entity/PinEntity.js +++ b/js/entity/PinEntity.js @@ -7,20 +7,6 @@ import ObjectReferenceEntity from "./ObjectReferenceEntity" import PinReferenceEntity from "./PinReferenceEntity" import TypeInitialization from "./TypeInitialization" -/** - * @typedef {{ - * PinCategory: String, - * PinSubCategory: String, - * PinSubCategoryObject: ObjectReferenceEntity, - * PinSubCategoryMemberReference: *, - * PinValueType: String, - * ContainerType: ObjectReferenceEntity, - * bIsReference: Boolean, - * bIsConst: Boolean, - * bIsWeakPointer: Boolean, - * bIsUObjectWrapper: Boolean, - * }} PinTypeObjectType - */ export default class PinEntity extends IEntity { static lookbehind = "Pin" @@ -55,6 +41,40 @@ export default class PinEntity extends IEntity { bOrphanedPin: false, } + constructor(options = {}) { + super(options) + /** @type {GuidEntity} */ this.PinId + /** @type {String} */ this.PinName + /** @type {LocalizedTextEntity} */ this.PinFriendlyName + /** @type {String} */ this.PinToolTip + /** @type {String} */ this.Direction + /** + * @type {{ + * PinCategory: String, + * PinSubCategory: String, + * PinSubCategoryObject: ObjectReferenceEntity, + * PinSubCategoryMemberReference: any, + * PinValueType: String, + * ContainerType: ObjectReferenceEntity, + * bIsReference: Boolean, + * bIsConst: Boolean, + * bIsWeakPointer: Boolean, + * bIsUObjectWrapper: Boolean, + * }} + */ this.PinType + /** @type {PinReferenceEntity[]} */ this.LinkedTo + /** @type {String} */ this.DefaultValue + /** @type {String} */ this.AutogeneratedDefaultValue + /** @type {ObjectReferenceEntity} */ this.DefaultObject + /** @type {GuidEntity} */ this.PersistentGuid + /** @type {Boolean} */ this.bHidden + /** @type {Boolean} */ this.bNotConnectable + /** @type {Boolean} */ this.bDefaultValueIsReadOnly + /** @type {Boolean} */ this.bDefaultValueIsIgnored + /** @type {Boolean} */ this.bAdvancedView + /** @type {Boolean} */ this.bOrphanedPin + } + isInput() { return !this.bHidden && this.Direction !== "EGPD_Output" } @@ -75,6 +95,7 @@ export default class PinEntity extends IEntity { /** @type {PinReferenceEntity[]} */ this.LinkedTo const linkFound = this.LinkedTo?.find(pinReferenceEntity => { + // @ts-ignore return pinReferenceEntity.objectName == targetObjectName && pinReferenceEntity.pinGuid.valueOf() == targetPinEntity.PinId.valueOf() }) @@ -96,6 +117,7 @@ export default class PinEntity extends IEntity { /** @type {PinReferenceEntity[]} */ this.LinkedTo const indexElement = this.LinkedTo.findIndex(pinReferenceEntity => { + // @ts-expect-error return pinReferenceEntity.objectName == targetObjectName && pinReferenceEntity.pinGuid == targetPinEntity.PinId }) diff --git a/js/entity/PinReferenceEntity.js b/js/entity/PinReferenceEntity.js index 219670c..c3c8aef 100755 --- a/js/entity/PinReferenceEntity.js +++ b/js/entity/PinReferenceEntity.js @@ -10,4 +10,10 @@ export default class PinReferenceEntity extends IEntity { objectName: PathSymbolEntity, pinGuid: GuidEntity, } + + constructor(options = {}) { + super(options) + /** @type {PathSymbolEntity} */ this.objectName + /** @type {GuidEntity} */ this.pinGuid + } } diff --git a/js/entity/TypeInitialization.js b/js/entity/TypeInitialization.js index c11d6f1..22880da 100755 --- a/js/entity/TypeInitialization.js +++ b/js/entity/TypeInitialization.js @@ -1,5 +1,8 @@ // @ts-check +/** + * @template T + */ export default class TypeInitialization { static sanitize(value) { @@ -13,9 +16,9 @@ export default class TypeInitialization { } /** - * @param {Object} type - * @param {boolean} showDefault - * @param {*} value + * @param {new () => T} type + * @param {Boolean} showDefault + * @param {any} value */ constructor(type, showDefault = true, value = undefined) { if (value === undefined) { diff --git a/js/entity/VariableReferenceEntity.js b/js/entity/VariableReferenceEntity.js index f1baee4..0bf6015 100755 --- a/js/entity/VariableReferenceEntity.js +++ b/js/entity/VariableReferenceEntity.js @@ -10,4 +10,11 @@ export default class VariableReferenceEntity extends IEntity { MemberGuid: GuidEntity, bSelfContext: false, } + + constructor(options = {}) { + super(options) + /** @type {String} */ this.MemberName + /** @type {GuidEntity} */ this.MemberGuid + /** @type {Boolean} */ this.bSelfContext + } } diff --git a/js/input/IContext.js b/js/input/IContext.js index f63d6c3..174fb06 100644 --- a/js/input/IContext.js +++ b/js/input/IContext.js @@ -1,11 +1,14 @@ // @ts-check +/** + * @typedef {import("../Blueprint").default} Blueprint + */ export default class IContext { /** @type {HTMLElement} */ target - /** @type {import("../Blueprint").default}" */ + /** @type {Blueprint} */ blueprint /** @type {Object} */ diff --git a/js/input/common/Paste.js b/js/input/common/Paste.js index f98617f..cd3ad83 100755 --- a/js/input/common/Paste.js +++ b/js/input/common/Paste.js @@ -40,7 +40,7 @@ export default class Paste extends IContext { if (nodes.length > 0) { this.blueprint.unselectAll() } - let mousePosition = this.blueprint.entity.mousePosition + let mousePosition = this.blueprint.mousePosition this.blueprint.addGraphElement(...nodes) nodes.forEach(node => { const locationOffset = [ diff --git a/js/input/keybaord/IKeyboardShortcut.js b/js/input/keybaord/IKeyboardShortcut.js index 14d7be2..be4eaf7 100644 --- a/js/input/keybaord/IKeyboardShortcut.js +++ b/js/input/keybaord/IKeyboardShortcut.js @@ -4,6 +4,7 @@ import Configuration from "../../Configuration" import IContext from "../IContext" import ISerializer from "../../serialization/ISerializer" import KeyBindingEntity from "../../entity/KeyBindingEntity" + export default class IKeyboardShortcut extends IContext { /** @type {KeyBindingEntity} */ @@ -61,7 +62,6 @@ export default class IKeyboardShortcut extends IContext { || keyEntry.bAlt && e.key == "Alt" || keyEntry.bCmd && e.key == "Meta" // Unsure about this, what key is that? || Configuration.Keys[keyEntry.Key] == e.code - )) { self.unfire() document.removeEventListener("keyup", this.keyUpHandler) diff --git a/js/input/mouse/IMouseClickDrag.js b/js/input/mouse/IMouseClickDrag.js index ad2d549..976f4b3 100644 --- a/js/input/mouse/IMouseClickDrag.js +++ b/js/input/mouse/IMouseClickDrag.js @@ -83,7 +83,7 @@ export default class IMouseClickDrag extends IPointing { const movement = [e.movementX, e.movementY] self.dragTo(location, movement) if (self.#trackingMouse) { - self.blueprint.entity.mousePosition = self.locationFromEvent(e) + self.blueprint.mousePosition = self.locationFromEvent(e) } } diff --git a/js/input/mouse/IMouseWheel.js b/js/input/mouse/IMouseWheel.js index f1bc693..f8a2ec5 100644 --- a/js/input/mouse/IMouseWheel.js +++ b/js/input/mouse/IMouseWheel.js @@ -22,6 +22,7 @@ export default class IMouseWheel extends IPointing { let self = this this.#mouseWheelHandler = e => { + e.preventDefault() const location = self.locationFromEvent(e) self.wheel(Math.sign(e.deltaY), location) } diff --git a/js/input/mouse/MouseTracking.js b/js/input/mouse/MouseTracking.js index 3617316..0ef4d82 100755 --- a/js/input/mouse/MouseTracking.js +++ b/js/input/mouse/MouseTracking.js @@ -24,11 +24,13 @@ export default class MouseTracking extends IPointing { let self = this this.#mousemoveHandler = e => { - self.blueprint.entity.mousePosition = self.locationFromEvent(e) + e.preventDefault() + self.blueprint.mousePosition = self.locationFromEvent(e) } this.#trackingMouseStolenHandler = e => { if (!self.#mouseTracker) { + e.preventDefault() this.#mouseTracker = e.detail.tracker self.unlistenMouseMove() } @@ -36,6 +38,7 @@ export default class MouseTracking extends IPointing { this.#trackingMouseGaveBackHandler = e => { if (self.#mouseTracker == e.detail.tracker) { + e.preventDefault() self.#mouseTracker = null self.listenMouseMove() } @@ -52,13 +55,22 @@ export default class MouseTracking extends IPointing { listenEvents() { this.listenMouseMove() - this.blueprint.addEventListener(Configuration.trackingMouseEventName.begin, this.#trackingMouseStolenHandler) - this.blueprint.addEventListener(Configuration.trackingMouseEventName.end, this.#trackingMouseGaveBackHandler) + this.blueprint.addEventListener( + Configuration.trackingMouseEventName.begin, + /** @type {(e: Event) => any} */(this.#trackingMouseStolenHandler)) + this.blueprint.addEventListener( + Configuration.trackingMouseEventName.end, + /** @type {(e: Event) => any} */(this.#trackingMouseGaveBackHandler)) } unlistenEvents() { this.unlistenMouseMove() - this.blueprint.removeEventListener(Configuration.trackingMouseEventName.begin, this.#trackingMouseStolenHandler) - this.blueprint.removeEventListener(Configuration.trackingMouseEventName.end, this.#trackingMouseGaveBackHandler) + this.blueprint.removeEventListener( + Configuration.trackingMouseEventName.begin, + /** @type {(e: Event) => any} */(this.#trackingMouseStolenHandler)) + this.blueprint.removeEventListener( + Configuration.trackingMouseEventName.end, + /** @type {(e: Event) => any} */(this.#trackingMouseGaveBackHandler) + ) } } diff --git a/js/serialization/GeneralSerializer.js b/js/serialization/GeneralSerializer.js index a9b4ae8..f0658fe 100755 --- a/js/serialization/GeneralSerializer.js +++ b/js/serialization/GeneralSerializer.js @@ -11,6 +11,11 @@ export default class GeneralSerializer extends ISerializer { this.wrap = wrap } + /** + * @template T + * @param {String} value + * @returns {T} + */ read(value) { let grammar = Grammar.getGrammarForType(ISerializer.grammar, this.entityType) const parseResult = grammar.parse(value) @@ -21,6 +26,11 @@ export default class GeneralSerializer extends ISerializer { return parseResult.value } + /** + * @template T + * @param {T} object + * @returns {String} + */ write(object) { let result = this.wrap(this.subWrite([], object)) return result diff --git a/js/serialization/Grammar.js b/js/serialization/Grammar.js index d72c1be..72e29be 100755 --- a/js/serialization/Grammar.js +++ b/js/serialization/Grammar.js @@ -20,7 +20,6 @@ export default class Grammar { /* --- Factory --- */ - /** @param {Grammar} r */ static getGrammarForType(r, attributeType, defaultGrammar) { switch (Utility.getType(attributeType)) { case Boolean: @@ -66,7 +65,6 @@ export default class Grammar { } } - /** @param {Grammar} r */ static createAttributeGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) => r.AttributeName.skip(valueSeparator) .chain(attributeName => { @@ -79,14 +77,20 @@ export default class Grammar { ) }) - /** @param {Grammar} r */ + /** + * @template T + * @param {new () => T} entityType + * @returns {Parsimmon.Parser} + */ 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. */ P.seqMap( + // @ts-expect-error entityType.lookbehind + // @ts-expect-error ? P.seq(P.string(entityType.lookbehind), P.optWhitespace, P.string("(")) : P.string("("), Grammar.createAttributeGrammar(r, entityType) @@ -102,33 +106,24 @@ export default class Grammar { /* --- General --- */ - /** @param {Grammar} r */ InlineWhitespace = r => P.regex(/[^\S\n]+/).desc("inline whitespace") - /** @param {Grammar} r */ InlineOptWhitespace = r => P.regex(/[^\S\n]*/).desc("inline optional whitespace") - /** @param {Grammar} r */ MultilineWhitespace = r => P.regex(/[^\S\n]*\n\s*/).desc("whitespace with at least a newline") - /** @param {Grammar} r */ Null = r => P.seq(P.string("("), r.InlineOptWhitespace, P.string(")")).map(_ => null).desc("null: ()") - /** @param {Grammar} r */ Boolean = r => P.alt(P.string("True"), P.string("False")).map(v => v === "True" ? true : false) .desc("either True or False") - /** @param {Grammar} r */ Number = r => P.regex(/[\-\+]?[0-9]+(?:\.[0-9]+)?/).map(Number).desc("a number") - /** @param {Grammar} r */ Word = r => P.regex(/[a-zA-Z]+/).desc("a word") - /** @param {Grammar} r */ String = r => P.regex(/(?:[^"\\]|\\.)*/).wrap(P.string('"'), P.string('"')) .desc('string (with possibility to escape the quote using \")') - /** @param {Grammar} r */ ReferencePath = r => P.seq( P.string("/"), r.PathSymbol @@ -141,28 +136,21 @@ export default class Grammar { .tie() .desc('a path (words with possibly underscore, separated by ".", separated by "/")') - /** @param {Grammar} r */ AttributeName = r => r.Word.sepBy1(P.string(".")).tieWith(".").desc('words separated by ""') /* --- Entity --- */ - /** @param {Grammar} r */ None = r => P.string("None").map(_ => new ObjectReferenceEntity({ type: "None", path: "" })).desc("none") - /** @param {Grammar} r */ Integer = r => P.regex(/[\-\+]?[0-9]+/).map(v => new IntegerEntity(v)).desc("an integer") - /** @param {Grammar} r */ 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") - /** @param {Grammar} */ Identifier = r => P.regex(/\w+/).map(v => new IdentifierEntity(v)) - /** @param {Grammar} r */ PathSymbol = r => P.regex(/[0-9a-zA-Z_]+/).map(v => new PathSymbolEntity({ value: v })) - /** @param {Grammar} r */ Reference = r => P.alt( r.None, ...[r.ReferencePath.map(path => new ObjectReferenceEntity({ type: "", path: path }))] @@ -182,7 +170,6 @@ export default class Grammar { r.Word.map(type => new ObjectReferenceEntity({ type: type, path: "" })), ) - /** @param {Grammar} r */ LocalizedText = r => P.seqMap( P.string(LocalizedTextEntity.lookbehind).skip(P.optWhitespace).skip(P.string("(")), // Goes into _ (ignored) r.String.trim(P.optWhitespace), // Goes into namespace @@ -198,7 +185,6 @@ export default class Grammar { }) ) - /** @param {Grammar} r */ AttributeAnyValue = r => P.alt( r.Null, r.None, @@ -210,7 +196,6 @@ export default class Grammar { r.Reference, r.LocalizedText) - /** @param {Grammar} r */ PinReference = r => P.seqMap( r.PathSymbol, // Goes into objectNAme P.whitespace, // Goes into _ (ignored) @@ -221,10 +206,8 @@ export default class Grammar { }) ) - /** @param {Grammar} r */ FunctionReference = r => Grammar.createMultiAttributeGrammar(r, FunctionReferenceEntity) - /** @param {Grammar} r */ KeyBinding = r => P.alt( r.Identifier.map(identifier => new KeyBindingEntity({ Key: identifier @@ -232,10 +215,8 @@ export default class Grammar { Grammar.createMultiAttributeGrammar(r, KeyBindingEntity) ) - /** @param {Grammar} r */ Pin = r => Grammar.createMultiAttributeGrammar(r, PinEntity) - /** @param {Grammar} r */ CustomProperties = r => P.string("CustomProperties") .then(P.whitespace) @@ -247,7 +228,7 @@ export default class Grammar { Utility.objectSet(entity, ["CustomProperties"], properties, true) }) - /** @param {Grammar} r */ + /** @returns {Parsimmon.Parser} */ Object = r => P.seqMap( P.seq(P.string("Begin"), P.whitespace, P.string("Object"), P.whitespace), P @@ -264,6 +245,6 @@ export default class Grammar { } ) - /** @param {Grammar} r */ + /** @returns {Parsimmon.Parser} */ MultipleObject = r => r.Object.sepBy1(P.whitespace).trim(P.optWhitespace) } diff --git a/js/serialization/ObjectSerializer.js b/js/serialization/ObjectSerializer.js index 45954a3..9429a88 100755 --- a/js/serialization/ObjectSerializer.js +++ b/js/serialization/ObjectSerializer.js @@ -38,8 +38,7 @@ export default class ObjectSerializer extends ISerializer { readMultiple(value) { const parseResult = ISerializer.grammar.MultipleObject.parse(value) if (!parseResult.status) { - console.error("Error when trying to parse the object.") - return parseResult + throw new Error("Error when trying to parse the object.") } return parseResult.value } diff --git a/js/template/StringPinTemplate.js b/js/template/StringPinTemplate.js index 2ecd35d..5dd22fa 100644 --- a/js/template/StringPinTemplate.js +++ b/js/template/StringPinTemplate.js @@ -1,3 +1,5 @@ +// @ts-check + import html from "./html" import PinTemplate from "./PinTemplate"