using System.Runtime.CompilerServices;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.JavaScript.Contracts;
using Elsa.Workflows;
using Elsa.Workflows.Attributes;
using Elsa.Workflows.Models;
using Elsa.Workflows.UIHints;
using Jint;
// ReSharper disable once CheckNamespace
namespace Elsa.JavaScript.Activities;
///
/// Executes JavaScript code.
///
[Activity("Elsa", "Scripting", "Executes JavaScript code", DisplayName = "Run JavaScript")]
public class RunJavaScript : CodeActivity
{
///
public RunJavaScript([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
{
}
///
public RunJavaScript(string script, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line)
{
Script = new Input(script);
}
///
/// The script to run.
///
[Input(
Description = "The script to run.",
UIHint = InputUIHints.CodeEditor,
UIHandler = typeof(RunJavaScriptOptionsProvider)
)]
public Input Script { get; set; } = new("");
///
/// A list of possible outcomes. Use "setOutcome()" to set the outcome. Use "setOutcomes" to set multiple outcomes.
///
[Input(Description = "A list of possible outcomes.", UIHint = InputUIHints.DynamicOutcomes)]
public Input> PossibleOutcomes { get; set; } = default!;
///
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
var script = context.Get(Script);
// If no script was specified, there's nothing to do.
if (string.IsNullOrWhiteSpace(script))
return;
// Get a JavaScript evaluator.
var javaScriptEvaluator = context.GetRequiredService();
// Run the script.
var result = await javaScriptEvaluator.EvaluateAsync(
script,
typeof(object),
context.ExpressionExecutionContext,
ExpressionEvaluatorOptions.Empty,
engine => ConfigureEngine(engine, context),
context.CancellationToken);
// Set the result as output, if any.
if (result is not null)
context.Set(Result, result);
// Get the outcome or outcomes set by the script, if any. If not set, use "Done".
var outcomes = context.TransientProperties.GetValueOrDefault("Outcomes", () => new[] { "Done" })!;
// Complete the activity with the outcome.
await context.CompleteActivityWithOutcomesAsync(outcomes);
}
private static void ConfigureEngine(Engine engine, ActivityExecutionContext context)
{
engine.SetValue("setOutcome", (Action)(value => context.TransientProperties["Outcomes"] = new[] { value }));
engine.SetValue("setOutcomes", (Action)(value => context.TransientProperties["Outcomes"] = value));
}
}