text: "use strict";
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.createProps = createProps;
  
  var _seerIntegration = require("../lib/seer-integration");
  
  var _log = _interopRequireDefault(require("../utils/log"));
  
  var _propTypes = require("./prop-types");
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance](left); } else { return left instanceof right; } }
  
  // Create a property object
  function createProps() {
    var component = this; // eslint-disable-line
    // Get default prop object (a prototype chain for now)
  
    var propsPrototype = getPropsPrototypeAndTypes(component.constructor).defaultProps; // Create a new prop object with default props object in prototype chain
  
    var propsInstance = Object.create(propsPrototype, {
      // Props need a back pointer to the owning component
      _component: {
        enumerable: false,
        value: component
      },
      // The supplied (original) values for those async props that are set to url strings or Promises.
      // In this case, the actual (i.e. resolved) values are looked up from component.internalState
      _asyncPropOriginalValues: {
        enumerable: false,
        value: {}
      },
      // Note: the actual (resolved) values for props that are NOT set to urls or Promises.
      // in this case the values are served directly from this map
      _asyncPropResolvedValues: {
        enumerable: false,
        value: {}
      }
    }); // "Copy" all sync props
  
    for (var i = 0; i < arguments.length; ++i) {
      Object.assign(propsInstance, arguments[i]);
    } // SEER: Apply any overrides from the seer debug extension if it is active
  
  
    (0, _seerIntegration.applyPropOverrides)(propsInstance); // Props must be immutable
  
    Object.freeze(propsInstance);
    return propsInstance;
  } // Return precalculated defaultProps and propType objects if available
  // build them if needed
  
  
  function getPropsPrototypeAndTypes(componentClass) {
    var props = getOwnProperty(componentClass, '_mergedDefaultProps');
  
    if (props) {
      return {
        defaultProps: props,
        propTypes: getOwnProperty(componentClass, '_propTypes')
      };
    }
  
    return createPropsPrototypeAndTypes(componentClass);
  } // Build defaultProps and propType objects by walking component prototype chain
  
  
  function createPropsPrototypeAndTypes(componentClass) {
    var parent = componentClass.prototype;
  
    if (!parent) {
      return {
        defaultProps: {}
      };
    }
  
    var parentClass = Object.getPrototypeOf(componentClass);
    var parentPropDefs = parent && getPropsPrototypeAndTypes(parentClass) || null; // Parse propTypes from Component.defaultProps
  
    var componentDefaultProps = getOwnProperty(componentClass, 'defaultProps') || {};
    var componentPropDefs = (0, _propTypes.parsePropTypes)(componentDefaultProps); // Create a merged type object
  
    var propTypes = Object.assign({}, parentPropDefs && parentPropDefs.propTypes, componentPropDefs.propTypes); // Create any necessary property descriptors and create the default prop object
    // Assign merged default props
  
    var defaultProps = createPropsPrototype(componentPropDefs.defaultProps, parentPropDefs && parentPropDefs.defaultProps, propTypes, componentClass); // Store the precalculated props
  
    componentClass._mergedDefaultProps = defaultProps;
    componentClass._propTypes = propTypes;
    return {
      propTypes: propTypes,
      defaultProps: defaultProps
    };
  } // Builds a pre-merged default props object that component props can inherit from
  
  
  function createPropsPrototype(props, parentProps, propTypes, componentClass) {
    var defaultProps = Object.create(null);
    Object.assign(defaultProps, parentProps, props); // Avoid freezing `id` prop
  
    var id = getComponentName(componentClass);
    delete props.id; // Add getters/setters for async prop properties
  
    Object.defineProperties(defaultProps, {
      // `id` is treated specially because layer might need to override it
      id: {
        configurable: false,
        writable: true,
        value: id
      }
    }); // Add getters/setters for async prop properties
  
    addAsyncPropsToPropPrototype(defaultProps, propTypes);
    return defaultProps;
  } // Create descriptors for overridable props
  
  
  function addAsyncPropsToPropPrototype(defaultProps, propTypes) {
    var defaultValues = {};
    var descriptors = {
      // Default "resolved" values for async props, returned if value not yet resolved/set.
      _asyncPropDefaultValues: {
        enumerable: false,
        value: defaultValues
      },
      // Shadowed object, just to make sure "early indexing" into the instance does not fail
      _asyncPropOriginalValues: {
        enumerable: false,
        value: {}
      }
    }; // Move async props into shadow values
  
    for (var propName in propTypes) {
      var propType = propTypes[propName];
      var name = propType.name,
          value = propType.value; // Note: async is ES7 keyword, can't destructure
  
      if (propType.async) {
        defaultValues[name] = value;
        descriptors[name] = getDescriptorForAsyncProp(name, value);
      }
    }
  
    Object.defineProperties(defaultProps, descriptors);
  } // Helper: Configures getter and setter for one async prop
  
  
  function getDescriptorForAsyncProp(name) {
    return {
      configurable: false,
      enumerable: true,
      // Save the provided value for async props in a special map
      set: function set(newValue) {
        if (typeof newValue === 'string' || _instanceof(newValue, Promise)) {
          this._asyncPropOriginalValues[name] = newValue;
        } else {
          this._asyncPropResolvedValues[name] = newValue;
        }
      },
      // Only the component's state knows the true value of async prop
      get: function get() {
        if (this._asyncPropResolvedValues) {
          // Prop value isn't async, so just return it
          if (name in this._asyncPropResolvedValues) {
            var value = this._asyncPropResolvedValues[name]; // Special handling - components expect null `data` prop expects to be replaced with `[]`
  
            if (name === 'data') {
              return value || this._asyncPropDefaultValues[name];
            }
  
            return value;
          } // It's an async prop value: look into component state
  
  
          var state = this._component && this._component.internalState;
  
          if (state && state.hasAsyncProp(name)) {
            return state.getAsyncProp(name);
          }
        } // component not yet initialized/matched, return the component's default value for the prop
  
  
        return this._asyncPropDefaultValues[name];
      }
    };
  } // HELPER METHODS
  // Constructors have their super class constructors as prototypes
  
  
  function getOwnProperty(object, prop) {
    return Object.prototype.hasOwnProperty.call(object, prop) && object[prop];
  }
  
  function getComponentName(componentClass) {
    var componentName = getOwnProperty(componentClass, 'layerName') || getOwnProperty(componentClass, 'componentName');
  
    if (!componentName) {
      _log.default.once(0, "".concat(componentClass.name, ".componentName not specified"));
    }
  
    return componentName || componentClass.name;
  }
  //# sourceMappingURL=create-props.js.map