text: /**
   * Copyright 2014 Facebook, Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   * @providesModule ReactDescriptor
   */
  
  "use strict";
  
  var ReactContext = require('ReactContext');
  var ReactCurrentOwner = require('ReactCurrentOwner');
  
  var monitorCodeUse = require('monitorCodeUse');
  var warning = require('warning');
  
  /**
   * Warn if there's no key explicitly set on dynamic arrays of children or
   * object keys are not valid. This allows us to keep track of children between
   * updates.
   */
  var ownerHasExplicitKeyWarning = {};
  var ownerHasPropertyWarning = {};
  var ownerHasMonitoredObjectMap = {};
  
  var NUMERIC_PROPERTY_REGEX = /^\d+$/;
  
  /**
   * Warn if the component doesn't have an explicit key assigned to it.
   * This component is in an array. The array could grow and shrink or be
   * reordered. All children that haven't already been validated are required to
   * have a "key" property assigned to it.
   *
   * @internal
   * @param {ReactComponent} component Component that requires a key.
   */
  function validateExplicitKey(component) {
    if (component._store.validated || component.props.key != null) {
      return;
    }
    component._store.validated = true;
  
    // We can't provide friendly warnings for top level components.
    if (!ReactCurrentOwner.current) {
      return;
    }
  
    // Name of the component whose render method tried to pass children.
    var currentName = ReactCurrentOwner.current.constructor.displayName;
    if (ownerHasExplicitKeyWarning.hasOwnProperty(currentName)) {
      return;
    }
    ownerHasExplicitKeyWarning[currentName] = true;
  
    var message = 'Each child in an array should have a unique "key" prop. ' +
                  'Check the render method of ' + currentName + '.';
  
    var childOwnerName = null;
    if (component._owner !== ReactCurrentOwner.current) {
      // Name of the component that originally created this child.
      childOwnerName =
        component._owner &&
        component._owner.constructor.displayName;
  
      // Usually the current owner is the offender, but if it accepts
      // children as a property, it may be the creator of the child that's
      // responsible for assigning it a key.
      message += ' It was passed a child from ' + childOwnerName + '.';
    }
  
    message += ' See http://fb.me/react-warning-keys for more information.';
    monitorCodeUse('react_key_warning', {
      component: currentName,
      componentOwner: childOwnerName
    });
    console.warn(message);
  }
  
  /**
   * Warn if the key is being defined as an object property but has an incorrect
   * value.
   *
   * @internal
   * @param {string} name Property name of the key.
   * @param {ReactComponent} component Component that requires a key.
   */
  function validatePropertyKey(name) {
    // We can't provide friendly warnings for top level components.
    if (!ReactCurrentOwner.current) {
      return;
    }
  
    if (NUMERIC_PROPERTY_REGEX.test(name)) {
      // Name of the component whose render method tried to pass children.
      var currentName = ReactCurrentOwner.current.constructor.displayName;
      if (ownerHasPropertyWarning.hasOwnProperty(currentName)) {
        return;
      }
      ownerHasPropertyWarning[currentName] = true;
  
      monitorCodeUse('react_numeric_key_warning');
      console.warn(
        'Child objects should have non-numeric keys so ordering is preserved. ' +
        'Check the render method of ' + currentName + '. ' +
        'See http://fb.me/react-warning-keys for more information.'
      );
    }
  }
  
  /**
   * Log that we're using an object map. We're considering deprecating this
   * feature and replace it with proper Map and ImmutableMap data structures.
   *
   * @internal
   */
  function monitorUseOfObjectMap() {
    // Name of the component whose render method tried to pass children.
    // We only use this to avoid spewing the logs. We lose additional
    // owner stacks but hopefully one level is enough to trace the source.
    var currentName = (ReactCurrentOwner.current &&
                      ReactCurrentOwner.current.constructor.displayName) || '';
    if (ownerHasMonitoredObjectMap.hasOwnProperty(currentName)) {
      return;
    }
    ownerHasMonitoredObjectMap[currentName] = true;
    monitorCodeUse('react_object_map_children');
  }
  
  /**
   * Ensure that every component either is passed in a static location, in an
   * array with an explicit keys property defined, or in an object literal
   * with valid key property.
   *
   * @internal
   * @param {*} component Statically passed child of any type.
   * @return {boolean}
   */
  function validateChildKeys(component) {
    if (Array.isArray(component)) {
      for (var i = 0; i < component.length; i++) {
        var child = component[i];
        if (ReactDescriptor.isValidDescriptor(child)) {
          validateExplicitKey(child);
        }
      }
    } else if (ReactDescriptor.isValidDescriptor(component)) {
      // This component was passed in a valid location.
      component._store.validated = true;
    } else if (component && typeof component === 'object') {
      monitorUseOfObjectMap();
      for (var name in component) {
        validatePropertyKey(name, component);
      }
    }
  }
  
  /**
   * Warn for mutations.
   *
   * @internal
   * @param {object} object
   * @param {string} key
   */
  function defineWarningProperty(object, key) {
    Object.defineProperty(object, key, {
  
      configurable: false,
      enumerable: true,
  
      get: function() {
        if (!this._store) {
          return null;
        }
        return this._store[key];
      },
  
      set: function(value) {
        warning(
          false,
          'Don\'t set the ' + key + ' property of the component. ' +
          'Mutate the existing props object instead.'
        );
        this._store[key] = value;
      }
  
    });
  }
  
  /**
   * This is updated to true if the membrane is successfully created.
   */
  var useMutationMembrane = false;
  
  /**
   * Warn for mutations.
   *
   * @internal
   * @param {object} descriptor
   */
  function defineMutationMembrane(prototype) {
    try {
      var pseudoFrozenProperties = {
        props: true
      };
      for (var key in pseudoFrozenProperties) {
        defineWarningProperty(prototype, key);
      }
      useMutationMembrane = true;
    } catch (x) {
      // IE will fail on defineProperty
    }
  }
  
  /**
   * Base constructor for all React descriptors. This is only used to make this
   * work with a dynamic instanceof check. Nothing should live on this prototype.
   *
   * @param {*} type
   * @internal
   */
  var ReactDescriptor = function() {};
  
  if (__DEV__) {
    defineMutationMembrane(ReactDescriptor.prototype);
  }
  
  ReactDescriptor.createFactory = function(type) {
  
    var descriptorPrototype = Object.create(ReactDescriptor.prototype);
  
    var factory = function(props, children) {
      if (props == null) {
        props = {};
      }
  
      // Children can be more than one argument
      var childrenLength = arguments.length - 1;
      if (childrenLength === 1) {
        if (__DEV__) {
          validateChildKeys(children);
        }
        props.children = children;
      } else if (childrenLength > 1) {
        var childArray = Array(childrenLength);
        for (var i = 0; i < childrenLength; i++) {
          if (__DEV__) {
            validateChildKeys(arguments[i + 1]);
          }
          childArray[i] = arguments[i + 1];
        }
        props.children = childArray;
      }
  
      var descriptor = Object.create(descriptorPrototype);
  
      // Record the component responsible for creating this descriptor.
      descriptor._owner = ReactCurrentOwner.current;
  
      // TODO: Deprecate withContext, and then the context becomes accessible
      // through the owner.
      descriptor._context = ReactContext.current;
  
      if (__DEV__) {
        // The validation flag and props are currently mutative. We put them on
        // an external backing store so that we can freeze the whole object.
        descriptor._store = { validated: false, props: props };
  
        // We're not allowed to set props directly on the object so we early
        // return and rely on the prototype membrane toward to the backing store.
        if (useMutationMembrane) {
          Object.freeze(descriptor);
          return descriptor;
        }
      }
  
      descriptor.props = props;
      return descriptor;
  
    };
  
    // Currently we expose the prototype of the descriptor so that
    // <Foo /> instanceof Foo works. This is controversial pattern.
    factory.prototype = descriptorPrototype;
  
    // Expose the type on the factory and the prototype so that it can be
    // easily accessed on descriptors. E.g. <Foo />.type === Foo.type and for
    // static methods like <Foo />.type.staticMethod();
    // This should not be named constructor since this may not be the function
    // that created the descriptor, and it may not even be a constructor.
    factory.type = type;
    descriptorPrototype.type = type;
  
    // Expose a unique constructor on the prototype is that this works with type
    // systems that compare constructor properties: <Foo />.constructor === Foo
    // This may be controversial since it requires a known factory function.
    descriptorPrototype.constructor = factory;
  
    return factory;
  
  };
  
  ReactDescriptor.cloneAndReplaceProps = function(oldDescriptor, newProps) {
    var newDescriptor = Object.create(oldDescriptor.constructor.prototype);
    // It's important that this property order matches the hidden class of the
    // original descriptor to maintain perf.
    newDescriptor._owner = oldDescriptor._owner;
    newDescriptor._context = oldDescriptor._context;
  
    if (__DEV__) {
      newDescriptor._store = {
        validated: oldDescriptor._store.validated,
        props: newProps
      };
      if (useMutationMembrane) {
        Object.freeze(newDescriptor);
        return newDescriptor;
      }
    }
  
    newDescriptor.props = newProps;
    return newDescriptor;
  };
  
  /**
   * Checks if a value is a valid descriptor constructor.
   *
   * @param {*}
   * @return {boolean}
   * @public
   */
  ReactDescriptor.isValidFactory = function(factory) {
    return typeof factory === 'function' &&
           factory.prototype instanceof ReactDescriptor;
  };
  
  /**
   * @param {?object} object
   * @return {boolean} True if `object` is a valid component.
   * @final
   */
  ReactDescriptor.isValidDescriptor = function(object) {
    return object instanceof ReactDescriptor;
  };
  
  module.exports = ReactDescriptor;
  