Jelajahi Sumber

Fix custom reference resolver argument (#1938)

Marko Lahma 11 bulan lalu
induk
melakukan
a37f39cddf
2 mengubah file dengan 79 tambahan dan 6 penghapusan
  1. 62 0
      Jint.Tests.PublicInterface/RavenApiUsageTests.cs
  2. 17 6
      Jint/Engine.cs

+ 62 - 0
Jint.Tests.PublicInterface/RavenApiUsageTests.cs

@@ -201,6 +201,36 @@ public class RavenApiUsageTests
         var engine = new Engine();
         engine.Advanced.ResetCallStack();
     }
+
+    [Fact]
+    public void CanUseCustomReferenceResolver()
+    {
+        var engine = new Engine(options =>
+        {
+            options.ReferenceResolver = new MyReferenceResolver();
+        });
+
+        engine
+            .Execute("""
+                          function output(doc) {
+                         var rows123 = [{}];
+                     var test = null;
+                         return { 
+                             Rows : [{}].map(row=>({row:row, myRows:test.filter(x=>x)
+                             })).map(__rvn4=>({
+                                 Custom:__rvn4.myRows[0].Custom,
+                                 Custom2:__rvn4.myRows
+                                 }))
+                                 };
+                     }
+                     """);
+
+        var result = engine.Evaluate("output()");
+
+        var rows = result.AsObject()["Rows"];
+        var custom = rows.AsArray()[0].AsObject()["Custom"];
+        Assert.Equal(JsValue.Null, custom);
+    }
 }
 
 file sealed class CustomString : JsString
@@ -287,3 +317,35 @@ file sealed class CustomUndefined : JsValue
         return "null";
     }
 }
+
+file sealed class MyReferenceResolver : IReferenceResolver
+{
+    public bool TryUnresolvableReference(Engine engine, Reference reference, out JsValue value)
+    {
+        JsValue referencedName = reference.ReferencedName;
+
+        if (referencedName.IsString())
+        {
+            value = reference.IsPropertyReference ? JsValue.Undefined : JsValue.Null;
+            return true;
+        }
+
+        throw new InvalidOperationException();
+    }
+
+    public bool TryPropertyReference(Engine engine, Reference reference, ref JsValue value)
+    {
+        return value.IsNull() || value.IsUndefined();
+    }
+
+    public bool TryGetCallable(Engine engine, object callee, out JsValue value)
+    {
+        value = new ClrFunction(engine, "function", static (_, _) => JsValue.Undefined);
+        return true;
+    }
+
+    public bool CheckCoercible(JsValue value)
+    {
+        return true;
+    }
+}

+ 17 - 6
Jint/Engine.cs

@@ -1,5 +1,5 @@
 using System.Diagnostics;
-using System.Collections.Concurrent;
+using System.Collections.Concurrent;
 using System.Diagnostics.CodeAnalysis;
 using System.Runtime.CompilerServices;
 using Jint.Native;
@@ -50,7 +50,10 @@ public sealed partial class Engine : IDisposable
     internal readonly Constraint[] _constraints;
     internal readonly bool _isDebugMode;
     internal readonly bool _isStrict;
+
+    private bool _customResolver;
     internal readonly IReferenceResolver _referenceResolver;
+
     internal readonly ReferencePool _referencePool;
     internal readonly ArgumentsInstancePool _argumentsInstancePool;
     internal readonly JsValueArrayPool _jsValueArrayPool;
@@ -135,6 +138,7 @@ public sealed partial class Engine : IDisposable
 
         _constraints = Options.Constraints.Constraints.ToArray();
         _referenceResolver = Options.ReferenceResolver;
+        _customResolver = !ReferenceEquals(_referenceResolver, DefaultReferenceResolver.Instance);
 
         _referencePool = new ReferencePool();
         _argumentsInstancePool = new ArgumentsInstancePool(this);
@@ -564,18 +568,25 @@ public sealed partial class Engine : IDisposable
 
         if (baseValue.IsUndefined())
         {
-            if (_referenceResolver.TryUnresolvableReference(this, reference, out var val))
+            if (_customResolver)
             {
-                return val;
+                reference.EvaluateAndCachePropertyKey();
+                if (_referenceResolver.TryUnresolvableReference(this, reference, out var val))
+                {
+                    return val;
+                }
             }
 
             ExceptionHelper.ThrowReferenceError(Realm, reference);
         }
 
-        if ((baseValue._type & InternalTypes.ObjectEnvironmentRecord) == InternalTypes.Empty
-            && _referenceResolver.TryPropertyReference(this, reference, ref baseValue))
+        if ((baseValue._type & InternalTypes.ObjectEnvironmentRecord) == InternalTypes.Empty && _customResolver)
         {
-            return baseValue;
+            reference.EvaluateAndCachePropertyKey();
+            if (_referenceResolver.TryPropertyReference(this, reference, ref baseValue))
+            {
+                return baseValue;
+            }
         }
 
         if (reference.IsPropertyReference)