From 9f3fad611e51d3a9b6a6c62a330f22e9e3bfc837 Mon Sep 17 00:00:00 2001 From: _Kerman Date: Thu, 9 Nov 2023 17:38:30 +0800 Subject: [PATCH] feat: add `do` block --- packages/compiler/src/types/specialBlock.ts | 10 +- packages/compiler/src/viewCompiler.ts | 15 +++ packages/northstar/src/blocks/special/do.r.ts | 126 ++++++++++++++++++ .../northstar/src/blocks/special/index.ts | 4 +- 4 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 packages/northstar/src/blocks/special/do.r.ts diff --git a/packages/compiler/src/types/specialBlock.ts b/packages/compiler/src/types/specialBlock.ts index 3d8a7cb..ae1e321 100644 --- a/packages/compiler/src/types/specialBlock.ts +++ b/packages/compiler/src/types/specialBlock.ts @@ -76,6 +76,13 @@ export interface StateSetterBlockOutput { state: number; } +export interface DoBlockOutput { + type: "do"; + id: number; + when: ConnectTo[]; + then: ConnectTo[]; +} + export type SpecialBlockOutput = | RootBlockOutput | FuncBlockOutput @@ -84,4 +91,5 @@ export type SpecialBlockOutput = | IfBlockOutput | ViewBlockOutput | StateBlockOutput - | StateSetterBlockOutput; + | StateSetterBlockOutput + | DoBlockOutput; diff --git a/packages/compiler/src/viewCompiler.ts b/packages/compiler/src/viewCompiler.ts index 16c6eec..43b47c3 100644 --- a/packages/compiler/src/viewCompiler.ts +++ b/packages/compiler/src/viewCompiler.ts @@ -185,6 +185,8 @@ const ${this.view.name}_view = ${ break; case "state-setter": throw new Error("State setter block has no data output"); + case "do": + throw new Error("State setter block has no data output"); } return `${lineId}()`; } @@ -297,6 +299,19 @@ const ${this.view.name}_view = ${ )}_update_${blockId}`, ); break; + case "do": + if (socketName !== "when") { + throw new Error( + `Cannot find socket ${socketName} in block ${blockId}`, + ); + } + this.impDefs.set( + impId, + `() => {${block.then + .map((v) => this.compileEventLineStart(v)) + .join(";\n")}}`, + ); + break; } return `${impId}()`; } diff --git a/packages/northstar/src/blocks/special/do.r.ts b/packages/northstar/src/blocks/special/do.r.ts new file mode 100644 index 0000000..c6b67b8 --- /dev/null +++ b/packages/northstar/src/blocks/special/do.r.ts @@ -0,0 +1,126 @@ +import { DoBlockOutput } from "@quasi-dev/compiler"; +import { + Block, + Direction, + MultiInSocket, + PATH_IN_TRIANGLE, + PATH_OUT_TRIANGLE, + RectBlock, + SingleOutSocket, + Socket, + blockCtors, +} from "@quasi-dev/visual-flow"; +import { Context } from "refina"; +import { PropsData } from "../../utils/props"; +import { multiInSocketToOutput, singleOutSocketToOutput } from "../../utils/toOutpus"; + +export class DoBlock extends RectBlock { + type = "state-setter"; + + boardWidth = 70; + boardHeight = 30; + + removable = true; + duplicateable = true; + + clone() { + const block = new DoBlock(); + block.initialize(); + return block; + } + + whenSocket: MultiInSocket; + thenSockets: SingleOutSocket[] = []; + + initialize(): void { + this.whenSocket = new MultiInSocket(); + this.whenSocket.label = "when"; + this.whenSocket.hideLabel = true; + this.whenSocket.type = "E"; + this.whenSocket.path = PATH_IN_TRIANGLE; + this.addSocket(Direction.TOP, this.whenSocket); + + this.updateSockets(2); + } + + updateSockets(length: number): void { + if (length < this.thenSockets.length) { + for (let i = length; i < this.thenSockets.length; i++) { + const socket = this.thenSockets[i]; + socket.allConnectedLines.forEach(l => { + l.a.disconnectTo(l); + (l.b as Socket).disconnectTo(l); + this.graph.removeLine(l); + }); + const sockets = this.getSocketsByDirection(socket.direction); + const index = sockets.indexOf(socket); + sockets.splice(index, 1); + } + this.thenSockets = this.thenSockets.slice(0, length); + } else if (length > this.thenSockets.length) { + for (let i = this.thenSockets.length; i < length; i++) { + const socket = new SingleOutSocket(); + socket.label = `then${i}`; + socket.hideLabel = true; + socket.type = "E"; + socket.path = PATH_OUT_TRIANGLE; + this.addSocket(Direction.BOTTOM, socket); + this.thenSockets.push(socket); + } + } + } + + getProps(): PropsData { + return [ + { + name: "number", + type: "text", + getVal: () => { + return this.thenSockets.length.toString(); + }, + setVal: val => { + const length = parseInt(val); + if (isNaN(length)) return; + this.updateSockets(length); + }, + }, + ]; + } + + contentMain = (_: Context) => { + _.$cls`absolute flex items-center left-0 top-0 justify-around text-gray-600`; + _.$css`width:${this.pageWidth}px;height:${this.pageHeight}px;`; + _.$css`transform:scale(${this.graph.boardScale})`; + _.div(_ => { + _.span("do"); + }); + }; + + toOutput(): DoBlockOutput { + let stateBlock: Block = this; + while (stateBlock.dockedToBlock) { + stateBlock = stateBlock.dockedToBlock; + } + return { + type: "do", + id: this.id, + when: multiInSocketToOutput(this.whenSocket), + then: this.thenSockets.map(singleOutSocketToOutput), + }; + } + + protected exportData() { + return { + ...super.exportData(), + whenSocket: this.whenSocket.id, + thenSockets: this.thenSockets.map(s => s.id), + }; + } + protected importData(data: any, sockets: any): void { + super.importData(data, sockets); + this.whenSocket = sockets[data.whenSocket]; + this.thenSockets = data.thenSockets.map((id: number) => sockets[id]); + } +} + +blockCtors["DoBlock"] = DoBlock; diff --git a/packages/northstar/src/blocks/special/index.ts b/packages/northstar/src/blocks/special/index.ts index 154d186..203aaa6 100644 --- a/packages/northstar/src/blocks/special/index.ts +++ b/packages/northstar/src/blocks/special/index.ts @@ -1,10 +1,11 @@ +import { DoBlock } from "./do.r"; import { ExprBlock } from "./expr"; import { IfElseBlock } from "./if.r"; import { ImpBlock } from "./imp"; import { StateBlock } from "./state"; +import { StateSetterBlock } from "./stateSetter.r"; import { StringBlock } from "./string"; import { ValidatorBlock } from "./validator"; -import { StateSetterBlock } from "./stateSetter.r"; export default Object.entries({ // root: RootBlock, @@ -15,4 +16,5 @@ export default Object.entries({ validator: ValidatorBlock, state: StateBlock, stateSetter: StateSetterBlock, + do: DoBlock, });