diff --git a/README.md b/README.md
index 390f423..f5f841f 100644
--- a/README.md
+++ b/README.md
@@ -25,11 +25,42 @@ If you prefer a `
```
-## Difference from `React.PropTypes`: Development and Production Versions
+## Difference from `React.PropTypes`: Don’t Call Validator Functions
-In production, **all validator functions are replaced with empty functions that throw an error**. This is done to optimize the bundle size. This is new behavior, and you will only encounter it when you migrate from `React.PropTypes` to the `prop-types` package. For the vast majority of components, this doesn’t matter, and if you didn’t see [this warning](https://facebook.github.io/react/warnings/dont-call-proptypes.html) in your components, your code is safe to migrate. This is not a breaking change in React because you are only opting into this change for a component by explicitly changing your imports to use `prop-types`.
+When you migrate components to use the standalone `prop-types`, **all validator functions will start throwing an error if you call them directly**. This makes sure that nobody relies on them in production code, and it is safe to strip their implementations to optimize the bundle size.
-Don’t call the validator functions manually in your code. React automatically calls `PropTypes` validators declared on your components in development version, and it won’t call them in production. **If you absolutely need to trigger the validation manually**, call `PropTypes.checkPropTypes(propTypes, props, location, componentName)`. Unlike the validators themselves, this function is safe to call in production, as it will be replaced by an empty function.
+Code like this is still fine:
+
+```js
+MyComponent.propTypes = {
+ myProp: PropTypes.bool
+};
+```
+
+However, code like this will not work with the `prop-types` package:
+
+```js
+// Will not work with `prop-types` package!
+var errorOrNull = PropTypes.bool(42, 'myProp', 'MyComponent', 'prop');
+```
+
+It will throw an error:
+
+```
+Calling PropTypes validators directly is not supported by the `prop-types` package.
+Use PropTypes.checkPropTypes() to call them.
+```
+
+This is new behavior, and you will only encounter it when you migrate from `React.PropTypes` to the `prop-types` package. For the vast majority of components, this doesn’t matter, and if you didn’t see [this warning](https://facebook.github.io/react/warnings/dont-call-proptypes.html) in your components, your code is safe to migrate. This is not a breaking change in React because you are only opting into this change for a component by explicitly changing your imports to use `prop-types`. If you temporarily need the old behavior, you can keep using `React.PropTypes` until React 16.
+
+**If you absolutely need to trigger the validation manually**, call `PropTypes.checkPropTypes()`. Unlike the validators themselves, this function is safe to call in production, as it will be replaced by an empty function:
+
+```js
+// Works with standalone PropTypes
+PropTypes.checkPropTypes(MyComponent.propTypes, props, 'prop', 'MyComponent');
+```
+
+**You might also see this error** if you’re calling a `PropTypes` validator from your own custom `PropTypes` validator. In this case, the fix is to make sure that you are passing *all* of the arguments to the inner function. There is a more in-depth explanation of how to fix it [on this page](https://facebook.github.io/react/warnings/dont-call-proptypes.html#fixing-the-false-positive-in-third-party-proptypes). Alternatively, you can temporarily keep using `React.PropTypes` until React 16, as it would still only warn in this case.
If you use a bundler like Browserify or Webpack, don’t forget to [follow these instructions](https://facebook.github.io/react/docs/installation.html#development-and-production-versions) to correctly bundle your application in development or production mode. Otherwise you’ll ship unnecessary code to your users.
diff --git a/__tests__/PropTypes-test.js b/__tests__/PropTypesDevelopmentReact15.js
similarity index 98%
rename from __tests__/PropTypes-test.js
rename to __tests__/PropTypesDevelopmentReact15.js
index 95431ac..de801c1 100644
--- a/__tests__/PropTypes-test.js
+++ b/__tests__/PropTypesDevelopmentReact15.js
@@ -13,11 +13,13 @@
var React;
var PropTypes;
-var checkPropTypes;
function resetWarningCache() {
jest.resetModules();
- checkPropTypes = require('../checkPropTypes');
+
+ React = require('react');
+ // This is how React 15 imports `prop-types`.
+ PropTypes = require('../factory')(React.isValidElement);
}
function getPropTypeWarningMessage(propTypes, object, componentName) {
@@ -27,7 +29,8 @@ function getPropTypeWarningMessage(propTypes, object, componentName) {
console.error.calls.reset();
}
resetWarningCache();
- checkPropTypes(propTypes, object, 'prop', 'testComponent');
+
+ PropTypes.checkPropTypes(propTypes, object, 'prop', 'testComponent');
const callCount = console.error.calls.count();
if (callCount > 1) {
throw new Error('Too many warnings.');
@@ -103,11 +106,8 @@ function expectWarningInDevelopment(declaration, value) {
console.error.calls.reset();
}
-describe('ReactPropTypes', () => {
+describe('PropTypesDevelopmentReact15', () => {
beforeEach(() => {
- React = require('react');
- PropTypes = require('../index');
- checkPropTypes = PropTypes.checkPropTypes;
resetWarningCache();
});
@@ -120,7 +120,7 @@ describe('ReactPropTypes', () => {
},
};
const props = {foo: 'foo'};
- const returnValue = checkPropTypes(
+ const returnValue = PropTypes.checkPropTypes(
propTypes,
props,
'prop',
@@ -139,7 +139,7 @@ describe('ReactPropTypes', () => {
},
};
const props = {foo: 'foo'};
- const returnValue = checkPropTypes(
+ const returnValue = PropTypes.checkPropTypes(
propTypes,
props,
'prop',
@@ -839,9 +839,9 @@ describe('ReactPropTypes', () => {
it('should warn if called manually in development', () => {
spyOn(console, 'error');
- expect(PropTypes.oneOf(['red', 'blue']), true);
- expect(PropTypes.oneOf(['red', 'blue']), null);
- expect(PropTypes.oneOf(['red', 'blue']), undefined);
+ expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), true);
+ expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), null);
+ expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), undefined);
});
});
diff --git a/__tests__/PropTypesDevelopmentStandalone-test.js b/__tests__/PropTypesDevelopmentStandalone-test.js
new file mode 100644
index 0000000..98c8162
--- /dev/null
+++ b/__tests__/PropTypesDevelopmentStandalone-test.js
@@ -0,0 +1,1053 @@
+/**
+ * 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';
+
+var React;
+var PropTypes;
+
+function resetWarningCache() {
+ jest.resetModules();
+
+ React = require('react');
+ PropTypes = require('../index');
+}
+
+function getPropTypeWarningMessage(propTypes, object, componentName) {
+ if (!console.error.calls) {
+ spyOn(console, 'error');
+ } else {
+ console.error.calls.reset();
+ }
+ resetWarningCache();
+
+ PropTypes.checkPropTypes(propTypes, object, 'prop', 'testComponent');
+ const callCount = console.error.calls.count();
+ if (callCount > 1) {
+ throw new Error('Too many warnings.');
+ }
+ const message = console.error.calls.argsFor(0)[0] || null;
+ console.error.calls.reset();
+
+ return message;
+}
+
+function typeCheckFail(declaration, value, expectedMessage) {
+ const propTypes = {
+ testProp: declaration,
+ };
+ const props = {
+ testProp: value,
+ };
+ const message = getPropTypeWarningMessage(propTypes, props, 'testComponent');
+ expect(message).toContain(expectedMessage);
+}
+
+function typeCheckFailRequiredValues(declaration) {
+ var specifiedButIsNullMsg = 'The prop `testProp` is marked as required in ' +
+ '`testComponent`, but its value is `null`.';
+ var unspecifiedMsg = 'The prop `testProp` is marked as required in ' +
+ '`testComponent`, but its value is \`undefined\`.';
+
+ var propTypes = {testProp: declaration};
+
+ // Required prop is null
+ var message1 = getPropTypeWarningMessage(
+ propTypes,
+ {testProp: null},
+ 'testComponent',
+ );
+ expect(message1).toContain(specifiedButIsNullMsg);
+
+ // Required prop is undefined
+ var message2 = getPropTypeWarningMessage(
+ propTypes,
+ {testProp: undefined},
+ 'testComponent',
+ );
+ expect(message2).toContain(unspecifiedMsg);
+
+ // Required prop is not a member of props object
+ var message3 = getPropTypeWarningMessage(propTypes, {}, 'testComponent');
+ expect(message3).toContain(unspecifiedMsg);
+}
+
+function typeCheckPass(declaration, value) {
+ const propTypes = {
+ testProp: declaration,
+ };
+ const props = {
+ testProp: value,
+ };
+ const message = getPropTypeWarningMessage(propTypes, props, 'testComponent');
+ expect(message).toBe(null);
+}
+
+function expectThrowsInDevelopment(declaration, value) {
+ resetWarningCache();
+ var props = {testProp: value};
+ expect(() => {
+ declaration(props, 'testProp', 'testComponent', 'prop');
+ }).toThrowError(
+ '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'
+ );
+}
+
+describe('PropTypesDevelopmentStandalone', () => {
+ beforeEach(() => {
+ resetWarningCache();
+ });
+
+ describe('checkPropTypes', () => {
+ it('does not return a value from a validator', () => {
+ spyOn(console, 'error');
+ const propTypes = {
+ foo(props, propName, componentName) {
+ return new Error('some error');
+ },
+ };
+ const props = {foo: 'foo'};
+ const returnValue = PropTypes.checkPropTypes(
+ propTypes,
+ props,
+ 'prop',
+ 'testComponent',
+ null,
+ );
+ expect(console.error.calls.argsFor(0)[0]).toContain('some error');
+ expect(returnValue).toBe(undefined);
+ });
+
+ it('does not throw if validator throws', () => {
+ spyOn(console, 'error');
+ const propTypes = {
+ foo(props, propName, componentName) {
+ throw new Error('some error');
+ },
+ };
+ const props = {foo: 'foo'};
+ const returnValue = PropTypes.checkPropTypes(
+ propTypes,
+ props,
+ 'prop',
+ 'testComponent',
+ null,
+ );
+ expect(console.error.calls.argsFor(0)[0]).toContain('some error');
+ expect(returnValue).toBe(undefined);
+ });
+ });
+
+ describe('Primitive Types', () => {
+ it('should warn for invalid strings', () => {
+ typeCheckFail(
+ PropTypes.string,
+ [],
+ 'Invalid prop `testProp` of type `array` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ typeCheckFail(
+ PropTypes.string,
+ false,
+ 'Invalid prop `testProp` of type `boolean` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ typeCheckFail(
+ PropTypes.string,
+ 0,
+ 'Invalid prop `testProp` of type `number` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ typeCheckFail(
+ PropTypes.string,
+ {},
+ 'Invalid prop `testProp` of type `object` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ typeCheckFail(
+ PropTypes.string,
+ Symbol(),
+ 'Invalid prop `testProp` of type `symbol` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ });
+
+ it('should fail date and regexp correctly', () => {
+ typeCheckFail(
+ PropTypes.string,
+ new Date(),
+ 'Invalid prop `testProp` of type `date` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ typeCheckFail(
+ PropTypes.string,
+ /please/,
+ 'Invalid prop `testProp` of type `regexp` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ });
+
+ it('should not warn for valid values', () => {
+ typeCheckPass(PropTypes.array, []);
+ typeCheckPass(PropTypes.bool, false);
+ typeCheckPass(PropTypes.func, function() {});
+ typeCheckPass(PropTypes.number, 0);
+ typeCheckPass(PropTypes.string, '');
+ typeCheckPass(PropTypes.object, {});
+ typeCheckPass(PropTypes.object, new Date());
+ typeCheckPass(PropTypes.object, /please/);
+ typeCheckPass(PropTypes.symbol, Symbol());
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ typeCheckPass(PropTypes.string, null);
+ typeCheckPass(PropTypes.string, undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(PropTypes.string.isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(PropTypes.array, /please/);
+ expectThrowsInDevelopment(PropTypes.array, []);
+ expectThrowsInDevelopment(PropTypes.array.isRequired, /please/);
+ expectThrowsInDevelopment(PropTypes.array.isRequired, []);
+ expectThrowsInDevelopment(PropTypes.array.isRequired, null);
+ expectThrowsInDevelopment(PropTypes.array.isRequired, undefined);
+ expectThrowsInDevelopment(PropTypes.bool, []);
+ expectThrowsInDevelopment(PropTypes.bool, true);
+ expectThrowsInDevelopment(PropTypes.bool.isRequired, []);
+ expectThrowsInDevelopment(PropTypes.bool.isRequired, true);
+ expectThrowsInDevelopment(PropTypes.bool.isRequired, null);
+ expectThrowsInDevelopment(PropTypes.bool.isRequired, undefined);
+ expectThrowsInDevelopment(PropTypes.func, false);
+ expectThrowsInDevelopment(PropTypes.func, function() {});
+ expectThrowsInDevelopment(PropTypes.func.isRequired, false);
+ expectThrowsInDevelopment(PropTypes.func.isRequired, function() {});
+ expectThrowsInDevelopment(PropTypes.func.isRequired, null);
+ expectThrowsInDevelopment(PropTypes.func.isRequired, undefined);
+ expectThrowsInDevelopment(PropTypes.number, function() {});
+ expectThrowsInDevelopment(PropTypes.number, 42);
+ expectThrowsInDevelopment(PropTypes.number.isRequired, function() {});
+ expectThrowsInDevelopment(PropTypes.number.isRequired, 42);
+ expectThrowsInDevelopment(PropTypes.number.isRequired, null);
+ expectThrowsInDevelopment(PropTypes.number.isRequired, undefined);
+ expectThrowsInDevelopment(PropTypes.string, 0);
+ expectThrowsInDevelopment(PropTypes.string, 'foo');
+ expectThrowsInDevelopment(PropTypes.string.isRequired, 0);
+ expectThrowsInDevelopment(PropTypes.string.isRequired, 'foo');
+ expectThrowsInDevelopment(PropTypes.string.isRequired, null);
+ expectThrowsInDevelopment(PropTypes.string.isRequired, undefined);
+ expectThrowsInDevelopment(PropTypes.symbol, 0);
+ expectThrowsInDevelopment(PropTypes.symbol, Symbol('Foo'));
+ expectThrowsInDevelopment(PropTypes.symbol.isRequired, 0);
+ expectThrowsInDevelopment(PropTypes.symbol.isRequired, Symbol('Foo'));
+ expectThrowsInDevelopment(PropTypes.symbol.isRequired, null);
+ expectThrowsInDevelopment(PropTypes.symbol.isRequired, undefined);
+ expectThrowsInDevelopment(PropTypes.object, '');
+ expectThrowsInDevelopment(PropTypes.object, {foo: 'bar'});
+ expectThrowsInDevelopment(PropTypes.object.isRequired, '');
+ expectThrowsInDevelopment(PropTypes.object.isRequired, {foo: 'bar'});
+ expectThrowsInDevelopment(PropTypes.object.isRequired, null);
+ expectThrowsInDevelopment(PropTypes.object.isRequired, undefined);
+ });
+ });
+
+ describe('Any type', () => {
+ it('should should accept any value', () => {
+ typeCheckPass(PropTypes.any, 0);
+ typeCheckPass(PropTypes.any, 'str');
+ typeCheckPass(PropTypes.any, []);
+ typeCheckPass(PropTypes.any, Symbol());
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ typeCheckPass(PropTypes.any, null);
+ typeCheckPass(PropTypes.any, undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(PropTypes.any.isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(PropTypes.any, null);
+ expectThrowsInDevelopment(PropTypes.any.isRequired, null);
+ expectThrowsInDevelopment(PropTypes.any.isRequired, undefined);
+ });
+ });
+
+ describe('ArrayOf Type', () => {
+ it('should fail for invalid argument', () => {
+ typeCheckFail(
+ PropTypes.arrayOf({foo: PropTypes.string}),
+ {foo: 'bar'},
+ 'Property `testProp` of component `testComponent` has invalid PropType notation inside arrayOf.',
+ );
+ });
+
+ it('should support the arrayOf propTypes', () => {
+ typeCheckPass(PropTypes.arrayOf(PropTypes.number), [1, 2, 3]);
+ typeCheckPass(PropTypes.arrayOf(PropTypes.string), ['a', 'b', 'c']);
+ typeCheckPass(PropTypes.arrayOf(PropTypes.oneOf(['a', 'b'])), ['a', 'b']);
+ typeCheckPass(PropTypes.arrayOf(PropTypes.symbol), [Symbol(), Symbol()]);
+ });
+
+ it('should support arrayOf with complex types', () => {
+ typeCheckPass(
+ PropTypes.arrayOf(PropTypes.shape({a: PropTypes.number.isRequired})),
+ [{a: 1}, {a: 2}],
+ );
+
+ function Thing() {}
+ typeCheckPass(PropTypes.arrayOf(PropTypes.instanceOf(Thing)), [
+ new Thing(),
+ new Thing(),
+ ]);
+ });
+
+ it('should warn with invalid items in the array', () => {
+ typeCheckFail(
+ PropTypes.arrayOf(PropTypes.number),
+ [1, 2, 'b'],
+ 'Invalid prop `testProp[2]` of type `string` supplied to ' +
+ '`testComponent`, expected `number`.',
+ );
+ });
+
+ it('should warn with invalid complex types', () => {
+ function Thing() {}
+ var name = Thing.name || '<>';
+
+ typeCheckFail(
+ PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
+ [new Thing(), 'xyz'],
+ 'Invalid prop `testProp[1]` of type `String` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ name +
+ '`.',
+ );
+ });
+
+ it('should warn when passed something other than an array', () => {
+ typeCheckFail(
+ PropTypes.arrayOf(PropTypes.number),
+ {'0': 'maybe-array', length: 1},
+ 'Invalid prop `testProp` of type `object` supplied to ' +
+ '`testComponent`, expected an array.',
+ );
+ typeCheckFail(
+ PropTypes.arrayOf(PropTypes.number),
+ 123,
+ 'Invalid prop `testProp` of type `number` supplied to ' +
+ '`testComponent`, expected an array.',
+ );
+ typeCheckFail(
+ PropTypes.arrayOf(PropTypes.number),
+ 'string',
+ 'Invalid prop `testProp` of type `string` supplied to ' +
+ '`testComponent`, expected an array.',
+ );
+ });
+
+ it('should not warn when passing an empty array', () => {
+ typeCheckPass(PropTypes.arrayOf(PropTypes.number), []);
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ typeCheckPass(PropTypes.arrayOf(PropTypes.number), null);
+ typeCheckPass(PropTypes.arrayOf(PropTypes.number), undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(
+ PropTypes.arrayOf(PropTypes.number).isRequired,
+ );
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(PropTypes.arrayOf({foo: PropTypes.string}), {
+ foo: 'bar',
+ });
+ expectThrowsInDevelopment(PropTypes.arrayOf(PropTypes.number), [
+ 1,
+ 2,
+ 'b',
+ ]);
+ expectThrowsInDevelopment(PropTypes.arrayOf(PropTypes.number), {
+ '0': 'maybe-array',
+ length: 1,
+ });
+ expectThrowsInDevelopment(
+ PropTypes.arrayOf(PropTypes.number).isRequired,
+ null,
+ );
+ expectThrowsInDevelopment(
+ PropTypes.arrayOf(PropTypes.number).isRequired,
+ undefined,
+ );
+ });
+ });
+
+ describe('Component Type', () => {
+
+ it('should support components', () => {
+ typeCheckPass(PropTypes.element, );
+ });
+
+ it('should not support multiple components or scalar values', () => {
+ typeCheckFail(
+ PropTypes.element,
+ [, ],
+ 'Invalid prop `testProp` of type `array` supplied to `testComponent`, ' +
+ 'expected a single ReactElement.',
+ );
+ typeCheckFail(
+ PropTypes.element,
+ 123,
+ 'Invalid prop `testProp` of type `number` supplied to `testComponent`, ' +
+ 'expected a single ReactElement.',
+ );
+ typeCheckFail(
+ PropTypes.element,
+ 'foo',
+ 'Invalid prop `testProp` of type `string` supplied to `testComponent`, ' +
+ 'expected a single ReactElement.',
+ );
+ typeCheckFail(
+ PropTypes.element,
+ false,
+ 'Invalid prop `testProp` of type `boolean` supplied to `testComponent`, ' +
+ 'expected a single ReactElement.',
+ );
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ typeCheckPass(PropTypes.element, null);
+ typeCheckPass(PropTypes.element, undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(PropTypes.element.isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(PropTypes.element, [, ]);
+ expectThrowsInDevelopment(PropTypes.element, );
+ expectThrowsInDevelopment(PropTypes.element, 123);
+ expectThrowsInDevelopment(PropTypes.element, 'foo');
+ expectThrowsInDevelopment(PropTypes.element, false);
+ expectThrowsInDevelopment(PropTypes.element.isRequired, null);
+ expectThrowsInDevelopment(PropTypes.element.isRequired, undefined);
+ });
+ });
+
+ describe('Instance Types', () => {
+ it('should warn for invalid instances', () => {
+ function Person() {}
+ function Cat() {}
+ var personName = Person.name || '<>';
+ var dateName = Date.name || '<>';
+ var regExpName = RegExp.name || '<>';
+
+ typeCheckFail(
+ PropTypes.instanceOf(Person),
+ false,
+ 'Invalid prop `testProp` of type `Boolean` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ typeCheckFail(
+ PropTypes.instanceOf(Person),
+ {},
+ 'Invalid prop `testProp` of type `Object` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ typeCheckFail(
+ PropTypes.instanceOf(Person),
+ '',
+ 'Invalid prop `testProp` of type `String` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ typeCheckFail(
+ PropTypes.instanceOf(Date),
+ {},
+ 'Invalid prop `testProp` of type `Object` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ dateName +
+ '`.',
+ );
+ typeCheckFail(
+ PropTypes.instanceOf(RegExp),
+ {},
+ 'Invalid prop `testProp` of type `Object` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ regExpName +
+ '`.',
+ );
+ typeCheckFail(
+ PropTypes.instanceOf(Person),
+ new Cat(),
+ 'Invalid prop `testProp` of type `Cat` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ typeCheckFail(
+ PropTypes.instanceOf(Person),
+ Object.create(null),
+ 'Invalid prop `testProp` of type `<>` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ });
+
+ it('should not warn for valid values', () => {
+ function Person() {}
+ function Engineer() {}
+ Engineer.prototype = new Person();
+
+ typeCheckPass(PropTypes.instanceOf(Person), new Person());
+ typeCheckPass(PropTypes.instanceOf(Person), new Engineer());
+
+ typeCheckPass(PropTypes.instanceOf(Date), new Date());
+ typeCheckPass(PropTypes.instanceOf(RegExp), /please/);
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ typeCheckPass(PropTypes.instanceOf(String), null);
+ typeCheckPass(PropTypes.instanceOf(String), undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(PropTypes.instanceOf(String).isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(PropTypes.instanceOf(Date), {});
+ expectThrowsInDevelopment(PropTypes.instanceOf(Date), new Date());
+ expectThrowsInDevelopment(PropTypes.instanceOf(Date).isRequired, {});
+ expectThrowsInDevelopment(
+ PropTypes.instanceOf(Date).isRequired,
+ new Date(),
+ );
+ });
+ });
+
+ describe('React Component Types', () => {
+ it('should warn for invalid values', () => {
+ var failMessage = 'Invalid prop `testProp` supplied to ' +
+ '`testComponent`, expected a ReactNode.';
+ typeCheckFail(PropTypes.node, true, failMessage);
+ typeCheckFail(PropTypes.node, function() {}, failMessage);
+ typeCheckFail(PropTypes.node, {key: function() {}}, failMessage);
+ typeCheckFail(PropTypes.node, {key: }, failMessage);
+ });
+
+ it('should not warn for valid values', () => {
+ function MyComponent() {}
+ MyComponent.prototype.render = function() {
+ return ;
+ };
+ typeCheckPass(PropTypes.node, );
+ typeCheckPass(PropTypes.node, false);
+ typeCheckPass(PropTypes.node, );
+ typeCheckPass(PropTypes.node, 'Some string');
+ typeCheckPass(PropTypes.node, []);
+ typeCheckPass(PropTypes.node, [
+ 123,
+ 'Some string',
+ ,
+ ['Another string', [456], , ],
+ ,
+ null,
+ undefined,
+ ]);
+ });
+
+ it('should not warn for iterables', () => {
+ function MyComponent() {}
+ MyComponent.prototype.render = function() {
+ return ;
+ };
+ var iterable = {
+ '@@iterator': function() {
+ var i = 0;
+ return {
+ next: function() {
+ var done = ++i > 2;
+ return {value: done ? undefined : , done: done};
+ },
+ };
+ },
+ };
+
+ typeCheckPass(PropTypes.node, iterable);
+ });
+
+ it('should not warn for entry iterables', () => {
+ function MyComponent() {}
+ MyComponent.prototype.render = function() {
+ return ;
+ };
+ var iterable = {
+ '@@iterator': function() {
+ var i = 0;
+ return {
+ next: function() {
+ var done = ++i > 2;
+ return {
+ value: done ? undefined : ['#' + i, ],
+ done: done,
+ };
+ },
+ };
+ },
+ };
+ iterable.entries = iterable['@@iterator'];
+
+ typeCheckPass(PropTypes.node, iterable);
+ });
+
+ it('should not warn for null/undefined if not required', () => {
+ typeCheckPass(PropTypes.node, null);
+ typeCheckPass(PropTypes.node, undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(PropTypes.node.isRequired);
+ });
+
+ it('should accept empty array for required props', () => {
+ typeCheckPass(PropTypes.node.isRequired, []);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(PropTypes.node, 'node');
+ expectThrowsInDevelopment(PropTypes.node, {});
+ expectThrowsInDevelopment(PropTypes.node.isRequired, 'node');
+ expectThrowsInDevelopment(PropTypes.node.isRequired, undefined);
+ expectThrowsInDevelopment(PropTypes.node.isRequired, undefined);
+ });
+ });
+
+ describe('ObjectOf Type', () => {
+ it('should fail for invalid argument', () => {
+ typeCheckFail(
+ PropTypes.objectOf({foo: PropTypes.string}),
+ {foo: 'bar'},
+ 'Property `testProp` of component `testComponent` has invalid PropType notation inside objectOf.',
+ );
+ });
+
+ it('should support the objectOf propTypes', () => {
+ typeCheckPass(PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 3});
+ typeCheckPass(PropTypes.objectOf(PropTypes.string), {
+ a: 'a',
+ b: 'b',
+ c: 'c',
+ });
+ typeCheckPass(PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])), {
+ a: 'a',
+ b: 'b',
+ });
+ typeCheckPass(PropTypes.objectOf(PropTypes.symbol), {
+ a: Symbol(),
+ b: Symbol(),
+ c: Symbol(),
+ });
+ });
+
+ it('should support objectOf with complex types', () => {
+ typeCheckPass(
+ PropTypes.objectOf(PropTypes.shape({a: PropTypes.number.isRequired})),
+ {a: {a: 1}, b: {a: 2}},
+ );
+
+ function Thing() {}
+ typeCheckPass(PropTypes.objectOf(PropTypes.instanceOf(Thing)), {
+ a: new Thing(),
+ b: new Thing(),
+ });
+ });
+
+ it('should warn with invalid items in the object', () => {
+ typeCheckFail(
+ PropTypes.objectOf(PropTypes.number),
+ {a: 1, b: 2, c: 'b'},
+ 'Invalid prop `testProp.c` of type `string` supplied to `testComponent`, ' +
+ 'expected `number`.',
+ );
+ });
+
+ it('should warn with invalid complex types', () => {
+ function Thing() {}
+ var name = Thing.name || '<>';
+
+ typeCheckFail(
+ PropTypes.objectOf(PropTypes.instanceOf(Thing)),
+ {a: new Thing(), b: 'xyz'},
+ 'Invalid prop `testProp.b` of type `String` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ name +
+ '`.',
+ );
+ });
+
+ it('should warn when passed something other than an object', () => {
+ typeCheckFail(
+ PropTypes.objectOf(PropTypes.number),
+ [1, 2],
+ 'Invalid prop `testProp` of type `array` supplied to ' +
+ '`testComponent`, expected an object.',
+ );
+ typeCheckFail(
+ PropTypes.objectOf(PropTypes.number),
+ 123,
+ 'Invalid prop `testProp` of type `number` supplied to ' +
+ '`testComponent`, expected an object.',
+ );
+ typeCheckFail(
+ PropTypes.objectOf(PropTypes.number),
+ 'string',
+ 'Invalid prop `testProp` of type `string` supplied to ' +
+ '`testComponent`, expected an object.',
+ );
+ typeCheckFail(
+ PropTypes.objectOf(PropTypes.symbol),
+ Symbol(),
+ 'Invalid prop `testProp` of type `symbol` supplied to ' +
+ '`testComponent`, expected an object.',
+ );
+ });
+
+ it('should not warn when passing an empty object', () => {
+ typeCheckPass(PropTypes.objectOf(PropTypes.number), {});
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ typeCheckPass(PropTypes.objectOf(PropTypes.number), null);
+ typeCheckPass(PropTypes.objectOf(PropTypes.number), undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(
+ PropTypes.objectOf(PropTypes.number).isRequired,
+ );
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(PropTypes.objectOf({foo: PropTypes.string}), {
+ foo: 'bar',
+ });
+ expectThrowsInDevelopment(PropTypes.objectOf(PropTypes.number), {
+ a: 1,
+ b: 2,
+ c: 'b',
+ });
+ expectThrowsInDevelopment(PropTypes.objectOf(PropTypes.number), [1, 2]);
+ expectThrowsInDevelopment(PropTypes.objectOf(PropTypes.number), null);
+ expectThrowsInDevelopment(
+ PropTypes.objectOf(PropTypes.number),
+ undefined,
+ );
+ });
+ });
+
+ describe('OneOf Types', () => {
+ it('should warn but not error for invalid argument', () => {
+ spyOn(console, 'error');
+
+ PropTypes.oneOf('red', 'blue');
+
+ expect(console.error).toHaveBeenCalled();
+ expect(console.error.calls.argsFor(0)[0]).toContain(
+ 'Invalid argument supplied to oneOf, expected an instance of array.',
+ );
+
+ typeCheckPass(PropTypes.oneOf('red', 'blue'), 'red');
+ });
+
+ it('should warn for invalid values', () => {
+ typeCheckFail(
+ PropTypes.oneOf(['red', 'blue']),
+ true,
+ 'Invalid prop `testProp` of value `true` supplied to ' +
+ '`testComponent`, expected one of ["red","blue"].',
+ );
+ typeCheckFail(
+ PropTypes.oneOf(['red', 'blue']),
+ [],
+ 'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
+ 'expected one of ["red","blue"].',
+ );
+ typeCheckFail(
+ PropTypes.oneOf(['red', 'blue']),
+ '',
+ 'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
+ 'expected one of ["red","blue"].',
+ );
+ typeCheckFail(
+ PropTypes.oneOf([0, 'false']),
+ false,
+ 'Invalid prop `testProp` of value `false` supplied to ' +
+ '`testComponent`, expected one of [0,"false"].',
+ );
+ });
+
+ it('should not warn for valid values', () => {
+ typeCheckPass(PropTypes.oneOf(['red', 'blue']), 'red');
+ typeCheckPass(PropTypes.oneOf(['red', 'blue']), 'blue');
+ typeCheckPass(PropTypes.oneOf(['red', 'blue', NaN]), NaN);
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ typeCheckPass(PropTypes.oneOf(['red', 'blue']), null);
+ typeCheckPass(PropTypes.oneOf(['red', 'blue']), undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(PropTypes.oneOf(['red', 'blue']).isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(PropTypes.oneOf(['red', 'blue']), true);
+ expectThrowsInDevelopment(PropTypes.oneOf(['red', 'blue']), null);
+ expectThrowsInDevelopment(PropTypes.oneOf(['red', 'blue']), undefined);
+ });
+ });
+
+ describe('Union Types', () => {
+ it('should warn but not error for invalid argument', () => {
+ spyOn(console, 'error');
+
+ PropTypes.oneOfType(PropTypes.string, PropTypes.number);
+
+ expect(console.error).toHaveBeenCalled();
+ expect(console.error.calls.argsFor(0)[0]).toContain(
+ 'Invalid argument supplied to oneOfType, expected an instance of array.',
+ );
+
+ typeCheckPass(PropTypes.oneOf(PropTypes.string, PropTypes.number), []);
+ });
+
+ it('should warn if none of the types are valid', () => {
+ typeCheckFail(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ [],
+ 'Invalid prop `testProp` supplied to `testComponent`.',
+ );
+
+ var checker = PropTypes.oneOfType([
+ PropTypes.shape({a: PropTypes.number.isRequired}),
+ PropTypes.shape({b: PropTypes.number.isRequired}),
+ ]);
+ typeCheckFail(
+ checker,
+ {c: 1},
+ 'Invalid prop `testProp` supplied to `testComponent`.',
+ );
+ });
+
+ it('should not warn if one of the types are valid', () => {
+ var checker = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
+ typeCheckPass(checker, null);
+ typeCheckPass(checker, 'foo');
+ typeCheckPass(checker, 123);
+
+ checker = PropTypes.oneOfType([
+ PropTypes.shape({a: PropTypes.number.isRequired}),
+ PropTypes.shape({b: PropTypes.number.isRequired}),
+ ]);
+ typeCheckPass(checker, {a: 1});
+ typeCheckPass(checker, {b: 1});
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ typeCheckPass(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ null,
+ );
+ typeCheckPass(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ undefined,
+ );
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+ );
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ [],
+ );
+ expectThrowsInDevelopment(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ null,
+ );
+ expectThrowsInDevelopment(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ undefined,
+ );
+ });
+ });
+
+ describe('Shape Types', () => {
+ it('should warn for non objects', () => {
+ typeCheckFail(
+ PropTypes.shape({}),
+ 'some string',
+ 'Invalid prop `testProp` of type `string` supplied to ' +
+ '`testComponent`, expected `object`.',
+ );
+ typeCheckFail(
+ PropTypes.shape({}),
+ ['array'],
+ 'Invalid prop `testProp` of type `array` supplied to ' +
+ '`testComponent`, expected `object`.',
+ );
+ });
+
+ it('should not warn for empty values', () => {
+ typeCheckPass(PropTypes.shape({}), undefined);
+ typeCheckPass(PropTypes.shape({}), null);
+ typeCheckPass(PropTypes.shape({}), {});
+ });
+
+ it('should not warn for an empty object', () => {
+ typeCheckPass(PropTypes.shape({}).isRequired, {});
+ });
+
+ it('should not warn for non specified types', () => {
+ typeCheckPass(PropTypes.shape({}), {key: 1});
+ });
+
+ it('should not warn for valid types', () => {
+ typeCheckPass(PropTypes.shape({key: PropTypes.number}), {key: 1});
+ });
+
+ it('should warn for required valid types', () => {
+ typeCheckFail(
+ PropTypes.shape({key: PropTypes.number.isRequired}),
+ {},
+ 'The prop `testProp.key` is marked as required in `testComponent`, ' +
+ 'but its value is `undefined`.',
+ );
+ });
+
+ it('should warn for the first required type', () => {
+ typeCheckFail(
+ PropTypes.shape({
+ key: PropTypes.number.isRequired,
+ secondKey: PropTypes.number.isRequired,
+ }),
+ {},
+ 'The prop `testProp.key` is marked as required in `testComponent`, ' +
+ 'but its value is `undefined`.',
+ );
+ });
+
+ it('should warn for invalid key types', () => {
+ typeCheckFail(
+ PropTypes.shape({key: PropTypes.number}),
+ {key: 'abc'},
+ 'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' +
+ 'expected `number`.',
+ );
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ typeCheckPass(
+ PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
+ null,
+ );
+ typeCheckPass(
+ PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
+ undefined,
+ );
+ });
+
+ it('should warn for missing required values', () => {
+ typeCheckFailRequiredValues(
+ PropTypes.shape({key: PropTypes.number}).isRequired,
+ );
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectThrowsInDevelopment(PropTypes.shape({}), 'some string');
+ expectThrowsInDevelopment(PropTypes.shape({foo: PropTypes.number}), {
+ foo: 42,
+ });
+ expectThrowsInDevelopment(
+ PropTypes.shape({key: PropTypes.number}).isRequired,
+ null,
+ );
+ expectThrowsInDevelopment(
+ PropTypes.shape({key: PropTypes.number}).isRequired,
+ undefined,
+ );
+ expectThrowsInDevelopment(PropTypes.element, );
+ });
+ });
+
+ describe('Symbol Type', () => {
+ it('should warn for non-symbol', () => {
+ typeCheckFail(
+ PropTypes.symbol,
+ 'hello',
+ 'Invalid prop `testProp` of type `string` supplied to ' +
+ '`testComponent`, expected `symbol`.',
+ );
+ typeCheckFail(
+ PropTypes.symbol,
+ function() {},
+ 'Invalid prop `testProp` of type `function` supplied to ' +
+ '`testComponent`, expected `symbol`.',
+ );
+ typeCheckFail(
+ PropTypes.symbol,
+ {
+ '@@toStringTag': 'Katana',
+ },
+ 'Invalid prop `testProp` of type `object` supplied to ' +
+ '`testComponent`, expected `symbol`.',
+ );
+ });
+
+ it('should not warn for a polyfilled Symbol', () => {
+ var CoreSymbol = require('core-js/library/es6/symbol');
+ typeCheckPass(PropTypes.symbol, CoreSymbol('core-js'));
+ });
+ });
+});
diff --git a/__tests__/PropTypesProductionReact15-test.js b/__tests__/PropTypesProductionReact15-test.js
new file mode 100644
index 0000000..1d16a31
--- /dev/null
+++ b/__tests__/PropTypesProductionReact15-test.js
@@ -0,0 +1,952 @@
+/**
+ * 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';
+
+var React;
+var PropTypes;
+
+function resetWarningCache() {
+ jest.resetModules();
+
+ // Set production mode throughout this test.
+ process.env.NODE_ENV = 'production';
+ React = require('react');
+ // We are testing that when imported in the same way React 15 imports `prop-types`,
+ // it just suppresses warnings but doesn't actually throw when calling validators.
+ PropTypes = require('../factory')(React.isValidElement);
+}
+
+function expectNoop(declaration, value) {
+ if (!console.error.calls) {
+ spyOn(console, 'error');
+ } else {
+ console.error.calls.reset();
+ }
+
+ var props = {testProp: value};
+ var propName = 'testProp' + Math.random().toString();
+ var componentName = 'testComponent' + Math.random().toString();
+ // Try calling it manually
+ for (var i = 0; i < 3; i++) {
+ declaration(props, propName, componentName, 'prop');
+ }
+ // Try calling it via checkPropTypes
+ const propTypes = {
+ testProp: declaration,
+ };
+ PropTypes.checkPropTypes(propTypes, props, 'prop', 'testComponent');
+
+ // They should all be no-ops
+ expect(console.error.calls.count()).toBe(0);
+ console.error.calls.reset();
+}
+
+describe('PropTypesProductionReact15', () => {
+ beforeEach(() => {
+ resetWarningCache();
+ });
+
+ describe('Primitive Types', () => {
+ it('should warn for invalid strings', () => {
+ expectNoop(
+ PropTypes.string,
+ [],
+ 'Invalid prop `testProp` of type `array` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ expectNoop(
+ PropTypes.string,
+ false,
+ 'Invalid prop `testProp` of type `boolean` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ expectNoop(
+ PropTypes.string,
+ 0,
+ 'Invalid prop `testProp` of type `number` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ expectNoop(
+ PropTypes.string,
+ {},
+ 'Invalid prop `testProp` of type `object` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ expectNoop(
+ PropTypes.string,
+ Symbol(),
+ 'Invalid prop `testProp` of type `symbol` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ });
+
+ it('should fail date and regexp correctly', () => {
+ expectNoop(
+ PropTypes.string,
+ new Date(),
+ 'Invalid prop `testProp` of type `date` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ expectNoop(
+ PropTypes.string,
+ /please/,
+ 'Invalid prop `testProp` of type `regexp` supplied to ' +
+ '`testComponent`, expected `string`.',
+ );
+ });
+
+ it('should not warn for valid values', () => {
+ expectNoop(PropTypes.array, []);
+ expectNoop(PropTypes.bool, false);
+ expectNoop(PropTypes.func, function() {});
+ expectNoop(PropTypes.number, 0);
+ expectNoop(PropTypes.string, '');
+ expectNoop(PropTypes.object, {});
+ expectNoop(PropTypes.object, new Date());
+ expectNoop(PropTypes.object, /please/);
+ expectNoop(PropTypes.symbol, Symbol());
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ expectNoop(PropTypes.string, null);
+ expectNoop(PropTypes.string, undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(PropTypes.string.isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(PropTypes.array, /please/);
+ expectNoop(PropTypes.array, []);
+ expectNoop(PropTypes.array.isRequired, /please/);
+ expectNoop(PropTypes.array.isRequired, []);
+ expectNoop(PropTypes.array.isRequired, null);
+ expectNoop(PropTypes.array.isRequired, undefined);
+ expectNoop(PropTypes.bool, []);
+ expectNoop(PropTypes.bool, true);
+ expectNoop(PropTypes.bool.isRequired, []);
+ expectNoop(PropTypes.bool.isRequired, true);
+ expectNoop(PropTypes.bool.isRequired, null);
+ expectNoop(PropTypes.bool.isRequired, undefined);
+ expectNoop(PropTypes.func, false);
+ expectNoop(PropTypes.func, function() {});
+ expectNoop(PropTypes.func.isRequired, false);
+ expectNoop(PropTypes.func.isRequired, function() {});
+ expectNoop(PropTypes.func.isRequired, null);
+ expectNoop(PropTypes.func.isRequired, undefined);
+ expectNoop(PropTypes.number, function() {});
+ expectNoop(PropTypes.number, 42);
+ expectNoop(PropTypes.number.isRequired, function() {});
+ expectNoop(PropTypes.number.isRequired, 42);
+ expectNoop(PropTypes.number.isRequired, null);
+ expectNoop(PropTypes.number.isRequired, undefined);
+ expectNoop(PropTypes.string, 0);
+ expectNoop(PropTypes.string, 'foo');
+ expectNoop(PropTypes.string.isRequired, 0);
+ expectNoop(PropTypes.string.isRequired, 'foo');
+ expectNoop(PropTypes.string.isRequired, null);
+ expectNoop(PropTypes.string.isRequired, undefined);
+ expectNoop(PropTypes.symbol, 0);
+ expectNoop(PropTypes.symbol, Symbol('Foo'));
+ expectNoop(PropTypes.symbol.isRequired, 0);
+ expectNoop(PropTypes.symbol.isRequired, Symbol('Foo'));
+ expectNoop(PropTypes.symbol.isRequired, null);
+ expectNoop(PropTypes.symbol.isRequired, undefined);
+ expectNoop(PropTypes.object, '');
+ expectNoop(PropTypes.object, {foo: 'bar'});
+ expectNoop(PropTypes.object.isRequired, '');
+ expectNoop(PropTypes.object.isRequired, {foo: 'bar'});
+ expectNoop(PropTypes.object.isRequired, null);
+ expectNoop(PropTypes.object.isRequired, undefined);
+ });
+ });
+
+ describe('Any type', () => {
+ it('should should accept any value', () => {
+ expectNoop(PropTypes.any, 0);
+ expectNoop(PropTypes.any, 'str');
+ expectNoop(PropTypes.any, []);
+ expectNoop(PropTypes.any, Symbol());
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ expectNoop(PropTypes.any, null);
+ expectNoop(PropTypes.any, undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(PropTypes.any.isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(PropTypes.any, null);
+ expectNoop(PropTypes.any.isRequired, null);
+ expectNoop(PropTypes.any.isRequired, undefined);
+ });
+ });
+
+ describe('ArrayOf Type', () => {
+ it('should fail for invalid argument', () => {
+ expectNoop(
+ PropTypes.arrayOf({foo: PropTypes.string}),
+ {foo: 'bar'},
+ 'Property `testProp` of component `testComponent` has invalid PropType notation inside arrayOf.',
+ );
+ });
+
+ it('should support the arrayOf propTypes', () => {
+ expectNoop(PropTypes.arrayOf(PropTypes.number), [1, 2, 3]);
+ expectNoop(PropTypes.arrayOf(PropTypes.string), ['a', 'b', 'c']);
+ expectNoop(PropTypes.arrayOf(PropTypes.oneOf(['a', 'b'])), ['a', 'b']);
+ expectNoop(PropTypes.arrayOf(PropTypes.symbol), [Symbol(), Symbol()]);
+ });
+
+ it('should support arrayOf with complex types', () => {
+ expectNoop(
+ PropTypes.arrayOf(PropTypes.shape({a: PropTypes.number.isRequired})),
+ [{a: 1}, {a: 2}],
+ );
+
+ function Thing() {}
+ expectNoop(PropTypes.arrayOf(PropTypes.instanceOf(Thing)), [
+ new Thing(),
+ new Thing(),
+ ]);
+ });
+
+ it('should warn with invalid items in the array', () => {
+ expectNoop(
+ PropTypes.arrayOf(PropTypes.number),
+ [1, 2, 'b'],
+ 'Invalid prop `testProp[2]` of type `string` supplied to ' +
+ '`testComponent`, expected `number`.',
+ );
+ });
+
+ it('should warn with invalid complex types', () => {
+ function Thing() {}
+ var name = Thing.name || '<>';
+
+ expectNoop(
+ PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
+ [new Thing(), 'xyz'],
+ 'Invalid prop `testProp[1]` of type `String` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ name +
+ '`.',
+ );
+ });
+
+ it('should warn when passed something other than an array', () => {
+ expectNoop(
+ PropTypes.arrayOf(PropTypes.number),
+ {'0': 'maybe-array', length: 1},
+ 'Invalid prop `testProp` of type `object` supplied to ' +
+ '`testComponent`, expected an array.',
+ );
+ expectNoop(
+ PropTypes.arrayOf(PropTypes.number),
+ 123,
+ 'Invalid prop `testProp` of type `number` supplied to ' +
+ '`testComponent`, expected an array.',
+ );
+ expectNoop(
+ PropTypes.arrayOf(PropTypes.number),
+ 'string',
+ 'Invalid prop `testProp` of type `string` supplied to ' +
+ '`testComponent`, expected an array.',
+ );
+ });
+
+ it('should not warn when passing an empty array', () => {
+ expectNoop(PropTypes.arrayOf(PropTypes.number), []);
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ expectNoop(PropTypes.arrayOf(PropTypes.number), null);
+ expectNoop(PropTypes.arrayOf(PropTypes.number), undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(
+ PropTypes.arrayOf(PropTypes.number).isRequired,
+ );
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(PropTypes.arrayOf({foo: PropTypes.string}), {
+ foo: 'bar',
+ });
+ expectNoop(PropTypes.arrayOf(PropTypes.number), [
+ 1,
+ 2,
+ 'b',
+ ]);
+ expectNoop(PropTypes.arrayOf(PropTypes.number), {
+ '0': 'maybe-array',
+ length: 1,
+ });
+ expectNoop(
+ PropTypes.arrayOf(PropTypes.number).isRequired,
+ null,
+ );
+ expectNoop(
+ PropTypes.arrayOf(PropTypes.number).isRequired,
+ undefined,
+ );
+ });
+ });
+
+ describe('Component Type', () => {
+
+ it('should support components', () => {
+ expectNoop(PropTypes.element, );
+ });
+
+ it('should not support multiple components or scalar values', () => {
+ expectNoop(
+ PropTypes.element,
+ [, ],
+ 'Invalid prop `testProp` of type `array` supplied to `testComponent`, ' +
+ 'expected a single ReactElement.',
+ );
+ expectNoop(
+ PropTypes.element,
+ 123,
+ 'Invalid prop `testProp` of type `number` supplied to `testComponent`, ' +
+ 'expected a single ReactElement.',
+ );
+ expectNoop(
+ PropTypes.element,
+ 'foo',
+ 'Invalid prop `testProp` of type `string` supplied to `testComponent`, ' +
+ 'expected a single ReactElement.',
+ );
+ expectNoop(
+ PropTypes.element,
+ false,
+ 'Invalid prop `testProp` of type `boolean` supplied to `testComponent`, ' +
+ 'expected a single ReactElement.',
+ );
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ expectNoop(PropTypes.element, null);
+ expectNoop(PropTypes.element, undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(PropTypes.element.isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(PropTypes.element, [, ]);
+ expectNoop(PropTypes.element, );
+ expectNoop(PropTypes.element, 123);
+ expectNoop(PropTypes.element, 'foo');
+ expectNoop(PropTypes.element, false);
+ expectNoop(PropTypes.element.isRequired, null);
+ expectNoop(PropTypes.element.isRequired, undefined);
+ });
+ });
+
+ describe('Instance Types', () => {
+ it('should warn for invalid instances', () => {
+ function Person() {}
+ function Cat() {}
+ var personName = Person.name || '<>';
+ var dateName = Date.name || '<>';
+ var regExpName = RegExp.name || '<>';
+
+ expectNoop(
+ PropTypes.instanceOf(Person),
+ false,
+ 'Invalid prop `testProp` of type `Boolean` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ expectNoop(
+ PropTypes.instanceOf(Person),
+ {},
+ 'Invalid prop `testProp` of type `Object` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ expectNoop(
+ PropTypes.instanceOf(Person),
+ '',
+ 'Invalid prop `testProp` of type `String` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ expectNoop(
+ PropTypes.instanceOf(Date),
+ {},
+ 'Invalid prop `testProp` of type `Object` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ dateName +
+ '`.',
+ );
+ expectNoop(
+ PropTypes.instanceOf(RegExp),
+ {},
+ 'Invalid prop `testProp` of type `Object` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ regExpName +
+ '`.',
+ );
+ expectNoop(
+ PropTypes.instanceOf(Person),
+ new Cat(),
+ 'Invalid prop `testProp` of type `Cat` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ expectNoop(
+ PropTypes.instanceOf(Person),
+ Object.create(null),
+ 'Invalid prop `testProp` of type `<>` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ personName +
+ '`.',
+ );
+ });
+
+ it('should not warn for valid values', () => {
+ function Person() {}
+ function Engineer() {}
+ Engineer.prototype = new Person();
+
+ expectNoop(PropTypes.instanceOf(Person), new Person());
+ expectNoop(PropTypes.instanceOf(Person), new Engineer());
+
+ expectNoop(PropTypes.instanceOf(Date), new Date());
+ expectNoop(PropTypes.instanceOf(RegExp), /please/);
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ expectNoop(PropTypes.instanceOf(String), null);
+ expectNoop(PropTypes.instanceOf(String), undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(PropTypes.instanceOf(String).isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(PropTypes.instanceOf(Date), {});
+ expectNoop(PropTypes.instanceOf(Date), new Date());
+ expectNoop(PropTypes.instanceOf(Date).isRequired, {});
+ expectNoop(
+ PropTypes.instanceOf(Date).isRequired,
+ new Date(),
+ );
+ });
+ });
+
+ describe('React Component Types', () => {
+ it('should warn for invalid values', () => {
+ var failMessage = 'Invalid prop `testProp` supplied to ' +
+ '`testComponent`, expected a ReactNode.';
+ expectNoop(PropTypes.node, true, failMessage);
+ expectNoop(PropTypes.node, function() {}, failMessage);
+ expectNoop(PropTypes.node, {key: function() {}}, failMessage);
+ expectNoop(PropTypes.node, {key: }, failMessage);
+ });
+
+ it('should not warn for valid values', () => {
+ function MyComponent() {}
+ MyComponent.prototype.render = function() {
+ return ;
+ };
+ expectNoop(PropTypes.node, );
+ expectNoop(PropTypes.node, false);
+ expectNoop(PropTypes.node, );
+ expectNoop(PropTypes.node, 'Some string');
+ expectNoop(PropTypes.node, []);
+ expectNoop(PropTypes.node, [
+ 123,
+ 'Some string',
+ ,
+ ['Another string', [456], , ],
+ ,
+ null,
+ undefined,
+ ]);
+ });
+
+ it('should not warn for iterables', () => {
+ function MyComponent() {}
+ MyComponent.prototype.render = function() {
+ return ;
+ };
+ var iterable = {
+ '@@iterator': function() {
+ var i = 0;
+ return {
+ next: function() {
+ var done = ++i > 2;
+ return {value: done ? undefined : , done: done};
+ },
+ };
+ },
+ };
+
+ expectNoop(PropTypes.node, iterable);
+ });
+
+ it('should not warn for entry iterables', () => {
+ function MyComponent() {}
+ MyComponent.prototype.render = function() {
+ return ;
+ };
+ var iterable = {
+ '@@iterator': function() {
+ var i = 0;
+ return {
+ next: function() {
+ var done = ++i > 2;
+ return {
+ value: done ? undefined : ['#' + i, ],
+ done: done,
+ };
+ },
+ };
+ },
+ };
+ iterable.entries = iterable['@@iterator'];
+
+ expectNoop(PropTypes.node, iterable);
+ });
+
+ it('should not warn for null/undefined if not required', () => {
+ expectNoop(PropTypes.node, null);
+ expectNoop(PropTypes.node, undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(PropTypes.node.isRequired);
+ });
+
+ it('should accept empty array for required props', () => {
+ expectNoop(PropTypes.node.isRequired, []);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(PropTypes.node, 'node');
+ expectNoop(PropTypes.node, {});
+ expectNoop(PropTypes.node.isRequired, 'node');
+ expectNoop(PropTypes.node.isRequired, undefined);
+ expectNoop(PropTypes.node.isRequired, undefined);
+ });
+ });
+
+ describe('ObjectOf Type', () => {
+ it('should fail for invalid argument', () => {
+ expectNoop(
+ PropTypes.objectOf({foo: PropTypes.string}),
+ {foo: 'bar'},
+ 'Property `testProp` of component `testComponent` has invalid PropType notation inside objectOf.',
+ );
+ });
+
+ it('should support the objectOf propTypes', () => {
+ expectNoop(PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 3});
+ expectNoop(PropTypes.objectOf(PropTypes.string), {
+ a: 'a',
+ b: 'b',
+ c: 'c',
+ });
+ expectNoop(PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])), {
+ a: 'a',
+ b: 'b',
+ });
+ expectNoop(PropTypes.objectOf(PropTypes.symbol), {
+ a: Symbol(),
+ b: Symbol(),
+ c: Symbol(),
+ });
+ });
+
+ it('should support objectOf with complex types', () => {
+ expectNoop(
+ PropTypes.objectOf(PropTypes.shape({a: PropTypes.number.isRequired})),
+ {a: {a: 1}, b: {a: 2}},
+ );
+
+ function Thing() {}
+ expectNoop(PropTypes.objectOf(PropTypes.instanceOf(Thing)), {
+ a: new Thing(),
+ b: new Thing(),
+ });
+ });
+
+ it('should warn with invalid items in the object', () => {
+ expectNoop(
+ PropTypes.objectOf(PropTypes.number),
+ {a: 1, b: 2, c: 'b'},
+ 'Invalid prop `testProp.c` of type `string` supplied to `testComponent`, ' +
+ 'expected `number`.',
+ );
+ });
+
+ it('should warn with invalid complex types', () => {
+ function Thing() {}
+ var name = Thing.name || '<>';
+
+ expectNoop(
+ PropTypes.objectOf(PropTypes.instanceOf(Thing)),
+ {a: new Thing(), b: 'xyz'},
+ 'Invalid prop `testProp.b` of type `String` supplied to ' +
+ '`testComponent`, expected instance of `' +
+ name +
+ '`.',
+ );
+ });
+
+ it('should warn when passed something other than an object', () => {
+ expectNoop(
+ PropTypes.objectOf(PropTypes.number),
+ [1, 2],
+ 'Invalid prop `testProp` of type `array` supplied to ' +
+ '`testComponent`, expected an object.',
+ );
+ expectNoop(
+ PropTypes.objectOf(PropTypes.number),
+ 123,
+ 'Invalid prop `testProp` of type `number` supplied to ' +
+ '`testComponent`, expected an object.',
+ );
+ expectNoop(
+ PropTypes.objectOf(PropTypes.number),
+ 'string',
+ 'Invalid prop `testProp` of type `string` supplied to ' +
+ '`testComponent`, expected an object.',
+ );
+ expectNoop(
+ PropTypes.objectOf(PropTypes.symbol),
+ Symbol(),
+ 'Invalid prop `testProp` of type `symbol` supplied to ' +
+ '`testComponent`, expected an object.',
+ );
+ });
+
+ it('should not warn when passing an empty object', () => {
+ expectNoop(PropTypes.objectOf(PropTypes.number), {});
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ expectNoop(PropTypes.objectOf(PropTypes.number), null);
+ expectNoop(PropTypes.objectOf(PropTypes.number), undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(
+ PropTypes.objectOf(PropTypes.number).isRequired,
+ );
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(PropTypes.objectOf({foo: PropTypes.string}), {
+ foo: 'bar',
+ });
+ expectNoop(PropTypes.objectOf(PropTypes.number), {
+ a: 1,
+ b: 2,
+ c: 'b',
+ });
+ expectNoop(PropTypes.objectOf(PropTypes.number), [1, 2]);
+ expectNoop(PropTypes.objectOf(PropTypes.number), null);
+ expectNoop(
+ PropTypes.objectOf(PropTypes.number),
+ undefined,
+ );
+ });
+ });
+
+ describe('OneOf Types', () => {
+ it('should ignore invalid argument', () => {
+ spyOn(console, 'error');
+
+ PropTypes.oneOf('red', 'blue');
+
+ expect(console.error).not.toHaveBeenCalled();
+ expectNoop(PropTypes.oneOf('red', 'blue'), 'red');
+ });
+
+ it('should ignore invalid values', () => {
+ expectNoop(
+ PropTypes.oneOf(['red', 'blue']),
+ true,
+ 'Invalid prop `testProp` of value `true` supplied to ' +
+ '`testComponent`, expected one of ["red","blue"].',
+ );
+ expectNoop(
+ PropTypes.oneOf(['red', 'blue']),
+ [],
+ 'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
+ 'expected one of ["red","blue"].',
+ );
+ expectNoop(
+ PropTypes.oneOf(['red', 'blue']),
+ '',
+ 'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
+ 'expected one of ["red","blue"].',
+ );
+ expectNoop(
+ PropTypes.oneOf([0, 'false']),
+ false,
+ 'Invalid prop `testProp` of value `false` supplied to ' +
+ '`testComponent`, expected one of [0,"false"].',
+ );
+ });
+
+ it('should not warn for valid values', () => {
+ expectNoop(PropTypes.oneOf(['red', 'blue']), 'red');
+ expectNoop(PropTypes.oneOf(['red', 'blue']), 'blue');
+ expectNoop(PropTypes.oneOf(['red', 'blue', NaN]), NaN);
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ expectNoop(PropTypes.oneOf(['red', 'blue']), null);
+ expectNoop(PropTypes.oneOf(['red', 'blue']), undefined);
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(PropTypes.oneOf(['red', 'blue']).isRequired);
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(PropTypes.oneOf(['red', 'blue']), true);
+ expectNoop(PropTypes.oneOf(['red', 'blue']), null);
+ expectNoop(PropTypes.oneOf(['red', 'blue']), undefined);
+ });
+ });
+
+ describe('Union Types', () => {
+ it('should ignore invalid argument', () => {
+ spyOn(console, 'error');
+
+ PropTypes.oneOfType(PropTypes.string, PropTypes.number);
+
+ expect(console.error).not.toHaveBeenCalled();
+ expectNoop(PropTypes.oneOf(PropTypes.string, PropTypes.number), []);
+ });
+
+ it('should warn if none of the types are valid', () => {
+ expectNoop(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ [],
+ 'Invalid prop `testProp` supplied to `testComponent`.',
+ );
+
+ var checker = PropTypes.oneOfType([
+ PropTypes.shape({a: PropTypes.number.isRequired}),
+ PropTypes.shape({b: PropTypes.number.isRequired}),
+ ]);
+ expectNoop(
+ checker,
+ {c: 1},
+ 'Invalid prop `testProp` supplied to `testComponent`.',
+ );
+ });
+
+ it('should not warn if one of the types are valid', () => {
+ var checker = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
+ expectNoop(checker, null);
+ expectNoop(checker, 'foo');
+ expectNoop(checker, 123);
+
+ checker = PropTypes.oneOfType([
+ PropTypes.shape({a: PropTypes.number.isRequired}),
+ PropTypes.shape({b: PropTypes.number.isRequired}),
+ ]);
+ expectNoop(checker, {a: 1});
+ expectNoop(checker, {b: 1});
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ expectNoop(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ null,
+ );
+ expectNoop(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ undefined,
+ );
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+ );
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ [],
+ );
+ expectNoop(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ null,
+ );
+ expectNoop(
+ PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ undefined,
+ );
+ });
+ });
+
+ describe('Shape Types', () => {
+ it('should warn for non objects', () => {
+ expectNoop(
+ PropTypes.shape({}),
+ 'some string',
+ 'Invalid prop `testProp` of type `string` supplied to ' +
+ '`testComponent`, expected `object`.',
+ );
+ expectNoop(
+ PropTypes.shape({}),
+ ['array'],
+ 'Invalid prop `testProp` of type `array` supplied to ' +
+ '`testComponent`, expected `object`.',
+ );
+ });
+
+ it('should not warn for empty values', () => {
+ expectNoop(PropTypes.shape({}), undefined);
+ expectNoop(PropTypes.shape({}), null);
+ expectNoop(PropTypes.shape({}), {});
+ });
+
+ it('should not warn for an empty object', () => {
+ expectNoop(PropTypes.shape({}).isRequired, {});
+ });
+
+ it('should not warn for non specified types', () => {
+ expectNoop(PropTypes.shape({}), {key: 1});
+ });
+
+ it('should not warn for valid types', () => {
+ expectNoop(PropTypes.shape({key: PropTypes.number}), {key: 1});
+ });
+
+ it('should warn for required valid types', () => {
+ expectNoop(
+ PropTypes.shape({key: PropTypes.number.isRequired}),
+ {},
+ 'The prop `testProp.key` is marked as required in `testComponent`, ' +
+ 'but its value is `undefined`.',
+ );
+ });
+
+ it('should warn for the first required type', () => {
+ expectNoop(
+ PropTypes.shape({
+ key: PropTypes.number.isRequired,
+ secondKey: PropTypes.number.isRequired,
+ }),
+ {},
+ 'The prop `testProp.key` is marked as required in `testComponent`, ' +
+ 'but its value is `undefined`.',
+ );
+ });
+
+ it('should warn for invalid key types', () => {
+ expectNoop(
+ PropTypes.shape({key: PropTypes.number}),
+ {key: 'abc'},
+ 'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' +
+ 'expected `number`.',
+ );
+ });
+
+ it('should be implicitly optional and not warn without values', () => {
+ expectNoop(
+ PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
+ null,
+ );
+ expectNoop(
+ PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
+ undefined,
+ );
+ });
+
+ it('should warn for missing required values', () => {
+ expectNoop(
+ PropTypes.shape({key: PropTypes.number}).isRequired,
+ );
+ });
+
+ it('should warn if called manually in development', () => {
+ spyOn(console, 'error');
+ expectNoop(PropTypes.shape({}), 'some string');
+ expectNoop(PropTypes.shape({foo: PropTypes.number}), {
+ foo: 42,
+ });
+ expectNoop(
+ PropTypes.shape({key: PropTypes.number}).isRequired,
+ null,
+ );
+ expectNoop(
+ PropTypes.shape({key: PropTypes.number}).isRequired,
+ undefined,
+ );
+ expectNoop(PropTypes.element, );
+ });
+ });
+
+ describe('Symbol Type', () => {
+ it('should warn for non-symbol', () => {
+ expectNoop(
+ PropTypes.symbol,
+ 'hello',
+ 'Invalid prop `testProp` of type `string` supplied to ' +
+ '`testComponent`, expected `symbol`.',
+ );
+ expectNoop(
+ PropTypes.symbol,
+ function() {},
+ 'Invalid prop `testProp` of type `function` supplied to ' +
+ '`testComponent`, expected `symbol`.',
+ );
+ expectNoop(
+ PropTypes.symbol,
+ {
+ '@@toStringTag': 'Katana',
+ },
+ 'Invalid prop `testProp` of type `object` supplied to ' +
+ '`testComponent`, expected `symbol`.',
+ );
+ });
+
+ it('should not warn for a polyfilled Symbol', () => {
+ var CoreSymbol = require('core-js/library/es6/symbol');
+ expectNoop(PropTypes.symbol, CoreSymbol('core-js'));
+ });
+ });
+});
diff --git a/__tests__/PropTypesProductionStandalone-test.js b/__tests__/PropTypesProductionStandalone-test.js
new file mode 100644
index 0000000..b60af87
--- /dev/null
+++ b/__tests__/PropTypesProductionStandalone-test.js
@@ -0,0 +1,238 @@
+/**
+ * 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('PropTypesProductionStandalone', function() {
+ var React;
+ var PropTypes;
+
+ function resetWarningCache() {
+ jest.resetModules();
+ process.env.NODE_ENV = 'production';
+
+ React = require('react');
+ PropTypes = require('../index');
+ }
+
+ beforeEach(function() {
+ resetWarningCache();
+ });
+
+ afterEach(function() {
+ delete process.env.NODE_ENV;
+ });
+
+ function getPropTypeWarningMessage(propTypes, object, componentName) {
+ if (!console.error.calls) {
+ spyOn(console, 'error');
+ } else {
+ console.error.calls.reset();
+ }
+ resetWarningCache();
+ PropTypes.checkPropTypes(propTypes, object, 'prop', 'testComponent');
+ const callCount = console.error.calls.count();
+ if (callCount > 1) {
+ throw new Error('Too many warnings.');
+ }
+ const message = console.error.calls.argsFor(0)[0] || null;
+ console.error.calls.reset();
+
+ return message;
+ }
+
+ function expectThrowsInProduction(declaration, value) {
+ resetWarningCache();
+ var props = {testProp: value};
+ expect(() => {
+ declaration(props, 'testProp', 'testComponent', 'prop');
+ }).toThrowError(
+ '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'
+ );
+ }
+
+ function typeCheckPass(declaration, value) {
+ const propTypes = {
+ testProp: declaration,
+ };
+ const props = {
+ testProp: value,
+ };
+ const message = getPropTypeWarningMessage(propTypes, props, 'testComponent');
+ expect(message).toBe(null);
+ }
+
+ 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('checkPropTypes', function() {
+ it('does not call validators', function() {
+ spyOn(console, 'error');
+
+ var spy = jest.fn();
+ typeCheckPass(PropTypes.string, 42);
+ typeCheckPass(PropTypes.bool, 'whatever');
+ typeCheckPass(spy, 'no way');
+ expect(spy).not.toBeCalled();
+ });
+ });
+});
diff --git a/checkPropTypes.js b/checkPropTypes.js
index 0b68714..c2b536f 100644
--- a/checkPropTypes.js
+++ b/checkPropTypes.js
@@ -9,12 +9,12 @@
'use strict';
-var invariant = require('fbjs/lib/invariant');
-var warning = require('fbjs/lib/warning');
-
-var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
-
-var loggedTypeFailures = {};
+if (process.env.NODE_ENV !== 'production') {
+ var invariant = require('fbjs/lib/invariant');
+ var warning = require('fbjs/lib/warning');
+ var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
+ var loggedTypeFailures = {};
+}
/**
* Assert that the values match with the type specs.
@@ -43,7 +43,7 @@ function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
} catch (ex) {
error = ex;
}
- process.env.NODE_ENV !== 'production' ? 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) : void 0;
+ 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.
@@ -51,7 +51,7 @@ function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
var stack = getStack ? getStack() : '';
- process.env.NODE_ENV !== 'production' ? warning(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : '') : void 0;
+ warning(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : '');
}
}
}
diff --git a/factory.js b/factory.js
index 9cab0a4..7758ec1 100644
--- a/factory.js
+++ b/factory.js
@@ -9,476 +9,13 @@
'use strict';
-var emptyFunction = require('fbjs/lib/emptyFunction');
-var invariant = require('fbjs/lib/invariant');
-var warning = require('fbjs/lib/warning');
-
-var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
-var checkPropTypes = require('./checkPropTypes');
-
-module.exports = function (isValidElement) {
- /* 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 = '<>';
-
- var ReactPropTypes;
-
- if (process.env.NODE_ENV !== 'production') {
- // 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 = function () {
- return 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 (process.env.NODE_ENV !== 'production') {
- var manualPropTypeCallCache = {};
- }
- function checkType(isRequired, props, propName, componentName, location, propFullName, secret) {
- componentName = componentName || ANONYMOUS;
- propFullName = propFullName || propName;
- if (process.env.NODE_ENV !== 'production') {
- if (secret !== ReactPropTypesSecret && typeof console !== 'undefined') {
- var cacheKey = componentName + ':' + propName;
- if (!manualPropTypeCallCache[cacheKey]) {
- process.env.NODE_ENV !== 'production' ? 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) : void 0;
- 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 (!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)) {
- process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0;
- 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)) {
- process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0;
- 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 || 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;
- }
-
- ReactPropTypes.checkPropTypes = checkPropTypes;
- ReactPropTypes.PropTypes = ReactPropTypes;
-
- return ReactPropTypes;
+// React 15.5 references this module, and assumes PropTypes are still callable in production.
+// Therefore we re-export development-only version with all the PropTypes checks here.
+// However if one is migrating to the `prop-types` npm library, they will go through the
+// `index.js` entry point, and it will branch depending on the environment.
+var factory = require('./factoryWithTypeCheckers');
+module.exports = function(isValidElement) {
+ // It is still allowed in 15.5.
+ var throwOnDirectAccess = false;
+ return factory(isValidElement, throwOnDirectAccess);
};
diff --git a/factoryWithThrowingShims.js b/factoryWithThrowingShims.js
new file mode 100644
index 0000000..257f710
--- /dev/null
+++ b/factoryWithThrowingShims.js
@@ -0,0 +1,54 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+var emptyFunction = require('fbjs/lib/emptyFunction');
+var invariant = require('fbjs/lib/invariant');
+
+module.exports = function() {
+ // Important!
+ // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.
+ function shim() {
+ invariant(
+ false,
+ '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'
+ );
+ };
+ shim.isRequired = shim;
+ function getShim() {
+ return shim;
+ };
+ var ReactPropTypes = {
+ array: shim,
+ bool: shim,
+ func: shim,
+ number: shim,
+ object: shim,
+ string: shim,
+ symbol: shim,
+
+ any: shim,
+ arrayOf: getShim,
+ element: shim,
+ instanceOf: getShim,
+ node: shim,
+ objectOf: getShim,
+ oneOf: getShim,
+ oneOfType: getShim,
+ shape: getShim
+ };
+
+ ReactPropTypes.checkPropTypes = emptyFunction;
+ ReactPropTypes.PropTypes = ReactPropTypes;
+
+ return ReactPropTypes;
+};
diff --git a/factoryWithTypeCheckers.js b/factoryWithTypeCheckers.js
new file mode 100644
index 0000000..4bef015
--- /dev/null
+++ b/factoryWithTypeCheckers.js
@@ -0,0 +1,472 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+var emptyFunction = require('fbjs/lib/emptyFunction');
+var invariant = require('fbjs/lib/invariant');
+var warning = require('fbjs/lib/warning');
+
+var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
+var checkPropTypes = require('./checkPropTypes');
+
+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 = '<>';
+
+ // 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(),
+ instanceOf: createInstanceTypeChecker,
+ node: createNodeChecker(),
+ objectOf: createObjectOfTypeChecker,
+ oneOf: createEnumTypeChecker,
+ oneOfType: createUnionTypeChecker,
+ shape: createShapeTypeChecker
+ };
+
+ /**
+ * 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 = {};
+ }
+ 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
+ invariant(
+ false,
+ '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'
+ );
+ } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') {
+ // Old behavior for people using React.PropTypes
+ 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 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.',
+ 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 (!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)) {
+ process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0;
+ 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)) {
+ process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0;
+ 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 || 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;
+ }
+
+ ReactPropTypes.checkPropTypes = checkPropTypes;
+ ReactPropTypes.PropTypes = ReactPropTypes;
+
+ return ReactPropTypes;
+};
diff --git a/index.js b/index.js
index e4b9ab3..8f94a31 100644
--- a/index.js
+++ b/index.js
@@ -7,17 +7,24 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
-var factory = require('./factory');
+if (process.env.NODE_ENV !== 'production') {
+ var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&
+ Symbol.for &&
+ Symbol.for('react.element')) ||
+ 0xeac7;
-var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&
- Symbol.for &&
- Symbol.for('react.element')) ||
- 0xeac7;
+ var isValidElement = function(object) {
+ return typeof object === 'object' &&
+ object !== null &&
+ object.$$typeof === REACT_ELEMENT_TYPE;
+ };
-function isValidElement(object) {
- return typeof object === 'object' &&
- object !== null &&
- object.$$typeof === REACT_ELEMENT_TYPE;
+ // By explicitly using `prop-types` you are opting into new development behavior.
+ // http://fb.me/prop-types-in-prod
+ var throwOnDirectAccess = true;
+ module.exports = require('./factoryWithTypeCheckers')(isValidElement, throwOnDirectAccess);
+} else {
+ // By explicitly using `prop-types` you are opting into new production behavior.
+ // http://fb.me/prop-types-in-prod
+ module.exports = require('./factoryWithThrowingShims')();
}
-
-module.exports = factory(isValidElement);
diff --git a/package.json b/package.json
index 8a4904d..45f1983 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "prop-types",
- "version": "15.5.6",
+ "version": "15.5.7-alpha.1",
"description": "Runtime type checking for React props and similar objects.",
"main": "index.js",
"license": "BSD-3-Clause",
@@ -10,6 +10,8 @@
"README.md",
"checkPropTypes.js",
"factory.js",
+ "factoryWithThrowingShims.js",
+ "factoryWithTypeCheckers.js",
"index.js",
"prop-types.js",
"prop-types.min.js",
@@ -29,7 +31,7 @@
"scripts": {
"test": "jest",
"umd": "NODE_ENV=development browserify index.js -t envify --standalone PropTypes -o prop-types.js",
- "umd-min": "NODE_ENV=production browserify index.js -t envify --standalone PropTypes -o | uglifyjs --compress unused,dead_code -o prop-types.min.js",
+ "umd-min": "NODE_ENV=production browserify index.js -t envify -t uglifyify --standalone PropTypes -p bundle-collapser/plugin -o | uglifyjs --compress unused,dead_code -o prop-types.min.js",
"build": "yarn umd && yarn umd-min",
"prepublish": "yarn build"
},
@@ -37,9 +39,11 @@
"babel-jest": "^19.0.0",
"babel-preset-react": "^6.24.1",
"browserify": "^14.3.0",
+ "bundle-collapser": "^1.2.1",
"envify": "^4.0.0",
"jest": "^19.0.2",
"react": "^15.5.1",
+ "uglifyify": "^3.0.4",
"uglifyjs": "^2.4.10"
}
}
diff --git a/yarn.lock b/yarn.lock
index 20b2408..0f11ded 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -19,6 +19,10 @@ acorn-globals@^3.1.0:
dependencies:
acorn "^4.0.4"
+acorn@^1.0.3:
+ version "1.2.2"
+ resolved "http://npme.walmart.com/acorn/-/acorn-1.2.2.tgz#c8ce27de0acc76d896d2b1fad3df588d9e82f014"
+
acorn@^4.0.3, acorn@^4.0.4:
version "4.0.11"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
@@ -426,6 +430,16 @@ brorand@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+browser-pack@^5.0.1:
+ version "5.0.1"
+ resolved "http://npme.walmart.com/browser-pack/-/browser-pack-5.0.1.tgz#4197719b20c6e0aaa09451c5111e53efb6fbc18d"
+ dependencies:
+ JSONStream "^1.0.3"
+ combine-source-map "~0.6.1"
+ defined "^1.0.0"
+ through2 "^1.0.0"
+ umd "^3.0.0"
+
browser-pack@^6.0.1:
version "6.0.2"
resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.2.tgz#f86cd6cef4f5300c8e63e07a4d512f65fbff4531"
@@ -442,6 +456,15 @@ browser-resolve@^1.11.0, browser-resolve@^1.11.2, browser-resolve@^1.7.0:
dependencies:
resolve "1.1.7"
+browser-unpack@^1.1.0:
+ version "1.2.0"
+ resolved "http://npme.walmart.com/browser-unpack/-/browser-unpack-1.2.0.tgz#357aee31fc467831684d063e4355e070a782970d"
+ dependencies:
+ acorn "^4.0.3"
+ browser-pack "^5.0.1"
+ concat-stream "^1.5.0"
+ minimist "^1.1.1"
+
browserify-aes@^1.0.0, browserify-aes@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
@@ -580,6 +603,17 @@ builtin-status-codes@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+bundle-collapser@^1.2.1:
+ version "1.2.1"
+ resolved "http://npme.walmart.com/bundle-collapser/-/bundle-collapser-1.2.1.tgz#e119afc92638e440b9085f47ae081fa756cba33d"
+ dependencies:
+ browser-pack "^5.0.1"
+ browser-unpack "^1.1.0"
+ concat-stream "^1.5.0"
+ falafel "^1.2.0"
+ minimist "^1.1.1"
+ through2 "^2.0.0"
+
cached-path-relative@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.1.tgz#d09c4b52800aa4c078e2dd81a869aac90d2e54e7"
@@ -661,6 +695,15 @@ color-name@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+combine-source-map@~0.6.1:
+ version "0.6.1"
+ resolved "http://npme.walmart.com/combine-source-map/-/combine-source-map-0.6.1.tgz#9b4a09c316033d768e0f11e029fa2730e079ad96"
+ dependencies:
+ convert-source-map "~1.1.0"
+ inline-source-map "~0.5.0"
+ lodash.memoize "~3.0.3"
+ source-map "~0.4.2"
+
combine-source-map@~0.7.1:
version "0.7.2"
resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e"
@@ -680,7 +723,7 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-concat-stream@~1.5.0, concat-stream@~1.5.1:
+concat-stream@^1.5.0, concat-stream@~1.5.0, concat-stream@~1.5.1:
version "1.5.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
dependencies:
@@ -702,11 +745,7 @@ content-type-parser@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
-convert-source-map@^1.1.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
-
-convert-source-map@~1.1.0:
+convert-source-map@^1.1.0, convert-source-map@~1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860"
@@ -967,6 +1006,10 @@ expand-range@^1.8.1:
dependencies:
fill-range "^2.1.0"
+extend@^1.2.1:
+ version "1.3.0"
+ resolved "http://npme.walmart.com/extend/-/extend-1.3.0.tgz#d1516fb0ff5624d2ebf9123ea1dac5a1994004f8"
+
extend@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
@@ -981,6 +1024,15 @@ extsprintf@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+falafel@^1.2.0:
+ version "1.2.0"
+ resolved "http://npme.walmart.com/falafel/-/falafel-1.2.0.tgz#c18d24ef5091174a497f318cd24b026a25cddab4"
+ dependencies:
+ acorn "^1.0.3"
+ foreach "^2.0.5"
+ isarray "0.0.1"
+ object-keys "^1.0.6"
+
fast-levenshtein@~2.0.4:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
@@ -1053,6 +1105,10 @@ for-own@^0.1.4:
dependencies:
for-in "^1.0.1"
+foreach@^2.0.5:
+ version "2.0.5"
+ resolved "http://npme.walmart.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
+
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@@ -1247,6 +1303,12 @@ inherits@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+inline-source-map@~0.5.0:
+ version "0.5.0"
+ resolved "http://npme.walmart.com/inline-source-map/-/inline-source-map-0.5.0.tgz#4a4c5dd8e4fb5e9b3cda60c822dfadcaee66e0af"
+ dependencies:
+ source-map "~0.4.0"
+
inline-source-map@~0.6.0:
version "0.6.2"
resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5"
@@ -1358,14 +1420,14 @@ is-utf8@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+isarray@0.0.1, isarray@~0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+
isarray@1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
-isarray@~0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
-
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -1969,6 +2031,10 @@ object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+object-keys@^1.0.6:
+ version "1.0.11"
+ resolved "http://npme.walmart.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
+
object.omit@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
@@ -2238,6 +2304,15 @@ read-pkg@^1.0.0:
normalize-package-data "^2.3.2"
path-type "^1.0.0"
+"readable-stream@>=1.1.13-1 <1.2.0-0":
+ version "1.1.14"
+ resolved "http://npme.walmart.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.6:
version "2.2.8"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.8.tgz#ad28b686f3554c73d39bc32347fa058356624705"
@@ -2431,7 +2506,7 @@ source-map@0.1.34:
dependencies:
amdefine ">=0.0.4"
-source-map@^0.4.4:
+source-map@^0.4.4, source-map@~0.4.0, source-map@~0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
dependencies:
@@ -2595,6 +2670,13 @@ throat@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+through2@^1.0.0:
+ version "1.1.1"
+ resolved "http://npme.walmart.com/through2/-/through2-1.1.1.tgz#0847cbc4449f3405574dbdccd9bb841b83ac3545"
+ dependencies:
+ readable-stream ">=1.1.13-1 <1.2.0-0"
+ xtend ">=4.0.0 <4.1.0-0"
+
through2@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
@@ -2666,7 +2748,7 @@ ua-parser-js@^0.7.9:
version "0.7.12"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
-uglify-js@^2.6:
+uglify-js@2.x.x, uglify-js@^2.6:
version "2.8.21"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.21.tgz#1733f669ae6f82fc90c7b25ec0f5c783ee375314"
dependencies:
@@ -2679,6 +2761,16 @@ uglify-to-browserify@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+uglifyify@^3.0.4:
+ version "3.0.4"
+ resolved "http://npme.walmart.com/uglifyify/-/uglifyify-3.0.4.tgz#487e080a5a7798880e68e90def9b06681fb13bd2"
+ dependencies:
+ convert-source-map "~1.1.0"
+ extend "^1.2.1"
+ minimatch "^3.0.2"
+ through "~2.3.4"
+ uglify-js "2.x.x"
+
uglifyjs@^2.4.10:
version "2.4.10"
resolved "https://registry.yarnpkg.com/uglifyjs/-/uglifyjs-2.4.10.tgz#632927319fa6a3da3fc91f9773ac27bfe6c3ee92"
@@ -2781,14 +2873,10 @@ window-size@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
-wordwrap@0.0.2:
+wordwrap@0.0.2, wordwrap@~0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
-wordwrap@~0.0.2:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
-
wordwrap@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"