فهرست منبع

Make JsMap public (#1988)

* make JsSet and JsMap members new as they indicate a specific usage scenario
Marko Lahma 9 ماه پیش
والد
کامیت
1461bf14bc

+ 43 - 0
Jint.Tests.PublicInterface/MapTests.cs

@@ -0,0 +1,43 @@
+using FluentAssertions;
+using Jint.Native;
+
+namespace Jint.Tests.Runtime;
+
+public class MapTests
+{
+    [Fact]
+    public void ConConstructMap()
+    {
+        var engine = new Engine();
+
+        var map = engine.Intrinsics.Map.Construct();
+        map.Set(42, "the meaning of life");
+        map.Set("foo", "bar");
+        map.Size.Should().Be(2);
+
+        map.Has(42).Should().BeTrue();
+        map.Has("foo").Should().BeTrue();
+        map.Has(24).Should().BeFalse();
+
+        map.Get(42).Should().Be((JsString) "the meaning of life");
+        map.Get("foo").Should().Be((JsString) "bar");
+        map.Get(24).Should().Be(JsValue.Undefined);
+
+        engine.SetValue("m", map);
+        engine.Evaluate("m.size").Should().Be((JsNumber) 2);
+        engine.Evaluate("m.has(42)").Should().Be(JsBoolean.True);
+        engine.Evaluate("m.has('foo')").Should().Be(JsBoolean.True);
+        engine.Evaluate("m.has(24)").Should().Be(JsBoolean.False);
+
+        map.Should().Contain((JsNumber) 42, (JsString) "the meaning of life");
+        map.Remove(42).Should().BeTrue();
+        map.Has(42).Should().BeFalse();
+        engine.Evaluate("m.has(42)").Should().Be(JsBoolean.False);
+        engine.Evaluate("m.size").Should().Be((JsNumber) 1);
+
+        map.Clear();
+        map.Should().BeEmpty();
+        map.Size.Should().Be(0);
+        engine.Evaluate("m.size").Should().Be((JsNumber) 0);
+    }
+}

+ 1 - 1
Jint.Tests.PublicInterface/SetTests.cs

@@ -27,7 +27,7 @@ public class SetTests
         engine.Evaluate("s.has('foo')").Should().Be(JsBoolean.True);
         engine.Evaluate("s.has(24)").Should().Be(JsBoolean.False);
 
-        set.Remove(42).Should().BeTrue();
+        set.Delete(42).Should().BeTrue();
         set.Has(42).Should().BeFalse();
         engine.Evaluate("s.has(42)").Should().Be(JsBoolean.False);
         engine.Evaluate("s.size").Should().Be((JsNumber) 1);

+ 21 - 32
Jint/Native/JsMap.cs

@@ -1,3 +1,4 @@
+using System.Collections;
 using System.Diagnostics.CodeAnalysis;
 using Jint.Native.Object;
 using Jint.Runtime;
@@ -5,7 +6,7 @@ using Jint.Runtime.Descriptors;
 
 namespace Jint.Native;
 
-internal sealed class JsMap : ObjectInstance
+public sealed class JsMap : ObjectInstance, IEnumerable<KeyValuePair<JsValue, JsValue>>
 {
     private readonly Realm _realm;
     internal readonly OrderedDictionary<JsValue, JsValue> _map;
@@ -37,22 +38,25 @@ internal sealed class JsMap : ObjectInstance
         return base.TryGetProperty(property, out descriptor);
     }
 
-    internal void Clear()
-    {
-        _map.Clear();
-    }
+    public int Size => _map.Count;
 
-    internal bool Has(JsValue key)
-    {
-        return _map.ContainsKey(key);
-    }
+    public void Clear() => _map.Clear();
 
-    internal bool MapDelete(JsValue key)
+    public bool Has(JsValue key) => _map.ContainsKey(key);
+
+    public bool Remove(JsValue key) => _map.Remove(key);
+
+    public new JsValue Get(JsValue key)
     {
-        return _map.Remove(key);
+        if (!_map.TryGetValue(key, out var value))
+        {
+            return Undefined;
+        }
+
+        return value;
     }
 
-    internal void MapSet(JsValue key, JsValue value)
+    public new void Set(JsValue key, JsValue value)
     {
         if (key is JsNumber number && number.IsNegativeZero())
         {
@@ -76,28 +80,13 @@ internal sealed class JsMap : ObjectInstance
         _engine._jsValueArrayPool.ReturnArray(args);
     }
 
-    internal JsValue MapGet(JsValue key)
-    {
-        if (!_map.TryGetValue(key, out var value))
-        {
-            return Undefined;
-        }
+    internal ObjectInstance Iterator() => _realm.Intrinsics.MapIteratorPrototype.ConstructEntryIterator(this);
 
-        return value;
-    }
+    internal ObjectInstance Keys() => _realm.Intrinsics.MapIteratorPrototype.ConstructKeyIterator(this);
 
-    internal ObjectInstance Iterator()
-    {
-        return _realm.Intrinsics.MapIteratorPrototype.ConstructEntryIterator(this);
-    }
+    internal ObjectInstance Values() => _realm.Intrinsics.MapIteratorPrototype.ConstructValueIterator(this);
 
-    internal ObjectInstance Keys()
-    {
-        return _realm.Intrinsics.MapIteratorPrototype.ConstructKeyIterator(this);
-    }
+    public IEnumerator<KeyValuePair<JsValue, JsValue>> GetEnumerator() => _map.GetEnumerator();
 
-    internal ObjectInstance Values()
-    {
-        return _realm.Intrinsics.MapIteratorPrototype.ConstructValueIterator(this);
-    }
+    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 }

+ 1 - 1
Jint/Native/JsSet.cs

@@ -54,7 +54,7 @@ public sealed class JsSet : ObjectInstance, IEnumerable<JsValue>
 
     public bool Has(JsValue key) => _set.Contains(key);
 
-    public bool Remove(JsValue key) => _set.Remove(key);
+    public new bool Delete(JsValue key) => _set.Remove(key);
 
     internal void ForEach(ICallable callable, JsValue thisArg)
     {

+ 25 - 22
Jint/Native/Map/MapConstructor.cs

@@ -11,7 +11,7 @@ using Jint.Runtime.Interop;
 
 namespace Jint.Native.Map;
 
-internal sealed class MapConstructor : Constructor
+public sealed class MapConstructor : Constructor
 {
     private static readonly JsString _functionName = new("Map");
 
@@ -33,28 +33,34 @@ internal sealed class MapConstructor : Constructor
     protected override void Initialize()
     {
         const PropertyFlag PropertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
-        var properties = new PropertyDictionary(1, checkExistingKeys: false)
-        {
-            ["groupBy"] = new(new ClrFunction(Engine, "groupBy", GroupBy, 2, PropertyFlag.Configurable), PropertyFlags),
-        };
+        var properties = new PropertyDictionary(1, checkExistingKeys: false) { ["groupBy"] = new(new ClrFunction(Engine, "groupBy", GroupBy, 2, PropertyFlag.Configurable), PropertyFlags), };
         SetProperties(properties);
 
-        var symbols = new SymbolDictionary(1)
-        {
-            [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunction(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable)
-        };
+        var symbols = new SymbolDictionary(1) { [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunction(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable) };
         SetSymbols(symbols);
     }
 
-    private static JsValue Species(JsValue thisObject, JsValue[] arguments)
-    {
-        return thisObject;
-    }
+    public JsMap Construct() => ConstructMap(this);
 
     /// <summary>
     /// https://tc39.es/ecma262/#sec-map-iterable
     /// </summary>
     public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+    {
+        var map = ConstructMap(newTarget);
+
+        if (arguments.Length > 0 && !arguments[0].IsNullOrUndefined())
+        {
+            var adder = ((ObjectInstance) map).Get("set");
+            var iterator = arguments.At(0).GetIterator(_realm);
+
+            IteratorProtocol.AddEntriesFromIterable(map, iterator, adder);
+        }
+
+        return map;
+    }
+
+    private JsMap ConstructMap(JsValue newTarget)
     {
         if (newTarget.IsUndefined())
         {
@@ -66,14 +72,6 @@ internal sealed class MapConstructor : Constructor
             static intrinsics => intrinsics.Map.PrototypeObject,
             static (Engine engine, Realm realm, object? _) => new JsMap(engine, realm));
 
-        if (arguments.Length > 0 && !arguments[0].IsNullOrUndefined())
-        {
-            var adder = map.Get("set");
-            var iterator = arguments.At(0).GetIterator(_realm);
-
-            IteratorProtocol.AddEntriesFromIterable(map, iterator, adder);
-        }
-
         return map;
     }
 
@@ -89,9 +87,14 @@ internal sealed class MapConstructor : Constructor
         var map = (JsMap) Construct(_realm.Intrinsics.Map);
         foreach (var pair in grouping)
         {
-            map.MapSet(pair.Key, pair.Value);
+            map.Set(pair.Key, pair.Value);
         }
 
         return map;
     }
+
+    private static JsValue Species(JsValue thisObject, JsValue[] arguments)
+    {
+        return thisObject;
+    }
 }

+ 3 - 3
Jint/Native/Map/MapPrototype.cs

@@ -63,7 +63,7 @@ internal sealed class MapPrototype : Prototype
     private JsValue Get(JsValue thisObject, JsValue[] arguments)
     {
         var map = AssertMapInstance(thisObject);
-        return map.MapGet(arguments.At(0));
+        return map.Get(arguments.At(0));
     }
 
     private JsValue Clear(JsValue thisObject, JsValue[] arguments)
@@ -76,7 +76,7 @@ internal sealed class MapPrototype : Prototype
     private JsValue Delete(JsValue thisObject, JsValue[] arguments)
     {
         var map = AssertMapInstance(thisObject);
-        return map.MapDelete(arguments.At(0))
+        return map.Remove(arguments.At(0))
             ? JsBoolean.True
             : JsBoolean.False;
     }
@@ -84,7 +84,7 @@ internal sealed class MapPrototype : Prototype
     private JsValue Set(JsValue thisObject, JsValue[] arguments)
     {
         var map = AssertMapInstance(thisObject);
-        map.MapSet(arguments.At(0), arguments.At(1));
+        map.Set(arguments.At(0), arguments.At(1));
         return thisObject;
     }
 

+ 4 - 4
Jint/Native/Set/SetPrototype.cs

@@ -85,7 +85,7 @@ internal sealed class SetPrototype : Prototype
     private JsBoolean Delete(JsValue thisObject, JsValue[] arguments)
     {
         var set = AssertSetInstance(thisObject);
-        return set.Remove(arguments.At(0))
+        return set.Delete(arguments.At(0))
             ? JsBoolean.True
             : JsBoolean.False;
     }
@@ -119,7 +119,7 @@ internal sealed class SetPrototype : Prototype
                     var inOther = TypeConverter.ToBoolean(otherRec.Has.Call(otherRec.Set, args));
                     if (inOther)
                     {
-                        resultSetData.Remove(e);
+                        resultSetData.Delete(e);
                         index--;
                     }
                 }
@@ -144,7 +144,7 @@ internal sealed class SetPrototype : Prototype
                 nextValue = JsNumber.PositiveZero;
             }
 
-            resultSetData.Remove(nextValue);
+            resultSetData.Delete(nextValue);
         }
 
         return resultSetData;
@@ -308,7 +308,7 @@ internal sealed class SetPrototype : Prototype
             {
                 if (inResult)
                 {
-                    resultSetData.Remove(nextValue);
+                    resultSetData.Delete(nextValue);
                 }
             }
             else

+ 2 - 2
Jint/Runtime/Intrinsics.cs

@@ -192,7 +192,7 @@ public sealed partial class Intrinsics
     public Float64ArrayConstructor Float64Array =>
         _float64Array ??= new Float64ArrayConstructor(_engine, _realm, TypedArray, TypedArray.PrototypeObject);
 
-    internal MapConstructor Map =>
+    public MapConstructor Map =>
         _map ??= new MapConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);
 
     internal MapIteratorPrototype MapIteratorPrototype =>
@@ -293,4 +293,4 @@ public sealed partial class Intrinsics
 
     internal ThrowTypeError ThrowTypeError =>
         _throwTypeError ??= new ThrowTypeError(_engine, _engine.Realm) { _prototype = _engine.Realm.Intrinsics.Function.PrototypeObject };
-}
+}