///|
/// JavaScript Proxy
///
/// After creation with Proxy::new(), use JsImpl trait methods to interact:
/// - proxy.get("key") - triggers get trap
/// - proxy.set("key", value) - triggers set trap
/// - proxy.delete("key") - triggers deleteProperty trap
/// - proxy.hasOwnProperty("key") - triggers has trap
/// - proxy._invoke(args) - triggers apply trap (for function proxies)
#external
pub type Proxy
///|
pub fn Proxy::as_any(self : Proxy) -> @core.Any = "%identity"
///|
/// get the Proxy class
fn proxy_class() -> @core.Any {
@core.global_this()["Proxy"]
}
///|
/// JS: new Proxy(target, handler)
/// Creates a new Proxy object with optional trap handlers
///
/// Example with get trap:
/// ```moonbit no-check
/// let target = @core.new_object()
///
/// let _proxy = Proxy::new(@core.any(target), get=fn(_target, _prop, _receiver) {
/// @core.any("value")
/// })
/// ```
pub fn Proxy::new(
target : @core.Any,
get? : (@core.Any, @core.Any, @core.Any) -> @core.Any,
set? : (@core.Any, @core.Any, @core.Any, @core.Any) -> Bool,
has? : (@core.Any, @core.Any) -> Bool,
deleteProperty? : (@core.Any, @core.Any) -> Bool,
apply? : (@core.Any, @core.Any, @core.Any) -> @core.Any,
construct? : (@core.Any, @core.Any, @core.Any) -> @core.Any,
ownKeys? : (@core.Any) -> @core.Any,
getPrototypeOf? : (@core.Any) -> @core.Any,
setPrototypeOf? : (@core.Any, @core.Any) -> Bool,
isExtensible? : (@core.Any) -> Bool,
preventExtensions? : (@core.Any) -> Bool,
getOwnPropertyDescriptor? : (@core.Any, @core.Any) -> @core.Any,
defineProperty? : (@core.Any, @core.Any, @core.Any) -> Bool,
) -> Proxy {
let handler = ffi_object_create()
if get is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["get"] = js_fn
}
if set is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["set"] = js_fn
}
if has is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["has"] = js_fn
}
if deleteProperty is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["deleteProperty"] = js_fn
}
if apply is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["apply"] = js_fn
}
if construct is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["construct"] = js_fn
}
if ownKeys is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["ownKeys"] = js_fn
}
if getPrototypeOf is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["getPrototypeOf"] = js_fn
}
if setPrototypeOf is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["setPrototypeOf"] = js_fn
}
if isExtensible is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["isExtensible"] = js_fn
}
if preventExtensions is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["preventExtensions"] = js_fn
}
if getOwnPropertyDescriptor is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["getOwnPropertyDescriptor"] = js_fn
}
if defineProperty is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["defineProperty"] = js_fn
}
ffi_new_proxy(target, handler)
}
///|
/// JS: Proxy.revocable(target, handler)
/// Creates a revocable Proxy object
/// Returns an object with {proxy: Proxy, revoke: Function}
pub fn Proxy::revocable(
target : @core.Any,
get? : (@core.Any, @core.Any, @core.Any) -> @core.Any,
set? : (@core.Any, @core.Any, @core.Any, @core.Any) -> Bool,
has? : (@core.Any, @core.Any) -> Bool,
deleteProperty? : (@core.Any, @core.Any) -> Bool,
apply? : (@core.Any, @core.Any, @core.Any) -> @core.Any,
construct? : (@core.Any, @core.Any, @core.Any) -> @core.Any,
ownKeys? : (@core.Any) -> @core.Any,
getPrototypeOf? : (@core.Any) -> @core.Any,
setPrototypeOf? : (@core.Any, @core.Any) -> Bool,
isExtensible? : (@core.Any) -> Bool,
preventExtensions? : (@core.Any) -> Bool,
getOwnPropertyDescriptor? : (@core.Any, @core.Any) -> @core.Any,
defineProperty? : (@core.Any, @core.Any, @core.Any) -> Bool,
) -> @core.Any {
let handler = ffi_object_create()
if get is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["get"] = js_fn
}
if set is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["set"] = js_fn
}
if has is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["has"] = js_fn
}
if deleteProperty is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["deleteProperty"] = js_fn
}
if apply is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["apply"] = js_fn
}
if construct is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["construct"] = js_fn
}
if ownKeys is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["ownKeys"] = js_fn
}
if getPrototypeOf is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["getPrototypeOf"] = js_fn
}
if setPrototypeOf is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["setPrototypeOf"] = js_fn
}
if isExtensible is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["isExtensible"] = js_fn
}
if preventExtensions is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["preventExtensions"] = js_fn
}
if getOwnPropertyDescriptor is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["getOwnPropertyDescriptor"] = js_fn
}
if defineProperty is Some(trap) {
let js_fn : @core.Any = @core.identity(trap)
handler["defineProperty"] = js_fn
}
proxy_class()._call("revocable", [target, handler])
}
///| FFI
///|
extern "js" fn ffi_object_create() -> @core.Any =
#| () => ({})
///|
extern "js" fn ffi_new_proxy(target : @core.Any, handler : @core.Any) -> Proxy =
#| (target, handler) => new Proxy(target, handler)