This document provides an overview of the ElsaScript DSL implementation for Elsa Workflows.
ElsaScript is a JavaScript-inspired textual DSL for authoring Elsa 3 workflows. It provides a concise, code-centric alternative to C# WorkflowBuilder APIs and JSON workflow definitions.
The parser uses a simplified regex-based approach to parse ElsaScript source code into an Abstract Syntax Tree (AST).
Supported Syntax:
usestatements for namespaces and expression language configurationworkflow "Name" { ... }declarations- Variable declarations:
var,let,const - Activity invocations with positional and named arguments
- Expression literals (strings, numbers, booleans, arrays)
- Expression language prefixes (
=>,js =>,cs =>,py =>,liquid =>) listenkeyword for workflow triggers (partial support)
Complete set of AST node types:
WorkflowNode- Root workflow definitionStatementNodebase class with implementations:VariableDeclarationNodeActivityInvocationNodeBlockNode(for sequences)IfNode,ForEachNode,ForNode,WhileNode,SwitchNodeFlowchartNode,ListenNode
ExpressionNodebase class with implementations:LiteralNode,IdentifierNode,ArrayLiteralNodeElsaExpressionNode(with language support)TemplateStringNode,BinaryExpressionNode,UnaryExpressionNode
ArgumentNodefor activity parametersUseNodefor import/configuration statements
Compiles AST to Elsa workflow activities:
- Traverses AST and constructs Elsa activity graphs
- Maps DSL constructs to Elsa activities:
- Blocks →
Sequence - Variables →
Variableinstances - Activity invocations → Elsa activity instances
- Control flow nodes → corresponding Elsa activities
- Blocks →
- Resolves activities via
IActivityRegistry - Binds expressions to Elsa expression system with language support
- Maps expression languages (js, cs, py, liquid) to Elsa providers
Integration with Elsa's module system:
ElsaScriptFeaturefor service registrationModuleExtensions.UseElsaScript()for easy setup- Registers
IElsaScriptParserandIElsaScriptCompilerservices
use Elsa.Activities.Console;
use expressions js;
workflow "HelloWorld" {
var greeting = "Hello";
WriteLine(=> greeting + " World");
WriteLine("Great to meet you!");
}
Six integration tests demonstrate the implementation:
- Parser can parse a simple workflow definition - Verifies basic workflow parsing
- Parser can parse variable declarations - Tests var/let/const parsing
- Parser can parse activity invocations with named arguments - Tests argument parsing
- Compiler service is registered and available - Verifies DI setup
- Compiler can parse and analyze a workflow AST - Tests AST analysis
- Compiler recognizes variable declarations in AST - Tests variable compilation
This is a foundation implementation with several areas for future enhancement:
- Uses regex instead of Parlot for parsing (simpler but less robust)
- Control flow parsing (if/foreach/while/for/switch) needs completion
- Block/sequence parsing needs enhancement
- Flowchart syntax not yet implemented
- Template string parsing incomplete
- Dynamic activity instantiation needs refinement
- Control flow compilation stubs need full implementation
- For loop compilation not implemented
- Flowchart compilation not implemented
- Error handling and diagnostics minimal
- End-to-end workflow execution not fully working
- Activity property setting needs enhancement
- Complex expression evaluation untested
- Complete parser using Parlot for robust parsing
- Implement full control flow parsing and compilation
- Fix dynamic activity instantiation for runtime execution
- Add comprehensive error messages and diagnostics
- Implement flowchart parsing and compilation
- Support template strings with interpolation
- Add output capture syntax (
let result = Activity()) - Implement switch fallthrough options
- Add try/catch/finally support
- IDE support (syntax highlighting, IntelliSense)
- Debugging support
- Performance optimizations
- Extended DSL features (custom operators, macros, etc.)
Current tests focus on:
- Parser correctness for basic constructs
- AST structure validation
- Compiler service availability
- Variable and activity node recognition
Additional testing needed for:
- Control flow execution
- Expression evaluation
- Error handling
- Edge cases and invalid syntax
The simplified regex-based parser was chosen to deliver a working proof-of-concept quickly. While less robust than a full Parlot implementation, it demonstrates the DSL concept and can be replaced with a more sophisticated parser later.
The separation allows for:
- Multiple compilation targets (if needed)
- AST analysis and transformation
- Better error reporting
- Easier testing of each component
Rather than creating a new expression language, ElsaScript wraps Elsa's existing expression providers (JavaScript, C#, Python, Liquid). This provides:
- Consistency with existing Elsa workflows
- Proven expression evaluation
- No additional dependencies
- Familiar syntax for Elsa users
src/modules/Elsa.Dsl.ElsaScript/Ast/- AST node definitionsCompiler/- AST to Elsa workflow compilerContracts/- Service interfacesExtensions/- DI extension methodsFeatures/- Elsa feature moduleParser/- ElsaScript parserElsa.Dsl.ElsaScript.csproj- Project file
test/integration/Elsa.Dsl.ElsaScript.IntegrationTests/ParserTests.cs- Parser integration testsCompilerTests.cs- Compiler integration testsElsa.Dsl.ElsaScript.IntegrationTests.csproj- Test project
Directory.Packages.props- Added Parlot package reference
The ElsaScript DSL provides a solid foundation for text-based workflow authoring in Elsa 3. While this initial implementation has limitations, it demonstrates the core concepts and provides a framework for future enhancements. The modular architecture integrates cleanly with Elsa's existing systems and can be extended incrementally.