1/** 2 * Copyright (c) 650 Industries. 3 * Copyright (c) Meta Platforms, Inc. and affiliates. 4 * 5 * This source code is licensed under the MIT license found in the 6 * LICENSE file in the root directory of this source tree. 7 */ 8 9import { StackFrame as UpstreamStackFrame } from 'stacktrace-parser'; 10 11import symbolicateStackTrace from '../modules/symbolicateStackTrace'; 12 13type SymbolicatedStackTrace = any; 14 15type StackFrame = UpstreamStackFrame & { collapse?: boolean }; 16 17export type Stack = StackFrame[]; 18 19const cache: Map<Stack, Promise<SymbolicatedStackTrace>> = new Map(); 20 21/** 22 * Sanitize because sometimes, `symbolicateStackTrace` gives us invalid values. 23 */ 24const sanitize = ({ 25 stack: maybeStack, 26 codeFrame, 27}: SymbolicatedStackTrace): SymbolicatedStackTrace => { 28 if (!Array.isArray(maybeStack)) { 29 throw new Error('Expected stack to be an array.'); 30 } 31 const stack: StackFrame[] = []; 32 for (const maybeFrame of maybeStack) { 33 let collapse = false; 34 if ('collapse' in maybeFrame) { 35 if (typeof maybeFrame.collapse !== 'boolean') { 36 throw new Error('Expected stack frame `collapse` to be a boolean.'); 37 } 38 collapse = maybeFrame.collapse; 39 } 40 stack.push({ 41 arguments: [], 42 column: maybeFrame.column, 43 file: maybeFrame.file, 44 lineNumber: maybeFrame.lineNumber, 45 methodName: maybeFrame.methodName, 46 collapse, 47 }); 48 } 49 return { stack, codeFrame }; 50}; 51 52export function deleteStack(stack: Stack): void { 53 cache.delete(stack); 54} 55 56export function symbolicate(stack: Stack): Promise<SymbolicatedStackTrace> { 57 let promise = cache.get(stack); 58 if (promise == null) { 59 promise = symbolicateStackTrace(stack).then(sanitize); 60 cache.set(stack, promise); 61 } 62 63 return promise; 64} 65