react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / react-tools / src / core / ReactElementValidator.js
81152 views/**1* Copyright 2014, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @providesModule ReactElementValidator9*/1011/**12* ReactElementValidator provides a wrapper around a element factory13* which validates the props passed to the element. This is intended to be14* used only in DEV and could be replaced by a static type checker for languages15* that support it.16*/1718"use strict";1920var ReactElement = require('ReactElement');21var ReactPropTypeLocations = require('ReactPropTypeLocations');22var ReactCurrentOwner = require('ReactCurrentOwner');2324var monitorCodeUse = require('monitorCodeUse');25var warning = require('warning');2627/**28* Warn if there's no key explicitly set on dynamic arrays of children or29* object keys are not valid. This allows us to keep track of children between30* updates.31*/32var ownerHasKeyUseWarning = {33'react_key_warning': {},34'react_numeric_key_warning': {}35};36var ownerHasMonitoredObjectMap = {};3738var loggedTypeFailures = {};3940var NUMERIC_PROPERTY_REGEX = /^\d+$/;4142/**43* Gets the current owner's displayName for use in warnings.44*45* @internal46* @return {?string} Display name or undefined47*/48function getCurrentOwnerDisplayName() {49var current = ReactCurrentOwner.current;50return current && current.constructor.displayName || undefined;51}5253/**54* Warn if the component doesn't have an explicit key assigned to it.55* This component is in an array. The array could grow and shrink or be56* reordered. All children that haven't already been validated are required to57* have a "key" property assigned to it.58*59* @internal60* @param {ReactComponent} component Component that requires a key.61* @param {*} parentType component's parent's type.62*/63function validateExplicitKey(component, parentType) {64if (component._store.validated || component.key != null) {65return;66}67component._store.validated = true;6869warnAndMonitorForKeyUse(70'react_key_warning',71'Each child in an array should have a unique "key" prop.',72component,73parentType74);75}7677/**78* Warn if the key is being defined as an object property but has an incorrect79* value.80*81* @internal82* @param {string} name Property name of the key.83* @param {ReactComponent} component Component that requires a key.84* @param {*} parentType component's parent's type.85*/86function validatePropertyKey(name, component, parentType) {87if (!NUMERIC_PROPERTY_REGEX.test(name)) {88return;89}90warnAndMonitorForKeyUse(91'react_numeric_key_warning',92'Child objects should have non-numeric keys so ordering is preserved.',93component,94parentType95);96}9798/**99* Shared warning and monitoring code for the key warnings.100*101* @internal102* @param {string} warningID The id used when logging.103* @param {string} message The base warning that gets output.104* @param {ReactComponent} component Component that requires a key.105* @param {*} parentType component's parent's type.106*/107function warnAndMonitorForKeyUse(warningID, message, component, parentType) {108var ownerName = getCurrentOwnerDisplayName();109var parentName = parentType.displayName;110111var useName = ownerName || parentName;112var memoizer = ownerHasKeyUseWarning[warningID];113if (memoizer.hasOwnProperty(useName)) {114return;115}116memoizer[useName] = true;117118message += ownerName ?119` Check the render method of ${ownerName}.` :120` Check the renderComponent call using <${parentName}>.`;121122// Usually the current owner is the offender, but if it accepts children as a123// property, it may be the creator of the child that's responsible for124// assigning it a key.125var childOwnerName = null;126if (component._owner && component._owner !== ReactCurrentOwner.current) {127// Name of the component that originally created this child.128childOwnerName = component._owner.constructor.displayName;129130message += ` It was passed a child from ${childOwnerName}.`;131}132133message += ' See http://fb.me/react-warning-keys for more information.';134monitorCodeUse(warningID, {135component: useName,136componentOwner: childOwnerName137});138console.warn(message);139}140141/**142* Log that we're using an object map. We're considering deprecating this143* feature and replace it with proper Map and ImmutableMap data structures.144*145* @internal146*/147function monitorUseOfObjectMap() {148var currentName = getCurrentOwnerDisplayName() || '';149if (ownerHasMonitoredObjectMap.hasOwnProperty(currentName)) {150return;151}152ownerHasMonitoredObjectMap[currentName] = true;153monitorCodeUse('react_object_map_children');154}155156/**157* Ensure that every component either is passed in a static location, in an158* array with an explicit keys property defined, or in an object literal159* with valid key property.160*161* @internal162* @param {*} component Statically passed child of any type.163* @param {*} parentType component's parent's type.164* @return {boolean}165*/166function validateChildKeys(component, parentType) {167if (Array.isArray(component)) {168for (var i = 0; i < component.length; i++) {169var child = component[i];170if (ReactElement.isValidElement(child)) {171validateExplicitKey(child, parentType);172}173}174} else if (ReactElement.isValidElement(component)) {175// This component was passed in a valid location.176component._store.validated = true;177} else if (component && typeof component === 'object') {178monitorUseOfObjectMap();179for (var name in component) {180validatePropertyKey(name, component[name], parentType);181}182}183}184185/**186* Assert that the props are valid187*188* @param {string} componentName Name of the component for error messages.189* @param {object} propTypes Map of prop name to a ReactPropType190* @param {object} props191* @param {string} location e.g. "prop", "context", "child context"192* @private193*/194function checkPropTypes(componentName, propTypes, props, location) {195for (var propName in propTypes) {196if (propTypes.hasOwnProperty(propName)) {197var error;198// Prop type validation may throw. In case they do, we don't want to199// fail the render phase where it didn't fail before. So we log it.200// After these have been cleaned up, we'll let them throw.201try {202error = propTypes[propName](props, propName, componentName, location);203} catch (ex) {204error = ex;205}206if (error instanceof Error && !(error.message in loggedTypeFailures)) {207// Only monitor this failure once because there tends to be a lot of the208// same error.209loggedTypeFailures[error.message] = true;210// This will soon use the warning module211monitorCodeUse(212'react_failed_descriptor_type_check',213{ message: error.message }214);215}216}217}218}219220var ReactElementValidator = {221222createElement: function(type, props, children) {223// We warn in this case but don't throw. We expect the element creation to224// succeed and there will likely be errors in render.225warning(226type != null,227'React.createElement: type should not be null or undefined. It should ' +228'be a string (for DOM elements) or a ReactClass (for composite ' +229'components).'230);231232var element = ReactElement.createElement.apply(this, arguments);233234// The result can be nullish if a mock or a custom function is used.235// TODO: Drop this when these are no longer allowed as the type argument.236if (element == null) {237return element;238}239240for (var i = 2; i < arguments.length; i++) {241validateChildKeys(arguments[i], type);242}243244if (type) {245var name = type.displayName;246if (type.propTypes) {247checkPropTypes(248name,249type.propTypes,250element.props,251ReactPropTypeLocations.prop252);253}254if (type.contextTypes) {255checkPropTypes(256name,257type.contextTypes,258element._context,259ReactPropTypeLocations.context260);261}262}263return element;264},265266createFactory: function(type) {267var validatedFactory = ReactElementValidator.createElement.bind(268null,269type270);271validatedFactory.type = type;272return validatedFactory;273}274275};276277module.exports = ReactElementValidator;278279280