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. import type {Fiber} from './ReactInternalTypes';
    
  11. import type {CapturedValue} from './ReactCapturedValue';
    
  12. 
    
  13. import {showErrorDialog} from './ReactFiberErrorDialog';
    
  14. import {ClassComponent} from './ReactWorkTags';
    
  15. import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
    
  16. import {HostRoot} from 'react-reconciler/src/ReactWorkTags';
    
  17. 
    
  18. export function logCapturedError(
    
  19.   boundary: Fiber,
    
  20.   errorInfo: CapturedValue<mixed>,
    
  21. ): void {
    
  22.   try {
    
  23.     const logError = showErrorDialog(boundary, errorInfo);
    
  24. 
    
  25.     // Allow injected showErrorDialog() to prevent default console.error logging.
    
  26.     // This enables renderers like ReactNative to better manage redbox behavior.
    
  27.     if (logError === false) {
    
  28.       return;
    
  29.     }
    
  30. 
    
  31.     const error = (errorInfo.value: any);
    
  32.     if (__DEV__) {
    
  33.       const source = errorInfo.source;
    
  34.       const stack = errorInfo.stack;
    
  35.       const componentStack = stack !== null ? stack : '';
    
  36.       // Browsers support silencing uncaught errors by calling
    
  37.       // `preventDefault()` in window `error` handler.
    
  38.       // We record this information as an expando on the error.
    
  39.       if (error != null && error._suppressLogging) {
    
  40.         if (boundary.tag === ClassComponent) {
    
  41.           // The error is recoverable and was silenced.
    
  42.           // Ignore it and don't print the stack addendum.
    
  43.           // This is handy for testing error boundaries without noise.
    
  44.           return;
    
  45.         }
    
  46.         // The error is fatal. Since the silencing might have
    
  47.         // been accidental, we'll surface it anyway.
    
  48.         // However, the browser would have silenced the original error
    
  49.         // so we'll print it first, and then print the stack addendum.
    
  50.         console['error'](error); // Don't transform to our wrapper
    
  51.         // For a more detailed description of this block, see:
    
  52.         // https://github.com/facebook/react/pull/13384
    
  53.       }
    
  54. 
    
  55.       const componentName = source ? getComponentNameFromFiber(source) : null;
    
  56.       const componentNameMessage = componentName
    
  57.         ? `The above error occurred in the <${componentName}> component:`
    
  58.         : 'The above error occurred in one of your React components:';
    
  59. 
    
  60.       let errorBoundaryMessage;
    
  61.       if (boundary.tag === HostRoot) {
    
  62.         errorBoundaryMessage =
    
  63.           'Consider adding an error boundary to your tree to customize error handling behavior.\n' +
    
  64.           'Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.';
    
  65.       } else {
    
  66.         const errorBoundaryName =
    
  67.           getComponentNameFromFiber(boundary) || 'Anonymous';
    
  68.         errorBoundaryMessage =
    
  69.           `React will try to recreate this component tree from scratch ` +
    
  70.           `using the error boundary you provided, ${errorBoundaryName}.`;
    
  71.       }
    
  72.       const combinedMessage =
    
  73.         `${componentNameMessage}\n${componentStack}\n\n` +
    
  74.         `${errorBoundaryMessage}`;
    
  75. 
    
  76.       // In development, we provide our own message with just the component stack.
    
  77.       // We don't include the original error message and JS stack because the browser
    
  78.       // has already printed it. Even if the application swallows the error, it is still
    
  79.       // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils.
    
  80.       console['error'](combinedMessage); // Don't transform to our wrapper
    
  81.     } else {
    
  82.       // In production, we print the error directly.
    
  83.       // This will include the message, the JS stack, and anything the browser wants to show.
    
  84.       // We pass the error object instead of custom message so that the browser displays the error natively.
    
  85.       console['error'](error); // Don't transform to our wrapper
    
  86.     }
    
  87.   } catch (e) {
    
  88.     // This method must not throw, or React internal state will get messed up.
    
  89.     // If console.error is overridden, or logCapturedError() shows a dialog that throws,
    
  90.     // we want to report this error outside of the normal stack as a last resort.
    
  91.     // https://github.com/facebook/react/issues/13188
    
  92.     setTimeout(() => {
    
  93.       throw e;
    
  94.     });
    
  95.   }
    
  96. }