using Jint.Collections; using Jint.Native.Function; using Jint.Native.Object; using Jint.Runtime; using Jint.Runtime.Descriptors; using Jint.Runtime.Interop; namespace Jint.Native.Proxy { public sealed class ProxyConstructor : FunctionInstance, IConstructor { private static readonly JsString _name = new JsString("Proxy"); private static readonly JsString PropertyProxy = new JsString("proxy"); private static readonly JsString PropertyRevoke = new JsString("revoke"); internal ProxyConstructor( Engine engine, Realm realm) : base(engine, realm, _name) { _length = new PropertyDescriptor(2, PropertyFlag.Configurable); } public override JsValue Call(JsValue thisObject, JsValue[] arguments) { ExceptionHelper.ThrowTypeError(_realm, "Constructor Proxy requires 'new'"); return null; } /// /// https://www.ecma-international.org/ecma-262/6.0/index.html#sec-proxy-object-internal-methods-and-internal-slots-construct-argumentslist-newtarget /// public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget) { var target = arguments.At(0); var handler = arguments.At(1); if (!target.IsObject() || !handler.IsObject()) { ExceptionHelper.ThrowTypeError(_realm, "Cannot create proxy with a non-object as target or handler"); } return Construct(target.AsObject(), handler.AsObject()); } protected override void Initialize() { var properties = new PropertyDictionary(1, checkExistingKeys: false) { ["revocable"] = new PropertyDescriptor(new ClrFunctionInstance(_engine, "revocable", Revocable, 2, PropertyFlag.Configurable), true, true, true) }; SetProperties(properties); } protected internal override ObjectInstance GetPrototypeOf() { return _realm.Intrinsics.Function.Prototype; } public ProxyInstance Construct(ObjectInstance target, ObjectInstance handler) { if (target is ProxyInstance targetProxy && targetProxy._handler is null) { ExceptionHelper.ThrowTypeError(_realm); } if (handler is ProxyInstance handlerProxy && handlerProxy._handler is null) { ExceptionHelper.ThrowTypeError(_realm); } var instance = new ProxyInstance(Engine, target, handler); return instance; } private JsValue Revocable(JsValue thisObject, JsValue[] arguments) { var p = Construct(arguments, thisObject); System.Func revoke = (JsValue thisObject, JsValue[] arguments) => { var proxy = (ProxyInstance) p; proxy._handler = null; proxy._target = null; return Undefined; }; var result = _realm.Intrinsics.Object.Construct(System.Array.Empty()); result.DefineOwnProperty(PropertyRevoke, new PropertyDescriptor(new ClrFunctionInstance(_engine, name: null, revoke, 0, PropertyFlag.Configurable), PropertyFlag.ConfigurableEnumerableWritable)); result.DefineOwnProperty(PropertyProxy, new PropertyDescriptor(p, PropertyFlag.ConfigurableEnumerableWritable)); return result; } } }