{"version":3,"file":"computeStackTrace.mjs","names":[],"sources":["../../../src/tools/stackTrace/computeStackTrace.ts"],"sourcesContent":["/**\n * Cross-browser stack trace computation.\n *\n * Reference implementation: https://github.com/csnover/TraceKit/blob/04530298073c3823de72deb0b97e7b38ca7bcb59/tracekit.js\n */\n\nimport { isIndexableObject } from '@openobserve/js-core/util'\n\nexport interface StackFrame {\n  url?: string\n  func?: string\n  /** The arguments passed to the function, if known. */\n  args?: string[]\n  line?: number\n  column?: number\n  /** An array of source code lines; the middle element corresponds to the correct line. */\n  context?: string[]\n}\n\nexport interface StackTrace {\n  name?: string\n  message?: string\n  url?: string\n  stack: StackFrame[]\n  incomplete?: boolean\n  partial?: boolean\n}\n\nconst UNKNOWN_FUNCTION = '?'\n\nexport function computeStackTrace(ex: unknown): StackTrace {\n  const stack: StackFrame[] = []\n\n  let stackProperty = tryToGetString(ex, 'stack')\n  const exString = String(ex)\n  if (stackProperty?.startsWith(exString)) {\n    stackProperty = stackProperty.slice(exString.length)\n  }\n  if (stackProperty) {\n    stackProperty.split('\\n').forEach((line) => {\n      const stackFrame =\n        parseChromeLine(line) || parseChromeAnonymousLine(line) || parseWinLine(line) || parseGeckoLine(line)\n      if (stackFrame) {\n        if (!stackFrame.func && stackFrame.line) {\n          stackFrame.func = UNKNOWN_FUNCTION\n        }\n\n        stack.push(stackFrame)\n      }\n    })\n  }\n\n  if (stack.length > 0 && isWronglyReportingCustomErrors() && ex instanceof Error) {\n    // if we are wrongly reporting custom errors\n    const constructors: string[] = []\n\n    // go through each inherited constructor\n    let currentPrototype: object | undefined = ex\n    while (\n      (currentPrototype = Object.getPrototypeOf(currentPrototype)) &&\n      isNonNativeClassPrototype(currentPrototype)\n    ) {\n      const constructorName = currentPrototype.constructor?.name || UNKNOWN_FUNCTION\n      constructors.push(constructorName)\n    }\n\n    // traverse the stacktrace in reverse order because the stacktrace starts with the last inherited constructor\n    // we check constructor names to ensure we remove the correct frame (and there isn't a weird unsupported environment behavior)\n    for (let i = constructors.length - 1; i >= 0 && stack[0]?.func === constructors[i]; i--) {\n      // if the first stack frame is the custom error constructor\n      // null stack frames may represent frames that failed to be parsed because the error class did not have a constructor\n      stack.shift() // remove it\n    }\n  }\n\n  return {\n    message: tryToGetString(ex, 'message'),\n    name: tryToGetString(ex, 'name'),\n    stack,\n  }\n}\nconst fileUrl =\n  '((?:file|https?|blob|chrome-extension|electron|native|eval|webpack|snippet|<anonymous>|\\\\w+\\\\.|\\\\/).*?)'\nconst filePosition = '(?::(\\\\d+))'\nconst CHROME_LINE_RE = new RegExp(`^\\\\s*at (.*?) ?\\\\(${fileUrl}${filePosition}?${filePosition}?\\\\)?\\\\s*$`, 'i')\n\nconst CHROME_EVAL_RE = new RegExp(`\\\\((\\\\S*)${filePosition}${filePosition}\\\\)`)\n\nfunction parseChromeLine(line: string): StackFrame | undefined {\n  const parts = CHROME_LINE_RE.exec(line)\n\n  if (!parts) {\n    return\n  }\n\n  const isNative = parts[2]?.indexOf('native') === 0 // start of line\n  const isEval = parts[2]?.indexOf('eval') === 0 // start of line\n  const submatch = CHROME_EVAL_RE.exec(parts[2])\n\n  if (isEval && submatch) {\n    // throw out eval line/column and use top-most line/column number\n    parts[2] = submatch[1] // url\n    parts[3] = submatch[2] // line\n    parts[4] = submatch[3] // column\n  }\n\n  return {\n    args: isNative ? [parts[2]] : [],\n    column: parts[4] ? +parts[4] : undefined,\n    func: parts[1] || UNKNOWN_FUNCTION,\n    line: parts[3] ? +parts[3] : undefined,\n    url: !isNative ? parts[2] : undefined,\n  }\n}\n\nconst htmlAnonymousPart = '(?:(.*)?(?: @))'\nconst CHROME_ANONYMOUS_FUNCTION_RE = new RegExp(\n  `^\\\\s*at\\\\s*${htmlAnonymousPart}?\\\\s*${fileUrl}${filePosition}?${filePosition}??\\\\s*$`,\n  'i'\n)\n\nfunction parseChromeAnonymousLine(line: string): StackFrame | undefined {\n  const parts = CHROME_ANONYMOUS_FUNCTION_RE.exec(line)\n\n  if (!parts) {\n    return\n  }\n\n  return {\n    args: [],\n    column: parts[4] ? +parts[4] : undefined,\n    func: parts[1] || UNKNOWN_FUNCTION,\n    line: parts[3] ? +parts[3] : undefined,\n    url: parts[2],\n  }\n}\n\nconst WINJS_LINE_RE =\n  /^\\s*at (?:((?:\\[object object\\])?.+) )?\\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\\d+)(?::(\\d+))?\\)?\\s*$/i\n\nfunction parseWinLine(line: string): StackFrame | undefined {\n  const parts = WINJS_LINE_RE.exec(line)\n  if (!parts) {\n    return\n  }\n\n  return {\n    args: [],\n    column: parts[4] ? +parts[4] : undefined,\n    func: parts[1] || UNKNOWN_FUNCTION,\n    line: +parts[3],\n    url: parts[2],\n  }\n}\n\nconst GECKO_LINE_RE =\n  /^\\s*(.*?)(?:\\((.*?)\\))?(?:(?:(?:^|@)((?:file|https?|blob|chrome|webpack|resource|capacitor|\\[native).*?|[^@]*bundle|\\[wasm code\\])(?::(\\d+))?(?::(\\d+))?)|@)\\s*$/i\nconst GECKO_EVAL_RE = /(\\S+) line (\\d+)(?: > eval line \\d+)* > eval/i\n\nfunction parseGeckoLine(line: string): StackFrame | undefined {\n  const parts = GECKO_LINE_RE.exec(line)\n  if (!parts) {\n    return\n  }\n\n  const isEval = parts[3] && parts[3].indexOf(' > eval') > -1\n  const submatch = GECKO_EVAL_RE.exec(parts[3])\n\n  if (isEval && submatch) {\n    // throw out eval line/column and use top-most line number\n    parts[3] = submatch[1]\n    parts[4] = submatch[2]\n    parts[5] = undefined! // no column when eval\n  }\n\n  return {\n    args: parts[2] ? parts[2].split(',') : [],\n    column: parts[5] ? +parts[5] : undefined,\n    func: parts[1] || UNKNOWN_FUNCTION,\n    line: parts[4] ? +parts[4] : undefined,\n    url: parts[3],\n  }\n}\n\nfunction tryToGetString(candidate: unknown, property: string) {\n  return isIndexableObject(candidate) && typeof candidate[property] === 'string' ? candidate[property] : undefined\n}\n\nexport function computeStackTraceFromOnErrorMessage(\n  messageObj: unknown,\n  url?: string,\n  line?: number,\n  column?: number\n): StackTrace | undefined {\n  if (url === undefined) {\n    return\n  }\n  const { name, message } = tryToParseMessage(messageObj)\n  return {\n    name,\n    message,\n    stack: [{ url, column, line }],\n  }\n}\n\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types\nconst ERROR_TYPES_RE =\n  /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?([\\s\\S]*)$/\n\nfunction tryToParseMessage(messageObj: unknown) {\n  let name\n  let message\n  if ({}.toString.call(messageObj) === '[object String]') {\n    ;[, name, message] = ERROR_TYPES_RE.exec(messageObj as string)!\n  }\n  return { name, message }\n}\n\n// Custom error stacktrace fix\n// Some browsers (safari/firefox) add the error constructor as a frame in the stacktrace\n// In order to normalize the stacktrace, we need to remove it\n\nfunction isNonNativeClassPrototype(prototype: object) {\n  return String(prototype.constructor).startsWith('class ')\n}\n\nlet isWronglyReportingCustomErrorsCache: boolean | undefined\n\nfunction isWronglyReportingCustomErrors() {\n  if (isWronglyReportingCustomErrorsCache !== undefined) {\n    return isWronglyReportingCustomErrorsCache\n  }\n\n  /* eslint-disable no-restricted-syntax */\n  class DatadogTestCustomError extends Error {\n    constructor() {\n      super()\n      this.name = 'Error' // set name to Error so that no browser would default to the constructor name\n    }\n  }\n\n  const [customError, nativeError] = [DatadogTestCustomError, Error].map((errConstructor) => new errConstructor()) // so that both errors should exactly have the same stacktrace\n\n  isWronglyReportingCustomErrorsCache =\n    // If customError is not a class, it means that this was built with ES5 as target, converting the class to a normal object.\n    // Thus, error constructors will be reported on all browsers, which is the expected behavior.\n    isNonNativeClassPrototype(Object.getPrototypeOf(customError)) &&\n    // If the browser is correctly reporting the stacktrace, the normal error stacktrace should be the same as the custom error stacktrace\n    nativeError.stack !== customError.stack\n\n  return isWronglyReportingCustomErrorsCache\n}\n"],"mappings":"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"}