/// <summary>
/// Gets the value of the property with the given name.
/// </summary>
/// <param name="key"> The property key (either a string or a Symbol). </param>
/// <param name="thisValue"> The value of the "this" keyword inside a getter. </param>
/// <returns> The value of the property, or <c>null</c> if the property doesn't exist. </returns>
/// <remarks> The prototype chain is searched if the property does not exist directly on
/// this object. </remarks>
public override object GetPropertyValue(object key, object thisValue)
{
// Check for revocation.
if (target == null || handler == null)
{
throw new JavaScriptException(ErrorType.TypeError, "Cannot call 'get' on a proxy that has been revoked.");
}
// Call the handler, if one exists.
var trap = handler.GetMethod("get");
if (trap == null)
{
return(target.GetPropertyValue(key, thisValue));
}
var result = trap.CallLateBound(handler, target, key, thisValue);
// Validate.
var targetDescriptor = target.GetOwnPropertyDescriptor(key);
if (targetDescriptor.Exists && !targetDescriptor.IsConfigurable)
{
if (!targetDescriptor.IsAccessor && !targetDescriptor.IsWritable && !TypeComparer.SameValue(result, targetDescriptor.Value))
{
throw new JavaScriptException(ErrorType.TypeError, $"'get' on proxy: property '{TypeConverter.ToString(key)}' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '{TypeConverter.ToString(targetDescriptor.Value)}' but got '{TypeConverter.ToString(result)}').");
}
if (targetDescriptor.IsAccessor && targetDescriptor.Getter == null && result != null && result != Undefined.Value)
{
throw new JavaScriptException(ErrorType.TypeError, $"'get' on proxy: property '{TypeConverter.ToString(key)}' is a non-configurable accessor property on the proxy target and does not have a getter function, but the trap did not return 'undefined' (got '{TypeConverter.ToString(result)}').");
}
}
return(result);
}