From 524ce20d9e68ca2919d9a657a1e666bffb77c511 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 11 Apr 2017 10:10:04 -0700 Subject: [PATCH] Added createClass and PropTypes getters (w/ depreaction warnings) to React --- package.json | 6 +- scripts/rollup/bundles.js | 7 +- scripts/rollup/results.json | 26 +- src/isomorphic/React.js | 20 +- src/isomorphic/__tests__/React-test.js | 14 +- src/isomorphic/classic/class/createClass.js | 19 + .../classic/types/ReactPropTypes.js | 547 +----------------- .../ReactPropTypesProduction-test.js | 219 ------- .../classic/types/checkPropTypes.js | 82 +-- yarn.lock | 7 +- 10 files changed, 81 insertions(+), 866 deletions(-) create mode 100644 src/isomorphic/classic/class/createClass.js delete mode 100644 src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js diff --git a/package.json b/package.json index f8dc8b83fd..013388e7b2 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "coffee-script": "^1.8.0", "core-js": "^2.2.1", "coveralls": "^2.11.6", - "create-react-class": "^15.5.0", "del": "^2.0.2", "derequire": "^2.0.3", "escape-string-regexp": "^1.0.5", @@ -73,7 +72,6 @@ "object-assign": "^4.1.1", "platform": "^1.1.0", "prettier": "^0.22.0", - "prop-types": "^15.5.6", "rimraf": "^2.6.1", "rollup": "^0.41.6", "rollup-plugin-alias": "^1.2.1", @@ -95,6 +93,10 @@ "node": "4.x || 5.x || 6.x || 7.x", "npm": "2.x || 3.x || 4.x" }, + "dependencies": { + "create-react-class": "^15.5.2", + "prop-types": "^15.5.6" + }, "commonerConfig": { "version": 7 }, diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 80f7361418..9af8766572 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -45,7 +45,12 @@ const bundles = [ sourceMap: false, }, entry: 'src/isomorphic/React.js', - externals: [], + externals: [ + 'create-react-class/factory', + 'prop-types', + 'prop-types/checkPropTypes', + 'prop-types/factory', + ], fbEntry: 'src/fb/ReactFBEntry.js', hasteName: 'React', isRenderer: false, diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json index d3774916fd..a193b5fb91 100644 --- a/scripts/rollup/results.json +++ b/scripts/rollup/results.json @@ -1,13 +1,13 @@ { - "branch": null, + "branch": "prop-types", "bundleSizes": { "react.development.js (UMD_DEV)": { - "size": 92740, - "gzip": 23440 + "size": 76661, + "gzip": 19565 }, "react.production.min.js (UMD_PROD)": { - "size": 10409, - "gzip": 4091 + "size": 10467, + "gzip": 4074 }, "react-dom.development.js (UMD_DEV)": { "size": 563910, @@ -34,20 +34,20 @@ "gzip": 28991 }, "react.development.js (NODE_DEV)": { - "size": 85810, - "gzip": 21432 + "size": 69636, + "gzip": 17533 }, "react.production.min.js (NODE_PROD)": { - "size": 9288, - "gzip": 3659 + "size": 9226, + "gzip": 3623 }, "React-dev.js (FB_DEV)": { - "size": 87652, - "gzip": 22071 + "size": 71493, + "gzip": 18168 }, "React-prod.js (FB_PROD)": { - "size": 37663, - "gzip": 9519 + "size": 36701, + "gzip": 9254 }, "ReactDOMStack-dev.js (FB_DEV)": { "size": 522667, diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index ccc351225e..9f1f7bc368 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -20,6 +20,7 @@ var ReactVersion = require('ReactVersion'); var onlyChild = require('onlyChild'); var checkPropTypes = require('checkPropTypes'); +var createReactClass = require('createClass'); var createElement = ReactElement.createElement; var createFactory = ReactElement.createFactory; @@ -28,6 +29,7 @@ var cloneElement = ReactElement.cloneElement; if (__DEV__) { var warning = require('fbjs/lib/warning'); var canDefineProperty = require('canDefineProperty'); + var didWarnPropTypesDeprecated = false; var ReactElementValidator = require('ReactElementValidator'); createElement = ReactElementValidator.createElement; createFactory = ReactElementValidator.createFactory; @@ -60,7 +62,8 @@ var React = { // Classic - PropTypes: ReactPropTypes, + PropTypes: ReactPropTypes, // TODO (bvaughn) Remove this getter in 16.0.0-alpha.10 + createClass: createReactClass, // TODO (bvaughn) Remove this getter in 16.0.0-alpha.10 createFactory: createFactory, createMixin: createMixin, @@ -95,6 +98,7 @@ if (__DEV__) { return mixin; }; + // TODO (bvaughn) Remove both of these deprecation warnings in 16.0.0-alpha.10 if (canDefineProperty) { Object.defineProperty(React, 'createClass', { get: function() { @@ -106,7 +110,19 @@ if (__DEV__) { 'drop-in replacement.', ); warnedForCreateClass = true; - return undefined; + return createReactClass; + }, + }); + + Object.defineProperty(React, 'PropTypes', { + get() { + warning( + didWarnPropTypesDeprecated, + 'PropTypes have moved out of the react package. ' + + 'Use the prop-types package from npm instead.', + ); + didWarnPropTypesDeprecated = true; + return ReactPropTypes; }, }); } diff --git a/src/isomorphic/__tests__/React-test.js b/src/isomorphic/__tests__/React-test.js index f2ea926dd9..8796f46a87 100644 --- a/src/isomorphic/__tests__/React-test.js +++ b/src/isomorphic/__tests__/React-test.js @@ -32,7 +32,7 @@ describe('React', () => { spyOn(console, 'error'); let createClass = React.createClass; createClass = React.createClass; - expect(createClass).toBe(undefined); + expect(createClass).not.toBe(undefined); expectDev(console.error.calls.count()).toBe(1); expectDev(console.error.calls.argsFor(0)[0]).toContain( 'React.createClass is no longer supported. Use a plain ' + @@ -41,4 +41,16 @@ describe('React', () => { 'drop-in replacement.', ); }); + + it('should warn once when attempting to access React.PropTypes', () => { + spyOn(console, 'error'); + let PropTypes = React.PropTypes; + PropTypes = React.PropTypes; + expect(PropTypes).not.toBe(undefined); + expectDev(console.error.calls.count()).toBe(1); + expectDev(console.error.calls.argsFor(0)[0]).toContain( + 'PropTypes have moved out of the react package. ' + + 'Use the prop-types package from npm instead.', + ); + }); }); diff --git a/src/isomorphic/classic/class/createClass.js b/src/isomorphic/classic/class/createClass.js new file mode 100644 index 0000000000..3791e5392d --- /dev/null +++ b/src/isomorphic/classic/class/createClass.js @@ -0,0 +1,19 @@ +/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule createClass + */ + +'use strict'; + +var {Component} = require('ReactBaseClasses'); +var {isValidElement} = require('ReactElement'); +var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue'); +var factory = require('create-react-class/factory'); + +module.exports = factory(Component, isValidElement, ReactNoopUpdateQueue); diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index 01710a0086..5c0ca77351 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -11,548 +11,7 @@ 'use strict'; -var ReactElement = require('ReactElement'); -var ReactPropTypesSecret = require('ReactPropTypesSecret'); +var {isValidElement} = require('ReactElement'); +var factory = require('prop-types/factory'); -var emptyFunction = require('fbjs/lib/emptyFunction'); -var getIteratorFn = require('getIteratorFn'); -var invariant = require('fbjs/lib/invariant'); -var warning = require('fbjs/lib/warning'); - -/** - * 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 = '<>'; - -var ReactPropTypes; - -if (__DEV__) { - // Keep in sync with production version below - 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(), - instanceOf: createInstanceTypeChecker, - node: createNodeChecker(), - objectOf: createObjectOfTypeChecker, - oneOf: createEnumTypeChecker, - oneOfType: createUnionTypeChecker, - shape: createShapeTypeChecker, - }; -} else { - var productionTypeChecker = function() { - invariant( - false, - 'React.PropTypes type checking code is stripped in production.', - ); - }; - productionTypeChecker.isRequired = productionTypeChecker; - var getProductionTypeChecker = () => productionTypeChecker; - // Keep in sync with development version above - ReactPropTypes = { - array: productionTypeChecker, - bool: productionTypeChecker, - func: productionTypeChecker, - number: productionTypeChecker, - object: productionTypeChecker, - string: productionTypeChecker, - symbol: productionTypeChecker, - - any: productionTypeChecker, - arrayOf: getProductionTypeChecker, - element: productionTypeChecker, - instanceOf: getProductionTypeChecker, - node: productionTypeChecker, - objectOf: getProductionTypeChecker, - oneOf: getProductionTypeChecker, - oneOfType: getProductionTypeChecker, - shape: getProductionTypeChecker, - }; -} - -/** - * 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 (__DEV__) { - var manualPropTypeCallCache = {}; - } - function checkType( - isRequired, - props, - propName, - componentName, - location, - propFullName, - secret, - ) { - componentName = componentName || ANONYMOUS; - propFullName = propFullName || propName; - if (__DEV__) { - if (secret !== ReactPropTypesSecret && typeof console !== 'undefined') { - var cacheKey = `${componentName}:${propName}`; - if (!manualPropTypeCallCache[cacheKey]) { - warning( - false, - 'You are manually calling a React.PropTypes validation ' + - 'function for the `%s` prop on `%s`. This is deprecated ' + - 'and will not work in production with the next major version. ' + - 'You may be seeing this warning due to a third-party PropTypes ' + - 'library. See https://fb.me/react-warning-dont-call-proptypes ' + - 'for details.', - propFullName, - componentName, - ); - manualPropTypeCallCache[cacheKey] = true; - } - } - } - 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(emptyFunction.thatReturnsNull); -} - -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 (!ReactElement.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 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)) { - warning( - false, - 'Invalid argument supplied to oneOf, expected an instance of array.', - ); - return emptyFunction.thatReturnsNull; - } - - 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); - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` of value \`${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 (propValue.hasOwnProperty(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)) { - warning( - false, - 'Invalid argument supplied to oneOfType, expected an instance of array.', - ); - return emptyFunction.thatReturnsNull; - } - - 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 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 || ReactElement.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; - } - - // 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) { - var propType = getPropType(propValue); - if (propType === 'object') { - if (propValue instanceof Date) { - return 'date'; - } else if (propValue instanceof RegExp) { - return 'regexp'; - } - } - return propType; -} - -// Returns class name of the object, if any. -function getClassName(propValue) { - if (!propValue.constructor || !propValue.constructor.name) { - return ANONYMOUS; - } - return propValue.constructor.name; -} - -module.exports = ReactPropTypes; +module.exports = factory(isValidElement); diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js deleted file mode 100644 index 33ccb85bd8..0000000000 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ /dev/null @@ -1,219 +0,0 @@ -/** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @emails react-core - */ - -'use strict'; - -describe('ReactPropTypesProduction', function() { - var PropTypes; - var React; - var ReactTestUtils; - var oldProcess; - - beforeEach(function() { - __DEV__ = false; - - // Mutating process.env.NODE_ENV would cause our babel plugins to do the - // wrong thing. If you change this, make sure to test with jest --no-cache. - oldProcess = process; - global.process = { - ...process, - env: {...process.env, NODE_ENV: 'production'}, - }; - - jest.resetModules(); - PropTypes = require('ReactPropTypes'); - React = require('react'); - ReactTestUtils = require('ReactTestUtils'); - }); - - afterEach(function() { - __DEV__ = true; - global.process = oldProcess; - }); - - function expectThrowsInProduction(declaration, value) { - var props = {testProp: value}; - expect(() => { - declaration(props, 'testProp', 'testComponent', 'prop'); - }).toThrowError('Minified React error #144'); - } - - describe('Primitive Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.array, /please/); - expectThrowsInProduction(PropTypes.array.isRequired, /please/); - expectThrowsInProduction(PropTypes.array.isRequired, null); - expectThrowsInProduction(PropTypes.array.isRequired, undefined); - expectThrowsInProduction(PropTypes.bool, []); - expectThrowsInProduction(PropTypes.bool.isRequired, []); - expectThrowsInProduction(PropTypes.bool.isRequired, null); - expectThrowsInProduction(PropTypes.bool.isRequired, undefined); - expectThrowsInProduction(PropTypes.func, false); - expectThrowsInProduction(PropTypes.func.isRequired, false); - expectThrowsInProduction(PropTypes.func.isRequired, null); - expectThrowsInProduction(PropTypes.func.isRequired, undefined); - expectThrowsInProduction(PropTypes.number, function() {}); - expectThrowsInProduction(PropTypes.number.isRequired, function() {}); - expectThrowsInProduction(PropTypes.number.isRequired, null); - expectThrowsInProduction(PropTypes.number.isRequired, undefined); - expectThrowsInProduction(PropTypes.string, 0); - expectThrowsInProduction(PropTypes.string.isRequired, 0); - expectThrowsInProduction(PropTypes.string.isRequired, null); - expectThrowsInProduction(PropTypes.string.isRequired, undefined); - expectThrowsInProduction(PropTypes.symbol, 0); - expectThrowsInProduction(PropTypes.symbol.isRequired, 0); - expectThrowsInProduction(PropTypes.symbol.isRequired, null); - expectThrowsInProduction(PropTypes.symbol.isRequired, undefined); - expectThrowsInProduction(PropTypes.object, ''); - expectThrowsInProduction(PropTypes.object.isRequired, ''); - expectThrowsInProduction(PropTypes.object.isRequired, null); - expectThrowsInProduction(PropTypes.object.isRequired, undefined); - }); - }); - - describe('Any Type', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.any, null); - expectThrowsInProduction(PropTypes.any.isRequired, null); - expectThrowsInProduction(PropTypes.any.isRequired, undefined); - }); - }); - - describe('ArrayOf Type', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.arrayOf({foo: PropTypes.string}), { - foo: 'bar', - }); - expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number), [ - 1, - 2, - 'b', - ]); - expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number), { - '0': 'maybe-array', - length: 1, - }); - expectThrowsInProduction( - PropTypes.arrayOf(PropTypes.number).isRequired, - null, - ); - expectThrowsInProduction( - PropTypes.arrayOf(PropTypes.number).isRequired, - undefined, - ); - }); - }); - - describe('Component Type', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.element, [
,
]); - expectThrowsInProduction(PropTypes.element, 123); - expectThrowsInProduction(PropTypes.element, 'foo'); - expectThrowsInProduction(PropTypes.element, false); - expectThrowsInProduction(PropTypes.element.isRequired, null); - expectThrowsInProduction(PropTypes.element.isRequired, undefined); - }); - }); - - describe('Instance Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.instanceOf(Date), {}); - expectThrowsInProduction(PropTypes.instanceOf(Date).isRequired, {}); - }); - }); - - describe('React Component Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.node, {}); - expectThrowsInProduction(PropTypes.node.isRequired, null); - expectThrowsInProduction(PropTypes.node.isRequired, undefined); - }); - }); - - describe('ObjectOf Type', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.objectOf({foo: PropTypes.string}), { - foo: 'bar', - }); - expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), { - a: 1, - b: 2, - c: 'b', - }); - expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), [1, 2]); - expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), null); - expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), undefined); - }); - }); - - describe('OneOf Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.oneOf('red', 'blue'), 'red'); - expectThrowsInProduction(PropTypes.oneOf(['red', 'blue']), true); - expectThrowsInProduction(PropTypes.oneOf(['red', 'blue']), null); - expectThrowsInProduction(PropTypes.oneOf(['red', 'blue']), undefined); - }); - }); - - describe('Union Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction( - PropTypes.oneOfType(PropTypes.string, PropTypes.number), - 'red', - ); - expectThrowsInProduction( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - [], - ); - expectThrowsInProduction( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - null, - ); - expectThrowsInProduction( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - undefined, - ); - }); - }); - - describe('Shape Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.shape({}), 'some string'); - expectThrowsInProduction( - PropTypes.shape({key: PropTypes.number}).isRequired, - null, - ); - expectThrowsInProduction( - PropTypes.shape({key: PropTypes.number}).isRequired, - undefined, - ); - }); - }); - - describe('Custom validator', function() { - beforeEach(function() { - jest.resetModules(); - }); - - it('should not have been called', function() { - var spy = jest.fn(); - function Component() { - return
; - } - Component.propTypes = {num: spy}; - - var instance = ; - ReactTestUtils.renderIntoDocument(instance); - - expect(spy).not.toBeCalled(); - }); - }); -}); diff --git a/src/isomorphic/classic/types/checkPropTypes.js b/src/isomorphic/classic/types/checkPropTypes.js index 5168efd9c0..32d9ecc677 100644 --- a/src/isomorphic/classic/types/checkPropTypes.js +++ b/src/isomorphic/classic/types/checkPropTypes.js @@ -11,84 +11,4 @@ 'use strict'; -var ReactPropTypesSecret = require('ReactPropTypesSecret'); - -var invariant = require('fbjs/lib/invariant'); -var warning = require('fbjs/lib/warning'); - -var loggedTypeFailures = {}; - -/** - * Assert that the values match with the type specs. - * Error messages are memorized and will only be shown once. - * - * @param {object} typeSpecs Map of name to a ReactPropType - * @param {object} values Runtime values that need to be type-checked - * @param {string} location e.g. "prop", "context", "child context" - * @param {string} componentName Name of the component for error messages. - * @param {?Function} getStack Returns the component stack. - * @private - */ -function checkPropTypes(typeSpecs, values, location, componentName, getStack) { - if (__DEV__) { - for (var typeSpecName in typeSpecs) { - if (typeSpecs.hasOwnProperty(typeSpecName)) { - 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 { - // This is intentionally an invariant that gets caught. It's the same - // behavior as without this statement except with a better message. - invariant( - typeof typeSpecs[typeSpecName] === 'function', - '%s: %s type `%s` is invalid; it must be a function, usually from ' + - 'React.PropTypes.', - componentName || 'React class', - location, - typeSpecName, - ); - error = typeSpecs[typeSpecName]( - values, - typeSpecName, - componentName, - location, - null, - ReactPropTypesSecret, - ); - } catch (ex) { - error = ex; - } - warning( - !error || error instanceof Error, - '%s: type specification of %s `%s` is invalid; the type checker ' + - 'function must return `null` or an `Error` but returned a %s. ' + - 'You may have forgotten to pass an argument to the type checker ' + - 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + - 'shape all require an argument).', - componentName || 'React class', - location, - typeSpecName, - typeof error, - ); - 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; - - var stack = getStack ? getStack() : ''; - - warning( - false, - 'Failed %s type: %s%s', - location, - error.message, - stack != null ? stack : '', - ); - } - } - } - } -} - -module.exports = checkPropTypes; +module.exports = require('prop-types/checkPropTypes'); diff --git a/yarn.lock b/yarn.lock index b297a7165e..bd8f7924ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1438,11 +1438,12 @@ create-hmac@^1.1.0, create-hmac@^1.1.2: create-hash "^1.1.0" inherits "^2.0.1" -create-react-class@^15.5.0: - version "15.5.0" - resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.0.tgz#7508ffcad56a0804fb244d6ff70b07648abfe5fb" +create-react-class@^15.5.2: + version "15.5.2" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.2.tgz#6a8758348df660b88326a0e764d569f274aad681" dependencies: fbjs "^0.8.9" + object-assign "^4.1.1" cross-spawn-async@^2.2.2: version "2.2.5"