import * as React from 'react';
import {use, useContext} from 'react';
import useOpenResource from '../useOpenResource';
import ElementBadges from './ElementBadges';
import styles from './StackTraceView.css';
import type {ReactStackTrace, ReactCallSite} from 'shared/ReactTypes';
import type {SourceMappedLocation} from 'react-devtools-shared/src/symbolicateSource';
import FetchFileWithCachingContext from './FetchFileWithCachingContext';
import {symbolicateSourceWithCache} from 'react-devtools-shared/src/symbolicateSource';
import formatLocationForDisplay from './formatLocationForDisplay';
type CallSiteViewProps = {
callSite: ReactCallSite,
environmentName: null | string,
};
export function CallSiteView({
callSite,
environmentName,
}: CallSiteViewProps): React.Node {
const fetchFileWithCaching = useContext(FetchFileWithCachingContext);
const [virtualFunctionName, virtualURL, virtualLine, virtualColumn] =
callSite;
const symbolicatedCallSite: null | SourceMappedLocation =
fetchFileWithCaching !== null
? use(
symbolicateSourceWithCache(
fetchFileWithCaching,
virtualURL,
virtualLine,
virtualColumn,
),
)
: null;
const [linkIsEnabled, viewSource] = useOpenResource(
callSite,
symbolicatedCallSite == null ? null : symbolicatedCallSite.location,
);
const [functionName, url, line, column] =
symbolicatedCallSite !== null ? symbolicatedCallSite.location : callSite;
const ignored =
symbolicatedCallSite !== null ? symbolicatedCallSite.ignored : false;
const isBuiltIn = url === '' || url.startsWith('<anonymous>');
return (
<div
className={
ignored
? styles.IgnoredCallSite
: isBuiltIn
? styles.BuiltInCallSite
: styles.CallSite
}>
{functionName || virtualFunctionName}
{!isBuiltIn && (
<>
{' @ '}
<span
className={linkIsEnabled ? styles.Link : null}
onClick={viewSource}
title={url + ':' + line}>
{formatLocationForDisplay(url, line, column)}
</span>
</>
)}
<ElementBadges
className={styles.ElementBadges}
environmentName={environmentName}
/>
</div>
);
}
type Props = {
stack: ReactStackTrace,
environmentName: null | string,
};
export default function StackTraceView({
stack,
environmentName,
}: Props): React.Node {
return (
<div className={styles.StackTraceView}>
{stack.map((callSite, index) => (
<CallSiteView
key={index}
callSite={callSite}
environmentName={
// Badge last row
// TODO: If we start ignore listing the last row, we should badge the last
// non-ignored row.
index === stack.length - 1 ? environmentName : null
}
/>
))}
</div>
);
}