      const namePrefix = typeName !== null && typeName !== 'global' ? `${typeName}.` : '';
          const originalName = `${namePrefix}${fnName || '<anonymous>'}`;
          // The original call site may have a different symbol name
          // associated with it, use it:
          const prefix = (name && name !== originalName) ?
            `${name}` :
            `${originalName}`;
          const hasName = !!(name || originalName);
          const originalSourceNoScheme =
            StringPrototypeStartsWith(originalSource, 'file://') ?
              fileURLToPath(originalSource) : originalSource;
          // Replace the transpiled call site with the original:
          return `${str}${prefix}${hasName ? ' (' : ''}` +
            `${originalSourceNoScheme}:${originalLine + 1}:` +
            `${originalColumn + 1}${hasName ? ')' : ''}`;
        }
      }
    } catch (err) {
      debug(err);
    }
    return `${str}${t}`;
  }), '');
  return `${errorSource}${errorString}\n    at ${preparedTrace}`;
};

// Transpilers may have removed the original symbol name used in the stack
// trace, if possible restore it from the names field of the source map:
function getOriginalSymbolName(sourceMap, trace, curIndex) {
  // First check for a symbol name associated with the enclosing function:
  const enclosingEntry = sourceMap.findEntry(
    trace[curIndex].getEnclosingLineNumber() - 1,
    trace[curIndex].getEnclosingColumnNumber() - 1
  );
  if (enclosingEntry.name) return enclosingEntry.name;
  // Fallback to using the symbol name attached to the next stack frame:
  const currentFileName = trace[curIndex].getFileName();
  const nextCallSite = trace[curIndex + 1];
  if (nextCallSite && currentFileName === nextCallSite.getFileName()) {
    const { name } = sourceMap.findEntry(
      nextCallSite.getLineNumber() - 1,
      nextCallSite.getColumnNumber() - 1
    );
    return name;
  }
}

// Places a snippet of code from where the exception was originally thrown
// above the stack trace. This logic is modeled after GetErrorSource in
// node_errors.cc.
function getErrorSource(
  sourceMap,
  originalSourcePath,
  originalLine,
  originalColumn
) {
  let exceptionLine = '';
  const originalSourcePathNoScheme =
    StringPrototypeStartsWith(originalSourcePath, 'file://') ?
      fileURLToPath(originalSourcePath) : originalSourcePath;
  const source = getOriginalSource(
    sourceMap.payload,
    originalSourcePathNoScheme
  );
  const lines = StringPrototypeSplit(source, /\r?\n/, originalLine + 1);
  const line = lines[originalLine];
  if (!line) return exceptionLine;

  // Display ^ in appropriate position, regardless of whether tabs or
  // spaces are used:
  let prefix = '';
  for (const character of new SafeStringIterator(
    StringPrototypeSlice(line, 0, originalColumn + 1))) {
    prefix += character === '\t' ? '\t' :
      StringPrototypeRepeat(' ', getStringWidth(character));
  }
  prefix = StringPrototypeSlice(prefix, 0, -1); // The last character is '^'.

  exceptionLine =
   `${originalSourcePathNoScheme}:${originalLine + 1}\n${line}\n${prefix}^\n\n`;
  return exceptionLine;
}

function getOriginalSource(payload, originalSourcePath) {
  let source;
  const originalSourcePathNoScheme =
    StringPrototypeStartsWith(originalSourcePath, 'file://') ?
      fileURLToPath(originalSourcePath) : originalSourcePath;
  const sourceContentIndex =
    ArrayPrototypeIndexOf(payload.sources, originalSourcePath);
  if (payload.sourcesContent?.[sourceContentIndex]) {
    // First we check if the original source content was provided in the
    // source map itself:
    source = payload.sourcesContent[sourceContentIndex];
  } else {
    // If no sourcesContent was found, attempt to load the original source
    // from disk:
    try {
      source = readFileSync(originalSourcePathNoScheme, 'utf8');
    } catch (err) {
      debug(err);
      source = '';
    }
  }
  return source;
}

module.exports = {
  prepareStackTrace,
};
