Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/long-guests-enter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@workflow/swc-plugin": patch
---

Apply workflow function transformation in "step" mode
559 changes: 430 additions & 129 deletions packages/swc-plugin-workflow/transform/src/lib.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export async function validStep() {
return 42;
}
export const validWorkflow = async ()=>{
'use workflow';
return 'test';
throw new Error("You attempted to execute workflow validWorkflow function directly. To start a workflow, use start(validWorkflow) from workflow/api");
};
validWorkflow.workflowId = "workflow//input.js//validWorkflow";
registerStepFunction("step//input.js//validStep", validStep);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Test anonymous default export workflow
/**__internal_workflows{"workflows":{"input.js":{"default":{"workflowId":"workflow//input.js//__default"}}}}*/;
export default async function() {
'use workflow';
const result = await someStep();
return result;
}
const __default = async function() {
throw new Error("You attempted to execute workflow __default function directly. To start a workflow, use start(__default) from workflow/api");
};
__default.workflowId = "workflow//input.js//__default";
export default __default;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Test default export arrow workflow
/**__internal_workflows{"workflows":{"input.js":{"default":{"workflowId":"workflow//input.js//__default"}}}}*/;
export default (async (data)=>{
'use workflow';
const processed = await processData(data);
return processed;
});
const __default = async (data)=>{
throw new Error("You attempted to execute workflow __default function directly. To start a workflow, use start(__default) from workflow/api");
};
__default.workflowId = "workflow//input.js//__default";
export default __default;
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ async function convertToLanguageModelPrompt({ prompt, supportedUrls, download =
};
}
export async function myWorkflow(input) {
'use workflow';
const result = await convertToLanguageModelPrompt({
prompt: input.prompt,
supportedUrls: {},
download: undefined
});
return result;
throw new Error("You attempted to execute workflow myWorkflow function directly. To start a workflow, use start(myWorkflow) from workflow/api");
}
myWorkflow.workflowId = "workflow//input.js//myWorkflow";
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
const __default = "existing variable";
// Use it to avoid unused variable
console.log(__default);
// Anonymous default export should get unique name (__default$1)
export default async function() {
'use workflow';
const result = await someStep();
return result;
}
const __default$1 = async function() {
throw new Error("You attempted to execute workflow __default$1 function directly. To start a workflow, use start(__default$1) from workflow/api");
};
__default$1.workflowId = "workflow//input.js//__default$1";
export default __default$1;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**__internal_workflows{"workflows":{"input.js":{"default":{"workflowId":"workflow//input.js//__default"}}}}*/;
export default async function() {
'use workflow';
const result = await someStep();
return result;
}
const __default = async function() {
throw new Error("You attempted to execute workflow __default function directly. To start a workflow, use start(__default) from workflow/api");
};
__default.workflowId = "workflow//input.js//__default";
export default __default;
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ async function stepFunctionWithoutExport(a, b) {
return a - b;
}
export async function workflowFunction(a, b) {
'use workflow';
const result = await stepFunction(a, b);
const result2 = await stepFunctionWithoutExport(a, b);
return result + result2;
throw new Error("You attempted to execute workflow workflowFunction function directly. To start a workflow, use start(workflowFunction) from workflow/api");
}
workflowFunction.workflowId = "workflow//input.js//workflowFunction";
export async function normalFunction(a, b) {
return a * b;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
/**__internal_workflows{"workflows":{"input.js":{"arrowWorkflow":{"workflowId":"workflow//input.js//arrowWorkflow"},"workflow":{"workflowId":"workflow//input.js//workflow"}}}}*/;
'use workflow';
async function local(input) {
return input.foo;
}
const localArrow = async (input)=>{
return input.bar;
};
export async function workflow(input) {
return input.foo;
throw new Error("You attempted to execute workflow workflow function directly. To start a workflow, use start(workflow) from workflow/api");
}
workflow.workflowId = "workflow//input.js//workflow";
export const arrowWorkflow = async (input)=>{
return input.bar;
throw new Error("You attempted to execute workflow arrowWorkflow function directly. To start a workflow, use start(arrowWorkflow) from workflow/api");
};
arrowWorkflow.workflowId = "workflow//input.js//arrowWorkflow";
Original file line number Diff line number Diff line change
@@ -1,37 +1,21 @@
import { registerStepFunction } from "workflow/internal/private";
/**__internal_workflows{"workflows":{"input.js":{"example":{"workflowId":"workflow//input.js//example"}}},"steps":{"input.js":{"arrowStep":{"stepId":"step//input.js//arrowStep"},"helpers/objectStep":{"stepId":"step//input.js//helpers/objectStep"},"letArrowStep":{"stepId":"step//input.js//letArrowStep"},"step":{"stepId":"step//input.js//step"},"varArrowStep":{"stepId":"step//input.js//varArrowStep"}}}}*/;
/**__internal_workflows{"workflows":{"input.js":{"example":{"workflowId":"workflow//input.js//example"}}},"steps":{"input.js":{"arrowStep":{"stepId":"step//input.js//arrowStep"},"helpers/objectStep":{"stepId":"step//input.js//example/helpers/objectStep"},"letArrowStep":{"stepId":"step//input.js//letArrowStep"},"step":{"stepId":"step//input.js//step"},"varArrowStep":{"stepId":"step//input.js//varArrowStep"}}}}*/;
// Function declaration step
async function example$step(a, b) {
return a + b;
}
var example$arrowStep = async (x, y)=>x * y;
var example$letArrowStep = async (x, y)=>x - y;
var example$varArrowStep = async (x, y)=>x / y;
var helpers$objectStep = async (x, y)=>{
var example$helpers$objectStep = async (x, y)=>{
return x + y + 10;
};
export async function example(a, b) {
"use workflow";
const step = example$step;
// Arrow function with const
const arrowStep = example$arrowStep;
// Arrow function with let
let letArrowStep = example$letArrowStep;
// Arrow function with var
var varArrowStep = example$varArrowStep;
// Object with step method
const helpers = {
objectStep: helpers$objectStep
};
const val = await step(a, b);
const val2 = await arrowStep(a, b);
const val3 = await letArrowStep(a, b);
const val4 = await varArrowStep(a, b);
const val5 = await helpers.objectStep(a, b);
return val + val2 + val3 + val4 + val5;
throw new Error("You attempted to execute workflow example function directly. To start a workflow, use start(example) from workflow/api");
}
example.workflowId = "workflow//input.js//example";
registerStepFunction("step//input.js//example/step", example$step);
registerStepFunction("step//input.js//example/arrowStep", example$arrowStep);
registerStepFunction("step//input.js//example/letArrowStep", example$letArrowStep);
registerStepFunction("step//input.js//example/varArrowStep", example$varArrowStep);
registerStepFunction("step//input.js//helpers/objectStep", helpers$objectStep);
registerStepFunction("step//input.js//example/helpers/objectStep", example$helpers$objectStep);
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**__internal_workflows{"workflows":{"input.js":{"example":{"workflowId":"workflow//input.js//example"}}},"steps":{"input.js":{"arrowStep":{"stepId":"step//input.js//arrowStep"},"helpers/objectStep":{"stepId":"step//input.js//helpers/objectStep"},"letArrowStep":{"stepId":"step//input.js//letArrowStep"},"step":{"stepId":"step//input.js//step"},"varArrowStep":{"stepId":"step//input.js//varArrowStep"}}}}*/;
/**__internal_workflows{"workflows":{"input.js":{"example":{"workflowId":"workflow//input.js//example"}}},"steps":{"input.js":{"arrowStep":{"stepId":"step//input.js//arrowStep"},"helpers/objectStep":{"stepId":"step//input.js//example/helpers/objectStep"},"letArrowStep":{"stepId":"step//input.js//letArrowStep"},"step":{"stepId":"step//input.js//step"},"varArrowStep":{"stepId":"step//input.js//varArrowStep"}}}}*/;
export async function example(a, b) {
var step = globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//example/step");
// Arrow function with const
Expand All @@ -9,7 +9,7 @@ export async function example(a, b) {
var varArrowStep = globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//example/varArrowStep");
// Object with step method
const helpers = {
objectStep: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//helpers/objectStep")
objectStep: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//example/helpers/objectStep")
};
const val = await step(a, b);
const val2 = await arrowStep(a, b);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,23 +80,9 @@ const arrowWrapperReturnNamedFunctionVar = (a, b, c)=>{
return fn;
};
export async function wflow() {
'use workflow';
let count = 42;
const namedStepWithClosureVars = wflow$namedStepWithClosureVars;
const agent = new DurableAgent({
arrowFunctionWithClosureVars: _anonymousStep2,
namedFunctionWithClosureVars: _anonymousStep3,
methodWithClosureVars: _anonymousStep4
});
await stepWrapperReturnArrowFunctionVar(1, 2, 3)();
await stepWrapperReturnNamedFunction(1, 2, 3)();
await stepWrapperReturnArrowFunction(1, 2, 3)();
await stepWrapperReturnNamedFunctionVar(1, 2, 3)();
await arrowWrapperReturnArrowFunctionVar(1, 2, 3)();
await arrowWrapperReturnNamedFunction(1, 2, 3)();
await arrowWrapperReturnArrowFunction(1, 2, 3)();
await arrowWrapperReturnNamedFunctionVar(1, 2, 3)();
throw new Error("You attempted to execute workflow wflow function directly. To start a workflow, use start(wflow) from workflow/api");
}
wflow.workflowId = "workflow//input.js//wflow";
registerStepFunction("step//input.js//stepWrapperReturnArrowFunctionVar/fn", stepWrapperReturnArrowFunctionVar$fn);
registerStepFunction("step//input.js//stepWrapperReturnNamedFunction/f", stepWrapperReturnNamedFunction$f);
registerStepFunction("step//input.js//stepWrapperReturnArrowFunction/_anonymousStep0", stepWrapperReturnArrowFunction$_anonymousStep0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ function stepWrapperReturnArrowFunctionVar(a, b, c) {
return fn;
}
function stepWrapperReturnNamedFunction(a, b, c) {
return globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//f", ()=>({
return globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//stepWrapperReturnNamedFunction/f", ()=>({
a,
b,
c
}));
}
function stepWrapperReturnArrowFunction(a, b, c) {
return globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//_anonymousStep0", ()=>({
return globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//stepWrapperReturnArrowFunction/_anonymousStep0", ()=>({
a,
b,
c
Expand All @@ -39,14 +39,14 @@ const arrowWrapperReturnArrowFunctionVar = (a, b, c)=>{
return fn;
};
const arrowWrapperReturnNamedFunction = (a, b, c)=>{
return globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//f", ()=>({
return globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//arrowWrapperReturnNamedFunction/f", ()=>({
a,
b,
c
}));
};
const arrowWrapperReturnArrowFunction = (a, b, c)=>{
return globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//_anonymousStep1", ()=>({
return globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//input.js//arrowWrapperReturnArrowFunction/_anonymousStep1", ()=>({
a,
b,
c
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,8 @@ import * as z from 'zod';
var test$_anonymousStep0 = async ()=>gateway('openai/gpt-5');
var test$_anonymousStep1 = async ({ location })=>`Weather in ${location}: Sunny, 72°F`;
export async function test() {
'use workflow';
const agent = new DurableAgent({
model: _anonymousStep0,
tools: {
getWeather: tool({
description: 'Get weather for a location',
inputSchema: z.object({
location: z.string()
}),
execute: _anonymousStep1
})
}
});
await agent.stream({
messages: [
{
role: 'user',
content: 'What is the weather in San Francisco?'
}
]
});
throw new Error("You attempted to execute workflow test function directly. To start a workflow, use start(test) from workflow/api");
}
test.workflowId = "workflow//input.js//test";
registerStepFunction("step//input.js//test/_anonymousStep0", test$_anonymousStep0);
registerStepFunction("step//input.js//test/_anonymousStep1", test$_anonymousStep1);
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**__internal_workflows{"workflows":{"input.js":{"workflow":{"workflowId":"workflow//input.js//workflow"}}}}*/;
export async function workflow(a, b) {
'use workflow';
return add(a, b);
throw new Error("You attempted to execute workflow workflow function directly. To start a workflow, use start(workflow) from workflow/api");
}
workflow.workflowId = "workflow//input.js//workflow";
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**__internal_workflows{"workflows":{"input.js":{"processData":{"workflowId":"workflow//input.js//processData"}}}}*/;
export const processData = async (data)=>{
'use workflow';
return data.processed;
throw new Error("You attempted to execute workflow processData function directly. To start a workflow, use start(processData) from workflow/api");
};
processData.workflowId = "workflow//input.js//processData";
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
// Test workflow functions in client mode
/**__internal_workflows{"workflows":{"input.js":{"arrowWorkflow":{"workflowId":"workflow//input.js//arrowWorkflow"},"default":{"workflowId":"workflow//input.js//defaultWorkflow"},"internalWorkflow":{"workflowId":"workflow//input.js//internalWorkflow"},"myWorkflow":{"workflowId":"workflow//input.js//myWorkflow"}}}}*/;
export async function myWorkflow() {
'use workflow';
const result = await someStep();
return result;
throw new Error("You attempted to execute workflow myWorkflow function directly. To start a workflow, use start(myWorkflow) from workflow/api");
}
myWorkflow.workflowId = "workflow//input.js//myWorkflow";
export const arrowWorkflow = async ()=>{
'use workflow';
const data = await fetchData();
return data;
throw new Error("You attempted to execute workflow arrowWorkflow function directly. To start a workflow, use start(arrowWorkflow) from workflow/api");
};
arrowWorkflow.workflowId = "workflow//input.js//arrowWorkflow";
export default async function defaultWorkflow() {
'use workflow';
return await process();
throw new Error("You attempted to execute workflow defaultWorkflow function directly. To start a workflow, use start(defaultWorkflow) from workflow/api");
}
defaultWorkflow.workflowId = "workflow//input.js//defaultWorkflow";
// Non-export workflow function
async function internalWorkflow() {
'use workflow';
return 'internal';
throw new Error("You attempted to execute workflow internalWorkflow function directly. To start a workflow, use start(internalWorkflow) from workflow/api");
}
internalWorkflow.workflowId = "workflow//input.js//internalWorkflow";
// Use the internal workflow to avoid lint warning
regularFunction(internalWorkflow);
// Regular function should not be affected
Expand Down
Loading