Implement Enum to String Conversion for JavaScript Engine

Add a new `EnumToStringConverter` to convert enums to strings within the JavaScript engine, enhancing object conversion capabilities. Update `DefaultActivityExecutionMapper` with logging functionality for error handling. Modify constructors and improve code styling across multiple files.
This commit is contained in:
Sipke Schoorstra 2024-11-28 19:23:13 +01:00
parent 08632471e3
commit 341eeb471f
5 changed files with 53 additions and 29 deletions

View file

@ -3,31 +3,20 @@ namespace Elsa.Api.Client.Resources.Scripting.Requests;
/// <summary>
/// A request to retrieve the type definitions
/// </summary>
public class GetWorkflowJavaScriptDefinitionRequest
public class GetWorkflowJavaScriptDefinitionRequest(string workflowDefinitionId, string? activityTypeName, string? propertyName)
{
/// <summary>
/// Initialize new type definition request.
/// </summary>
/// <param name="workflowDefinitionId">Id of workflow definition to retrieve type definitions for.</param>
/// <param name="activityTypeName">Type name of the activity to retrieve type definitions for.</param>
/// <param name="propertyName">Name of the property to retrieve type definitions for.</param>
public GetWorkflowJavaScriptDefinitionRequest(string workflowDefinitionId, string activityTypeName, string propertyName)
{
WorkflowDefinitionId = workflowDefinitionId;
ActivityTypeName = activityTypeName;
PropertyName = propertyName;
}
/// <summary>
/// Gets or sets workflow definition to retrieve type definitions for.
/// </summary>
public string WorkflowDefinitionId { get; set; }
public string WorkflowDefinitionId { get; set; } = workflowDefinitionId;
/// <summary>
/// Gets or sets type name of the activity to retrieve type definitions for.
/// Gets or sets the type name of the activity to retrieve type definitions for.
/// </summary>
public string ActivityTypeName { get; set; }
public string? ActivityTypeName { get; set; } = activityTypeName;
/// <summary>
/// Gets or sets name of the property to retrieve type definitions for.
/// Gets or sets the name of the property to retrieve type definitions for.
/// </summary>
public string PropertyName { get; set; }
public string? PropertyName { get; set; } = propertyName;
}

View file

