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  }