diff --git a/Jint.Tests/Runtime/Domain/Shape.cs b/Jint.Tests/Runtime/Domain/Shape.cs index 2c053bbe8..08314bdd6 100644 --- a/Jint.Tests/Runtime/Domain/Shape.cs +++ b/Jint.Tests/Runtime/Domain/Shape.cs @@ -9,9 +9,9 @@ namespace Shapes { public abstract class Shape { + public int Id = 123; public abstract double Perimeter(); public Colors Color { get; set; } - } public class Circle : Shape @@ -22,33 +22,34 @@ public Meta() { _description = "descp"; } - private string _description; - public string Description - { - get + private string _description; + + public string Description { - return _description; + get + { + return _description; + } + set + { + _description = value; + } } - set + + public enum Usage { - _description = value; + Public, + Private, + Internal = 11 } - } - - public enum Usage - { - Public, - Private, - Internal = 11 - } } public enum Kind { - Unit, - Ellipse, - Round = 5 + Unit, + Ellipse, + Round = 5 } public Circle() @@ -64,7 +65,7 @@ public Circle(double radius) public override double Perimeter() { - return Math.PI*Math.Pow(Radius, 2); + return Math.PI * Math.Pow(Radius, 2); } } } diff --git a/Jint.Tests/Runtime/InteropTests.cs b/Jint.Tests/Runtime/InteropTests.cs index 7054c1d0f..43fcc01ab 100644 --- a/Jint.Tests/Runtime/InteropTests.cs +++ b/Jint.Tests/Runtime/InteropTests.cs @@ -3585,4 +3585,20 @@ public void ShouldNotThrowOnInspectingClrClassFunction() decl.Should().BeNull(); } + + [Fact] + public void StringifyShouldIncludeInheritedFieldsAndProperties() + { + var engine = new Engine(); + engine.SetValue("c", new Circle(12.34)); + engine.Evaluate("JSON.stringify(c)").ToString().Should().Be("{\"Radius\":12.34,\"Color\":0,\"Id\":123}"); + + + engine = new Engine(options => + { + options.Interop.ObjectWrapperReportOnlyDeclaredMembers = true; + }); + engine.SetValue("c", new Circle(12.34)); + engine.Evaluate("JSON.stringify(c)").ToString().Should().Be("{\"Radius\":12.34}"); + } } diff --git a/Jint/Options.cs b/Jint/Options.cs index 1cee53c6c..613bf3de9 100644 --- a/Jint/Options.cs +++ b/Jint/Options.cs @@ -371,6 +371,13 @@ public class InteropOptions /// All other values are ignored. /// public MemberTypes ObjectWrapperReportedMemberTypes { get; set; } = MemberTypes.Field | MemberTypes.Property | MemberTypes.Method; + + /// + /// Whether object wrapper should only report members that are declared on the object type itself, not inherited members. Defaults to false. + /// This is different from JS logic where only object's own members are reported and not prototypes. + /// + /// This configuration does not affect methods, only methods declared in type itself will be reported. + public bool ObjectWrapperReportOnlyDeclaredMembers { get; set; } } public class ConstraintOptions diff --git a/Jint/Runtime/Interop/ObjectWrapper.cs b/Jint/Runtime/Interop/ObjectWrapper.cs index d19b58973..4328a39f0 100644 --- a/Jint/Runtime/Interop/ObjectWrapper.cs +++ b/Jint/Runtime/Interop/ObjectWrapper.cs @@ -253,12 +253,18 @@ private IEnumerable EnumerateOwnPropertyKeys(Types types) } else if (includeStrings) { + var interopOptions = _engine.Options.Interop; + // we take public properties, fields and methods - const BindingFlags BindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public; + var bindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public; + if (interopOptions.ObjectWrapperReportOnlyDeclaredMembers) + { + bindingFlags |= BindingFlags.DeclaredOnly; + } - if ((_engine.Options.Interop.ObjectWrapperReportedMemberTypes & MemberTypes.Property) == MemberTypes.Property) + if ((interopOptions.ObjectWrapperReportedMemberTypes & MemberTypes.Property) == MemberTypes.Property) { - foreach (var p in ClrType.GetProperties(BindingFlags)) + foreach (var p in ClrType.GetProperties(bindingFlags)) { var indexParameters = p.GetIndexParameters(); if (indexParameters.Length == 0) @@ -268,17 +274,17 @@ private IEnumerable EnumerateOwnPropertyKeys(Types types) } } - if ((_engine.Options.Interop.ObjectWrapperReportedMemberTypes & MemberTypes.Field) == MemberTypes.Field) + if ((interopOptions.ObjectWrapperReportedMemberTypes & MemberTypes.Field) == MemberTypes.Field) { - foreach (var f in ClrType.GetFields(BindingFlags | BindingFlags.DeclaredOnly)) + foreach (var f in ClrType.GetFields(bindingFlags)) { yield return JsString.Create(f.Name); } } - if ((_engine.Options.Interop.ObjectWrapperReportedMemberTypes & MemberTypes.Method) == MemberTypes.Method) + if ((interopOptions.ObjectWrapperReportedMemberTypes & MemberTypes.Method) == MemberTypes.Method) { - foreach (var m in ClrType.GetMethods(BindingFlags | BindingFlags.DeclaredOnly)) + foreach (var m in ClrType.GetMethods(bindingFlags | BindingFlags.DeclaredOnly)) { if (m.IsSpecialName) {