RuntimeErrorStack.js 2.3 KB
const ErrorStackParser = require('error-stack-parser');
const theme = require('../theme.js');
const utils = require('../utils.js');

/**
 * @typedef {Object} RuntimeErrorStackProps
 * @property {Error} error
 */

/**
 * A formatter that turns runtime error stacks into highlighted HTML stacks.
 * @param {Document} document
 * @param {HTMLElement} root
 * @param {RuntimeErrorStackProps} props
 * @returns {void}
 */
function RuntimeErrorStack(document, root, props) {
  const stackTitle = document.createElement('h4');
  stackTitle.innerText = 'Call Stack';
  stackTitle.style.color = '#' + theme.white;
  stackTitle.style.fontSize = '1.0625rem';
  stackTitle.style.fontWeight = '500';
  stackTitle.style.lineHeight = '1.3';
  stackTitle.style.margin = '0 0 0.5rem';

  const stackContainer = document.createElement('div');
  stackContainer.style.fontSize = '0.8125rem';
  stackContainer.style.lineHeight = '1.3';
  stackContainer.style.whiteSpace = 'pre-wrap';

  let errorStacks;
  try {
    errorStacks = ErrorStackParser.parse(props.error);
  } catch (e) {
    errorStacks = [];
    stackContainer.innerHTML = 'No stack trace is available for this error!';
  }

  for (let i = 0; i < Math.min(errorStacks.length, 10); i += 1) {
    const currentStack = errorStacks[i];

    const functionName = document.createElement('code');
    functionName.innerHTML = '&emsp;' + currentStack.functionName || '(anonymous function)';
    functionName.style.color = '#' + theme.yellow;
    functionName.style.fontFamily = [
      '"Operator Mono SSm"',
      '"Operator Mono"',
      '"Fira Code Retina"',
      '"Fira Code"',
      '"FiraCode-Retina"',
      '"Andale Mono"',
      '"Lucida Console"',
      'Menlo',
      'Consolas',
      'Monaco',
      'monospace',
    ].join(', ');

    const fileName = document.createElement('div');
    fileName.innerHTML =
      '&emsp;&emsp;' +
      utils.formatFilename(currentStack.fileName) +
      ':' +
      currentStack.lineNumber +
      ':' +
      currentStack.columnNumber;
    fileName.style.color = '#' + theme.white;
    fileName.style.fontSize = '0.6875rem';
    fileName.style.marginBottom = '0.25rem';

    stackContainer.appendChild(functionName);
    stackContainer.appendChild(fileName);
  }

  root.appendChild(stackTitle);
  root.appendChild(stackContainer);
}

module.exports = RuntimeErrorStack;