ProxyConstructor.cs 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. using Jint.Collections;
  2. using Jint.Native.Function;
  3. using Jint.Native.Object;
  4. using Jint.Runtime;
  5. using Jint.Runtime.Descriptors;
  6. using Jint.Runtime.Interop;
  7. namespace Jint.Native.Proxy
  8. {
  9. public sealed class ProxyConstructor : FunctionInstance, IConstructor
  10. {
  11. private static readonly JsString _name = new JsString("Proxy");
  12. private static readonly JsString PropertyProxy = new JsString("proxy");
  13. private static readonly JsString PropertyRevoke = new JsString("revoke");
  14. private ProxyConstructor(Engine engine)
  15. : base(engine, _name)
  16. {
  17. }
  18. public static ProxyConstructor CreateProxyConstructor(Engine engine)
  19. {
  20. var obj = new ProxyConstructor(engine);
  21. obj._length = new PropertyDescriptor(2, PropertyFlag.Configurable);
  22. return obj;
  23. }
  24. public override JsValue Call(JsValue thisObject, JsValue[] arguments)
  25. {
  26. return ExceptionHelper.ThrowTypeError<JsValue>(_engine, "Constructor Proxy requires 'new'");
  27. }
  28. /// <summary>
  29. /// https://www.ecma-international.org/ecma-262/6.0/index.html#sec-proxy-object-internal-methods-and-internal-slots-construct-argumentslist-newtarget
  30. /// </summary>
  31. public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
  32. {
  33. var target = arguments.At(0);
  34. var handler = arguments.At(1);
  35. if (!target.IsObject() || !handler.IsObject())
  36. {
  37. return ExceptionHelper.ThrowTypeError<ObjectInstance>(_engine, "Cannot create proxy with a non-object as target or handler");
  38. }
  39. return Construct(target.AsObject(), handler.AsObject());
  40. }
  41. protected override void Initialize()
  42. {
  43. var properties = new PropertyDictionary(1, checkExistingKeys: false)
  44. {
  45. ["revocable"] = new PropertyDescriptor(new ClrFunctionInstance(_engine, "revocable", Revocable, 2, PropertyFlag.Configurable), true, true, true)
  46. };
  47. SetProperties(properties);
  48. }
  49. protected internal override ObjectInstance GetPrototypeOf()
  50. {
  51. return _engine.Function.Prototype;
  52. }
  53. public ProxyInstance Construct(ObjectInstance target, ObjectInstance handler)
  54. {
  55. if (target is ProxyInstance targetProxy && targetProxy._handler is null)
  56. {
  57. ExceptionHelper.ThrowTypeError(_engine);
  58. }
  59. if (handler is ProxyInstance handlerProxy && handlerProxy._handler is null)
  60. {
  61. ExceptionHelper.ThrowTypeError(_engine);
  62. }
  63. var instance = new ProxyInstance(Engine, target, handler);
  64. return instance;
  65. }
  66. private JsValue Revocable(JsValue thisObject, JsValue[] arguments)
  67. {
  68. var p = Construct(arguments, thisObject);
  69. System.Func<JsValue, JsValue[], JsValue> revoke = (JsValue thisObject, JsValue[] arguments) =>
  70. {
  71. var proxy = (ProxyInstance) p;
  72. proxy._handler = null;
  73. proxy._target = null;
  74. return Undefined;
  75. };
  76. var result = _engine.Object.Construct(System.Array.Empty<JsValue>());
  77. result.DefineOwnProperty(PropertyRevoke, new PropertyDescriptor(new ClrFunctionInstance(_engine, name: null, revoke, 0, PropertyFlag.Configurable), PropertyFlag.ConfigurableEnumerableWritable));
  78. result.DefineOwnProperty(PropertyProxy, new PropertyDescriptor(p, PropertyFlag.ConfigurableEnumerableWritable));
  79. return result;
  80. }
  81. }
  82. }