mirror of
https://github.com/zhigang1992/create-react-app.git
synced 2026-01-13 09:00:30 +08:00
1166 lines
27 KiB
JavaScript
1166 lines
27 KiB
JavaScript
/**
|
||
* 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.
|
||
*/
|
||
|
||
'use strict';
|
||
|
||
var stackFrameParser = require('stack-frame-parser');
|
||
var stackFrameMapper = require('stack-frame-mapper');
|
||
var stackFrameUnmapper = require('stack-frame-unmapper');
|
||
var codeFrame = require('babel-code-frame');
|
||
var ansiHTML = require('./ansiHTML');
|
||
|
||
var boundErrorHandler = null;
|
||
|
||
function errorHandler(callback, e) {
|
||
if (!e.error) {
|
||
return;
|
||
}
|
||
// $FlowFixMe
|
||
var error = e.error;
|
||
|
||
if (error instanceof Error) {
|
||
callback(error);
|
||
} else {
|
||
// A non-error was thrown, we don't have a trace. :(
|
||
// Look in your browser's devtools for more information
|
||
callback(new Error(error));
|
||
}
|
||
}
|
||
|
||
function registerUnhandledError(target, callback) {
|
||
if (boundErrorHandler !== null) {
|
||
return;
|
||
}
|
||
boundErrorHandler = errorHandler.bind(undefined, callback);
|
||
target.addEventListener('error', boundErrorHandler);
|
||
}
|
||
|
||
function unregisterUnhandledError(target) {
|
||
if (boundErrorHandler === null) {
|
||
return;
|
||
}
|
||
target.removeEventListener('error', boundErrorHandler);
|
||
boundErrorHandler = null;
|
||
}
|
||
|
||
var boundRejectionHandler = null;
|
||
|
||
function rejectionHandler(callback, e) {
|
||
if (e == null || e.reason == null) {
|
||
return callback(new Error('Unknown'));
|
||
}
|
||
var reason = e.reason;
|
||
|
||
if (reason instanceof Error) {
|
||
return callback(reason);
|
||
}
|
||
// A non-error was rejected, we don't have a trace :(
|
||
// Look in your browser's devtools for more information
|
||
return callback(new Error(reason));
|
||
}
|
||
|
||
function registerUnhandledRejection(target, callback) {
|
||
if (boundRejectionHandler !== null) {
|
||
return;
|
||
}
|
||
boundRejectionHandler = rejectionHandler.bind(undefined, callback);
|
||
// $FlowFixMe
|
||
target.addEventListener('unhandledrejection', boundRejectionHandler);
|
||
}
|
||
|
||
function unregisterUnhandledRejection(target) {
|
||
if (boundRejectionHandler === null) {
|
||
return;
|
||
}
|
||
// $FlowFixMe
|
||
target.removeEventListener('unhandledrejection', boundRejectionHandler);
|
||
boundRejectionHandler = null;
|
||
}
|
||
|
||
var SHORTCUT_ESCAPE = 'SHORTCUT_ESCAPE';
|
||
var SHORTCUT_LEFT = 'SHORTCUT_LEFT';
|
||
var SHORTCUT_RIGHT = 'SHORTCUT_RIGHT';
|
||
|
||
var boundKeyHandler = null;
|
||
|
||
function keyHandler(callback, e) {
|
||
var key = e.key, keyCode = e.keyCode, which = e.which;
|
||
|
||
if (key === 'Escape' || keyCode === 27 || which === 27) {
|
||
callback(SHORTCUT_ESCAPE);
|
||
} else if (key === 'ArrowLeft' || keyCode === 37 || which === 37) {
|
||
callback(SHORTCUT_LEFT);
|
||
} else if (key === 'ArrowRight' || keyCode === 39 || which === 39) {
|
||
callback(SHORTCUT_RIGHT);
|
||
}
|
||
}
|
||
|
||
function registerShortcuts(target, callback) {
|
||
if (boundKeyHandler !== null) {
|
||
return;
|
||
}
|
||
boundKeyHandler = keyHandler.bind(undefined, callback);
|
||
target.addEventListener('keydown', boundKeyHandler);
|
||
}
|
||
|
||
function unregisterShortcuts(target) {
|
||
if (boundKeyHandler === null) {
|
||
return;
|
||
}
|
||
target.removeEventListener('keydown', boundKeyHandler);
|
||
boundKeyHandler = null;
|
||
}
|
||
|
||
var stackTraceRegistered = false;
|
||
// Default: https://docs.microsoft.com/en-us/scripting/javascript/reference/stacktracelimit-property-error-javascript
|
||
var restoreStackTraceValue = 10;
|
||
|
||
var MAX_STACK_LENGTH = 50;
|
||
|
||
function registerStackTraceLimit() {
|
||
var limit = arguments.length > 0 && arguments[0] !== undefined
|
||
? arguments[0]
|
||
: MAX_STACK_LENGTH;
|
||
|
||
if (stackTraceRegistered) {
|
||
return;
|
||
}
|
||
try {
|
||
restoreStackTraceValue = Error.stackTraceLimit;
|
||
Error.stackTraceLimit = limit;
|
||
stackTraceRegistered = true;
|
||
} catch (e) {
|
||
// Not all browsers support this so we don't care if it errors
|
||
}
|
||
}
|
||
|
||
function unregisterStackTraceLimit() {
|
||
if (!stackTraceRegistered) {
|
||
return;
|
||
}
|
||
try {
|
||
Error.stackTraceLimit = restoreStackTraceValue;
|
||
stackTraceRegistered = false;
|
||
} catch (e) {
|
||
// Not all browsers support this so we don't care if it errors
|
||
}
|
||
}
|
||
|
||
var recorded = [];
|
||
var errorsConsumed = 0;
|
||
|
||
function consume(error) {
|
||
var unhandledRejection = arguments.length > 1 && arguments[1] !== undefined
|
||
? arguments[1]
|
||
: false;
|
||
var contextSize = arguments.length > 2 && arguments[2] !== undefined
|
||
? arguments[2]
|
||
: 3;
|
||
|
||
var parsedFrames = stackFrameParser.parse(error);
|
||
var enhancedFramesPromise = void 0;
|
||
if (error.__unmap_source) {
|
||
enhancedFramesPromise = stackFrameUnmapper.unmap(
|
||
error.__unmap_source,
|
||
parsedFrames,
|
||
contextSize
|
||
);
|
||
} else {
|
||
enhancedFramesPromise = stackFrameMapper.map(parsedFrames, contextSize);
|
||
}
|
||
return enhancedFramesPromise.then(function(enhancedFrames) {
|
||
enhancedFrames = enhancedFrames.filter(function(_ref) {
|
||
var functionName = _ref.functionName;
|
||
return functionName == null ||
|
||
functionName.indexOf('__stack_frame_overlay_proxy_console__') === -1;
|
||
});
|
||
recorded[++errorsConsumed] = {
|
||
error: error,
|
||
unhandledRejection: unhandledRejection,
|
||
contextSize: contextSize,
|
||
enhancedFrames: enhancedFrames,
|
||
};
|
||
return errorsConsumed;
|
||
});
|
||
}
|
||
|
||
function getErrorRecord(ref) {
|
||
return recorded[ref];
|
||
}
|
||
|
||
function drain() {
|
||
// $FlowFixMe
|
||
var keys = Object.keys(recorded);
|
||
for (var index = 0; index < keys.length; ++index) {
|
||
delete recorded[keys[index]];
|
||
}
|
||
}
|
||
|
||
var black = '#293238';
|
||
var darkGray = '#878e91';
|
||
var lightGray = '#fafafa';
|
||
var red = '#ce1126';
|
||
var lightRed = '#fccfcf';
|
||
var yellow = '#fbf5b4';
|
||
|
||
var iframeStyle = {
|
||
'background-color': lightGray,
|
||
position: 'fixed',
|
||
top: '1em',
|
||
left: '1em',
|
||
bottom: '1em',
|
||
right: '1em',
|
||
width: 'calc(100% - 2em)',
|
||
height: 'calc(100% - 2em)',
|
||
border: 'none',
|
||
'border-radius': '3px',
|
||
'box-shadow': '0 0 6px 0 rgba(0, 0, 0, 0.5)',
|
||
'z-index': 1337,
|
||
};
|
||
|
||
var overlayStyle = {
|
||
'box-sizing': 'border-box',
|
||
padding: '4rem',
|
||
'font-family': 'Consolas, Menlo, monospace',
|
||
color: black,
|
||
'white-space': 'pre-wrap',
|
||
overflow: 'auto',
|
||
'overflow-x': 'hidden',
|
||
'word-break': 'break-word',
|
||
'line-height': 1.5,
|
||
};
|
||
|
||
var hintsStyle = {
|
||
'font-size': '0.8em',
|
||
'margin-top': '-3em',
|
||
'margin-bottom': '3em',
|
||
'text-align': 'right',
|
||
color: darkGray,
|
||
};
|
||
|
||
var hintStyle = {
|
||
padding: '0.5em 1em',
|
||
cursor: 'pointer',
|
||
};
|
||
|
||
var closeButtonStyle = {
|
||
'font-size': '26px',
|
||
color: black,
|
||
padding: '0.5em 1em',
|
||
cursor: 'pointer',
|
||
position: 'absolute',
|
||
right: 0,
|
||
top: 0,
|
||
};
|
||
|
||
var additionalStyle = {
|
||
'margin-bottom': '1.5em',
|
||
'margin-top': '-4em',
|
||
};
|
||
|
||
var headerStyle = {
|
||
'font-size': '1.7em',
|
||
'font-weight': 'bold',
|
||
color: red,
|
||
};
|
||
|
||
var functionNameStyle = {
|
||
'margin-top': '1em',
|
||
'font-size': '1.2em',
|
||
};
|
||
|
||
var linkStyle = {
|
||
'font-size': '0.9em',
|
||
};
|
||
|
||
var anchorStyle = {
|
||
'text-decoration': 'none',
|
||
color: darkGray,
|
||
};
|
||
|
||
var traceStyle = {
|
||
'font-size': '1em',
|
||
};
|
||
|
||
var depStyle = {
|
||
'font-size': '1.2em',
|
||
};
|
||
|
||
var primaryErrorStyle = {
|
||
'background-color': lightRed,
|
||
};
|
||
|
||
var secondaryErrorStyle = {
|
||
'background-color': yellow,
|
||
};
|
||
|
||
var omittedFramesStyle = {
|
||
color: black,
|
||
'font-size': '0.9em',
|
||
margin: '1.5em 0',
|
||
cursor: 'pointer',
|
||
};
|
||
|
||
var preStyle = {
|
||
display: 'block',
|
||
padding: '0.5em',
|
||
'margin-top': '1.5em',
|
||
'margin-bottom': '0px',
|
||
'overflow-x': 'auto',
|
||
'font-size': '1.1em',
|
||
'white-space': 'pre',
|
||
};
|
||
|
||
var toggleStyle = {
|
||
'margin-bottom': '1.5em',
|
||
color: darkGray,
|
||
cursor: 'pointer',
|
||
};
|
||
|
||
var codeStyle = {
|
||
'font-family': 'Consolas, Menlo, monospace',
|
||
};
|
||
|
||
var hiddenStyle = {
|
||
display: 'none',
|
||
};
|
||
|
||
var groupStyle = {
|
||
'margin-left': '1em',
|
||
};
|
||
|
||
var _groupElemStyle = {
|
||
'background-color': 'inherit',
|
||
'border-color': '#ddd',
|
||
'border-width': '1px',
|
||
'border-radius': '4px',
|
||
'border-style': 'solid',
|
||
padding: '3px 6px',
|
||
cursor: 'pointer',
|
||
};
|
||
|
||
var groupElemLeft = Object.assign({}, _groupElemStyle, {
|
||
'border-top-right-radius': '0px',
|
||
'border-bottom-right-radius': '0px',
|
||
'margin-right': '0px',
|
||
});
|
||
|
||
var groupElemRight = Object.assign({}, _groupElemStyle, {
|
||
'border-top-left-radius': '0px',
|
||
'border-bottom-left-radius': '0px',
|
||
'margin-left': '-1px',
|
||
});
|
||
|
||
var footerStyle = {
|
||
'text-align': 'center',
|
||
color: darkGray,
|
||
};
|
||
|
||
var injectedCount = 0;
|
||
var injectedCache = {};
|
||
|
||
function getHead(document) {
|
||
return document.head || document.getElementsByTagName('head')[0];
|
||
}
|
||
|
||
function injectCss(document, css) {
|
||
var head = getHead(document);
|
||
var style = document.createElement('style');
|
||
style.type = 'text/css';
|
||
style.appendChild(document.createTextNode(css));
|
||
head.appendChild(style);
|
||
|
||
injectedCache[++injectedCount] = style;
|
||
return injectedCount;
|
||
}
|
||
|
||
function applyStyles(element, styles) {
|
||
element.setAttribute('style', '');
|
||
for (var key in styles) {
|
||
if (!styles.hasOwnProperty(key)) {
|
||
continue;
|
||
}
|
||
// $FlowFixMe
|
||
element.style[key] = styles[key];
|
||
}
|
||
}
|
||
|
||
function createHint(document, hint) {
|
||
var span = document.createElement('span');
|
||
span.appendChild(document.createTextNode(hint));
|
||
applyStyles(span, hintStyle);
|
||
return span;
|
||
}
|
||
|
||
function createClose(document, callback) {
|
||
var hints = document.createElement('div');
|
||
applyStyles(hints, hintsStyle);
|
||
|
||
var close = createHint(document, '×');
|
||
close.addEventListener('click', function() {
|
||
return callback();
|
||
});
|
||
applyStyles(close, closeButtonStyle);
|
||
hints.appendChild(close);
|
||
return hints;
|
||
}
|
||
|
||
function enableTabClick(node) {
|
||
node.setAttribute('tabindex', '0');
|
||
node.addEventListener('keydown', function(e) {
|
||
var key = e.key, which = e.which, keyCode = e.keyCode;
|
||
|
||
if (key === 'Enter' || which === 13 || keyCode === 13) {
|
||
e.preventDefault();
|
||
if (typeof e.target.click === 'function') {
|
||
e.target.click();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
function removeNextBr(parent, component) {
|
||
while (component != null && component.tagName.toLowerCase() !== 'br') {
|
||
component = component.nextElementSibling;
|
||
}
|
||
if (component != null) {
|
||
parent.removeChild(component);
|
||
}
|
||
}
|
||
|
||
function absolutifyCaret(component) {
|
||
var ccn = component.childNodes;
|
||
for (var index = 0; index < ccn.length; ++index) {
|
||
var c = ccn[index];
|
||
// $FlowFixMe
|
||
if (c.tagName.toLowerCase() !== 'span') {
|
||
continue;
|
||
}
|
||
var _text = c.innerText;
|
||
if (_text == null) {
|
||
continue;
|
||
}
|
||
var text = _text.replace(/\s/g, '');
|
||
if (text !== '|^') {
|
||
continue;
|
||
}
|
||
// $FlowFixMe
|
||
c.style.position = 'absolute';
|
||
// $FlowFixMe
|
||
removeNextBr(component, c);
|
||
}
|
||
}
|
||
|
||
function createCode(document, sourceLines, lineNum, columnNum, contextSize) {
|
||
var main = arguments.length > 5 && arguments[5] !== undefined
|
||
? arguments[5]
|
||
: false;
|
||
|
||
var sourceCode = [];
|
||
var whiteSpace = Infinity;
|
||
sourceLines.forEach(function(e) {
|
||
var text = e.content;
|
||
|
||
var m = text.match(/^\s*/);
|
||
if (text === '') {
|
||
return;
|
||
}
|
||
if (m && m[0]) {
|
||
whiteSpace = Math.min(whiteSpace, m[0].length);
|
||
} else {
|
||
whiteSpace = 0;
|
||
}
|
||
});
|
||
sourceLines.forEach(function(e) {
|
||
var text = e.content;
|
||
var line = e.lineNumber;
|
||
|
||
if (isFinite(whiteSpace)) {
|
||
text = text.substring(whiteSpace);
|
||
}
|
||
sourceCode[line - 1] = text;
|
||
});
|
||
var ansiHighlight = codeFrame(
|
||
sourceCode.join('\n'),
|
||
lineNum,
|
||
columnNum - (isFinite(whiteSpace) ? whiteSpace : 0),
|
||
{
|
||
forceColor: true,
|
||
linesAbove: contextSize,
|
||
linesBelow: contextSize,
|
||
}
|
||
);
|
||
var htmlHighlight = ansiHTML(ansiHighlight);
|
||
var code = document.createElement('code');
|
||
code.innerHTML = htmlHighlight;
|
||
absolutifyCaret(code);
|
||
applyStyles(code, codeStyle);
|
||
|
||
var ccn = code.childNodes;
|
||
oLoop: for (var index = 0; index < ccn.length; ++index) {
|
||
var node = ccn[index];
|
||
var ccn2 = node.childNodes;
|
||
for (var index2 = 0; index2 < ccn2.length; ++index2) {
|
||
var lineNode = ccn2[index2];
|
||
var text = lineNode.innerText;
|
||
if (text == null) {
|
||
continue;
|
||
}
|
||
if (text.indexOf(' ' + lineNum + ' |') === -1) {
|
||
continue;
|
||
}
|
||
// $FlowFixMe
|
||
applyStyles(node, main ? primaryErrorStyle : secondaryErrorStyle);
|
||
break oLoop;
|
||
}
|
||
}
|
||
var pre = document.createElement('pre');
|
||
applyStyles(pre, preStyle);
|
||
pre.appendChild(code);
|
||
return pre;
|
||
}
|
||
|
||
function isInternalFile(url, sourceFileName) {
|
||
return url.indexOf('/~/') !== -1 ||
|
||
url.indexOf('/node_modules/') !== -1 ||
|
||
url.trim().indexOf(' ') !== -1 ||
|
||
sourceFileName == null ||
|
||
sourceFileName.length === 0;
|
||
}
|
||
|
||
function getGroupToggle(document, omitsCount, omitBundle) {
|
||
var omittedFrames = document.createElement('div');
|
||
enableTabClick(omittedFrames);
|
||
var text1 = document.createTextNode(
|
||
'\u25B6 ' + omitsCount + ' stack frames were collapsed.'
|
||
);
|
||
omittedFrames.appendChild(text1);
|
||
omittedFrames.addEventListener('click', function() {
|
||
var hide = text1.textContent.match(/▲/);
|
||
var list = document.getElementsByName('bundle-' + omitBundle);
|
||
for (var index = 0; index < list.length; ++index) {
|
||
var 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');
|
||
} else {
|
||
text1.textContent = text1.textContent.replace(/▶/, '▲');
|
||
text1.textContent = text1.textContent.replace(/collapsed/, 'expanded');
|
||
}
|
||
});
|
||
applyStyles(omittedFrames, omittedFramesStyle);
|
||
return omittedFrames;
|
||
}
|
||
|
||
function insertBeforeBundle(
|
||
document,
|
||
parent,
|
||
omitsCount,
|
||
omitBundle,
|
||
actionElement
|
||
) {
|
||
var children = document.getElementsByName('bundle-' + omitBundle);
|
||
if (children.length < 1) {
|
||
return;
|
||
}
|
||
var first = children[0];
|
||
while (first != null && first.parentNode !== parent) {
|
||
first = first.parentNode;
|
||
}
|
||
var div = document.createElement('div');
|
||
enableTabClick(div);
|
||
div.setAttribute('name', 'bundle-' + omitBundle);
|
||
var text = document.createTextNode(
|
||
'\u25BC ' + omitsCount + ' stack frames were expanded.'
|
||
);
|
||
div.appendChild(text);
|
||
div.addEventListener('click', function() {
|
||
return actionElement.click();
|
||
});
|
||
applyStyles(div, omittedFramesStyle);
|
||
div.style.display = 'none';
|
||
|
||
parent.insertBefore(div, first);
|
||
}
|
||
|
||
function frameDiv(document, functionName, url, internalUrl) {
|
||
var frame = document.createElement('div');
|
||
var frameFunctionName = document.createElement('div');
|
||
|
||
var cleanedFunctionName = void 0;
|
||
if (!functionName || functionName === 'Object.<anonymous>') {
|
||
cleanedFunctionName = '(anonymous function)';
|
||
} else {
|
||
cleanedFunctionName = functionName;
|
||
}
|
||
|
||
var cleanedUrl = url.replace('webpack://', '.');
|
||
|
||
if (internalUrl) {
|
||
applyStyles(
|
||
frameFunctionName,
|
||
Object.assign({}, functionNameStyle, depStyle)
|
||
);
|
||
} else {
|
||
applyStyles(frameFunctionName, functionNameStyle);
|
||
}
|
||
|
||
frameFunctionName.appendChild(document.createTextNode(cleanedFunctionName));
|
||
frame.appendChild(frameFunctionName);
|
||
|
||
var frameLink = document.createElement('div');
|
||
applyStyles(frameLink, linkStyle);
|
||
var frameAnchor = document.createElement('a');
|
||
applyStyles(frameAnchor, anchorStyle);
|
||
frameAnchor.appendChild(document.createTextNode(cleanedUrl));
|
||
frameLink.appendChild(frameAnchor);
|
||
frame.appendChild(frameLink);
|
||
|
||
return frame;
|
||
}
|
||
|
||
function createFrame(
|
||
document,
|
||
frameSetting,
|
||
frame,
|
||
contextSize,
|
||
critical,
|
||
omits,
|
||
omitBundle,
|
||
parentContainer,
|
||
lastElement
|
||
) {
|
||
var compiled = frameSetting.compiled;
|
||
var functionName = frame.functionName,
|
||
fileName = frame.fileName,
|
||
lineNumber = frame.lineNumber,
|
||
columnNumber = frame.columnNumber,
|
||
scriptLines = frame._scriptCode,
|
||
sourceFileName = frame._originalFileName,
|
||
sourceLineNumber = frame._originalLineNumber,
|
||
sourceColumnNumber = frame._originalColumnNumber,
|
||
sourceLines = frame._originalScriptCode;
|
||
|
||
var url = void 0;
|
||
if (!compiled && sourceFileName) {
|
||
url = sourceFileName + ':' + sourceLineNumber;
|
||
if (sourceColumnNumber) {
|
||
url += ':' + sourceColumnNumber;
|
||
}
|
||
} else {
|
||
url = fileName + ':' + lineNumber;
|
||
if (columnNumber) {
|
||
url += ':' + columnNumber;
|
||
}
|
||
}
|
||
|
||
var needsHidden = false;
|
||
var internalUrl = isInternalFile(url, sourceFileName);
|
||
if (internalUrl) {
|
||
++omits.value;
|
||
needsHidden = true;
|
||
}
|
||
var collapseElement = null;
|
||
if (!internalUrl || lastElement) {
|
||
if (omits.value > 0) {
|
||
var capV = omits.value;
|
||
var omittedFrames = getGroupToggle(document, capV, omitBundle);
|
||
window.requestAnimationFrame(function() {
|
||
insertBeforeBundle(
|
||
document,
|
||
parentContainer,
|
||
capV,
|
||
omitBundle,
|
||
omittedFrames
|
||
);
|
||
});
|
||
if (lastElement && internalUrl) {
|
||
collapseElement = omittedFrames;
|
||
} else {
|
||
parentContainer.appendChild(omittedFrames);
|
||
}
|
||
++omits.bundle;
|
||
}
|
||
omits.value = 0;
|
||
}
|
||
|
||
var elem = frameDiv(document, functionName, url, internalUrl);
|
||
if (needsHidden) {
|
||
applyStyles(elem, hiddenStyle);
|
||
elem.setAttribute('name', 'bundle-' + omitBundle);
|
||
}
|
||
|
||
var hasSource = false;
|
||
if (!internalUrl) {
|
||
if (compiled && scriptLines.length !== 0) {
|
||
elem.appendChild(
|
||
createCode(
|
||
document,
|
||
scriptLines,
|
||
lineNumber,
|
||
columnNumber,
|
||
contextSize,
|
||
critical
|
||
)
|
||
);
|
||
hasSource = true;
|
||
} else if (!compiled && sourceLines.length !== 0) {
|
||
elem.appendChild(
|
||
createCode(
|
||
document,
|
||
sourceLines,
|
||
sourceLineNumber,
|
||
sourceColumnNumber,
|
||
contextSize,
|
||
critical
|
||
)
|
||
);
|
||
hasSource = true;
|
||
}
|
||
}
|
||
|
||
return { elem: elem, hasSource: hasSource, collapseElement: collapseElement };
|
||
}
|
||
|
||
function createFrameWrapper(
|
||
document,
|
||
parent,
|
||
factory,
|
||
lIndex,
|
||
frameSettings,
|
||
contextSize
|
||
) {
|
||
var fac = factory();
|
||
if (fac == null) {
|
||
return;
|
||
}
|
||
var hasSource = fac.hasSource,
|
||
elem = fac.elem,
|
||
collapseElement = fac.collapseElement;
|
||
|
||
var elemWrapper = document.createElement('div');
|
||
elemWrapper.appendChild(elem);
|
||
|
||
if (hasSource) {
|
||
var compiledDiv = document.createElement('div');
|
||
enableTabClick(compiledDiv);
|
||
applyStyles(compiledDiv, toggleStyle);
|
||
|
||
var o = frameSettings[lIndex];
|
||
var compiledText = document.createTextNode(
|
||
'View ' + (o && o.compiled ? 'source' : 'compiled')
|
||
);
|
||
compiledDiv.addEventListener('click', function() {
|
||
if (o) {
|
||
o.compiled = !o.compiled;
|
||
}
|
||
|
||
var next = createFrameWrapper(
|
||
document,
|
||
parent,
|
||
factory,
|
||
lIndex,
|
||
frameSettings,
|
||
contextSize
|
||
);
|
||
if (next != null) {
|
||
parent.insertBefore(next, elemWrapper);
|
||
parent.removeChild(elemWrapper);
|
||
}
|
||
});
|
||
compiledDiv.appendChild(compiledText);
|
||
elemWrapper.appendChild(compiledDiv);
|
||
}
|
||
|
||
if (collapseElement != null) {
|
||
elemWrapper.appendChild(collapseElement);
|
||
}
|
||
|
||
return elemWrapper;
|
||
}
|
||
|
||
function createFrames(document, resolvedFrames, frameSettings, contextSize) {
|
||
if (resolvedFrames.length !== frameSettings.length) {
|
||
throw new Error(
|
||
'You must give a frame settings array of identical length to resolved frames.'
|
||
);
|
||
}
|
||
var trace = document.createElement('div');
|
||
applyStyles(trace, traceStyle);
|
||
|
||
var index = 0;
|
||
var critical = true;
|
||
var omits = { value: 0, bundle: 1 };
|
||
resolvedFrames.forEach(function(frame) {
|
||
var lIndex = index++;
|
||
var elem = createFrameWrapper(
|
||
document,
|
||
trace,
|
||
createFrame.bind(
|
||
undefined,
|
||
document,
|
||
frameSettings[lIndex],
|
||
frame,
|
||
contextSize,
|
||
critical,
|
||
omits,
|
||
omits.bundle,
|
||
trace,
|
||
index === resolvedFrames.length
|
||
),
|
||
lIndex,
|
||
frameSettings,
|
||
contextSize
|
||
);
|
||
if (elem == null) {
|
||
return;
|
||
}
|
||
critical = false;
|
||
trace.appendChild(elem);
|
||
});
|
||
//TODO: fix this
|
||
omits.value = 0;
|
||
|
||
return trace;
|
||
}
|
||
|
||
function createFooter(document) {
|
||
var div = document.createElement('div');
|
||
applyStyles(div, footerStyle);
|
||
div.appendChild(
|
||
document.createTextNode(
|
||
'This screen is visible only in development. It will not appear when the app crashes in production.'
|
||
)
|
||
);
|
||
div.appendChild(document.createElement('br'));
|
||
div.appendChild(
|
||
document.createTextNode(
|
||
'Open your browser’s developer console to further inspect this error.'
|
||
)
|
||
);
|
||
return div;
|
||
}
|
||
|
||
function consumeEvent(e) {
|
||
e.preventDefault();
|
||
if (typeof e.target.blur === 'function') {
|
||
e.target.blur();
|
||
}
|
||
}
|
||
|
||
function updateAdditional(
|
||
document,
|
||
additionalReference,
|
||
currentError,
|
||
totalErrors,
|
||
switchCallback
|
||
) {
|
||
if (additionalReference.lastChild) {
|
||
additionalReference.removeChild(additionalReference.lastChild);
|
||
}
|
||
|
||
var text = ' ';
|
||
if (totalErrors <= 1) {
|
||
additionalReference.appendChild(document.createTextNode(text));
|
||
return;
|
||
}
|
||
text = 'Errors ' + currentError + ' of ' + totalErrors;
|
||
var span = document.createElement('span');
|
||
span.appendChild(document.createTextNode(text));
|
||
var group = document.createElement('span');
|
||
applyStyles(group, groupStyle);
|
||
var left = document.createElement('button');
|
||
applyStyles(left, groupElemLeft);
|
||
left.addEventListener('click', function(e) {
|
||
consumeEvent(e);
|
||
switchCallback(-1);
|
||
});
|
||
left.appendChild(document.createTextNode('←'));
|
||
enableTabClick(left);
|
||
var right = document.createElement('button');
|
||
applyStyles(right, groupElemRight);
|
||
right.addEventListener('click', function(e) {
|
||
consumeEvent(e);
|
||
switchCallback(1);
|
||
});
|
||
right.appendChild(document.createTextNode('→'));
|
||
enableTabClick(right);
|
||
group.appendChild(left);
|
||
group.appendChild(right);
|
||
span.appendChild(group);
|
||
additionalReference.appendChild(span);
|
||
}
|
||
|
||
function createOverlay(
|
||
document,
|
||
name,
|
||
message,
|
||
frames,
|
||
contextSize,
|
||
currentError,
|
||
totalErrors,
|
||
switchCallback,
|
||
closeCallback
|
||
) {
|
||
var frameSettings = frames.map(function() {
|
||
return { compiled: false };
|
||
});
|
||
// Create overlay
|
||
var overlay = document.createElement('div');
|
||
applyStyles(overlay, overlayStyle);
|
||
overlay.appendChild(createClose(document, closeCallback));
|
||
|
||
// Create container
|
||
var container = document.createElement('div');
|
||
container.className = 'cra-container';
|
||
overlay.appendChild(container);
|
||
|
||
// Create additional
|
||
var additional = document.createElement('div');
|
||
applyStyles(additional, additionalStyle);
|
||
container.appendChild(additional);
|
||
updateAdditional(
|
||
document,
|
||
additional,
|
||
currentError,
|
||
totalErrors,
|
||
switchCallback
|
||
);
|
||
|
||
// Create header
|
||
var header = document.createElement('div');
|
||
applyStyles(header, headerStyle);
|
||
if (message.match(/^\w*:/)) {
|
||
header.appendChild(document.createTextNode(message));
|
||
} else {
|
||
header.appendChild(document.createTextNode(name + ': ' + message));
|
||
}
|
||
container.appendChild(header);
|
||
|
||
// Create trace
|
||
container.appendChild(
|
||
createFrames(document, frames, frameSettings, contextSize)
|
||
);
|
||
|
||
// Show message
|
||
container.appendChild(createFooter(document));
|
||
|
||
return {
|
||
overlay: overlay,
|
||
additional: additional,
|
||
};
|
||
}
|
||
|
||
var CONTEXT_SIZE = 3;
|
||
var iframeReference = null;
|
||
var additionalReference = null;
|
||
var errorReferences = [];
|
||
var currReferenceIndex = -1;
|
||
|
||
var css = [
|
||
'.cra-container {',
|
||
' padding-right: 15px;',
|
||
' padding-left: 15px;',
|
||
' margin-right: auto;',
|
||
' margin-left: auto;',
|
||
'}',
|
||
'',
|
||
'@media (min-width: 768px) {',
|
||
' .cra-container {',
|
||
' width: calc(750px - 6em);',
|
||
' }',
|
||
'}',
|
||
'',
|
||
'@media (min-width: 992px) {',
|
||
' .cra-container {',
|
||
' width: calc(970px - 6em);',
|
||
' }',
|
||
'}',
|
||
'',
|
||
'@media (min-width: 1200px) {',
|
||
' .cra-container {',
|
||
' width: calc(1170px - 6em);',
|
||
' }',
|
||
'}',
|
||
].join('\n');
|
||
|
||
function render(name, message, resolvedFrames) {
|
||
disposeCurrentView();
|
||
|
||
var iframe = window.document.createElement('iframe');
|
||
applyStyles(iframe, iframeStyle);
|
||
iframeReference = iframe;
|
||
iframe.onload = function() {
|
||
if (iframeReference == null) {
|
||
return;
|
||
}
|
||
var w = iframeReference.contentWindow;
|
||
var document = iframeReference.contentDocument;
|
||
|
||
var _createOverlay = createOverlay(
|
||
document,
|
||
name,
|
||
message,
|
||
resolvedFrames,
|
||
CONTEXT_SIZE,
|
||
currReferenceIndex + 1,
|
||
errorReferences.length,
|
||
function(offset) {
|
||
switchError(offset);
|
||
},
|
||
function() {
|
||
unmount();
|
||
}
|
||
),
|
||
overlay = _createOverlay.overlay,
|
||
additional = _createOverlay.additional;
|
||
|
||
if (w != null) {
|
||
w.onkeydown = function(event) {
|
||
keyHandler(
|
||
function(type) {
|
||
return shortcutHandler(type);
|
||
},
|
||
event
|
||
);
|
||
};
|
||
}
|
||
injectCss(iframeReference.contentDocument, css);
|
||
if (document.body != null) {
|
||
document.body.appendChild(overlay);
|
||
}
|
||
additionalReference = additional;
|
||
};
|
||
window.document.body.appendChild(iframe);
|
||
}
|
||
|
||
function renderErrorByIndex(index) {
|
||
currReferenceIndex = index;
|
||
|
||
var _getErrorRecord = getErrorRecord(errorReferences[index]),
|
||
error = _getErrorRecord.error,
|
||
unhandledRejection = _getErrorRecord.unhandledRejection,
|
||
enhancedFrames = _getErrorRecord.enhancedFrames;
|
||
|
||
if (unhandledRejection) {
|
||
render(
|
||
'Unhandled Rejection (' + error.name + ')',
|
||
error.message,
|
||
enhancedFrames
|
||
);
|
||
} else {
|
||
render(error.name, error.message, enhancedFrames);
|
||
}
|
||
}
|
||
|
||
function switchError(offset) {
|
||
var nextView = currReferenceIndex + offset;
|
||
if (nextView < 0 || nextView >= errorReferences.length) {
|
||
return;
|
||
}
|
||
renderErrorByIndex(nextView);
|
||
}
|
||
|
||
function disposeCurrentView() {
|
||
if (iframeReference === null) {
|
||
return;
|
||
}
|
||
window.document.body.removeChild(iframeReference);
|
||
iframeReference = null;
|
||
additionalReference = null;
|
||
}
|
||
|
||
function unmount() {
|
||
disposeCurrentView();
|
||
drain();
|
||
errorReferences = [];
|
||
currReferenceIndex = -1;
|
||
}
|
||
|
||
function crash(error) {
|
||
var unhandledRejection = arguments.length > 1 && arguments[1] !== undefined
|
||
? arguments[1]
|
||
: false;
|
||
|
||
if (module.hot && typeof module.hot.decline === 'function') {
|
||
module.hot.decline();
|
||
}
|
||
consume(error, unhandledRejection, CONTEXT_SIZE)
|
||
.then(function(ref) {
|
||
errorReferences.push(ref);
|
||
if (iframeReference !== null && additionalReference !== null) {
|
||
updateAdditional(
|
||
iframeReference.contentDocument,
|
||
additionalReference,
|
||
currReferenceIndex + 1,
|
||
errorReferences.length,
|
||
function(offset) {
|
||
switchError(offset);
|
||
}
|
||
);
|
||
} else {
|
||
if (errorReferences.length !== 1) {
|
||
throw new Error('Something is *really* wrong.');
|
||
}
|
||
renderErrorByIndex((currReferenceIndex = 0));
|
||
}
|
||
})
|
||
.catch(function(e) {
|
||
console.log('Could not consume error:', e);
|
||
});
|
||
}
|
||
|
||
function shortcutHandler(type) {
|
||
switch (type) {
|
||
case SHORTCUT_ESCAPE: {
|
||
unmount();
|
||
break;
|
||
}
|
||
case SHORTCUT_LEFT: {
|
||
switchError(-1);
|
||
break;
|
||
}
|
||
case SHORTCUT_RIGHT: {
|
||
switchError(1);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
function inject() {
|
||
registerUnhandledError(window, function(error) {
|
||
return crash(error);
|
||
});
|
||
registerUnhandledRejection(window, function(error) {
|
||
return crash(error, true);
|
||
});
|
||
registerShortcuts(window, shortcutHandler);
|
||
registerStackTraceLimit();
|
||
}
|
||
|
||
function uninject() {
|
||
unregisterStackTraceLimit();
|
||
unregisterShortcuts(window);
|
||
unregisterUnhandledRejection(window);
|
||
unregisterUnhandledError(window);
|
||
}
|
||
|
||
inject();
|
||
if (module.hot && typeof module.hot.dispose === 'function') {
|
||
module.hot.dispose(function() {
|
||
uninject();
|
||
});
|
||
}
|