-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add Elsa Script DSL #7076
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop/3.6.0
Are you sure you want to change the base?
Add Elsa Script DSL #7076
Conversation
Remove unnecessary line breaks
…t references - Updated multiple package versions in `Directory.Packages.props` for better dependency management, including `BenchmarkDotNet`, `FastEndpoints`, and `Microsoft.Extensions.Http.Resilience`. - Minor version upgrade for `System.Formats.Asn1` in `_build.csproj`. - Replaced project reference to `Elsa.csproj` with `Elsa.IO.Http.csproj` in `Elsa.ServerAndStudio.Web.csproj`, enhancing modularity. - Added new using directive for `Elsa.IO.Http.Features` in `Program.cs` to support new HTTP functionalities.
These changes indicate that the associated projects or dependencies are no longer needed or have been replaced by other components in the solution.
* Update RawStringContent encoding in JsonContentFactory Modified the instantiation of `RawStringContent` to use a new `UTF8Encoding` instance with `encoderShouldEmitUTF8Identifier` set to `false`, affecting the handling of the UTF-8 byte order mark (BOM) in serialized JSON content. Fixes a bug with content length being different than expected. * Refactor JsonContentFactory to reuse UTF8Encoding Introduced a private static readonly field `_utf8Encoding` in the `JsonContentFactory` class to improve code readability and performance. This change replaces the instantiation of `UTF8Encoding` in the `CreateHttpContent` method, allowing for the reuse of the same encoding instance. --------- Co-authored-by: Max Brooks <[email protected]>
* Enhance thread safety with ConcurrentDictionary usage Replaced `IDictionary` with `ConcurrentDictionary` for both `_scheduledTasks` and `_scheduledTaskKeys` to improve thread safety in a multi-threaded environment. Updated methods `RegisterScheduledTask`, `RemoveScheduledTask`, and `RemoveScheduledTasks` to utilize the `Remove` method of `ConcurrentDictionary`, ensuring safe and efficient removal of scheduled tasks. * Refactor task registration and removal logic Updated `RegisterScheduledTask` to use `AddOrUpdate` for streamlined task management. This change simplifies the addition and updating of scheduled tasks by consolidating logic into a single operation. Introduced `RemoveScheduledTask` method to handle task removal by name, improving code organization and clarity. * Improve task removal handling in LocalScheduler Modified the `LocalScheduler` class to enhance the removal process of scheduled tasks from the `_scheduledTaskKeys` collection. The removal operation now captures the result in a variable and includes a conditional check to log a warning if the task was not found, improving error handling and debugging capabilities. * Refactor task removal in LocalScheduler Updated the removal process for scheduled tasks in `_scheduledTasks`. The new implementation collects all corresponding keys and attempts to remove them individually, logging warnings for any failures. This enhances error handling and provides better debugging information. --------- Co-authored-by: Max Brooks <[email protected]>
…sions.GetItemSource (#6897)
Co-authored-by: Peter Klooster <[email protected]>
- Deleted several project references from `Elsa.sln` to clean up the solution. - Updated `Directory.Packages.props` for consistency and alignment with the latest package versions.
Co-authored-by: sfmskywalker <[email protected]>
Co-authored-by: sfmskywalker <[email protected]>
Co-authored-by: sfmskywalker <[email protected]>
- Removed `ActivityFactory` and its related interfaces and extensions. - Introduced `ActivityActivator` for handling activity creation. - Extended AST with support for comprehensive workflow structures: - Added nodes for flowcharts, if/else, loops, and variable declarations. - Updated `IElsaScriptCompiler` to use asynchronous methods. - Expanded `ElsaScriptParser` to simplify syntax for `UseNode` and argument parsing. - Adjusted compiler and parser for compatibility with new workflow AST model.
…r tests - Updated method names in `CompilerTests` and `ParserTests` for better readability and description of test intent. - Added tests for compiler and parser: - Support for workflows without the `workflow` keyword.
…e a tokenizer - Added `TokenizeStatements` method to split source into statements for enhanced parsing accuracy. - Updated logic to process statements instead of raw lines, reducing parsing complexity and improving reliability. - Improved handling of workflow and statement parsing, including edge cases with braces, parentheses, and string literals.
- Added the `Elsa.WorkflowProviders.BlobStorage.ElsaScript` module to enable ElsaScript-based workflow definitions for BlobStorage. - Implemented `ElsaScriptBlobWorkflowFormatHandler` for parsing ElsaScript workflows stored in BlobStorage. - Extended `ElsaScriptParser` to leverage Parlot for improved DSL parsing. - Introduced `IBlobWorkflowFormatHandler` to centralize workflow format handling and parsing. - Updated `Elsa.Server.Web` to reference the new module and include an ElsaScript "Hello World" example workflow.
…ndling - Changed `ElsaScriptCompiler` service registration from `Singleton` to `Scoped` for better dependency management. - Enhanced the "Hello World" example workflow and added `CopyToOutputDirectory` configuration. - Removed unused namespaces and adjusted references in multiple projects to improve maintainability. - Updated logging levels in `appsettings.json` to reduce unnecessary debug output. - Improved `PolymorphicObjectConverter` by removing redundant dependencies. - Added missing references to enhance feature support and ensure compatibility.
…aScriptCompiler` - Added support for positional arguments with constructor matching logic. - Refactored `InstantiateActivityUsingConstructor` to enhance activity creation. - Updated `ActivityDescriptor` and related types to include `ClrType` for streamlined activity resolution. - Simplified `TypedActivityProvider` by annotating it with `[UsedImplicitly]`. - Adjusted `ElsaScriptParser` to remove unnecessary options from string literal definitions.
- Deleted `elsa-studio.yml` workflow as it's no longer used. - Updated `Elsa.sln` to remove reference to the deleted workflow. - Changed `base_version` in `packages.yml` from `3.7.0` to `3.6.0`.
…view` to `v3.6.0-preview`
…eview` to `v3.6-preview`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Process use statements (workflow-level overrides global) | ||
| foreach (var useNode in workflowNode.UseStatements) | ||
| { | ||
| if (useNode.Type == UseType.Expressions) | ||
| { | ||
| _defaultExpressionLanguage = MapLanguageName(useNode.Value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reset default expression language per compilation
ElsaScriptCompiler stores the default expression language in _defaultExpressionLanguage and mutates it when a use expressions directive is parsed, but CompileWorkflowNodeAsync never reinitializes the field for a new compilation. Because the compiler is registered as a scoped service and reused, compiling a workflow after one that set use expressions liquid will keep Liquid as the default even if the later workflow omits that directive, so unqualified expressions get compiled in the wrong language. Reset the default before processing each workflow to avoid leaking state across compilations.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces ElsaScript, a JavaScript-inspired textual DSL for authoring Elsa 3 workflows, providing a code-centric alternative to C# WorkflowBuilder APIs and JSON workflow definitions.
Key changes include:
- New ElsaScript parser and compiler using Parlot for robust parsing
- AST-based workflow compilation with support for variables, control flow, and flowcharts
- Integration with BlobStorage provider for
.elsafile support - Database schema updates to support symmetric round-trip preservation of original source
- Refactored activity instantiation to remove dependency on
IActivityFactory
Reviewed Changes
Copilot reviewed 105 out of 108 changed files in this pull request and generated 33 comments.
Show a summary per file
| File | Description |
|---|---|
src/modules/Elsa.Dsl.ElsaScript/ |
New module implementing ElsaScript parser, compiler, AST nodes, and materializer |
src/modules/Elsa.WorkflowProviders.BlobStorage.ElsaScript/ |
BlobStorage integration for ElsaScript workflows |
src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs |
Refactored from interface-based to factory-based activity instantiation |
src/modules/Elsa.Workflows.Management/Entities/WorkflowDefinition.cs |
Added OriginalSource field for symmetric round-trip support |
test/integration/Elsa.Dsl.ElsaScript.IntegrationTests/ |
Comprehensive parser and compiler integration tests |
| Database migrations | Added OriginalSource column across all EF Core providers |
src/modules/Elsa.Scheduling/Services/LocalScheduler.cs |
Fixed race conditions by using ConcurrentDictionary |
Files not reviewed (2)
- src/modules/Elsa.Persistence.EFCore.SqlServer/Migrations/Management/20251116182628_V3_6.Designer.cs: Language not supported
- src/modules/Elsa.Persistence.EFCore.Sqlite/Migrations/Management/20251116182711_V3_6.Designer.cs: Language not supported
Comments suppressed due to low confidence (4)
src/modules/Elsa.Persistence.EFCore.PostgreSql/Migrations/Management/20251116182753_V3_6.cs:30
- The migration adds the OriginalSource column, then performs ALTER TABLE operations, and finally drops the OriginalSource column in the same Up() method. This will remove the column that was just added. The DropColumn should only be in the Down() method for rollback.
src/modules/Elsa.Workflows.Management/Extensions/ActivityFactoryExtensions.cs:1 - The entire ActivityFactoryExtensions.cs file has been deleted, but references to this extension method may still exist elsewhere in the codebase if it was used. Ensure that all usages of the
Create<T>()extension method have been updated to use the new pattern.
test-flowchart.txt:1 - Test files
test-flowchart.txtandtest-simple-flowchart.elsaappear to be temporary test artifacts that should not be committed to the repository root. Consider moving them to a test fixtures directory or adding them to .gitignore.
src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs:62 - Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
src/modules/Elsa.Workflows.Management/Extensions/ActivityDescriberExtensions.cs
Show resolved
Hide resolved
| name: "OriginalSource", | ||
| schema: _schema.Schema, | ||
| table: "WorkflowDefinitions", | ||
| type: "NCLOB", | ||
| nullable: true); |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using NCLOB for OriginalSource in Oracle may cause performance issues for large workflow definitions. The ModelSnapshot shows NVARCHAR2(2000) instead. Consider using CLOB or ensure consistency between migration and snapshot, or document the size limitation if NVARCHAR2(2000) is intentional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to apply changes based on this feedback. Use the recommended solution, keeping in mind that OriginalSource may exceed the 2000 character limit, given that it may store large workflow definitions in JSON format.
| var removed = _scheduledTaskKeys.TryRemove(existingScheduledTask, out ICollection<string>? _); | ||
| if (!removed) | ||
| System.Diagnostics.Debug.WriteLine($"[LocalScheduler] Warning: Tried to remove scheduled task keys for an existing scheduled task, but it was not present in _scheduledTaskKeys."); |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using System.Diagnostics.Debug.WriteLine for production diagnostics is not recommended. This output will only appear in debug builds and won't be visible in production logs. Use the ILogger infrastructure instead for consistent logging across environments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to apply changes based on this feedback. Find all occurrences of System.Diagnostics.Debug.WriteLine and replace them appropriately with the ILogger infrastructure.
src/modules/Elsa.WorkflowProviders.BlobStorage/Handlers/JsonBlobWorkflowFormatHandler.cs
Show resolved
Hide resolved
...lsa.WorkflowProviders.BlobStorage.ElsaScript/Handlers/ElsaScriptBlobWorkflowFormatHandler.cs
Show resolved
Hide resolved
| if (p.HasDefaultValue) | ||
| { | ||
| args[i] = p.DefaultValue; | ||
| } | ||
| else | ||
| { | ||
| args[i] = p.ParameterType.IsValueType | ||
| ? Activator.CreateInstance(p.ParameterType) | ||
| : null; | ||
| } |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
| if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Input<>)) | ||
| { | ||
| // Extract the T from Input<T> | ||
| innerType = targetType.GetGenericArguments()[0]; | ||
| } | ||
| else | ||
| { | ||
| innerType = targetType; | ||
| } |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
| if (materializedWorkflow.MaterializerName == "Json") | ||
| { | ||
| stringData = _activitySerializer.Serialize(workflow.Root); | ||
| } | ||
| else | ||
| { | ||
| // For new formats (ElsaScript, YAML, etc.), only OriginalSource is needed | ||
| // StringData can be null as these materializers only use OriginalSource | ||
| stringData = null; | ||
| } |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
…rts in `LocalScheduler` - Cleaned up unnecessary using directives to improve code readability and maintainability. - Minor whitespace adjustment for consistent formatting.
- Updated exception handling in `ElsaScriptBlobWorkflowFormatHandler` and `JsonBlobWorkflowFormatHandler` to gracefully catch and log all exceptions during workflow parsing. - Adjusted comments to clarify behavior for invalid user-provided files, ensuring the workflow loading process is not disrupted.
…or improved file filtering - Added `SupportedExtensions` property to all blob format handlers to optimize blob storage browsing. - Simplified `CanHandle` logic by removing extension checks, leveraging `SupportedExtensions` for initial filtering. - Updated comments for clarity and consistency across handlers.
…gData` assignment logic and improve readability
Co-authored-by: Copilot <[email protected]>
|
@sfmskywalker I've opened a new pull request, #7079, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@sfmskywalker I've opened a new pull request, #7080, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@sfmskywalker I've opened a new pull request, #7081, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@sfmskywalker I've opened a new pull request, #7082, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@sfmskywalker I've opened a new pull request, #7083, to work on those changes. Once the pull request is ready, I'll request review from you. |
…prove language mapping, and enhance asynchronous flowchart compilation
* Initial plan * Fix ParseError formatting to use Message and Position properties Co-authored-by: sfmskywalker <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: sfmskywalker <[email protected]>
…7083) * Initial plan * Replace 'as' casts with direct casts in ParserTests for better null safety Co-authored-by: sfmskywalker <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: sfmskywalker <[email protected]>
#7079) * Initial plan * Fix Oracle OriginalSource and StringData column types to handle large data Co-authored-by: sfmskywalker <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: sfmskywalker <[email protected]>
…ed clarity and type safety
… copilot/add-elsascript-dsl
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Description
This PR introduces ElsaScript, a JavaScript-inspired textual Domain Specific Language (DSL) for authoring Elsa 3 workflows.
While the visual designer remains excellent for high-level composition and non-technical users, a textual DSL fills a critical gap for developers who need speed, precision, and better integration with source control workflows.
Motivation & Rationale
Why introduce a textual DSL when we already have JSON/YAML and a visual designer?
Superior Source Control & Code Reviews
Developer Productivity
Runtime Flexibility with "Compiled" Safety
Workflowobject model at runtime. This allows workflows to be loaded dynamically from Blob Storage or databases (like scripts) without requiring a full project recompile/redeployment (unlike C# workflows), while offering a much terser syntax than raw JSON.Expressive Logic
flowchart,forloops,if/elseblocks, andswitchstatements that map 1:1 to their Activity counterparts. It also supports mixed expression languages (JavaScript, C#, Liquid) within the same file.Key Features
var,const) and control flow.Example
A simple workflow demonstrating loops, mixed expression languages (JS and C#), and variable scoping:
This change is