Skip to content

Commit

Permalink
Allow adding symbol properties to CLR objects (#1131)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Apr 16, 2022
1 parent 21bdb74 commit 6b24844
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 6 deletions.
46 changes: 46 additions & 0 deletions Jint.Tests/Runtime/InteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Reflection;
using Jint.Native;
using Jint.Native.Object;
using Jint.Native.Symbol;
using Jint.Runtime;
using Jint.Runtime.Interop;
using Jint.Tests.Runtime.Converters;
Expand Down Expand Up @@ -918,6 +919,51 @@ public void CanAddArrayPrototypeForArrayLikeClrObjects()
var name = e.Evaluate("o.values.filter(x => x.age == 12)[0].name").ToString();
Assert.Equal("John", name);
}


[Fact]
public void CanSetIsConcatSpreadableForArrays()
{
var engine = new Engine(opt =>
{
opt.SetWrapObjectHandler((eng, obj) =>
{
var wrapper = new ObjectWrapper(eng, obj);
if (wrapper.IsArrayLike)
{
wrapper.SetPrototypeOf(eng.Realm.Intrinsics.Array.PrototypeObject);
wrapper.Set(GlobalSymbolRegistry.IsConcatSpreadable, true);
}
return wrapper;
});
});

engine
.SetValue("list1", new List<string> { "A", "B", "C" })
.SetValue("list2", new List<string> { "D", "E", "F" })
.Execute("var array1 = ['A', 'B', 'C'];")
.Execute("var array2 = ['D', 'E', 'F'];");

Assert.True(engine.Evaluate("list1[Symbol.isConcatSpreadable] = true; list1[Symbol.isConcatSpreadable];").AsBoolean());
Assert.True(engine.Evaluate("list2[Symbol.isConcatSpreadable] = true; list2[Symbol.isConcatSpreadable];").AsBoolean());

Assert.Equal("[\"A\",\"B\",\"C\"]", engine.Evaluate("JSON.stringify(array1);"));
Assert.Equal("[\"D\",\"E\",\"F\"]", engine.Evaluate("JSON.stringify(array2);"));
Assert.Equal("[\"A\",\"B\",\"C\"]", engine.Evaluate("JSON.stringify(list1);"));
Assert.Equal("[\"D\",\"E\",\"F\"]", engine.Evaluate("JSON.stringify(list2);"));

const string Concatenated = "[\"A\",\"B\",\"C\",\"D\",\"E\",\"F\"]";
Assert.Equal(Concatenated, engine.Evaluate("JSON.stringify(array1.concat(array2));"));
Assert.Equal(Concatenated, engine.Evaluate("JSON.stringify(array1.concat(list2));"));
Assert.Equal(Concatenated, engine.Evaluate("JSON.stringify(list1.concat(array2));"));
Assert.Equal(Concatenated, engine.Evaluate("JSON.stringify(list1.concat(list2));"));

Assert.False(engine.Evaluate("list1[Symbol.isConcatSpreadable] = false; list1[Symbol.isConcatSpreadable];").AsBoolean());
Assert.False(engine.Evaluate("list2[Symbol.isConcatSpreadable] = false; list2[Symbol.isConcatSpreadable];").AsBoolean());

Assert.Equal("[[\"A\",\"B\",\"C\"]]", engine.Evaluate("JSON.stringify([].concat(list1));"));
Assert.Equal("[[\"A\",\"B\",\"C\"],[\"D\",\"E\",\"F\"]]", engine.Evaluate("JSON.stringify(list1.concat(list2));"));
}

[Fact]
public void ShouldConvertArrayToArrayInstance()
Expand Down
16 changes: 10 additions & 6 deletions Jint/Runtime/Interop/ObjectWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ public override bool Set(JsValue property, JsValue value, JsValue receiver)
return true;
}
}
else if (property is JsSymbol jsSymbol)
{
// symbol addition will never hit any known CLR object properties, so if write is allowed, allow writing symbols too
if (_engine.Options.Interop.AllowWrite)
{
return base.Set(jsSymbol, value, receiver);
}

return false;
}

return SetSlow(property, value);
}
Expand Down Expand Up @@ -105,12 +115,6 @@ public override JsValue Get(JsValue property, JsValue receiver)
return (uint) index < list.Count ? FromObject(_engine, list[index]) : Undefined;
}

if (property.IsSymbol() && property != GlobalSymbolRegistry.Iterator)
{
// wrapped objects cannot have symbol properties
return Undefined;
}

return base.Get(property, receiver);
}

Expand Down

0 comments on commit 6b24844

Please sign in to comment.