Merge branch 'v3.0.5'
This commit is contained in:
commit
5436d954d0
|
|
@ -26,8 +26,8 @@ const bool useDapper = false;
|
|||
const bool useProtoActor = false;
|
||||
const bool useHangfire = false;
|
||||
const bool useQuartz = true;
|
||||
const bool useMassTransit = true;
|
||||
const bool useMassTransitAzureServiceBus = false;
|
||||
const bool useMassTransit = false;
|
||||
const bool useMassTransitAzureServiceBus = true;
|
||||
const bool useMassTransitRabbitMq = false;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
|
@ -133,7 +133,10 @@ services
|
|||
});
|
||||
}
|
||||
|
||||
runtime.UseMassTransitDispatcher();
|
||||
if(useMassTransit)
|
||||
{
|
||||
runtime.UseMassTransitDispatcher();
|
||||
}
|
||||
runtime.WorkflowInboxCleanupOptions = options => configuration.GetSection("Runtime:WorkflowInboxCleanup").Bind(options);
|
||||
})
|
||||
.UseEnvironments(environments => environments.EnvironmentsOptions = options => configuration.GetSection("Environments").Bind(options))
|
||||
|
|
@ -186,7 +189,11 @@ services
|
|||
ef.UseSqlite(sqliteConnectionString);
|
||||
});
|
||||
|
||||
alterations.UseMassTransitDispatcher();
|
||||
if (useMassTransit)
|
||||
{
|
||||
alterations.UseMassTransitDispatcher();
|
||||
}
|
||||
|
||||
})
|
||||
.UseWorkflowContexts();
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public interface IJavaScriptEvaluator
|
|||
string expression,
|
||||
Type returnType,
|
||||
ExpressionExecutionContext context,
|
||||
ExpressionEvaluatorOptions options,
|
||||
ExpressionEvaluatorOptions? options = default,
|
||||
Action<Engine>? configureEngine = default,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageReference Include="Jint" Version="3.0.0-beta-2057" />
|
||||
<PackageReference Include="Jint" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
39
src/modules/Elsa.JavaScript/Helpers/ObjectArrayHelper.cs
Normal file
39
src/modules/Elsa.JavaScript/Helpers/ObjectArrayHelper.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
using System.Collections;
|
||||
|
||||
namespace Elsa.JavaScript.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Contains helper methods for working with object arrays.
|
||||
/// </summary>
|
||||
public static class ObjectArrayHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if the specified object is an array-like CLR collection.
|
||||
/// </summary>
|
||||
public static bool DetermineIfObjectIsArrayLikeClrCollection(Type type)
|
||||
{
|
||||
var isDictionary = typeof(IDictionary).IsAssignableFrom(type);
|
||||
|
||||
if (isDictionary)
|
||||
return false;
|
||||
|
||||
if (typeof(ICollection).IsAssignableFrom(type))
|
||||
return true;
|
||||
|
||||
foreach (var interfaceType in type.GetInterfaces())
|
||||
{
|
||||
if (!interfaceType.IsGenericType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interfaceType.GetGenericTypeDefinition() == typeof(IReadOnlyCollection<>)
|
||||
|| interfaceType.GetGenericTypeDefinition() == typeof(ICollection<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,11 +5,13 @@ using Elsa.Expressions.Helpers;
|
|||
using Elsa.Expressions.Models;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.JavaScript.Contracts;
|
||||
using Elsa.JavaScript.Helpers;
|
||||
using Elsa.JavaScript.Notifications;
|
||||
using Elsa.JavaScript.Options;
|
||||
using Elsa.Mediator.Contracts;
|
||||
using Humanizer;
|
||||
using Jint;
|
||||
using Jint.Runtime.Interop;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
// ReSharper disable ConvertClosureToMethodGroup
|
||||
|
|
@ -37,7 +39,7 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
public async Task<object?> EvaluateAsync(string expression,
|
||||
Type returnType,
|
||||
ExpressionExecutionContext context,
|
||||
ExpressionEvaluatorOptions options,
|
||||
ExpressionEvaluatorOptions? options = default,
|
||||
Action<Engine>? configureEngine = default,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
|
@ -47,12 +49,25 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
return result.ConvertTo(returnType);
|
||||
}
|
||||
|
||||
private async Task<Engine> GetConfiguredEngine(Action<Engine>? configureEngine, ExpressionExecutionContext context, ExpressionEvaluatorOptions options, CancellationToken cancellationToken)
|
||||
private async Task<Engine> GetConfiguredEngine(Action<Engine>? configureEngine, ExpressionExecutionContext context, ExpressionEvaluatorOptions? options, CancellationToken cancellationToken)
|
||||
{
|
||||
options ??= new ExpressionEvaluatorOptions();
|
||||
|
||||
var engine = new Engine(opts =>
|
||||
{
|
||||
if (_jintOptions.AllowClrAccess)
|
||||
opts.AllowClr();
|
||||
|
||||
// Wrap objects in ObjectWrapper instances and set their prototype to Array.prototype if they are array-like.
|
||||
opts.SetWrapObjectHandler((engine, target, type) =>
|
||||
{
|
||||
var instance = new ObjectWrapper(engine, target);
|
||||
|
||||
if (ObjectArrayHelper.DetermineIfObjectIsArrayLikeClrCollection(target.GetType()))
|
||||
instance.Prototype = engine.Intrinsics.Array.PrototypeObject;
|
||||
|
||||
return instance;
|
||||
});
|
||||
});
|
||||
|
||||
configureEngine?.Invoke(engine);
|
||||
|
|
@ -76,11 +91,11 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
|
||||
// Create output getters for each activity.
|
||||
CreateActivityOutputAccessors(engine, context);
|
||||
|
||||
|
||||
// Create argument getters for each argument.
|
||||
foreach (var argument in options.Arguments)
|
||||
engine.SetValue($"get{argument.Key}", (Func<object?>)(() => argument.Value));
|
||||
|
||||
|
||||
// Add common functions.
|
||||
engine.SetValue("isNullOrWhiteSpace", (Func<string, bool>)(value => string.IsNullOrWhiteSpace(value)));
|
||||
engine.SetValue("isNullOrEmpty", (Func<string, bool>)(value => string.IsNullOrEmpty(value)));
|
||||
|
|
|
|||
|
|
@ -292,10 +292,10 @@ public static class ExpressionExecutionContextExtensions
|
|||
select v;
|
||||
|
||||
var variable = q.FirstOrDefault();
|
||||
|
||||
if(variable != null)
|
||||
|
||||
if (variable != null)
|
||||
variable.Set(context, value);
|
||||
|
||||
|
||||
if (variable == null)
|
||||
CreateVariable(context, variableName, value);
|
||||
}
|
||||
|
|
@ -362,7 +362,7 @@ public static class ExpressionExecutionContextExtensions
|
|||
var input = workflowExecutionContext.Input;
|
||||
return input.TryGetValue(name, out var value) ? value : default;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the specified input.
|
||||
/// </summary>
|
||||
|
|
@ -393,7 +393,9 @@ public static class ExpressionExecutionContextExtensions
|
|||
/// </summary>
|
||||
public static IEnumerable<ActivityOutputs> GetActivityOutputs(this ExpressionExecutionContext context)
|
||||
{
|
||||
var activityExecutionContext = context.GetActivityExecutionContext();
|
||||
if (!context.TryGetActivityExecutionContext(out var activityExecutionContext))
|
||||
yield break;
|
||||
|
||||
var useActivityName = activityExecutionContext.WorkflowExecutionContext.Workflow.CreatedWithModernTooling();
|
||||
var activitiesWithOutputs = activityExecutionContext.GetActivitiesWithOutputs();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Expressions.Models;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.JavaScript.Contracts;
|
||||
using Elsa.Testing.Shared;
|
||||
using Jint;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Elsa.IntegrationTests.Scenarios.JavaScriptListsAndArrays;
|
||||
|
||||
public class Tests
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly IJavaScriptEvaluator _evaluator;
|
||||
private readonly ExpressionExecutionContext _expressionContext;
|
||||
|
||||
public Tests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
var testOutputHelper1 = testOutputHelper ?? throw new ArgumentNullException(nameof(testOutputHelper));
|
||||
_services = new TestApplicationBuilder(testOutputHelper1).Build();
|
||||
_evaluator = _services.GetRequiredService<IJavaScriptEvaluator>();
|
||||
_expressionContext = new ExpressionExecutionContext(_services, new MemoryRegister());
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Workflow inputs containing .NET lists on dynamic objects are converted to arrays for use in JavaScript.")]
|
||||
public async Task Test1()
|
||||
{
|
||||
dynamic dynamicObject = new ExpandoObject();
|
||||
|
||||
dynamicObject.List = new List<string> { "a", "b", "c" };
|
||||
var script = "getObj().List.filter(x => x === 'b').length === 1";
|
||||
_expressionContext.SetVariable("obj", (object)dynamicObject);
|
||||
var result = await _evaluator.EvaluateAsync(script, typeof(bool), _expressionContext);
|
||||
|
||||
Assert.True((bool)result!);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Can access list properties as arrays")]
|
||||
public async Task Test2()
|
||||
{
|
||||
var person = new ExpandoObject();
|
||||
var magicNumbers = new[]{42, 43, 44};
|
||||
var order1 = new ExpandoObject();
|
||||
|
||||
order1.TryAdd("magicNumbers", magicNumbers);
|
||||
person.TryAdd("orders", new []{ order1 });
|
||||
person.TryAdd("name", "John");
|
||||
person.TryAdd("age", 12);
|
||||
|
||||
var languages = new List<object>
|
||||
{
|
||||
"English",
|
||||
"French"
|
||||
};
|
||||
|
||||
person.TryAdd("languages", languages);
|
||||
|
||||
var obj = new ExpandoObject();
|
||||
obj.TryAdd("persons", new List<object> { person });
|
||||
|
||||
var name = await _evaluator.EvaluateAsync("o.persons.filter(x => x.age == 12)[0].name", typeof(string), _expressionContext, configureEngine: engine => engine.SetValue("o", obj));
|
||||
var language = await _evaluator.EvaluateAsync("o.persons[0].languages.filter(x => x == 'English')[0]", typeof(string), _expressionContext, configureEngine: engine => engine.SetValue("o", obj));
|
||||
var magicNumber = await _evaluator.EvaluateAsync("o.persons[0].orders[0].magicNumbers[1]", typeof(int), _expressionContext, configureEngine: engine => engine.SetValue("o", obj));
|
||||
Assert.Equal("John", name);
|
||||
Assert.Equal("English", language);
|
||||
Assert.Equal(43, magicNumber);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue