summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2020-11-24 17:47:51 +0000
committerAndreas Kling <kling@serenityos.org>2020-11-24 21:35:03 +0100
commitf6f0d3cbaee541bef3897fb367f482b27b4f6056 (patch)
treef12bf671ff37994b9cddebec86cbde5da3765f22 /Libraries
parent76308c2e1f7bf09686b14b797562d0e98efba97d (diff)
downloadserenity-f6f0d3cbaee541bef3897fb367f482b27b4f6056.zip
LibJS: Support receiver in ProxyObject::get/put()
If a receiver is given, e.g. via Reflect.get/set(), forward it to the target object's get()/put() or use it as last argument of the trap function. The default value is the Proxy object itself.
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibJS/Runtime/ProxyObject.cpp16
-rw-r--r--Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-get.js10
-rw-r--r--Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-set.js15
3 files changed, 35 insertions, 6 deletions
diff --git a/Libraries/LibJS/Runtime/ProxyObject.cpp b/Libraries/LibJS/Runtime/ProxyObject.cpp
index 02cd11634f..4096558bdc 100644
--- a/Libraries/LibJS/Runtime/ProxyObject.cpp
+++ b/Libraries/LibJS/Runtime/ProxyObject.cpp
@@ -359,24 +359,26 @@ bool ProxyObject::has_property(const PropertyName& name) const
return trap_result.to_boolean();
}
-Value ProxyObject::get(const PropertyName& name, Value) const
+Value ProxyObject::get(const PropertyName& name, Value receiver) const
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
+ if (receiver.is_empty())
+ receiver = Value(const_cast<ProxyObject*>(this));
auto trap = m_handler.get(vm.names.get);
if (vm.exception())
return {};
if (trap.is_empty() || trap.is_nullish())
- return m_target.get(name);
+ return m_target.get(name, receiver);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "get");
return {};
}
- auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), name.to_value(vm), Value(const_cast<ProxyObject*>(this)));
+ auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), name.to_value(vm), receiver);
if (vm.exception())
return {};
auto target_desc = m_target.get_own_property_descriptor(name);
@@ -395,23 +397,25 @@ Value ProxyObject::get(const PropertyName& name, Value) const
return trap_result;
}
-bool ProxyObject::put(const PropertyName& name, Value value, Value)
+bool ProxyObject::put(const PropertyName& name, Value value, Value receiver)
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
+ if (receiver.is_empty())
+ receiver = Value(const_cast<ProxyObject*>(this));
auto trap = m_handler.get(vm.names.set);
if (vm.exception())
return false;
if (trap.is_empty() || trap.is_nullish())
- return m_target.put(name, value);
+ return m_target.put(name, value, receiver);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "set");
return false;
}
- auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), name.to_value(vm), value, Value(const_cast<ProxyObject*>(this)));
+ auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), name.to_value(vm), value, receiver);
if (vm.exception() || !trap_result.to_boolean())
return false;
auto target_desc = m_target.get_own_property_descriptor(name);
diff --git a/Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-get.js b/Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-get.js
index a1fa8499c2..9d9ab486c9 100644
--- a/Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-get.js
+++ b/Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-get.js
@@ -40,6 +40,16 @@ describe("[[Get]] trap normal behavior", () => {
expect(p.test).toBeUndefined();
expect(p[Symbol.hasInstance]).toBeUndefined();
});
+
+ test("custom receiver value", () => {
+ let p = new Proxy({}, {
+ get(target, property, receiver) {
+ return receiver;
+ },
+ });
+
+ expect(Reflect.get(p, "foo", 42)).toBe(42);
+ });
});
describe("[[Get]] invariants", () => {
diff --git a/Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-set.js b/Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-set.js
index c78235884e..ef1a75c48a 100644
--- a/Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-set.js
+++ b/Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-set.js
@@ -43,6 +43,21 @@ describe("[[Set]] trap normal behavior", () => {
p[Symbol.hasInstance] = "foo"
expect(p[Symbol.hasInstance]).toBe("foo");
});
+
+ test("custom receiver value", () => {
+ const o = {};
+ const r = {};
+ let p = new Proxy(o, {
+ set(target, property, value, receiver) {
+ receiver[property] = value;
+ return true;
+ },
+ });
+
+ expect(Reflect.set(p, "foo", 42, r)).toBe(true);
+ expect(o.foo).toBeUndefined();
+ expect(r.foo).toBe(42);
+ });
});
describe("[[Set]] invariants", () => {