text: /**
   * Copyright (c) 2015-present, Facebook, Inc.
   * All rights reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree. An additional grant
   * of patent rights can be found in the PATENTS file in the same directory.
   */
  
  /* @flow */
  import { enableTabClick } from '../utils/dom/enableTabClick';
  import { createCode } from './code';
  import { isInternalFile } from '../utils/isInternalFile';
  import type { StackFrame } from '../utils/stack-frame';
  import type { FrameSetting, OmitsObject } from './frames';
  import { applyStyles } from '../utils/dom/css';
  import {
    omittedFramesExpandedStyle,
    omittedFramesCollapsedStyle,
    functionNameStyle,
    depStyle,
    linkStyle,
    anchorStyle,
    hiddenStyle,
  } from '../styles';
  import { getCompiledModuleByPath } from '../../eval/js/index';
  import actions, { dispatch } from '../../actions';
  
  function getGroupToggle(
    document: Document,
    omitsCount: number,
    omitBundle: number,
  ) {
    const omittedFrames = document.createElement('div');
    enableTabClick(omittedFrames);
    const text1 = document.createTextNode(
      '\u25B6 ' + omitsCount + ' stack frames were collapsed.',
    );
    omittedFrames.appendChild(text1);
    omittedFrames.addEventListener('click', function() {
      const hide = text1.textContent.match(/▲/);
      const list = document.getElementsByName('bundle-' + omitBundle);
      for (let index = 0; index < list.length; ++index) {
        const n = list[index];
        if (hide) {
          n.style.display = 'none';
        } else {
          n.style.display = '';
        }
      }
      if (hide) {
        text1.textContent = text1.textContent.replace(/▲/, '▶');
        text1.textContent = text1.textContent.replace(/expanded/, 'collapsed');
        applyStyles(omittedFrames, omittedFramesCollapsedStyle);
      } else {
        text1.textContent = text1.textContent.replace(/▶/, '▲');
        text1.textContent = text1.textContent.replace(/collapsed/, 'expanded');
        applyStyles(omittedFrames, omittedFramesExpandedStyle);
      }
    });
    applyStyles(omittedFrames, omittedFramesCollapsedStyle);
    return omittedFrames;
  }
  
  function insertBeforeBundle(
    document: Document,
    parent: Node,
    omitsCount: number,
    omitBundle: number,
    actionElement,
  ) {
    const children = document.getElementsByName('bundle-' + omitBundle);
    if (children.length < 1) {
      return;
    }
    let first: ?Node = children[0];
    while (first != null && first.parentNode !== parent) {
      first = first.parentNode;
    }
    const div = document.createElement('div');
    enableTabClick(div);
    div.setAttribute('name', 'bundle-' + omitBundle);
    const text = document.createTextNode(
      '\u25BC ' + omitsCount + ' stack frames were expanded.',
    );
    div.appendChild(text);
    div.addEventListener('click', function() {
      return actionElement.click();
    });
    applyStyles(div, omittedFramesExpandedStyle);
    div.style.display = 'none';
  
    parent.insertBefore(div, first);
  }
  
  function frameDiv(
    document: Document,
    functionName,
    url,
    internalUrl,
    onSourceClick: ?Function,
  ) {
    const frame = document.createElement('div');
    const frameFunctionName = document.createElement('div');
  
    let cleanedFunctionName;
    if (!functionName || functionName === 'Object.<anonymous>') {
      cleanedFunctionName = '(anonymous function)';
    } else {
      cleanedFunctionName = functionName;
    }
  
    const cleanedUrl = url.replace('webpack://', '.');
  
    if (internalUrl) {
      applyStyles(
        frameFunctionName,
        Object.assign({}, functionNameStyle, depStyle),
      );
    } else {
      applyStyles(frameFunctionName, functionNameStyle);
    }
  
    frameFunctionName.appendChild(document.createTextNode(cleanedFunctionName));
    frame.appendChild(frameFunctionName);
  
    const frameLink = document.createElement('div');
    applyStyles(frameLink, linkStyle);
    const frameAnchor = document.createElement('a');
    applyStyles(frameAnchor, anchorStyle);
    frameAnchor.appendChild(document.createTextNode(cleanedUrl));
    frameLink.appendChild(frameAnchor);
    frame.appendChild(frameLink);
  
    if (typeof onSourceClick === 'function') {
      let handler = onSourceClick;
      enableTabClick(frameAnchor);
      frameAnchor.style.cursor = 'pointer';
      frameAnchor.addEventListener('click', function() {
        handler();
      });
    }
  
    return frame;
  }
  
  function isBultinErrorName(errorName: ?string) {
    switch (errorName) {
      case 'EvalError':
      case 'InternalError':
      case 'RangeError':
      case 'ReferenceError':
      case 'SyntaxError':
      case 'TypeError':
      case 'URIError':
        return true;
      default:
        return false;
    }
  }
  
  function getPrettyURL(
    sourceFileName: ?string,
    sourceLineNumber: ?number,
    sourceColumnNumber: ?number,
    fileName: ?string,
    lineNumber: ?number,
    columnNumber: ?number,
    compiled: boolean,
  ): string {
    let prettyURL;
    if (!compiled && sourceFileName && typeof sourceLineNumber === 'number') {
      // Remove everything up to the first /src/ or /node_modules/
      const trimMatch = /^[/|\\].*?[/|\\]((src|node_modules)[/|\\].*)/.exec(
        sourceFileName,
      );
      if (trimMatch && trimMatch[1]) {
        prettyURL = trimMatch[1];
      } else {
        prettyURL = sourceFileName;
      }
      prettyURL += ':' + sourceLineNumber;
      // Note: we intentionally skip 0's because they're produced by cheap Webpack maps
      if (sourceColumnNumber) {
        prettyURL += ':' + sourceColumnNumber;
      }
    } else if (fileName && typeof lineNumber === 'number') {
      prettyURL = fileName + ':' + lineNumber;
      // Note: we intentionally skip 0's because they're produced by cheap Webpack maps
      if (columnNumber) {
        prettyURL += ':' + columnNumber;
      }
    } else {
      prettyURL = 'unknown';
    }
    return prettyURL;
  }
  
  function createFrame(
    document: Document,
    frameSetting: FrameSetting,
    frame: StackFrame,
    contextSize: number,
    critical: boolean,
    omits: OmitsObject,
    omitBundle: number,
    parentContainer: HTMLDivElement,
    lastElement: boolean,
    errorName: ?string,
  ) {
    const { compiled } = frameSetting;
    let { functionName, _originalFileName: sourceFileName } = frame;
    const {
      fileName,
      lineNumber,
      columnNumber,
      _scriptCode: scriptLines,
      _originalLineNumber: sourceLineNumber,
      _originalColumnNumber: sourceColumnNumber,
      _originalScriptCode: sourceLines,
    } = frame;
  
    // TODO: find a better place for this.
    // Chrome has a bug with inferring function.name:
    // https://github.com/facebookincubator/create-react-app/issues/2097
    // Let's ignore a meaningless name we get for top-level modules.
    if (
      functionName === 'Object.friendlySyntaxErrorLabel' ||
      functionName === 'Object.exports.__esModule'
    ) {
      functionName = '(anonymous function)';
    }
  
    const prettyURL = getPrettyURL(
      sourceFileName,
      sourceLineNumber,
      sourceColumnNumber,
      fileName,
      lineNumber,
      columnNumber,
      compiled,
    );
  
    let needsHidden = false;
    const isInternalUrl = isInternalFile(sourceFileName, fileName);
    const isThrownIntentionally = !isBultinErrorName(errorName);
    const shouldCollapse =
      isInternalUrl && (isThrownIntentionally || omits.hasReachedAppCode);
  
    if (!isInternalUrl) {
      omits.hasReachedAppCode = true;
    }
  
    if (shouldCollapse) {
      ++omits.value;
      needsHidden = true;
    }
  
    let collapseElement = null;
    if (!shouldCollapse || lastElement) {
      if (omits.value > 0) {
        const capV = omits.value;
        const omittedFrames = getGroupToggle(document, capV, omitBundle);
        window.requestAnimationFrame(() => {
          insertBeforeBundle(
            document,
            parentContainer,
            capV,
            omitBundle,
            omittedFrames,
          );
        });
        if (lastElement && shouldCollapse) {
          collapseElement = omittedFrames;
        } else {
          parentContainer.appendChild(omittedFrames);
        }
        ++omits.bundle;
      }
      omits.value = 0;
    }
  
    let onSourceClick = null;
    if (sourceFileName) {
      // e.g. "/path-to-my-app/webpack/bootstrap eaddeb46b67d75e4dfc1"
      const isInternalWebpackBootstrapCode =
        sourceFileName.trim().indexOf(' ') !== -1;
      if (!isInternalWebpackBootstrapCode) {
        onSourceClick = () => {
          // OKAY IK BEN EEN KOEKE
          const module = getCompiledModuleByPath(sourceFileName);
  
          dispatch(
            actions.editor.openModule(
              module.id,
              window.encodeURIComponent(sourceLineNumber || 1),
            ),
          );
        };
      }
    }
  
    const elem = frameDiv(
      document,
      functionName,
      prettyURL,
      shouldCollapse,
      onSourceClick,
    );
    if (needsHidden) {
      applyStyles(elem, hiddenStyle);
      elem.setAttribute('name', 'bundle-' + omitBundle);
    }
  
    let hasSource = false;
    if (!shouldCollapse) {
      if (
        compiled &&
        scriptLines &&
        scriptLines.length !== 0 &&
        lineNumber != null
      ) {
        elem.appendChild(
          createCode(
            document,
            scriptLines,
            lineNumber,
            columnNumber,
            contextSize,
            critical,
            onSourceClick,
          ),
        );
        hasSource = true;
      } else if (
        !compiled &&
        sourceLines &&
        sourceLines.length !== 0 &&
        sourceLineNumber != null
      ) {
        elem.appendChild(
          createCode(
            document,
            sourceLines,
            sourceLineNumber,
            sourceColumnNumber,
            contextSize,
            critical,
            onSourceClick,
          ),
        );
        hasSource = true;
      }
    }
  
    return { elem: elem, hasSource: hasSource, collapseElement: collapseElement };
  }
  
  export { createFrame };
  