An error occurred while loading the file. Please try again.
-
Dan Abramov authored55afd862
/* @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';
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);
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
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':
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
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;
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
// 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 = () => {
// Keep this in sync with react-error-overlay/middleware.js
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
fetch(
'/__open-stack-frame-in-editor?fileName=' +
window.encodeURIComponent(sourceFileName) +
'&lineNumber=' +
window.encodeURIComponent(sourceLineNumber || 1)
).then(() => {}, () => {});
};
}
}
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 };