filename: getRelativeFileName()

in lib/stacktraces.js [134:348]


        filename: getRelativeFileName(filename, cwd),
        function: frame.getFunctionName(),
        lineno: frame.getLineNumber(),
        library_frame: !isStackFrameApp(frame),
        abs_path: filename,
      });
    }
  }

  return stacktrace;
}

const NODE_MODULES_PATH_SEG = 'node_modules' + path.sep;

// Return true iff the given StackFrame
// (https://github.com/stacktracejs/stackframe) is an application frame.
function isStackFrameApp(stackframe) {
  if (isStackFrameNode(stackframe)) {
    return false;
  } else {
    const fileName = filePathFromCallSite(stackframe);
    if (!fileName) {
      return true;
    } else if (fileName.indexOf(NODE_MODULES_PATH_SEG) === -1) {
      return true;
    } else {
      return false;
    }
  }
}

// Return true iff the given StackFrame
// (https://github.com/stacktracejs/stackframe) is a Node frame.
function isStackFrameNode(stackframe) {
  if (stackframe.isNative) {
    return true;
  } else {
    const fileName = filePathFromCallSite(stackframe);
    if (!fileName) {
      return true;
    } else {
      return !path.isAbsolute(fileName) && fileName[0] !== '.';
    }
  }
}

function isCallSiteApp(callsite) {
  if (isCallSiteNode(callsite)) {
    return false;
  } else {
    const fileName = filePathFromCallSite(callsite);
    if (!fileName) {
      return true;
    } else if (fileName.indexOf(NODE_MODULES_PATH_SEG) === -1) {
      return true;
    } else {
      return false;
    }
  }
}

function isCallSiteNode(callsite) {
  if (callsite.isNative()) {
    return true;
  } else {
    const fileName = filePathFromCallSite(callsite);
    if (!fileName) {
      return true;
    } else {
      return !path.isAbsolute(fileName) && fileName[0] !== '.';
    }
  }
}

function isValidCallsites(callsites) {
  return (
    Array.isArray(callsites) &&
    callsites.length > 0 &&
    typeof callsites[0] === 'object' &&
    typeof callsites[0].getFileName === 'function'
  );
}

// From stackman getTypeNameSafely().
function getCallSiteTypeNameSafely(callsite) {
  try {
    return callsite.getTypeName();
  } catch (e) {
    // This seems to happen sometimes when using 'use strict',
    // stemming from `getTypeName`.
    // [TypeError: Cannot read property 'constructor' of undefined]
    return null;
  }
}

// From stackman getFunctionNameSanitized().
function getCallSiteFunctionNameSanitized(callsite) {
  var fnName = callsite.getFunctionName();
  if (fnName) return fnName;
  var typeName = getCallSiteTypeNameSafely(callsite);
  if (typeName)
    return typeName + '.' + (callsite.getMethodName() || '<anonymous>');
  return '<anonymous>';
}

function addSourceContextToFrame(frame, lines, lineNum, n) {
  var index = lineNum - 1; // lines 1-based -> index 0-based
  var nBefore = Math.ceil((n - 1) / 2);
  var nAfter = Math.floor((n - 1) / 2);
  frame.pre_context = lines.slice(Math.max(0, index - nBefore), index);
  frame.context_line = lines[index];
  frame.post_context = lines.slice(index + 1, index + 1 + nAfter);
}

// Get the path of `filename` relative to `relTo` -- which should be a directory
// path *without* a trailing path separator.
function getRelativeFileName(filename, relTo) {
  if (filename.startsWith(relTo + path.sep)) {
    return filename.slice(relTo.length + 1);
  } else {
    return filename;
  }
}

async function getSourceMapConsumer(callsite) {
  if (isCallSiteNode(callsite)) {
    return null;
  } else {
    var filename = filePathFromCallSite(callsite);
    if (!filename) {
      return null;
    } else {
      return sourceMapCache.fetch(filename);
    }
  }
}

// Put together an APM stacktrace frame object:
//     {
//       "filename": "...",
//       "lineno": 65,
//       "function": "...",
//       "library_frame": <bool>,
//       "abs_path": "...",
//       "pre_context": [ ... ],
//       "context_line": "...",
//       "post_context": [ ... ],
//     },
// from a v8 CallSite object
// (https://v8.dev/docs/stack-trace-api#customizing-stack-traces).
//
// This asynchronously returns the call frame object. Getting source context
// is best-effort, so the returned Promise never rejects.
async function frameFromCallSite(
  log,
  callsite,
  cwd,
  sourceLinesAppFrames,
  sourceLinesLibraryFrames,
) {
  // getFileName can return null, e.g. with a `at Generator.next (<anonymous>)` frame.
  const filename = filePathFromCallSite(callsite) || '';
  const lineno = callsite.getLineNumber();
  const colno = callsite.getColumnNumber();

  // Caching
  const cacheKey = [
    filename,
    lineno,
    colno,
    sourceLinesAppFrames,
    sourceLinesLibraryFrames,
  ].join(':');
  const cachedFrame = frameCache.get(cacheKey);
  if (cachedFrame !== undefined) {
    frameCacheStats.hits++;

    // Guard against later JSON serialization mistakenly changing duplicate
    // frames in a stacktrace (a totally legal thing) into '[Circular]' as a
    // guard against serializing an object with circular references.
    const clonedFrame = Object.assign({}, cachedFrame);
    if (clonedFrame.pre_context) {
      clonedFrame.pre_context = clonedFrame.pre_context.slice();
    }
    if (clonedFrame.post_context) {
      clonedFrame.post_context = clonedFrame.post_context.slice();
    }

    return clonedFrame;
  }

  function cacheIt(frame) {
    frameCacheStats.misses++;
    frameCache.set(cacheKey, frame);
  }

  let mappedFilename = null;
  let absMappedFilename = null;
  let mappedLineno = null;

  // If the file has a sourcemap, we use that for: filename, lineno, source
  // context.
  let sourceMapConsumer = null;
  try {
    sourceMapConsumer = await getSourceMapConsumer(callsite);
  } catch (sourceMapErr) {
    log.debug(
      { filename, err: sourceMapErr },
      'could not process file source map',
    );
  }
  if (sourceMapConsumer) {
    let pos;
    try {
      pos = sourceMapConsumer.originalPositionFor({