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 ReactDescriptorValidator
   */
  
  /**
   * ReactDescriptorValidator provides a wrapper around a descriptor factory
   * which validates the props passed to the descriptor. This is intended to be
   * used only in DEV and could be replaced by a static type checker for languages
   * that support it.
   */
  
  "use strict";
  
  var ReactDescriptor = require('ReactDescriptor');
  var ReactPropTypeLocations = require('ReactPropTypeLocations');
  var ReactCurrentOwner = require('ReactCurrentOwner');
  
  var monitorCodeUse = require('monitorCodeUse');
  
  /**
   * 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 ownerHasKeyUseWarning = {
    'react_key_warning': {},
    'react_numeric_key_warning': {}
  };
  var ownerHasMonitoredObjectMap = {};
  
  var loggedTypeFailures = {};
  
  var NUMERIC_PROPERTY_REGEX = /^\d+$/;
  
  /**
   * Gets the current owner's displayName for use in warnings.
   *
   * @internal
   * @return {?string} Display name or undefined
   */
  function getCurrentOwnerDisplayName() {
    var current = ReactCurrentOwner.current;
    return current && current.constructor.displayName || undefined;
  }
  
  /**
   * 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.
   * @param {*} parentType component's parent's type.
   */
  function validateExplicitKey(component, parentType) {
    if (component._store.validated || component.key != null) {
      return;
    }
    component._store.validated = true;
  
    warnAndMonitorForKeyUse(
      'react_key_warning',
      'Each child in an array should have a unique "key" prop.',
      component,
      parentType
    );
  }
  
  /**
   * 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.
   * @param {*} parentType component's parent's type.
   */
  function validatePropertyKey(name, component, parentType) {
    if (!NUMERIC_PROPERTY_REGEX.test(name)) {
      return;
    }
    warnAndMonitorForKeyUse(
      'react_numeric_key_warning',
      'Child objects should have non-numeric keys so ordering is preserved.',
      component,
      parentType
    );
  }
  
  /**
   * Shared warning and monitoring code for the key warnings.
   *
   * @internal
   * @param {string} warningID The id used when logging.
   * @param {string} message The base warning that gets output.
   * @param {ReactComponent} component Component that requires a key.
   * @param {*} parentType component's parent's type.
   */
  function warnAndMonitorForKeyUse(warningID, message, component, parentType) {
    var ownerName = getCurrentOwnerDisplayName();
    var parentName = parentType.displayName;
  
    var useName = ownerName || parentName;
    var memoizer = ownerHasKeyUseWarning[warningID];
    if (memoizer.hasOwnProperty(useName)) {
      return;
    }
    memoizer[useName] = true;
  
    message += ownerName ?
      ` Check the render method of ${ownerName}.` :
      ` Check the renderComponent call using <${parentName}>.`;
  
    // 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.
    var childOwnerName = null;
    if (component._owner && component._owner !== ReactCurrentOwner.current) {
      // Name of the component that originally created this child.
      childOwnerName = component._owner.constructor.displayName;
  
      message += ` It was passed a child from ${childOwnerName}.`;
    }
  
    message += ' See http://fb.me/react-warning-keys for more information.';
    monitorCodeUse(warningID, {
      component: useName,
      componentOwner: childOwnerName
    });
    console.warn(message);
  }
  
  /**
   * 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() {
    var currentName = getCurrentOwnerDisplayName() || '';
    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.
   * @param {*} parentType component's parent's type.
   * @return {boolean}
   */
  function validateChildKeys(component, parentType) {
    if (Array.isArray(component)) {
      for (var i = 0; i < component.length; i++) {
        var child = component[i];
        if (ReactDescriptor.isValidDescriptor(child)) {
          validateExplicitKey(child, parentType);
        }
      }
    } 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[name], parentType);
      }
    }
  }
  
  /**
   * Assert that the props are valid
   *
   * @param {string} componentName Name of the component for error messages.
   * @param {object} propTypes Map of prop name to a ReactPropType
   * @param {object} props
   * @param {string} location e.g. "prop", "context", "child context"
   * @private
   */
  function checkPropTypes(componentName, propTypes, props, location) {
    for (var propName in propTypes) {
      if (propTypes.hasOwnProperty(propName)) {
        var error;
        // Prop type validation may throw. In case they do, we don't want to
        // fail the render phase where it didn't fail before. So we log it.
        // After these have been cleaned up, we'll let them throw.
        try {
          error = propTypes[propName](props, propName, componentName, location);
        } catch (ex) {
          error = ex;
        }
        if (error instanceof Error && !(error.message in loggedTypeFailures)) {
          // Only monitor this failure once because there tends to be a lot of the
          // same error.
          loggedTypeFailures[error.message] = true;
          // This will soon use the warning module
          monitorCodeUse(
            'react_failed_descriptor_type_check',
            { message: error.message }
          );
        }
      }
    }
  }
  
  var ReactDescriptorValidator = {
  
    createDescriptor: function(type, props, children) {
      var descriptor = ReactDescriptor.createDescriptor.apply(this, arguments);
  
      for (var i = 2; i < arguments.length; i++) {
        validateChildKeys(arguments[i], type);
      }
  
      var name = type.displayName;
      if (type.propTypes) {
        checkPropTypes(
          name,
          type.propTypes,
          descriptor.props,
          ReactPropTypeLocations.prop
        );
      }
      if (type.contextTypes) {
        checkPropTypes(
          name,
          type.contextTypes,
          descriptor._context,
          ReactPropTypeLocations.context
        );
      }
      return descriptor;
    },
  
    createFactory: function(type) {
      if (type.isReactLegacyFactory) {
        // This is probably a legacy factory created by ReactCompositeComponent.
        // We unwrap it to get to the underlying class.
        // TODO: Drop this check when we drop ReactLegacyDescriptor.
        type = type.type;
      }
      var validatedFactory = ReactDescriptorValidator.createDescriptor.bind(
        null,
        type
      );
      validatedFactory.type = type;
      return validatedFactory;
    }
  
  };
  
  module.exports = ReactDescriptorValidator;
  