| 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 {LazyComponent} from 'react/src/ReactLazy'; |
| 11 | import type {ReactContext, ReactConsumerType} from 'shared/ReactTypes'; |
| 12 | |
| 13 | import { |
| 14 | REACT_CONTEXT_TYPE, |
| 15 | REACT_CONSUMER_TYPE, |
| 16 | REACT_FORWARD_REF_TYPE, |
| 17 | REACT_FRAGMENT_TYPE, |
| 18 | REACT_PORTAL_TYPE, |
| 19 | REACT_MEMO_TYPE, |
| 20 | REACT_PROFILER_TYPE, |
| 21 | REACT_STRICT_MODE_TYPE, |
| 22 | REACT_SUSPENSE_TYPE, |
| 23 | REACT_SUSPENSE_LIST_TYPE, |
| 24 | REACT_LAZY_TYPE, |
| 25 | REACT_TRACING_MARKER_TYPE, |
| 26 | REACT_VIEW_TRANSITION_TYPE, |
| 27 | REACT_ACTIVITY_TYPE, |
| 28 | } from 'shared/ReactSymbols'; |
| 29 | |
| 30 | import { |
| 31 | enableTransitionTracing, |
| 32 | enableViewTransition, |
| 33 | } from './ReactFeatureFlags'; |
| 34 | |
| 35 | // Keep in sync with react-reconciler/getComponentNameFromFiber |
| 36 | function getWrappedName( |
| 37 | outerType: mixed, |
| 38 | innerType: any, |
| 39 | wrapperName: string, |
| 40 | ): string { |
| 41 | const displayName = (outerType as any).displayName; |
| 42 | if (displayName) { |
| 43 | return displayName; |
| 44 | } |
| 45 | const functionName = innerType.displayName || innerType.name || ''; |
| 46 | return functionName !== '' ? `${wrapperName}(${functionName})` : wrapperName; |
| 47 | } |
| 48 | |
| 49 | // Keep in sync with react-reconciler/getComponentNameFromFiber |
| 50 | function getContextName(type: ReactContext<any>) { |
| 51 | return type.displayName || 'Context'; |
| 52 | } |
| 53 | |
| 54 | const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference'); |
| 55 | |
| 56 | // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. |
| 57 | export default function getComponentNameFromType(type: mixed): string | null { |
| 58 | if (type == null) { |
| 59 | // Host root, text node or just invalid type. |
| 60 | return null; |
| 61 | } |
| 62 | if (typeof type === 'function') { |
| 63 | if ((type as any).$$typeof === REACT_CLIENT_REFERENCE) { |
| 64 | // TODO: Create a convention for naming client references with debug info. |
| 65 | return null; |
| 66 | } |
| 67 | return (type as any).displayName || type.name || null; |
| 68 | } |
| 69 | if (typeof type === 'string') { |
| 70 | return type; |
| 71 | } |
| 72 | switch (type) { |
| 73 | case REACT_FRAGMENT_TYPE: |
| 74 | return 'Fragment'; |
| 75 | case REACT_PROFILER_TYPE: |
| 76 | return 'Profiler'; |
| 77 | case REACT_STRICT_MODE_TYPE: |
| 78 | return 'StrictMode'; |
| 79 | case REACT_SUSPENSE_TYPE: |
| 80 | return 'Suspense'; |
| 81 | case REACT_SUSPENSE_LIST_TYPE: |
| 82 | return 'SuspenseList'; |
| 83 | case REACT_ACTIVITY_TYPE: |
| 84 | return 'Activity'; |
| 85 | case REACT_VIEW_TRANSITION_TYPE: |
| 86 | if (enableViewTransition) { |
| 87 | return 'ViewTransition'; |
| 88 | } |
| 89 | // Fall through |
| 90 | case REACT_TRACING_MARKER_TYPE: |
| 91 | if (enableTransitionTracing) { |
| 92 | return 'TracingMarker'; |
| 93 | } |
| 94 | } |
| 95 | if (typeof type === 'object') { |
| 96 | if (__DEV__) { |
| 97 | if (typeof (type as any).tag === 'number') { |
| 98 | console.error( |
| 99 | 'Received an unexpected object in getComponentNameFromType(). ' + |
| 100 | 'This is likely a bug in React. Please file an issue.', |
| 101 | ); |
| 102 | } |
| 103 | } |
| 104 | switch (type.$$typeof) { |
| 105 | case REACT_PORTAL_TYPE: |
| 106 | return 'Portal'; |
| 107 | case REACT_CONTEXT_TYPE: |
| 108 | const context: ReactContext<any> = type as any; |
| 109 | return getContextName(context); |
| 110 | case REACT_CONSUMER_TYPE: |
| 111 | const consumer: ReactConsumerType<any> = type as any; |
| 112 | return getContextName(consumer._context) + '.Consumer'; |
| 113 | case REACT_FORWARD_REF_TYPE: |
| 114 | return getWrappedName(type, type.render, 'ForwardRef'); |
| 115 | case REACT_MEMO_TYPE: |
| 116 | const outerName = (type as any).displayName || null; |
| 117 | if (outerName !== null) { |
| 118 | return outerName; |
| 119 | } |
| 120 | return getComponentNameFromType(type.type) || 'Memo'; |
| 121 | case REACT_LAZY_TYPE: { |
| 122 | const lazyComponent: LazyComponent<any, any> = type as any; |
| 123 | const payload = lazyComponent._payload; |
| 124 | const init = lazyComponent._init; |
| 125 | try { |
| 126 | return getComponentNameFromType(init(payload)); |
| 127 | } catch (x) { |
| 128 | return null; |
| 129 | } |
| 130 | } |
| 131 | } |
| 132 | } |
| 133 | return null; |
| 134 | } |