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
45 changes: 40 additions & 5 deletions src/WorkflowCore.DSL/Services/DefinitionLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
using WorkflowCore.Interface;
using WorkflowCore.Models;
Expand All @@ -18,6 +19,40 @@ public class DefinitionLoader : IDefinitionLoader
{
private readonly IWorkflowRegistry _registry;
private readonly ITypeResolver _typeResolver;

// ParsingConfig to allow access to commonly used .NET methods like object.Equals
private static readonly ParsingConfig ParsingConfig = new ParsingConfig
{
AllowNewToEvaluateAnyType = true,
AreContextKeywordsEnabled = true
};

// Transform expressions to be compatible with System.Linq.Dynamic.Core 1.6.0+
private static string TransformExpression(string expression)
{
if (string.IsNullOrEmpty(expression))
return expression;

// Transform object.Equals(a, b) to Convert.ToBoolean(a) == Convert.ToBoolean(b)
// This is a simple regex replacement for the common pattern
var objectEqualsPattern = @"object\.Equals\s*\(\s*([^,]+)\s*,\s*([^)]+)\s*\)";
var transformed = Regex.Replace(expression, objectEqualsPattern,
match =>
{
var arg1 = match.Groups[1].Value.Trim();
var arg2 = match.Groups[2].Value.Trim();

// If arg2 is a boolean literal, convert arg1 to boolean and compare
if (arg2 == "true" || arg2 == "false")
{
return $"Convert.ToBoolean({arg1}) == {arg2}";
}
// Otherwise, convert both to strings for comparison
return $"Convert.ToString({arg1}) == Convert.ToString({arg2})";
});

return transformed;
}

public DefinitionLoader(IWorkflowRegistry registry, ITypeResolver typeResolver)
{
Expand Down Expand Up @@ -94,7 +129,7 @@ private WorkflowStepCollection ConvertSteps(ICollection<StepSourceV1> source, Ty
{
var cancelExprType = typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(dataType, typeof(bool)));
var dataParameter = Expression.Parameter(dataType, "data");
var cancelExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter }, typeof(bool), nextStep.CancelCondition);
var cancelExpr = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { dataParameter }, typeof(bool), TransformExpression(nextStep.CancelCondition));
targetStep.CancelCondition = cancelExpr;
}

Expand Down Expand Up @@ -217,7 +252,7 @@ private void AttachOutputs(StepSourceV1 source, Type dataType, Type stepType, Wo
foreach (var output in source.Outputs)
{
var stepParameter = Expression.Parameter(stepType, "step");
var sourceExpr = DynamicExpressionParser.ParseLambda(new[] { stepParameter }, typeof(object), output.Value);
var sourceExpr = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { stepParameter }, typeof(object), TransformExpression(output.Value));

var dataParameter = Expression.Parameter(dataType, "data");

Expand Down Expand Up @@ -344,7 +379,7 @@ private void AttachOutcomes(StepSourceV1 source, Type dataType, WorkflowStep ste

foreach (var nextStep in source.SelectNextStep)
{
var sourceDelegate = DynamicExpressionParser.ParseLambda(new[] { dataParameter, outcomeParameter }, typeof(object), nextStep.Value).Compile();
var sourceDelegate = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { dataParameter, outcomeParameter }, typeof(object), TransformExpression(nextStep.Value)).Compile();
Expression<Func<object, object, bool>> sourceExpr = (data, outcome) => System.Convert.ToBoolean(sourceDelegate.DynamicInvoke(data, outcome));
step.Outcomes.Add(new ExpressionOutcome<object>(sourceExpr)
{
Expand All @@ -361,7 +396,7 @@ private Type FindType(string name)
private static Action<IStepBody, object, IStepExecutionContext> BuildScalarInputAction(KeyValuePair<string, object> input, ParameterExpression dataParameter, ParameterExpression contextParameter, ParameterExpression environmentVarsParameter, PropertyInfo stepProperty)
{
var expr = System.Convert.ToString(input.Value);
var sourceExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), expr);
var sourceExpr = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), TransformExpression(expr));

void acn(IStepBody pStep, object pData, IStepExecutionContext pContext)
{
Expand Down Expand Up @@ -394,7 +429,7 @@ void acn(IStepBody pStep, object pData, IStepExecutionContext pContext)
{
if (prop.Name.StartsWith("@"))
{
var sourceExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), prop.Value.ToString());
var sourceExpr = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), TransformExpression(prop.Value.ToString()));
object resolvedValue = sourceExpr.Compile().DynamicInvoke(pData, pContext, Environment.GetEnvironmentVariables());
subobj.Remove(prop.Name);
subobj.Add(prop.Name.TrimStart('@'), JToken.FromObject(resolvedValue));
Expand Down
2 changes: 1 addition & 1 deletion src/WorkflowCore.DSL/WorkflowCore.DSL.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="SharpYaml" Version="1.6.5" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading