From 9081e562ab35e06fe043cc1f666b58127270c45a Mon Sep 17 00:00:00 2001 From: Ayush Kashyap <55059858+ayushk7@users.noreply.github.com> Date: Thu, 5 Mar 2026 04:33:03 +0530 Subject: [PATCH 01/10] refactor: add the node registry and remove the spreaded code handling (#28) * refactor: add the node registry and remove the spreaded code handling * Refactor/file structure n naming (#29) * chore: update file and folder naming conventions, fix casing issues in imports, and add AppStage module * refactor: the file and folder structure --- CONVENTIONS.md | 54 + README.md | 129 +- javascript/Nodes/nodes.js | 2321 ----------------- .../VisualScriptToJavascript.js | 578 ---- package.json | 11 + scripts/git-hooks/commit-msg | 30 + scripts/git-hooks/pre-push | 24 + scripts/setup-git-hooks.js | 43 + {images => src/images}/Capture.JPG | Bin {images => src/images}/Code Wire Logo.ai | 0 {images => src/images}/Code Wire Logo.png | Bin {images => src/images}/Code Wire Logo.svg | 0 {images => src/images}/Factorial.png | Bin {images => src/images}/FibonacciSeries.png | Bin {images => src/images}/PrimeNumberCheck.png | Bin .../images}/Untitled Diagram.drawio.png | Bin {images => src/images}/add_ex.JPG | Bin {images => src/images}/fib.png | Bin {images => src/images}/httpreq.png | Bin {images => src/images}/print_ctx_menu.JPG | Bin {images => src/images}/print_example.JPG | Bin {images => src/images}/print_node.JPG | Bin {images => src/images}/right-chevron.svg | 0 {images => src/images}/sqq1.png | Bin index.html => src/index.html | 82 +- javascript/main/main.js => src/js/app.js | 23 +- .../js/compiler}/builtInFunctions.js | 5 + .../js/compiler/codePreview.js | 0 src/js/compiler/compiler.js | 171 ++ .../ColorMap => src/js/core}/colorMap.js | 0 .../intiStage.js => src/js/core/stage.js | 4 +- .../js/editor}/contextMenu.js | 57 +- .../js/editor/deleteHandler.js | 0 .../js/editor/dragAndDrop.js | 0 .../js/editor/selectionBox.js | 2 +- src/js/nodes/nodeFactory.js | 535 ++++ .../js/nodes/nodeInputBox.js | 4 +- .../js/nodes/nodePosition.js | 4 +- .../Wiring.js => src/js/nodes/wiring.js | 4 +- .../js/persistence/saveAndLoad.js | 8 +- src/js/registry/index.js | 15 + src/js/registry/nodeDefinitions.js | 1383 ++++++++++ src/js/registry/registry.js | 142 + .../main/alertBox.js => src/js/ui/dialogs.js | 4 +- .../variable.js => src/js/ui/variableList.js | 4 +- .../js/ui/variablePanel.js | 6 +- style.css => src/style.css | 0 .../vendor/codemirror}/ayu-dark.css | 0 .../vendor/codemirror}/ayu-mirage.css | 0 .../vendor/codemirror}/codemirror.css | 0 .../vendor/codemirror}/codemirror.js | 0 .../vendor/codemirror}/javascript/index.html | 0 .../codemirror}/javascript/javascript.js | 0 .../codemirror}/javascript/json-ld.html | 0 .../vendor/codemirror}/javascript/test.js | 0 .../codemirror}/javascript/typescript.html | 0 .../vendor/codemirror}/material.css | 0 .../vendor}/jquery/jquery.js | 0 .../Konva => src/vendor/konva}/konva.min.js | 0 59 files changed, 2511 insertions(+), 3132 deletions(-) create mode 100644 CONVENTIONS.md delete mode 100644 javascript/Nodes/nodes.js delete mode 100644 javascript/VisualScriptToJavascript/VisualScriptToJavascript.js create mode 100644 package.json create mode 100644 scripts/git-hooks/commit-msg create mode 100644 scripts/git-hooks/pre-push create mode 100644 scripts/setup-git-hooks.js rename {images => src/images}/Capture.JPG (100%) rename {images => src/images}/Code Wire Logo.ai (100%) rename {images => src/images}/Code Wire Logo.png (100%) rename {images => src/images}/Code Wire Logo.svg (100%) rename {images => src/images}/Factorial.png (100%) rename {images => src/images}/FibonacciSeries.png (100%) rename {images => src/images}/PrimeNumberCheck.png (100%) rename {images => src/images}/Untitled Diagram.drawio.png (100%) rename {images => src/images}/add_ex.JPG (100%) rename {images => src/images}/fib.png (100%) rename {images => src/images}/httpreq.png (100%) rename {images => src/images}/print_ctx_menu.JPG (100%) rename {images => src/images}/print_example.JPG (100%) rename {images => src/images}/print_node.JPG (100%) rename {images => src/images}/right-chevron.svg (100%) rename {images => src/images}/sqq1.png (100%) rename index.html => src/index.html (71%) rename javascript/main/main.js => src/js/app.js (90%) rename {javascript/VisualScriptToJavascript => src/js/compiler}/builtInFunctions.js (93%) rename javascript/VisualScriptToJavascript/liveCode.js => src/js/compiler/codePreview.js (100%) create mode 100644 src/js/compiler/compiler.js rename {javascript/ColorMap => src/js/core}/colorMap.js (100%) rename javascript/AppStage/intiStage.js => src/js/core/stage.js (96%) rename {javascript/ContextMenu => src/js/editor}/contextMenu.js (77%) rename javascript/Delete/delete.js => src/js/editor/deleteHandler.js (100%) rename javascript/DragAndDrop/DragAndDrop.js => src/js/editor/dragAndDrop.js (100%) rename javascript/SelectionBox/SelectionBox.js => src/js/editor/selectionBox.js (97%) create mode 100644 src/js/nodes/nodeFactory.js rename javascript/InputBox/InputBox.js => src/js/nodes/nodeInputBox.js (99%) rename javascript/setLocationOfNode/setLocationOfNode.js => src/js/nodes/nodePosition.js (81%) rename javascript/Wiring/Wiring.js => src/js/nodes/wiring.js (98%) rename javascript/SaveAndLoad/SaveAndLoad.js => src/js/persistence/saveAndLoad.js (97%) create mode 100644 src/js/registry/index.js create mode 100644 src/js/registry/nodeDefinitions.js create mode 100644 src/js/registry/registry.js rename javascript/main/alertBox.js => src/js/ui/dialogs.js (99%) rename javascript/Variable/variable.js => src/js/ui/variableList.js (97%) rename javascript/LeftPanel/LeftPanel.js => src/js/ui/variablePanel.js (97%) rename style.css => src/style.css (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/ayu-dark.css (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/ayu-mirage.css (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/codemirror.css (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/codemirror.js (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/javascript/index.html (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/javascript/javascript.js (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/javascript/json-ld.html (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/javascript/test.js (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/javascript/typescript.html (100%) rename {javascript/Dependencies/CodeMirror => src/vendor/codemirror}/material.css (100%) rename {javascript/Dependencies => src/vendor}/jquery/jquery.js (100%) rename {javascript/Dependencies/Konva => src/vendor/konva}/konva.min.js (100%) diff --git a/CONVENTIONS.md b/CONVENTIONS.md new file mode 100644 index 0000000..ad11df1 --- /dev/null +++ b/CONVENTIONS.md @@ -0,0 +1,54 @@ +# CodeWire – Branch & Commit Conventions + +## Branch names + +Use lowercase with a type prefix and short description: + +- **Format:** `type/short-description` (e.g. `feature/node-registry`, `fix/context-menu`) +- **Allowed types:** `feature`, `fix`, `chore`, `docs`, `refactor`, `test` +- **Protected:** `master` and `main` are allowed as-is (no validation when pushing them) + +**Examples:** `feature/visual-script-export`, `fix/compiler-edge-case`, `chore/deps` + +--- + +## Commit messages + +Use [Conventional Commits](https://www.conventionalcommits.org/): + +- **Format:** `type(scope): short description` or `type: short description` +- **Types:** `feat`, `fix`, `chore`, `docs`, `refactor`, `style`, `test`, `perf` +- **Scope (optional):** e.g. `feat(nodes): add custom node type` +- **Length:** First line should be under 72 characters. + +**Examples:** +- `feat: add node registry and definitions` +- `fix(compiler): handle empty script output` +- `chore: update dependencies` + +--- + +## File and folder naming + +- **Domain folders:** Use lowercase for domain group folders under `src/js/` (e.g. `core`, `nodes`, `registry`, `compiler`, `editor`, `ui`, `persistence`). +- **JavaScript files:** Use camelCase (e.g. `nodeFactory.js`, `contextMenu.js`, `stage.js`, `saveAndLoad.js`). Match the main export or feature name. Use `index.js` for module entry points. +- **App layout:** App source lives under `src/`: entry point `src/index.html`, styles and images in `src/`, app JavaScript in `src/js/` (domain folders as above), app entry point at `src/js/app.js`. Third-party libraries live in `src/vendor/` (e.g. `codemirror`, `jquery`, `konva`). Use lowercase for vendor subfolders to avoid case-sensitivity issues. +- **Avoid:** Typos in filenames; mixing casing for the same concept (e.g. `Dependencies` vs `dependencies`). + +--- + +## Enforcing conventions + +After cloning the repo, install the Git hooks once: + +```bash +npm run setup:hooks +``` + +This installs: + +- **commit-msg** – Rejects commits that don’t match the commit message format. +- **pre-push** – Rejects pushes if the current branch name doesn’t match the branch format (except when pushing `master` or `main`). + +To skip hook checks in rare cases (e.g. emergency fix): +`git commit --no-verify` or `git push --no-verify` (use sparingly). diff --git a/README.md b/README.md index 4afaf6b..5650d03 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,13 @@ ![Forks](https://img.shields.io/github/forks/ayushk7/CodeWire?style=social)

- CodeWire + CodeWire

Try at https://ayushk7.github.io/CodeWire/ + +**Run locally:** From the repo root run `npm start`. The app is served from the `src/` directory (default http://localhost:3000). + CodeWire is a node based editor inspired by UE4 Blueprints which helps in better visualization of the code, and faster scripting of complex and repetitive tasks. It doesn't bind to any particular language. @@ -28,130 +31,34 @@ Tutorial: ## Fibonacci Series -![Fibonacci Series](images/fib.png) +![Fibonacci Series](src/images/fib.png) ## HTTP REQUEST/Compiled Code -![HTTP REQUEST/Compiled Code](images/httpreq.png) +![HTTP REQUEST/Compiled Code](src/images/httpreq.png) ## Documentation ### Node Anatomy -![](images/Untitled%20Diagram.drawio.png) +![](src/images/Untitled%20Diagram.drawio.png) ### Adding New Nodes -1. Add the description of node in the [javascript/Nodes/nodes.js](javascript/Nodes/nodes.js) -```js - //description of the Print node - if (type == 'Print') { - nodeDescription.nodeTitle = 'Print'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: 'Data', - defValue: "'hello'", - pinInId: null, - } - } - // styling for the node - nodeDescription.color = 'Print'; - nodeDescription.rows = 3; - nodeDescription.colums = 12; - } - - //NOTE: this same object is furthur used for serialization and deserialization of the graph, so we have some meta info like pinIds -``` -But still the node is not available in the context menu -![](images/print_ctx_menu.JPG) - - -2. To make this node available in the context menu you need to add it to the markup in [index.html](index.html) -```html -
Begin
-
Print
-
Alert
-
Confirm
-``` -Result -![](images/print_node.JPG) - -3. Now only thing left is to add the logic for the node, that is what code it should generate on it's turn - -For this you need add the logic in [VisualScriptToJavascript.js](javascript/VisualScriptToJavascript/VisualScriptToJavascript.js) in coreAlgorithm(node) method - -```js - case "Print": { - this.script += `console.log(${this.handleInp(inputPins[0])});\n - `; - this.coreAlgorithm(execOutPins[0]); // this tells algo to go to the next node which is connected at first pin(triangle shaped) - } - - // this will append the console.log(input) in the generated js -``` -Result -![](images/print_example.JPG) - - -#### NOTE: The above node only takes input, but if the node also do outputs, then that logic is needed to be added separately -Example: Add Node - -Description: -```js - if (type == 'Add') { // this type should match the entry in the context menu's markup in index.html - nodeDescription.nodeTitle = 'Add'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 0, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } -``` - -And In [VisualScriptToJavascript.js](javascript/VisualScriptToJavascript/VisualScriptToJavascript.js) - -in handleInputs() method - -```js -case "Add": { - expr = `(${this.handleInputs(inputPins[0])} + ${this.handleInputs(inputPins[1])})`; -} -// this will generate and return (inp1 + inp2) expression -``` -![](images/add_ex.JPG) + +With the node registry, adding a new node only requires editing one file: [src/js/registry/nodeDefinitions.js](src/js/registry/nodeDefinitions.js). + +1. Call `registerNode({ id, schema, execCodegen?, exprCodegen? })` with the node's schema (inputs, outputs, exec pins, color, rows, columns). +2. Add the node id to the `registerMenuOrder()` array at the bottom of the file (use `null` for a separator). +3. If the node has execution flow, provide an `execCodegen(compiler, node)` function. +4. If the node produces an expression output, provide an `exprCodegen(compiler, inputNode)` function. + +See existing definitions in [src/js/registry/nodeDefinitions.js](src/js/registry/nodeDefinitions.js) for examples (e.g. Print, Add, Branch). + +The node factory ([src/js/nodes/nodeFactory.js](src/js/nodes/nodeFactory.js)) and compiler ([src/js/compiler/compiler.js](src/js/compiler/compiler.js)) automatically pick up any registered node. diff --git a/javascript/Nodes/nodes.js b/javascript/Nodes/nodes.js deleted file mode 100644 index e5e4a49..0000000 --- a/javascript/Nodes/nodes.js +++ /dev/null @@ -1,2321 +0,0 @@ -import { InputBox } from '../InputBox/InputBox.js' -import { colorMap } from '../ColorMap/colorMap.js' -import { setLocationOfNode } from '../setLocationOfNode/setLocationOfNode.js'; -let placeLocation = function (location) { - //"this" is stage - return { - x: (location.x - this.x()) / this.scaleX(), - y: (location.y - this.y()) / this.scaleY() - }; -} -export var Nodes = { - countNodes: 0, - getExecPin: function (inType, helper, layer) { - // let pointsExecIn = [0, 0, -14, -7, -14, 7]; - // let pointsExecOut = [] - let pin = new Konva.Line({ - points: [0, 0, -14, -7, -14, 7], - stroke: 'white', - strokeWidth: 2, - hitStrokeWidth: 10, - closed: true, - helper: helper, - name: 'pin', - offsetX: (inType) ? -14 : 0, - pinType: (inType) ? 'exec-in' : 'exec-out', - pinDataType: null, - fill: '', - }); - pin.on("mouseenter", () => { - pin.strokeWidth(4); - layer.draw(); - }); - pin.on("mouseleave", () => { - pin.strokeWidth(2); - layer.draw(); - }); - pin.on("wireremoved", (e) => { - if (e.isPinEmpty) { - pin.fill('transparent'); - } - }); - pin.on("wireconnected", (e) => { - pin.fill("white"); - }); - pin.on("wiringstart", (e) => { - pin.fill("white"); - layer.draw(); - }); - return pin; - }, - getRectBlock: function (height, width) { - let rect = new Konva.Rect({ - height: height, - width: width, - // fill: colorMap['MainBox'], - opacity: 0.8, - cornerRadius: 5, - shadowColor: 'black', - shadowBlur: 15, - shadowOffset: { x: 15, y: 15 }, - shadowOpacity: 0.5, - fillLinearGradientStartPoint: { x: 0, y: 0 }, - fillLinearGradientEndPoint: { x: width, y: height }, - fillLinearGradientColorStops: [0, colorMap['MainBoxGradient']['start'], 1, colorMap['MainBoxGradient']['end']], - // fillLinearGradientColorStops: [0, '#12100e', 1, '#2b4162'], - - // strokeWidth: [10, 10, 110, 0], - }); - return rect; - }, - getInputPin: function (inType, helper, type, layer) { - let pin = new Konva.Circle({ - radius: 7, - stroke: colorMap[type], - strokeWidth: 2, - hitStrokeWidth: 10, - name: 'pin', - pinType: (inType) ? 'inp' : 'outp', - pinDataType: type, - offsetX: (inType) ? -7 : 7, - helper: helper, - fill: '', - }); - pin.on("mouseenter", () => { - pin.strokeWidth(4); - layer.draw(); - }); - pin.on("mouseleave", () => { - pin.strokeWidth(2); - layer.draw(); - }); - pin.on("wireremoved", (e) => { - if (e.isPinEmpty) { - pin.fill('transparent'); - } - }); - pin.on("wireconnected", (e) => { - pin.fill(`${colorMap[type]}`); - }); - pin.on("wiringstart", (e) => { - pin.fill(`${colorMap[type]}`); - layer.draw(); - }); - return pin; - }, - // getOutputPin: function(){ - // let pin = new Konva.Circle({ - // radius: 7, - // stroke: 'yellow', - // strokeWidth: '2', - // name: 'pin', - // pinType: 'outp', - // }); - // return pin; - // }, - getLabel: function (text, size, width, color) { - let rect = new Konva.Rect({ - width: width, - height: size + 3, - fill: colorMap[color], - cornerRadius: [5, 5, 0, 0], - // fillLinearGradientStartPoint: { x: 0, y: 0 }, - // fillLinearGradientEndPoint: { x: width, y: size + 3 }, - // fillLinearGradientColorStops: [0, colorMap[color], 1, 'rgba(0, 0, 0, 0)'], - // fillRadialGradientStartPoint: {x: 0, y: 0}, - // fillRadialGradientEndPoint: { x: 30, y: 0 }, - // fillRadialGradientColorStops: [0, colorMap[color], 1, '#2d3436'], - // fillRadialGradientStartRadius: size / 3, - // fillRadialGradientEndRadius: 100, - - // fillLinearGradientColorStops: [0, '#9e768f', 1, '#ff4e00'], - - // #ec9f05 #ff4e00 - }); - let label = new Konva.Text({ - text: text, - fontSize: size - 5, - fontFamily: 'Verdana', - fill: colorMap['MainLabel'], - width: width, - // height: size + 3, - y: 2, - align: 'left', - padding: 3, - // padding: 10 - }); - return { bg: rect, text: label }; - }, - getPinCounts: function (nodeDescription) { - let inputPinCounts = 0; - let outputPinCounts = 0; - if (nodeDescription.execIn) - inputPinCounts++; - if (nodeDescription.inputs) { - inputPinCounts += Object.keys(nodeDescription.inputs).length; - } - - //For outputs - if (nodeDescription.execOut) { - outputPinCounts += Object.keys(nodeDescription.execOut).length; - } - if (nodeDescription.outputs) { - outputPinCounts += Object.keys(nodeDescription.outputs).length; - - } - return Math.max(inputPinCounts, outputPinCounts); - }, - // getEditableTextBox: function (type, stage, index) { - // let rect = new Konva.Rect({ - // width: (type == 'Boolean') ? 14 : 50, - // height: 14, - // stroke: colorMap[type], - // strokeWidth: 1, - // }); - // return rect; - // }, - getInputLabel: function (labelText, isInput) { - let text = new Konva.Text({ - // width: 40, - height: 14, - text: labelText, - fontSize: 11, - fontFamily: 'Verdana', - fill: colorMap['Text'], - }); - if (isInput) - text.offsetX(0); - else - text.offsetX(text.width()); - // text.off() - return text; - }, - getExecOutTitle: function (labelText) { - let text = new Konva.Text({ - height: 14, - fontSize: 11, - text: labelText, - fontFamily: 'Verdana', - fill: "white", - }); - text.offsetX(text.width()); - return text; - }, - optimizeDrag: function (grp, stage, layer) { - let dragLayer = stage.findOne('#dragLayer'); - let wireLayer = stage.findOne('#wireLayer'); - grp.on('dragstart', () => { - grp.moveTo(dragLayer); - for (let each of grp.customClass.execInPins) { - for (let aWire of each.wire) { - aWire.moveTo(dragLayer); - } - } - for (let each of grp.customClass.execOutPins) { - if (each.wire) - each.wire.moveTo(dragLayer); - } - for (let each of grp.customClass.inputPins) { - if (each.wire) - each.wire.moveTo(dragLayer); - } - for (let each of grp.customClass.outputPins) { - for (let aWire of each.wire) { - aWire.moveTo(dragLayer); - } - } - wireLayer.draw(); - dragLayer.draw(); - layer.draw(); - // try { - // if (layer.hasChildren()) - // layer.cache(); - // if (wireLayer.hasChildren()) - // wireLayer.cache(); - // } - // catch (err) { - - // } - }) - grp.on('dragend', () => { - grp.moveTo(layer); - for (let each of grp.customClass.execInPins) { - for (let aWire of each.wire) { - aWire.moveTo(wireLayer); - } - } - for (let each of grp.customClass.execOutPins) { - if (each.wire) - each.wire.moveTo(wireLayer); - } - for (let each of grp.customClass.inputPins) { - if (each.wire) - each.wire.moveTo(wireLayer); - } - for (let each of grp.customClass.outputPins) { - for (let aWire of each.wire) { - aWire.moveTo(wireLayer); - } - } - // layer.clearCache(); - // wireLayer.clearCache(); - wireLayer.draw(); - dragLayer.draw(); - layer.draw(); - }); - }, - getBorderRect: function (height, width) { - let rect = new Konva.Rect({ - height: height, - width: width, - fill: 'transparent', - stroke: '#dbd8e3', - strokeWidth: 0, - cornerRadius: 5, - name: 'borderbox', - }); - rect.off('click mouseover mouseenter mouseleave'); - return rect; - }, - ProgramNode: class { - constructor(nodeDescription, location, layer, stage) { - - - - this.grp = new Konva.Group({ - draggable: true, - name: "aProgramNodeGroup", - }); - if (nodeDescription.nodeTitle == 'Begin') { - this.grp.id('Begin'); - } - this.grp.customClass = this; - // this.grp.on('dblclick', (e) => { - // console.table(e.currentTarget.customClass); - // }) - this.nodeDescription = nodeDescription; - let relativePosition = placeLocation.bind(stage); - let maxOfPinsOnEitherSide = Nodes.getPinCounts(nodeDescription); - let height = maxOfPinsOnEitherSide * 50 + 15; - let width = nodeDescription.colums * 15; - this.grp.position(relativePosition(location)); - let rect = Nodes.getRectBlock(height, width); - this.grp.add(rect); - let borderRect = Nodes.getBorderRect(height, width); - let titleLabel = Nodes.getLabel(nodeDescription.nodeTitle, 20, width, nodeDescription.color); - this.grp.add(titleLabel.bg); - this.grp.add(titleLabel.text); - this.grp.add(borderRect); - - this.grp.on("mouseover", (e) => { - // console.log(e); - // if(shape == this.grp) - borderRect.strokeWidth(1); - layer.draw(); - }); - this.grp.on("mouseleave", (e) => { - // rect.opacity(0.9); - // rect.shadowOffset({ x: 15, y: 15 }); - // this.grp.scale(1); - // this.grp.filters([]); - borderRect.strokeWidth(0); - layer.draw(); - }); - this.grp.on('mousedown', (e) => { - rect.shadowBlur(25); - // rect.shadowOffset({ x: 25, y: 25 }); - layer.draw(); - }) - this.grp.on('mouseup', (e) => { - rect.shadowBlur(15); - // rect.shadowOffset({ x: 15, y: 15 }); - layer.draw(); - }) - /****/ - - Nodes.optimizeDrag(this.grp, stage, layer); - - /****/ - // titleLabel.offsetX(titleLabel.width() / 2); - let inputPinsPlaced = 0, outputPinsPlaced = 0; - this.execInPins = []; - if (nodeDescription.execIn == true) { - let execInPin = Nodes.getExecPin(true, 'exec-in-0', layer); - execInPin.position({ x: 7, y: 44 }); - if (nodeDescription.pinExecInId == null) { - execInPin.id(`${execInPin._id}`); - } - else { - execInPin.id(nodeDescription.pinExecInId); - } - this.nodeDescription.pinExecInId = execInPin.id(); - this.grp.add(execInPin); - let tmp = { - thisNode: execInPin, - wire: [], - } - this.execInPins.push(tmp); - inputPinsPlaced = 1; - } - - let X = nodeDescription.nodeTitle.split(" "); - this.type = { - isGetSet: (X[0] == 'Get' || X[0] == 'Set'), - typeOfNode: nodeDescription.nodeTitle, - } - this.execOutPins = []; - if (nodeDescription.execOut) { - Object.keys(nodeDescription.execOut).forEach((value, index) => { - let execOutPin = Nodes.getExecPin(false, `exec-out-${index}`, layer); - execOutPin.position({ x: width - 7, y: 44 + nodeDescription.execOut[value].outOrder * 39 }); - if (nodeDescription.execOut[value].pinExecOutId == null) { - execOutPin.id(`${execOutPin._id}`); - } - else { - execOutPin.id(nodeDescription.execOut[value].pinExecOutId); - } - this.nodeDescription.execOut[value].pinExecOutId = execOutPin.id(); - this.grp.add(execOutPin); - if (nodeDescription.execOut[value].execOutTitle) { - let exLabel = Nodes.getExecOutTitle(nodeDescription.execOut[value].execOutTitle); - exLabel.position({ x: width - 28, y: 44 + nodeDescription.execOut[value].outOrder * 39 - 4 }); - this.grp.add(exLabel); - } - let tmp = { - thisNode: execOutPin, - wire: null, - title: value.execOutTitle, - } - this.execOutPins.push(tmp); - outputPinsPlaced++; - }); - } - this.inputPins = []; - if (nodeDescription.inputs) { - Object.keys(nodeDescription.inputs).forEach((value, index) => { - let inputPin = Nodes.getInputPin(true, `inp-${index}`, nodeDescription.inputs[value].dataType, layer); - inputPin.position({ x: 7, y: 44 + 39 * inputPinsPlaced }); - if (nodeDescription.inputs[value].pinInId == null) { - inputPin.id(`${inputPin._id}`); - } - else { - inputPin.id(nodeDescription.inputs[value].pinInId); - } - this.nodeDescription.inputs[value].pinInId = inputPin.id(); - // iprect.position({ x: 28, y: 44 + 39 * inputPinsPlaced - 2 }); - let iprect = null; - let iplabel = Nodes.getInputLabel(nodeDescription.inputs[value].inputTitle, true); - iplabel.position({ x: 28, y: 44 + 39 * inputPinsPlaced - 4 }); - if (nodeDescription.inputs[value].isInputBoxRequired !== false) { - // console.log(nodeDescription.inputs, this.nodeDescription.inputs); - iprect = new InputBox(stage, layer, nodeDescription.inputs[value].dataType, this.grp, { x: 28, y: 44 + 39 * inputPinsPlaced - 2 }, colorMap, inputPin, iplabel, inputPinsPlaced, nodeDescription.inputs[value], this.nodeDescription.inputs[value]); - iplabel.position({ x: 28, y: 44 + 39 * inputPinsPlaced - 14 }); - } - this.grp.add(iplabel); - this.grp.add(inputPin); - // this.grp.add(iprect); - let tmp = { - thisNode: inputPin, - wire: null, - textBox: iprect, - value: null, - title: value.inputTitle, - } - this.inputPins.push(tmp); - inputPinsPlaced++; - }); - } - this.outputPins = []; - if (nodeDescription.outputs) { - Object.keys(nodeDescription.outputs).forEach((value, index) => { - let outputPin = Nodes.getInputPin(false, `out-${index}`, nodeDescription.outputs[value].dataType, layer); - outputPin.position({ x: width - 7, y: 44 + 39 * nodeDescription.outputs[value].outOrder }); - if (nodeDescription.outputs[value].pinOutId == null) { - outputPin.id(`${outputPin._id}`); - } - else { - outputPin.id(nodeDescription.outputs[value].pinOutId); - } - nodeDescription.outputs[value].pinOutId = outputPin.id(); - this.grp.add(outputPin); - let outLabel = Nodes.getInputLabel(nodeDescription.outputs[value].outputTitle, false); - outLabel.position({ x: width - 28, y: 44 + 39 * nodeDescription.outputs[value].outOrder - 4 }) - this.grp.add(outLabel); - let tmp = { - wire: [], - value: null, - title: value.outputTitle, - } - this.outputPins.push(tmp); - outputPinsPlaced++; - }) - }; - // this.grp.cache(); - layer.add(this.grp); - layer.draw(); - layer.draw(); - // console.log(JSON.parse(JSON.stringify(this.grp))); - } - }, - - - - - - CreateNode: function (type, location, layer, stage, isGetSet, dataType, defValue) { - let nodeDescription = {}; - if (type == 'Begin') { - nodeDescription.nodeTitle = 'Begin'; - nodeDescription.execIn = false; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - } - }; - nodeDescription.color = 'Begin'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Print') { - nodeDescription.nodeTitle = 'Print'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: 'Data', - defValue: "'hello'", - pinInId: null, - } - } - nodeDescription.color = 'Print'; - nodeDescription.rows = 3; - nodeDescription.colums = 12; - } - if (type == 'Alert') { - nodeDescription.nodeTitle = 'Alert'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: 'Data', - defValue: "'hello'", - pinInId: null, - } - } - nodeDescription.color = 'Print'; - nodeDescription.rows = 3; - nodeDescription.colums = 12; - } - if (type == 'Confirm') { - nodeDescription.nodeTitle = 'Confirm'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Message', - dataType: 'String', - defValue: "'Ok'", - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Ok?', - dataType: 'Boolean', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Print'; - nodeDescription.rows = 3; - nodeDescription.colums = 12; - } - if (type == 'Prompt') { - nodeDescription.nodeTitle = 'Prompt'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Message', - dataType: 'String', - defValue: "'Ok'", - pinInId: null, - }, - input1: { - inputTitle: 'Default', - dataType: 'String', - defValue: "'Yes'", - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Ok?', - dataType: 'Boolean', - pinOutId: null, - outOrder: 1, - }, - output1: { - outputTitle: 'Value', - dataType: 'String', - pinOutId: null, - outOrder: 2, - }, - } - nodeDescription.color = 'Print'; - nodeDescription.rows = 3; - nodeDescription.colums = 12; - } - if (type == 'If/Else') { - nodeDescription.nodeTitle = 'If/Else'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: 'True', - pinExecOutId: null, - outOrder: 0, - }, - execOut1: { - execOutTitle: 'False', - pinExecOutId: null, - outOrder: 1, - }, - execOut2: { - execOutTitle: 'Done', - pinExecOutId: null, - outOrder: 2, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Bool', - dataType: 'Boolean', - defValue: true, - pinInId: null, - } - } - nodeDescription.color = 'Logic'; - nodeDescription.rows = 3; - nodeDescription.colums = 12; - } - if (type == 'Add') { - nodeDescription.nodeTitle = 'Add'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 0, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Modulo') { - nodeDescription.nodeTitle = 'Modulo'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 1, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 2, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Subtract') { - nodeDescription.nodeTitle = 'Subtract'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 0, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Multiply') { - nodeDescription.nodeTitle = 'Multiply'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 1, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Divide') { - nodeDescription.nodeTitle = 'Divide'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 1, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Power') { - nodeDescription.nodeTitle = 'Power'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 2, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 2, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Ceil') { - nodeDescription.nodeTitle = 'Ceil'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 1, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Floor') { - nodeDescription.nodeTitle = 'Floor'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 1, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - - if (type == 'WhileLoop') { - nodeDescription.nodeTitle = 'WhileLoop'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.inputs = { - input0: { - inputTitle: 'Bool', - dataType: 'Boolean', - defValue: false, - pinInId: null, - }, - } - nodeDescription.execOut = { - execOut0: { - execOutTitle: 'Loop Body', - pinExecOutId: null, - outOrder: 0, - - }, - execOut1: { - execOutTitle: 'Completed', - pinExecOutId: null, - outOrder: 1, - - } - } - nodeDescription.color = 'Logic'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - - if (type == 'OR') { - nodeDescription.nodeTitle = 'OR'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Boolean', - defValue: true, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Boolean', - defValue: true, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'AND') { - nodeDescription.nodeTitle = 'AND'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Boolean', - defValue: true, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Boolean', - defValue: true, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'XOR') { - nodeDescription.nodeTitle = 'XOR'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Boolean', - defValue: true, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Boolean', - defValue: true, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'bXOR') { - nodeDescription.nodeTitle = 'bXOR'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 1, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'bOR') { - nodeDescription.nodeTitle = 'bOR'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 1, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'bAND') { - nodeDescription.nodeTitle = 'bAND'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 1, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'bXOR') { - nodeDescription.nodeTitle = 'XOR'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 1, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'bNEG') { - nodeDescription.nodeTitle = 'bNEG'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == "Swap") { - nodeDescription.nodeTitle = 'Swap'; - nodeDescription.execIn = true, - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Ref1', - dataType: 'Data', - isInputBoxRequired: false, - pinInId: null, - }, - input1: { - inputTitle: 'Ref2', - dataType: 'Data', - isInputBoxRequired: false, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Ref1', - dataType: 'Data', - pinOutId: null, - outOrder: 1, - - }, - output1: { - outputTitle: 'Ref2', - dataType: 'Data', - pinOutId: null, - outOrder: 2, - - } - } - nodeDescription.color = 'Func'; - - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (type == "Equals") { - nodeDescription.nodeTitle = 'Equals'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Data', - defValue: 0, - pinInId: null, - - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Data', - defValue: 0, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == "Not Equals") { - nodeDescription.nodeTitle = 'Not Equals'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Data', - defValue: 0, - pinInId: null, - - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Data', - defValue: 0, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == "LessEq") { - nodeDescription.nodeTitle = 'LessEq'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == "Less") { - nodeDescription.nodeTitle = 'Less'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == "Greater") { - nodeDescription.nodeTitle = 'Greater'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == "GreaterEq") { - nodeDescription.nodeTitle = 'GreaterEq'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'NEG') { - nodeDescription.nodeTitle = 'NEG'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: 'Boolean', - defValue: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == "Max(Num)") { - nodeDescription.nodeTitle = 'Max(Num)'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 0, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Max', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == "Min(Num)") { - nodeDescription.nodeTitle = 'Min(Num)'; - nodeDescription.inputs = { - input0: { - inputTitle: 'ValueA', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'ValueB', - dataType: 'Number', - defValue: 0, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Min', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (isGetSet == "Set") { - let defaultValueByType = { - "Number": 0, - "Boolean": true, - "String": "'hello'", - "Array": '[]', - } - nodeDescription.nodeTitle = type; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: dataType, - defValue: defaultValueByType[dataType], - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Value(Ref)', - dataType: dataType, - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (isGetSet == "Get") { - nodeDescription.nodeTitle = type; - nodeDescription.outputs = { - output0: { - outputTitle: 'Value(Ref)', - dataType: dataType, - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Get'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Random') { - nodeDescription.nodeTitle = 'Random'; - nodeDescription.outputs = { - output0: { - outputTitle: 'Random[0,1)', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Math'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'ForLoop') { - nodeDescription.nodeTitle = 'ForLoop'; - nodeDescription.pinExecInId = null; - nodeDescription.execIn = true; - nodeDescription.execOut = { - execOut0: { - execOutTitle: 'Loop Body', - pinExecOutId: null, - outOrder: 0, - }, - execOut1: { - execOutTitle: 'Completed', - pinExecOutId: null, - outOrder: 2, - } - } - nodeDescription.inputs = { - input0: { - inputTitle: 'From', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'To(Excl)', - dataType: 'Number', - defValue: 10, - pinInId: null, - }, - input2: { - inputTitle: 'Increment', - dataType: 'Number', - defValue: 1, - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Index', - dataType: 'Number', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Logic'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (type == 'ForEachLoop') { - nodeDescription.nodeTitle = 'ForEachLoop'; - nodeDescription.pinExecInId = null; - nodeDescription.execIn = true; - nodeDescription.execOut = { - execOut0: { - execOutTitle: 'Loop Body', - pinExecOutId: null, - outOrder: 0, - }, - execOut1: { - execOutTitle: 'Completed', - pinExecOutId: null, - outOrder: 4, - } - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Value', - dataType: 'Data', - pinOutId: null, - outOrder: 1, - }, - output1: { - outputTitle: 'Index', - dataType: 'Number', - pinOutId: null, - outOrder: 2, - }, - output2: { - outputTitle: 'Array', - dataType: 'Array', - pinOutId: null, - outOrder: 3, - } - } - nodeDescription.color = 'Logic'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (type == "Break") { - nodeDescription.nodeTitle = 'Break'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.color = 'Logic'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == "Continue") { - nodeDescription.nodeTitle = 'Continue'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.color = 'Logic'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Length') { - nodeDescription.nodeTitle = 'Length'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Value', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Get'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'isEmpty') { - nodeDescription.nodeTitle = 'isEmpty'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Result', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Get'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Reverse') { - nodeDescription.nodeTitle = 'Reverse'; - nodeDescription.pinExecInId = null; - nodeDescription.execIn = true; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - } - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Array', - dataType: 'Array', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Front') { - nodeDescription.nodeTitle = 'Front'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Front(Ref)', - dataType: 'Data', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Get'; - nodeDescription.rows = 2; - nodeDescription.colums = 11; - } - if (type == 'Sort(Num)') { - nodeDescription.nodeTitle = 'Sort(Num)'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - input1: { - inputTitle: 'Increasing', - dataType: 'Boolean', - pinInId: null, - defValue: true, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Array', - dataType: 'Array', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (type == 'Back') { - nodeDescription.nodeTitle = 'Back'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Back(Ref)', - dataType: 'Data', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Get'; - nodeDescription.rows = 2; - nodeDescription.colums = 11; - } - if (type == 'GetByPos') { - nodeDescription.nodeTitle = 'GetByPos'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Pos', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Value(Ref)', - dataType: 'Data', - pinOutId: null, - outOrder: 0, - } - } - nodeDescription.color = 'Get'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (type == 'SetByPos') { - nodeDescription.nodeTitle = 'SetByPos'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Pos', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'Value', - dataType: 'Data', - defValue: 1, - pinInId: null, - - }, - input2: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Value(Ref)', - dataType: 'Data', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 4; - nodeDescription.colums = 12; - } - if (type == 'Insert') { - nodeDescription.nodeTitle = 'Insert'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Pos', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'Value', - dataType: 'Data', - defValue: 1, - pinInId: null, - }, - input2: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Array', - dataType: 'Array', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 4; - nodeDescription.colums = 10; - } - if (type == 'PushBack') { - nodeDescription.nodeTitle = 'PushBack'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: 'Data', - defValue: 1, - pinInId: null, - }, - input1: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Array', - dataType: 'Array', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'PushFront') { - nodeDescription.nodeTitle = 'PushFront'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: 'Data', - defValue: 1, - pinInId: null, - }, - input1: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Array', - dataType: 'Array', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'PopBack') { - nodeDescription.nodeTitle = 'PopBack'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Array', - dataType: 'Array', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'PopFront') { - nodeDescription.nodeTitle = 'PopFront'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Array', - dataType: 'Array', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 10; - } - if (type == 'Search') { - nodeDescription.nodeTitle = 'Search'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: 'Data', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Exist', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - }, - output1: { - outputTitle: 'Index', - dataType: 'Number', - pinOutId: null, - outOrder: 1, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 11; - } - if (type == 'BinarySearch(Num)') { - nodeDescription.nodeTitle = 'BinarySearch(Num)'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Value', - dataType: 'Number', - defValue: 0, - pinInId: null, - }, - input1: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Exist', - dataType: 'Boolean', - pinOutId: null, - outOrder: 0, - - }, - output1: { - outputTitle: 'Lower Bound', - dataType: 'Number', - pinOutId: null, - outOrder: 1, - }, - output2: { - outputTitle: 'Upper Bound', - dataType: 'Number', - pinOutId: null, - outOrder: 2, - } - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 13; - } - if (type == 'Max(Array)') { - nodeDescription.nodeTitle = 'Max(Array)'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'MaxValue', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - }, - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 11; - } - if (type == 'Min(Array)') { - nodeDescription.nodeTitle = 'Min(Array)'; - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'MinValue', - dataType: 'Number', - pinOutId: null, - outOrder: 0, - }, - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 11; - } - if (type == 'HttpRequest') { - nodeDescription.nodeTitle = 'HttpRequest'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: 'OnSuccess', - pinExecOutId: null, - outOrder: 0, - }, - execOut1: { - execOutTitle: 'OnFail', - pinExecOutId: null, - outOrder: 2, - }, - execOut2: { - execOutTitle: 'Continue', - pinExecOutId: null, - outOrder: 3, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'URL', - dataType: 'String', - defValue: "'link'", - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'JSON', - dataType: 'Data', - pinOutId: null, - outOrder: 1, - }, - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (type == 'OpenWindow') { - nodeDescription.nodeTitle = 'OpenWindow'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'URL', - dataType: 'String', - defValue: "'link'", - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Success?', - dataType: 'Boolean', - pinOutId: null, - outOrder: 1, - }, - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (type == 'GetByName(JSON)') { - nodeDescription.nodeTitle = 'GetByName(JSON)'; - nodeDescription.inputs = { - input0: { - inputTitle: 'JSON', - dataType: 'Data', - isInputBoxRequired: false, - pinInId: null, - }, - input1: { - inputTitle: 'Name', - dataType: 'String', - defValue: "'id'", - pinInId: null, - } - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Data', - dataType: 'Data', - pinOutId: null, - outOrder: 0, - }, - } - nodeDescription.color = 'Get'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (type == 'StrToArray') { - nodeDescription.nodeTitle = 'StrToArray'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'String', - dataType: 'String', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'Array', - dataType: 'Array', - pinOutId: null, - outOrder: 1, - }, - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - if (type == 'ArrayToStr') { - nodeDescription.nodeTitle = 'ArrayToStr'; - nodeDescription.execIn = true; - nodeDescription.pinExecInId = null; - nodeDescription.execOut = { - execOut0: { - execOutTitle: null, - pinExecOutId: null, - outOrder: 0, - }, - } - nodeDescription.inputs = { - input0: { - inputTitle: 'Array', - dataType: 'Array', - isInputBoxRequired: false, - pinInId: null, - }, - } - nodeDescription.outputs = { - output0: { - outputTitle: 'String', - dataType: 'String', - pinOutId: null, - outOrder: 1, - }, - } - nodeDescription.color = 'Func'; - nodeDescription.rows = 2; - nodeDescription.colums = 12; - } - - new this.ProgramNode(nodeDescription, location, layer, stage); - } - - -} - - - -/* - -//required json -{ - type: string, - id: num, - inputs:{ - count: integer, - execIn1:{ - name: "", - wire: KonvaWire else null - } - ip1: { - dataType: string, - default: num/str etc, - value: num/str etc, - name: "" - wire: Konva.Line else null if no wire - } - } - outputs:{ - count: integer, - execOut1:{ - name: "", - wire: KonvaWire else null - } - out1: { - dataType: string, - default: num/str etc, - value: num/str etc, - name: "" - wire: Konva.Line else null if no wire - } - } - -} - - -*/ \ No newline at end of file diff --git a/javascript/VisualScriptToJavascript/VisualScriptToJavascript.js b/javascript/VisualScriptToJavascript/VisualScriptToJavascript.js deleted file mode 100644 index 13af7e7..0000000 --- a/javascript/VisualScriptToJavascript/VisualScriptToJavascript.js +++ /dev/null @@ -1,578 +0,0 @@ -import { variableList } from '../Variable/variable.js' -import { showAlert } from '../main/alertBox.js' -import { BuilInFunctions } from './builtInFunctions.js' -export var VSToJS = class { - - constructor(stage, layer, isRunOrCode) { - this.script = ''; - this.builtin_functions = {}; - this.nodeCount = 0; - this.isRunOrCode = isRunOrCode; - for (let variable of variableList.variables) { - // console.log(variable); - this.script += `let ${variable.name} = ${variable.value};\n`; - } - let begin = this.getBegin(stage); - if (begin) { - try { - this.coreAlgorithm(begin); - // console.log(this.script); - if (this.isRunOrCode == "Run") { - document.getElementById("console-window").classList.toggle("hidden", false); - let codeDoc = document.getElementById("console").contentWindow.document; - // console.log("run"); - codeDoc.open(); - codeDoc.writeln( - `\n - - -

- - - - ` - ); - codeDoc.close(); - } - } - catch (err) { - document.getElementById("console-window").classList.toggle("hidden", false); - let codeDoc = document.getElementById("console").contentWindow.document; - this.script = ''; - this.builtin_functions = {}; - codeDoc.open(); - codeDoc.writeln( - `\n - - - - Recheck the nodes
- ${err.name === 'RangeError' ? 'CyclicDependence : Irresolvable Cycle(s) Exists' : `UnknownException: Improve The Editor By Opening Issue On GitHub(Just Attach The Exported Graph)`} -
- - - ` - ); - } - } - } - getBegin(stage) { - let X = stage.find("#Begin"); - if (X.length == 0) { - showAlert("Include Begin Node"); - } - else if (X.length > 1) { - showAlert("Multiple Begin Nodes"); - } - else return X[0]; - } - getExecOut(node) { - let X = []; - for (let aNode of node.customClass.execOutPins) { - if (aNode.wire) - X.push(aNode.wire.attrs.dest.getParent()); - else - X.push(null); - } - // console.log(X); - return X; - } - getSrcOutputPinNumber(grp, aNodeWire) { - let c = 0; - for (let eachPin of grp.customClass.outputPins) { - for (let aWire of eachPin.wire) { - if (aWire === aNodeWire) { - return c; - } - } - c++; - } - } - getInputPins(node) { - let X = []; - for (let aNode of node.customClass.inputPins) { - if (aNode.wire) { - X.push({ node: aNode.wire.attrs.src.getParent(), isWire: true, srcOutputPinNumber: this.getSrcOutputPinNumber(aNode.wire.attrs.src.getParent(), aNode.wire) }); - } - else { - // console.log(aNode.textBox); - X.push({ node: aNode.textBox.textBox.text(), isWire: false, srcOutputPinNumber: null }); - } - } - return X; - } - coreAlgorithm(node) { - if (node == null) return; - let execOutPins = this.getExecOut(node); - let inputPins = this.getInputPins(node); - // console.log(node.customClass.type); - // console.log(inputPins); - if (node.customClass.type.isGetSet) { - if (node.customClass.type.typeOfNode.slice(0, 3) == 'Set') { - this.script += `${node.customClass.type.typeOfNode.slice(4)} = ${this.handleInputs(inputPins[0])};\n`; - for (let each of execOutPins) { - this.coreAlgorithm(each); - } - } - } - else { - switch (node.customClass.type.typeOfNode) { - case "Begin": { - this.coreAlgorithm(execOutPins[0]); - let func_string = `/////////CodeWire Functions Space Begins///////////// - - `; - for (let each_function in this.builtin_functions) { - func_string = func_string + BuilInFunctions[each_function]; - } - func_string += ` - /////////CodeWire Functions Space Ends///////////// - //\n//\n/////////Generated JS Code Space Begins///////////// - `; - this.script = func_string + this.script; - this.script += `\n/////////Generated JS Code Space Ends/////////////`; - } - break; - case "Print": { - this.script += `console.log(${this.handleInputs(inputPins[0])});\n - `; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "Alert": { - this.script += `alert(${this.handleInputs(inputPins[0])});\n - `; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "Confirm": { - this.builtin_functions = { ...this.builtin_functions, _confirm: true }; - this.script += `let _confirm_answer${node._id} = _confirm(${this.handleInputs(inputPins[0])});\n - `; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "Prompt": { - this.builtin_functions = { ...this.builtin_functions, _prompt: true }; - this.script += `let [_prompt_ok${node._id}, _prompt_value${node._id}] = _prompt(${this.handleInputs(inputPins[0])}, ${this.handleInputs(inputPins[1])});\n - `; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "OpenWindow": { - this.builtin_functions = { ...this.builtin_functions, _newWindow: true }; - this.script += `let _window_opened${node._id} = _newWindow(${this.handleInputs(inputPins[0])});\n - `; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "If/Else": { - this.script += `if(${this.handleInputs(inputPins[0])}){\n`; - this.coreAlgorithm(execOutPins[0]); - this.script += `}\n`; - this.script += `else{\n`; - this.coreAlgorithm(execOutPins[1]); - this.script += `}\n`; - this.coreAlgorithm(execOutPins[2]); - } - break; - case "ForLoop": { - let forVar = `i${node._id}`; //variable used inside the for loop - this.script += `for(let ${forVar} = (${this.handleInputs(inputPins[0])}); ${forVar} < (${this.handleInputs(inputPins[1])}); ${forVar} += (${this.handleInputs(inputPins[2])})){\n`; - this.coreAlgorithm(execOutPins[0]); - this.script += `}\n`; - this.coreAlgorithm(execOutPins[1]); - } - break; - case "ForEachLoop": { - let forVar = `i${node._id}`; //variable used inside the for loop - this.script += `${this.handleInputs(inputPins[0])}.forEach((value${forVar}, ${forVar}, array${forVar}) => {\n`; - this.coreAlgorithm(execOutPins[0]); - this.script += `});\n`; - this.coreAlgorithm(execOutPins[1]); - } - break; - case "Break": { - this.script += `break;\n`; - } - break; - case "Continue": { - this.script += `continue;\n`; - } - break; - case "WhileLoop": { - this.script += ` while(${this.handleInputs(inputPins[0])}){\n`; - this.coreAlgorithm(execOutPins[0]); - this.script += `}\n`; - this.coreAlgorithm(execOutPins[1]); - } - break; - case "SetByPos": { - this.script += `${this.handleInputs(inputPins[2])}[${this.handleInputs(inputPins[0])}] = ${this.handleInputs(inputPins[1])};\n`; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "PushBack": { - this.script += `${this.handleInputs(inputPins[1])}.push(${this.handleInputs(inputPins[0])});\n`; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "PushFront": { - this.script += `${this.handleInputs(inputPins[1])}.unshift(${this.handleInputs(inputPins[0])});\n`; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "PopBack": { - this.script += `${this.handleInputs(inputPins[0])}.pop();\n`; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "PopFront": { - this.script += `${this.handleInputs(inputPins[0])}.shift();\n`; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "Insert": { - this.script += `${this.handleInputs(inputPins[2])}.splice(${this.handleInputs(inputPins[0])}, 0, ${this.handleInputs(inputPins[1])});\n`; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "Reverse": { - this.script += `${this.handleInputs(inputPins[0])}.reverse(); - `; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "Swap": { - this.script += ` - [${this.handleInputs(inputPins[0])}, ${this.handleInputs(inputPins[1])}] = [${this.handleInputs(inputPins[1])}, ${this.handleInputs(inputPins[0])}]; //swap using array destructuring :) \n`; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "Sort(Num)": { - this.script += ` - (${this.handleInputs(inputPins[1])}) ? ${this.handleInputs(inputPins[0])}.sort((a, b) => a-b) : ${this.handleInputs(inputPins[0])}.sort((a, b) => b-a);\n - `; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "HttpRequest": { - this.builtin_functions = { ...this.builtin_functions, fetch_data: true }; - this.script += ` - fetch_data(${this.handleInputs(inputPins[0])}) - .then((json_data${node._id}) => { - `; - this.coreAlgorithm(execOutPins[0]); - this.script += ` - }) - .catch((err) => { - ` - this.coreAlgorithm(execOutPins[1]); - this.script += ` - }); - `; - this.coreAlgorithm(execOutPins[2]); - } - break; - case "StrToArray": { - this.script += `let strArray${node._id} = ${this.handleInputs(inputPins[0])}.split(''); - `; - this.coreAlgorithm(execOutPins[0]); - } - break; - case "ArrayToStr": { - this.script += `let arrayStr${node._id} = ${this.handleInputs(inputPins[0])}.join(''); - `; - this.coreAlgorithm(execOutPins[0]); - } - break; - } - } - } - handleInputs(inputNode) { - - if (!inputNode.isWire) { - return inputNode.node; - } - let inputPins = this.getInputPins(inputNode.node); - if (inputNode.node.customClass.type.isGetSet) { - return `${inputNode.node.customClass.type.typeOfNode.slice(4)}`; - } - // if (inputNode.node.customClass.type.isFor) { - // return `(i${inputNode.node.customClass.type.isFor})`; - // } - let expr = ``; - switch (inputNode.node.customClass.type.typeOfNode) { - case "Add": { - expr = `(${this.handleInputs(inputPins[0])} + ${this.handleInputs(inputPins[1])})`; - } - break; - case "Subtract": { - expr = `(${this.handleInputs(inputPins[0])} - ${this.handleInputs(inputPins[1])})`; - } - break; - case "Multiply": { - expr = `(${this.handleInputs(inputPins[0])} * ${this.handleInputs(inputPins[1])})`; - } - break; - case "Divide": { - expr = `(${this.handleInputs(inputPins[0])} / ${this.handleInputs(inputPins[1])})`; - } - break; - case "Power": { - expr = `Math.pow(${this.handleInputs(inputPins[0])}, ${this.handleInputs(inputPins[1])})`; - } - break; - case "Modulo": { - expr = `(${this.handleInputs(inputPins[0])} % ${this.handleInputs(inputPins[1])})`; - } - break; - case "AND": { - expr = `(${this.handleInputs(inputPins[0])} && ${this.handleInputs(inputPins[1])})`; - } - break; - case "Ceil": { - expr = `Math.ceil(${this.handleInputs(inputPins[0])})`; - } - break; - case "Floor": { - expr = `Math.floor(${this.handleInputs(inputPins[0])})`; - } - break; - case "OR": { - expr = `(${this.handleInputs(inputPins[0])} || ${this.handleInputs(inputPins[1])})`; - } - break; - case "XOR": { - expr = `(${this.handleInputs(inputPins[0])} ^ ${this.handleInputs(inputPins[1])})`; - } - break; - case "NEG": { - expr = `!(${this.handleInputs(inputPins[0])})`; - } - break; - case "bAND": { - expr = `(${this.handleInputs(inputPins[0])} & ${this.handleInputs(inputPins[1])})`; - } - break; - case "bOR": { - expr = `(${this.handleInputs(inputPins[0])} | ${this.handleInputs(inputPins[1])})`; - } - break; - case "bXOR": { - expr = `(${this.handleInputs(inputPins[0])} ^ ${this.handleInputs(inputPins[1])})`; - } - break; - case "bNEG": { - expr = `~${this.handleInputs(inputPins[0])}`; - } - break; - case "Random": { - expr = `Math.random()`; - } - break; - case "Equals": { - expr = `(${this.handleInputs(inputPins[0])} === ${this.handleInputs(inputPins[1])})`; - } - break; - case "Not Equals": { - expr = `(${this.handleInputs(inputPins[0])} !== ${this.handleInputs(inputPins[1])})`; - } - break; - case "LessEq": { - expr = `(${this.handleInputs(inputPins[0])} <= ${this.handleInputs(inputPins[1])})`; - } - break; - case "Less": { - expr = `(${this.handleInputs(inputPins[0])} < ${this.handleInputs(inputPins[1])})`; - } - break; - case "Greater": { - expr = `(${this.handleInputs(inputPins[0])} > ${this.handleInputs(inputPins[1])})`; - } - break; - case "GreaterEq": { - expr = `(${this.handleInputs(inputPins[0])} >= ${this.handleInputs(inputPins[1])})`; - } - break; - case "Length": { - expr = `${this.handleInputs(inputPins[0])}.length`; - } - break; - case "GetByPos": { - // console.log("GetByPos"); - expr = `${this.handleInputs(inputPins[1])}[${this.handleInputs(inputPins[0])}]`; - } - break; - case "SetByPos": { - expr = `${this.handleInputs(inputPins[2])}[${this.handleInputs(inputPins[0])}]`; - } - break; - case "isEmpty": { - expr = `(${this.handleInputs(inputPins[0])}.length == (0))`; - } - break; - case "Reverse": { - expr = `${this.handleInputs(inputPins[0])}`; - } - break; - case "PushBack": { - expr = `${this.handleInputs(inputPins[1])}`; - } - break; - case "PushFront": { - expr = `${this.handleInputs(inputPins[1])}`; - } - break; - case "PopBack": { - expr = `${this.handleInputs(inputPins[0])}`; - } - break; - case "PopFront": { - expr = `${this.handleInputs(inputPins[0])}`; - } - break; - case "Front": { - expr = `${this.handleInputs(inputPins[0])}[0]`; - } - break; - case "Back": { - expr = `${this.handleInputs(inputPins[0])}[${this.handleInputs(inputPins[0])}.length - 1]`; - } - break; - case "Insert": { - expr = `${this.handleInputs(inputPins[2])}`; - } - break; - case "Swap": { - expr = `${this.handleInputs(inputPins[inputNode.srcOutputPinNumber])}`; - } - break; - case "ForLoop": { - expr = `i${inputNode.node._id}`; - } - break; - case "ForEachLoop": { - expr = ``; - if (inputNode.srcOutputPinNumber == 0) - expr = `valuei${inputNode.node._id}`; - else if (inputNode.srcOutputPinNumber == 1) - expr = `i${inputNode.node._id}`; - else - expr = `arrayi${inputNode.node._id}`; - } - break; - case "Sort(Num)": { - expr = `${this.handleInputs(inputPins[0])}`; - } - break; - case "Max(Array)": { - expr = `Math.max(...${this.handleInputs(inputPins[0])})`; - } - break; - case "Min(Array)": { - expr = `Math.min(...${this.handleInputs(inputPins[0])})`; - } - break; - case "Max(Num)": { - expr = `Math.max(${this.handleInputs(inputPins[0])}, ${this.handleInputs(inputPins[1])})`; - } - break; - case "Min(Num)": { - expr = `Math.min(${this.handleInputs(inputPins[0])}, ${this.handleInputs(inputPins[1])})`; - } - break; - case "Search": { - expr = ``; - if (inputNode.srcOutputPinNumber == 0) { - expr = `(${this.handleInputs(inputPins[1])}.find((value) => value === ${this.handleInputs(inputPins[0])}) === ${this.handleInputs(inputPins[0])})`; - } - else { - expr = `(${this.handleInputs(inputPins[1])}.findIndex((value) => value === ${this.handleInputs(inputPins[0])}))`; - } - } - break; - case "BinarySearch(Num)": { - expr = ``; - if (inputNode.srcOutputPinNumber == 0) { - this.builtin_functions = { ...this.builtin_functions, binary_search_exist: true }; - expr = `binary_search_exist(${this.handleInputs(inputPins[1])}, ${this.handleInputs(inputPins[0])})`; - } - else if (inputNode.srcOutputPinNumber == 1) { - this.builtin_functions = { ...this.builtin_functions, lower_bound: true }; - expr = `lower_bound(${this.handleInputs(inputPins[1])}, ${this.handleInputs(inputPins[0])})`; - } - else { - this.builtin_functions = { ...this.builtin_functions, upper_bound: true }; - expr = `upper_bound(${this.handleInputs(inputPins[1])}, ${this.handleInputs(inputPins[0])})`; - } - } - break; - case "HttpRequest": { - expr = `json_data${inputNode.node._id}`; - } - break; - case "GetByName(JSON)": { - expr = `${this.handleInputs(inputPins[0])}[${this.handleInputs(inputPins[1])}]`; - } - break; - case "Confirm": { - expr = `_confirm_answer${inputNode.node._id}`; - } - break; - case "OpenWindow": { - expr = `_window_opened${inputNode.node._id}`; - } - break; - case "Prompt": { - expr = ``; - if (inputNode.srcOutputPinNumber == 0) { - expr = `_prompt_ok${inputNode.node._id}`; - } - else { - expr = `_prompt_value${inputNode.node._id}`; - } - } - break; - case "StrToArray": { - expr = `strArray${inputNode.node._id}`; - } - break; - case "ArrayToStr": { - expr = `arrayStr${inputNode.node._id}`; - } - break; - } - return expr; - } - - - -}; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..3eaf186 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "codewire", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "npx serve src -p 3000", + "test": "node test/compiler.test.js", + "test:compiler": "node test/compiler.test.js", + "setup:hooks": "node scripts/setup-git-hooks.js" + } +} diff --git a/scripts/git-hooks/commit-msg b/scripts/git-hooks/commit-msg new file mode 100644 index 0000000..c6bff55 --- /dev/null +++ b/scripts/git-hooks/commit-msg @@ -0,0 +1,30 @@ +#!/bin/sh +# Enforces Conventional Commits: type(scope): description +# Types: feat, fix, chore, docs, refactor, style, test, perf + +commit_msg_file="$1" +if [ ! -f "$commit_msg_file" ]; then + echo "Error: No commit message file." >&2 + exit 1 +fi + +# Read first line, trim +first_line=$(head -n 1 "$commit_msg_file" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + +# Pattern: type or type(scope) followed by : and space and message +# Also allow Merge commits and Revert +if echo "$first_line" | grep -qE '^(Merge |Revert "|feat|fix|chore|docs|refactor|style|test|perf)(\([a-zA-Z0-9_-]+\))?!?: .+'; then + exit 0 +fi + +# Allow merge commit (no colon) +if echo "$first_line" | grep -qE '^Merge (branch|pull request|remote-tracking)'; then + exit 0 +fi + +echo "Invalid commit message format." >&2 +echo "Use: type(scope): description" >&2 +echo "Types: feat, fix, chore, docs, refactor, style, test, perf" >&2 +echo "Example: feat(nodes): add custom node type" >&2 +echo "Your first line was: $first_line" >&2 +exit 1 diff --git a/scripts/git-hooks/pre-push b/scripts/git-hooks/pre-push new file mode 100644 index 0000000..64b441c --- /dev/null +++ b/scripts/git-hooks/pre-push @@ -0,0 +1,24 @@ +#!/bin/sh +# Enforces branch name format: type/short-description +# Allowed types: feature, fix, chore, docs, refactor, test +# master and main are always allowed. + +# Get current branch +current_branch=$(git rev-parse --abbrev-ref HEAD) + +# Allow master and main +case "$current_branch" in + master|main) exit 0 ;; +esac + +# Must match type/description (lowercase, hyphens allowed) +if echo "$current_branch" | grep -qE '^(feature|fix|chore|docs|refactor|test)/[a-z0-9][a-z0-9_-]*$'; then + exit 0 +fi + +echo "Branch name does not follow conventions." >&2 +echo "Use: type/short-description" >&2 +echo "Types: feature, fix, chore, docs, refactor, test" >&2 +echo "Example: feature/node-registry" >&2 +echo "Current branch: $current_branch" >&2 +exit 1 diff --git a/scripts/setup-git-hooks.js b/scripts/setup-git-hooks.js new file mode 100644 index 0000000..2be936d --- /dev/null +++ b/scripts/setup-git-hooks.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node +/** + * Copies Git hook scripts from scripts/git-hooks/ into .git/hooks/ + * so branch and commit message conventions are enforced. + */ + +import { copyFileSync, existsSync, mkdirSync } from 'fs'; +import { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const repoRoot = join(__dirname, '..'); +const hooksSrc = join(repoRoot, 'scripts', 'git-hooks'); +const hooksDest = join(repoRoot, '.git', 'hooks'); + +const hookNames = ['commit-msg', 'pre-push']; + +if (!existsSync(join(repoRoot, '.git', 'HEAD'))) { + console.error('Not a Git repo (no .git/HEAD). Run this from the repo root.'); + process.exit(1); +} + +if (!existsSync(hooksSrc)) { + console.error('scripts/git-hooks not found.'); + process.exit(1); +} + +if (!existsSync(hooksDest)) { + mkdirSync(hooksDest, { recursive: true }); +} + +for (const name of hookNames) { + const src = join(hooksSrc, name); + const dest = join(hooksDest, name); + if (!existsSync(src)) { + console.warn('Skip (missing):', name); + continue; + } + copyFileSync(src, dest); + console.log('Installed:', name); +} + +console.log('Git hooks are installed. See CONVENTIONS.md for branch and commit formats.'); diff --git a/images/Capture.JPG b/src/images/Capture.JPG similarity index 100% rename from images/Capture.JPG rename to src/images/Capture.JPG diff --git a/images/Code Wire Logo.ai b/src/images/Code Wire Logo.ai similarity index 100% rename from images/Code Wire Logo.ai rename to src/images/Code Wire Logo.ai diff --git a/images/Code Wire Logo.png b/src/images/Code Wire Logo.png similarity index 100% rename from images/Code Wire Logo.png rename to src/images/Code Wire Logo.png diff --git a/images/Code Wire Logo.svg b/src/images/Code Wire Logo.svg similarity index 100% rename from images/Code Wire Logo.svg rename to src/images/Code Wire Logo.svg diff --git a/images/Factorial.png b/src/images/Factorial.png similarity index 100% rename from images/Factorial.png rename to src/images/Factorial.png diff --git a/images/FibonacciSeries.png b/src/images/FibonacciSeries.png similarity index 100% rename from images/FibonacciSeries.png rename to src/images/FibonacciSeries.png diff --git a/images/PrimeNumberCheck.png b/src/images/PrimeNumberCheck.png similarity index 100% rename from images/PrimeNumberCheck.png rename to src/images/PrimeNumberCheck.png diff --git a/images/Untitled Diagram.drawio.png b/src/images/Untitled Diagram.drawio.png similarity index 100% rename from images/Untitled Diagram.drawio.png rename to src/images/Untitled Diagram.drawio.png diff --git a/images/add_ex.JPG b/src/images/add_ex.JPG similarity index 100% rename from images/add_ex.JPG rename to src/images/add_ex.JPG diff --git a/images/fib.png b/src/images/fib.png similarity index 100% rename from images/fib.png rename to src/images/fib.png diff --git a/images/httpreq.png b/src/images/httpreq.png similarity index 100% rename from images/httpreq.png rename to src/images/httpreq.png diff --git a/images/print_ctx_menu.JPG b/src/images/print_ctx_menu.JPG similarity index 100% rename from images/print_ctx_menu.JPG rename to src/images/print_ctx_menu.JPG diff --git a/images/print_example.JPG b/src/images/print_example.JPG similarity index 100% rename from images/print_example.JPG rename to src/images/print_example.JPG diff --git a/images/print_node.JPG b/src/images/print_node.JPG similarity index 100% rename from images/print_node.JPG rename to src/images/print_node.JPG diff --git a/images/right-chevron.svg b/src/images/right-chevron.svg similarity index 100% rename from images/right-chevron.svg rename to src/images/right-chevron.svg diff --git a/images/sqq1.png b/src/images/sqq1.png similarity index 100% rename from images/sqq1.png rename to src/images/sqq1.png diff --git a/index.html b/src/index.html similarity index 71% rename from index.html rename to src/index.html index 70181bd..b6fac4c 100644 --- a/index.html +++ b/src/index.html @@ -11,8 +11,8 @@ - - + + @@ -189,73 +189,7 @@

L @@ -279,10 +213,10 @@

L - - - - - + + + + + \ No newline at end of file diff --git a/javascript/main/main.js b/src/js/app.js similarity index 90% rename from javascript/main/main.js rename to src/js/app.js index ab5d8b7..395e48d 100644 --- a/javascript/main/main.js +++ b/src/js/app.js @@ -1,14 +1,15 @@ -import { AppStage } from '../AppStage/intiStage.js' -// import {SelectionBox} from '../SelectionBox/SelectionBox.js' -import { DragAndDrop } from '../DragAndDrop/DragAndDrop.js' -import { Wiring } from '../Wiring/Wiring.js' -import { ContextMenu } from '../ContextMenu/contextMenu.js' -import { leftPanel } from '../LeftPanel/LeftPanel.js' -import { VSToJS } from '../VisualScriptToJavascript/VisualScriptToJavascript.js' -import { Delete } from '../Delete/delete.js' -import { Export, Import, Save, prompLastSave } from '../SaveAndLoad/SaveAndLoad.js' -import { showAlert, prompRefreshOrStarter } from './alertBox.js' -import { refresh } from '../VisualScriptToJavascript/liveCode.js' +import './registry/index.js'; +import { AppStage } from './core/stage.js' +// import { SelectionBox } from './editor/selectionBox.js' +import { DragAndDrop } from './editor/dragAndDrop.js' +import { Wiring } from './nodes/wiring.js' +import { ContextMenu } from './editor/contextMenu.js' +import { leftPanel } from './ui/variablePanel.js' +import { VSToJS } from './compiler/compiler.js' +import { Delete } from './editor/deleteHandler.js' +import { Export, Import, Save, prompLastSave } from './persistence/saveAndLoad.js' +import { showAlert, prompRefreshOrStarter } from './ui/dialogs.js' +import { refresh } from './compiler/codePreview.js' // var width = window.innerWidth; // var height = window.innerHeight; let stage = AppStage.getStage(document.getElementById("container").clientWidth, document.getElementById("container").clientHeight, 'container'); diff --git a/javascript/VisualScriptToJavascript/builtInFunctions.js b/src/js/compiler/builtInFunctions.js similarity index 93% rename from javascript/VisualScriptToJavascript/builtInFunctions.js rename to src/js/compiler/builtInFunctions.js index c405900..f5bbe3b 100644 --- a/javascript/VisualScriptToJavascript/builtInFunctions.js +++ b/src/js/compiler/builtInFunctions.js @@ -61,6 +61,11 @@ export const BuilInFunctions = { return [(_value !== null), _value]; } `, + _sleep: `function _sleep(_ms){ + const _start = Date.now(); + while (Date.now() - _start < _ms) {} + } + `, } \ No newline at end of file diff --git a/javascript/VisualScriptToJavascript/liveCode.js b/src/js/compiler/codePreview.js similarity index 100% rename from javascript/VisualScriptToJavascript/liveCode.js rename to src/js/compiler/codePreview.js diff --git a/src/js/compiler/compiler.js b/src/js/compiler/compiler.js new file mode 100644 index 0000000..868c6c3 --- /dev/null +++ b/src/js/compiler/compiler.js @@ -0,0 +1,171 @@ +import { variableList } from '../ui/variableList.js' +import { showAlert } from '../ui/dialogs.js' +import { BuilInFunctions } from './builtInFunctions.js' +import { runExecCodegen, runExprCodegen, hasType } from '../registry/index.js' +export var VSToJS = class { + + constructor(stage, layer, isRunOrCode) { + this.script = ''; + this.builtin_functions = {}; + this.nodeCount = 0; + this.isRunOrCode = isRunOrCode; + for (let variable of variableList.variables) { + // console.log(variable); + this.script += `let ${variable.name} = ${variable.value};\n`; + } + let begin = this.getBegin(stage); + if (begin) { + try { + this.coreAlgorithm(begin); + // console.log(this.script); + if (this.isRunOrCode == "Run") { + document.getElementById("console-window").classList.toggle("hidden", false); + let codeDoc = document.getElementById("console").contentWindow.document; + // console.log("run"); + codeDoc.open(); + codeDoc.writeln( + `\n + + +

+ + + + ` + ); + codeDoc.close(); + } + } + catch (err) { + document.getElementById("console-window").classList.toggle("hidden", false); + let codeDoc = document.getElementById("console").contentWindow.document; + this.script = ''; + this.builtin_functions = {}; + codeDoc.open(); + codeDoc.writeln( + `\n + + + + Recheck the nodes
+ ${err.name === 'RangeError' ? 'CyclicDependence : Irresolvable Cycle(s) Exists' : `UnknownException: Improve The Editor By Opening Issue On GitHub(Just Attach The Exported Graph)`} +
+ + + ` + ); + } + } + } + getBegin(stage) { + let X = stage.find("#Begin"); + if (X.length == 0) { + showAlert("Include Begin Node"); + } + else if (X.length > 1) { + showAlert("Multiple Begin Nodes"); + } + else return X[0]; + } + getExecOut(node) { + let X = []; + for (let aNode of node.customClass.execOutPins) { + if (aNode.wire) + X.push(aNode.wire.attrs.dest.getParent()); + else + X.push(null); + } + // console.log(X); + return X; + } + getSrcOutputPinNumber(grp, aNodeWire) { + let c = 0; + for (let eachPin of grp.customClass.outputPins) { + for (let aWire of eachPin.wire) { + if (aWire === aNodeWire) { + return c; + } + } + c++; + } + } + getInputPins(node) { + let X = []; + for (let aNode of node.customClass.inputPins) { + if (aNode.wire) { + X.push({ node: aNode.wire.attrs.src.getParent(), isWire: true, srcOutputPinNumber: this.getSrcOutputPinNumber(aNode.wire.attrs.src.getParent(), aNode.wire) }); + } + else { + // console.log(aNode.textBox); + X.push({ node: aNode.textBox.textBox.text(), isWire: false, srcOutputPinNumber: null }); + } + } + return X; + } + coreAlgorithm(node) { + if (node == null) return; + let execOutPins = this.getExecOut(node); + let inputPins = this.getInputPins(node); + // console.log(node.customClass.type); + // console.log(inputPins); + if (node.customClass.type.isGetSet) { + if (node.customClass.type.typeOfNode.slice(0, 3) == 'Set') { + this.script += `${node.customClass.type.typeOfNode.slice(4)} = ${this.handleInputs(inputPins[0])};\n`; + for (let each of execOutPins) { + this.coreAlgorithm(each); + } + } + } else { + const type = node.customClass.type.typeOfNode; + if (hasType(type)) { + runExecCodegen(type, this, node); + } + } + } + handleInputs(inputNode) { + + if (!inputNode.isWire) { + return inputNode.node; + } + let inputPins = this.getInputPins(inputNode.node); + if (inputNode.node.customClass.type.isGetSet) { + return `${inputNode.node.customClass.type.typeOfNode.slice(4)}`; + } + const type = inputNode.node.customClass.type.typeOfNode; + if (hasType(type)) { + const result = runExprCodegen(type, this, inputNode); + if (result !== undefined) return result; + } + return ''; + } + + + +}; \ No newline at end of file diff --git a/javascript/ColorMap/colorMap.js b/src/js/core/colorMap.js similarity index 100% rename from javascript/ColorMap/colorMap.js rename to src/js/core/colorMap.js diff --git a/javascript/AppStage/intiStage.js b/src/js/core/stage.js similarity index 96% rename from javascript/AppStage/intiStage.js rename to src/js/core/stage.js index 3e5ef61..a946fdb 100644 --- a/javascript/AppStage/intiStage.js +++ b/src/js/core/stage.js @@ -57,13 +57,11 @@ export var AppStage = { }) window.addEventListener('resize', () => { let container = document.querySelector('#container'); - // console.log("Resized"); let containerWidth = container.offsetWidth; - let scale = containerWidth / stage.width(); stage.width(container.offsetWidth); stage.height(container.offsetHeight); stage.draw(); }); return stage; } -} \ No newline at end of file +} diff --git a/javascript/ContextMenu/contextMenu.js b/src/js/editor/contextMenu.js similarity index 77% rename from javascript/ContextMenu/contextMenu.js rename to src/js/editor/contextMenu.js index 34dcb36..8dab526 100644 --- a/javascript/ContextMenu/contextMenu.js +++ b/src/js/editor/contextMenu.js @@ -1,14 +1,35 @@ -import { setLocationOfNode } from '../setLocationOfNode/setLocationOfNode.js' -import { Nodes } from '../Nodes/nodes.js' -import { variableList } from '../Variable/variable.js' -import { deleteProgramNode, deleteWire } from '../Delete/delete.js' +import { setLocationOfNode } from '../nodes/nodePosition.js' +import { Nodes } from '../nodes/nodeFactory.js' +import { variableList } from '../ui/variableList.js' +import { deleteProgramNode, deleteWire } from './deleteHandler.js' +import { getMenuOrder, getDefinition } from '../registry/index.js' export var ContextMenu = { contextMenu: function (stage, layer) { let contextMenu = document.getElementById("ctx-menu-container"); + let contextMenuList = document.getElementById("context-menu"); let deleteCtxMenu = document.getElementById("delete-ctx-container"); let getSetCtxMenu = document.getElementById("get-set-ctx-menu-container"); let searchBar = document.getElementById("ctx-search-bar"); + + // Build context menu from node registry (single source of truth) + contextMenuList.innerHTML = ''; + const menuOrder = getMenuOrder(); + for (const id of menuOrder) { + if (id === null) { + const hr = document.createElement('hr'); + contextMenuList.appendChild(hr); + } else { + const def = getDefinition(id); + if (def) { + const div = document.createElement('div'); + div.className = 'context-menu-items'; + div.textContent = def.label; + div.dataset.nodeId = id; + contextMenuList.appendChild(div); + } + } + } let draggedVariableInfo = { name: null, dataType: null, @@ -24,7 +45,9 @@ export var ContextMenu = { contextMenu.classList.toggle("hidden", true); searchBar.value = ''; for (let ctxItem of contextMenu.children[1].children) { - ctxItem.classList.toggle("hidden", false); + if (ctxItem.classList && ctxItem.classList.contains('context-menu-items')) { + ctxItem.classList.toggle("hidden", false); + } } } } @@ -61,11 +84,12 @@ export var ContextMenu = { // let patt = new RegExp(`${key}`, "gis"); // console.log(patt); for (let ctxItem of contextMenu.children[1].children) { - if (ctxItem.innerHTML.toString().toLowerCase().includes(key)) { - ctxItem.classList.toggle("hidden", false); - } - else { - ctxItem.classList.toggle("hidden", true); + if (ctxItem.classList && ctxItem.classList.contains('context-menu-items')) { + if (ctxItem.textContent.toLowerCase().includes(key)) { + ctxItem.classList.toggle("hidden", false); + } else { + ctxItem.classList.toggle("hidden", true); + } } } @@ -75,8 +99,10 @@ export var ContextMenu = { for (let e of contextMenu.children[1].children) { - this.addEventToCtxMenuItems(e); - }; + if (e.classList && e.classList.contains('context-menu-items')) { + this.addEventToCtxMenuItems(e); + } + } // let alreadyPresent = []; // to prevent adding multiple eventListeners stage.on('contextmenu', function (e) { @@ -167,19 +193,18 @@ export var ContextMenu = { function makeNode(e, stage, layer, toggleContextMenu) { let xx = e.parentElement.getBoundingClientRect().x - stage.getContainer().getBoundingClientRect().x; let yy = e.parentElement.getBoundingClientRect().y - stage.getContainer().getBoundingClientRect().y; - let node = undefined; let dataType; if (e.dataset.datatype) dataType = e.dataset.datatype; - let tmp = e.innerHTML.split(" "); + const type = e.dataset.nodeId || e.innerHTML; + let tmp = type.split(" "); let isGetSet = ""; if (tmp[0] == "Get") isGetSet = "Get"; else if (tmp[0] == "Set") isGetSet = "Set"; let defValue = null; - // console.log(e.innerHTML); - Nodes.CreateNode(e.innerHTML, { x: xx, y: yy }, layer, stage, isGetSet, dataType, defValue); + Nodes.CreateNode(type, { x: xx, y: yy }, layer, stage, isGetSet, dataType, defValue); layer.draw(); toggleContextMenu([], false); } diff --git a/javascript/Delete/delete.js b/src/js/editor/deleteHandler.js similarity index 100% rename from javascript/Delete/delete.js rename to src/js/editor/deleteHandler.js diff --git a/javascript/DragAndDrop/DragAndDrop.js b/src/js/editor/dragAndDrop.js similarity index 100% rename from javascript/DragAndDrop/DragAndDrop.js rename to src/js/editor/dragAndDrop.js diff --git a/javascript/SelectionBox/SelectionBox.js b/src/js/editor/selectionBox.js similarity index 97% rename from javascript/SelectionBox/SelectionBox.js rename to src/js/editor/selectionBox.js index 32061ef..3a1cd9b 100644 --- a/javascript/SelectionBox/SelectionBox.js +++ b/src/js/editor/selectionBox.js @@ -1,4 +1,4 @@ -import { setLocationOfNode } from '../setLocationOfNode/setLocationOfNode.js' +import { setLocationOfNode } from '../nodes/nodePosition.js' export var SelectionBox = { setSelectionBox: function (layer, stage) { this.selectionRectangle = new Konva.Rect({ diff --git a/src/js/nodes/nodeFactory.js b/src/js/nodes/nodeFactory.js new file mode 100644 index 0000000..3b0a47c --- /dev/null +++ b/src/js/nodes/nodeFactory.js @@ -0,0 +1,535 @@ +import { InputBox } from './nodeInputBox.js' +import { colorMap } from '../core/colorMap.js' +import { setLocationOfNode } from './nodePosition.js'; +import { buildNodeDescription, hasType } from '../registry/index.js'; +let placeLocation = function (location) { + //"this" is stage + return { + x: (location.x - this.x()) / this.scaleX(), + y: (location.y - this.y()) / this.scaleY() + }; +} +export var Nodes = { + countNodes: 0, + getExecPin: function (inType, helper, layer) { + // let pointsExecIn = [0, 0, -14, -7, -14, 7]; + // let pointsExecOut = [] + let pin = new Konva.Line({ + points: [0, 0, -14, -7, -14, 7], + stroke: 'white', + strokeWidth: 2, + hitStrokeWidth: 10, + closed: true, + helper: helper, + name: 'pin', + offsetX: (inType) ? -14 : 0, + pinType: (inType) ? 'exec-in' : 'exec-out', + pinDataType: null, + fill: '', + }); + pin.on("mouseenter", () => { + pin.strokeWidth(4); + layer.draw(); + }); + pin.on("mouseleave", () => { + pin.strokeWidth(2); + layer.draw(); + }); + pin.on("wireremoved", (e) => { + if (e.isPinEmpty) { + pin.fill('transparent'); + } + }); + pin.on("wireconnected", (e) => { + pin.fill("white"); + }); + pin.on("wiringstart", (e) => { + pin.fill("white"); + layer.draw(); + }); + return pin; + }, + getRectBlock: function (height, width) { + let rect = new Konva.Rect({ + height: height, + width: width, + // fill: colorMap['MainBox'], + opacity: 0.8, + cornerRadius: 5, + shadowColor: 'black', + shadowBlur: 15, + shadowOffset: { x: 15, y: 15 }, + shadowOpacity: 0.5, + fillLinearGradientStartPoint: { x: 0, y: 0 }, + fillLinearGradientEndPoint: { x: width, y: height }, + fillLinearGradientColorStops: [0, colorMap['MainBoxGradient']['start'], 1, colorMap['MainBoxGradient']['end']], + // fillLinearGradientColorStops: [0, '#12100e', 1, '#2b4162'], + + // strokeWidth: [10, 10, 110, 0], + }); + return rect; + }, + getInputPin: function (inType, helper, type, layer) { + let pin = new Konva.Circle({ + radius: 7, + stroke: colorMap[type], + strokeWidth: 2, + hitStrokeWidth: 10, + name: 'pin', + pinType: (inType) ? 'inp' : 'outp', + pinDataType: type, + offsetX: (inType) ? -7 : 7, + helper: helper, + fill: '', + }); + pin.on("mouseenter", () => { + pin.strokeWidth(4); + layer.draw(); + }); + pin.on("mouseleave", () => { + pin.strokeWidth(2); + layer.draw(); + }); + pin.on("wireremoved", (e) => { + if (e.isPinEmpty) { + pin.fill('transparent'); + } + }); + pin.on("wireconnected", (e) => { + pin.fill(`${colorMap[type]}`); + }); + pin.on("wiringstart", (e) => { + pin.fill(`${colorMap[type]}`); + layer.draw(); + }); + return pin; + }, + // getOutputPin: function(){ + // let pin = new Konva.Circle({ + // radius: 7, + // stroke: 'yellow', + // strokeWidth: '2', + // name: 'pin', + // pinType: 'outp', + // }); + // return pin; + // }, + getLabel: function (text, size, width, color) { + let rect = new Konva.Rect({ + width: width, + height: size + 3, + fill: colorMap[color], + cornerRadius: [5, 5, 0, 0], + // fillLinearGradientStartPoint: { x: 0, y: 0 }, + // fillLinearGradientEndPoint: { x: width, y: size + 3 }, + // fillLinearGradientColorStops: [0, colorMap[color], 1, 'rgba(0, 0, 0, 0)'], + // fillRadialGradientStartPoint: {x: 0, y: 0}, + // fillRadialGradientEndPoint: { x: 30, y: 0 }, + // fillRadialGradientColorStops: [0, colorMap[color], 1, '#2d3436'], + // fillRadialGradientStartRadius: size / 3, + // fillRadialGradientEndRadius: 100, + + // fillLinearGradientColorStops: [0, '#9e768f', 1, '#ff4e00'], + + // #ec9f05 #ff4e00 + }); + let label = new Konva.Text({ + text: text, + fontSize: size - 5, + fontFamily: 'Verdana', + fill: colorMap['MainLabel'], + width: width, + // height: size + 3, + y: 2, + align: 'left', + padding: 3, + // padding: 10 + }); + return { bg: rect, text: label }; + }, + getPinCounts: function (nodeDescription) { + let inputPinCounts = 0; + let outputPinCounts = 0; + if (nodeDescription.execIn) + inputPinCounts++; + if (nodeDescription.inputs) { + inputPinCounts += Object.keys(nodeDescription.inputs).length; + } + + //For outputs + if (nodeDescription.execOut) { + outputPinCounts += Object.keys(nodeDescription.execOut).length; + } + if (nodeDescription.outputs) { + outputPinCounts += Object.keys(nodeDescription.outputs).length; + + } + return Math.max(inputPinCounts, outputPinCounts); + }, + // getEditableTextBox: function (type, stage, index) { + // let rect = new Konva.Rect({ + // width: (type == 'Boolean') ? 14 : 50, + // height: 14, + // stroke: colorMap[type], + // strokeWidth: 1, + // }); + // return rect; + // }, + getInputLabel: function (labelText, isInput) { + let text = new Konva.Text({ + // width: 40, + height: 14, + text: labelText, + fontSize: 11, + fontFamily: 'Verdana', + fill: colorMap['Text'], + }); + if (isInput) + text.offsetX(0); + else + text.offsetX(text.width()); + // text.off() + return text; + }, + getExecOutTitle: function (labelText) { + let text = new Konva.Text({ + height: 14, + fontSize: 11, + text: labelText, + fontFamily: 'Verdana', + fill: "white", + }); + text.offsetX(text.width()); + return text; + }, + optimizeDrag: function (grp, stage, layer) { + let dragLayer = stage.findOne('#dragLayer'); + let wireLayer = stage.findOne('#wireLayer'); + grp.on('dragstart', () => { + grp.moveTo(dragLayer); + for (let each of grp.customClass.execInPins) { + for (let aWire of each.wire) { + aWire.moveTo(dragLayer); + } + } + for (let each of grp.customClass.execOutPins) { + if (each.wire) + each.wire.moveTo(dragLayer); + } + for (let each of grp.customClass.inputPins) { + if (each.wire) + each.wire.moveTo(dragLayer); + } + for (let each of grp.customClass.outputPins) { + for (let aWire of each.wire) { + aWire.moveTo(dragLayer); + } + } + wireLayer.draw(); + dragLayer.draw(); + layer.draw(); + // try { + // if (layer.hasChildren()) + // layer.cache(); + // if (wireLayer.hasChildren()) + // wireLayer.cache(); + // } + // catch (err) { + + // } + }) + grp.on('dragend', () => { + grp.moveTo(layer); + for (let each of grp.customClass.execInPins) { + for (let aWire of each.wire) { + aWire.moveTo(wireLayer); + } + } + for (let each of grp.customClass.execOutPins) { + if (each.wire) + each.wire.moveTo(wireLayer); + } + for (let each of grp.customClass.inputPins) { + if (each.wire) + each.wire.moveTo(wireLayer); + } + for (let each of grp.customClass.outputPins) { + for (let aWire of each.wire) { + aWire.moveTo(wireLayer); + } + } + // layer.clearCache(); + // wireLayer.clearCache(); + wireLayer.draw(); + dragLayer.draw(); + layer.draw(); + }); + }, + getBorderRect: function (height, width) { + let rect = new Konva.Rect({ + height: height, + width: width, + fill: 'transparent', + stroke: '#dbd8e3', + strokeWidth: 0, + cornerRadius: 5, + name: 'borderbox', + }); + rect.off('click mouseover mouseenter mouseleave'); + return rect; + }, + ProgramNode: class { + constructor(nodeDescription, location, layer, stage) { + + + + this.grp = new Konva.Group({ + draggable: true, + name: "aProgramNodeGroup", + }); + if (nodeDescription.nodeTitle == 'Begin') { + this.grp.id('Begin'); + } + this.grp.customClass = this; + // this.grp.on('dblclick', (e) => { + // console.table(e.currentTarget.customClass); + // }) + this.nodeDescription = nodeDescription; + let relativePosition = placeLocation.bind(stage); + let maxOfPinsOnEitherSide = Nodes.getPinCounts(nodeDescription); + let height = maxOfPinsOnEitherSide * 50 + 15; + let width = nodeDescription.colums * 15; + this.grp.position(relativePosition(location)); + let rect = Nodes.getRectBlock(height, width); + this.grp.add(rect); + let borderRect = Nodes.getBorderRect(height, width); + let titleLabel = Nodes.getLabel(nodeDescription.nodeTitle, 20, width, nodeDescription.color); + this.grp.add(titleLabel.bg); + this.grp.add(titleLabel.text); + this.grp.add(borderRect); + + this.grp.on("mouseover", (e) => { + // console.log(e); + // if(shape == this.grp) + borderRect.strokeWidth(1); + layer.draw(); + }); + this.grp.on("mouseleave", (e) => { + // rect.opacity(0.9); + // rect.shadowOffset({ x: 15, y: 15 }); + // this.grp.scale(1); + // this.grp.filters([]); + borderRect.strokeWidth(0); + layer.draw(); + }); + this.grp.on('mousedown', (e) => { + rect.shadowBlur(25); + // rect.shadowOffset({ x: 25, y: 25 }); + layer.draw(); + }) + this.grp.on('mouseup', (e) => { + rect.shadowBlur(15); + // rect.shadowOffset({ x: 15, y: 15 }); + layer.draw(); + }) + /****/ + + Nodes.optimizeDrag(this.grp, stage, layer); + + /****/ + // titleLabel.offsetX(titleLabel.width() / 2); + let inputPinsPlaced = 0, outputPinsPlaced = 0; + this.execInPins = []; + if (nodeDescription.execIn == true) { + let execInPin = Nodes.getExecPin(true, 'exec-in-0', layer); + execInPin.position({ x: 7, y: 44 }); + if (nodeDescription.pinExecInId == null) { + execInPin.id(`${execInPin._id}`); + } + else { + execInPin.id(nodeDescription.pinExecInId); + } + this.nodeDescription.pinExecInId = execInPin.id(); + this.grp.add(execInPin); + let tmp = { + thisNode: execInPin, + wire: [], + } + this.execInPins.push(tmp); + inputPinsPlaced = 1; + } + + let X = nodeDescription.nodeTitle.split(" "); + this.type = { + isGetSet: (X[0] == 'Get' || X[0] == 'Set'), + typeOfNode: nodeDescription.nodeTitle, + } + this.execOutPins = []; + if (nodeDescription.execOut) { + Object.keys(nodeDescription.execOut).forEach((value, index) => { + let execOutPin = Nodes.getExecPin(false, `exec-out-${index}`, layer); + execOutPin.position({ x: width - 7, y: 44 + nodeDescription.execOut[value].outOrder * 39 }); + if (nodeDescription.execOut[value].pinExecOutId == null) { + execOutPin.id(`${execOutPin._id}`); + } + else { + execOutPin.id(nodeDescription.execOut[value].pinExecOutId); + } + this.nodeDescription.execOut[value].pinExecOutId = execOutPin.id(); + this.grp.add(execOutPin); + if (nodeDescription.execOut[value].execOutTitle) { + let exLabel = Nodes.getExecOutTitle(nodeDescription.execOut[value].execOutTitle); + exLabel.position({ x: width - 28, y: 44 + nodeDescription.execOut[value].outOrder * 39 - 4 }); + this.grp.add(exLabel); + } + let tmp = { + thisNode: execOutPin, + wire: null, + title: value.execOutTitle, + } + this.execOutPins.push(tmp); + outputPinsPlaced++; + }); + } + this.inputPins = []; + if (nodeDescription.inputs) { + Object.keys(nodeDescription.inputs).forEach((value, index) => { + let inputPin = Nodes.getInputPin(true, `inp-${index}`, nodeDescription.inputs[value].dataType, layer); + inputPin.position({ x: 7, y: 44 + 39 * inputPinsPlaced }); + if (nodeDescription.inputs[value].pinInId == null) { + inputPin.id(`${inputPin._id}`); + } + else { + inputPin.id(nodeDescription.inputs[value].pinInId); + } + this.nodeDescription.inputs[value].pinInId = inputPin.id(); + // iprect.position({ x: 28, y: 44 + 39 * inputPinsPlaced - 2 }); + let iprect = null; + let iplabel = Nodes.getInputLabel(nodeDescription.inputs[value].inputTitle, true); + iplabel.position({ x: 28, y: 44 + 39 * inputPinsPlaced - 4 }); + if (nodeDescription.inputs[value].isInputBoxRequired !== false) { + // console.log(nodeDescription.inputs, this.nodeDescription.inputs); + iprect = new InputBox(stage, layer, nodeDescription.inputs[value].dataType, this.grp, { x: 28, y: 44 + 39 * inputPinsPlaced - 2 }, colorMap, inputPin, iplabel, inputPinsPlaced, nodeDescription.inputs[value], this.nodeDescription.inputs[value]); + iplabel.position({ x: 28, y: 44 + 39 * inputPinsPlaced - 14 }); + } + this.grp.add(iplabel); + this.grp.add(inputPin); + // this.grp.add(iprect); + let tmp = { + thisNode: inputPin, + wire: null, + textBox: iprect, + value: null, + title: value.inputTitle, + } + this.inputPins.push(tmp); + inputPinsPlaced++; + }); + } + this.outputPins = []; + if (nodeDescription.outputs) { + Object.keys(nodeDescription.outputs).forEach((value, index) => { + let outputPin = Nodes.getInputPin(false, `out-${index}`, nodeDescription.outputs[value].dataType, layer); + outputPin.position({ x: width - 7, y: 44 + 39 * nodeDescription.outputs[value].outOrder }); + if (nodeDescription.outputs[value].pinOutId == null) { + outputPin.id(`${outputPin._id}`); + } + else { + outputPin.id(nodeDescription.outputs[value].pinOutId); + } + nodeDescription.outputs[value].pinOutId = outputPin.id(); + this.grp.add(outputPin); + let outLabel = Nodes.getInputLabel(nodeDescription.outputs[value].outputTitle, false); + outLabel.position({ x: width - 28, y: 44 + 39 * nodeDescription.outputs[value].outOrder - 4 }) + this.grp.add(outLabel); + let tmp = { + wire: [], + value: null, + title: value.outputTitle, + } + this.outputPins.push(tmp); + outputPinsPlaced++; + }) + }; + // this.grp.cache(); + layer.add(this.grp); + layer.draw(); + layer.draw(); + // console.log(JSON.parse(JSON.stringify(this.grp))); + } + }, + + + + + + CreateNode: function (type, location, layer, stage, isGetSet, dataType, defValue) { + let nodeDescription = null; + if (hasType(type)) { + nodeDescription = buildNodeDescription(type); + } else if (isGetSet === 'Set' || isGetSet === 'Get') { + nodeDescription = {}; + if (isGetSet == "Set") { + let defaultValueByType = { "Number": 0, "Boolean": true, "String": "'hello'", "Array": '[]' }; + nodeDescription.nodeTitle = type; + nodeDescription.execIn = true; + nodeDescription.pinExecInId = null; + nodeDescription.execOut = { execOut0: { execOutTitle: null, pinExecOutId: null, outOrder: 0 } }; + nodeDescription.inputs = { input0: { inputTitle: 'Value', dataType: dataType, defValue: defaultValueByType[dataType], pinInId: null } }; + nodeDescription.outputs = { output0: { outputTitle: 'Value(Ref)', dataType: dataType, pinOutId: null, outOrder: 1 } }; + nodeDescription.color = 'Func'; + nodeDescription.rows = 2; + nodeDescription.colums = 12; + } + if (isGetSet == "Get") { + nodeDescription.nodeTitle = type; + nodeDescription.outputs = { output0: { outputTitle: 'Value(Ref)', dataType: dataType, pinOutId: null, outOrder: 0 } }; + nodeDescription.color = 'Get'; + nodeDescription.rows = 2; + nodeDescription.colums = 10; + } + } + if (!nodeDescription) return; + new this.ProgramNode(nodeDescription, location, layer, stage); + } +}; + +/* + +//required json +{ + type: string, + id: num, + inputs:{ + count: integer, + execIn1:{ + name: "", + wire: KonvaWire else null + } + ip1: { + dataType: string, + default: num/str etc, + value: num/str etc, + name: "" + wire: Konva.Line else null if no wire + } + } + outputs:{ + count: integer, + execOut1:{ + name: "", + wire: KonvaWire else null + } + out1: { + dataType: string, + default: num/str etc, + value: num/str etc, + name: "" + wire: Konva.Line else null if no wire + } + } + +} + + +*/ diff --git a/javascript/InputBox/InputBox.js b/src/js/nodes/nodeInputBox.js similarity index 99% rename from javascript/InputBox/InputBox.js rename to src/js/nodes/nodeInputBox.js index f345c14..1ce1663 100644 --- a/javascript/InputBox/InputBox.js +++ b/src/js/nodes/nodeInputBox.js @@ -1,4 +1,4 @@ - + export var InputBox = class{ constructor(stage, layer, type, grp, position, colorMap, inputPin, iplabel, inputPinsPlaced, defValueContainer, defValueContainerForSave) { @@ -103,4 +103,4 @@ export var InputBox = class{ }); grp.add(this.inputBox); } -} \ No newline at end of file +} diff --git a/javascript/setLocationOfNode/setLocationOfNode.js b/src/js/nodes/nodePosition.js similarity index 81% rename from javascript/setLocationOfNode/setLocationOfNode.js rename to src/js/nodes/nodePosition.js index b405820..592b506 100644 --- a/javascript/setLocationOfNode/setLocationOfNode.js +++ b/src/js/nodes/nodePosition.js @@ -1,6 +1,6 @@ -export var setLocationOfNode = { +export var setLocationOfNode = { place: function(node, location , stage){ node.x((location.x - stage.x()) / stage.scaleX()); node.y((location.y - stage.y()) / stage.scaleY()); } -} \ No newline at end of file +} diff --git a/javascript/Wiring/Wiring.js b/src/js/nodes/wiring.js similarity index 98% rename from javascript/Wiring/Wiring.js rename to src/js/nodes/wiring.js index c1924dd..5601ef0 100644 --- a/javascript/Wiring/Wiring.js +++ b/src/js/nodes/wiring.js @@ -1,5 +1,5 @@ -import { deleteWire, deleteHalfWire } from '../Delete/delete.js' -import { colorMap } from '../ColorMap/colorMap.js' +import { deleteWire, deleteHalfWire } from '../editor/deleteHandler.js' +import { colorMap } from '../core/colorMap.js' let placeLocation = function (location, stage) { return { x: (location.x - stage.x()) / stage.scaleX(), diff --git a/javascript/SaveAndLoad/SaveAndLoad.js b/src/js/persistence/saveAndLoad.js similarity index 97% rename from javascript/SaveAndLoad/SaveAndLoad.js rename to src/js/persistence/saveAndLoad.js index cc39ce7..86dfa55 100644 --- a/javascript/SaveAndLoad/SaveAndLoad.js +++ b/src/js/persistence/saveAndLoad.js @@ -1,7 +1,7 @@ -import { Nodes } from '../Nodes/nodes.js' -import { addConnectionWire } from '../Wiring/Wiring.js' -import { variableList } from '../Variable/variable.js' -import {showAlert, vscriptOnLoad} from '../main/alertBox.js' +import { Nodes } from '../nodes/nodeFactory.js' +import { addConnectionWire } from '../nodes/wiring.js' +import { variableList } from '../ui/variableList.js' +import { showAlert, vscriptOnLoad } from '../ui/dialogs.js' function writeError(err, msg) { document.getElementById("console-window").classList.toggle("hidden", false); let codeDoc = document.getElementById("console").contentWindow.document; diff --git a/src/js/registry/index.js b/src/js/registry/index.js new file mode 100644 index 0000000..9eb4c4d --- /dev/null +++ b/src/js/registry/index.js @@ -0,0 +1,15 @@ +/** + * Node registry entry point. Import this once (e.g. from main.js) to register all built-in nodes. + * Then use the registry API for node descriptions, context menu order, and compiler codegen. + */ +import './nodeDefinitions.js'; +export { + registerNode, + registerMenuOrder, + buildNodeDescription, + getDefinition, + getMenuOrder, + runExecCodegen, + runExprCodegen, + hasType, +} from './registry.js'; diff --git a/src/js/registry/nodeDefinitions.js b/src/js/registry/nodeDefinitions.js new file mode 100644 index 0000000..2e49ad1 --- /dev/null +++ b/src/js/registry/nodeDefinitions.js @@ -0,0 +1,1383 @@ +/** + * All built-in node definitions in one place. + * + * To add a new node (one place only): + * 1. Call registerNode({ id, label?, schema, execCodegen?, exprCodegen? }). + * 2. schema: { execIn?, execOut?: [{ execOutTitle?, outOrder? }], inputs?, outputs?, color, rows, colums }. + * 3. execCodegen(compiler, node): use compiler.script, compiler.getExecOut(node), compiler.getInputPins(node), compiler.coreAlgorithm(), compiler.handleInputs(). + * 4. exprCodegen(compiler, inputNode): return a string expression; use compiler.getInputPins(inputNode.node), inputNode.srcOutputPinNumber for multi-output nodes. + * 5. Add the node id to the registerMenuOrder() array at the bottom (use null for a separator). + */ +import { registerNode, registerMenuOrder } from './registry.js'; +import { BuilInFunctions } from '../compiler/builtInFunctions.js'; + +// ---------- Helper used by codegen (compiler has getExecOut, getInputPins, handleInputs, script, coreAlgorithm, builtin_functions) ---------- +// Codegen functions receive (compiler, node) or (compiler, inputNode) and use compiler.* freely. + +// ---------- Flow: Begin, Print, Alert, Confirm, Prompt ---------- +registerNode({ + id: 'Begin', + schema: { + execIn: false, + execOut: [{ execOutTitle: null, outOrder: 0 }], + color: 'Begin', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + const execOutPins = compiler.getExecOut(node); + compiler.coreAlgorithm(execOutPins[0]); // traverse first so script has generated code + let func_string = `/////////CodeWire Functions Space Begins/////////////\n\n`; + for (const each_function in compiler.builtin_functions) { + func_string = func_string + BuilInFunctions[each_function]; + } + func_string += `\n/////////CodeWire Functions Space Ends/////////////\n//\n//\n/////////Generated JS Code Space Begins/////////////\n`; + compiler.script = func_string + compiler.script; + compiler.script += `\n/////////Generated JS Code Space Ends/////////////`; + }, +}); + +registerNode({ + id: 'Print', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'Value', dataType: 'Data', defValue: "'hello'" }], + color: 'Print', + rows: 3, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `console.log(${compiler.handleInputs(inputPins[0])});\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, +}); + +registerNode({ + id: 'Alert', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'Value', dataType: 'Data', defValue: "'hello'" }], + color: 'Print', + rows: 3, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `alert(${compiler.handleInputs(inputPins[0])});\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, +}); + +registerNode({ + id: 'Confirm', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'Message', dataType: 'String', defValue: "'Ok'" }], + outputs: [{ outputTitle: 'Ok?', dataType: 'Boolean', outOrder: 1 }], + color: 'Print', + rows: 3, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.builtin_functions = { ...compiler.builtin_functions, _confirm: true }; + compiler.script += `let _confirm_answer${node._id} = _confirm(${compiler.handleInputs(inputPins[0])});\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + return `_confirm_answer${inputNode.node._id}`; + }, +}); + +registerNode({ + id: 'Prompt', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [ + { inputTitle: 'Message', dataType: 'String', defValue: "'Ok'" }, + { inputTitle: 'Default', dataType: 'String', defValue: "'Yes'" }, + ], + outputs: [ + { outputTitle: 'Ok?', dataType: 'Boolean', outOrder: 1 }, + { outputTitle: 'Value', dataType: 'String', outOrder: 2 }, + ], + color: 'Print', + rows: 3, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.builtin_functions = { ...compiler.builtin_functions, _prompt: true }; + compiler.script += `let [_prompt_ok${node._id}, _prompt_value${node._id}] = _prompt(${compiler.handleInputs(inputPins[0])}, ${compiler.handleInputs(inputPins[1])});\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + if (inputNode.srcOutputPinNumber == 0) return `_prompt_ok${inputNode.node._id}`; + return `_prompt_value${inputNode.node._id}`; + }, +}); + +// ---------- Flow: If/Else, While, For, ForEach, Break, Continue ---------- +registerNode({ + id: 'If/Else', + schema: { + execIn: true, + execOut: [ + { execOutTitle: 'True', outOrder: 0 }, + { execOutTitle: 'False', outOrder: 1 }, + { execOutTitle: 'Done', outOrder: 2 }, + ], + inputs: [{ inputTitle: 'Bool', dataType: 'Boolean', defValue: true }], + color: 'Logic', + rows: 3, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `if(${compiler.handleInputs(inputPins[0])}){\n`; + compiler.coreAlgorithm(execOutPins[0]); + compiler.script += `}\nelse{\n`; + compiler.coreAlgorithm(execOutPins[1]); + compiler.script += `}\n`; + compiler.coreAlgorithm(execOutPins[2]); + }, +}); + +registerNode({ + id: 'WhileLoop', + schema: { + execIn: true, + execOut: [ + { execOutTitle: 'Loop', outOrder: 0 }, + { execOutTitle: 'Done', outOrder: 1 }, + ], + inputs: [{ inputTitle: 'Condition', dataType: 'Boolean', defValue: true }], + color: 'Logic', + rows: 3, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += ` while(${compiler.handleInputs(inputPins[0])}){\n`; + compiler.coreAlgorithm(execOutPins[0]); + compiler.script += `}\n`; + compiler.coreAlgorithm(execOutPins[1]); + }, +}); + +registerNode({ + id: 'ForLoop', + schema: { + execIn: true, + execOut: [ + { execOutTitle: 'Loop Body', outOrder: 0 }, + { execOutTitle: 'Completed', outOrder: 2 }, + ], + inputs: [ + { inputTitle: 'From', dataType: 'Number', defValue: 0 }, + { inputTitle: 'To(Excl)', dataType: 'Number', defValue: 10 }, + { inputTitle: 'Increment', dataType: 'Number', defValue: 1 }, + ], + outputs: [{ outputTitle: 'Index', dataType: 'Number', outOrder: 1 }], + color: 'Logic', + rows: 2, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + const forVar = `i${node._id}`; + compiler.script += `for(let ${forVar} = (${compiler.handleInputs(inputPins[0])}); ${forVar} < (${compiler.handleInputs(inputPins[1])}); ${forVar} += (${compiler.handleInputs(inputPins[2])})){\n`; + compiler.coreAlgorithm(execOutPins[0]); + compiler.script += `}\n`; + compiler.coreAlgorithm(execOutPins[1]); + }, + exprCodegen(compiler, inputNode) { + return `i${inputNode.node._id}`; + }, +}); + +registerNode({ + id: 'ForEachLoop', + schema: { + execIn: true, + execOut: [ + { execOutTitle: 'Loop Body', outOrder: 0 }, + { execOutTitle: 'Completed', outOrder: 4 }, + ], + inputs: [{ inputTitle: 'Array', dataType: 'Array', defValue: '[]', isInputBoxRequired: false }], + outputs: [ + { outputTitle: 'Value', dataType: 'Data', outOrder: 1 }, + { outputTitle: 'Index', dataType: 'Number', outOrder: 2 }, + ], + color: 'Logic', + rows: 2, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + const forVar = `i${node._id}`; + compiler.script += `${compiler.handleInputs(inputPins[0])}.forEach((value${forVar}, ${forVar}, array${forVar}) => {\n`; + compiler.coreAlgorithm(execOutPins[0]); + compiler.script += `});\n`; + compiler.coreAlgorithm(execOutPins[1]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + if (inputNode.srcOutputPinNumber == 0) return `valuei${inputNode.node._id}`; + if (inputNode.srcOutputPinNumber == 1) return `i${inputNode.node._id}`; + return `arrayi${inputNode.node._id}`; + }, +}); + +registerNode({ + id: 'Continue', + schema: { + execIn: true, + execOut: [], + color: 'Logic', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + compiler.script += `continue;\n`; + }, +}); + +registerNode({ + id: 'Break', + schema: { + execIn: true, + execOut: [], + color: 'Logic', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + compiler.script += `break;\n`; + }, +}); + +registerNode({ + id: 'Assert', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'Condition', dataType: 'Boolean', defValue: true }], + color: 'Logic', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `if (!(${compiler.handleInputs(inputPins[0])})) throw new Error('Assertion failed');\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, +}); + +registerNode({ + id: 'Sleep', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'Ms', dataType: 'Number', defValue: 1000 }], + color: 'Func', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.builtin_functions = { ...compiler.builtin_functions, _sleep: true }; + compiler.script += `_sleep(${compiler.handleInputs(inputPins[0])});\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, +}); + +registerNode({ + id: 'Try/Catch', + schema: { + execIn: true, + execOut: [ + { execOutTitle: 'Try', outOrder: 0 }, + { execOutTitle: 'Catch', outOrder: 1 }, + { execOutTitle: 'Continue', outOrder: 2 }, + ], + color: 'Logic', + rows: 2, + colums: 12, + }, + execCodegen(compiler, node) { + const execOutPins = compiler.getExecOut(node); + compiler.script += `try {\n`; + compiler.coreAlgorithm(execOutPins[0]); + compiler.script += `} catch(_err) {\n`; + compiler.coreAlgorithm(execOutPins[1]); + compiler.script += `}\n`; + compiler.coreAlgorithm(execOutPins[2]); + }, +}); + +// ---------- Math ---------- +registerNode({ + id: 'Add', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} + ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Subtract', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} - ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Multiply', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} * ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Divide', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} / ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Modulo', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 1 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 2 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} % ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Power', + schema: { + inputs: [ + { inputTitle: 'Base', dataType: 'Number', defValue: 0 }, + { inputTitle: 'Exp', dataType: 'Number', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `Math.pow(${compiler.handleInputs(inputPins[0])}, ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Random', + schema: { + outputs: [{ outputTitle: 'Random[0,1)', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler) { + return `Math.random()`; + }, +}); + +registerNode({ + id: 'Ceil', + schema: { + inputs: [{ inputTitle: 'Value', dataType: 'Number', defValue: 0 }], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `Math.ceil(${compiler.handleInputs(inputPins[0])})`; + }, +}); + +registerNode({ + id: 'Floor', + schema: { + inputs: [{ inputTitle: 'Value', dataType: 'Number', defValue: 0 }], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `Math.floor(${compiler.handleInputs(inputPins[0])})`; + }, +}); + +registerNode({ + id: 'Max(Num)', + schema: { + inputs: [ + { inputTitle: 'A', dataType: 'Number', defValue: 0 }, + { inputTitle: 'B', dataType: 'Number', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `Math.max(${compiler.handleInputs(inputPins[0])}, ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Min(Num)', + schema: { + inputs: [ + { inputTitle: 'A', dataType: 'Number', defValue: 0 }, + { inputTitle: 'B', dataType: 'Number', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `Math.min(${compiler.handleInputs(inputPins[0])}, ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Round', + schema: { + inputs: [{ inputTitle: 'Value', dataType: 'Number', defValue: 0 }], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `Math.round(${compiler.handleInputs(inputPins[0])})`; + }, +}); + +registerNode({ + id: 'Abs', + schema: { + inputs: [{ inputTitle: 'Value', dataType: 'Number', defValue: 0 }], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `Math.abs(${compiler.handleInputs(inputPins[0])})`; + }, +}); + +registerNode({ + id: 'Clamp(Num)', + schema: { + inputs: [ + { inputTitle: 'Value', dataType: 'Number', defValue: 0 }, + { inputTitle: 'Min', dataType: 'Number', defValue: 0 }, + { inputTitle: 'Max', dataType: 'Number', defValue: 10 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + const v = compiler.handleInputs(inputPins[0]); + const min = compiler.handleInputs(inputPins[1]); + const max = compiler.handleInputs(inputPins[2]); + return `Math.min(Math.max(${v}, ${min}), ${max})`; + }, +}); + +// ---------- Comparison: Swap, Equals, Not Equals, Less, LessEq, Greater, GreaterEq ---------- +registerNode({ + id: 'Swap', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [ + { inputTitle: 'Ref1', dataType: 'Data', isInputBoxRequired: false }, + { inputTitle: 'Ref2', dataType: 'Data', isInputBoxRequired: false }, + ], + outputs: [ + { outputTitle: 'Ref1', dataType: 'Data', outOrder: 1 }, + { outputTitle: 'Ref2', dataType: 'Data', outOrder: 2 }, + ], + color: 'Func', + rows: 2, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `[${compiler.handleInputs(inputPins[0])}, ${compiler.handleInputs(inputPins[1])}] = [${compiler.handleInputs(inputPins[1])}, ${compiler.handleInputs(inputPins[0])}];\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[inputNode.srcOutputPinNumber])}`; + }, +}); + +registerNode({ + id: 'Equals', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Data', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Data', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} === ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Not Equals', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Data', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Data', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} !== ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Less', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 1 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} < ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'LessEq', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 1 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} <= ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'Greater', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 1 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} > ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'GreaterEq', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 0 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 1 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} >= ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +// ---------- Logic: AND, OR, XOR, NEG, bAND, bOR, bXOR, bNEG ---------- +registerNode({ + id: 'AND', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Boolean', defValue: true }, + { inputTitle: 'ValueB', dataType: 'Boolean', defValue: true }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} && ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'OR', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Boolean', defValue: true }, + { inputTitle: 'ValueB', dataType: 'Boolean', defValue: true }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} || ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'XOR', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Boolean', defValue: true }, + { inputTitle: 'ValueB', dataType: 'Boolean', defValue: true }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} ^ ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'NEG', + schema: { + inputs: [{ inputTitle: 'Value', dataType: 'Boolean', defValue: false }], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `!(${compiler.handleInputs(inputPins[0])})`; + }, +}); + +registerNode({ + id: 'Ternary', + schema: { + inputs: [ + { inputTitle: 'Condition', dataType: 'Boolean', defValue: true }, + { inputTitle: 'Then', dataType: 'Data', defValue: 0 }, + { inputTitle: 'Else', dataType: 'Data', defValue: 0 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Data', outOrder: 0 }], + color: 'Logic', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} ? ${compiler.handleInputs(inputPins[1])} : ${compiler.handleInputs(inputPins[2])})`; + }, +}); + +registerNode({ + id: 'bAND', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 1 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 1 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} & ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'bOR', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 1 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 1 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} | ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'bXOR', + schema: { + inputs: [ + { inputTitle: 'ValueA', dataType: 'Number', defValue: 1 }, + { inputTitle: 'ValueB', dataType: 'Number', defValue: 1 }, + ], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])} ^ ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +registerNode({ + id: 'bNEG', + schema: { + inputs: [{ inputTitle: 'Value', dataType: 'Number', defValue: 0 }], + outputs: [{ outputTitle: 'Result', dataType: 'Number', outOrder: 0 }], + color: 'Math', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `~${compiler.handleInputs(inputPins[0])}`; + }, +}); + +// ---------- Func: OpenWindow, HttpRequest, GetByName(JSON) ---------- +registerNode({ + id: 'OpenWindow', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'URL', dataType: 'String', defValue: "'link'" }], + outputs: [{ outputTitle: 'Success?', dataType: 'Boolean', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.builtin_functions = { ...compiler.builtin_functions, _newWindow: true }; + compiler.script += `let _window_opened${node._id} = _newWindow(${compiler.handleInputs(inputPins[0])});\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + return `_window_opened${inputNode.node._id}`; + }, +}); + +registerNode({ + id: 'HttpRequest', + schema: { + execIn: true, + execOut: [ + { execOutTitle: 'OnSuccess', outOrder: 0 }, + { execOutTitle: 'OnFail', outOrder: 2 }, + { execOutTitle: 'Continue', outOrder: 3 }, + ], + inputs: [{ inputTitle: 'URL', dataType: 'String', defValue: "'link'" }], + outputs: [{ outputTitle: 'JSON', dataType: 'Data', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.builtin_functions = { ...compiler.builtin_functions, fetch_data: true }; + compiler.script += `fetch_data(${compiler.handleInputs(inputPins[0])})\n.then((json_data${node._id}) => {\n`; + compiler.coreAlgorithm(execOutPins[0]); + compiler.script += `})\n.catch((err) => {\n`; + compiler.coreAlgorithm(execOutPins[1]); + compiler.script += `});\n`; + compiler.coreAlgorithm(execOutPins[2]); + }, + exprCodegen(compiler, inputNode) { + return `json_data${inputNode.node._id}`; + }, +}); + +registerNode({ + id: 'GetByName(JSON)', + schema: { + inputs: [ + { inputTitle: 'JSON', dataType: 'Data', isInputBoxRequired: false }, + { inputTitle: 'Name', dataType: 'String', defValue: "'id'" }, + ], + outputs: [{ outputTitle: 'Data', dataType: 'Data', outOrder: 0 }], + color: 'Get', + rows: 2, + colums: 12, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[0])}[${compiler.handleInputs(inputPins[1])}]`; + }, +}); + +registerNode({ + id: 'ParseInt', + schema: { + inputs: [ + { inputTitle: 'String', dataType: 'String', defValue: "'0'", isInputBoxRequired: false }, + { inputTitle: 'Radix', dataType: 'Number', defValue: 10 }, + ], + outputs: [{ outputTitle: 'Number', dataType: 'Number', outOrder: 0 }], + color: 'Func', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `parseInt(${compiler.handleInputs(inputPins[0])}, ${compiler.handleInputs(inputPins[1])})`; + }, +}); + +// ---------- Str/Array: StrToArray, ArrayToStr ---------- +registerNode({ + id: 'StrToArray', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'String', dataType: 'String', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'Array', dataType: 'Array', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `let strArray${node._id} = ${compiler.handleInputs(inputPins[0])}.split('');\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + return `strArray${inputNode.node._id}`; + }, +}); + +registerNode({ + id: 'ArrayToStr', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'String', dataType: 'String', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `let arrayStr${node._id} = ${compiler.handleInputs(inputPins[0])}.join('');\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + return `arrayStr${inputNode.node._id}`; + }, +}); + +// ---------- Array: Length, Front, Back, GetByPos, SetByPos, Search, BinarySearch(Num), PushBack, PopBack, PushFront, PopFront, Insert, Sort(Num), isEmpty, Reverse, Max(Array), Min(Array) ---------- +registerNode({ + id: 'Length', + schema: { + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'Value', dataType: 'Number', outOrder: 0 }], + color: 'Get', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[0])}.length`; + }, +}); + +registerNode({ + id: 'Front', + schema: { + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'Front(Ref)', dataType: 'Data', outOrder: 0 }], + color: 'Get', + rows: 2, + colums: 11, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[0])}[0]`; + }, +}); + +registerNode({ + id: 'Back', + schema: { + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'Back(Ref)', dataType: 'Data', outOrder: 0 }], + color: 'Get', + rows: 2, + colums: 11, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[0])}[${compiler.handleInputs(inputPins[0])}.length - 1]`; + }, +}); + +registerNode({ + id: 'GetByPos', + schema: { + inputs: [ + { inputTitle: 'Pos', dataType: 'Number', defValue: 0 }, + { inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }, + ], + outputs: [{ outputTitle: 'Value(Ref)', dataType: 'Data', outOrder: 0 }], + color: 'Get', + rows: 2, + colums: 12, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[1])}[${compiler.handleInputs(inputPins[0])}]`; + }, +}); + +registerNode({ + id: 'SetByPos', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [ + { inputTitle: 'Pos', dataType: 'Number', defValue: 0 }, + { inputTitle: 'Value', dataType: 'Data', defValue: 1 }, + { inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }, + ], + outputs: [{ outputTitle: 'Value(Ref)', dataType: 'Data', outOrder: 1 }], + color: 'Func', + rows: 4, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `${compiler.handleInputs(inputPins[2])}[${compiler.handleInputs(inputPins[0])}] = ${compiler.handleInputs(inputPins[1])};\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[2])}[${compiler.handleInputs(inputPins[0])}]`; + }, +}); + +registerNode({ + id: 'Search', + schema: { + inputs: [ + { inputTitle: 'Value', dataType: 'Data', defValue: 0 }, + { inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }, + ], + outputs: [ + { outputTitle: 'Exist', dataType: 'Boolean', outOrder: 0 }, + { outputTitle: 'Index', dataType: 'Number', outOrder: 1 }, + ], + color: 'Func', + rows: 2, + colums: 11, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + if (inputNode.srcOutputPinNumber == 0) { + return `(${compiler.handleInputs(inputPins[1])}.find((value) => value === ${compiler.handleInputs(inputPins[0])}) === ${compiler.handleInputs(inputPins[0])})`; + } + return `(${compiler.handleInputs(inputPins[1])}.findIndex((value) => value === ${compiler.handleInputs(inputPins[0])}))`; + }, +}); + +registerNode({ + id: 'BinarySearch(Num)', + schema: { + inputs: [ + { inputTitle: 'Value', dataType: 'Number', defValue: 0 }, + { inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }, + ], + outputs: [ + { outputTitle: 'Exist', dataType: 'Boolean', outOrder: 0 }, + { outputTitle: 'Lower Bound', dataType: 'Number', outOrder: 1 }, + { outputTitle: 'Upper Bound', dataType: 'Number', outOrder: 2 }, + ], + color: 'Func', + rows: 2, + colums: 13, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + if (inputNode.srcOutputPinNumber == 0) { + compiler.builtin_functions = { ...compiler.builtin_functions, binary_search_exist: true }; + return `binary_search_exist(${compiler.handleInputs(inputPins[1])}, ${compiler.handleInputs(inputPins[0])})`; + } + if (inputNode.srcOutputPinNumber == 1) { + compiler.builtin_functions = { ...compiler.builtin_functions, lower_bound: true }; + return `lower_bound(${compiler.handleInputs(inputPins[1])}, ${compiler.handleInputs(inputPins[0])})`; + } + compiler.builtin_functions = { ...compiler.builtin_functions, upper_bound: true }; + return `upper_bound(${compiler.handleInputs(inputPins[1])}, ${compiler.handleInputs(inputPins[0])})`; + }, +}); + +registerNode({ + id: 'PushBack', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [ + { inputTitle: 'Value', dataType: 'Data', defValue: 1 }, + { inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }, + ], + outputs: [{ outputTitle: 'Array', dataType: 'Array', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `${compiler.handleInputs(inputPins[1])}.push(${compiler.handleInputs(inputPins[0])});\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[1])}`; + }, +}); + +registerNode({ + id: 'PushFront', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [ + { inputTitle: 'Value', dataType: 'Data', defValue: 1 }, + { inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }, + ], + outputs: [{ outputTitle: 'Array', dataType: 'Array', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `${compiler.handleInputs(inputPins[1])}.unshift(${compiler.handleInputs(inputPins[0])});\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[1])}`; + }, +}); + +registerNode({ + id: 'PopBack', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'Array', dataType: 'Array', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `${compiler.handleInputs(inputPins[0])}.pop();\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[0])}`; + }, +}); + +registerNode({ + id: 'PopFront', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'Array', dataType: 'Array', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `${compiler.handleInputs(inputPins[0])}.shift();\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[0])}`; + }, +}); + +registerNode({ + id: 'Insert', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [ + { inputTitle: 'Pos', dataType: 'Number', defValue: 0 }, + { inputTitle: 'Value', dataType: 'Data', defValue: 1 }, + { inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }, + ], + outputs: [{ outputTitle: 'Array', dataType: 'Array', outOrder: 1 }], + color: 'Func', + rows: 4, + colums: 10, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `${compiler.handleInputs(inputPins[2])}.splice(${compiler.handleInputs(inputPins[0])}, 0, ${compiler.handleInputs(inputPins[1])});\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[2])}`; + }, +}); + +registerNode({ + id: 'Sort(Num)', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [ + { inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }, + { inputTitle: 'Increasing', dataType: 'Boolean', defValue: true }, + ], + outputs: [{ outputTitle: 'Array', dataType: 'Array', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 12, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `(${compiler.handleInputs(inputPins[1])}) ? ${compiler.handleInputs(inputPins[0])}.sort((a, b) => a-b) : ${compiler.handleInputs(inputPins[0])}.sort((a, b) => b-a);\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[0])}`; + }, +}); + +registerNode({ + id: 'isEmpty', + schema: { + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'Result', dataType: 'Boolean', outOrder: 0 }], + color: 'Get', + rows: 2, + colums: 10, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `(${compiler.handleInputs(inputPins[0])}.length == (0))`; + }, +}); + +registerNode({ + id: 'Reverse', + schema: { + execIn: true, + execOut: [{ outOrder: 0 }], + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'Array', dataType: 'Array', outOrder: 1 }], + color: 'Func', + rows: 2, + colums: 10, + }, + execCodegen(compiler, node) { + const inputPins = compiler.getInputPins(node); + const execOutPins = compiler.getExecOut(node); + compiler.script += `${compiler.handleInputs(inputPins[0])}.reverse();\n`; + compiler.coreAlgorithm(execOutPins[0]); + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `${compiler.handleInputs(inputPins[0])}`; + }, +}); + +registerNode({ + id: 'Max(Array)', + schema: { + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'MaxValue', dataType: 'Number', outOrder: 0 }], + color: 'Func', + rows: 2, + colums: 11, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `Math.max(...${compiler.handleInputs(inputPins[0])})`; + }, +}); + +registerNode({ + id: 'Min(Array)', + schema: { + inputs: [{ inputTitle: 'Array', dataType: 'Array', isInputBoxRequired: false }], + outputs: [{ outputTitle: 'MinValue', dataType: 'Number', outOrder: 0 }], + color: 'Func', + rows: 2, + colums: 11, + }, + exprCodegen(compiler, inputNode) { + const inputPins = compiler.getInputPins(inputNode.node); + return `Math.min(...${compiler.handleInputs(inputPins[0])})`; + }, +}); + +// ---------- Menu order (null = separator) ---------- +registerMenuOrder([ + 'Begin', 'Print', 'Alert', 'Confirm', 'Prompt', null, + 'If/Else', 'Try/Catch', 'WhileLoop', 'ForLoop', 'ForEachLoop', 'Continue', 'Break', 'Assert', 'Sleep', null, + 'Add', 'Subtract', 'Multiply', 'Divide', 'Modulo', 'Power', 'Random', 'Ceil', 'Floor', 'Round', 'Abs', 'Clamp(Num)', 'Max(Num)', 'Min(Num)', null, + 'Swap', 'Equals', 'Not Equals', 'Less', 'LessEq', 'Greater', 'GreaterEq', null, + 'AND', 'OR', 'XOR', 'NEG', 'Ternary', null, + 'bAND', 'bOR', 'bXOR', 'bNEG', null, + 'OpenWindow', 'HttpRequest', 'GetByName(JSON)', 'ParseInt', null, + 'StrToArray', 'ArrayToStr', 'Length', 'Front', 'Back', 'GetByPos', 'SetByPos', 'Search', 'BinarySearch(Num)', + 'PushBack', 'PopBack', 'PushFront', 'PopFront', 'Insert', 'Sort(Num)', 'isEmpty', 'Reverse', 'Max(Array)', 'Min(Array)', null, +]); diff --git a/src/js/registry/registry.js b/src/js/registry/registry.js new file mode 100644 index 0000000..16e626e --- /dev/null +++ b/src/js/registry/registry.js @@ -0,0 +1,142 @@ +/** + * Central node registry: single source of truth for node types. + * Register a node once with schema + codegen; it drives the context menu, node creation, and compiler. + */ + +const definitions = new Map(); +const menuOrder = []; + +/** + * Build full nodeDescription (with null pin ids) from a compact schema. + * Schema shape: + * - nodeTitle (id string) + * - execIn?: boolean + * - execOut?: Array<{ execOutTitle?: string }> (outOrder = index) + * - inputs?: Array<{ inputTitle, dataType, defValue }> + * - outputs?: Array<{ outputTitle, dataType, outOrder }> + * - color, rows, colums + */ +function schemaToNodeDescription(schema) { + const nodeDescription = { + nodeTitle: schema.nodeTitle, + color: schema.color, + rows: schema.rows, + colums: schema.colums, + }; + if (schema.execIn !== undefined) { + nodeDescription.execIn = schema.execIn; + nodeDescription.pinExecInId = null; + } + if (schema.execOut && schema.execOut.length > 0) { + nodeDescription.execOut = {}; + schema.execOut.forEach((out, i) => { + nodeDescription.execOut[`execOut${i}`] = { + execOutTitle: out.execOutTitle ?? null, + pinExecOutId: null, + outOrder: out.outOrder ?? i, + }; + }); + } + if (schema.inputs && schema.inputs.length > 0) { + nodeDescription.inputs = {}; + schema.inputs.forEach((inp, i) => { + nodeDescription.inputs[`input${i}`] = { + inputTitle: inp.inputTitle, + dataType: inp.dataType, + defValue: inp.defValue !== undefined ? inp.defValue : null, + pinInId: null, + isInputBoxRequired: inp.isInputBoxRequired !== false, + }; + }); + } + if (schema.outputs && schema.outputs.length > 0) { + nodeDescription.outputs = {}; + schema.outputs.forEach((out, i) => { + nodeDescription.outputs[`output${i}`] = { + outputTitle: out.outputTitle, + dataType: out.dataType, + pinOutId: null, + outOrder: out.outOrder ?? i, + }; + }); + } + return nodeDescription; +} + +/** + * Register a node type. All node definitions live here (or in files that call this). + * @param {Object} def - { id, label?, schema, execCodegen?, exprCodegen? } + * - id: unique string (e.g. 'Print') + * - label: display name in context menu (default: id) + * - schema: compact schema for nodeDescription (nodeTitle, execIn, execOut, inputs, outputs, color, rows, colums) + * - execCodegen(compiler, node): called for execution flow (append to compiler.script, call compiler.coreAlgorithm) + * - exprCodegen(compiler, inputNode): optional; called for expression value (return string) + */ +export function registerNode(def) { + const id = def.id; + const schema = { ...def.schema, nodeTitle: id }; + definitions.set(id, { + id, + label: def.label ?? id, + schema, + execCodegen: def.execCodegen ?? null, + exprCodegen: def.exprCodegen ?? null, + }); + return id; +} + +/** + * Register a menu separator (no node, just order). Call with registerNode({ id: null, menuOnly: true }) or add a separate API. + * We use menuOrder array: push null for separator when registering. So we need registerSeparator() or we add to menuOrder in definitions.js. + */ +export function registerMenuOrder(orderedIdsAndNulls) { + menuOrder.length = 0; + menuOrder.push(...orderedIdsAndNulls); +} + +/** + * Get full nodeDescription for a registered type (for Nodes.CreateNode). Returns null if not found. + */ +export function buildNodeDescription(type) { + const def = definitions.get(type); + if (!def) return null; + return schemaToNodeDescription(def.schema); +} + +/** + * Get registry definition for a type. + */ +export function getDefinition(type) { + return definitions.get(type) ?? null; +} + +/** + * Get ordered list of menu entries: array of node ids (string) or null for separator. + */ +export function getMenuOrder() { + return [...menuOrder]; +} + +/** + * Run exec codegen for a node type. No-op if no execCodegen. + */ +export function runExecCodegen(type, compiler, node) { + const def = definitions.get(type); + if (def && def.execCodegen) def.execCodegen(compiler, node); +} + +/** + * Run expr codegen for a node type. Returns undefined if no exprCodegen (caller should handle). + */ +export function runExprCodegen(type, compiler, inputNode) { + const def = definitions.get(type); + if (def && def.exprCodegen) return def.exprCodegen(compiler, inputNode); + return undefined; +} + +/** + * Check if a type is registered (built-in node). Get/Set are not registered. + */ +export function hasType(type) { + return definitions.has(type); +} diff --git a/javascript/main/alertBox.js b/src/js/ui/dialogs.js similarity index 99% rename from javascript/main/alertBox.js rename to src/js/ui/dialogs.js index eb6df97..b8d1928 100644 --- a/javascript/main/alertBox.js +++ b/src/js/ui/dialogs.js @@ -1,5 +1,5 @@ -import { refresh } from '../SaveAndLoad/SaveAndLoad.js' -import { Import } from '../SaveAndLoad/SaveAndLoad.js' +import { refresh } from '../persistence/saveAndLoad.js' +import { Import } from '../persistence/saveAndLoad.js' export function showAlert(msg) { let alertMsg = document.getElementById("alert-box").children[0].children[0]; diff --git a/javascript/Variable/variable.js b/src/js/ui/variableList.js similarity index 97% rename from javascript/Variable/variable.js rename to src/js/ui/variableList.js index f9083b9..67bd899 100644 --- a/javascript/Variable/variable.js +++ b/src/js/ui/variableList.js @@ -1,5 +1,5 @@ -import {colorMap} from '../ColorMap/colorMap.js' -import {ContextMenu } from '../ContextMenu/contextMenu.js' +import { colorMap } from '../core/colorMap.js' +import { ContextMenu } from '../editor/contextMenu.js' class VariableList { constructor() diff --git a/javascript/LeftPanel/LeftPanel.js b/src/js/ui/variablePanel.js similarity index 97% rename from javascript/LeftPanel/LeftPanel.js rename to src/js/ui/variablePanel.js index 99c856b..35f8bab 100644 --- a/javascript/LeftPanel/LeftPanel.js +++ b/src/js/ui/variablePanel.js @@ -1,6 +1,6 @@ -import { colorMap } from '../ColorMap/colorMap.js' -import { variableList } from '../Variable/variable.js' -import { showAlert } from '../main/alertBox.js' +import { colorMap } from '../core/colorMap.js' +import { variableList } from './variableList.js' +import { showAlert } from './dialogs.js' export class leftPanel { constructor() { let isBooleanValid = false; diff --git a/style.css b/src/style.css similarity index 100% rename from style.css rename to src/style.css diff --git a/javascript/Dependencies/CodeMirror/ayu-dark.css b/src/vendor/codemirror/ayu-dark.css similarity index 100% rename from javascript/Dependencies/CodeMirror/ayu-dark.css rename to src/vendor/codemirror/ayu-dark.css diff --git a/javascript/Dependencies/CodeMirror/ayu-mirage.css b/src/vendor/codemirror/ayu-mirage.css similarity index 100% rename from javascript/Dependencies/CodeMirror/ayu-mirage.css rename to src/vendor/codemirror/ayu-mirage.css diff --git a/javascript/Dependencies/CodeMirror/codemirror.css b/src/vendor/codemirror/codemirror.css similarity index 100% rename from javascript/Dependencies/CodeMirror/codemirror.css rename to src/vendor/codemirror/codemirror.css diff --git a/javascript/Dependencies/CodeMirror/codemirror.js b/src/vendor/codemirror/codemirror.js similarity index 100% rename from javascript/Dependencies/CodeMirror/codemirror.js rename to src/vendor/codemirror/codemirror.js diff --git a/javascript/Dependencies/CodeMirror/javascript/index.html b/src/vendor/codemirror/javascript/index.html similarity index 100% rename from javascript/Dependencies/CodeMirror/javascript/index.html rename to src/vendor/codemirror/javascript/index.html diff --git a/javascript/Dependencies/CodeMirror/javascript/javascript.js b/src/vendor/codemirror/javascript/javascript.js similarity index 100% rename from javascript/Dependencies/CodeMirror/javascript/javascript.js rename to src/vendor/codemirror/javascript/javascript.js diff --git a/javascript/Dependencies/CodeMirror/javascript/json-ld.html b/src/vendor/codemirror/javascript/json-ld.html similarity index 100% rename from javascript/Dependencies/CodeMirror/javascript/json-ld.html rename to src/vendor/codemirror/javascript/json-ld.html diff --git a/javascript/Dependencies/CodeMirror/javascript/test.js b/src/vendor/codemirror/javascript/test.js similarity index 100% rename from javascript/Dependencies/CodeMirror/javascript/test.js rename to src/vendor/codemirror/javascript/test.js diff --git a/javascript/Dependencies/CodeMirror/javascript/typescript.html b/src/vendor/codemirror/javascript/typescript.html similarity index 100% rename from javascript/Dependencies/CodeMirror/javascript/typescript.html rename to src/vendor/codemirror/javascript/typescript.html diff --git a/javascript/Dependencies/CodeMirror/material.css b/src/vendor/codemirror/material.css similarity index 100% rename from javascript/Dependencies/CodeMirror/material.css rename to src/vendor/codemirror/material.css diff --git a/javascript/Dependencies/jquery/jquery.js b/src/vendor/jquery/jquery.js similarity index 100% rename from javascript/Dependencies/jquery/jquery.js rename to src/vendor/jquery/jquery.js diff --git a/javascript/Dependencies/Konva/konva.min.js b/src/vendor/konva/konva.min.js similarity index 100% rename from javascript/Dependencies/Konva/konva.min.js rename to src/vendor/konva/konva.min.js From 23ae596b1b93f22a3b6ce16283a8613ad9f2f001 Mon Sep 17 00:00:00 2001 From: Ayush Kashyap <55059858+ayushk7@users.noreply.github.com> Date: Thu, 5 Mar 2026 07:04:02 +0530 Subject: [PATCH 02/10] feat: Add the variable deletion support (#30) --- src/index.html | 71 ++-- src/js/app.js | 2 + src/js/compiler/compiler.js | 36 +- src/js/editor/deleteHandler.js | 69 ++-- src/js/nodes/nodeFactory.js | 88 +++-- src/js/nodes/wiring.js | 88 ++++- src/js/ui/dialogs.js | 32 +- src/js/ui/variableList.js | 663 +++++++++++++++++++++++++++++++-- src/js/ui/variablePanel.js | 8 +- src/style.css | 202 +++++++--- 10 files changed, 1045 insertions(+), 214 deletions(-) diff --git a/src/index.html b/src/index.html index b6fac4c..438cb0d 100644 --- a/src/index.html +++ b/src/index.html @@ -31,51 +31,34 @@ style="position: absolute; right: 0.7rem; transition: 0.1s;">
-
-
-
Type
- +
+ + + + + + +
+
-
-
Name
- -
-
-
Value
- -
- - - -
Variable List
-
+
@@ -176,9 +159,17 @@

L

+
+
-
Add Variable
diff --git a/src/js/editor/contextMenu.js b/src/js/editor/contextMenu.js index b0a95bb..f40004c 100644 --- a/src/js/editor/contextMenu.js +++ b/src/js/editor/contextMenu.js @@ -301,13 +301,14 @@ export var ContextMenu = { if (e.dataTransfer.getData("functionTabId")) { const funcTabId = e.dataTransfer.getData("functionTabId"); const funcTab = tabManager.getTab(funcTabId); - if (funcTab) { + if (funcTab && funcTab.saved) { + const saved = funcTab.saved; const containerRect = stage.getContainer().getBoundingClientRect(); const x = e.clientX - containerRect.x; const y = e.clientY - containerRect.y; const activeLayer = tabManager.getActiveLayer(); - Nodes.CreateCallNode(funcTab.name, funcTab.inputParams, funcTab.outputParams, - { x, y }, activeLayer, stage, funcTab.docString || ''); + Nodes.CreateCallNode(saved.name, saved.inputParams, saved.outputParams, + { x, y }, activeLayer, stage, saved.docString || ''); activeLayer.draw(); } } else if (e.dataTransfer.getData("variableName")) { diff --git a/src/js/editor/tabManager.js b/src/js/editor/tabManager.js index 157e11e..096a4bb 100644 --- a/src/js/editor/tabManager.js +++ b/src/js/editor/tabManager.js @@ -56,6 +56,7 @@ class TabManager { getTab(id) { return this._tabs.get(id); } getAllTabs() { return [...this._tabs.values()]; } getAllFunctionTabs() { return [...this._tabs.values()].filter(t => t.type === 'function'); } + getAllSavedFunctionTabs() { return [...this._tabs.values()].filter(t => t.type === 'function' && t.saved); } createTab(name) { if (!isValidFunctionName(name)) { @@ -90,6 +91,7 @@ class TabManager { returnNodeId: null, variables: [], docString: '', + saved: null, }; this._tabs.set(id, tab); @@ -131,6 +133,7 @@ class TabManager { if (!tab) return false; const oldName = tab.name; tab.name = newName; + if (tab.saved) tab.saved.name = newName; this._renderTabBar(); this._emit('tabRenamed', { tab, oldName, newName }); return true; @@ -165,6 +168,18 @@ class TabManager { }; } + saveFunction(tabId) { + const tab = this._tabs.get(tabId); + if (!tab || tab.type !== 'function') return; + tab.saved = { + name: tab.name, + inputParams: tab.inputParams.map(p => ({ ...p })), + outputParams: tab.outputParams.map(p => ({ ...p })), + docString: tab.docString || '', + }; + this._emit('functionSaved', tab); + } + on(event, fn) { if (!this._listeners[event]) this._listeners[event] = []; this._listeners[event].push(fn); diff --git a/src/js/nodes/nodeFactory.js b/src/js/nodes/nodeFactory.js index fac9337..5417a1e 100644 --- a/src/js/nodes/nodeFactory.js +++ b/src/js/nodes/nodeFactory.js @@ -626,6 +626,16 @@ export var Nodes = { }); } + const savedExecOuts = []; + for (let j = 0; j < programNode.execOutPins.length; j++) { + const ep = programNode.execOutPins[j]; + if (ep.wire) { + const destPin = ep.wire.attrs.dest; + deleteWire(ep.wire); + savedExecOuts[j] = destPin; + } + } + const pos = grp.position(); const grpId = grp.id(); grp.destroy(); @@ -638,6 +648,14 @@ export var Nodes = { newNode.grp.id(grpId); const newCC = newNode.grp.customClass; + for (let j = 0; j < savedExecOuts.length; j++) { + if (!savedExecOuts[j]) continue; + const newExecOutPin = newCC.execOutPins[j]?.thisNode; + if (newExecOutPin) { + addConnectionWire(savedExecOuts[j], newExecOutPin, stage, 1, wireLayer); + } + } + const outPins = newNode.grp.find('.pin').filter(p => p.attrs.pinType === 'outp'); outPins.sort((a, b) => { const ai = parseInt(String(a.attrs.helper || '').split('-')[1], 10) || 0; @@ -866,6 +884,19 @@ export var Nodes = { } } + const savedExecIns = []; + for (let i = 0; i < programNode.execInPins.length; i++) { + const ep = programNode.execInPins[i]; + if (ep.wire && ep.wire.length > 0) { + const wireCopy = [...ep.wire]; + savedExecIns[i] = wireCopy.map(w => { + const srcPin = w.attrs.src; + deleteWire(w); + return srcPin; + }); + } + } + const pos = grp.position(); const grpId = grp.id(); grp.destroy(); @@ -878,6 +909,16 @@ export var Nodes = { newNode.grp.id(grpId); const newCC = newNode.grp.customClass; + for (let i = 0; i < savedExecIns.length; i++) { + if (!savedExecIns[i]) continue; + const newExecInPin = newCC.execInPins[0]?.thisNode; + if (newExecInPin) { + for (const srcPin of savedExecIns[i]) { + addConnectionWire(newExecInPin, srcPin, stage, 1, wireLayer); + } + } + } + const outputParamsArr = outputParams || []; for (let i = 0; i < savedInputs.length && i < outputParamsArr.length; i++) { const saved = savedInputs[i]; diff --git a/src/js/persistence/saveAndLoad.js b/src/js/persistence/saveAndLoad.js index 1a06fd6..3be1f41 100644 --- a/src/js/persistence/saveAndLoad.js +++ b/src/js/persistence/saveAndLoad.js @@ -232,6 +232,12 @@ function printContent(json, stage, layer, wireLayer) { tab.outputParams = funcData.outputParams || []; tab.variables = funcData.variables || []; tab.docString = funcData.docString || ''; + tab.saved = { + name: tab.name, + inputParams: tab.inputParams.map(p => ({ ...p })), + outputParams: tab.outputParams.map(p => ({ ...p })), + docString: tab.docString, + }; loadLayerContent(funcData.nodesData, funcData.wireData, tab.layer, tab.wireLayer, stage); @@ -248,6 +254,7 @@ function printContent(json, stage, layer, wireLayer) { tab.layer.draw(); tab.wireLayer.draw(); + tabManager._emit('functionSaved', tab); } catch (err) { tabManager._suppressAutoNodes = false; writeError(err, "Error Occurred In Importing The JSON(Function Data Not Valid)"); diff --git a/src/js/ui/functionPanel.js b/src/js/ui/functionPanel.js index f8c2334..d130d2a 100644 --- a/src/js/ui/functionPanel.js +++ b/src/js/ui/functionPanel.js @@ -230,17 +230,15 @@ export function initFunctionPanel() { const tab = tabManager.getActiveTab(); if (!tab || tab.type !== 'function') return; tab.docString = docStringInput.value.trim(); - Nodes.updateCallNodesDocString(tab.name, tab.docString); - tabManager._emit('functionDocChanged', { tab }); }); } - const updateCallersBtn = document.getElementById('update-callers-btn'); - if (updateCallersBtn) { - updateCallersBtn.addEventListener('click', () => { + const saveFunctionBtn = document.getElementById('save-function-btn'); + if (saveFunctionBtn) { + saveFunctionBtn.addEventListener('click', () => { const tab = tabManager.getActiveTab(); if (!tab || tab.type !== 'function') return; - Nodes.updateCallNodesToDefinition(tab.name, tab.inputParams, tab.outputParams, tab.docString || ''); + tabManager.saveFunction(tab.id); }); } @@ -280,8 +278,6 @@ export function initFunctionPanel() { if (tab.type === 'function' && !tabManager._suppressAutoNodes) { createFunctionNodes(tab); } - refreshFunctionsList(); - refreshContextMenuFunctions(); }); tabManager.on('tabClosed', (tab) => { @@ -311,13 +307,13 @@ export function initFunctionPanel() { tabManager.on('functionParamsChanged', ({ tab, paramType }) => { syncFunctionNodes(tab, paramType); - Nodes.updateCallNodesToDefinition(tab.name, tab.inputParams, tab.outputParams, tab.docString || ''); - refreshFunctionsList(); - refreshContextMenuFunctions(); }); - tabManager.on('functionDocChanged', () => { + tabManager.on('functionSaved', (tab) => { + Nodes.updateCallNodesToDefinition(tab.name, tab.saved.inputParams, tab.saved.outputParams, tab.saved.docString); + Nodes.updateCallNodesDocString(tab.name, tab.saved.docString); refreshFunctionsList(); + refreshContextMenuFunctions(); }); } @@ -364,13 +360,13 @@ function updatePanelVisibility(tab) { const outputSection = document.getElementById('output-params-section'); const docSection = document.getElementById('doc-string-section'); const docStringInput = document.getElementById('doc-string-input'); - const updateCallersSection = document.getElementById('update-callers-section'); + const saveFunctionSection = document.getElementById('save-function-section'); if (tab.type === 'function') { inputSection.classList.remove('hidden'); outputSection.classList.remove('hidden'); if (docSection) docSection.classList.remove('hidden'); - if (updateCallersSection) updateCallersSection.classList.remove('hidden'); + if (saveFunctionSection) saveFunctionSection.classList.remove('hidden'); if (docStringInput) docStringInput.value = tab.docString || ''; refreshInputList(); refreshOutputList(); @@ -378,7 +374,7 @@ function updatePanelVisibility(tab) { inputSection.classList.add('hidden'); outputSection.classList.add('hidden'); if (docSection) docSection.classList.add('hidden'); - if (updateCallersSection) updateCallersSection.classList.add('hidden'); + if (saveFunctionSection) saveFunctionSection.classList.add('hidden'); } } @@ -387,8 +383,9 @@ function refreshFunctionsList() { if (!listEl) return; listEl.innerHTML = ''; - const funcTabs = tabManager.getAllFunctionTabs(); + const funcTabs = tabManager.getAllSavedFunctionTabs(); for (const ft of funcTabs) { + const saved = ft.saved; const li = document.createElement('li'); li.className = 'left-panel-variable'; li.style.borderWidth = '2px'; @@ -400,7 +397,7 @@ function refreshFunctionsList() { const nameSpan = document.createElement('span'); nameSpan.className = 'var-name-text'; - nameSpan.textContent = ft.name; + nameSpan.textContent = saved.name; nameSpan.style.overflow = 'hidden'; nameSpan.style.textOverflow = 'ellipsis'; nameSpan.style.whiteSpace = 'nowrap'; @@ -408,7 +405,7 @@ function refreshFunctionsList() { li.appendChild(nameSpan); let docIcon = null; - if (ft.docString) { + if (saved.docString) { docIcon = document.createElement('span'); docIcon.className = 'function-list-doc-icon'; docIcon.textContent = 'i'; @@ -420,8 +417,8 @@ function refreshFunctionsList() { infoSpan.style.fontSize = '0.8rem'; infoSpan.style.opacity = '0.5'; infoSpan.style.marginLeft = '0.3rem'; - const inCount = ft.inputParams.length; - const outCount = ft.outputParams.length; + const inCount = saved.inputParams.length; + const outCount = saved.outputParams.length; infoSpan.textContent = `(${inCount}→${outCount})`; li.appendChild(infoSpan); @@ -435,7 +432,7 @@ function refreshFunctionsList() { if (docIcon) { li.addEventListener('mouseenter', (e) => { - showDocTooltip(docIcon, ft.docString); + showDocTooltip(docIcon, saved.docString); }); } @@ -461,7 +458,7 @@ function refreshContextMenuFunctions() { section.remove(); } - const funcTabs = tabManager.getAllFunctionTabs(); + const funcTabs = tabManager.getAllSavedFunctionTabs(); if (funcTabs.length === 0) return; section = document.createElement('div'); @@ -493,9 +490,10 @@ function refreshContextMenuFunctions() { body.className = 'ctx-menu-section-body'; for (const ft of funcTabs) { + const saved = ft.saved; const item = document.createElement('div'); item.className = 'context-menu-items'; - item.textContent = `Call ${ft.name}`; + item.textContent = `Call ${saved.name}`; item.dataset.functionTabId = ft.id; item.style.borderLeftColor = callColor; item.style.color = callColor; @@ -507,8 +505,8 @@ function refreshContextMenuFunctions() { const containerRect = stage.container().getBoundingClientRect(); const x = rect.x - containerRect.x; const y = rect.y - containerRect.y; - Nodes.CreateCallNode(ft.name, ft.inputParams, ft.outputParams, - { x, y }, activeLayer, stage, ft.docString || ''); + Nodes.CreateCallNode(saved.name, saved.inputParams, saved.outputParams, + { x, y }, activeLayer, stage, saved.docString || ''); activeLayer.draw(); document.getElementById('ctx-menu-container').classList.add('hidden'); }); diff --git a/src/style.css b/src/style.css index 1d7dd21..7e644f3 100644 --- a/src/style.css +++ b/src/style.css @@ -81,7 +81,7 @@ background-size: 10rem 10rem; #input-params-section, #output-params-section, #doc-string-section, - #update-callers-section{ + #save-function-section{ width: 100%; } #ctx-menu-container{ @@ -636,7 +636,7 @@ iframe{ .left-panel-variable .var-actions .var-delete-btn:hover{ color: #f44; } -.update-callers-btn{ +.save-function-btn{ width: 100%; min-width: 0; max-width: 100%; @@ -651,7 +651,7 @@ iframe{ cursor: pointer; transition: background 0.15s, border-color 0.15s; } -.update-callers-btn:hover{ +.save-function-btn:hover{ background: #00a090; border-color: #00e5cc; color: #fff; From daf72deb4fde2c991717fd8e20cd0bf6e1f3e9f2 Mon Sep 17 00:00:00 2001 From: Ayush Kashyap Date: Mon, 9 Mar 2026 03:26:22 +0530 Subject: [PATCH 09/10] switch to pnpm --- pnpm-lock.yaml | 626 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 626 insertions(+) create mode 100644 pnpm-lock.yaml diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..a80808a --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,626 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +devDependencies: + vite: + specifier: ^7.3.1 + version: 7.3.1 + +packages: + + /@esbuild/aix-ppc64@0.27.3: + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.27.3: + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.27.3: + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.27.3: + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.27.3: + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.27.3: + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.27.3: + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.27.3: + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.27.3: + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.27.3: + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.27.3: + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.27.3: + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.27.3: + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.27.3: + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.27.3: + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.27.3: + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.27.3: + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-arm64@0.27.3: + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.27.3: + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-arm64@0.27.3: + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.27.3: + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openharmony-arm64@0.27.3: + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.27.3: + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.27.3: + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.27.3: + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.27.3: + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm-eabi@4.59.0: + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.59.0: + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.59.0: + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.59.0: + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-freebsd-arm64@4.59.0: + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-freebsd-x64@4.59.0: + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.59.0: + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-musleabihf@4.59.0: + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.59.0: + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.59.0: + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-loong64-gnu@4.59.0: + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-loong64-musl@4.59.0: + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-ppc64-gnu@4.59.0: + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-ppc64-musl@4.59.0: + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.59.0: + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-musl@4.59.0: + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-s390x-gnu@4.59.0: + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.59.0: + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.59.0: + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-openbsd-x64@4.59.0: + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-openharmony-arm64@4.59.0: + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.59.0: + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.59.0: + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-gnu@4.59.0: + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.59.0: + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@types/estree@1.0.8: + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + dev: true + + /esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + dev: true + + /fdir@6.5.0(picomatch@4.0.3): + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + dependencies: + picomatch: 4.0.3 + dev: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + dev: true + + /picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + dev: true + + /postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + dev: true + + /rollup@4.59.0: + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 + fsevents: 2.3.3 + dev: true + + /source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + dev: true + + /tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + dev: true + + /vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + dependencies: + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.8 + rollup: 4.59.0 + tinyglobby: 0.2.15 + optionalDependencies: + fsevents: 2.3.3 + dev: true From bde1f3acc90ca92c47a587da7db75134c664cd06 Mon Sep 17 00:00:00 2001 From: Ayush Kashyap Date: Fri, 20 Mar 2026 19:30:16 +0530 Subject: [PATCH 10/10] Docker --- .dockerignore | 6 ++++++ dockerfile | 26 ++++++++++++++++++++++++++ package-lock.json | 1 - 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c8afdf7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +node_modules +dist +.git +.gitignore +Dockerfile +README.md diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..e2f3e51 --- /dev/null +++ b/dockerfile @@ -0,0 +1,26 @@ +# ---------- Build Stage ---------- +FROM node:22 AS builder + +WORKDIR /app + +RUN npm install -g pnpm + +COPY package.json pnpm-lock.yaml* ./ + +RUN pnpm install + +COPY . . + +RUN pnpm run build + + +# ---------- Production Stage ---------- +FROM nginx:alpine + +RUN rm -rf /usr/share/nginx/html/* + +COPY --from=builder /app/dist /usr/share/nginx/html + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/package-lock.json b/package-lock.json index e4639e8..5713b12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -917,7 +917,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" },