Move input accessors to Jint service to control order

This commit is contained in:
Sipke Schoorstra 2023-08-22 14:59:31 +02:00
parent 9416461f78
commit 46c9a76259
3 changed files with 32 additions and 83 deletions

View file

@ -1,70 +0,0 @@
using Elsa.Expressions.Contracts;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.JavaScript.Notifications;
using Elsa.Mediator.Contracts;
using Elsa.Workflows.Core.Contracts;
using Elsa.Workflows.Core.Memory;
using Humanizer;
using JetBrains.Annotations;
using Jint;
namespace Elsa.JavaScript.Handlers;
/// <summary>
/// Configures the JavaScript engine with workflow input getters.
/// </summary>
[PublicAPI]
public class WorkflowDefinitionActivityJavaScriptHandler : INotificationHandler<EvaluatingJavaScript>
{
private readonly IActivityRegistry _activityRegistry;
/// <summary>
/// Constructor.
/// </summary>
public WorkflowDefinitionActivityJavaScriptHandler(IActivityRegistry activityRegistry, IExpressionEvaluator expressionEvaluator)
{
_activityRegistry = activityRegistry;
}
/// <inheritdoc />
public Task HandleAsync(EvaluatingJavaScript notification, CancellationToken cancellationToken)
{
var engine = notification.Engine;
var context = notification.Context;
// Create workflow input accessors.
CreateWorkflowInputAccessors(engine, context);
return Task.CompletedTask;
}
private void CreateWorkflowInputAccessors(Engine engine, ExpressionExecutionContext context)
{
if(context.TryGetWorkflowExecutionContext(out var workflowExecutionContext))
{
var input = workflowExecutionContext.Input;
foreach (var inputEntry in input)
{
var inputPascalName = inputEntry.Key.Pascalize();
var inputValue = inputEntry.Value;
engine.SetValue($"get{inputPascalName}", (Func<object?>)(() => inputValue));
}
}
else
{
// We end up here when we are evaluating an expression during trigger indexing.
// Typically, a workflow definition might have variables declared, that we want to be able to access from JavaScript expressions.
foreach(var block in context.Memory.Blocks.Values)
{
if(block.Metadata is not VariableBlockMetadata variableBlockMetadata)
continue;
var variable = variableBlockMetadata.Variable;
var variablePascaleName = variable.Name.Pascalize();
engine.SetValue($"get{variablePascaleName}", (Func<object?>)(() => block.Value));
}
}
}
}

View file

@ -68,6 +68,9 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
engine.SetValue("getOutputFrom", (Func<string, string?, object?>)((activityIdOrNodeId, outputName) => GetOutput(context, activityIdOrNodeId, outputName)));
engine.SetValue("getLastResult", (Func<object?>)(() => GetLastResult(context)));
// Create workflow input accessors.
CreateWorkflowInputAccessors(engine, context);
// Create variable getters and setters for each variable.
CreateVariableAccessors(engine, context);
@ -117,6 +120,35 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
var outputRecord = filteredOutputRecordCandidates.FirstOrDefault();
return outputRecord?.Value;
}
private void CreateWorkflowInputAccessors(Engine engine, ExpressionExecutionContext context)
{
if(context.TryGetWorkflowExecutionContext(out var workflowExecutionContext))
{
var input = workflowExecutionContext.Input;
foreach (var inputEntry in input)
{
var inputPascalName = inputEntry.Key.Pascalize();
var inputValue = inputEntry.Value;
engine.SetValue($"get{inputPascalName}", (Func<object?>)(() => inputValue));
}
}
else
{
// We end up here when we are evaluating an expression during trigger indexing.
// The scenario being that a workflow definition might have variables declared, that we want to be able to access from JavaScript expressions.
foreach(var block in context.Memory.Blocks.Values)
{
if(block.Metadata is not VariableBlockMetadata variableBlockMetadata)
continue;
var variable = variableBlockMetadata.Variable;
var variablePascaleName = variable.Name.Pascalize();
engine.SetValue($"get{variablePascaleName}", (Func<object?>)(() => block.Value));
}
}
}
private static void CreateVariableAccessors(Engine engine, ExpressionExecutionContext context)
{

View file

@ -1,22 +1,9 @@
using Elsa.Expressions.Contracts;
using Elsa.JavaScript.Handlers;
using Elsa.Workflows.Core.Contracts;
using Moq;
using Xunit;
namespace Elsa.JavaScript.UnitTests;
public class WorkflowDefinitionActivityJavaScriptHandlerTests
{
private readonly WorkflowDefinitionActivityJavaScriptHandler _handler;
public WorkflowDefinitionActivityJavaScriptHandlerTests()
{
var activityRegistryMock = new Mock<IActivityRegistry>();
var expressionEvaluatorMock = new Mock<IExpressionEvaluator>();
_handler = new WorkflowDefinitionActivityJavaScriptHandler(activityRegistryMock.Object, expressionEvaluatorMock.Object);
}
[Fact]
public void Test1()
{