2022-12-31 15:16:43 +00:00
|
|
|
|
using Elsa.Expressions.Models;
|
|
|
|
|
|
using Elsa.Extensions;
|
2022-05-26 10:47:31 +00:00
|
|
|
|
using Elsa.JavaScript.Notifications;
|
|
|
|
|
|
using Elsa.JavaScript.Options;
|
|
|
|
|
|
using Elsa.JavaScript.Services;
|
|
|
|
|
|
using Elsa.Mediator.Services;
|
2022-12-15 21:53:56 +00:00
|
|
|
|
using Humanizer;
|
2022-01-12 10:43:46 +00:00
|
|
|
|
using Jint;
|
|
|
|
|
|
using Microsoft.Extensions.Options;
|
|
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
namespace Elsa.JavaScript.Implementations;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Provides a JavaScript evaluator using Jint.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
2022-01-12 10:43:46 +00:00
|
|
|
|
{
|
2023-01-04 19:36:38 +00:00
|
|
|
|
private readonly IEventPublisher _mediator;
|
|
|
|
|
|
private readonly JintOptions _jintOptions;
|
|
|
|
|
|
|
2022-11-30 20:52:41 +00:00
|
|
|
|
/// <summary>
|
2023-01-04 19:36:38 +00:00
|
|
|
|
/// Constructor.
|
2022-11-30 20:52:41 +00:00
|
|
|
|
/// </summary>
|
2023-01-04 19:36:38 +00:00
|
|
|
|
public JintJavaScriptEvaluator(IEventPublisher mediator, IOptions<JintOptions> scriptOptions)
|
2022-01-12 10:43:46 +00:00
|
|
|
|
{
|
2023-01-04 19:36:38 +00:00
|
|
|
|
_mediator = mediator;
|
|
|
|
|
|
_jintOptions = scriptOptions.Value;
|
|
|
|
|
|
}
|
2022-01-12 10:43:46 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public async Task<object?> EvaluateAsync(string expression,
|
|
|
|
|
|
Type returnType,
|
|
|
|
|
|
ExpressionExecutionContext context,
|
|
|
|
|
|
Action<Engine>? configureEngine = default,
|
|
|
|
|
|
CancellationToken cancellationToken = default)
|
|
|
|
|
|
{
|
|
|
|
|
|
var engine = await GetConfiguredEngine(configureEngine, context, cancellationToken);
|
|
|
|
|
|
var result = ExecuteExpressionAndGetResult(engine, expression);
|
2022-01-12 10:43:46 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2022-01-12 10:43:46 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
private async Task<Engine> GetConfiguredEngine(Action<Engine>? configureEngine, ExpressionExecutionContext context, CancellationToken cancellationToken)
|
|
|
|
|
|
{
|
|
|
|
|
|
var engine = new Engine(opts =>
|
2022-01-12 10:43:46 +00:00
|
|
|
|
{
|
2023-01-04 19:36:38 +00:00
|
|
|
|
if (_jintOptions.AllowClrAccess)
|
|
|
|
|
|
opts.AllowClr();
|
|
|
|
|
|
});
|
2022-01-12 10:43:46 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
configureEngine?.Invoke(engine);
|
2022-03-28 11:25:45 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
// Add common functions.
|
|
|
|
|
|
engine.SetValue("setVariable", (Action<string, object>)((name, value) => context.SetVariable(name, value)));
|
2022-04-27 17:48:17 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
// ReSharper disable once ConvertClosureToMethodGroup (Jint does not understand method groups).
|
|
|
|
|
|
engine.SetValue("getVariable", (Func<string, object?>)(name => context.GetVariable(name)));
|
2022-11-30 20:52:41 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
// Create variable setters and getters for each variable.
|
|
|
|
|
|
CreateVariableAccessors(engine, context);
|
2023-01-06 19:00:03 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
engine.SetValue("isNullOrWhiteSpace", (Func<string, bool>)string.IsNullOrWhiteSpace);
|
|
|
|
|
|
engine.SetValue("isNullOrEmpty", (Func<string, bool>)string.IsNullOrEmpty);
|
2022-01-12 10:43:46 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
// Add common .NET types.
|
|
|
|
|
|
engine.RegisterType<DateTime>();
|
|
|
|
|
|
engine.RegisterType<DateTimeOffset>();
|
|
|
|
|
|
engine.RegisterType<TimeSpan>();
|
2022-01-12 10:43:46 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
// Allow listeners invoked by the mediator to configure the engine.
|
|
|
|
|
|
await _mediator.PublishAsync(new EvaluatingJavaScript(engine, context), cancellationToken);
|
2022-01-12 10:43:46 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
return engine;
|
|
|
|
|
|
}
|
2022-12-15 21:53:56 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
private static void CreateVariableAccessors(Engine engine, ExpressionExecutionContext context)
|
|
|
|
|
|
{
|
|
|
|
|
|
var variablesDictionary = context.GetVariableValues();
|
2022-12-15 21:53:56 +00:00
|
|
|
|
|
2023-01-04 19:36:38 +00:00
|
|
|
|
foreach (var variable in variablesDictionary)
|
2022-01-12 10:43:46 +00:00
|
|
|
|
{
|
2023-01-04 19:36:38 +00:00
|
|
|
|
var pascalName = variable.Key.Pascalize();
|
|
|
|
|
|
engine.SetValue($"get{pascalName}", (Func<object?>)(() => context.GetVariable(variable.Key)));
|
|
|
|
|
|
engine.SetValue($"set{pascalName}", (Action<object?>)(value => context.SetVariable(variable.Key, value)));
|
2022-01-12 10:43:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-01-04 19:36:38 +00:00
|
|
|
|
|
|
|
|
|
|
private static object? ExecuteExpressionAndGetResult(Engine engine, string expression)
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = engine.Evaluate(expression);
|
|
|
|
|
|
return result.ToObject();
|
|
|
|
|
|
}
|
2022-01-12 10:43:46 +00:00
|
|
|
|
}
|