Skip to content

Commit 8b470f0

Browse files
authored
Apply SWC transformation on step functions returned from factory function (#360)
Added support for transforming step functions that are returned from factory functions. ### What changed? Enhanced the SWC plugin to detect and transform step functions that are defined within object literals returned by factory functions. The transformation now properly identifies arrow functions with object literal bodies and processes their step functions accordingly. Added test fixtures to verify the functionality: - Created test cases for a factory function that returns an object with a step method - Added corresponding output files for client, step, and workflow modes ### How to test? 1. Create a factory function that returns an object with methods marked as steps: ```javascript const myFactory = () => ({ myStep: async () => { 'use step'; await fs.mkdir('test'); }, }); ``` 2. Verify that the step function is properly transformed and registered when used in a workflow. ### Why make this change? This enhancement supports a common pattern where developers create factory functions that return objects containing step methods. Without this change, step functions defined in this pattern weren't being properly transformed, which limited the flexibility of the workflow system.
1 parent fb9fd0f commit 8b470f0

File tree

6 files changed

+73
-1
lines changed

6 files changed

+73
-1
lines changed

.changeset/metal-cycles-slide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@workflow/swc-plugin": patch
3+
---
4+
5+
Apply SWC transformation on step functions returned from factory function

packages/swc-plugin-workflow/transform/src/lib.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,40 @@ impl StepTransform {
864864
stmt.visit_mut_children_with(self);
865865
}
866866
}
867-
Stmt::Decl(Decl::Var(_)) => {
867+
Stmt::Decl(Decl::Var(var_decl)) => {
868+
// Check if any declarators contain arrow functions with object literal bodies
869+
for declarator in &mut var_decl.decls {
870+
if let Some(init) = &mut declarator.init {
871+
if let Pat::Ident(binding) = &declarator.name {
872+
let name = binding.id.sym.to_string();
873+
874+
// Check if the initializer is an arrow function with object literal body
875+
if let Expr::Arrow(arrow_expr) = &mut **init {
876+
match &mut *arrow_expr.body {
877+
BlockStmtOrExpr::Expr(expr) => {
878+
// Handle both direct object literals and parenthesized ones
879+
let obj_lit_mut = match &mut **expr {
880+
Expr::Object(obj) => Some(obj),
881+
Expr::Paren(paren) => {
882+
if let Expr::Object(obj) = &mut *paren.expr {
883+
Some(obj)
884+
} else {
885+
None
886+
}
887+
}
888+
_ => None,
889+
};
890+
891+
if let Some(obj_lit) = obj_lit_mut {
892+
self.process_object_properties_for_step_functions(obj_lit, &name);
893+
}
894+
}
895+
_ => {}
896+
}
897+
}
898+
}
899+
}
900+
}
868901
stmt.visit_mut_children_with(self);
869902
}
870903
_ => {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import fs from 'fs/promises';
2+
3+
const myFactory = () => ({
4+
myStep: async () => {
5+
'use step';
6+
await fs.mkdir('test');
7+
},
8+
});
9+
10+
export default myFactory;
11+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import fs from 'fs/promises';
2+
const myFactory = ()=>({
3+
myStep: async ()=>{
4+
await fs.mkdir('test');
5+
}
6+
});
7+
export default myFactory;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { registerStepFunction } from "workflow/internal/private";
2+
import fs from 'fs/promises';
3+
/**__internal_workflows{"steps":{"input.js":{"myFactory/myStep":{"stepId":"step//input.js//myFactory/myStep"}}}}*/;
4+
var myFactory$myStep = async ()=>{
5+
await fs.mkdir('test');
6+
};
7+
const myFactory = ()=>({
8+
myStep: myFactory$myStep
9+
});
10+
export default myFactory;
11+
registerStepFunction("step//input.js//myFactory/myStep", myFactory$myStep);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**__internal_workflows{"steps":{"input.js":{"myFactory/myStep":{"stepId":"step//input.js//myFactory/myStep"}}}}*/;
2+
const myFactory = ()=>({
3+
myStep: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//myFactory/myStep")
4+
});
5+
export default myFactory;

0 commit comments

Comments
 (0)