1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | 'use strict';
|
9 |
|
10 | var ReactIs = require('react-is');
|
11 | var assign = require('object-assign');
|
12 |
|
13 | var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
|
14 | var checkPropTypes = require('./checkPropTypes');
|
15 |
|
16 | var has = Function.call.bind(Object.prototype.hasOwnProperty);
|
17 | var printWarning = function() {};
|
18 |
|
19 | if (process.env.NODE_ENV !== 'production') {
|
20 | printWarning = function(text) {
|
21 | var message = 'Warning: ' + text;
|
22 | if (typeof console !== 'undefined') {
|
23 | console.error(message);
|
24 | }
|
25 | try {
|
26 |
|
27 |
|
28 |
|
29 | throw new Error(message);
|
30 | } catch (x) {}
|
31 | };
|
32 | }
|
33 |
|
34 | function emptyFunctionThatReturnsNull() {
|
35 | return null;
|
36 | }
|
37 |
|
38 | module.exports = function(isValidElement, throwOnDirectAccess) {
|
39 |
|
40 | var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
|
41 | var FAUX_ITERATOR_SYMBOL = '@@iterator';
|
42 |
|
43 | |
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 | function getIteratorFn(maybeIterable) {
|
58 | var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
|
59 | if (typeof iteratorFn === 'function') {
|
60 | return iteratorFn;
|
61 | }
|
62 | }
|
63 |
|
64 | |
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | var ANONYMOUS = '<<anonymous>>';
|
112 |
|
113 |
|
114 |
|
115 | var ReactPropTypes = {
|
116 | array: createPrimitiveTypeChecker('array'),
|
117 | bool: createPrimitiveTypeChecker('boolean'),
|
118 | func: createPrimitiveTypeChecker('function'),
|
119 | number: createPrimitiveTypeChecker('number'),
|
120 | object: createPrimitiveTypeChecker('object'),
|
121 | string: createPrimitiveTypeChecker('string'),
|
122 | symbol: createPrimitiveTypeChecker('symbol'),
|
123 |
|
124 | any: createAnyTypeChecker(),
|
125 | arrayOf: createArrayOfTypeChecker,
|
126 | element: createElementTypeChecker(),
|
127 | elementType: createElementTypeTypeChecker(),
|
128 | instanceOf: createInstanceTypeChecker,
|
129 | node: createNodeChecker(),
|
130 | objectOf: createObjectOfTypeChecker,
|
131 | oneOf: createEnumTypeChecker,
|
132 | oneOfType: createUnionTypeChecker,
|
133 | shape: createShapeTypeChecker,
|
134 | exact: createStrictShapeTypeChecker,
|
135 | };
|
136 |
|
137 | |
138 |
|
139 |
|
140 |
|
141 |
|
142 | function is(x, y) {
|
143 |
|
144 | if (x === y) {
|
145 |
|
146 |
|
147 | return x !== 0 || 1 / x === 1 / y;
|
148 | } else {
|
149 |
|
150 | return x !== x && y !== y;
|
151 | }
|
152 | }
|
153 |
|
154 |
|
155 | |
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 | function PropTypeError(message) {
|
163 | this.message = message;
|
164 | this.stack = '';
|
165 | }
|
166 |
|
167 | PropTypeError.prototype = Error.prototype;
|
168 |
|
169 | function createChainableTypeChecker(validate) {
|
170 | if (process.env.NODE_ENV !== 'production') {
|
171 | var manualPropTypeCallCache = {};
|
172 | var manualPropTypeWarningCount = 0;
|
173 | }
|
174 | function checkType(isRequired, props, propName, componentName, location, propFullName, secret) {
|
175 | componentName = componentName || ANONYMOUS;
|
176 | propFullName = propFullName || propName;
|
177 |
|
178 | if (secret !== ReactPropTypesSecret) {
|
179 | if (throwOnDirectAccess) {
|
180 |
|
181 | var err = new Error(
|
182 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
|
183 | 'Use `PropTypes.checkPropTypes()` to call them. ' +
|
184 | 'Read more at http://fb.me/use-check-prop-types'
|
185 | );
|
186 | err.name = 'Invariant Violation';
|
187 | throw err;
|
188 | } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') {
|
189 |
|
190 | var cacheKey = componentName + ':' + propName;
|
191 | if (
|
192 | !manualPropTypeCallCache[cacheKey] &&
|
193 |
|
194 | manualPropTypeWarningCount < 3
|
195 | ) {
|
196 | printWarning(
|
197 | 'You are manually calling a React.PropTypes validation ' +
|
198 | 'function for the `' + propFullName + '` prop on `' + componentName + '`. This is deprecated ' +
|
199 | 'and will throw in the standalone `prop-types` package. ' +
|
200 | 'You may be seeing this warning due to a third-party PropTypes ' +
|
201 | 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.'
|
202 | );
|
203 | manualPropTypeCallCache[cacheKey] = true;
|
204 | manualPropTypeWarningCount++;
|
205 | }
|
206 | }
|
207 | }
|
208 | if (props[propName] == null) {
|
209 | if (isRequired) {
|
210 | if (props[propName] === null) {
|
211 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.'));
|
212 | }
|
213 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.'));
|
214 | }
|
215 | return null;
|
216 | } else {
|
217 | return validate(props, propName, componentName, location, propFullName);
|
218 | }
|
219 | }
|
220 |
|
221 | var chainedCheckType = checkType.bind(null, false);
|
222 | chainedCheckType.isRequired = checkType.bind(null, true);
|
223 |
|
224 | return chainedCheckType;
|
225 | }
|
226 |
|
227 | function createPrimitiveTypeChecker(expectedType) {
|
228 | function validate(props, propName, componentName, location, propFullName, secret) {
|
229 | var propValue = props[propName];
|
230 | var propType = getPropType(propValue);
|
231 | if (propType !== expectedType) {
|
232 |
|
233 |
|
234 |
|
235 | var preciseType = getPreciseType(propValue);
|
236 |
|
237 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.'));
|
238 | }
|
239 | return null;
|
240 | }
|
241 | return createChainableTypeChecker(validate);
|
242 | }
|
243 |
|
244 | function createAnyTypeChecker() {
|
245 | return createChainableTypeChecker(emptyFunctionThatReturnsNull);
|
246 | }
|
247 |
|
248 | function createArrayOfTypeChecker(typeChecker) {
|
249 | function validate(props, propName, componentName, location, propFullName) {
|
250 | if (typeof typeChecker !== 'function') {
|
251 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.');
|
252 | }
|
253 | var propValue = props[propName];
|
254 | if (!Array.isArray(propValue)) {
|
255 | var propType = getPropType(propValue);
|
256 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.'));
|
257 | }
|
258 | for (var i = 0; i < propValue.length; i++) {
|
259 | var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret);
|
260 | if (error instanceof Error) {
|
261 | return error;
|
262 | }
|
263 | }
|
264 | return null;
|
265 | }
|
266 | return createChainableTypeChecker(validate);
|
267 | }
|
268 |
|
269 | function createElementTypeChecker() {
|
270 | function validate(props, propName, componentName, location, propFullName) {
|
271 | var propValue = props[propName];
|
272 | if (!isValidElement(propValue)) {
|
273 | var propType = getPropType(propValue);
|
274 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.'));
|
275 | }
|
276 | return null;
|
277 | }
|
278 | return createChainableTypeChecker(validate);
|
279 | }
|
280 |
|
281 | function createElementTypeTypeChecker() {
|
282 | function validate(props, propName, componentName, location, propFullName) {
|
283 | var propValue = props[propName];
|
284 | if (!ReactIs.isValidElementType(propValue)) {
|
285 | var propType = getPropType(propValue);
|
286 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement type.'));
|
287 | }
|
288 | return null;
|
289 | }
|
290 | return createChainableTypeChecker(validate);
|
291 | }
|
292 |
|
293 | function createInstanceTypeChecker(expectedClass) {
|
294 | function validate(props, propName, componentName, location, propFullName) {
|
295 | if (!(props[propName] instanceof expectedClass)) {
|
296 | var expectedClassName = expectedClass.name || ANONYMOUS;
|
297 | var actualClassName = getClassName(props[propName]);
|
298 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.'));
|
299 | }
|
300 | return null;
|
301 | }
|
302 | return createChainableTypeChecker(validate);
|
303 | }
|
304 |
|
305 | function createEnumTypeChecker(expectedValues) {
|
306 | if (!Array.isArray(expectedValues)) {
|
307 | if (process.env.NODE_ENV !== 'production') {
|
308 | if (arguments.length > 1) {
|
309 | printWarning(
|
310 | 'Invalid arguments supplied to oneOf, expected an array, got ' + arguments.length + ' arguments. ' +
|
311 | 'A common mistake is to write oneOf(x, y, z) instead of oneOf([x, y, z]).'
|
312 | );
|
313 | } else {
|
314 | printWarning('Invalid argument supplied to oneOf, expected an array.');
|
315 | }
|
316 | }
|
317 | return emptyFunctionThatReturnsNull;
|
318 | }
|
319 |
|
320 | function validate(props, propName, componentName, location, propFullName) {
|
321 | var propValue = props[propName];
|
322 | for (var i = 0; i < expectedValues.length; i++) {
|
323 | if (is(propValue, expectedValues[i])) {
|
324 | return null;
|
325 | }
|
326 | }
|
327 |
|
328 | var valuesString = JSON.stringify(expectedValues, function replacer(key, value) {
|
329 | var type = getPreciseType(value);
|
330 | if (type === 'symbol') {
|
331 | return String(value);
|
332 | }
|
333 | return value;
|
334 | });
|
335 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + String(propValue) + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.'));
|
336 | }
|
337 | return createChainableTypeChecker(validate);
|
338 | }
|
339 |
|
340 | function createObjectOfTypeChecker(typeChecker) {
|
341 | function validate(props, propName, componentName, location, propFullName) {
|
342 | if (typeof typeChecker !== 'function') {
|
343 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.');
|
344 | }
|
345 | var propValue = props[propName];
|
346 | var propType = getPropType(propValue);
|
347 | if (propType !== 'object') {
|
348 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.'));
|
349 | }
|
350 | for (var key in propValue) {
|
351 | if (has(propValue, key)) {
|
352 | var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
|
353 | if (error instanceof Error) {
|
354 | return error;
|
355 | }
|
356 | }
|
357 | }
|
358 | return null;
|
359 | }
|
360 | return createChainableTypeChecker(validate);
|
361 | }
|
362 |
|
363 | function createUnionTypeChecker(arrayOfTypeCheckers) {
|
364 | if (!Array.isArray(arrayOfTypeCheckers)) {
|
365 | process.env.NODE_ENV !== 'production' ? printWarning('Invalid argument supplied to oneOfType, expected an instance of array.') : void 0;
|
366 | return emptyFunctionThatReturnsNull;
|
367 | }
|
368 |
|
369 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
|
370 | var checker = arrayOfTypeCheckers[i];
|
371 | if (typeof checker !== 'function') {
|
372 | printWarning(
|
373 | 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' +
|
374 | 'received ' + getPostfixForTypeWarning(checker) + ' at index ' + i + '.'
|
375 | );
|
376 | return emptyFunctionThatReturnsNull;
|
377 | }
|
378 | }
|
379 |
|
380 | function validate(props, propName, componentName, location, propFullName) {
|
381 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
|
382 | var checker = arrayOfTypeCheckers[i];
|
383 | if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) {
|
384 | return null;
|
385 | }
|
386 | }
|
387 |
|
388 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.'));
|
389 | }
|
390 | return createChainableTypeChecker(validate);
|
391 | }
|
392 |
|
393 | function createNodeChecker() {
|
394 | function validate(props, propName, componentName, location, propFullName) {
|
395 | if (!isNode(props[propName])) {
|
396 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.'));
|
397 | }
|
398 | return null;
|
399 | }
|
400 | return createChainableTypeChecker(validate);
|
401 | }
|
402 |
|
403 | function createShapeTypeChecker(shapeTypes) {
|
404 | function validate(props, propName, componentName, location, propFullName) {
|
405 | var propValue = props[propName];
|
406 | var propType = getPropType(propValue);
|
407 | if (propType !== 'object') {
|
408 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
|
409 | }
|
410 | for (var key in shapeTypes) {
|
411 | var checker = shapeTypes[key];
|
412 | if (!checker) {
|
413 | continue;
|
414 | }
|
415 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
|
416 | if (error) {
|
417 | return error;
|
418 | }
|
419 | }
|
420 | return null;
|
421 | }
|
422 | return createChainableTypeChecker(validate);
|
423 | }
|
424 |
|
425 | function createStrictShapeTypeChecker(shapeTypes) {
|
426 | function validate(props, propName, componentName, location, propFullName) {
|
427 | var propValue = props[propName];
|
428 | var propType = getPropType(propValue);
|
429 | if (propType !== 'object') {
|
430 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
|
431 | }
|
432 |
|
433 |
|
434 | var allKeys = assign({}, props[propName], shapeTypes);
|
435 | for (var key in allKeys) {
|
436 | var checker = shapeTypes[key];
|
437 | if (!checker) {
|
438 | return new PropTypeError(
|
439 | 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' +
|
440 | '\nBad object: ' + JSON.stringify(props[propName], null, ' ') +
|
441 | '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ')
|
442 | );
|
443 | }
|
444 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
|
445 | if (error) {
|
446 | return error;
|
447 | }
|
448 | }
|
449 | return null;
|
450 | }
|
451 |
|
452 | return createChainableTypeChecker(validate);
|
453 | }
|
454 |
|
455 | function isNode(propValue) {
|
456 | switch (typeof propValue) {
|
457 | case 'number':
|
458 | case 'string':
|
459 | case 'undefined':
|
460 | return true;
|
461 | case 'boolean':
|
462 | return !propValue;
|
463 | case 'object':
|
464 | if (Array.isArray(propValue)) {
|
465 | return propValue.every(isNode);
|
466 | }
|
467 | if (propValue === null || isValidElement(propValue)) {
|
468 | return true;
|
469 | }
|
470 |
|
471 | var iteratorFn = getIteratorFn(propValue);
|
472 | if (iteratorFn) {
|
473 | var iterator = iteratorFn.call(propValue);
|
474 | var step;
|
475 | if (iteratorFn !== propValue.entries) {
|
476 | while (!(step = iterator.next()).done) {
|
477 | if (!isNode(step.value)) {
|
478 | return false;
|
479 | }
|
480 | }
|
481 | } else {
|
482 |
|
483 | while (!(step = iterator.next()).done) {
|
484 | var entry = step.value;
|
485 | if (entry) {
|
486 | if (!isNode(entry[1])) {
|
487 | return false;
|
488 | }
|
489 | }
|
490 | }
|
491 | }
|
492 | } else {
|
493 | return false;
|
494 | }
|
495 |
|
496 | return true;
|
497 | default:
|
498 | return false;
|
499 | }
|
500 | }
|
501 |
|
502 | function isSymbol(propType, propValue) {
|
503 |
|
504 | if (propType === 'symbol') {
|
505 | return true;
|
506 | }
|
507 |
|
508 |
|
509 | if (!propValue) {
|
510 | return false;
|
511 | }
|
512 |
|
513 |
|
514 | if (propValue['@@toStringTag'] === 'Symbol') {
|
515 | return true;
|
516 | }
|
517 |
|
518 |
|
519 | if (typeof Symbol === 'function' && propValue instanceof Symbol) {
|
520 | return true;
|
521 | }
|
522 |
|
523 | return false;
|
524 | }
|
525 |
|
526 |
|
527 | function getPropType(propValue) {
|
528 | var propType = typeof propValue;
|
529 | if (Array.isArray(propValue)) {
|
530 | return 'array';
|
531 | }
|
532 | if (propValue instanceof RegExp) {
|
533 |
|
534 |
|
535 |
|
536 | return 'object';
|
537 | }
|
538 | if (isSymbol(propType, propValue)) {
|
539 | return 'symbol';
|
540 | }
|
541 | return propType;
|
542 | }
|
543 |
|
544 |
|
545 |
|
546 | function getPreciseType(propValue) {
|
547 | if (typeof propValue === 'undefined' || propValue === null) {
|
548 | return '' + propValue;
|
549 | }
|
550 | var propType = getPropType(propValue);
|
551 | if (propType === 'object') {
|
552 | if (propValue instanceof Date) {
|
553 | return 'date';
|
554 | } else if (propValue instanceof RegExp) {
|
555 | return 'regexp';
|
556 | }
|
557 | }
|
558 | return propType;
|
559 | }
|
560 |
|
561 |
|
562 |
|
563 | function getPostfixForTypeWarning(value) {
|
564 | var type = getPreciseType(value);
|
565 | switch (type) {
|
566 | case 'array':
|
567 | case 'object':
|
568 | return 'an ' + type;
|
569 | case 'boolean':
|
570 | case 'date':
|
571 | case 'regexp':
|
572 | return 'a ' + type;
|
573 | default:
|
574 | return type;
|
575 | }
|
576 | }
|
577 |
|
578 |
|
579 | function getClassName(propValue) {
|
580 | if (!propValue.constructor || !propValue.constructor.name) {
|
581 | return ANONYMOUS;
|
582 | }
|
583 | return propValue.constructor.name;
|
584 | }
|
585 |
|
586 | ReactPropTypes.checkPropTypes = checkPropTypes;
|
587 | ReactPropTypes.resetWarningCache = checkPropTypes.resetWarningCache;
|
588 | ReactPropTypes.PropTypes = ReactPropTypes;
|
589 |
|
590 | return ReactPropTypes;
|
591 | };
|