"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _realm = require("../realm.js");

var _index = require("./index.js");

var _invariant = require("../invariant.js");

var _invariant2 = _interopRequireDefault(_invariant);

var _abstract = require("../methods/abstract.js");

var _get = require("../methods/get.js");

var _is = require("../methods/is.js");

var _singletons = require("../singletons.js");

var _call = require("../methods/call.js");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * Copyright (c) 2017-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

function FindPropertyKey(realm, keys, key) {
  for (let i = 0; i < keys.length; ++i) {
    if ((0, _abstract.SamePropertyKey)(realm, key, keys[i])) {
      return i;
    }
  }
  return -1;
}

class ProxyValue extends _index.ObjectValue {

  constructor(realm) {
    super(realm);
  }

  getTrackedPropertyNames() {
    return ProxyValue.trackedPropertyNames;
  }

  isSimpleObject() {
    return false;
  }

  // ECMA262 9.5.1
  $GetPrototypeOf() {
    let realm = this.$Realm;

    // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 2. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 3. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected an object");

    // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;
    (0, _invariant2.default)(target instanceof _index.ObjectValue);

    // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
    let trap = (0, _get.GetMethod)(realm, handler, "getPrototypeOf");

    // 6. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[GetPrototypeOf]]().
      return target.$GetPrototypeOf();
    }

    // 7. Let handlerProto be ? Call(trap, handler, « target »).
    let handlerProto = (0, _call.Call)(realm, trap, handler, [target]);

    // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError exception.
    if (!(handlerProto instanceof _index.ObjectValue) && !(handlerProto instanceof _index.NullValue)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 9. Let extensibleTarget be ? IsExtensible(target).
    let extensibleTarget = (0, _is.IsExtensible)(realm, target);

    // 10. If extensibleTarget is true, return handlerProto.
    if (extensibleTarget) return handlerProto;

    // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
    let targetProto = target.$GetPrototypeOf();

    // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception.
    if (!(0, _abstract.SameValuePartial)(realm, handlerProto, targetProto)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 13. Return handlerProto.
    return handlerProto;
  }

  // ECMA262 9.5.2
  $SetPrototypeOf(V) {
    let realm = this.$Realm;

    // 1. Assert: Either Type(V) is Object or Type(V) is Null.
    (0, _invariant2.default)(V instanceof _index.ObjectValue || V instanceof _index.NullValue, "expected object or null");

    // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 3. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;
    (0, _invariant2.default)(target instanceof _index.ObjectValue);

    // 6. Let trap be ? GetMethod(handler, "setPrototypeOf").
    let trap = (0, _get.GetMethod)(realm, handler, "setPrototypeOf");

    // 7. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[SetPrototypeOf]](V).
      return target.$SetPrototypeOf(V);
    }

    // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, V »)).
    let booleanTrapResult = _singletons.To.ToBooleanPartial(realm, (0, _call.Call)(realm, trap, handler, [target, V]));

    // 9. If booleanTrapResult is false, return false.
    if (!booleanTrapResult) return false;

    // 10. Let extensibleTarget be ? IsExtensible(target).
    let extensibleTarget = (0, _is.IsExtensible)(realm, target);

    // 11. If extensibleTarget is true, return true.
    if (extensibleTarget) return true;

    // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
    let targetProto = target.$GetPrototypeOf();

    // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
    if (!(0, _abstract.SameValuePartial)(realm, V, targetProto)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 14. Return true.
    return true;
  }

  // ECMA262 9.5.3
  $IsExtensible() {
    let realm = this.$Realm;

    // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 2. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 3. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;

    // 5. Let trap be ? GetMethod(handler, "isExtensible").
    let trap = (0, _get.GetMethod)(realm, handler, "isExtensible");

    // 6. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[IsExtensible]]().
      (0, _invariant2.default)(target instanceof _index.ObjectValue);
      return target.$IsExtensible();
    }

    // 7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target »)).
    let booleanTrapResult = _singletons.To.ToBooleanPartial(realm, (0, _call.Call)(realm, trap, handler, [target]));

    // 8. Let targetResult be ? target.[[IsExtensible]]().
    (0, _invariant2.default)(target instanceof _index.ObjectValue);
    let targetResult = target.$IsExtensible();

    // 9. If SameValue(booleanTrapResult, targetResult) is false, throw a TypeError exception.
    if (booleanTrapResult !== targetResult) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 10. Return booleanTrapResult.
    return booleanTrapResult;
  }

