@blokjs/if-else 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,251 @@
1
+ # @blokjs/if-else
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Initial public release of Blok packages.
8
+
9
+ This release includes:
10
+
11
+ - Core packages: @blokjs/shared, @blokjs/helper, @blokjs/runner
12
+ - Node packages: @blokjs/api-call, @blokjs/if-else, @blokjs/react
13
+ - Trigger packages: pubsub, queue, webhook, websocket, worker, cron, grpc
14
+ - CLI tool: blokctl
15
+ - Editor support: @blokjs/lsp-server, @blokjs/syntax
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+ - @blokjs/shared@0.2.0
21
+ - @blokjs/helper@0.2.0
22
+ - @blokjs/runner@0.2.0
23
+
24
+ ## 0.0.30
25
+
26
+ ### Patch Changes
27
+
28
+ - Updated dependencies
29
+ - @blokjs/runner@0.1.26
30
+
31
+ ## 0.0.29
32
+
33
+ ### Patch Changes
34
+
35
+ - Updated dependencies
36
+ - @blokjs/runner@0.1.25
37
+
38
+ ## 0.0.28
39
+
40
+ ### Patch Changes
41
+
42
+ - Updated dependencies
43
+ - @blokjs/runner@0.1.24
44
+
45
+ ## 0.0.27
46
+
47
+ ### Patch Changes
48
+
49
+ - Updated dependencies
50
+ - @blokjs/runner@0.1.23
51
+
52
+ ## 0.0.26
53
+
54
+ ### Patch Changes
55
+
56
+ - Updated dependencies
57
+ - @blokjs/runner@0.1.22
58
+
59
+ ## 0.0.25
60
+
61
+ ### Patch Changes
62
+
63
+ - Updated dependencies
64
+ - @blokjs/runner@0.1.21
65
+
66
+ ## 0.0.24
67
+
68
+ ### Patch Changes
69
+
70
+ - Updated dependencies
71
+ - @blokjs/helper@0.1.5
72
+ - @blokjs/runner@0.1.20
73
+
74
+ ## 0.0.23
75
+
76
+ ### Patch Changes
77
+
78
+ - Updated dependencies
79
+ - @blokjs/runner@0.1.19
80
+ - @blokjs/shared@0.0.9
81
+
82
+ ## 0.0.22
83
+
84
+ ### Patch Changes
85
+
86
+ - Added examples and create project' command to include examples and 'create node' command with options for type ('module' or 'class') and template ('class' or 'ui')
87
+ - Updated dependencies
88
+ - @blokjs/runner@0.1.18
89
+ - @blokjs/shared@0.0.8
90
+
91
+ ## 0.0.21
92
+
93
+ ### Patch Changes
94
+
95
+ - Updated dependencies
96
+ - @blokjs/runner@0.1.17
97
+
98
+ ## 0.0.20
99
+
100
+ ### Patch Changes
101
+
102
+ - Added support for YAML, XML and TOML in the workflow file. Upgraded package version recommended by Dependabot.
103
+ - Updated dependencies
104
+ - @blokjs/helper@0.1.4
105
+ - @blokjs/runner@0.1.16
106
+ - @blokjs/shared@0.0.7
107
+
108
+ ## 0.0.19
109
+
110
+ ### Patch Changes
111
+
112
+ - Improved the BlokService base class to accept a InputType. This force developer to always create a type to define the Node handle input. Added unit test for pending projects like if-else and api-call.
113
+ - Updated dependencies
114
+ - @blokjs/runner@0.1.15
115
+
116
+ ## 0.0.18
117
+
118
+ ### Patch Changes
119
+
120
+ - Updated dependencies
121
+ - @blokjs/shared@0.0.6
122
+ - @blokjs/runner@0.1.14
123
+
124
+ ## 0.0.17
125
+
126
+ ### Patch Changes
127
+
128
+ - Updated dependencies
129
+ - @blokjs/runner@0.1.13
130
+ - @blokjs/shared@0.0.5
131
+
132
+ ## 0.0.16
133
+
134
+ ### Patch Changes
135
+
136
+ - Updated dependencies
137
+ - @blokjs/runner@0.1.12
138
+ - @blokjs/shared@0.0.4
139
+
140
+ ## 0.0.15
141
+
142
+ ### Patch Changes
143
+
144
+ - Updated dependencies
145
+ - @blokjs/runner@0.1.11
146
+
147
+ ## 0.0.14
148
+
149
+ ### Patch Changes
150
+
151
+ - Updated dependencies
152
+ - @blokjs/runner@0.1.10
153
+
154
+ ## 0.0.13
155
+
156
+ ### Patch Changes
157
+
158
+ - Improved and extended the open telemetry feature
159
+ - Updated dependencies
160
+ - @blokjs/runner@0.1.9
161
+ - @blokjs/shared@0.0.3
162
+
163
+ ## 0.0.12
164
+
165
+ ### Patch Changes
166
+
167
+ - Fixed open telemetry issues and types
168
+ - Updated dependencies
169
+ - @blokjs/runner@0.1.8
170
+ - @blokjs/shared@0.0.2
171
+
172
+ ## 0.0.11
173
+
174
+ ### Patch Changes
175
+
176
+ - Fixed issue with the cli node creation test
177
+ - Updated dependencies
178
+ - @blokjs/runner@0.1.7
179
+ - @blokjs/shared@0.0.1
180
+
181
+ ## 0.0.10
182
+
183
+ ### Patch Changes
184
+
185
+ - Migrated and refactored shared library
186
+ - Updated dependencies
187
+ - @blokjs/runner@0.1.6
188
+
189
+ ## 0.0.9
190
+
191
+ ### Patch Changes
192
+
193
+ - Updated dependencies [e5225d2]
194
+ - @blokjs/runner@0.1.5
195
+
196
+ ## 0.0.8
197
+
198
+ ### Patch Changes
199
+
200
+ - Fixed build version
201
+
202
+ ## 0.0.7
203
+
204
+ ### Patch Changes
205
+
206
+ - Added main property to package.json
207
+
208
+ ## 0.0.6
209
+
210
+ ### Patch Changes
211
+
212
+ - Publishing those packages to npmjs
213
+
214
+ ## 0.0.5
215
+
216
+ ### Patch Changes
217
+
218
+ - Updated dependencies
219
+ - @blokjs/helper@0.1.3
220
+ - @blokjs/runner@0.1.4
221
+
222
+ ## 0.0.4
223
+
224
+ ### Patch Changes
225
+
226
+ - Updated dependencies
227
+ - @blokjs/helper@0.1.2
228
+ - @blokjs/runner@0.1.3
229
+
230
+ ## 0.0.3
231
+
232
+ ### Patch Changes
233
+
234
+ - Updated dependencies
235
+ - @blokjs/helper@0.1.1
236
+ - @blokjs/runner@0.1.2
237
+
238
+ ## 0.0.2
239
+
240
+ ### Patch Changes
241
+
242
+ - Updated dependencies
243
+ - @blokjs/runner@0.1.1
244
+
245
+ ## 0.0.1
246
+
247
+ ### Patch Changes
248
+
249
+ - Updated dependencies
250
+ - @blokjs/helper@0.1.0
251
+ - @blokjs/runner@0.1.0
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # Configuration Options
2
+ The IfElse node allows you to have a conditional statement and call other nodes depending on the conditions
3
+
4
+ ## Node properties
5
+
6
+ ### Required properties
7
+ - `conditions` (array): List of conditions to check
8
+ - `type` (string if | else): type of the condition
9
+ - `condition` (string): The condition string to be checked
10
+ - `steps` (array): List of steps to execute if the condition is true
11
+
12
+
13
+ ## Usage/Examples
14
+ ### Step Configuration
15
+
16
+ ```json
17
+ {
18
+ "name": "if-else",
19
+ "node": "if-else@1.0.0",
20
+ "type": "local"
21
+ }
22
+ ```
23
+
24
+ ### Node Configuration
25
+
26
+
27
+ ```json
28
+ "if-else": {
29
+ "conditions": [
30
+ {
31
+ "type": "if",
32
+ "condition": "data !== undefined",
33
+ "steps": []
34
+ },
35
+ {
36
+ "type": "else",
37
+ "steps": []
38
+ }
39
+ ]
40
+ }
41
+ ```
42
+
package/config.json ADDED
@@ -0,0 +1,116 @@
1
+ {
2
+ "name": "if-else",
3
+ "version": "1.0.0",
4
+ "description": "Conditional statement to check if a property is equal to a value",
5
+ "group": "FLOW_CONTROL",
6
+ "config": {
7
+ "type": "object",
8
+ "properties": {
9
+ "conditions": {
10
+ "type": "array",
11
+ "description": "List of conditions to check",
12
+ "items": [
13
+ {
14
+ "type": "object",
15
+ "properties": {
16
+ "type": {
17
+ "type": "string",
18
+ "default": "if",
19
+ "description": "Type of the condition"
20
+ },
21
+ "condition": {
22
+ "type": "string",
23
+ "description": "Condition to check",
24
+ "default": "data !== undefined"
25
+ },
26
+ "steps": {
27
+ "type": "array",
28
+ "items": {
29
+ "type": "object",
30
+ "properties": {
31
+ "name": {
32
+ "type": "string",
33
+ "description": "Name of the step"
34
+ },
35
+ "node": {
36
+ "type": "string",
37
+ "description": "Node of the step"
38
+ },
39
+ "type": {
40
+ "type": "string",
41
+ "description": "Type of the step",
42
+ "default": "local"
43
+ }
44
+ },
45
+ "required": ["name", "node", "type"]
46
+ },
47
+ "description": "List of steps to execute if the condition is true"
48
+ }
49
+ },
50
+ "required": ["type", "condition", "steps"]
51
+ },
52
+ {
53
+ "type": "object",
54
+ "properties": {
55
+ "type": {
56
+ "type": "string"
57
+ },
58
+ "steps": {
59
+ "type": "array",
60
+ "items": {
61
+ "type": "object",
62
+ "properties": {
63
+ "name": {
64
+ "type": "string",
65
+ "description": "Name of the step"
66
+ },
67
+ "node": {
68
+ "type": "string",
69
+ "description": "Node of the step"
70
+ },
71
+ "type": {
72
+ "type": "string",
73
+ "description": "Type of the step",
74
+ "default": "local"
75
+ }
76
+ },
77
+ "required": ["name", "node", "type"]
78
+ }
79
+ }
80
+ },
81
+ "required": ["type", "steps"]
82
+ }
83
+ ]
84
+ }
85
+ },
86
+ "required": ["conditions"],
87
+ "example": {
88
+ "conditions": [
89
+ {
90
+ "type": "if",
91
+ "condition": "data !== undefined",
92
+ "steps": []
93
+ },
94
+ {
95
+ "type": "else",
96
+ "steps": []
97
+ }
98
+ ]
99
+ }
100
+ },
101
+ "inputs": {
102
+ "type": "any",
103
+ "description": "This node accept an anything as input"
104
+ },
105
+ "output": {
106
+ "type": "any",
107
+ "description": "This node return the result of the steps"
108
+ },
109
+ "steps": {
110
+ "type": "boolean"
111
+ },
112
+ "functions": {
113
+ "type": "array",
114
+ "items": {}
115
+ }
116
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * If-Else Node - Function-First Implementation
3
+ *
4
+ * Control flow node that evaluates conditions and returns the matching branch's steps.
5
+ * Migrated from class-based to function-first pattern using defineNode.
6
+ */
7
+ import { type Condition } from "@blokjs/runner";
8
+ import { z } from "zod";
9
+ declare const _default: import("@blokjs/runner").FunctionNode<z.ZodArray<z.ZodObject<{
10
+ type: z.ZodEnum<["if", "else"]>;
11
+ condition: z.ZodOptional<z.ZodString>;
12
+ steps: z.ZodArray<z.ZodAny, "many">;
13
+ }, "strip", z.ZodTypeAny, {
14
+ type: "if" | "else";
15
+ steps: any[];
16
+ condition?: string | undefined;
17
+ }, {
18
+ type: "if" | "else";
19
+ steps: any[];
20
+ condition?: string | undefined;
21
+ }>, "many">, z.ZodArray<z.ZodAny, "many">>;
22
+ export default _default;
23
+ export type NodeOptions = {
24
+ conditions: Condition[];
25
+ };
package/dist/index.js ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * If-Else Node - Function-First Implementation
3
+ *
4
+ * Control flow node that evaluates conditions and returns the matching branch's steps.
5
+ * Migrated from class-based to function-first pattern using defineNode.
6
+ */
7
+ import { defineNode } from "@blokjs/runner";
8
+ import { z } from "zod";
9
+ /**
10
+ * Helper function to evaluate JavaScript expressions in context
11
+ * Replicates NodeBase.runJs() functionality
12
+ */
13
+ function runJs(str, ctx, data = {}, func = {}, vars = {}) {
14
+ return Function("ctx", "data", "func", "vars", `"use strict";return (${str});`)(ctx, data, func, vars);
15
+ }
16
+ /**
17
+ * Zod schema for a single condition
18
+ */
19
+ const conditionSchema = z.object({
20
+ type: z.enum(["if", "else"]),
21
+ condition: z.string().optional(),
22
+ steps: z.array(z.any()), // NodeBase[] - can't properly type this with Zod
23
+ });
24
+ export default defineNode({
25
+ name: "if-else",
26
+ description: "Evaluates conditions and returns the matching branch's steps for execution",
27
+ // This is a flow control node — the runner uses processFlow() instead of process()
28
+ flow: true,
29
+ // Input: Array of conditions (if, else if, else)
30
+ input: z.array(conditionSchema),
31
+ // Output: Array of NodeBase (steps to execute)
32
+ // Note: This is a special flow control node that returns steps, not a standard response
33
+ output: z.array(z.any()),
34
+ async execute(ctx, inputs) {
35
+ const conditions = inputs;
36
+ let steps = [];
37
+ // Validate first condition is "if"
38
+ const firstCondition = conditions[0];
39
+ if (firstCondition.type !== "if") {
40
+ throw new Error("First condition must be an if");
41
+ }
42
+ // Validate last condition is "else" (if there are multiple conditions)
43
+ if (conditions.length > 1) {
44
+ const lastCondition = conditions[conditions.length - 1];
45
+ if (lastCondition.type !== "else") {
46
+ throw new Error("Last condition must be an else");
47
+ }
48
+ }
49
+ // Evaluate conditions in order
50
+ for (let i = 0; i < conditions.length; i++) {
51
+ const condition = conditions[i];
52
+ // If condition has a JavaScript expression, evaluate it
53
+ if (condition.condition !== undefined && condition.condition.trim() !== "") {
54
+ const result = runJs(condition.condition, ctx, ctx.response.data, {}, ctx.vars || {});
55
+ // If condition matches, use these steps and break
56
+ if (result) {
57
+ steps = condition.steps;
58
+ break;
59
+ }
60
+ }
61
+ else {
62
+ // No condition (else block) - use these steps and break
63
+ steps = condition.steps;
64
+ break;
65
+ }
66
+ }
67
+ // Return steps as NodeBase[] (flow control)
68
+ // The runner will recognize this as a flow node and execute the steps
69
+ return steps;
70
+ },
71
+ });
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ export declare const inputSchema: {
2
+ $schema: string;
3
+ title: string;
4
+ type: string;
5
+ items: {
6
+ type: string;
7
+ properties: {
8
+ type: {
9
+ type: string;
10
+ };
11
+ steps: {
12
+ type: string;
13
+ items: {
14
+ type: string;
15
+ properties: {
16
+ name: {
17
+ type: string;
18
+ };
19
+ node: {
20
+ type: string;
21
+ };
22
+ type: {
23
+ type: string;
24
+ };
25
+ };
26
+ required: string[];
27
+ };
28
+ };
29
+ condition: {
30
+ type: string;
31
+ };
32
+ };
33
+ required: string[];
34
+ };
35
+ };
@@ -0,0 +1,36 @@
1
+ export const inputSchema = {
2
+ $schema: "http://json-schema.org/draft-07/schema#",
3
+ title: "Generated schema for Root",
4
+ type: "array",
5
+ items: {
6
+ type: "object",
7
+ properties: {
8
+ type: {
9
+ type: "string",
10
+ },
11
+ steps: {
12
+ type: "array",
13
+ items: {
14
+ type: "object",
15
+ properties: {
16
+ name: {
17
+ type: "string",
18
+ },
19
+ node: {
20
+ type: "string",
21
+ },
22
+ type: {
23
+ type: "string",
24
+ },
25
+ },
26
+ required: ["name", "node", "type"],
27
+ },
28
+ },
29
+ condition: {
30
+ type: "string",
31
+ },
32
+ },
33
+ required: ["type", "steps"],
34
+ },
35
+ };
36
+ //# sourceMappingURL=inputSchema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputSchema.js","sourceRoot":"","sources":["../inputSchema.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;IAC1B,OAAO,EAAE,yCAAyC;IAClD,KAAK,EAAE,2BAA2B;IAClC,IAAI,EAAE,OAAO;IACb,KAAK,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACX,IAAI,EAAE;gBACL,IAAI,EAAE,QAAQ;aACd;YACD,KAAK,EAAE;gBACN,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACX,IAAI,EAAE;4BACL,IAAI,EAAE,QAAQ;yBACd;wBACD,IAAI,EAAE;4BACL,IAAI,EAAE,QAAQ;yBACd;wBACD,IAAI,EAAE;4BACL,IAAI,EAAE,QAAQ;yBACd;qBACD;oBACD,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;iBAClC;aACD;YACD,SAAS,EAAE;gBACV,IAAI,EAAE,QAAQ;aACd;SACD;QACD,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;KAC3B;CACD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * If-Else Node Tests - Updated for Function-First Implementation
3
+ *
4
+ * Tests migrated from class-based to function-first pattern.
5
+ * All existing behavior is preserved.
6
+ */
7
+ export {};
@@ -0,0 +1,173 @@
1
+ /**
2
+ * If-Else Node Tests - Updated for Function-First Implementation
3
+ *
4
+ * Tests migrated from class-based to function-first pattern.
5
+ * All existing behavior is preserved.
6
+ */
7
+ import { describe, expect, it, vi } from "vitest";
8
+ import IfElseNode from "../index";
9
+ describe("IfElse Node - Function-First", () => {
10
+ const mockContext = {
11
+ response: {
12
+ data: null,
13
+ error: null,
14
+ success: true,
15
+ },
16
+ request: {
17
+ body: {},
18
+ headers: {},
19
+ params: {},
20
+ query: {},
21
+ method: "GET",
22
+ },
23
+ config: {
24
+ "if-else": {},
25
+ },
26
+ id: "test-id",
27
+ workflow_name: "test-workflow",
28
+ workflow_path: "/test",
29
+ error: {
30
+ message: [],
31
+ },
32
+ logger: {
33
+ log: vi.fn(),
34
+ info: vi.fn(),
35
+ error: vi.fn(),
36
+ warn: vi.fn(),
37
+ debug: vi.fn(),
38
+ },
39
+ vars: {},
40
+ env: {},
41
+ eventLogger: null,
42
+ _PRIVATE_: null,
43
+ };
44
+ const step = {
45
+ name: "node1",
46
+ run: async (ctx, data) => ({}),
47
+ };
48
+ it("should execute the correct steps when if condition is true", async () => {
49
+ const conditions = [
50
+ {
51
+ type: "if",
52
+ condition: "ctx.request.method === 'GET'",
53
+ steps: [
54
+ (() => {
55
+ step.name = "step1";
56
+ return step;
57
+ })(),
58
+ ],
59
+ },
60
+ {
61
+ type: "else",
62
+ steps: [step],
63
+ condition: "",
64
+ },
65
+ ];
66
+ mockContext.request.method = "GET";
67
+ const result = (await IfElseNode.handle(mockContext, conditions));
68
+ const steps = result.data;
69
+ expect(steps[0].name).toEqual("step1");
70
+ });
71
+ it("should execute the else step when if condition is false", async () => {
72
+ const conditions = [
73
+ {
74
+ type: "if",
75
+ condition: "ctx.request.method === 'POST'",
76
+ steps: [step],
77
+ },
78
+ {
79
+ type: "else",
80
+ steps: [
81
+ (() => {
82
+ step.name = "step2";
83
+ return step;
84
+ })(),
85
+ ],
86
+ condition: "",
87
+ },
88
+ ];
89
+ const result = (await IfElseNode.handle(mockContext, conditions));
90
+ const steps = result.data;
91
+ expect(steps[0].name).toEqual("step2");
92
+ });
93
+ it("should throw an error if the first condition is not 'if'", async () => {
94
+ const conditions = [
95
+ {
96
+ type: "else",
97
+ steps: [step],
98
+ condition: "",
99
+ },
100
+ ];
101
+ const result = (await IfElseNode.handle(mockContext, conditions));
102
+ expect(result.success).toBe(false);
103
+ expect(result.error).toBeDefined();
104
+ });
105
+ it("should throw an error if the last condition is not 'else'", async () => {
106
+ const conditions = [
107
+ {
108
+ type: "if",
109
+ condition: "ctx.request.method === 'GET'",
110
+ steps: [step],
111
+ },
112
+ {
113
+ type: "if",
114
+ condition: "ctx.request.method === 'POST'",
115
+ steps: [step],
116
+ },
117
+ ];
118
+ const result = (await IfElseNode.handle(mockContext, conditions));
119
+ expect(result.success).toBe(false);
120
+ expect(result.error).toBeDefined();
121
+ });
122
+ it("should execute the first matching condition", async () => {
123
+ const conditions = [
124
+ {
125
+ type: "if",
126
+ condition: "ctx.request.method === 'POST'",
127
+ steps: [step],
128
+ },
129
+ {
130
+ type: "if",
131
+ condition: "ctx.request.method === 'GET'",
132
+ steps: [
133
+ (() => {
134
+ step.name = "step2";
135
+ return step;
136
+ })(),
137
+ ],
138
+ },
139
+ {
140
+ type: "else",
141
+ steps: [step],
142
+ condition: "",
143
+ },
144
+ ];
145
+ mockContext.request.method = "GET";
146
+ const result = (await IfElseNode.handle(mockContext, conditions));
147
+ const steps = result.data;
148
+ expect(steps[0].name).toEqual("step2");
149
+ });
150
+ it("should execute the else condition if none match", async () => {
151
+ const conditions = [
152
+ {
153
+ type: "if",
154
+ condition: "ctx.request.method === 'POST'",
155
+ steps: [step],
156
+ },
157
+ {
158
+ type: "else",
159
+ steps: [
160
+ (() => {
161
+ step.name = "step2";
162
+ return step;
163
+ })(),
164
+ ],
165
+ condition: "",
166
+ },
167
+ ];
168
+ const result = (await IfElseNode.handle(mockContext, conditions));
169
+ const steps = result.data;
170
+ expect(steps[0].name).toEqual("step2");
171
+ });
172
+ });
173
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../test/index.test.ts"],"names":[],"mappings":"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"}
package/index.ts ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * If-Else Node - Function-First Implementation
3
+ *
4
+ * Control flow node that evaluates conditions and returns the matching branch's steps.
5
+ * Migrated from class-based to function-first pattern using defineNode.
6
+ */
7
+
8
+ import type { ConditionOpts } from "@blokjs/helper";
9
+ import { type Condition, type BlokService, defineNode } from "@blokjs/runner";
10
+ import type { Context, NodeBase } from "@blokjs/shared";
11
+ import type ParamsDictionary from "@blokjs/shared/dist/types/ParamsDictionary";
12
+ import { z } from "zod";
13
+
14
+ /**
15
+ * Helper function to evaluate JavaScript expressions in context
16
+ * Replicates NodeBase.runJs() functionality
17
+ */
18
+ function runJs(
19
+ str: string,
20
+ ctx: Context,
21
+ data: ParamsDictionary = {},
22
+ func: Record<string, unknown> = {},
23
+ vars: Record<string, unknown> = {},
24
+ ): unknown {
25
+ return Function("ctx", "data", "func", "vars", `"use strict";return (${str});`)(ctx, data, func, vars);
26
+ }
27
+
28
+ /**
29
+ * Zod schema for a single condition
30
+ */
31
+ const conditionSchema = z.object({
32
+ type: z.enum(["if", "else"]),
33
+ condition: z.string().optional(),
34
+ steps: z.array(z.any()), // NodeBase[] - can't properly type this with Zod
35
+ });
36
+
37
+ export default defineNode({
38
+ name: "if-else",
39
+ description: "Evaluates conditions and returns the matching branch's steps for execution",
40
+
41
+ // This is a flow control node — the runner uses processFlow() instead of process()
42
+ flow: true,
43
+
44
+ // Input: Array of conditions (if, else if, else)
45
+ input: z.array(conditionSchema),
46
+
47
+ // Output: Array of NodeBase (steps to execute)
48
+ // Note: This is a special flow control node that returns steps, not a standard response
49
+ output: z.array(z.any()),
50
+
51
+ async execute(ctx, inputs) {
52
+ const conditions = inputs;
53
+ let steps: NodeBase[] = [];
54
+
55
+ // Validate first condition is "if"
56
+ const firstCondition = conditions[0] as ConditionOpts;
57
+ if (firstCondition.type !== "if") {
58
+ throw new Error("First condition must be an if");
59
+ }
60
+
61
+ // Validate last condition is "else" (if there are multiple conditions)
62
+ if (conditions.length > 1) {
63
+ const lastCondition = conditions[conditions.length - 1];
64
+ if (lastCondition.type !== "else") {
65
+ throw new Error("Last condition must be an else");
66
+ }
67
+ }
68
+
69
+ // Evaluate conditions in order
70
+ for (let i = 0; i < conditions.length; i++) {
71
+ const condition = conditions[i];
72
+
73
+ // If condition has a JavaScript expression, evaluate it
74
+ if (condition.condition !== undefined && condition.condition.trim() !== "") {
75
+ const result = runJs(condition.condition, ctx, ctx.response.data as ParamsDictionary, {}, ctx.vars || {});
76
+
77
+ // If condition matches, use these steps and break
78
+ if (result) {
79
+ steps = condition.steps as NodeBase[];
80
+ break;
81
+ }
82
+ } else {
83
+ // No condition (else block) - use these steps and break
84
+ steps = condition.steps as NodeBase[];
85
+ break;
86
+ }
87
+ }
88
+
89
+ // Return steps as NodeBase[] (flow control)
90
+ // The runner will recognize this as a flow node and execute the steps
91
+ return steps as unknown as BlokService<Condition[]>[];
92
+ },
93
+ });
94
+
95
+ // For backward compatibility
96
+ export type NodeOptions = {
97
+ conditions: Condition[];
98
+ };
@@ -0,0 +1,49 @@
1
+ import type { ConditionOpts } from "@blok/helper";
2
+ import { type Condition, type INanoServiceResponse, NanoService } from "@blok/runner";
3
+ import type { Context, NodeBase } from "@blok/shared";
4
+ import type ParamsDictionary from "@blok/shared/dist/types/ParamsDictionary";
5
+
6
+ export default class IfElse extends NanoService<Array<Condition>> {
7
+ constructor() {
8
+ super();
9
+ this.flow = true;
10
+ this.contentType = "";
11
+ }
12
+
13
+ async handle(ctx: Context, inputs: Array<Condition>): Promise<INanoServiceResponse | NanoService<Condition[]>[]> {
14
+ let steps: NodeBase[] = [];
15
+ const conditions = inputs;
16
+
17
+ const firstCondition = conditions[0] as ConditionOpts;
18
+ if (firstCondition.type !== "if") throw new Error("First condition must be an if");
19
+
20
+ if (conditions.length > 1) {
21
+ const lastCondition = conditions[conditions.length - 1];
22
+ if (lastCondition.type !== "else") throw new Error("Last condition must be an else");
23
+ }
24
+
25
+ for (let i = 0; i < conditions.length; i++) {
26
+ const condition = conditions[i];
27
+
28
+ if (condition.condition !== undefined && condition.condition.trim() !== "") {
29
+ const result = this.runJs(condition.condition, ctx, ctx.response.data as ParamsDictionary, {}, ctx.vars);
30
+
31
+ if (result) {
32
+ steps = condition.steps as NodeBase[];
33
+ break;
34
+ }
35
+ } else {
36
+ steps = condition.steps as NodeBase[];
37
+ break;
38
+ }
39
+ }
40
+
41
+ return steps as unknown as NanoService<Condition[]>[];
42
+ }
43
+ }
44
+
45
+ type NodeOptions = {
46
+ conditions: Condition[];
47
+ };
48
+
49
+ export type { NodeOptions };
package/inputSchema.ts ADDED
@@ -0,0 +1,35 @@
1
+ export const inputSchema = {
2
+ $schema: "http://json-schema.org/draft-07/schema#",
3
+ title: "Generated schema for Root",
4
+ type: "array",
5
+ items: {
6
+ type: "object",
7
+ properties: {
8
+ type: {
9
+ type: "string",
10
+ },
11
+ steps: {
12
+ type: "array",
13
+ items: {
14
+ type: "object",
15
+ properties: {
16
+ name: {
17
+ type: "string",
18
+ },
19
+ node: {
20
+ type: "string",
21
+ },
22
+ type: {
23
+ type: "string",
24
+ },
25
+ },
26
+ required: ["name", "node", "type"],
27
+ },
28
+ },
29
+ condition: {
30
+ type: "string",
31
+ },
32
+ },
33
+ required: ["type", "steps"],
34
+ },
35
+ };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@blokjs/if-else",
3
+ "version": "0.2.0",
4
+ "description": "blok if-else",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=18.0.0"
8
+ },
9
+ "author": "Deskree Technologies Inc.",
10
+ "license": "Apache-2.0",
11
+ "main": "dist/index.js",
12
+ "types": "dist/index.d.ts",
13
+ "scripts": {
14
+ "start:dev": "bun --watch run src/index.ts",
15
+ "build": "rimraf ./dist && tsc",
16
+ "build:dev": "tsc --watch",
17
+ "test": "vitest run",
18
+ "test:dev": "vitest --watch"
19
+ },
20
+ "devDependencies": {
21
+ "@types/lodash": "^4.14.196",
22
+ "@types/node": "^22.15.21",
23
+ "rimraf": "^6.1.2",
24
+ "typescript": "^5.8.3",
25
+ "vitest": "^4.0.18"
26
+ },
27
+ "dependencies": {
28
+ "@blokjs/helper": "workspace:*",
29
+ "@blokjs/runner": "workspace:*",
30
+ "@blokjs/shared": "workspace:*",
31
+ "lodash": "^4.17.21",
32
+ "zod": "^3.24.2"
33
+ },
34
+ "private": false,
35
+ "publishConfig": {
36
+ "access": "public"
37
+ }
38
+ }
@@ -0,0 +1,192 @@
1
+ /**
2
+ * If-Else Node Tests - Updated for Function-First Implementation
3
+ *
4
+ * Tests migrated from class-based to function-first pattern.
5
+ * All existing behavior is preserved.
6
+ */
7
+
8
+ import type { Condition, IBlokResponse, JsonLikeObject, ParamsDictionary } from "@blokjs/runner";
9
+ import type { Context, NodeBase, ResponseContext } from "@blokjs/shared";
10
+ import { describe, expect, it, vi } from "vitest";
11
+ import IfElseNode from "../index";
12
+
13
+ describe("IfElse Node - Function-First", () => {
14
+ const mockContext: Context = {
15
+ response: {
16
+ data: null,
17
+ error: null,
18
+ success: true,
19
+ },
20
+ request: {
21
+ body: {} as ParamsDictionary,
22
+ headers: {},
23
+ params: {},
24
+ query: {},
25
+ method: "GET",
26
+ },
27
+ config: {
28
+ "if-else": {},
29
+ },
30
+ id: "test-id",
31
+ workflow_name: "test-workflow",
32
+ workflow_path: "/test",
33
+ error: {
34
+ message: [],
35
+ },
36
+ logger: {
37
+ log: vi.fn(),
38
+ info: vi.fn(),
39
+ error: vi.fn(),
40
+ warn: vi.fn(),
41
+ debug: vi.fn(),
42
+ } as unknown as Context["logger"],
43
+ vars: {},
44
+ env: {},
45
+ eventLogger: null,
46
+ _PRIVATE_: null,
47
+ } as unknown as Context;
48
+
49
+ const step: {
50
+ name: string;
51
+ run?: (ctx: Context, data: ParamsDictionary) => Promise<ResponseContext>;
52
+ } = {
53
+ name: "node1",
54
+ run: async (ctx: Context, data: ParamsDictionary): Promise<ResponseContext> => ({}) as ResponseContext,
55
+ } as unknown as NodeBase;
56
+
57
+ it("should execute the correct steps when if condition is true", async () => {
58
+ const conditions: Condition[] = [
59
+ {
60
+ type: "if",
61
+ condition: "ctx.request.method === 'GET'",
62
+ steps: [
63
+ (() => {
64
+ step.name = "step1";
65
+ return step as unknown as NodeBase;
66
+ })(),
67
+ ],
68
+ },
69
+ {
70
+ type: "else",
71
+ steps: [step as unknown as NodeBase],
72
+ condition: "",
73
+ },
74
+ ];
75
+
76
+ (mockContext.request as JsonLikeObject).method = "GET";
77
+ const result = (await IfElseNode.handle(mockContext, conditions)) as IBlokResponse;
78
+ const steps = result.data as NodeBase[];
79
+ expect(steps[0].name).toEqual("step1");
80
+ });
81
+
82
+ it("should execute the else step when if condition is false", async () => {
83
+ const conditions: Condition[] = [
84
+ {
85
+ type: "if",
86
+ condition: "ctx.request.method === 'POST'",
87
+ steps: [step as unknown as NodeBase],
88
+ },
89
+ {
90
+ type: "else",
91
+ steps: [
92
+ (() => {
93
+ step.name = "step2";
94
+ return step as unknown as NodeBase;
95
+ })(),
96
+ ],
97
+ condition: "",
98
+ },
99
+ ];
100
+
101
+ const result = (await IfElseNode.handle(mockContext, conditions)) as IBlokResponse;
102
+ const steps = result.data as NodeBase[];
103
+ expect(steps[0].name).toEqual("step2");
104
+ });
105
+
106
+ it("should throw an error if the first condition is not 'if'", async () => {
107
+ const conditions: Condition[] = [
108
+ {
109
+ type: "else",
110
+ steps: [step as unknown as NodeBase],
111
+ condition: "",
112
+ },
113
+ ];
114
+
115
+ const result = (await IfElseNode.handle(mockContext, conditions)) as IBlokResponse;
116
+ expect(result.success).toBe(false);
117
+ expect(result.error).toBeDefined();
118
+ });
119
+
120
+ it("should throw an error if the last condition is not 'else'", async () => {
121
+ const conditions: Condition[] = [
122
+ {
123
+ type: "if",
124
+ condition: "ctx.request.method === 'GET'",
125
+ steps: [step as unknown as NodeBase],
126
+ },
127
+ {
128
+ type: "if",
129
+ condition: "ctx.request.method === 'POST'",
130
+ steps: [step as unknown as NodeBase],
131
+ },
132
+ ];
133
+
134
+ const result = (await IfElseNode.handle(mockContext, conditions)) as IBlokResponse;
135
+ expect(result.success).toBe(false);
136
+ expect(result.error).toBeDefined();
137
+ });
138
+
139
+ it("should execute the first matching condition", async () => {
140
+ const conditions: Condition[] = [
141
+ {
142
+ type: "if",
143
+ condition: "ctx.request.method === 'POST'",
144
+ steps: [step as unknown as NodeBase],
145
+ },
146
+ {
147
+ type: "if",
148
+ condition: "ctx.request.method === 'GET'",
149
+ steps: [
150
+ (() => {
151
+ step.name = "step2";
152
+ return step as unknown as NodeBase;
153
+ })(),
154
+ ],
155
+ },
156
+ {
157
+ type: "else",
158
+ steps: [step as unknown as NodeBase],
159
+ condition: "",
160
+ },
161
+ ];
162
+
163
+ (mockContext.request as JsonLikeObject).method = "GET";
164
+ const result = (await IfElseNode.handle(mockContext, conditions)) as IBlokResponse;
165
+ const steps = result.data as NodeBase[];
166
+ expect(steps[0].name).toEqual("step2");
167
+ });
168
+
169
+ it("should execute the else condition if none match", async () => {
170
+ const conditions: Condition[] = [
171
+ {
172
+ type: "if",
173
+ condition: "ctx.request.method === 'POST'",
174
+ steps: [step as unknown as NodeBase],
175
+ },
176
+ {
177
+ type: "else",
178
+ steps: [
179
+ (() => {
180
+ step.name = "step2";
181
+ return step as unknown as NodeBase;
182
+ })(),
183
+ ],
184
+ condition: "",
185
+ },
186
+ ];
187
+
188
+ const result = (await IfElseNode.handle(mockContext, conditions)) as IBlokResponse;
189
+ const steps = result.data as NodeBase[];
190
+ expect(steps[0].name).toEqual("step2");
191
+ });
192
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2022",
4
+ "module": "es2022",
5
+ "moduleResolution": "bundler",
6
+ "declaration": true,
7
+ "sourceMap": true,
8
+ "outDir": "./dist",
9
+ "esModuleInterop": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "strict": true,
12
+ "noUnusedLocals": true,
13
+ "noImplicitReturns": true,
14
+ "skipLibCheck": true
15
+ },
16
+ "compileOnSave": true
17
+ }