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/Helpers/StringObjectDictionaryConverter.cs b/src/modules/Elsa.JavaScript/Helpers/StringObjectDictionaryConverter.cs
deleted file mode 100644
index 41b8f593a..000000000
--- a/src/modules/Elsa.JavaScript/Helpers/StringObjectDictionaryConverter.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System.Collections;
-
-namespace Elsa.JavaScript.Helpers;
-
-///
-/// Contains methods for converting dictionaries with string keys and object values by replacing IList fields with Array fields.
-///
-public static class StringObjectDictionaryConverter
-{
- ///
- /// Recursively converts all IList fields of an ExpandoObject to Array fields.
- /// This allows JS expressions to properly use Array methods on lists, such as .length, filter, etc.
- ///
- public static object? ConvertListsToArray(object? value)
- {
- if (value is not IDictionary dictionary)
- return value;
-
- // Copy the dictionary to avoid modifying the original.
- dictionary = new Dictionary(dictionary);
- var keys = dictionary.Keys.ToList();
- foreach (var key in keys)
- {
- if (dictionary[key] is IList && dictionary[key].GetType().IsGenericType)
- {
- var list = (IList)dictionary[key];
- var elementType = dictionary[key].GetType().GetGenericArguments()[0];
- var array = Array.CreateInstance(elementType, list.Count);
- list.CopyTo(array, 0);
- dictionary[key] = array;
- }
- else
- {
- ConvertListsToArray(dictionary[key]);
- }
- }
-
- return dictionary;
- }
-}
\ 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 127043d00..c7d733d65 100644
--- a/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs
+++ b/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs
@@ -11,6 +11,7 @@ using Elsa.JavaScript.Options;
using Elsa.Mediator.Contracts;
using Humanizer;
using Jint;
+using Jint.Runtime.Interop;
using Microsoft.Extensions.Options;
// ReSharper disable ConvertClosureToMethodGroup
@@ -56,6 +57,17 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
{
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);
@@ -122,7 +134,7 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
var inputs = context.GetWorkflowInputs();
foreach (var input in inputs)
- engine.SetValue($"get{input.Name}", (Func