  // ECMA262 9.5.4
  $PreventExtensions() {
    let realm = this.$Realm;

    // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 2. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 3. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;

    // 5. Let trap be ? GetMethod(handler, "preventExtensions").
    let trap = (0, _get.GetMethod)(realm, handler, "preventExtensions");

    // 6. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[PreventExtensions]]().
      (0, _invariant2.default)(target instanceof _index.ObjectValue);
      return target.$PreventExtensions();
    }

    // 7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target »)).
    let booleanTrapResult = _singletons.To.ToBooleanPartial(realm, (0, _call.Call)(realm, trap, handler, [target]));

    // 8. If booleanTrapResult is true, then
    if (booleanTrapResult) {
      // a. Let targetIsExtensible be ? target.[[IsExtensible]]().
      (0, _invariant2.default)(target instanceof _index.ObjectValue);
      let targetIsExtensible = target.$IsExtensible();

      // b. If targetIsExtensible is true, throw a TypeError exception.
      if (targetIsExtensible) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
      }
    }

    // 9. Return booleanTrapResult.
    return booleanTrapResult;
  }

  // ECMA262 9.5.5
  $GetOwnProperty(P) {
    let realm = this.$Realm;

    // 1. Assert: IsPropertyKey(P) is true.
    (0, _invariant2.default)((0, _is.IsPropertyKey)(realm, P), "expected property key");

    // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 3. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;
    (0, _invariant2.default)(target instanceof _index.ObjectValue);

    // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
    let trap = (0, _get.GetMethod)(realm, handler, "getOwnPropertyDescriptor");

    // 7. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[GetOwnProperty]](P).
      return target.$GetOwnProperty(P);
    }

    // 8. Let trapResultObj be ? Call(trap, handler, « target, P »).
    let trapResultObj = (0, _call.Call)(realm, trap, handler, [target, typeof P === "string" ? new _index.StringValue(realm, P) : P]);

    // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a TypeError exception.
    if (!(trapResultObj instanceof _index.ObjectValue) && !(trapResultObj instanceof _index.UndefinedValue)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
    let targetDesc = target.$GetOwnProperty(P);

    // 11. If trapResultObj is undefined, then
    if (trapResultObj instanceof _index.UndefinedValue) {
      // a. If targetDesc is undefined, return undefined.
      if (!targetDesc) return undefined;
      _singletons.Properties.ThrowIfMightHaveBeenDeleted(targetDesc.value);

      // b. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
      if (!targetDesc.configurable) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
      }

      // c. Let extensibleTarget be ? IsExtensible(target).
      let extensibleTarget = (0, _is.IsExtensible)(realm, target);

      // d. Assert: Type(extensibleTarget) is Boolean.
      (0, _invariant2.default)(typeof extensibleTarget === "boolean", "expected boolean");

      // e. If extensibleTarget is false, throw a TypeError exception.
      if (!extensibleTarget) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
      }

      // f. Return undefined.
      return undefined;
    }

    // 12. Let extensibleTarget be ? IsExtensible(target).
    let extensibleTarget = (0, _is.IsExtensible)(realm, target);

    // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
    let resultDesc = _singletons.To.ToPropertyDescriptor(realm, trapResultObj);

    // 14. Call CompletePropertyDescriptor(resultDesc).
    _singletons.Properties.CompletePropertyDescriptor(realm, resultDesc);

    // 15. Let valid be IsCompatiblePropertyDescriptor(extensibleTarget, resultDesc, targetDesc).
    let valid = _singletons.Properties.IsCompatiblePropertyDescriptor(realm, extensibleTarget, resultDesc, targetDesc);

    // 16. If valid is false, throw a TypeError exception.
    if (!valid) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 17. If resultDesc.[[Configurable]] is false, then
    if (!resultDesc.configurable) {
      // a. If targetDesc is undefined or targetDesc.[[Configurable]] is true, then
      if (!targetDesc || targetDesc.configurable) {
        // i. Throw a TypeError exception.
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
      }
    }

    // 18. Return resultDesc.
    return resultDesc;
  }

  // ECMA262 9.5.6
  $DefineOwnProperty(P, Desc) {
    let realm = this.$Realm;

    // 1. Assert: IsPropertyKey(P) is true.
    (0, _invariant2.default)((0, _is.IsPropertyKey)(realm, P), "expected property key");

    // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 3. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;
    (0, _invariant2.default)(target instanceof _index.ObjectValue);

    // 6. Let trap be ? GetMethod(handler, "defineProperty").
    let trap = (0, _get.GetMethod)(realm, handler, "defineProperty");

    // 7. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[DefineOwnProperty]](P, Desc).
      return target.$DefineOwnProperty(P, Desc);
    }

    // 8. Let descObj be FromPropertyDescriptor(Desc).
    let descObj = _singletons.Properties.FromPropertyDescriptor(realm, Desc);

    // 9. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P, descObj »)).
    let booleanTrapResult = _singletons.To.ToBooleanPartial(realm, (0, _call.Call)(realm, trap, handler, [target, typeof P === "string" ? new _index.StringValue(realm, P) : P, descObj]));

    // 10. If booleanTrapResult is false, return false.
    if (!booleanTrapResult) return false;

    // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
    let targetDesc = target.$GetOwnProperty(P);

    // 12. Let extensibleTarget be ? IsExtensible(target).
    let extensibleTarget = (0, _is.IsExtensible)(realm, target);

    // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] is false, then
    let settingConfigFalse;
    if ("configurable" in Desc && !Desc.configurable) {
      // a. Let settingConfigFalse be true.
      settingConfigFalse = true;
    } else {
      // 14. Else let settingConfigFalse be false.
      settingConfigFalse = false;
    }

    // 15. If targetDesc is undefined, then
    if (!targetDesc) {
      // a. If extensibleTarget is false, throw a TypeError exception.
      if (!extensibleTarget) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
      }

      // b. If settingConfigFalse is true, throw a TypeError exception.
      if (settingConfigFalse) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
      }
    } else {
      // 16. Else targetDesc is not undefined,
      _singletons.Properties.ThrowIfMightHaveBeenDeleted(targetDesc.value);

      // a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, targetDesc) is false, throw a TypeError exception.
      if (!_singletons.Properties.IsCompatiblePropertyDescriptor(realm, extensibleTarget, Desc, targetDesc)) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
      }

      // b. If settingConfigFalse is true and targetDesc.[[Configurable]] is true, throw a TypeError exception.
      if (settingConfigFalse && targetDesc.configurable) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
      }
    }

    // 17. Return true.
    return true;
  }

  // ECMA262 9.5.7
  $HasProperty(P) {
    let realm = this.$Realm;

    // 1. Assert: IsPropertyKey(P) is true.
    (0, _invariant2.default)((0, _is.IsPropertyKey)(realm, P), "expected property key");

    // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 3. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;
    (0, _invariant2.default)(target instanceof _index.ObjectValue);

    // 6. Let trap be ? GetMethod(handler, "has").
    let trap = (0, _get.GetMethod)(realm, handler, "has");

    // 7. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[HasProperty]](P).
      return target.$HasProperty(P);
    }

    // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P »)).
    let booleanTrapResult = _singletons.To.ToBooleanPartial(realm, (0, _call.Call)(realm, trap, handler, [target, typeof P === "string" ? new _index.StringValue(realm, P) : P]));

    // 9. If booleanTrapResult is false, then
    if (!booleanTrapResult) {
      // a. Let targetDesc be ? target.[[GetOwnProperty]](P).
      let targetDesc = target.$GetOwnProperty(P);

      // b. If targetDesc is not undefined, then
      if (targetDesc) {
        _singletons.Properties.ThrowIfMightHaveBeenDeleted(targetDesc.value);

        // i. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
        if (!targetDesc.configurable) {
          throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
        }

        // ii. Let extensibleTarget be ? IsExtensible(target).
        let extensibleTarget = (0, _is.IsExtensible)(realm, target);

        // iii. If extensibleTarget is false, throw a TypeError exception.
        if (!extensibleTarget) {
          throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
        }
      }
    }

    // 10. Return booleanTrapResult.
    return booleanTrapResult;
  }

  // ECMA262 9.5.8
  $Get(P, Receiver) {
    let realm = this.$Realm;

    // 1. Assert: IsPropertyKey(P) is true.
    (0, _invariant2.default)((0, _is.IsPropertyKey)(realm, P), "expected property key");

    // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 3. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;
    (0, _invariant2.default)(target instanceof _index.ObjectValue);

    // 6. Let trap be ? GetMethod(handler, "get").
    let trap = (0, _get.GetMethod)(realm, handler, "get");

    // 7. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[Get]](P, Receiver).
      return target.$Get(P, Receiver);
    }

    // 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »).
    let trapResult = (0, _call.Call)(realm, trap, handler, [target, typeof P === "string" ? new _index.StringValue(realm, P) : P, Receiver]);

    // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
    let targetDesc = target.$GetOwnProperty(P);

    // 10. If targetDesc is not undefined, then
    if (targetDesc) {
      _singletons.Properties.ThrowIfMightHaveBeenDeleted(targetDesc.value);

      // a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Configurable]] is false and targetDesc.[[Writable]] is false, then
      if ((0, _is.IsDataDescriptor)(realm, targetDesc) && targetDesc.configurable === false && targetDesc.writable === false) {
        // i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a TypeError exception.
        let targetValue = targetDesc.value || realm.intrinsics.undefined;
        (0, _invariant2.default)(targetValue instanceof _index.Value);
        if (!(0, _abstract.SameValuePartial)(realm, trapResult, targetValue)) {
          throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
        }
      }

      // b. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Configurable]] is false and targetDesc.[[Get]] is undefined, then
      if ((0, _is.IsAccessorDescriptor)(realm, targetDesc) && targetDesc.configurable === false && (!targetDesc.get || targetDesc.get instanceof _index.UndefinedValue)) {
        // i. If trapResult is not undefined, throw a TypeError exception.
        if (!(trapResult instanceof _index.UndefinedValue)) {
          throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
        }
      }
    }

    // 11. Return trapResult.
    return trapResult;
  }

  // ECMA262 9.5.9
  $Set(P, V, Receiver) {
    let realm = this.$Realm;

    // 1. Assert: IsPropertyKey(P) is true.
    (0, _invariant2.default)((0, _is.IsPropertyKey)(realm, P), "expected property key");

    // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 3. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;

    // 6. Let trap be ? GetMethod(handler, "set").
    let trap = (0, _get.GetMethod)(realm, handler, "set");

    // 7. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[Set]](P, V, Receiver).
      (0, _invariant2.default)(target instanceof _index.ObjectValue);
      return target.$Set(P, V, Receiver);
    }

    // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P, V, Receiver »)).
    let booleanTrapResult = _singletons.To.ToBooleanPartial(realm, (0, _call.Call)(realm, trap, handler, [target, typeof P === "string" ? new _index.StringValue(realm, P) : P, V, Receiver]));

    // 9. If booleanTrapResult is false, return false.
    if (!booleanTrapResult) return false;

    // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
    (0, _invariant2.default)(target instanceof _index.ObjectValue);
    let targetDesc = target.$GetOwnProperty(P);

    // 11. If targetDesc is not undefined, then
    if (targetDesc) {
      _singletons.Properties.ThrowIfMightHaveBeenDeleted(targetDesc.value);

      // a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Configurable]] is false and targetDesc.[[Writable]] is false, then
      if ((0, _is.IsDataDescriptor)(realm, targetDesc) && !targetDesc.configurable && !targetDesc.writable) {
        // i. If SameValue(V, targetDesc.[[Value]]) is false, throw a TypeError exception.
        let targetValue = targetDesc.value || realm.intrinsics.undefined;
        (0, _invariant2.default)(targetValue instanceof _index.Value);
        if (!(0, _abstract.SameValuePartial)(realm, V, targetValue)) {
          throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
        }
      }

      // b. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Configurable]] is false, then
      if ((0, _is.IsAccessorDescriptor)(realm, targetDesc) && !targetDesc.configurable) {
        // i. If targetDesc.[[Set]] is undefined, throw a TypeError exception.
        if (!targetDesc.set || targetDesc.set instanceof _index.UndefinedValue) {
          throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
        }
      }
    }

    // 12. Return true.
    return true;
  }

  // ECMA262 9.5.10
  $Delete(P) {
    let realm = this.$Realm;

    // 1. Assert: IsPropertyKey(P) is true.
    (0, _invariant2.default)((0, _is.IsPropertyKey)(realm, P), "expected property key");

    // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 3. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;

    // 6. Let trap be ? GetMethod(handler, "deleteProperty").
    let trap = (0, _get.GetMethod)(realm, handler, "deleteProperty");

    // 7. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[Delete]](P).
      (0, _invariant2.default)(target instanceof _index.ObjectValue);
      return target.$Delete(P);
    }

    // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P »)).
    let booleanTrapResult = _singletons.To.ToBooleanPartial(realm, (0, _call.Call)(realm, trap, handler, [target, typeof P === "string" ? new _index.StringValue(realm, P) : P]));

    // 9. If booleanTrapResult is false, return false.
    if (!booleanTrapResult) return false;

    // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
    (0, _invariant2.default)(target instanceof _index.ObjectValue);
    let targetDesc = target.$GetOwnProperty(P);

    // 11. If targetDesc is undefined, return true.
    if (!targetDesc) return true;
    _singletons.Properties.ThrowIfMightHaveBeenDeleted(targetDesc.value);

    // 12. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
    if (!targetDesc.configurable) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 13. Return true.
    return true;
  }

  // ECMA262 9.5.11
  $OwnPropertyKeys() {
    let realm = this.$Realm;

    // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
    let handler = this.$ProxyHandler;

    // 2. If handler is null, throw a TypeError exception.
    if (handler instanceof _index.NullValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 3. Assert: Type(handler) is Object.
    (0, _invariant2.default)(handler instanceof _index.ObjectValue, "expected object");

    // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
    let target = this.$ProxyTarget;
    (0, _invariant2.default)(target instanceof _index.ObjectValue);

    // 5. Let trap be ? GetMethod(handler, "ownKeys").
    let trap = (0, _get.GetMethod)(realm, handler, "ownKeys");

    // 6. If trap is undefined, then
    if (trap instanceof _index.UndefinedValue) {
      // a. Return ? target.[[OwnPropertyKeys]]().
      return target.$OwnPropertyKeys();
    }

    // 7. Let trapResultArray be ? Call(trap, handler, « target »).
    let trapResultArray = (0, _call.Call)(realm, trap, handler, [target]);

    // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, « String, Symbol »).
    let trapResult = _singletons.Create.CreateListFromArrayLike(realm, trapResultArray, ["String", "Symbol"]);

    // 9. Let extensibleTarget be ? IsExtensible(target).
    let extensibleTarget = (0, _is.IsExtensible)(realm, target);

    // 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
    let targetKeys = target.$OwnPropertyKeys();

    // 11. Assert: targetKeys is a List containing only String and Symbol values.
    for (let key of targetKeys) {
      (0, _invariant2.default)(key instanceof _index.SymbolValue || key instanceof _index.StringValue, "expected string or symbol");
    }

    // 12. Let targetConfigurableKeys be a new empty List.
    let targetConfigurableKeys = [];

    // 13. Let targetNonconfigurableKeys be a new empty List.
    let targetNonconfigurableKeys = [];

    // 14. Repeat, for each element key of targetKeys,
    for (let key of targetKeys) {
      // a. Let desc be ? target.[[GetOwnProperty]](key).
      let desc = target.$GetOwnProperty(key);
      if (desc) _singletons.Properties.ThrowIfMightHaveBeenDeleted(desc.value);

      // b. If desc is not undefined and desc.[[Configurable]] is false, then
      if (desc && desc.configurable === false) {
        // i. Append key as an element of targetNonconfigurableKeys.
        targetNonconfigurableKeys.push(key);
      } else {
        // c. Else,
        // i. Append key as an element of targetConfigurableKeys.
        targetConfigurableKeys.push(key);
      }
    }

    // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty, then
    if (extensibleTarget && !targetNonconfigurableKeys.length) {
      // a. Return trapResult.
      return trapResult;
    }

    // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
    let uncheckedResultKeys = trapResult.slice();

    // 17. Repeat, for each key that is an element of targetNonconfigurableKeys,
    for (let key of targetNonconfigurableKeys) {
      // a. If key is not an element of uncheckedResultKeys, throw a TypeError exception.
      let index = FindPropertyKey(realm, uncheckedResultKeys, key);
      if (index < 0) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "key is not an element of uncheckedResultKeys");
      }

      // b. Remove key from uncheckedResultKeys.
      uncheckedResultKeys.splice(index, 1);
    }

    // 18. If extensibleTarget is true, return trapResult.
    if (extensibleTarget) return trapResult;

    // 19. Repeat, for each key that is an element of targetConfigurableKeys,
    for (let key of targetConfigurableKeys) {
      // a. If key is not an element of uncheckedResultKeys, throw a TypeError exception.
      let index = FindPropertyKey(realm, uncheckedResultKeys, key);
      if (index < 0) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "key is not an element of uncheckedResultKeys");
      }

      // b. Remove key from uncheckedResultKeys.
      uncheckedResultKeys.splice(index, 1);
    }

    // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
    if (uncheckedResultKeys.length) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 21. Return trapResult.
    return trapResult;
  }
}
exports.default = ProxyValue;
ProxyValue.trackedPropertyNames = _index.ObjectValue.trackedPropertyNames.concat(["$ProxyTarget", "$ProxyHandler"]);
//# sourceMappingURL=ProxyValue.js.map