@ -10,7 +10,7 @@ namespace Elsa.JavaScript.Activities;
/// Produces <see cref="FunctionDefinition"/>s for common functions.
/// </summary>
[UsedImplicitly]
internal class RunJavaScriptFunctionsDefinitionProvider() : FunctionDefinitionProvider
internal class RunJavaScriptFunctionsDefinitionProvider : FunctionDefinitionProvider
{
protected override IEnumerable<FunctionDefinition> GetFunctionDefinitions(TypeDefinitionContext context)
{

View file

@ -0,0 +1,21 @@
using System.Diagnostics.CodeAnalysis;
using Jint;
using Jint.Native;
using Jint.Runtime.Interop;
namespace Elsa.JavaScript.ObjectConverters;
internal class EnumToStringConverter : IObjectConverter
{
public bool TryConvert(Engine engine, object value, [NotNullWhen(true)] out JsValue? result)
{
if (value is Enum)
{
result = value.ToString();
return true;
}
result = JsValue.Null;
return false;
}
}

View file

@ -50,7 +50,7 @@ public class JintJavaScriptEvaluator(IConfiguration configuration, INotification
var engineOptions = new Jint.Options
{
ExperimentalFeatures = ExperimentalFeature.TaskInterop
ExperimentalFeatures = ExperimentalFeature.TaskInterop,
};
ConfigureClrAccess(engineOptions);
@ -59,14 +59,14 @@ public class JintJavaScriptEvaluator(IConfiguration configuration, INotification
await mediator.SendAsync(new CreatingJavaScriptEngine(engineOptions, context), cancellationToken);
_jintOptions.ConfigureEngineOptionsCallback(engineOptions, context);
var engine = new Engine(engineOptions);
configureEngine?.Invoke(engine);
ConfigureArgumentGetters(engine, options);
ConfigureConfigurationAccess(engine);
_jintOptions.ConfigureEngineCallback(engine, context);
return engine;
}
@ -75,7 +75,7 @@ public class JintJavaScriptEvaluator(IConfiguration configuration, INotification
if (_jintOptions.AllowClrAccess)
options.AllowClr();
}
private void ConfigureObjectWrapper(Jint.Options options)
{
options.SetWrapObjectHandler((engine, target, type) =>
@ -91,7 +91,7 @@ public class JintJavaScriptEvaluator(IConfiguration configuration, INotification
private void ConfigureObjectConverters(Jint.Options options)
{
options.Interop.ObjectConverters.Add(new ByteArrayConverter());
options.Interop.ObjectConverters.AddRange([new ByteArrayConverter(), new EnumToStringConverter()]);
}
private void ConfigureArgumentGetters(Engine engine, ExpressionEvaluatorOptions options)
@ -99,7 +99,7 @@ public class JintJavaScriptEvaluator(IConfiguration configuration, INotification
foreach (var argument in options.Arguments)
engine.SetValue($"get{argument.Key}", (Func<object?>)(() => argument.Value));
}
private void ConfigureConfigurationAccess(Engine engine)
{
if (_jintOptions.AllowConfigurationAccess)

View file

@ -12,6 +12,7 @@ using Elsa.Workflows.Runtime.Entities;
using Elsa.Workflows.Serialization.Converters;
using Elsa.Workflows.State;
using Humanizer;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Elsa.Workflows.Runtime;
@ -22,16 +23,19 @@ public class DefaultActivityExecutionMapper : IActivityExecutionMapper
private readonly JsonSerializerOptions _logPersistenceConfigSerializerOptions;
private readonly IOptions<ManagementOptions> _options;
private readonly IExpressionEvaluator _expressionEvaluator;
private readonly ILogger<DefaultActivityExecutionMapper> _logger;
private readonly IDictionary<string, ILogPersistenceStrategy> _logPersistenceStrategies;
public DefaultActivityExecutionMapper(
IOptions<ManagementOptions> options,
ILogPersistenceStrategyService logPersistenceStrategyService,
IExpressionEvaluator expressionEvaluator,
IExpressionDescriptorRegistry expressionDescriptorRegistry)
IExpressionDescriptorRegistry expressionDescriptorRegistry,
ILogger<DefaultActivityExecutionMapper> logger)
{
_options = options;
_expressionEvaluator = expressionEvaluator;
_logger = logger;
_logPersistenceStrategies = logPersistenceStrategyService.ListStrategies().ToDictionary(x => x.GetType().GetSimpleAssemblyQualifiedName(), x => x);
_logPersistenceConfigSerializerOptions = new JsonSerializerOptions
@ -71,7 +75,8 @@ public class DefaultActivityExecutionMapper : IActivityExecutionMapper
var cancellationToken = source.WorkflowExecutionContext.CancellationToken;
var workflow = (Workflow?)source.GetAncestors().FirstOrDefault(x => x.Activity is Workflow)?.Activity ?? source.WorkflowExecutionContext.Workflow;
var workflowPersistenceProperty = await GetDefaultPersistenceModeAsync(source.WorkflowExecutionContext.ExpressionExecutionContext!, workflow.CustomProperties, () => _options.Value.LogPersistenceMode, cancellationToken);
var rootActivityExecutionContext = source.WorkflowExecutionContext.ActivityExecutionContexts.First(x => x.ParentActivityExecutionContext == null);
var workflowPersistenceProperty = await GetDefaultPersistenceModeAsync(rootActivityExecutionContext.ExpressionExecutionContext, workflow.CustomProperties, () => _options.Value.LogPersistenceMode, cancellationToken);
var activityPersistencePropertyDefault = await GetDefaultPersistenceModeAsync(source.ExpressionExecutionContext, source.Activity.CustomProperties, () => workflowPersistenceProperty, cancellationToken);
var legacyActivityPersistenceProperties = source.Activity.CustomProperties.GetValueOrDefault<IDictionary<string, object?>>(LegacyLogPersistenceModeKey, () => new Dictionary<string, object?>());
var activityPersistenceProperties = source.Activity.CustomProperties.GetValueOrDefault<IDictionary<string, object?>>(LogPersistenceConfigKey, () => new Dictionary<string, object?>());
@ -202,7 +207,16 @@ public class DefaultActivityExecutionMapper : IActivityExecutionMapper
return defaultMode();
var expression = config.Expression;
return await _expressionEvaluator.EvaluateAsync<LogPersistenceMode>(expression, executionContext);
try
{
return await _expressionEvaluator.EvaluateAsync<LogPersistenceMode>(expression, executionContext);
}
catch (Exception e)
{
_logger.LogWarning(e, "Error evaluating log persistence expression");
return defaultMode();
}
}
private static ActivityStatus GetAggregateStatus(ActivityExecutionContext context)