1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. const loggedTypeFailures: {[string]: boolean} = {};
    
  11. 
    
  12. import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
    
  13. 
    
  14. import ReactSharedInternals from 'shared/ReactSharedInternals';
    
  15. import hasOwnProperty from 'shared/hasOwnProperty';
    
  16. 
    
  17. const ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
    
  18. 
    
  19. function setCurrentlyValidatingElement(element: any) {
    
  20.   if (__DEV__) {
    
  21.     if (element) {
    
  22.       const owner = element._owner;
    
  23.       const stack = describeUnknownElementTypeFrameInDEV(
    
  24.         element.type,
    
  25.         element._source,
    
  26.         owner ? owner.type : null,
    
  27.       );
    
  28.       ReactDebugCurrentFrame.setExtraStackFrame(stack);
    
  29.     } else {
    
  30.       ReactDebugCurrentFrame.setExtraStackFrame(null);
    
  31.     }
    
  32.   }
    
  33. }
    
  34. 
    
  35. export default function checkPropTypes(
    
  36.   typeSpecs: Object,
    
  37.   values: Object,
    
  38.   location: string,
    
  39.   componentName: ?string,
    
  40.   element?: any,
    
  41. ): void {
    
  42.   if (__DEV__) {
    
  43.     // $FlowFixMe[incompatible-use] This is okay but Flow doesn't know it.
    
  44.     const has = Function.call.bind(hasOwnProperty);
    
  45.     for (const typeSpecName in typeSpecs) {
    
  46.       if (has(typeSpecs, typeSpecName)) {
    
  47.         let error;
    
  48.         // Prop type validation may throw. In case they do, we don't want to
    
  49.         // fail the render phase where it didn't fail before. So we log it.
    
  50.         // After these have been cleaned up, we'll let them throw.
    
  51.         try {
    
  52.           // This is intentionally an invariant that gets caught. It's the same
    
  53.           // behavior as without this statement except with a better message.
    
  54.           if (typeof typeSpecs[typeSpecName] !== 'function') {
    
  55.             // eslint-disable-next-line react-internal/prod-error-codes
    
  56.             const err = Error(
    
  57.               (componentName || 'React class') +
    
  58.                 ': ' +
    
  59.                 location +
    
  60.                 ' type `' +
    
  61.                 typeSpecName +
    
  62.                 '` is invalid; ' +
    
  63.                 'it must be a function, usually from the `prop-types` package, but received `' +
    
  64.                 typeof typeSpecs[typeSpecName] +
    
  65.                 '`.' +
    
  66.                 'This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.',
    
  67.             );
    
  68.             err.name = 'Invariant Violation';
    
  69.             throw err;
    
  70.           }
    
  71.           error = typeSpecs[typeSpecName](
    
  72.             values,
    
  73.             typeSpecName,
    
  74.             componentName,
    
  75.             location,
    
  76.             null,
    
  77.             'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED',
    
  78.           );
    
  79.         } catch (ex) {
    
  80.           error = ex;
    
  81.         }
    
  82.         if (error && !(error instanceof Error)) {
    
  83.           setCurrentlyValidatingElement(element);
    
  84.           console.error(
    
  85.             '%s: type specification of %s' +
    
  86.               ' `%s` is invalid; the type checker ' +
    
  87.               'function must return `null` or an `Error` but returned a %s. ' +
    
  88.               'You may have forgotten to pass an argument to the type checker ' +
    
  89.               'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' +
    
  90.               'shape all require an argument).',
    
  91.             componentName || 'React class',
    
  92.             location,
    
  93.             typeSpecName,
    
  94.             typeof error,
    
  95.           );
    
  96.           setCurrentlyValidatingElement(null);
    
  97.         }
    
  98.         if (error instanceof Error && !(error.message in loggedTypeFailures)) {
    
  99.           // Only monitor this failure once because there tends to be a lot of the
    
  100.           // same error.
    
  101.           loggedTypeFailures[error.message] = true;
    
  102.           setCurrentlyValidatingElement(element);
    
  103.           console.error('Failed %s type: %s', location, error.message);
    
  104.           setCurrentlyValidatingElement(null);
    
  105.         }
    
  106.       }
    
  107.     }
    
  108.   }
    
  109. }