@synergenius/flow-weaver 0.3.0 → 0.4.1
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/README.md +1 -0
- package/dist/annotation-generator.js +36 -0
- package/dist/api/generate-in-place.js +39 -0
- package/dist/api/generate.js +11 -1
- package/dist/api/manipulation/nodes.js +22 -0
- package/dist/ast/types.d.ts +27 -1
- package/dist/built-in-nodes/index.d.ts +1 -0
- package/dist/built-in-nodes/index.js +1 -0
- package/dist/built-in-nodes/invoke-workflow.js +12 -1
- package/dist/built-in-nodes/mock-types.d.ts +2 -0
- package/dist/built-in-nodes/wait-for-agent.d.ts +13 -0
- package/dist/built-in-nodes/wait-for-agent.js +26 -0
- package/dist/chevrotain-parser/fan-parser.d.ts +38 -0
- package/dist/chevrotain-parser/fan-parser.js +149 -0
- package/dist/chevrotain-parser/grammar-diagrams.d.ts +1 -0
- package/dist/chevrotain-parser/grammar-diagrams.js +3 -0
- package/dist/chevrotain-parser/index.d.ts +3 -1
- package/dist/chevrotain-parser/index.js +3 -1
- package/dist/chevrotain-parser/tokens.d.ts +2 -0
- package/dist/chevrotain-parser/tokens.js +10 -0
- package/dist/cli/commands/diagram.d.ts +2 -1
- package/dist/cli/commands/diagram.js +9 -6
- package/dist/cli/commands/run.js +59 -1
- package/dist/cli/flow-weaver.mjs +1396 -77
- package/dist/cli/index.js +23 -36
- package/dist/diagram/geometry.js +47 -5
- package/dist/diagram/html-viewer.d.ts +12 -0
- package/dist/diagram/html-viewer.js +399 -0
- package/dist/diagram/index.d.ts +12 -0
- package/dist/diagram/index.js +22 -0
- package/dist/diagram/types.d.ts +1 -0
- package/dist/doc-metadata/extractors/annotations.js +282 -1
- package/dist/doc-metadata/types.d.ts +6 -0
- package/dist/generator/control-flow.d.ts +13 -0
- package/dist/generator/control-flow.js +74 -0
- package/dist/generator/inngest.js +23 -0
- package/dist/generator/unified.js +122 -2
- package/dist/jsdoc-parser.d.ts +24 -0
- package/dist/jsdoc-parser.js +41 -1
- package/dist/mcp/agent-channel.d.ts +35 -0
- package/dist/mcp/agent-channel.js +61 -0
- package/dist/mcp/run-registry.d.ts +29 -0
- package/dist/mcp/run-registry.js +24 -0
- package/dist/mcp/tools-diagram.d.ts +1 -1
- package/dist/mcp/tools-diagram.js +15 -7
- package/dist/mcp/tools-editor.js +75 -3
- package/dist/mcp/workflow-executor.d.ts +28 -0
- package/dist/mcp/workflow-executor.js +62 -1
- package/dist/parser.d.ts +8 -0
- package/dist/parser.js +100 -0
- package/dist/runtime/ExecutionContext.d.ts +2 -0
- package/dist/runtime/ExecutionContext.js +2 -0
- package/dist/runtime/events.d.ts +1 -1
- package/dist/sugar-optimizer.js +28 -3
- package/dist/validator.d.ts +8 -0
- package/dist/validator.js +92 -0
- package/docs/reference/advanced-annotations.md +431 -0
- package/docs/reference/built-in-nodes.md +225 -0
- package/docs/reference/cli-reference.md +882 -0
- package/docs/reference/compilation.md +351 -0
- package/docs/reference/concepts.md +400 -0
- package/docs/reference/debugging.md +255 -0
- package/docs/reference/deployment.md +207 -0
- package/docs/reference/error-codes.md +686 -0
- package/docs/reference/export-interface.md +229 -0
- package/docs/reference/iterative-development.md +186 -0
- package/docs/reference/jsdoc-grammar.md +471 -0
- package/docs/reference/marketplace.md +205 -0
- package/docs/reference/node-conversion.md +308 -0
- package/docs/reference/patterns.md +161 -0
- package/docs/reference/scaffold.md +160 -0
- package/docs/reference/tutorial.md +519 -0
- package/package.json +37 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Export Interface (Ports)
|
|
3
|
+
description: How to define workflow input/output ports, scoped iteration, and forEach patterns
|
|
4
|
+
keywords: [ports, interface, inputs, outputs, scoped, forEach, iteration, param, returns, workflow]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Code-First Architecture
|
|
8
|
+
|
|
9
|
+
Flow Weaver generates JS/TS files from TypeScript sources with `@flowWeaver` annotations. Each export becomes a callable function.
|
|
10
|
+
|
|
11
|
+
Any `.ts`, `.tsx`, `.js`, or `.jsx` file with `@flowWeaver` annotations works.
|
|
12
|
+
|
|
13
|
+
# Port Definition
|
|
14
|
+
|
|
15
|
+
## Workflow Inputs (@param)
|
|
16
|
+
|
|
17
|
+
Use JSDoc `@param` to define Start node ports:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
/**
|
|
21
|
+
* @flowWeaver workflow
|
|
22
|
+
* @param data - Input data to process
|
|
23
|
+
* @param [optional] - Optional input (brackets = optional in TS type)
|
|
24
|
+
* @param [withDefault=42] - Optional with default value
|
|
25
|
+
*/
|
|
26
|
+
export function myWorkflow(
|
|
27
|
+
execute: boolean,
|
|
28
|
+
params: { data: any; optional?: any; withDefault?: number }
|
|
29
|
+
) { ... }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**IMPORTANT:**
|
|
33
|
+
|
|
34
|
+
- Second parameter MUST be named `params` - generator uses this name
|
|
35
|
+
- Optional `[param]` marks the TypeScript type as optional, but **if you connect to that port, you must provide a value**. Use optional params for ports that may not be connected.
|
|
36
|
+
|
|
37
|
+
## Workflow Outputs (@returns)
|
|
38
|
+
|
|
39
|
+
Use JSDoc `@returns` to define Exit node ports:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
/**
|
|
43
|
+
* @flowWeaver workflow
|
|
44
|
+
* @returns result - The output result
|
|
45
|
+
* @returns status - Status message
|
|
46
|
+
*/
|
|
47
|
+
export function myWorkflow(...): {
|
|
48
|
+
onSuccess: boolean;
|
|
49
|
+
onFailure: boolean;
|
|
50
|
+
result: any;
|
|
51
|
+
status: string
|
|
52
|
+
} { ... }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Node Inputs/Outputs
|
|
56
|
+
|
|
57
|
+
Use `@input` and `@output` for node types. **Inputs become direct parameters:**
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
/**
|
|
61
|
+
* @flowWeaver nodeType
|
|
62
|
+
* @input value - Value to process
|
|
63
|
+
* @input count - Number of times
|
|
64
|
+
* @output result - Processed result
|
|
65
|
+
*/
|
|
66
|
+
function processNode(execute: boolean, value: any, count: number) { ... }
|
|
67
|
+
// ^ ^
|
|
68
|
+
// Direct parameters (NOT wrapped in object)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
# Mandatory Ports
|
|
72
|
+
|
|
73
|
+
Always present on every node/workflow:
|
|
74
|
+
|
|
75
|
+
**Input:**
|
|
76
|
+
|
|
77
|
+
- `execute` (STEP) - First function parameter
|
|
78
|
+
|
|
79
|
+
**Output:**
|
|
80
|
+
|
|
81
|
+
- `onSuccess` (STEP) - In return type
|
|
82
|
+
- `onFailure` (STEP) - In return type
|
|
83
|
+
|
|
84
|
+
# Async Workflows
|
|
85
|
+
|
|
86
|
+
Use `async` keyword on function - no annotation needed:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
/**
|
|
90
|
+
* @flowWeaver workflow
|
|
91
|
+
* @param data - Input
|
|
92
|
+
* @returns result - Output
|
|
93
|
+
*/
|
|
94
|
+
export async function asyncWorkflow(
|
|
95
|
+
execute: boolean,
|
|
96
|
+
params: { data: any }
|
|
97
|
+
): Promise<{ onSuccess: boolean; onFailure: boolean; result: any }> {
|
|
98
|
+
// async implementation
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
# Scoped Ports (Iteration/Looping)
|
|
103
|
+
|
|
104
|
+
For iteration (forEach), use **per-port scopes** with `scope:scopeName` suffix on ports.
|
|
105
|
+
|
|
106
|
+
## 1. Define ForEach Node Type
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
/**
|
|
110
|
+
* @flowWeaver nodeType
|
|
111
|
+
* @label For Each
|
|
112
|
+
* @input items - Array to iterate
|
|
113
|
+
* @output start scope:processItem - Mandatory: triggers child execute
|
|
114
|
+
* @output item scope:processItem - Current item to process
|
|
115
|
+
* @input success scope:processItem - Mandatory: from child onSuccess
|
|
116
|
+
* @input failure scope:processItem - Mandatory: from child onFailure
|
|
117
|
+
* @input processed scope:processItem - Result from child
|
|
118
|
+
* @output results - Collected results
|
|
119
|
+
*/
|
|
120
|
+
function forEach(
|
|
121
|
+
execute: boolean,
|
|
122
|
+
items: any[],
|
|
123
|
+
processItem: (start: boolean, item: any) => { success: boolean; failure: boolean; processed: any }
|
|
124
|
+
) {
|
|
125
|
+
if (!execute) return { onSuccess: false, onFailure: false, results: [] };
|
|
126
|
+
const results = items.map((item) => processItem(true, item).processed);
|
|
127
|
+
return { onSuccess: true, onFailure: false, results };
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Key points:
|
|
132
|
+
|
|
133
|
+
- Scope name (`processItem`) MUST match callback parameter name
|
|
134
|
+
- Callback is auto-generated by compiler, receives scoped port values as args
|
|
135
|
+
- The node implementation iterates by calling callback for each item
|
|
136
|
+
- Mandatory scoped STEP ports: `start` (output), `success`/`failure` (inputs)
|
|
137
|
+
|
|
138
|
+
## 2. Use ForEach in Workflow
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
/**
|
|
142
|
+
* @flowWeaver workflow
|
|
143
|
+
* @node loop forEach
|
|
144
|
+
* @node proc processor loop.processItem
|
|
145
|
+
* @connect Start.execute -> loop.execute
|
|
146
|
+
* @connect Start.items -> loop.items
|
|
147
|
+
* @connect loop.start:processItem -> proc.execute
|
|
148
|
+
* @connect loop.item:processItem -> proc.item
|
|
149
|
+
* @connect proc.result -> loop.processed:processItem
|
|
150
|
+
* @connect proc.onSuccess -> loop.success:processItem
|
|
151
|
+
* @connect proc.onFailure -> loop.failure:processItem
|
|
152
|
+
* @connect loop.results -> Exit.results
|
|
153
|
+
* @connect loop.onSuccess -> Exit.onSuccess
|
|
154
|
+
* @connect loop.onFailure -> Exit.onFailure
|
|
155
|
+
*/
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Key syntax:
|
|
159
|
+
|
|
160
|
+
- `@node proc processor loop.processItem` - child node inside `loop`'s `processItem` scope
|
|
161
|
+
- `loop.item:processItem` - scoped OUTPUT port (`:scopeName` suffix)
|
|
162
|
+
- `loop.processed:processItem` - scoped INPUT port (`:scopeName` suffix)
|
|
163
|
+
- Connect child's `execute`/`onSuccess`/`onFailure` to scope's mandatory ports
|
|
164
|
+
|
|
165
|
+
**IMPORTANT:** Don't forget to wire `Start.execute` and `Exit.onSuccess/onFailure`!
|
|
166
|
+
|
|
167
|
+
# Common Mistakes
|
|
168
|
+
|
|
169
|
+
**Wrong node signature (wrapping inputs)**
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// WRONG - inputs wrapped in object
|
|
173
|
+
function node(execute: boolean, params: { value: any }) { ... }
|
|
174
|
+
|
|
175
|
+
// CORRECT - direct parameters for nodes
|
|
176
|
+
function node(execute: boolean, value: any) { ... }
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Missing execute parameter**
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
// WRONG - no execute
|
|
183
|
+
function node(value: any) { ... }
|
|
184
|
+
|
|
185
|
+
// CORRECT
|
|
186
|
+
function node(execute: boolean, value: any) { ... }
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Missing return properties**
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// WRONG - missing onFailure
|
|
193
|
+
return { onSuccess: true, result: 42 };
|
|
194
|
+
|
|
195
|
+
// CORRECT
|
|
196
|
+
return { onSuccess: true, onFailure: false, result: 42 };
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Multiple connections to same Exit port**
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// PROBLEMATIC - only one value will be used
|
|
203
|
+
@connect nodeA.result -> Exit.output
|
|
204
|
+
@connect nodeB.result -> Exit.output
|
|
205
|
+
|
|
206
|
+
// BETTER - use separate Exit ports
|
|
207
|
+
@connect nodeA.result -> Exit.successOutput
|
|
208
|
+
@connect nodeB.result -> Exit.errorOutput
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Using reserved names for node types**
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// WRONG - 'process' is a Node.js global
|
|
215
|
+
function process(execute: boolean, item: any) { ... }
|
|
216
|
+
|
|
217
|
+
// CORRECT - use non-reserved names
|
|
218
|
+
function processItem(execute: boolean, item: any) { ... }
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Avoid: `process`, `module`, `require`, `exports`, `console`, `global`
|
|
222
|
+
|
|
223
|
+
# Validation
|
|
224
|
+
|
|
225
|
+
Always validate after changes:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
flow-weaver validate <file>
|
|
229
|
+
```
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Flow Weaver Iterative Development
|
|
3
|
+
description: Step-by-step workflow building with test-driven approach
|
|
4
|
+
keywords: [iterative, TDD, step-by-step, building, testing, development process, expression, validate]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Build Process
|
|
8
|
+
|
|
9
|
+
Test every step. Building everything before testing is like writing 1000 lines of code without running it.
|
|
10
|
+
|
|
11
|
+
Workflows are TypeScript files with @flowWeaver annotations. Any `.ts`, `.tsx`, `.js`, or `.jsx` file works.
|
|
12
|
+
|
|
13
|
+
### Phase 1: Plan your Flow
|
|
14
|
+
|
|
15
|
+
First understand what the Flow is trying to achieve. Think of it as a function - it takes in data and returns data.
|
|
16
|
+
|
|
17
|
+
Plan:
|
|
18
|
+
|
|
19
|
+
- Export Interface (inputs/outputs)
|
|
20
|
+
- What nodes are needed
|
|
21
|
+
- If async behavior is required (use `async` function)
|
|
22
|
+
|
|
23
|
+
The whole point is for each node to become a module - encapsulated abstracted logic that can be swapped and changed.
|
|
24
|
+
|
|
25
|
+
### Phase 2: Specify and Test the Export Interface
|
|
26
|
+
|
|
27
|
+
Create the Export Interface by editing the workflow file directly.
|
|
28
|
+
|
|
29
|
+
Define:
|
|
30
|
+
|
|
31
|
+
- Start ports using `@param` JSDoc tags
|
|
32
|
+
- Exit ports using `@returns` JSDoc tags
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
/**
|
|
36
|
+
* @flowWeaver workflow
|
|
37
|
+
* @param input - Input data
|
|
38
|
+
* @returns result - Output result
|
|
39
|
+
*/
|
|
40
|
+
export function myWorkflow(
|
|
41
|
+
execute: boolean,
|
|
42
|
+
params: { input: any }
|
|
43
|
+
): { onSuccess: boolean; onFailure: boolean; result: any } {
|
|
44
|
+
return { onSuccess: true, onFailure: false, result: null };
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**IMPORTANT:** Second parameter MUST be named `params`.
|
|
49
|
+
|
|
50
|
+
Test:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
flow-weaver validate <file>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Phase 3: Create the Nodes
|
|
57
|
+
|
|
58
|
+
**Start with `@expression` mode for all nodes.** Only switch to normal mode when you need explicit branching (quality gates, conditional routing, error-with-data patterns).
|
|
59
|
+
|
|
60
|
+
Create nodes by adding `@flowWeaver nodeType` annotated functions.
|
|
61
|
+
|
|
62
|
+
Create at most 3 nodes at a time, test each.
|
|
63
|
+
|
|
64
|
+
Default to expression mode. Use normal mode only for:
|
|
65
|
+
- **Quality gates** -- routing to different paths based on success/failure
|
|
66
|
+
- **Conditional routing** -- explicit `onSuccess`/`onFailure` branching
|
|
67
|
+
- **Error-with-data patterns** -- returning error details alongside the failure signal
|
|
68
|
+
|
|
69
|
+
**Expression mode (recommended for most nodes):**
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
/**
|
|
73
|
+
* @flowWeaver nodeType
|
|
74
|
+
* @expression
|
|
75
|
+
* @label Add Numbers
|
|
76
|
+
* @input a - First number
|
|
77
|
+
* @input b - Second number
|
|
78
|
+
* @output result - Sum
|
|
79
|
+
*/
|
|
80
|
+
function addNumbers(a: number, b: number): number {
|
|
81
|
+
return a + b;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
> Use `@expression` for most nodes. Only use normal mode when you need custom failure handling or void returns.
|
|
86
|
+
|
|
87
|
+
**Normal mode (for custom error handling):**
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
/**
|
|
91
|
+
* @flowWeaver nodeType
|
|
92
|
+
* @label Risky Operation
|
|
93
|
+
* @input url - URL to fetch
|
|
94
|
+
* @output data - Fetched data
|
|
95
|
+
*/
|
|
96
|
+
async function riskyFetch(
|
|
97
|
+
execute: boolean,
|
|
98
|
+
url: string
|
|
99
|
+
): Promise<{ onSuccess: boolean; onFailure: boolean; data: any }> {
|
|
100
|
+
if (!execute) return { onSuccess: false, onFailure: false, data: null };
|
|
101
|
+
try {
|
|
102
|
+
const res = await fetch(url);
|
|
103
|
+
return { onSuccess: true, onFailure: false, data: await res.json() };
|
|
104
|
+
} catch {
|
|
105
|
+
return { onSuccess: false, onFailure: true, data: null };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Add node instances with `@node` and connections with `@connect`:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
/**
|
|
114
|
+
* @flowWeaver workflow
|
|
115
|
+
* @node adder addNumbers
|
|
116
|
+
* @connect Start.a -> adder.a
|
|
117
|
+
* @connect adder.result -> Exit.result
|
|
118
|
+
* @position adder 180 0
|
|
119
|
+
*/
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
> Expression nodes don't need explicit STEP connections -- the compiler infers execution order from data connections. Add STEP connections explicitly only when you need branching control.
|
|
123
|
+
|
|
124
|
+
Test after each change:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
flow-weaver validate <file>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Phase 4: Finalizing
|
|
131
|
+
|
|
132
|
+
After everything is connected:
|
|
133
|
+
|
|
134
|
+
1. Run multiple test scenarios
|
|
135
|
+
2. If not returning values, check return type
|
|
136
|
+
3. Verify node positioning with `@position nodeId x y` (in pixels)
|
|
137
|
+
4. Inspect the compiled source file for errors (compilation modifies the file in-place)
|
|
138
|
+
|
|
139
|
+
Final validation:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
flow-weaver validate <file>
|
|
143
|
+
flow-weaver compile <file>
|
|
144
|
+
flow-weaver describe <file> # Get workflow structure as JSON
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Common Mistakes
|
|
148
|
+
|
|
149
|
+
### 1. Missing STEP Connections (Normal Mode) or Adding Unnecessary Ones (Expression Mode)
|
|
150
|
+
|
|
151
|
+
**Normal mode nodes** need explicit STEP wiring: `@connect Start.execute -> firstNode.execute`. Without this, no node will run. **Expression mode** nodes auto-wire STEP connections from data flow -- you only need data connections for linear pipelines. Add explicit STEP connections only for branching (e.g., routing `onFailure` to a different node).
|
|
152
|
+
|
|
153
|
+
### 2. Wrapping Node Inputs in Object
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// WRONG -- this is workflow style, not node style
|
|
157
|
+
function myNode(execute: boolean, params: { a: number; b: number });
|
|
158
|
+
|
|
159
|
+
// CORRECT -- node inputs are direct parameters
|
|
160
|
+
function myNode(execute: boolean, a: number, b: number);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 3. Mixing STEP and Data Ports
|
|
164
|
+
|
|
165
|
+
`onSuccess` -> `inputData` is WRONG. STEP ports only connect to STEP ports. Data ports only connect to data ports.
|
|
166
|
+
|
|
167
|
+
### 4. Forgetting Exit Connections
|
|
168
|
+
|
|
169
|
+
If the workflow should return values, connect them: `@connect lastNode.result -> Exit.resultPort`. Also connect `lastNode.onSuccess -> Exit.onSuccess`.
|
|
170
|
+
|
|
171
|
+
### 5. Not Validating After Each Change
|
|
172
|
+
|
|
173
|
+
Always run `flow-weaver validate` after adding nodes/connections. Don't batch 10 changes then validate -- validate incrementally.
|
|
174
|
+
|
|
175
|
+
### 6. Using Normal Mode When Expression Mode Works
|
|
176
|
+
|
|
177
|
+
If the function returns a value and doesn't need custom error handling, use `@expression`. It's simpler and less error-prone. Expression mode eliminates the `execute` parameter, the `if (!execute)` guard, and the `onSuccess`/`onFailure` boilerplate. The compiler handles all of it.
|
|
178
|
+
|
|
179
|
+
**Rule of thumb:** If you are writing `if (!execute) return ...` and a `try/catch` that just returns `{ onSuccess: false, onFailure: true }`, you should be using expression mode instead.
|
|
180
|
+
|
|
181
|
+
### 7. Defaulting to Normal Mode
|
|
182
|
+
|
|
183
|
+
Normal mode adds boilerplate that expression mode handles automatically. Default to `@expression` for every node. Only reach for normal mode when the function needs to:
|
|
184
|
+
- Route to different downstream nodes on success vs. failure
|
|
185
|
+
- Return error data (not just signal failure)
|
|
186
|
+
- Perform void side-effects with explicit control flow
|