github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/builtin_proxy.go (about) 1 package goja 2 3 import ( 4 "github.com/nuvolaris/goja/unistring" 5 ) 6 7 type nativeProxyHandler struct { 8 handler *ProxyTrapConfig 9 } 10 11 func (h *nativeProxyHandler) getPrototypeOf(target *Object) (Value, bool) { 12 if trap := h.handler.GetPrototypeOf; trap != nil { 13 return trap(target), true 14 } 15 return nil, false 16 } 17 18 func (h *nativeProxyHandler) setPrototypeOf(target *Object, proto *Object) (bool, bool) { 19 if trap := h.handler.SetPrototypeOf; trap != nil { 20 return trap(target, proto), true 21 } 22 return false, false 23 } 24 25 func (h *nativeProxyHandler) isExtensible(target *Object) (bool, bool) { 26 if trap := h.handler.IsExtensible; trap != nil { 27 return trap(target), true 28 } 29 return false, false 30 } 31 32 func (h *nativeProxyHandler) preventExtensions(target *Object) (bool, bool) { 33 if trap := h.handler.PreventExtensions; trap != nil { 34 return trap(target), true 35 } 36 return false, false 37 } 38 39 func (h *nativeProxyHandler) getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool) { 40 if trap := h.handler.GetOwnPropertyDescriptorIdx; trap != nil { 41 if idx, ok := strToInt(prop); ok { 42 desc := trap(target, idx) 43 return desc.toValue(target.runtime), true 44 } 45 } 46 if trap := h.handler.GetOwnPropertyDescriptor; trap != nil { 47 desc := trap(target, prop.String()) 48 return desc.toValue(target.runtime), true 49 } 50 return nil, false 51 } 52 53 func (h *nativeProxyHandler) getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool) { 54 if trap := h.handler.GetOwnPropertyDescriptorIdx; trap != nil { 55 desc := trap(target, toIntStrict(int64(prop))) 56 return desc.toValue(target.runtime), true 57 } 58 if trap := h.handler.GetOwnPropertyDescriptor; trap != nil { 59 desc := trap(target, prop.String()) 60 return desc.toValue(target.runtime), true 61 } 62 return nil, false 63 } 64 65 func (h *nativeProxyHandler) getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool) { 66 if trap := h.handler.GetOwnPropertyDescriptorSym; trap != nil { 67 desc := trap(target, prop) 68 return desc.toValue(target.runtime), true 69 } 70 return nil, false 71 } 72 73 func (h *nativeProxyHandler) definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool) { 74 if trap := h.handler.DefinePropertyIdx; trap != nil { 75 if idx, ok := strToInt(prop); ok { 76 return trap(target, idx, desc), true 77 } 78 } 79 if trap := h.handler.DefineProperty; trap != nil { 80 return trap(target, prop.String(), desc), true 81 } 82 return false, false 83 } 84 85 func (h *nativeProxyHandler) definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool) { 86 if trap := h.handler.DefinePropertyIdx; trap != nil { 87 return trap(target, toIntStrict(int64(prop)), desc), true 88 } 89 if trap := h.handler.DefineProperty; trap != nil { 90 return trap(target, prop.String(), desc), true 91 } 92 return false, false 93 } 94 95 func (h *nativeProxyHandler) definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool) { 96 if trap := h.handler.DefinePropertySym; trap != nil { 97 return trap(target, prop, desc), true 98 } 99 return false, false 100 } 101 102 func (h *nativeProxyHandler) hasStr(target *Object, prop unistring.String) (bool, bool) { 103 if trap := h.handler.HasIdx; trap != nil { 104 if idx, ok := strToInt(prop); ok { 105 return trap(target, idx), true 106 } 107 } 108 if trap := h.handler.Has; trap != nil { 109 return trap(target, prop.String()), true 110 } 111 return false, false 112 } 113 114 func (h *nativeProxyHandler) hasIdx(target *Object, prop valueInt) (bool, bool) { 115 if trap := h.handler.HasIdx; trap != nil { 116 return trap(target, toIntStrict(int64(prop))), true 117 } 118 if trap := h.handler.Has; trap != nil { 119 return trap(target, prop.String()), true 120 } 121 return false, false 122 } 123 124 func (h *nativeProxyHandler) hasSym(target *Object, prop *Symbol) (bool, bool) { 125 if trap := h.handler.HasSym; trap != nil { 126 return trap(target, prop), true 127 } 128 return false, false 129 } 130 131 func (h *nativeProxyHandler) getStr(target *Object, prop unistring.String, receiver Value) (Value, bool) { 132 if trap := h.handler.GetIdx; trap != nil { 133 if idx, ok := strToInt(prop); ok { 134 return trap(target, idx, receiver), true 135 } 136 } 137 if trap := h.handler.Get; trap != nil { 138 return trap(target, prop.String(), receiver), true 139 } 140 return nil, false 141 } 142 143 func (h *nativeProxyHandler) getIdx(target *Object, prop valueInt, receiver Value) (Value, bool) { 144 if trap := h.handler.GetIdx; trap != nil { 145 return trap(target, toIntStrict(int64(prop)), receiver), true 146 } 147 if trap := h.handler.Get; trap != nil { 148 return trap(target, prop.String(), receiver), true 149 } 150 return nil, false 151 } 152 153 func (h *nativeProxyHandler) getSym(target *Object, prop *Symbol, receiver Value) (Value, bool) { 154 if trap := h.handler.GetSym; trap != nil { 155 return trap(target, prop, receiver), true 156 } 157 return nil, false 158 } 159 160 func (h *nativeProxyHandler) setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool) { 161 if trap := h.handler.SetIdx; trap != nil { 162 if idx, ok := strToInt(prop); ok { 163 return trap(target, idx, value, receiver), true 164 } 165 } 166 if trap := h.handler.Set; trap != nil { 167 return trap(target, prop.String(), value, receiver), true 168 } 169 return false, false 170 } 171 172 func (h *nativeProxyHandler) setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool) { 173 if trap := h.handler.SetIdx; trap != nil { 174 return trap(target, toIntStrict(int64(prop)), value, receiver), true 175 } 176 if trap := h.handler.Set; trap != nil { 177 return trap(target, prop.String(), value, receiver), true 178 } 179 return false, false 180 } 181 182 func (h *nativeProxyHandler) setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool) { 183 if trap := h.handler.SetSym; trap != nil { 184 return trap(target, prop, value, receiver), true 185 } 186 return false, false 187 } 188 189 func (h *nativeProxyHandler) deleteStr(target *Object, prop unistring.String) (bool, bool) { 190 if trap := h.handler.DeletePropertyIdx; trap != nil { 191 if idx, ok := strToInt(prop); ok { 192 return trap(target, idx), true 193 } 194 } 195 if trap := h.handler.DeleteProperty; trap != nil { 196 return trap(target, prop.String()), true 197 } 198 return false, false 199 } 200 201 func (h *nativeProxyHandler) deleteIdx(target *Object, prop valueInt) (bool, bool) { 202 if trap := h.handler.DeletePropertyIdx; trap != nil { 203 return trap(target, toIntStrict(int64(prop))), true 204 } 205 if trap := h.handler.DeleteProperty; trap != nil { 206 return trap(target, prop.String()), true 207 } 208 return false, false 209 } 210 211 func (h *nativeProxyHandler) deleteSym(target *Object, prop *Symbol) (bool, bool) { 212 if trap := h.handler.DeletePropertySym; trap != nil { 213 return trap(target, prop), true 214 } 215 return false, false 216 } 217 218 func (h *nativeProxyHandler) ownKeys(target *Object) (*Object, bool) { 219 if trap := h.handler.OwnKeys; trap != nil { 220 return trap(target), true 221 } 222 return nil, false 223 } 224 225 func (h *nativeProxyHandler) apply(target *Object, this Value, args []Value) (Value, bool) { 226 if trap := h.handler.Apply; trap != nil { 227 return trap(target, this, args), true 228 } 229 return nil, false 230 } 231 232 func (h *nativeProxyHandler) construct(target *Object, args []Value, newTarget *Object) (Value, bool) { 233 if trap := h.handler.Construct; trap != nil { 234 return trap(target, args, newTarget), true 235 } 236 return nil, false 237 } 238 239 func (h *nativeProxyHandler) toObject(runtime *Runtime) *Object { 240 return runtime.ToValue(h.handler).ToObject(runtime) 241 } 242 243 func (r *Runtime) newNativeProxyHandler(nativeHandler *ProxyTrapConfig) proxyHandler { 244 return &nativeProxyHandler{handler: nativeHandler} 245 } 246 247 // ProxyTrapConfig provides a simplified Go-friendly API for implementing Proxy traps. 248 // If an *Idx trap is defined it gets called for integer property keys, including negative ones. Note that 249 // this only includes string property keys that represent a canonical integer 250 // (i.e. "0", "123", but not "00", "01", " 1" or "-0"). 251 // For efficiency strings representing integers exceeding 2^53 are not checked to see if they are canonical, 252 // i.e. the *Idx traps will receive "9007199254740993" as well as "9007199254740994", even though the former is not 253 // a canonical representation in ECMAScript (Number("9007199254740993") === 9007199254740992). 254 // See https://262.ecma-international.org/#sec-canonicalnumericindexstring 255 // If an *Idx trap is not set, the corresponding string one is used. 256 type ProxyTrapConfig struct { 257 // A trap for Object.getPrototypeOf, Reflect.getPrototypeOf, __proto__, Object.prototype.isPrototypeOf, instanceof 258 GetPrototypeOf func(target *Object) (prototype *Object) 259 260 // A trap for Object.setPrototypeOf, Reflect.setPrototypeOf 261 SetPrototypeOf func(target *Object, prototype *Object) (success bool) 262 263 // A trap for Object.isExtensible, Reflect.isExtensible 264 IsExtensible func(target *Object) (success bool) 265 266 // A trap for Object.preventExtensions, Reflect.preventExtensions 267 PreventExtensions func(target *Object) (success bool) 268 269 // A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (string properties) 270 GetOwnPropertyDescriptor func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) 271 272 // A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (integer properties) 273 GetOwnPropertyDescriptorIdx func(target *Object, prop int) (propertyDescriptor PropertyDescriptor) 274 275 // A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (Symbol properties) 276 GetOwnPropertyDescriptorSym func(target *Object, prop *Symbol) (propertyDescriptor PropertyDescriptor) 277 278 // A trap for Object.defineProperty, Reflect.defineProperty (string properties) 279 DefineProperty func(target *Object, key string, propertyDescriptor PropertyDescriptor) (success bool) 280 281 // A trap for Object.defineProperty, Reflect.defineProperty (integer properties) 282 DefinePropertyIdx func(target *Object, key int, propertyDescriptor PropertyDescriptor) (success bool) 283 284 // A trap for Object.defineProperty, Reflect.defineProperty (Symbol properties) 285 DefinePropertySym func(target *Object, key *Symbol, propertyDescriptor PropertyDescriptor) (success bool) 286 287 // A trap for the in operator, with operator, Reflect.has (string properties) 288 Has func(target *Object, property string) (available bool) 289 290 // A trap for the in operator, with operator, Reflect.has (integer properties) 291 HasIdx func(target *Object, property int) (available bool) 292 293 // A trap for the in operator, with operator, Reflect.has (Symbol properties) 294 HasSym func(target *Object, property *Symbol) (available bool) 295 296 // A trap for getting property values, Reflect.get (string properties) 297 Get func(target *Object, property string, receiver Value) (value Value) 298 299 // A trap for getting property values, Reflect.get (integer properties) 300 GetIdx func(target *Object, property int, receiver Value) (value Value) 301 302 // A trap for getting property values, Reflect.get (Symbol properties) 303 GetSym func(target *Object, property *Symbol, receiver Value) (value Value) 304 305 // A trap for setting property values, Reflect.set (string properties) 306 Set func(target *Object, property string, value Value, receiver Value) (success bool) 307 308 // A trap for setting property values, Reflect.set (integer properties) 309 SetIdx func(target *Object, property int, value Value, receiver Value) (success bool) 310 311 // A trap for setting property values, Reflect.set (Symbol properties) 312 SetSym func(target *Object, property *Symbol, value Value, receiver Value) (success bool) 313 314 // A trap for the delete operator, Reflect.deleteProperty (string properties) 315 DeleteProperty func(target *Object, property string) (success bool) 316 317 // A trap for the delete operator, Reflect.deleteProperty (integer properties) 318 DeletePropertyIdx func(target *Object, property int) (success bool) 319 320 // A trap for the delete operator, Reflect.deleteProperty (Symbol properties) 321 DeletePropertySym func(target *Object, property *Symbol) (success bool) 322 323 // A trap for Object.getOwnPropertyNames, Object.getOwnPropertySymbols, Object.keys, Reflect.ownKeys 324 OwnKeys func(target *Object) (object *Object) 325 326 // A trap for a function call, Function.prototype.apply, Function.prototype.call, Reflect.apply 327 Apply func(target *Object, this Value, argumentsList []Value) (value Value) 328 329 // A trap for the new operator, Reflect.construct 330 Construct func(target *Object, argumentsList []Value, newTarget *Object) (value *Object) 331 } 332 333 func (r *Runtime) newProxy(args []Value, proto *Object) *Object { 334 if len(args) >= 2 { 335 if target, ok := args[0].(*Object); ok { 336 if proxyHandler, ok := args[1].(*Object); ok { 337 return r.newProxyObject(target, proxyHandler, proto).val 338 } 339 } 340 } 341 panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler")) 342 } 343 344 func (r *Runtime) builtin_newProxy(args []Value, newTarget *Object) *Object { 345 if newTarget == nil { 346 panic(r.needNew("Proxy")) 347 } 348 return r.newProxy(args, r.getPrototypeFromCtor(newTarget, r.global.Proxy, r.global.ObjectPrototype)) 349 } 350 351 func (r *Runtime) NewProxy(target *Object, nativeHandler *ProxyTrapConfig) Proxy { 352 if p, ok := target.self.(*proxyObject); ok { 353 if p.handler == nil { 354 panic(r.NewTypeError("Cannot create proxy with a revoked proxy as target")) 355 } 356 } 357 handler := r.newNativeProxyHandler(nativeHandler) 358 proxy := r._newProxyObject(target, handler, nil) 359 return Proxy{proxy: proxy} 360 } 361 362 func (r *Runtime) builtin_proxy_revocable(call FunctionCall) Value { 363 if len(call.Arguments) >= 2 { 364 if target, ok := call.Argument(0).(*Object); ok { 365 if proxyHandler, ok := call.Argument(1).(*Object); ok { 366 proxy := r.newProxyObject(target, proxyHandler, nil) 367 revoke := r.newNativeFunc(func(FunctionCall) Value { 368 proxy.revoke() 369 return _undefined 370 }, nil, "", nil, 0) 371 ret := r.NewObject() 372 ret.self._putProp("proxy", proxy.val, true, true, true) 373 ret.self._putProp("revoke", revoke, true, true, true) 374 return ret 375 } 376 } 377 } 378 panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler")) 379 } 380 381 func (r *Runtime) createProxy(val *Object) objectImpl { 382 o := r.newNativeConstructOnly(val, r.builtin_newProxy, nil, "Proxy", 2) 383 384 o._putProp("revocable", r.newNativeFunc(r.builtin_proxy_revocable, nil, "revocable", nil, 2), true, false, true) 385 return o 386 } 387 388 func (r *Runtime) initProxy() { 389 r.global.Proxy = r.newLazyObject(r.createProxy) 390 r.addToGlobal("Proxy", r.global.Proxy) 391 }