"use strict";

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

exports.default = function (realm) {
  // ECMA262 19.1.1.1
  let func = new _index2.NativeFunctionValue(realm, "Object", "Object", 1, (context, [value], argCount, NewTarget) => {
    // 1. If NewTarget is neither undefined nor the active function, then
    if (NewTarget && NewTarget !== func) {
      // a. Return ? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
      return _singletons.Create.OrdinaryCreateFromConstructor(realm, NewTarget, "ObjectPrototype");
    }

    // 2. If value is null, undefined or not supplied, return ObjectCreate(%ObjectPrototype%).
    if ((0, _index3.HasSomeCompatibleType)(value, _index2.NullValue, _index2.UndefinedValue)) {
      return _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype);
    }

    // 3. Return ToObject(value).
    return _singletons.To.ToObjectPartial(realm, value);
  });

  // ECMA262 19.1.2.1
  let ObjectAssign = func.defineNativeMethod("assign", 2, (context, [target, ...sources]) => {
    // 1. Let to be ? ToObject(target).
    let to = _singletons.To.ToObjectPartial(realm, target);
    let to_must_be_partial = false;

    // 2. If only one argument was passed, return to.
    if (!sources.length) return to;

    // 3. Let sources be the List of argument values starting with the second argument.
    sources;
    let delayedSources = [];

    // 4. For each element nextSource of sources, in ascending index order,
    for (let nextSource of sources) {
      let keys, frm, frmSnapshot;

      // a. If nextSource is undefined or null, let keys be a new empty List.
      if ((0, _index3.HasSomeCompatibleType)(nextSource, _index2.NullValue, _index2.UndefinedValue)) continue;

      // b. Else,
      // i. Let from be ToObject(nextSource).
      frm = _singletons.To.ToObjectPartial(realm, nextSource);

      // ii. Let keys be ? from.[[OwnPropertyKeys]]().
      let frm_was_partial = frm.isPartialObject();
      if (frm_was_partial) {
        if (!to.isSimpleObject() || !frm.isSimpleObject()) {
          // If an object is not a simple object, it may have getters on it that can
          // mutate any state as a result. We don't yet support this.
          _index2.AbstractValue.reportIntrospectionError(nextSource);
          throw new _errors.FatalError();
        }

        to_must_be_partial = true;
        // Make this temporarily not partial
        // so that we can call frm.$OwnPropertyKeys below.
        frm.makeNotPartial();
      }
      keys = frm.$OwnPropertyKeys();

      if (to_must_be_partial) {
        if (to instanceof _index2.AbstractObjectValue && to.values.isTop()) {
          // We don't know which objects to make partial and making all objects partial is failure in itself
          _index2.AbstractValue.reportIntrospectionError(to);
          throw new _errors.FatalError();
        } else {
          // if to has properties, we better remove them because after the temporal call to Object.assign we don't know their values anymore
          if (to.hasStringOrSymbolProperties()) {
            // preserve them in a snapshot and add the snapshot to the sources
            delayedSources.push(to.getSnapshot({ removeProperties: true }));
          }

          if (frm_was_partial) {
            frmSnapshot = frm.getSnapshot();
            frm.temporalAlias = frmSnapshot;
            frm.makePartial();
            delayedSources.push(frmSnapshot);
          }
        }
      }

      // c. Repeat for each element nextKey of keys in List order,
      (0, _invariant2.default)(frm, "from required");
      (0, _invariant2.default)(keys, "keys required");
      copyKeys(keys, frm, to);
    }

    // 5. Return to.
    if (to_must_be_partial) {
      // if to has properties, we copy and delay them (at this stage we do not need to remove them)
      if (to.hasStringOrSymbolProperties()) {
        let toSnapshot = to.getSnapshot();
        delayedSources.push(toSnapshot);
      }

      to.makePartial();

      // We already established above that to is simple,
      // but now that it is partial we need to set the _isSimple flag.
      to.makeSimple();

      // Tell serializer that it may add properties to to only after temporalTo has been emitted
      let temporalTo = _index2.AbstractValue.createTemporalFromBuildFunction(realm, _index2.ObjectValue, [ObjectAssign, to, ...delayedSources], ([methodNode, targetNode, ...sourceNodes]) => {
        return t.callExpression(methodNode, [targetNode, ...sourceNodes]);
      }, { skipInvariant: true });
      (0, _invariant2.default)(temporalTo instanceof _index2.AbstractObjectValue);
      if (to instanceof _index2.AbstractObjectValue) {
        temporalTo.values = to.values;
      } else {
        (0, _invariant2.default)(to instanceof _index2.ObjectValue);
        temporalTo.values = new _index.ValuesDomain(to);
      }
      to.temporalAlias = temporalTo;
    }
    return to;
  });

  function copyKeys(keys, from, to) {
    // c. Repeat for each element nextKey of keys in List order,
    for (let nextKey of keys) {
      // i. Let desc be ? from.[[GetOwnProperty]](nextKey).
      let desc = from.$GetOwnProperty(nextKey);

      // ii. If desc is not undefined and desc.[[Enumerable]] is true, then
      if (desc && desc.enumerable) {
        _singletons.Properties.ThrowIfMightHaveBeenDeleted(desc.value);

        // 1. Let propValue be ? Get(from, nextKey).
        let propValue = (0, _index3.Get)(realm, from, nextKey);

        // 2. Perform ? Set(to, nextKey, propValue, true).
        _singletons.Properties.Set(realm, to, nextKey, propValue, true);
      }
    }
  }

  // ECMA262 19.1.2.2
  func.defineNativeMethod("create", 2, (context, [O, Properties]) => {
    // 1. If Type(O) is neither Object nor Null, throw a TypeError exception.
    if (!(0, _index3.HasSomeCompatibleType)(O, _index2.ObjectValue, _index2.NullValue)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 2. Let obj be ObjectCreate(O).
    let obj = _singletons.Create.ObjectCreate(realm, O.throwIfNotConcrete());

    // 3. If Properties is not undefined, then
    if (!Properties.mightBeUndefined()) {
      // a. Return ? ObjectDefineProperties(obj, Properties).
      return _singletons.Properties.ObjectDefineProperties(realm, obj, Properties);
    }
    Properties.throwIfNotConcrete();

    // 4. Return obj.
    return obj;
  });

  // ECMA262 19.1.2.3
  func.defineNativeMethod("defineProperties", 2, (context, [O, Properties]) => {
    // 1. Return ? ObjectDefineProperties(O, Properties).
    return _singletons.Properties.ObjectDefineProperties(realm, O, Properties);
  });

  // ECMA262 19.1.2.4
  func.defineNativeMethod("defineProperty", 3, (context, [O, P, Attributes]) => {
    // 1. If Type(O) is not Object, throw a TypeError exception.
    if (!O.mightBeObject()) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }
    O = O.throwIfNotObject();

    // 2. Let key be ? ToPropertyKey(P).
    let key = _singletons.To.ToPropertyKey(realm, P.throwIfNotConcrete());

    // 3. Let desc be ? ToPropertyDescriptor(Attributes).
    let desc = _singletons.To.ToPropertyDescriptor(realm, Attributes);

    // 4. Perform ? DefinePropertyOrThrow(O, key, desc).
    _singletons.Properties.DefinePropertyOrThrow(realm, O, key, desc);

    // 4. Return O.
    return O;
  });

  // ECMA262 19.1.2.5
  func.defineNativeMethod("freeze", 1, (context, [O]) => {
    // 1. If Type(O) is not Object, return O.
    if (!O.mightBeObject()) return O;

    // 2. Let status be ? SetIntegrityLevel(O, "frozen").
    O = O.throwIfNotConcreteObject();
    let status = (0, _index3.SetIntegrityLevel)(realm, O, "frozen");

    // 3. If status is false, throw a TypeError exception.
    if (status === false) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Return O.
    return O;
  });

  // ECMA262 19.1.2.6
  func.defineNativeMethod("getOwnPropertyDescriptor", 2, (context, [O, P]) => {
    // 1. Let obj be ? ToObject(O).
    let obj = _singletons.To.ToObjectPartial(realm, O);

    // 2. Let key be ? ToPropertyKey(P).
    let key = _singletons.To.ToPropertyKey(realm, P.throwIfNotConcrete());

    // 3. Let desc be ? obj.[[GetOwnProperty]](key).
    let desc = obj.$GetOwnProperty(key);

    // 4. Return FromPropertyDescriptor(desc).
    return _singletons.Properties.FromPropertyDescriptor(realm, desc);
  });

  // ECMA262 19.1.2.7
  func.defineNativeMethod("getOwnPropertyNames", 1, (context, [O]) => {
    // 1. Return ? GetOwnPropertyKeys(O, String).
    return (0, _index3.GetOwnPropertyKeys)(realm, O, _index2.StringValue);
  });

  // ECMA262 19.1.2.8
  func.defineNativeMethod("getOwnPropertyDescriptors", 1, (context, [O]) => {
    // 1. Let obj be ? ToObject(O).
    let obj = _singletons.To.ToObject(realm, O.throwIfNotConcrete());

    // 2. Let ownKeys be ? obj.[[OwnPropertyKeys]]().
    let ownKeys = obj.$OwnPropertyKeys();

    // 3. Let descriptors be ! ObjectCreate(%ObjectPrototype%).
    let descriptors = _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype);

    // 4. Repeat, for each element key of ownKeys in List order,
    for (let key of ownKeys) {
      // a. Let desc be ? obj.[[GetOwnProperty]](key).
      let desc = obj.$GetOwnProperty(key);
      if (desc !== undefined) _singletons.Properties.ThrowIfMightHaveBeenDeleted(desc.value);

      // b. Let descriptor be ! FromPropertyDescriptor(desc).
      let descriptor = _singletons.Properties.FromPropertyDescriptor(realm, desc);

      // c. If descriptor is not undefined, perform ! CreateDataProperty(descriptors, key, descriptor).
      if (!(descriptor instanceof _index2.UndefinedValue)) _singletons.Create.CreateDataProperty(realm, descriptors, key, descriptor);
    }

    // 5. Return descriptors.
    return descriptors;
  });

  // ECMA262 19.1.2.9
  func.defineNativeMethod("getOwnPropertySymbols", 1, (context, [O]) => {
    // Return ? GetOwnPropertyKeys(O, Symbol).
    return (0, _index3.GetOwnPropertyKeys)(realm, O, _index2.SymbolValue);
  });

  // ECMA262 19.1.2.10
  func.defineNativeMethod("getPrototypeOf", 1, (context, [O]) => {
    // 1. Let obj be ? ToObject(O).
    let obj = _singletons.To.ToObjectPartial(realm, O);

    // 2. Return ? obj.[[GetPrototypeOf]]().
    return obj.$GetPrototypeOf();
  });

  // ECMA262 19.1.2.11
  func.defineNativeMethod("is", 2, (context, [value1, value2]) => {
    // 1. Return SameValue(value1, value2).
    return new _index2.BooleanValue(realm, (0, _index3.SameValuePartial)(realm, value1, value2));
  });

  // ECMA262 19.1.2.12
  func.defineNativeMethod("isExtensible", 1, (context, [O]) => {
    // 1. If Type(O) is not Object, return false.
    if (!O.mightBeObject()) return realm.intrinsics.false;
    O = O.throwIfNotObject();

    // 2. Return ? IsExtensible(O).
    return new _index2.BooleanValue(realm, (0, _index3.IsExtensible)(realm, O));
  });

  // ECMA262 19.1.2.13
  func.defineNativeMethod("isFrozen", 1, (context, [O]) => {
    // 1. If Type(O) is not Object, return true.
    if (!O.mightBeObject()) return realm.intrinsics.true;

    // 2. Return ? TestIntegrityLevel(O, "frozen").
    O = O.throwIfNotConcreteObject();
    return new _index2.BooleanValue(realm, (0, _index3.TestIntegrityLevel)(realm, O, "frozen"));
  });

  // ECMA262 19.1.2.14
  func.defineNativeMethod("isSealed", 1, (context, [O]) => {
    // 1. If Type(O) is not Object, return true.
    if (!O.mightBeObject()) return realm.intrinsics.true;

    // 2. Return ? TestIntegrityLevel(O, "sealed").
    O = O.throwIfNotConcreteObject();
    return new _index2.BooleanValue(realm, (0, _index3.TestIntegrityLevel)(realm, O, "sealed"));
  });

  // ECMA262 19.1.2.15
  func.defineNativeMethod("keys", 1, (context, [O]) => {
    // 1. Let obj be ? ToObject(O).
    let obj = _singletons.To.ToObject(realm, O.throwIfNotConcrete());

    // 2. Let nameList be ? EnumerableOwnProperties(obj, "key").
    let nameList = (0, _index3.EnumerableOwnProperties)(realm, obj, "key");

    // 3. Return CreateArrayFromList(nameList).
    return _singletons.Create.CreateArrayFromList(realm, nameList);
  });

  // ECMA262 9.1.2.16
  if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION) && !realm.isCompatibleWith("mobile")) func.defineNativeMethod("values", 1, (context, [O]) => {
    // 1. Let obj be ? ToObject(O).
    let obj = _singletons.To.ToObject(realm, O.throwIfNotConcrete());

    // 2. Let nameList be ? EnumerableOwnProperties(obj, "value").
    let nameList = (0, _index3.EnumerableOwnProperties)(realm, obj, "value");

    // 3. Return CreateArrayFromList(nameList).
    return _singletons.Create.CreateArrayFromList(realm, nameList);
  });

  // ECMA262 19.1.2.17
  func.defineNativeMethod("entries", 1, (context, [O]) => {
    // 1. Let obj be ? ToObject(O).
    let obj = _singletons.To.ToObject(realm, O.throwIfNotConcrete());

    // 2. Let nameList be ? EnumerableOwnProperties(obj, "key+value").
    let nameList = (0, _index3.EnumerableOwnProperties)(realm, obj, "key+value");

    // 3. Return CreateArrayFromList(nameList).
    return _singletons.Create.CreateArrayFromList(realm, nameList);
  });

  // ECMA262 19.1.2.18
  func.defineNativeMethod("preventExtensions", 1, (context, [O]) => {
    // 1. If Type(O) is not Object, return O.
    if (!O.mightBeObject()) return O;

    // 2. Let status be ? O.[[PreventExtensions]]().
    O = O.throwIfNotConcreteObject();
    let status = O.$PreventExtensions();

    // 3. If status is false, throw a TypeError exception.
    if (status === false) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Return O.
    return O;
  });

  // ECMA262 19.1.2.19
  func.defineNativeMethod("seal", 1, (context, [O]) => {
    // 1. If Type(O) is not Object, return O.
    if (!O.mightBeObject()) return O;

    // 2. Let status be ? SetIntegrityLevel(O, "sealed").
    O = O.throwIfNotConcreteObject();
    let status = (0, _index3.SetIntegrityLevel)(realm, O, "sealed");

    // 3. If status is false, throw a TypeError exception.
    if (status === false) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 4. Return O.
    return O;
  });

  // ECMA262 19.1.2.20
  if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION) && !realm.isCompatibleWith("mobile")) func.defineNativeMethod("setPrototypeOf", 2, (context, [O, proto]) => {
    // 1. Let O be ? RequireObjectCoercible(O).
    O = (0, _index3.RequireObjectCoercible)(realm, O);

    // 2. If Type(proto) is neither Object nor Null, throw a TypeError exception.
    if (!(0, _index3.HasSomeCompatibleType)(proto, _index2.ObjectValue, _index2.NullValue)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 3. If Type(O) is not Object, return O.
    O = O.throwIfNotConcrete();
    if (!(O instanceof _index2.ObjectValue)) return O;

    // 4. Let status be ? O.[[SetPrototypeOf]](proto).
    let status = O.$SetPrototypeOf(proto);

    // 5. If status is false, throw a TypeError exception.
    if (status === false) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
    }

    // 6. Return O.
    return O;
  });

  return func;
};

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

var _errors = require("../../errors.js");

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

var _index2 = require("../../values/index.js");

var _index3 = require("../../methods/index.js");

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

var _babelTypes = require("babel-types");

var t = _interopRequireWildcard(_babelTypes);

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

var _invariant2 = _interopRequireDefault(_invariant);

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

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
//# sourceMappingURL=Object.js.map