| /** |
| * Copyright (c) 2013-present, Facebook, Inc. |
| * |
| * This source code is licensed under the MIT license found in the |
| * LICENSE file in the root directory of this source tree. |
| */ |
| |
| 'use strict'; |
| |
| var ReactIs = require('react-is'); |
| var assign = require('object-assign'); |
| |
| var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret'); |
| var checkPropTypes = require('./checkPropTypes'); |
| |
| var has = Function.call.bind(Object.prototype.hasOwnProperty); |
| var printWarning = function() {}; |
| |
| if (process.env.NODE_ENV !== 'production') { |
| printWarning = function(text) { |
| var message = 'Warning: ' + text; |
| if (typeof console !== 'undefined') { |
| console.error(message); |
| } |
| try { |
| // --- Welcome to debugging React --- |
| // This error was thrown as a convenience so that you can use this stack |
| // to find the callsite that caused this warning to fire. |
| throw new Error(message); |
| } catch (x) {} |
| }; |
| } |
| |
| function emptyFunctionThatReturnsNull() { |
| return null; |
| } |
| |
| module.exports = function(isValidElement, throwOnDirectAccess) { |
| /* global Symbol */ |
| var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; |
| var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. |
| |
| /** |
| * Returns the iterator method function contained on the iterable object. |
| * |
| * Be sure to invoke the function with the iterable as context: |
| * |
| * var iteratorFn = getIteratorFn(myIterable); |
| * if (iteratorFn) { |
| * var iterator = iteratorFn.call(myIterable); |
| * ... |
| * } |
| * |
| * @param {?object} maybeIterable |
| * @return {?function} |
| */ |
| function getIteratorFn(maybeIterable) { |
| var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]); |
| if (typeof iteratorFn === 'function') { |
| return iteratorFn; |
| } |
| } |
| |
| /** |
| * Collection of methods that allow declaration and validation of props that are |
| * supplied to React components. Example usage: |
| * |
| * var Props = require('ReactPropTypes'); |
| * var MyArticle = React.createClass({ |
| * propTypes: { |
| * // An optional string prop named "description". |
| * description: Props.string, |
| * |
| * // A required enum prop named "category". |
| * category: Props.oneOf(['News','Photos']).isRequired, |
| * |
| * // A prop named "dialog" that requires an instance of Dialog. |
| * dialog: Props.instanceOf(Dialog).isRequired |
| * }, |
| * render: function() { ... } |
| * }); |
| * |
| * A more formal specification of how these methods are used: |
| * |
| * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) |
| * decl := ReactPropTypes.{type}(.isRequired)? |
| * |
| * Each and every declaration produces a function with the same signature. This |
| * allows the creation of custom validation functions. For example: |
| * |
| * var MyLink = React.createClass({ |
| * propTypes: { |
| * // An optional string or URI prop named "href". |
| * href: function(props, propName, componentName) { |
| * var propValue = props[propName]; |
| * if (propValue != null && typeof propValue !== 'string' && |
| * !(propValue instanceof URI)) { |
| * return new Error( |
| * 'Expected a string or an URI for ' + propName + ' in ' + |
| * componentName |
| * ); |
| * } |
| * } |
| * }, |
| * render: function() {...} |
| * }); |
| * |
| * @internal |
| */ |
| |
| var ANONYMOUS = '<<anonymous>>'; |
| |
| // Important! |
| // Keep this list in sync with production version in `./factoryWithThrowingShims.js`. |
| var ReactPropTypes = { |
| array: createPrimitiveTypeChecker('array'), |
| bool: createPrimitiveTypeChecker('boolean'), |
| func: createPrimitiveTypeChecker('function'), |
| number: createPrimitiveTypeChecker('number'), |
| object: createPrimitiveTypeChecker('object'), |
| string: createPrimitiveTypeChecker('string'), |
| symbol: createPrimitiveTypeChecker('symbol'), |
| |
| any: createAnyTypeChecker(), |
| arrayOf: createArrayOfTypeChecker, |
| element: createElementTypeChecker(), |
| elementType: createElementTypeTypeChecker(), |
| instanceOf: createInstanceTypeChecker, |
| node: createNodeChecker(), |
| objectOf: createObjectOfTypeChecker, |
| oneOf: createEnumTypeChecker, |
| oneOfType: createUnionTypeChecker, |
| shape: createShapeTypeChecker, |
| exact: createStrictShapeTypeChecker, |
| }; |
| |
| /** |
| * inlined Object.is polyfill to avoid requiring consumers ship their own |
| * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is |
| */ |
| /*eslint-disable no-self-compare*/ |
| function is(x, y) { |
| // SameValue algorithm |
| if (x === y) { |
| // Steps 1-5, 7-10 |
| // Steps 6.b-6.e: +0 != -0 |
| return x !== 0 || 1 / x === 1 / y; |
| } else { |
| // Step 6.a: NaN == NaN |
| return x !== x && y !== y; |
| } |
| } |
| /*eslint-enable no-self-compare*/ |
| |
| /** |
| * We use an Error-like object for backward compatibility as people may call |
| * PropTypes directly and inspect their output. However, we don't use real |
| * Errors anymore. We don't inspect their stack anyway, and creating them |
| * is prohibitively expensive if they are created too often, such as what |
| * happens in oneOfType() for any type before the one that matched. |
| */ |
| function PropTypeError(message) { |
| this.message = message; |
| this.stack = ''; |
| } |
| // Make `instanceof Error` still work for returned errors. |
| PropTypeError.prototype = Error.prototype; |
| |
| function createChainableTypeChecker(validate) { |
| if (process.env.NODE_ENV !== 'production') { |
| var manualPropTypeCallCache = {}; |
| var manualPropTypeWarningCount = 0; |
| } |
| function checkType(isRequired, props, propName, componentName, location, propFullName, secret) { |
| componentName = componentName || ANONYMOUS; |
| propFullName = propFullName || propName; |
| |
| if (secret !== ReactPropTypesSecret) { |
| if (throwOnDirectAccess) { |
| // New behavior only for users of `prop-types` package |
| var err = new Error( |
| 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + |
| 'Use `PropTypes.checkPropTypes()` to call them. ' + |
| 'Read more at http://fb.me/use-check-prop-types' |
| ); |
| err.name = 'Invariant Violation'; |
| throw err; |
| } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') { |
| // Old behavior for people using React.PropTypes |
| var cacheKey = componentName + ':' + propName; |
| if ( |
| !manualPropTypeCallCache[cacheKey] && |
| // Avoid spamming the console because they are often not actionable except for lib authors |
| manualPropTypeWarningCount < 3 |
| ) { |
| printWarning( |
| 'You are manually calling a React.PropTypes validation ' + |
| 'function for the `' + propFullName + '` prop on `' + componentName + '`. This is deprecated ' + |
| 'and will throw in the standalone `prop-types` package. ' + |
| 'You may be seeing this warning due to a third-party PropTypes ' + |
| 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.' |
| ); |
| manualPropTypeCallCache[cacheKey] = true; |
| manualPropTypeWarningCount++; |
| } |
| } |
| } |
| if (props[propName] == null) { |
| if (isRequired) { |
| if (props[propName] === null) { |
| return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.')); |
| } |
| return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.')); |
| } |
| return null; |
| } else { |
| return validate(props, propName, componentName, location, propFullName); |
| } |
| } |
| |
| var chainedCheckType = checkType.bind(null, false); |
| chainedCheckType.isRequired = checkType.bind(null, true); |
| |
| return chainedCheckType; |
| } |
| |
| function createPrimitiveTypeChecker(expectedType) { |
| function validate(props, propName, componentName, location, propFullName, secret) { |
| var propValue = props[propName]; |
| var propType = getPropType(propValue); |
| if (propType !== expectedType) { |
| // `propValue` being instance of, say, date/regexp, pass the 'object' |
| // check, but we can offer a more precise error message here rather than |
| // 'of type `object`'. |
| var preciseType = getPreciseType(propValue); |
| |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.')); |
| } |
| return null; |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createAnyTypeChecker() { |
| return createChainableTypeChecker(emptyFunctionThatReturnsNull); |
| } |
| |
| function createArrayOfTypeChecker(typeChecker) { |
| function validate(props, propName, componentName, location, propFullName) { |
| if (typeof typeChecker !== 'function') { |
| return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.'); |
| } |
| var propValue = props[propName]; |
| if (!Array.isArray(propValue)) { |
| var propType = getPropType(propValue); |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.')); |
| } |
| for (var i = 0; i < propValue.length; i++) { |
| var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret); |
| if (error instanceof Error) { |
| return error; |
| } |
| } |
| return null; |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createElementTypeChecker() { |
| function validate(props, propName, componentName, location, propFullName) { |
| var propValue = props[propName]; |
| if (!isValidElement(propValue)) { |
| var propType = getPropType(propValue); |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.')); |
| } |
| return null; |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createElementTypeTypeChecker() { |
| function validate(props, propName, componentName, location, propFullName) { |
| var propValue = props[propName]; |
| if (!ReactIs.isValidElementType(propValue)) { |
| var propType = getPropType(propValue); |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement type.')); |
| } |
| return null; |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createInstanceTypeChecker(expectedClass) { |
| function validate(props, propName, componentName, location, propFullName) { |
| if (!(props[propName] instanceof expectedClass)) { |
| var expectedClassName = expectedClass.name || ANONYMOUS; |
| var actualClassName = getClassName(props[propName]); |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.')); |
| } |
| return null; |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createEnumTypeChecker(expectedValues) { |
| if (!Array.isArray(expectedValues)) { |
| if (process.env.NODE_ENV !== 'production') { |
| if (arguments.length > 1) { |
| printWarning( |
| 'Invalid arguments supplied to oneOf, expected an array, got ' + arguments.length + ' arguments. ' + |
| 'A common mistake is to write oneOf(x, y, z) instead of oneOf([x, y, z]).' |
| ); |
| } else { |
| printWarning('Invalid argument supplied to oneOf, expected an array.'); |
| } |
| } |
| return emptyFunctionThatReturnsNull; |
| } |
| |
| function validate(props, propName, componentName, location, propFullName) { |
| var propValue = props[propName]; |
| for (var i = 0; i < expectedValues.length; i++) { |
| if (is(propValue, expectedValues[i])) { |
| return null; |
| } |
| } |
| |
| var valuesString = JSON.stringify(expectedValues, function replacer(key, value) { |
| var type = getPreciseType(value); |
| if (type === 'symbol') { |
| return String(value); |
| } |
| return value; |
| }); |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + String(propValue) + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.')); |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createObjectOfTypeChecker(typeChecker) { |
| function validate(props, propName, componentName, location, propFullName) { |
| if (typeof typeChecker !== 'function') { |
| return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.'); |
| } |
| var propValue = props[propName]; |
| var propType = getPropType(propValue); |
| if (propType !== 'object') { |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.')); |
| } |
| for (var key in propValue) { |
| if (has(propValue, key)) { |
| var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); |
| if (error instanceof Error) { |
| return error; |
| } |
| } |
| } |
| return null; |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createUnionTypeChecker(arrayOfTypeCheckers) { |
| if (!Array.isArray(arrayOfTypeCheckers)) { |
| process.env.NODE_ENV !== 'production' ? printWarning('Invalid argument supplied to oneOfType, expected an instance of array.') : void 0; |
| return emptyFunctionThatReturnsNull; |
| } |
| |
| for (var i = 0; i < arrayOfTypeCheckers.length; i++) { |
| var checker = arrayOfTypeCheckers[i]; |
| if (typeof checker !== 'function') { |
| printWarning( |
| 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' + |
| 'received ' + getPostfixForTypeWarning(checker) + ' at index ' + i + '.' |
| ); |
| return emptyFunctionThatReturnsNull; |
| } |
| } |
| |
| function validate(props, propName, componentName, location, propFullName) { |
| for (var i = 0; i < arrayOfTypeCheckers.length; i++) { |
| var checker = arrayOfTypeCheckers[i]; |
| if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) { |
| return null; |
| } |
| } |
| |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.')); |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createNodeChecker() { |
| function validate(props, propName, componentName, location, propFullName) { |
| if (!isNode(props[propName])) { |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.')); |
| } |
| return null; |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createShapeTypeChecker(shapeTypes) { |
| function validate(props, propName, componentName, location, propFullName) { |
| var propValue = props[propName]; |
| var propType = getPropType(propValue); |
| if (propType !== 'object') { |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); |
| } |
| for (var key in shapeTypes) { |
| var checker = shapeTypes[key]; |
| if (!checker) { |
| continue; |
| } |
| var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); |
| if (error) { |
| return error; |
| } |
| } |
| return null; |
| } |
| return createChainableTypeChecker(validate); |
| } |
| |
| function createStrictShapeTypeChecker(shapeTypes) { |
| function validate(props, propName, componentName, location, propFullName) { |
| var propValue = props[propName]; |
| var propType = getPropType(propValue); |
| if (propType !== 'object') { |
| return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); |
| } |
| // We need to check all keys in case some are required but missing from |
| // props. |
| var allKeys = assign({}, props[propName], shapeTypes); |
| for (var key in allKeys) { |
| var checker = shapeTypes[key]; |
| if (!checker) { |
| return new PropTypeError( |
| 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' + |
| '\nBad object: ' + JSON.stringify(props[propName], null, ' ') + |
| '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ') |
| ); |
| } |
| var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); |
| if (error) { |
| return error; |
| } |
| } |
| return null; |
| } |
| |
| return createChainableTypeChecker(validate); |
| } |
| |
| function isNode(propValue) { |
| switch (typeof propValue) { |
| case 'number': |
| case 'string': |
| case 'undefined': |
| return true; |
| case 'boolean': |
| return !propValue; |
| case 'object': |
| if (Array.isArray(propValue)) { |
| return propValue.every(isNode); |
| } |
| if (propValue === null || isValidElement(propValue)) { |
| return true; |
| } |
| |
| var iteratorFn = getIteratorFn(propValue); |
| if (iteratorFn) { |
| var iterator = iteratorFn.call(propValue); |
| var step; |
| if (iteratorFn !== propValue.entries) { |
| while (!(step = iterator.next()).done) { |
| if (!isNode(step.value)) { |
| return false; |
| } |
| } |
| } else { |
| // Iterator will provide entry [k,v] tuples rather than values. |
| while (!(step = iterator.next()).done) { |
| var entry = step.value; |
| if (entry) { |
| if (!isNode(entry[1])) { |
| return false; |
| } |
| } |
| } |
| } |
| } else { |
| return false; |
| } |
| |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| function isSymbol(propType, propValue) { |
| // Native Symbol. |
| if (propType === 'symbol') { |
| return true; |
| } |
| |
| // falsy value can't be a Symbol |
| if (!propValue) { |
| return false; |
| } |
| |
| // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' |
| if (propValue['@@toStringTag'] === 'Symbol') { |
| return true; |
| } |
| |
| // Fallback for non-spec compliant Symbols which are polyfilled. |
| if (typeof Symbol === 'function' && propValue instanceof Symbol) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| // Equivalent of `typeof` but with special handling for array and regexp. |
| function getPropType(propValue) { |
| var propType = typeof propValue; |
| if (Array.isArray(propValue)) { |
| return 'array'; |
| } |
| if (propValue instanceof RegExp) { |
| // Old webkits (at least until Android 4.0) return 'function' rather than |
| // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ |
| // passes PropTypes.object. |
| return 'object'; |
| } |
| if (isSymbol(propType, propValue)) { |
| return 'symbol'; |
| } |
| return propType; |
| } |
| |
| // This handles more types than `getPropType`. Only used for error messages. |
| // See `createPrimitiveTypeChecker`. |
| function getPreciseType(propValue) { |
| if (typeof propValue === 'undefined' || propValue === null) { |
| return '' + propValue; |
| } |
| var propType = getPropType(propValue); |
| if (propType === 'object') { |
| if (propValue instanceof Date) { |
| return 'date'; |
| } else if (propValue instanceof RegExp) { |
| return 'regexp'; |
| } |
| } |
| return propType; |
| } |
| |
| // Returns a string that is postfixed to a warning about an invalid type. |
| // For example, "undefined" or "of type array" |
| function getPostfixForTypeWarning(value) { |
| var type = getPreciseType(value); |
| switch (type) { |
| case 'array': |
| case 'object': |
| return 'an ' + type; |
| case 'boolean': |
| case 'date': |
| case 'regexp': |
| return 'a ' + type; |
| default: |
| return type; |
| } |
| } |
| |
| // Returns class name of the object, if any. |
| function getClassName(propValue) { |
| if (!propValue.constructor || !propValue.constructor.name) { |
| return ANONYMOUS; |
| } |
| return propValue.constructor.name; |
| } |
| |
| ReactPropTypes.checkPropTypes = checkPropTypes; |
| ReactPropTypes.resetWarningCache = checkPropTypes.resetWarningCache; |
| ReactPropTypes.PropTypes = ReactPropTypes; |
| |
| return ReactPropTypes; |
| }; |