From 9caea42101805182e68eb48f79671691f119a5d5 Mon Sep 17 00:00:00 2001 From: barsdeveloper Date: Sun, 17 Oct 2021 21:54:40 +0200 Subject: [PATCH] Serialization work in progress --- .gitignore | 3 +- ueblueprint.js => dist/ueblueprint.js | 414 +++++++++++++++++++------- js/{UEBlueprint.js => Blueprint.js} | 20 +- js/ETypesNames.js | 17 -- js/GraphPin.js | 70 ----- js/Guid.js | 12 +- js/Utility.js | 36 +++ js/entity/ObjectEntity.js | 3 + js/entity/PinEntity.js | 38 +++ js/export.js | 5 + js/exporting.js | 5 - js/{ => graph}/GraphEntity.js | 4 +- js/{Link.js => graph/GraphLink.js} | 6 +- js/{ => graph}/GraphNode.js | 4 +- js/{ => graph}/GraphSelector.js | 4 +- js/{ => graph}/SelectableDraggable.js | 2 +- js/input/MouseWheel.js | 2 +- js/input/Pointing.js | 2 +- js/serialization/ObjectSerialize.js | 9 + js/serialization/PinGrammar.js | 57 ++++ js/serialization/PinSerializer.js | 22 ++ js/serialization/ReferenceTypeName.js | 37 +++ js/serialization/Serializer.js | 51 ++++ js/serialization/SerializerFactory.js | 15 + js/template/BlueprintTemplate.js | 2 +- js/template/Template.js | 2 +- package.json | 16 +- rollup.config.js | 17 +- ueblueprint.html | 2 +- 29 files changed, 635 insertions(+), 242 deletions(-) rename ueblueprint.js => dist/ueblueprint.js (62%) rename js/{UEBlueprint.js => Blueprint.js} (95%) delete mode 100644 js/ETypesNames.js delete mode 100644 js/GraphPin.js create mode 100644 js/entity/ObjectEntity.js create mode 100644 js/entity/PinEntity.js create mode 100644 js/export.js delete mode 100644 js/exporting.js rename js/{ => graph}/GraphEntity.js (78%) rename js/{Link.js => graph/GraphLink.js} (83%) rename js/{ => graph}/GraphNode.js (88%) rename js/{ => graph}/GraphSelector.js (94%) rename js/{ => graph}/SelectableDraggable.js (98%) create mode 100644 js/serialization/ObjectSerialize.js create mode 100644 js/serialization/PinGrammar.js create mode 100644 js/serialization/PinSerializer.js create mode 100644 js/serialization/ReferenceTypeName.js create mode 100644 js/serialization/Serializer.js create mode 100644 js/serialization/SerializerFactory.js diff --git a/.gitignore b/.gitignore index 40b878d..ccb2c80 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules/ \ No newline at end of file +node_modules/ +package-lock.json \ No newline at end of file diff --git a/ueblueprint.js b/dist/ueblueprint.js similarity index 62% rename from ueblueprint.js rename to dist/ueblueprint.js index 9022f11..5ba8df5 100644 --- a/ueblueprint.js +++ b/dist/ueblueprint.js @@ -6,6 +6,42 @@ class Utility { static getScale(element) { return getComputedStyle(element).getPropertyValue('--ueb-scale') } + + + /** + * Sets a value in an object + * @param {String[]} keys The chained keys to access from object in order to set the value + * @param {any} value Value to be set + * @param {Object} target Object holding the data + * @param {Boolean} create Whether to create or not the key in case it doesn't exist + * @returns {Boolean} Returns true on succes, false otherwise + */ + static objectSet = (keys, value, target) => { + if (keys.length == 1) { + if (keys[0] in target) { + target[keys[0]] = value; + return true + } + } else if (keys.length > 0) { + return Utility.objectSet(keys.slice(1), value, target[keys[0]]) + } + return false + } + + + /** + * Gets a value from an object, gives defaultValue in case of failure + * @param {String[]} keys The chained keys to access from object in order to get the value + * @param {any} defaultValue Value to return in case from doesn't have it + * @param {Object} from Object holding the data + * @returns {any} The value in from corresponding to the keys or defaultValue otherwise + */ + static objectGet = (keys, defaultValue, from) => { + if (keys.length == 0 || !(keys[0] in from)) { + return defaultValue + } + return Utility.objectGet(keys.slice(1), defaultValue, from[keys[0]]) + } } class Pointing { @@ -13,7 +49,7 @@ class Pointing { constructor(target, blueprint, options) { /** @type {HTMLElement} */ this.target = target; - /** @type {import("../UEBlueprint").default}" */ + /** @type {import("../Blueprint").Blueprint}" */ this.blueprint = blueprint; this.movementSpace = this.blueprint?.getGridDOMElement() ?? document.documentElement; } @@ -167,7 +203,7 @@ class MouseWheel extends Pointing { /** * * @param {HTMLElement} target - * @param {import("../UEBlueprint").default} blueprint + * @param {import("../Blueprint").Blueprint} blueprint * @param {Object} options */ constructor(target, blueprint, options) { @@ -206,11 +242,11 @@ class Zoom extends MouseWheel { class GraphEntity extends HTMLElement { /** * - * @param {import("./template/Template").default} template The template to render this node + * @param {import("../template/Template").default} template The template to render this node */ constructor(template) { super(); - /** @type {import("./UEBlueprint").default}" */ + /** @type {import("../Blueprint").Blueprint}" */ this.blueprint = null; this.template = template; } @@ -227,7 +263,7 @@ class GraphEntity extends HTMLElement { } /** - * @typedef {import("./GraphNode").default} GraphNode + * @typedef {import("../graph/GraphNode").default} GraphNode */ class Template { @@ -269,7 +305,7 @@ class BlueprintTemplate extends Template { /** * - * @param {import("../UEBlueprint").default} element + * @param {import("../Blueprint").Blueprint} element * @returns */ viewport(element) { @@ -666,9 +702,9 @@ class GraphSelector extends GraphEntity { customElements.define('u-selector', GraphSelector); /** - * @typedef {import("./GraphNode").default} GraphNode + * @typedef {import("./graph/GraphNode").default} GraphNode */ -class UEBlueprint extends GraphEntity { +class Blueprint extends GraphEntity { insertChildren() { this.querySelector('[data-nodes]').append(...this.nodes); @@ -685,7 +721,7 @@ class UEBlueprint extends GraphEntity { this.viewportElement = null; /** @type {HTMLElement} */ this.overlayElement = null; - /** @type {HTMLElement} */ + /** @type {GraphSelector} */ this.selectorElement = null; /** @type {HTMLElement} */ this.nodesContainerElement = null; @@ -954,117 +990,22 @@ class UEBlueprint extends GraphEntity { /** * - * @param {...GraphNode} blueprintNodes + * @param {...GraphNode} graphNodes */ - addNode(...blueprintNodes) { - [...blueprintNodes].reduce( + addNode(...graphNodes) { + [...graphNodes].reduce( (s, e) => { s.push(e); return s }, this.nodes); if (this.nodesContainerElement) { - this.nodesContainerElement.append(...blueprintNodes); + this.nodesContainerElement.append(...graphNodes); } } } -customElements.define('u-blueprint', UEBlueprint); - -class Guid { - static generateGuid() { - let result = ""; - let random = new Uint32Array(4); - crypto.getRandomValues(random); - random.forEach(n => { - this.result += ('00000000' + n.toString(16).toUpperCase()).slice(-8); - }); - return result - } - - constructor(guid) { - if (guid?.constructor?.name === 'String') { - this.value = guid; - } else if (guid?.constructor?.name === 'FGuid') { - this.value = guid.value; - } else { - this.value = Guid.generateGuid(); - } - } - - toString() { - return this.value - } -} - -class GraphPin { - constructor(Options) { - this.PinId = new Guid(Options?.PinId); - this.PinName = Options?.PinName ?? ""; - this.PinToolTip = Options?.PinToolTip ?? ""; - this.PinType = { - PinCategory: Options?.PinType?.PinCategory ?? "object", - PinSubCategory: Options?.PinType?.PinSubCategory ?? "", - PinSubCategoryMemberReference: Options?.PinType?.PinSubCategoryMemberReference ?? "", - PinValueType: Options?.PinType?.PinValueType ?? "", - PinValueType: Options?.PinType?.ContainerType ?? "None", - bIsReference: Options?.PinType?.bIsReference ?? false, - bIsConst: Options?.PinType?.bIsConst ?? false, - bIsWeakPointer: Options?.PinType?.bIsWeakPointer ?? false, - bIsUObjectWrapper: Options?.PinType?.bIsUObjectWrapper ?? false - }; - this.LinkedTo = Options?.LinkedTo ?? null; - this.DefaultValue = Options?.DefaultValue ?? true; - this.AutogeneratedDefaultValue = Options?.AutogeneratedDefaultValue ?? false; - this.PersistentGuid = Options?.PersistentGuid ?? null; - this.bHidden = Options?.bHidden ?? false; - this.bNotConnectable = Options?.bNotConnectable ?? false; - this.bDefaultValueIsReadOnly = Options?.bDefaultValueIsReadOnly ?? false; - this.bDefaultValueIsIgnored = Options?.bDefaultValueIsIgnored ?? false; - this.bAdvancedView = Options?.bAdvancedView ?? false; - this.bOrphanedPin = Options?.bOrphanedPin ?? false; - } - - static serializeValue(value) { - // No quotes - if (value === null) { - return '()' - } - if (value?.constructor?.name === 'Boolean') { - return value ? 'True' : 'False' - } - if (value?.constructor?.name === 'ETypesNames' || value?.constructor?.name === 'FGuid') { - return value.toString() - } - // Quotes - if (value?.constructor?.name === 'String') { - return `"${value}"` - } - } - - static subSerialize(prefix, object) { - let result = ""; - prefix += prefix != "" ? "." : ""; - for (const property in object) { - if (object[property]?.constructor?.name === 'Object') { - result += GraphPin.subSerialize(prefix + property, object[property]); - } else { - result += `${prefix + property}=${GraphPin.serializeValue(object[property])},`; - } - } - return result - } - - serialize() { - let result = `CustomProperties Pin (${this.constructor.subSerialize('', this)})`; - return result - } - - toString() { - return this.serialize() - } - -} +customElements.define('u-blueprint', Blueprint); class Drag extends MouseClickDrag { constructor(target, blueprint, options) { @@ -1241,7 +1182,7 @@ class GraphNode extends SelectableDraggable { constructor() { super(new NodeTemplate()); - this.graphNodeName = 'N/A'; + this.graphNodeName = 'n/a'; this.inputs = []; this.outputs = []; } @@ -1260,4 +1201,255 @@ class GraphNode extends SelectableDraggable { customElements.define('u-node', GraphNode); -export { GraphNode, UEBlueprint, GraphPin as UGraphPin }; +var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + +function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +var parsimmon_umd_min = {exports: {}}; + +(function (module, exports) { +!function(n,t){module.exports=t();}("undefined"!=typeof self?self:commonjsGlobal,function(){return function(n){var t={};function r(e){if(t[e])return t[e].exports;var u=t[e]={i:e,l:!1,exports:{}};return n[e].call(u.exports,u,u.exports,r),u.l=!0,u.exports}return r.m=n,r.c=t,r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e});},r.r=function(n){Object.defineProperty(n,"__esModule",{value:!0});},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},r.p="",r(r.s=0)}([function(n,t,r){function e(n){if(!(this instanceof e))return new e(n);this._=n;}var u=e.prototype;function o(n,t){for(var r=0;r>7),buf:function(n){var t=i(function(n,t,r,e){return n.concat(r===e.length-1?Buffer.from([t,0]).readUInt16BE(0):e.readUInt16BE(r))},[],n);return Buffer.from(f(function(n){return (n<<1&65535)>>8},t))}(r.buf)};}),r}function c(){return "undefined"!=typeof Buffer}function s(){if(!c())throw new Error("Buffer global does not exist; please use webpack if you need to parse Buffers in the browser.")}function l(n){s();var t=i(function(n,t){return n+t},0,n);if(t%8!=0)throw new Error("The bits ["+n.join(", ")+"] add up to "+t+" which is not an even number of bytes; the total should be divisible by 8");var r,u=t/8,o=(r=function(n){return n>48},i(function(n,t){return n||(r(t)?t:n)},null,n));if(o)throw new Error(o+" bit range requested exceeds 48 bit (6 byte) Number max.");return new e(function(t,r){var e=u+r;return e>t.length?x(r,u.toString()+" bytes"):b(e,i(function(n,t){var r=a(t,n.buf);return {coll:n.coll.concat(r.v),buf:r.buf}},{coll:[],buf:t.slice(r,e)},n).coll)})}function p(n,t){return new e(function(r,e){return s(),e+t>r.length?x(e,t+" bytes for "+n):b(e+t,r.slice(e,e+t))})}function h(n,t){if("number"!=typeof(r=t)||Math.floor(r)!==r||t<0||t>6)throw new Error(n+" requires integer length in range [0, 6].");var r;}function d(n){return h("uintBE",n),p("uintBE("+n+")",n).map(function(t){return t.readUIntBE(0,n)})}function v(n){return h("uintLE",n),p("uintLE("+n+")",n).map(function(t){return t.readUIntLE(0,n)})}function g(n){return h("intBE",n),p("intBE("+n+")",n).map(function(t){return t.readIntBE(0,n)})}function m(n){return h("intLE",n),p("intLE("+n+")",n).map(function(t){return t.readIntLE(0,n)})}function y(n){return n instanceof e}function E(n){return "[object Array]"==={}.toString.call(n)}function w(n){return c()&&Buffer.isBuffer(n)}function b(n,t){return {status:!0,index:n,value:t,furthest:-1,expected:[]}}function x(n,t){return E(t)||(t=[t]),{status:!1,index:-1,value:null,furthest:n,expected:t}}function B(n,t){if(!t)return n;if(n.furthest>t.furthest)return n;var r=n.furthest===t.furthest?function(n,t){if(function(){if(void 0!==e._supportsSet)return e._supportsSet;var n="undefined"!=typeof Set;return e._supportsSet=n,n}()&&Array.from){for(var r=new Set(n),u=0;u=0;){if(i in r){e=r[i].line,0===o&&(o=r[i].lineStart);break}"\n"===n.charAt(i)&&(u++,0===o&&(o=i+1)),i--;}var f=e+u,a=t-o;return r[t]={line:f,lineStart:o},{offset:t,line:f+1,column:a+1}}function _(n){if(!y(n))throw new Error("not a parser: "+n)}function L(n,t){return "string"==typeof n?n.charAt(t):n[t]}function O(n){if("number"!=typeof n)throw new Error("not a number: "+n)}function k(n){if("function"!=typeof n)throw new Error("not a function: "+n)}function P(n){if("string"!=typeof n)throw new Error("not a string: "+n)}var q=2,A=3,I=8,F=5*I,M=4*I,z=" ";function R(n,t){return new Array(t+1).join(n)}function U(n,t,r){var e=t-n.length;return e<=0?n:R(r,e)+n}function W(n,t,r,e){return {from:n-t>0?n-t:0,to:n+r>e?e:n+r}}function D(n,t){var r,e,u,o,a,c=t.index,s=c.offset,l=1;if(s===n.length)return "Got the end of the input";if(w(n)){var p=s-s%I,h=s-p,d=W(p,F,M+I,n.length),v=f(function(n){return f(function(n){return U(n.toString(16),2,"0")},n)},function(n,t){var r=n.length,e=[],u=0;if(r<=t)return [n.slice()];for(var o=0;o=4&&(r+=1),l=2,u=f(function(n){return n.length<=4?n.join(" "):n.slice(0,4).join(" ")+" "+n.slice(4).join(" ")},v),(a=(8*(o.to>0?o.to-1:o.to)).toString(16).length)<2&&(a=2);}else {var g=n.split(/\r\n|[\n\r\u2028\u2029]/);r=c.column-1,e=c.line-1,o=W(e,q,A,g.length),u=g.slice(o.from,o.to),a=o.to.toString().length;}var m=e-o.from;return w(n)&&(a=(8*(o.to>0?o.to-1:o.to)).toString(16).length)<2&&(a=2),i(function(t,e,u){var i,f=u===m,c=f?"> ":z;return i=w(n)?U((8*(o.from+u)).toString(16),a,"0"):U((o.from+u+1).toString(),a," "),[].concat(t,[c+i+" | "+e],f?[z+R(" ",a)+" | "+U("",r," ")+R("^",l)]:[])},[],u).join("\n")}function N(n,t){return ["\n","-- PARSING FAILED "+R("-",50),"\n\n",D(n,t),"\n\n",(r=t.expected,1===r.length?"Expected:\n\n"+r[0]:"Expected one of the following: \n\n"+r.join(", ")),"\n"].join("");var r;}function G(n){return void 0!==n.flags?n.flags:[n.global?"g":"",n.ignoreCase?"i":"",n.multiline?"m":"",n.unicode?"u":"",n.sticky?"y":""].join("")}function C(){for(var n=[].slice.call(arguments),t=n.length,r=0;r=2?O(t):t=0;var r=function(n){return RegExp("^(?:"+n.source+")",G(n))}(n),u=""+n;return e(function(n,e){var o=r.exec(n.slice(e));if(o){if(0<=t&&t<=o.length){var i=o[0],f=o[t];return b(e+i.length,f)}return x(e,"valid match group (0 to "+o.length+") in "+u)}return x(e,u)})}function X(n){return e(function(t,r){return b(r,n)})}function Y(n){return e(function(t,r){return x(r,n)})}function Z(n){if(y(n))return e(function(t,r){var e=n._(t,r);return e.index=r,e.value="",e});if("string"==typeof n)return Z(K(n));if(n instanceof RegExp)return Z(Q(n));throw new Error("not a string, regexp, or parser: "+n)}function $(n){return _(n),e(function(t,r){var e=n._(t,r),u=t.slice(r,e.index);return e.status?x(r,'not "'+u+'"'):b(r,null)})}function nn(n){return k(n),e(function(t,r){var e=L(t,r);return r=n.length?x(t,"any character/byte"):b(t+1,L(n,t))}),on=e(function(n,t){return b(n.length,n.slice(t))}),fn=e(function(n,t){return t=0}).desc(t)},e.optWhitespace=pn,e.Parser=e,e.range=function(n,t){return nn(function(r){return n<=r&&r<=t}).desc(n+"-"+t)},e.regex=Q,e.regexp=Q,e.sepBy=V,e.sepBy1=H,e.seq=C,e.seqMap=J,e.seqObj=function(){for(var n,t={},r=0,u=(n=arguments,Array.prototype.slice.call(n)),o=u.length,i=0;i255)throw new Error("Value specified to byte constructor ("+n+"=0x"+n.toString(16)+") is larger in value than a single byte.");var t=(n>15?"0x":"0x0")+n.toString(16);return e(function(r,e){var u=L(r,e);return u===n?b(e+1,u):x(e,t)})},buffer:function(n){return p("buffer",n).map(function(n){return Buffer.from(n)})},encodedString:function(n,t){return p("string",t).map(function(t){return t.toString(n)})},uintBE:d,uint8BE:d(1),uint16BE:d(2),uint32BE:d(4),uintLE:v,uint8LE:v(1),uint16LE:v(2),uint32LE:v(4),intBE:g,int8BE:g(1),int16BE:g(2),int32BE:g(4),intLE:m,int8LE:m(1),int16LE:m(2),int32LE:m(4),floatBE:p("floatBE",4).map(function(n){return n.readFloatBE(0)}),floatLE:p("floatLE",4).map(function(n){return n.readFloatLE(0)}),doubleBE:p("doubleBE",8).map(function(n){return n.readDoubleBE(0)}),doubleLE:p("doubleLE",8).map(function(n){return n.readDoubleLE(0)})},n.exports=e;}])}); +}(parsimmon_umd_min)); + +var Parsimmon = /*@__PURE__*/getDefaultExportFromCjs(parsimmon_umd_min.exports); + +class Guid { + static generateGuid(random) { + let result = ""; + let values = new Uint32Array(4); + if (random === true) { + crypto.getRandomValues(values); + } + values.forEach(n => { + this.result += ('00000000' + n.toString(16).toUpperCase()).slice(-8); + }); + return result + } + + constructor(guid) { + if (guid?.constructor?.name === 'String') { + this.value = guid; + } else if (guid?.constructor?.name === 'FGuid') { + this.value = guid.value; + } else { + this.value = Guid.generateGuid(guid === true); + } + } + + toString() { + return this.value + } +} + +class ReferenceTypeName { + + static Class = new ReferenceTypeName("Class") + static None = new ReferenceTypeName("None") + static ReferenceName = ['Class'] + + /** + * + * @param {String} reference + * @returns + */ + static splitReference(reference) { + const pathBegin = reference.search(/['"]/); + const referenceType = reference.substr(0, pathBegin > 0 ? pathBegin : undefined).trim(); // reference example Class'"/Script/Engine.PlayerCameraManager"' + const referencePath = pathBegin > 0 ? reference.substr(pathBegin).trim() : ""; + switch (referenceType) { + case "None": + if (referencePath.length > 0) { + return false // None cannot have a path + } + case "Class": + return [referenceType, referencePath] + default: + return false + } + } + + /** + * + * @param {String} reference + */ + constructor(reference) { + reference = ReferenceTypeName.splitReference(reference); + if (!reference) { + throw new Error('Invalid reference: ' + reference) + } + this.value = reference[0] + reference[1]; + } + + toString() { + return this.value + } +} + +class PinEntity { + static optionalKeys = ['Direction'] + constructor(options = {}) { + const getOrFalse = (keys) => Utility.objectGet(keys, false, options); + const getOrEmptyString = (keys) => Utility.objectGet(keys, "", options); + this.PinId = new Guid(Utility.objectGet(["PinId"], true, options)); + this.PinName = getOrEmptyString(["PinName"]); + this.PinToolTip = getOrEmptyString(["PinToolTip"]); + this.Direction = getOrEmptyString(["Direction"]); + this.PinType = { + PinCategory: getOrEmptyString(["PinType", "PinCategory"]), + PinSubCategory: getOrEmptyString(["PinType", "PinSubCategory"]), + PinSubCategoryObject: Utility.objectGet(["PinType", "PinSubCategoryObject"], ReferenceTypeName.None, options), + PinSubCategoryMemberReference: Utility.objectGet(["PinType", "PinSubCategoryMemberReference"], null, options), + PinValueType: getOrFalse(["PinType", "PinValueType"]), + ContainerType: Utility.objectGet(["PinType", "ContainerType"], ReferenceTypeName.None, options), + bIsReference: getOrFalse(["PinType", "bIsReference"]), + bIsConst: getOrFalse(["PinType", "bIsConst"]), + bIsWeakPointer: getOrFalse(["PinType", "bIsWeakPointer"]), + bIsUObjectWrapper: getOrFalse(["PinType", "bIsUObjectWrapper"]) + }; + this.LinkedTo = Utility.objectGet(["LinkedTo"], null, options); + this.DefaultValue = getOrFalse(["DefaultValue"]); + this.AutogeneratedDefaultValue = getOrFalse(["AutogeneratedDefaultValue"]); + this.PersistentGuid = new Guid(getOrFalse(["PersistentGuid"])); + this.bHidden = getOrFalse(["bHidden"]); + this.bNotConnectable = getOrFalse(["bNotConnectable"]); + this.bDefaultValueIsReadOnly = getOrFalse(["bDefaultValueIsReadOnly"]); + this.bDefaultValueIsIgnored = getOrFalse(["bDefaultValueIsIgnored"]); + this.bAdvancedView = getOrFalse(["bAdvancedView"]); + this.bOrphanedPin = getOrFalse(["bOrphanedPin"]); + } + +} + +function checkValidKeys(obj, args) { + if (args.length == 0) { + return true + } + return args[0] in obj && checkValidKeys(obj[args[0]], args.slice(1)) +} + +let P = Parsimmon; + +class PinGrammar { + static pinEntity = new PinEntity() + Null = (_) => P.string("()").map(() => null).desc("null value.") + None = (_) => P.string("None").map(() => new ReferenceTypeName("None")).desc('None value') + ReferenceName = () => P.alt(...ReferenceTypeName.ReferenceName.map(name => P.string(name))) + Word = (_) => P.regex(/[a-zA-Z]+/) + Guid = (_) => P.regex(/[0-9a-zA-Z]{32}/).desc("a 32 digit hexadecimal value") + String = (_) => P.regex(/(?:[^"\\]|\\")*/).wrap(P.string('"'), P.string('"')).desc('a string value (with possibility to escale the quote symbol " using \")') + Boolean = (_) => P.string("True").or(P.string("False")).map(v => v === "True" ? true : false).desc("either True or False") + AttributeName = (r) => r.Word + .sepBy1(P.string(".")) + .assert(attr => checkValidKeys(PinGrammar.pinEntity, attr), "a valid pin attribute (check the class PinEntity)") + .tieWith(".") + AttributeValue = (r) => P.alt(r.Null, r.None, r.Boolean, r.String, r.Guid) + Attribute = (r) => P.seqMap( + r.AttributeName, + P.string("=").trim(P.optWhitespace), + r.AttributeValue, + /** + * + * @param {String} name The key PinEntity + * @param {*} _ + * @param {*} value + * @returns + */ + (name, _, value) => + /** + * Sets the property name name in the object pinEntity to the value provided + * @param {PinEntity} pinEntity + */ + (pinEntity) => Utility.objectSet(name.split('.'), value, pinEntity) + ) + Pin = (r) => { + return P.seqObj( + P.string("Pin"), + P.optWhitespace, + P.string("("), + [ + "attributes", + r.Attribute + .trim(P.optWhitespace) + .sepBy(P.string(",")) + .skip(P.regex(/,?/).then(P.optWhitespace)) // Optional trailing comma + ], + P.string(')') + ).map(object => { + let result = new PinEntity(); + object.attributes.forEach(attributeSetter => attributeSetter(result)); + return result + }) + } +} + +class Serializer { + + static writeValue(value) { + if (value?.constructor?.name === 'Function') { + return this.writeValue(value()) + } + // No quotes + if (value === null) { + return '()' + } + if (value?.constructor?.name === 'Boolean') { + return value ? 'True' : 'False' + } + if (value?.constructor?.name === 'ETypesNames' || value?.constructor?.name === 'FGuid') { + return value.toString() + } + // Quotes + if (value?.constructor?.name === 'String') { + return `"${value}"` + } + } + + static subWrite(prefix, object) { + let result = ""; + prefix += prefix != "" ? "." : ""; + const fullPropertyName = prefix + property; + for (const property in object) { + if (object[property]?.constructor?.name === 'Object') { + result += Serializer.subWrite(fullPropertyName, object[property]); + } else if (!object.constructor.optionalKeys.contains(fullPropertyName)) { + result += `${fullPropertyName}=${Serializer.writeValue(object[property])},`; + } + } + return result + } + + /** + * + * @param {String} value + */ + read(value) { + //Parsimmon.length + } + + write(object) { + return '' + } +} + +class PinSerializer extends Serializer { + + static pinGrammar = Parsimmon.createLanguage(new PinGrammar()) + + read(value) { + const parseResult = PinSerializer.pinGrammar.Pin.parse(value); + if (!parseResult.status) { + console.error("Error when trying to parse the pin."); + return parseResult + } + return parseResult.value + } + + write(object) { + let result = `Pin (${Serializer.subWrite('', object)})`; + return result + } +} + +export { GraphNode, PinSerializer, Blueprint as UEBlueprint }; diff --git a/js/UEBlueprint.js b/js/Blueprint.js similarity index 95% rename from js/UEBlueprint.js rename to js/Blueprint.js index d67a891..1843cad 100644 --- a/js/UEBlueprint.js +++ b/js/Blueprint.js @@ -2,14 +2,14 @@ import Utility from "./Utility" import DragScroll from "./input/DragScroll" import Select from "./input/Select" import Zoom from "./input/Zoom" -import GraphEntity from "./GraphEntity" +import GraphEntity from "./graph/GraphEntity" import BlueprintTemplate from "./template/BlueprintTemplate" -import GraphSelector from "./GraphSelector" +import GraphSelector from "./graph/GraphSelector" /** - * @typedef {import("./GraphNode").default} GraphNode + * @typedef {import("./graph/GraphNode").default} GraphNode */ -export default class UEBlueprint extends GraphEntity { +export default class Blueprint extends GraphEntity { insertChildren() { this.querySelector('[data-nodes]').append(...this.nodes) @@ -26,7 +26,7 @@ export default class UEBlueprint extends GraphEntity { this.viewportElement = null /** @type {HTMLElement} */ this.overlayElement = null - /** @type {HTMLElement} */ + /** @type {GraphSelector} */ this.selectorElement = null /** @type {HTMLElement} */ this.nodesContainerElement = null @@ -295,19 +295,19 @@ export default class UEBlueprint extends GraphEntity { /** * - * @param {...GraphNode} blueprintNodes + * @param {...GraphNode} graphNodes */ - addNode(...blueprintNodes) { - [...blueprintNodes].reduce( + addNode(...graphNodes) { + [...graphNodes].reduce( (s, e) => { s.push(e) return s }, this.nodes) if (this.nodesContainerElement) { - this.nodesContainerElement.append(...blueprintNodes) + this.nodesContainerElement.append(...graphNodes) } } } -customElements.define('u-blueprint', UEBlueprint) +customElements.define('u-blueprint', Blueprint) diff --git a/js/ETypesNames.js b/js/ETypesNames.js deleted file mode 100644 index 1066bc8..0000000 --- a/js/ETypesNames.js +++ /dev/null @@ -1,17 +0,0 @@ -export default class ETypesNames { - - constructor(type) { - switch (type) { - case 'Class': - case 'None': - this.value = type - break - default: - throw new Error('Unexpected type name') - } - } - - toString() { - return this.value - } -} \ No newline at end of file diff --git a/js/GraphPin.js b/js/GraphPin.js deleted file mode 100644 index 8d20ddb..0000000 --- a/js/GraphPin.js +++ /dev/null @@ -1,70 +0,0 @@ -import Guid from "./Guid"; - -export default class GraphPin { - constructor(Options) { - this.PinId = new Guid(Options?.PinId) - this.PinName = Options?.PinName ?? "" - this.PinToolTip = Options?.PinToolTip ?? "" - this.PinType = { - PinCategory: Options?.PinType?.PinCategory ?? "object", - PinSubCategory: Options?.PinType?.PinSubCategory ?? "", - PinSubCategoryMemberReference: Options?.PinType?.PinSubCategoryMemberReference ?? "", - PinValueType: Options?.PinType?.PinValueType ?? "", - PinValueType: Options?.PinType?.ContainerType ?? "None", - bIsReference: Options?.PinType?.bIsReference ?? false, - bIsConst: Options?.PinType?.bIsConst ?? false, - bIsWeakPointer: Options?.PinType?.bIsWeakPointer ?? false, - bIsUObjectWrapper: Options?.PinType?.bIsUObjectWrapper ?? false - } - this.LinkedTo = Options?.LinkedTo ?? null - this.DefaultValue = Options?.DefaultValue ?? true - this.AutogeneratedDefaultValue = Options?.AutogeneratedDefaultValue ?? false - this.PersistentGuid = Options?.PersistentGuid ?? null - this.bHidden = Options?.bHidden ?? false - this.bNotConnectable = Options?.bNotConnectable ?? false - this.bDefaultValueIsReadOnly = Options?.bDefaultValueIsReadOnly ?? false - this.bDefaultValueIsIgnored = Options?.bDefaultValueIsIgnored ?? false - this.bAdvancedView = Options?.bAdvancedView ?? false - this.bOrphanedPin = Options?.bOrphanedPin ?? false - } - - static serializeValue(value) { - // No quotes - if (value === null) { - return '()' - } - if (value?.constructor?.name === 'Boolean') { - return value ? 'True' : 'False' - } - if (value?.constructor?.name === 'ETypesNames' || value?.constructor?.name === 'FGuid') { - return value.toString() - } - // Quotes - if (value?.constructor?.name === 'String') { - return `"${value}"` - } - } - - static subSerialize(prefix, object) { - let result = "" - prefix += prefix != "" ? "." : "" - for (const property in object) { - if (object[property]?.constructor?.name === 'Object') { - result += GraphPin.subSerialize(prefix + property, object[property]) - } else { - result += `${prefix + property}=${GraphPin.serializeValue(object[property])},` - } - } - return result - } - - serialize() { - let result = `CustomProperties Pin (${this.constructor.subSerialize('', this)})` - return result - } - - toString() { - return this.serialize() - } - -} \ No newline at end of file diff --git a/js/Guid.js b/js/Guid.js index ee482f7..7783928 100644 --- a/js/Guid.js +++ b/js/Guid.js @@ -1,9 +1,11 @@ export default class Guid { - static generateGuid() { + static generateGuid(random) { let result = "" - let random = new Uint32Array(4); - crypto.getRandomValues(random) - random.forEach(n => { + let values = new Uint32Array(4); + if (random === true) { + crypto.getRandomValues(values) + } + values.forEach(n => { this.result += ('00000000' + n.toString(16).toUpperCase()).slice(-8) }) return result @@ -15,7 +17,7 @@ export default class Guid { } else if (guid?.constructor?.name === 'FGuid') { this.value = guid.value } else { - this.value = Guid.generateGuid() + this.value = Guid.generateGuid(guid === true) } } diff --git a/js/Utility.js b/js/Utility.js index b348b94..f729c80 100644 --- a/js/Utility.js +++ b/js/Utility.js @@ -6,4 +6,40 @@ export default class Utility { static getScale(element) { return getComputedStyle(element).getPropertyValue('--ueb-scale') } + + + /** + * Sets a value in an object + * @param {String[]} keys The chained keys to access from object in order to set the value + * @param {any} value Value to be set + * @param {Object} target Object holding the data + * @param {Boolean} create Whether to create or not the key in case it doesn't exist + * @returns {Boolean} Returns true on succes, false otherwise + */ + static objectSet = (keys, value, target) => { + if (keys.length == 1) { + if (keys[0] in target) { + target[keys[0]] = value + return true + } + } else if (keys.length > 0) { + return Utility.objectSet(keys.slice(1), value, target[keys[0]]) + } + return false + } + + + /** + * Gets a value from an object, gives defaultValue in case of failure + * @param {String[]} keys The chained keys to access from object in order to get the value + * @param {any} defaultValue Value to return in case from doesn't have it + * @param {Object} from Object holding the data + * @returns {any} The value in from corresponding to the keys or defaultValue otherwise + */ + static objectGet = (keys, defaultValue, from) => { + if (keys.length == 0 || !(keys[0] in from)) { + return defaultValue + } + return Utility.objectGet(keys.slice(1), defaultValue, from[keys[0]]) + } } \ No newline at end of file diff --git a/js/entity/ObjectEntity.js b/js/entity/ObjectEntity.js new file mode 100644 index 0000000..ec0c6f8 --- /dev/null +++ b/js/entity/ObjectEntity.js @@ -0,0 +1,3 @@ +export default class ObjectEntity { + +} \ No newline at end of file diff --git a/js/entity/PinEntity.js b/js/entity/PinEntity.js new file mode 100644 index 0000000..7a92900 --- /dev/null +++ b/js/entity/PinEntity.js @@ -0,0 +1,38 @@ +import Guid from "../Guid"; +import ReferenceTypeName from "../serialization/ReferenceTypeName"; +import Utility from "../Utility" + +export default class PinEntity { + static optionalKeys = ['Direction'] + constructor(options = {}) { + const getOrFalse = (keys) => Utility.objectGet(keys, false, options) + const getOrEmptyString = (keys) => Utility.objectGet(keys, "", options) + this.PinId = new Guid(Utility.objectGet(["PinId"], true, options)) + this.PinName = getOrEmptyString(["PinName"]) + this.PinToolTip = getOrEmptyString(["PinToolTip"]) + this.Direction = getOrEmptyString(["Direction"]) + this.PinType = { + PinCategory: getOrEmptyString(["PinType", "PinCategory"]), + PinSubCategory: getOrEmptyString(["PinType", "PinSubCategory"]), + PinSubCategoryObject: Utility.objectGet(["PinType", "PinSubCategoryObject"], ReferenceTypeName.None, options), + PinSubCategoryMemberReference: Utility.objectGet(["PinType", "PinSubCategoryMemberReference"], null, options), + PinValueType: getOrFalse(["PinType", "PinValueType"]), + ContainerType: Utility.objectGet(["PinType", "ContainerType"], ReferenceTypeName.None, options), + bIsReference: getOrFalse(["PinType", "bIsReference"]), + bIsConst: getOrFalse(["PinType", "bIsConst"]), + bIsWeakPointer: getOrFalse(["PinType", "bIsWeakPointer"]), + bIsUObjectWrapper: getOrFalse(["PinType", "bIsUObjectWrapper"]) + } + this.LinkedTo = Utility.objectGet(["LinkedTo"], null, options) + this.DefaultValue = getOrFalse(["DefaultValue"]) + this.AutogeneratedDefaultValue = getOrFalse(["AutogeneratedDefaultValue"]) + this.PersistentGuid = new Guid(getOrFalse(["PersistentGuid"])) + this.bHidden = getOrFalse(["bHidden"]) + this.bNotConnectable = getOrFalse(["bNotConnectable"]) + this.bDefaultValueIsReadOnly = getOrFalse(["bDefaultValueIsReadOnly"]) + this.bDefaultValueIsIgnored = getOrFalse(["bDefaultValueIsIgnored"]) + this.bAdvancedView = getOrFalse(["bAdvancedView"]) + this.bOrphanedPin = getOrFalse(["bOrphanedPin"]) + } + +} \ No newline at end of file diff --git a/js/export.js b/js/export.js new file mode 100644 index 0000000..855837e --- /dev/null +++ b/js/export.js @@ -0,0 +1,5 @@ +import Blueprint from "./Blueprint" +import GraphNode from "./graph/GraphNode" +import PinSerializer from "./serialization/PinSerializer" + +export { Blueprint as UEBlueprint, GraphNode as GraphNode, PinSerializer as PinSerializer } \ No newline at end of file diff --git a/js/exporting.js b/js/exporting.js deleted file mode 100644 index 16fd1bc..0000000 --- a/js/exporting.js +++ /dev/null @@ -1,5 +0,0 @@ -import UEBlueprint from "./UEBlueprint" -import GraphPin from "./GraphPin" -import GraphNode from "./GraphNode" - -export { UEBlueprint as UEBlueprint, GraphNode as GraphNode, GraphPin as UGraphPin } \ No newline at end of file diff --git a/js/GraphEntity.js b/js/graph/GraphEntity.js similarity index 78% rename from js/GraphEntity.js rename to js/graph/GraphEntity.js index b063dd9..c2ed4c2 100644 --- a/js/GraphEntity.js +++ b/js/graph/GraphEntity.js @@ -4,11 +4,11 @@ export default class GraphEntity extends HTMLElement { /** * - * @param {import("./template/Template").default} template The template to render this node + * @param {import("../template/Template").default} template The template to render this node */ constructor(template) { super() - /** @type {import("./UEBlueprint").default}" */ + /** @type {import("../Blueprint").Blueprint}" */ this.blueprint = null this.template = template } diff --git a/js/Link.js b/js/graph/GraphLink.js similarity index 83% rename from js/Link.js rename to js/graph/GraphLink.js index 072f4f4..ecadc79 100644 --- a/js/Link.js +++ b/js/graph/GraphLink.js @@ -1,6 +1,6 @@ import UBlueprintEntity from "./UBlueprintEntity" -export default class Link extends UBlueprintEntity { +export default class GraphLink extends UBlueprintEntity { /** * @@ -22,8 +22,8 @@ export default class Link extends UBlueprintEntity { -` + ` } } -customElements.define('u-link', Link) +customElements.define('u-link', GraphLink) diff --git a/js/GraphNode.js b/js/graph/GraphNode.js similarity index 88% rename from js/GraphNode.js rename to js/graph/GraphNode.js index b78c4fb..e7450f2 100644 --- a/js/GraphNode.js +++ b/js/graph/GraphNode.js @@ -1,11 +1,11 @@ import SelectableDraggable from "./SelectableDraggable" -import NodeTemplate from "./template/NodeTemplate" +import NodeTemplate from "../template/NodeTemplate" export default class GraphNode extends SelectableDraggable { constructor() { super(new NodeTemplate()) - this.graphNodeName = 'N/A' + this.graphNodeName = 'n/a' this.inputs = [] this.outputs = [] } diff --git a/js/GraphSelector.js b/js/graph/GraphSelector.js similarity index 94% rename from js/GraphSelector.js rename to js/graph/GraphSelector.js index 2e30280..8b2f5b6 100644 --- a/js/GraphSelector.js +++ b/js/graph/GraphSelector.js @@ -1,6 +1,6 @@ -import FastSelectionModel from "./selection/FastSelectionModel"; +import FastSelectionModel from "../selection/FastSelectionModel"; import GraphEntity from "./GraphEntity"; -import Template from "./template/Template"; +import Template from "../template/Template"; export default class GraphSelector extends GraphEntity { diff --git a/js/SelectableDraggable.js b/js/graph/SelectableDraggable.js similarity index 98% rename from js/SelectableDraggable.js rename to js/graph/SelectableDraggable.js index 7e67203..063b2dc 100644 --- a/js/SelectableDraggable.js +++ b/js/graph/SelectableDraggable.js @@ -1,4 +1,4 @@ -import Drag from "./input/Drag" +import Drag from "../input/Drag" import GraphEntity from "./GraphEntity" export default class SelectableDraggable extends GraphEntity { diff --git a/js/input/MouseWheel.js b/js/input/MouseWheel.js index 4995e4b..512436f 100644 --- a/js/input/MouseWheel.js +++ b/js/input/MouseWheel.js @@ -5,7 +5,7 @@ export default class MouseWheel extends Pointing { /** * * @param {HTMLElement} target - * @param {import("../UEBlueprint").default} blueprint + * @param {import("../Blueprint").Blueprint} blueprint * @param {Object} options */ constructor(target, blueprint, options) { diff --git a/js/input/Pointing.js b/js/input/Pointing.js index 6230d06..3c359ce 100644 --- a/js/input/Pointing.js +++ b/js/input/Pointing.js @@ -5,7 +5,7 @@ export default class Pointing { constructor(target, blueprint, options) { /** @type {HTMLElement} */ this.target = target - /** @type {import("../UEBlueprint").default}" */ + /** @type {import("../Blueprint").Blueprint}" */ this.blueprint = blueprint this.movementSpace = this.blueprint?.getGridDOMElement() ?? document.documentElement } diff --git a/js/serialization/ObjectSerialize.js b/js/serialization/ObjectSerialize.js new file mode 100644 index 0000000..72fed68 --- /dev/null +++ b/js/serialization/ObjectSerialize.js @@ -0,0 +1,9 @@ +import Serializer from "./Serializer"; + +export default class ObjectSerializer extends Serializer { + + write(object) { + let result = `Pin (${this.constructor.subWrite('', this)})` + return result + } +} \ No newline at end of file diff --git a/js/serialization/PinGrammar.js b/js/serialization/PinGrammar.js new file mode 100644 index 0000000..707540e --- /dev/null +++ b/js/serialization/PinGrammar.js @@ -0,0 +1,57 @@ +import Parsimmon from "parsimmon" +import PinEntity from "../entity/PinEntity" +import Utility from "../Utility" +import ReferenceTypeName from "./ReferenceTypeName" + +let P = Parsimmon + +export default class PinGrammar { + static pinEntity = new PinEntity() + Null = _ => P.string("()").map(() => null).desc("null value.") + None = _ => P.string("None").map(() => new ReferenceTypeName("None")).desc('None value') + ReferencePath = _ => P.regex(/[a-zA-Z_]/).sepBy1(P.string(".")).tieWith(".").sepBy1(Parsimmon.string("/")).tieWith("/") + Reference = r => r.Word.skip(P.optWhitespace).then(r.ReferencePath) + Word = _ => P.regex(/[a-zA-Z]+/) + Guid = _ => P.regex(/[0-9a-zA-Z]{32}/).desc("a 32 digit hexadecimal value") + String = _ => P.regex(/(?:[^"\\]|\\")*/).wrap(P.string('"'), P.string('"')).desc('a string value, with possibility to escape the quote symbol (") using \"') + Boolean = _ => P.string("True").or(P.string("False")).map(v => v === "True" ? true : false).desc("either True or False") + AttributeName = r => r.Word.sepBy1(P.string(".")).tieWith(".") + AttributeValue = r => P.alt(r.Null, r.None, r.Boolean, Reference, r.String, r.Guid) + Attribute = r => P.seqMap( + r.AttributeName, + P.string("=").trim(P.optWhitespace), + r.AttributeValue, + /** + * + * @param {String} name The key PinEntity + * @param {*} _ + * @param {*} value + * @returns + */ + (name, _, value) => + /** + * Sets the property name name in the object pinEntity to the value provided + * @param {PinEntity} pinEntity + */ + (pinEntity) => Utility.objectSet(name.split('.'), value, pinEntity) + ) + Pin = r => { + return P.seqObj( + P.string("Pin"), + P.optWhitespace, + P.string("("), + [ + "attributes", + r.Attribute + .trim(P.optWhitespace) + .sepBy(P.string(",")) + .skip(P.regex(/,?/).then(P.optWhitespace)) // Optional trailing comma + ], + P.string(')') + ).map(object => { + let result = new PinEntity() + object.attributes.forEach(attributeSetter => attributeSetter(result)) + return result + }) + } +} \ No newline at end of file diff --git a/js/serialization/PinSerializer.js b/js/serialization/PinSerializer.js new file mode 100644 index 0000000..b595347 --- /dev/null +++ b/js/serialization/PinSerializer.js @@ -0,0 +1,22 @@ +import Parsimmon from "parsimmon" +import PinGrammar from "./PinGrammar" +import Serializer from "./Serializer" + +export default class PinSerializer extends Serializer { + + static pinGrammar = Parsimmon.createLanguage(new PinGrammar()) + + read(value) { + const parseResult = PinSerializer.pinGrammar.Pin.parse(value) + if (!parseResult.status) { + console.error("Error when trying to parse the pin.") + return parseResult + } + return parseResult.value + } + + write(object) { + let result = `Pin (${Serializer.subWrite('', object)})` + return result + } +} \ No newline at end of file diff --git a/js/serialization/ReferenceTypeName.js b/js/serialization/ReferenceTypeName.js new file mode 100644 index 0000000..4d0b8c9 --- /dev/null +++ b/js/serialization/ReferenceTypeName.js @@ -0,0 +1,37 @@ +export default class ReferenceTypeName { + + /** + * + * @param {String} reference + * @returns + */ + static splitReference(reference) { + const pathBegin = reference.search(/['"]/) + const referenceType = reference.substr(0, pathBegin > 0 ? pathBegin : undefined) // reference example Class'"/Script/Engine.PlayerCameraManager"' + const referencePath = pathBegin > 0 ? reference.substr(pathBegin) : "" + switch (referenceType) { + case "None": + if (referencePath.length > 0) { + return false // None cannot have a path + } + default: + return [referenceType, referencePath] + } + } + + /** + * + * @param {String} reference + */ + constructor(reference) { + reference = ReferenceTypeName.splitReference(reference) + if (!reference) { + throw new Error('Invalid reference: ' + reference) + } + this.reference = reference + } + + toString() { + return this.value + } +} \ No newline at end of file diff --git a/js/serialization/Serializer.js b/js/serialization/Serializer.js new file mode 100644 index 0000000..89c6316 --- /dev/null +++ b/js/serialization/Serializer.js @@ -0,0 +1,51 @@ +import Parsimmon from "parsimmon" +import PinGrammar from "./PinGrammar" + +export default class Serializer { + + static writeValue(value) { + if (value?.constructor?.name === 'Function') { + return this.writeValue(value()) + } + // No quotes + if (value === null) { + return '()' + } + if (value?.constructor?.name === 'Boolean') { + return value ? 'True' : 'False' + } + if (value?.constructor?.name === 'ETypesNames' || value?.constructor?.name === 'FGuid') { + return value.toString() + } + // Quotes + if (value?.constructor?.name === 'String') { + return `"${value}"` + } + } + + static subWrite(prefix, object) { + let result = "" + prefix += prefix != "" ? "." : "" + const fullPropertyName = prefix + property + for (const property in object) { + if (object[property]?.constructor?.name === 'Object') { + result += Serializer.subWrite(fullPropertyName, object[property]) + } else if (!object.constructor.optionalKeys.contains(fullPropertyName)) { + result += `${fullPropertyName}=${Serializer.writeValue(object[property])},` + } + } + return result + } + + /** + * + * @param {String} value + */ + read(value) { + //Parsimmon.length + } + + write(object) { + return '' + } +} \ No newline at end of file diff --git a/js/serialization/SerializerFactory.js b/js/serialization/SerializerFactory.js new file mode 100644 index 0000000..07d9123 --- /dev/null +++ b/js/serialization/SerializerFactory.js @@ -0,0 +1,15 @@ +import ObjectEntity from "../entity/ObjectEntity"; +import PinEntity from "../entity/PinEntity"; +import SerializeObject from "./ObjectSerialize"; +import PinSerializer from "./PinSerializer"; + +export default class SerializerFactory { + static serializers = new Map([ + [PinEntity.prototype.constructor.name, PinSerializer], + [ObjectEntity.prototype.constructor.name, SerializeObject] + ]) + + createSerializer(object) { + return SerializerFactory.serializers.get(object.constructor.name) + } +} \ No newline at end of file diff --git a/js/template/BlueprintTemplate.js b/js/template/BlueprintTemplate.js index 2b98a2e..904b298 100644 --- a/js/template/BlueprintTemplate.js +++ b/js/template/BlueprintTemplate.js @@ -17,7 +17,7 @@ export default class BlueprintTemplate extends Template { /** * - * @param {import("../UEBlueprint").default} element + * @param {import("../Blueprint").Blueprint} element * @returns */ viewport(element) { diff --git a/js/template/Template.js b/js/template/Template.js index 5da40b9..efcaedd 100644 --- a/js/template/Template.js +++ b/js/template/Template.js @@ -1,5 +1,5 @@ /** - * @typedef {import("./GraphNode").default} GraphNode + * @typedef {import("../graph/GraphNode").default} GraphNode */ export default class Template { diff --git a/package.json b/package.json index 48cd031..fa474f7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "ueblueprint", "version": "1.0.0", "description": "Unreal Engine's Blueprint visualisation library", - "main": "index.js", + "main": "ueblueprint.js", "scripts": { "build": "rollup --config" }, @@ -21,6 +21,14 @@ "url": "https://github.com/barsdeveloper/ueblueprint/issues" }, "homepage": "https://github.com/barsdeveloper/ueblueprint#readme", - "dependencies": {}, - "devDependencies": {} -} \ No newline at end of file + "devDependencies": { + "@rollup/plugin-commonjs": "^21.0.0", + "@rollup/plugin-node-resolve": "^13.0.5", + "rollup": "^2.58.0", + "rollup-plugin-terser": "^7.0.2", + "terser": "^5.9.0" + }, + "dependencies": { + "parsimmon": "^1.18.0" + } +} diff --git a/rollup.config.js b/rollup.config.js index aeb3388..b71ff3b 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,7 +1,16 @@ +import { nodeResolve } from '@rollup/plugin-node-resolve' +import commonjs from '@rollup/plugin-commonjs' +import { terser } from 'rollup-plugin-terser' + export default { - input: 'js/exporting.js', + input: 'js/export.js', output: { - file: 'ueblueprint.js', - format: 'es', + file: 'dist/ueblueprint.js', + format: 'es' }, -}; \ No newline at end of file + plugins: [ + nodeResolve({ browser: true }), + commonjs(), + //terser() + ] +} \ No newline at end of file diff --git a/ueblueprint.html b/ueblueprint.html index 08da7b9..3c585e7 100644 --- a/ueblueprint.html +++ b/ueblueprint.html @@ -14,7 +14,7 @@
Hello