From a1c30facbae44590ebd8d5662e052109950d535c Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 31 Jan 2024 21:10:13 +0100 Subject: [PATCH] Add ObjectArrayHelper and update array detection method A new ObjectArrayHelper class has been added into the Elsa.JavaScript module to improve array detection. The previous IsArrayLike method used in JintJavaScriptEvaluator and integration tests has been replaced by the DetermineIfObjectIsArrayLikeClrCollection method from this helper. These changes also provoked an update of the Jint package version from 3.0.0-beta-2057 to 3.0.0. --- .../Elsa.JavaScript/Elsa.JavaScript.csproj | 2 +- .../Helpers/ObjectArrayHelper.cs | 39 +++++++++++++++++++ .../Services/JintJavaScriptEvaluator.cs | 8 ++-- .../Scenarios/JavaScriptListAndArray/Tests.cs | 8 ++-- 4 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 src/modules/Elsa.JavaScript/Helpers/ObjectArrayHelper.cs diff --git a/src/modules/Elsa.JavaScript/Elsa.JavaScript.csproj b/src/modules/Elsa.JavaScript/Elsa.JavaScript.csproj index fcc2b11b8..26dc246fa 100644 --- a/src/modules/Elsa.JavaScript/Elsa.JavaScript.csproj +++ b/src/modules/Elsa.JavaScript/Elsa.JavaScript.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/modules/Elsa.JavaScript/Helpers/ObjectArrayHelper.cs b/src/modules/Elsa.JavaScript/Helpers/ObjectArrayHelper.cs new file mode 100644 index 000000000..059a7b49e --- /dev/null +++ b/src/modules/Elsa.JavaScript/Helpers/ObjectArrayHelper.cs @@ -0,0 +1,39 @@ +using System.Collections; + +namespace Elsa.JavaScript.Helpers; + +/// +/// Contains helper methods for working with object arrays. +/// +public static class ObjectArrayHelper +{ + /// + /// Determines if the specified object is an array-like CLR collection. + /// + 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; + } +} \ No newline at end of file diff --git a/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs b/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs index fbae349f6..c7d733d65 100644 --- a/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs +++ b/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs @@ -5,6 +5,7 @@ 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; @@ -61,10 +62,9 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator opts.SetWrapObjectHandler((engine, target, type) => { var instance = new ObjectWrapper(engine, target); - if (instance.IsArrayLike) - { - instance.SetPrototypeOf(engine.Realm.Intrinsics.Array.PrototypeObject); - } + + if (ObjectArrayHelper.DetermineIfObjectIsArrayLikeClrCollection(target.GetType())) + instance.Prototype = engine.Intrinsics.Array.PrototypeObject; return instance; }); diff --git a/test/integration/Elsa.IntegrationTests/Scenarios/JavaScriptListAndArray/Tests.cs b/test/integration/Elsa.IntegrationTests/Scenarios/JavaScriptListAndArray/Tests.cs index 12e9ba714..d1ef1c657 100644 --- a/test/integration/Elsa.IntegrationTests/Scenarios/JavaScriptListAndArray/Tests.cs +++ b/test/integration/Elsa.IntegrationTests/Scenarios/JavaScriptListAndArray/Tests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Dynamic; +using Elsa.JavaScript.Helpers; using Jint; using Jint.Runtime.Interop; using Xunit; @@ -19,10 +20,9 @@ public class Tests .SetWrapObjectHandler((engine, target, type) => { var instance = new ObjectWrapper(engine, target); - if (instance.IsArrayLike) - { - instance.SetPrototypeOf(engine.Realm.Intrinsics.Array.PrototypeObject); - } + + if (ObjectArrayHelper.DetermineIfObjectIsArrayLikeClrCollection(target.GetType())) + instance.Prototype = engine.Intrinsics.Array.PrototypeObject; return instance; })