import {REACT_LAZY_TYPE} from 'shared/ReactSymbols';
import {
callLazyInitInDEV,
callComponentInDEV,
callRenderInDEV,
} from './ReactFiberCallUserSpace';
const externalRegExp = /\/node\_modules\/|\(\<anonymous\>\)/;
let callComponentFrame: null | string = null;
let callIteratorFrame: null | string = null;
let callLazyInitFrame: null | string = null;
function isNotExternal(stackFrame: string): boolean {
return !externalRegExp.test(stackFrame);
}
function initCallComponentFrame(): string {
const error = callComponentInDEV(Error, 'react-stack-top-frame', {});
const stack = error.stack;
const startIdx = stack.startsWith('Error: react-stack-top-frame\n') ? 29 : 0;
const endIdx = stack.indexOf('\n', startIdx);
if (endIdx === -1) {
return stack.slice(startIdx);
}
return stack.slice(startIdx, endIdx);
}
function initCallRenderFrame(): string {
try {
(callRenderInDEV: any)({render: null});
return '';
} catch (error) {
const stack = error.stack;
const startIdx = stack.startsWith('TypeError: ')
? stack.indexOf('\n') + 1
: 0;
const endIdx = stack.indexOf('\n', startIdx);
if (endIdx === -1) {
return stack.slice(startIdx);
}
return stack.slice(startIdx, endIdx);
}
}
function initCallLazyInitFrame(): string {
const error = callLazyInitInDEV({
$$typeof: REACT_LAZY_TYPE,
_init: Error,
_payload: 'react-stack-top-frame',
});
const stack = error.stack;
const startIdx = stack.startsWith('Error: react-stack-top-frame\n') ? 29 : 0;
const endIdx = stack.indexOf('\n', startIdx);
if (endIdx === -1) {
return stack.slice(startIdx);
}
return stack.slice(startIdx, endIdx);
}
function filterDebugStack(error: Error): string {
let stack = error.stack;
if (stack.startsWith('Error: react-stack-top-frame\n')) {
stack = stack.slice(29);
}
const frames = stack.split('\n').slice(1);
if (callComponentFrame === null) {
callComponentFrame = initCallComponentFrame();
}
let lastFrameIdx = frames.indexOf(callComponentFrame);
if (lastFrameIdx === -1) {
if (callLazyInitFrame === null) {
callLazyInitFrame = initCallLazyInitFrame();
}
lastFrameIdx = frames.indexOf(callLazyInitFrame);
if (lastFrameIdx === -1) {
if (callIteratorFrame === null) {
callIteratorFrame = initCallRenderFrame();
}
lastFrameIdx = frames.indexOf(callIteratorFrame);
}
}
if (lastFrameIdx !== -1) {
frames.length = lastFrameIdx;
} else {
return '';
}
return frames.filter(isNotExternal).join('\n');
}
export function formatOwnerStack(ownerStackTrace: Error): string {
return filterDebugStack(ownerStackTrace);
}