main
js 78 lines 3 KB
Raw
1 import {use, useContext, useDeferredValue} from 'react';
2
3 import type {ReactCallSite} from 'shared/ReactTypes';
4
5 import type {SourceMappedLocation} from 'react-devtools-shared/src/symbolicateSource';
6
7 import type {SerializedAsyncInfo} from 'react-devtools-shared/src/frontend/types';
8
9 import FetchFileWithCachingContext from './Components/FetchFileWithCachingContext';
10
11 import {symbolicateSourceWithCache} from 'react-devtools-shared/src/symbolicateSource';
12
13 export default function useInferredName(
14 asyncInfo: SerializedAsyncInfo,
15 ): string {
16 const fetchFileWithCaching = useContext(FetchFileWithCachingContext);
17 const name = asyncInfo.awaited.name;
18 let inferNameFromStack = null;
19 if (!name || name === 'Promise' || name === 'lazy') {
20 // If all we have is a generic name, we can try to infer a better name from
21 // the stack. We only do this if the stack has more than one frame since
22 // otherwise it's likely to just be the name of the component which isn't better.
23 const bestStack = asyncInfo.awaited.stack || asyncInfo.stack;
24 if (bestStack !== null && bestStack.length > 1) {
25 inferNameFromStack = bestStack;
26 }
27 }
28 // Start by not source mapping and just taking the first name and upgrade to
29 // the better name asynchronously if we find one. Most of the time it'll just be
30 // the top of the stack.
31 const shouldSourceMap = useDeferredValue(inferNameFromStack !== null, false);
32 if (inferNameFromStack !== null) {
33 if (shouldSourceMap) {
34 let bestMatch = '';
35 for (let i = 0; i < inferNameFromStack.length; i++) {
36 const callSite: ReactCallSite = inferNameFromStack[i];
37 const [virtualFunctionName, virtualURL, virtualLine, virtualColumn] =
38 callSite;
39 const symbolicatedCallSite: null | SourceMappedLocation =
40 fetchFileWithCaching !== null
41 ? use(
42 symbolicateSourceWithCache(
43 fetchFileWithCaching,
44 virtualURL,
45 virtualLine,
46 virtualColumn,
47 ),
48 )
49 : null;
50 if (symbolicatedCallSite === null) {
51 // If we can't source map, we treat it as first party code. We called whatever was
52 // the previous callsite.
53 if (bestMatch === '') {
54 return virtualFunctionName || name;
55 } else {
56 return bestMatch;
57 }
58 } else if (!symbolicatedCallSite.ignored) {
59 if (bestMatch === '') {
60 // If we had no good stack frames for internal calls, just use the last
61 // first party function name.
62 return symbolicatedCallSite[0] || virtualFunctionName || name;
63 } else {
64 return bestMatch;
65 }
66 } else {
67 // This line was ignore listed, it might be the one we called into from first party.
68 bestMatch = symbolicatedCallSite[0] || virtualFunctionName;
69 }
70 }
71 return name;
72 } else {
73 return inferNameFromStack[0][0];
74 }
75 } else {
76 return name;
77 }
78 }