Browse Source

Add support for wrapped lists to push and pop items (#1822)

Eric J. Smith 1 year ago
parent
commit
3209ab31d6

+ 42 - 0
Jint.Tests/Runtime/InteropTests.cs

@@ -2913,6 +2913,48 @@ namespace Jint.Tests.Runtime
             Assert.Equal(1, engine.Evaluate("Array.prototype.lastIndexOf.call(list, 'B')"));
         }
 
+        [Fact]
+        public void ArrayPrototypeFindWithInteropList()
+        {
+            var engine = new Jint.Engine();
+            var list = new List<string> { "A", "B", "C" };
+ 
+            engine.SetValue("list", list);
+
+            Assert.Equal(1, engine.Evaluate("list.findIndex((x) => x === 'B')"));
+            Assert.Equal('B', engine.Evaluate("list.find((x) => x === 'B')"));
+        }
+
+        [Fact]
+        public void ArrayPrototypePushWithInteropList()
+        {
+            var engine = new Jint.Engine();
+
+            var list = new List<string> { "A", "B", "C" };
+
+            engine.SetValue("list", list);
+
+            engine.Evaluate("list.push('D')");
+            Assert.Equal(4, list.Count);
+            Assert.Equal("D", list[3]);
+            Assert.Equal(3, engine.Evaluate("list.lastIndexOf('D')"));
+        }
+
+        [Fact]
+        public void ArrayPrototypePopWithInteropList()
+        {
+            var engine = new Jint.Engine();
+
+            var list = new List<string> { "A", "B", "C" };
+            engine.SetValue("list", list);
+
+            Assert.Equal(2, engine.Evaluate("list.lastIndexOf('C')"));
+            Assert.Equal(3, list.Count);
+            Assert.Equal("C", engine.Evaluate("list.pop()"));
+            Assert.Equal(2, list.Count);
+            Assert.Equal(-1, engine.Evaluate("list.lastIndexOf('C')"));
+        }
+
         [Fact]
         public void ShouldBeJavaScriptException()
         {

+ 27 - 2
Jint/Native/Array/ArrayOperations.cs

@@ -493,7 +493,25 @@ namespace Jint.Native.Array
 
             public override ulong GetLongLength() => GetLength();
 
-            public override void SetLength(ulong length) => throw new NotSupportedException();
+            public override void SetLength(ulong length)
+            {
+                if (_list == null)
+                {
+                    throw new NotSupportedException();
+                }
+                
+                while (_list.Count > (int) length)
+                {
+                    // shrink list to fit
+                    _list.RemoveAt(_list.Count - 1);
+                }
+                
+                while (_list.Count < (int) length)
+                {
+                    // expand list to fit
+                    _list.Add(null);
+                }
+            }
 
             public override void EnsureCapacity(ulong capacity)
             {
@@ -530,7 +548,14 @@ namespace Jint.Native.Array
                 => _target.CreateDataPropertyOrThrow(index, value);
 
             public override void Set(ulong index, JsValue value, bool updateLength = false, bool throwOnError = true)
-                => _target[(int) index] = value;
+            {
+                if (updateLength && _list != null && index >= (ulong) _list.Count)
+                {
+                    SetLength(index + 1);
+                }
+                
+                _target[(int) index] = value;
+            }
 
             public override void DeletePropertyOrThrow(ulong index)
                 => _target.DeletePropertyOrThrow(index);

+ 10 - 0
Jint/Runtime/Interop/ObjectWrapper.cs

@@ -160,6 +160,16 @@ namespace Jint.Runtime.Interop
             return base.HasProperty(property);
         }
 
+        public override bool Delete(JsValue property)
+        {
+            if (Target is IList && property.IsNumber())
+            {
+                return true;
+            }
+            
+            return base.Delete(property);
+        }
+
         public override JsValue Get(JsValue property, JsValue receiver)
         {
             if (property.IsInteger())