"use strict";

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

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

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

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

var _invariant2 = _interopRequireDefault(_invariant);

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

var _utils = require("./utils.js");

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

var t = _interopRequireWildcard(_babelTypes);

var _BinaryExpression = require("../evaluators/BinaryExpression.js");

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

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; } }

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

function createPropsObject(realm, type, config, children) {
  let defaultProps = type instanceof _index.ObjectValue ? (0, _index2.Get)(realm, type, "defaultProps") : realm.intrinsics.undefined;
  let props = _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype);
  // start by having key and ref deleted, if they actually exist, they will be add later
  (0, _utils.deleteRefAndKeyFromProps)(realm, props);
  let key = realm.intrinsics.null;
  let ref = realm.intrinsics.null;

  const setProp = (name, value) => {
    if (name === "key" && value !== realm.intrinsics.null) {
      key = (0, _BinaryExpression.computeBinary)(realm, "+", realm.intrinsics.emptyString, value);
    } else if (name === "ref") {
      ref = value;
    } else if (name !== "__self" && name !== "__source") {
      (0, _invariant2.default)(props instanceof _index.ObjectValue);
      _singletons.Properties.Set(realm, props, name, value, true);
    }
  };

  if (config instanceof _index.AbstractObjectValue && config.isPartialObject() || config instanceof _index.AbstractValue || config instanceof _index.ObjectValue && config.isPartialObject() && config.isSimpleObject()) {
    // if we have defaultProps, we need to create a new merge of the objects along with our config
    if (defaultProps !== realm.intrinsics.undefined || children !== realm.intrinsics.undefined) {
      if ((0, _utils.objectHasNoPartialKeyAndRef)(realm, config)) {
        let args = [];
        if (defaultProps !== realm.intrinsics.undefined) {
          args.push(defaultProps);
        }
        args.push(config);
        // create a new props object that will be the target of the Object.assign
        props = _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype);
        // as this is "props" that is abstract, we need to make it partial and simple
        props.makePartial();
        props.makeSimple();
        // props objects also don't have a key and ref, so we remove them
        (0, _utils.deleteRefAndKeyFromProps)(realm, props);

        // get the global Object.assign
        let globalObj = (0, _index2.Get)(realm, realm.$GlobalObject, "Object");
        (0, _invariant2.default)(globalObj instanceof _index.ObjectValue);
        let objAssign = (0, _index2.Get)(realm, globalObj, "assign");
        (0, _invariant2.default)(realm.generator);

        _index.AbstractValue.createTemporalFromBuildFunction(realm, _index.FunctionValue, [objAssign, props, ...args], ([methodNode, ..._args]) => {
          return t.callExpression(methodNode, _args);
        });
      } else {
        // if either are abstract, this will impact the reconcilation process
        // and ultimately prevent us from folding ReactElements properly
        let diagnostic = new _errors.CompilerDiagnostic(`unable to evaluate "key" and "ref" on a ReactElement due to an abstract config passed to createElement`, realm.currentLocation, "PP0025", "FatalError");
        realm.handleError(diagnostic);
        if (realm.handleError(diagnostic) === "Fail") throw new _errors.FatalError();
      }
      if (children !== realm.intrinsics.undefined) {
        setProp("children", children);
      }
    } else {
      // as the config is partial and simple, we don't know about its prototype or properties
      // we don't have to worry about non-enumerable properties as its properties will never
      // be serialized, rather this object will be serialized as a spread.
      props = config;
    }
  } else {
    if (config instanceof _index.ObjectValue) {
      for (let [propKey, binding] of config.properties) {
        if (binding && binding.descriptor && binding.descriptor.enumerable) {
          setProp(propKey, (0, _index2.Get)(realm, config, propKey));
        }
      }
    }

    if (children !== realm.intrinsics.undefined) {
      setProp("children", children);
    }

    if (defaultProps instanceof _index.ObjectValue) {
      for (let [propKey, binding] of defaultProps.properties) {
        if (binding && binding.descriptor && binding.descriptor.enumerable) {
          if ((0, _index2.Get)(realm, props, propKey) === realm.intrinsics.undefined) {
            setProp(propKey, (0, _index2.Get)(realm, defaultProps, propKey));
          }
        }
      }
    }
  }
  if (props instanceof _index.ObjectValue || props instanceof _index.AbstractObjectValue) {
    // ensure the props is marked as final
    props.makeFinal();
  }
  return { key, props, ref };
} /**
   * 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 createReactElement(realm, type, config, children) {
  let { key, props, ref } = createPropsObject(realm, type, config, children);
  return createInternalReactElement(realm, type, key, ref, props);
}

function createInternalReactElement(realm, type, key, ref, props) {
  let obj = _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype);
  _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "$$typeof", (0, _utils.getReactSymbol)("react.element", realm));
  _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "type", type);
  _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "key", key);
  _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "ref", ref);
  _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "props", props);
  _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "_owner", realm.intrinsics.null);
  obj.makeFinal();
  return obj;
}
//# sourceMappingURL=elements.js.map