diff --git a/packages/react-error-overlay/package.json b/packages/react-error-overlay/package.json index 289f72126bfe05c6e652ea42be8e4ae127769b83..11ee85894478afda5c39d31409b76f4c459027e9 100644 --- a/packages/react-error-overlay/package.json +++ b/packages/react-error-overlay/package.json @@ -51,7 +51,7 @@ "eslint-plugin-import": "2.7.0", "eslint-plugin-jsx-a11y": "5.1.1", "eslint-plugin-react": "7.1.0", - "flow-bin": "0.52.0", + "flow-bin": "^0.54.0", "jest": "20.0.4", "jest-fetch-mock": "1.2.1", "rimraf": "^2.6.1" diff --git a/packages/react-error-overlay/src/components/Collapsible.js b/packages/react-error-overlay/src/components/Collapsible.js index 92f1de4295c6b4ddbfa51f164aa3af31c9796ba4..0954288130a066d894d0c120b5da32b84e41f001 100644 --- a/packages/react-error-overlay/src/components/Collapsible.js +++ b/packages/react-error-overlay/src/components/Collapsible.js @@ -11,6 +11,8 @@ import React, { Component } from 'react'; import { black } from '../styles'; +import type { Element as ReactElement } from 'react'; + const _collapsibleStyle = { color: black, cursor: 'pointer', @@ -35,7 +37,15 @@ const collapsibleExpandedStyle = { marginBottom: '0.6em', }; -class Collapsible extends Component { +type Props = {| + children: ReactElement<any>[], +|}; + +type State = {| + collapsed: boolean, +|}; + +class Collapsible extends Component<Props, State> { state = { collapsed: true, }; diff --git a/packages/react-error-overlay/src/components/ErrorOverlay.js b/packages/react-error-overlay/src/components/ErrorOverlay.js index 446105dad2e6decec61bc08e86b7c5a2e41a02f0..2f706f2424b421834c73524eb32afd747eb6ec99 100644 --- a/packages/react-error-overlay/src/components/ErrorOverlay.js +++ b/packages/react-error-overlay/src/components/ErrorOverlay.js @@ -11,6 +11,8 @@ import React, { Component } from 'react'; import { black } from '../styles'; +import type { Node as ReactNode } from 'react'; + const overlayStyle = { position: 'relative', display: 'inline-flex', @@ -31,10 +33,19 @@ const overlayStyle = { color: black, }; -class ErrorOverlay extends Component { +type Props = {| + children: ReactNode, + shortcutHandler?: (eventKey: string) => void, +|}; + +type State = {| + collapsed: boolean, +|}; + +class ErrorOverlay extends Component<Props, State> { iframeWindow: window = null; - getIframeWindow = (element: HTMLDivElement) => { + getIframeWindow = (element: ?HTMLDivElement) => { if (element) { const document = element.ownerDocument; this.iframeWindow = document.defaultView; diff --git a/packages/react-error-overlay/src/containers/CompileErrorContainer.js b/packages/react-error-overlay/src/containers/CompileErrorContainer.js index a3e89fe591d3087fc971b645a4edcc20813bdc23..9eb8c029b32d4e365deb2dd542129f77cd5f1696 100644 --- a/packages/react-error-overlay/src/containers/CompileErrorContainer.js +++ b/packages/react-error-overlay/src/containers/CompileErrorContainer.js @@ -15,7 +15,11 @@ import Header from '../components/Header'; import CodeBlock from '../components/CodeBlock'; import generateAnsiHTML from '../utils/generateAnsiHTML'; -class CompileErrorContainer extends PureComponent { +type Props = {| + error: string, +|}; + +class CompileErrorContainer extends PureComponent<Props, void> { render() { const { error } = this.props; return ( diff --git a/packages/react-error-overlay/src/containers/RuntimeError.js b/packages/react-error-overlay/src/containers/RuntimeError.js index c64824137d27846ad910fb26d1a694d91d5e8d2e..b21360d5e3019ef6e9d2d9193b3520e959d5cee2 100644 --- a/packages/react-error-overlay/src/containers/RuntimeError.js +++ b/packages/react-error-overlay/src/containers/RuntimeError.js @@ -11,6 +11,7 @@ import React from 'react'; import Header from '../components/Header'; import StackTrace from './StackTrace'; + import type { StackFrame } from '../utils/stack-frame'; const wrapperStyle = { @@ -18,7 +19,7 @@ const wrapperStyle = { flexDirection: 'column', }; -type ErrorRecord = {| +export type ErrorRecord = {| error: Error, unhandledRejection: boolean, contextSize: number, diff --git a/packages/react-error-overlay/src/containers/RuntimeErrorContainer.js b/packages/react-error-overlay/src/containers/RuntimeErrorContainer.js index 1e09724df9aaa09f2768c044f32881b7276743c5..dafd2af27addffda7042646416813c2c0b6f5b49 100644 --- a/packages/react-error-overlay/src/containers/RuntimeErrorContainer.js +++ b/packages/react-error-overlay/src/containers/RuntimeErrorContainer.js @@ -15,7 +15,19 @@ import NavigationBar from '../components/NavigationBar'; import RuntimeError from './RuntimeError'; import Footer from '../components/Footer'; -class RuntimeErrorContainer extends PureComponent { +import type { ErrorRecord } from './RuntimeError'; + +type Props = {| + errorRecords: ErrorRecord[], + close: () => void, + launchEditorEndpoint: ?string, +|}; + +type State = {| + currentIndex: number, +|}; + +class RuntimeErrorContainer extends PureComponent<Props, State> { state = { currentIndex: 0, }; diff --git a/packages/react-error-overlay/src/containers/StackFrame.js b/packages/react-error-overlay/src/containers/StackFrame.js index 1dfcbb4376a41becff41be7f9b9da06525b12447..9916623564aa49095b71f8234f50750725353b58 100644 --- a/packages/react-error-overlay/src/containers/StackFrame.js +++ b/packages/react-error-overlay/src/containers/StackFrame.js @@ -13,6 +13,8 @@ import CodeBlock from './StackFrameCodeBlock'; import { getPrettyURL } from '../utils/getPrettyURL'; import { darkGray } from '../styles'; +import type { StackFrame as StackFrameType } from '../utils/stack-frame'; + const linkStyle = { fontSize: '0.9em', marginBottom: '0.9em', @@ -43,7 +45,19 @@ const toggleStyle = { lineHeight: '1.5', }; -class StackFrame extends Component { +type Props = {| + frame: StackFrameType, + launchEditorEndpoint: ?string, + contextSize: number, + critical: boolean, + showCode: boolean, +|}; + +type State = {| + compiled: boolean, +|}; + +class StackFrame extends Component<Props, State> { state = { compiled: false, }; @@ -54,43 +68,45 @@ class StackFrame extends Component { })); }; - canOpenInEditor() { + getEndpointUrl(): string | null { if (!this.props.launchEditorEndpoint) { - return; + return null; } const { _originalFileName: sourceFileName } = this.props.frame; // Unknown file if (!sourceFileName) { - return false; + return null; } // e.g. "/path-to-my-app/webpack/bootstrap eaddeb46b67d75e4dfc1" const isInternalWebpackBootstrapCode = sourceFileName.trim().indexOf(' ') !== -1; if (isInternalWebpackBootstrapCode) { - return false; + return null; } // Code is in a real file - return true; + return this.props.launchEditorEndpoint || null; } openInEditor = () => { - if (!this.canOpenInEditor()) { + const endpointUrl = this.getEndpointUrl(); + if (endpointUrl === null) { return; } + const { _originalFileName: sourceFileName, _originalLineNumber: sourceLineNumber, } = this.props.frame; // Keep this in sync with react-error-overlay/middleware.js fetch( - `${this.props.launchEditorEndpoint}?fileName=` + + `${endpointUrl}?fileName=` + window.encodeURIComponent(sourceFileName) + '&lineNumber=' + window.encodeURIComponent(sourceLineNumber || 1) ).then(() => {}, () => {}); }; - onKeyDown = (e: SyntheticKeyboardEvent) => { + onKeyDown = (e: SyntheticKeyboardEvent<>) => { if (e.key === 'Enter') { this.openInEditor(); } @@ -152,7 +168,7 @@ class StackFrame extends Component { } } - const canOpenInEditor = this.canOpenInEditor(); + const canOpenInEditor = this.getEndpointUrl() !== null; return ( <div> <div>{functionName}</div> diff --git a/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js b/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js index 2ed685cff49dfcf98b89a9b0d66fc6e4860b0bc4..58a2c0d537cedf8619a16f133b5295cb3a7e44f5 100644 --- a/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js +++ b/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js @@ -21,12 +21,16 @@ import codeFrame from 'babel-code-frame'; type StackFrameCodeBlockPropsType = {| lines: ScriptLine[], lineNum: number, - columnNum: number, + columnNum: ?number, contextSize: number, main: boolean, |}; -function StackFrameCodeBlock(props: StackFrameCodeBlockPropsType) { +// Exact type workaround for spread operator. +// See: https://github.com/facebook/flow/issues/2405 +type Exact<T> = $Shape<T>; + +function StackFrameCodeBlock(props: Exact<StackFrameCodeBlockPropsType>) { const { lines, lineNum, columnNum, contextSize, main } = props; const sourceCode = []; let whiteSpace = Infinity; diff --git a/packages/react-error-overlay/src/containers/StackTrace.js b/packages/react-error-overlay/src/containers/StackTrace.js index 8d81cc9429e94480f6795457c491b8b4ab2c4893..8d4a487dc7bdc9631ef7d7b840eaa8c2a2103a14 100644 --- a/packages/react-error-overlay/src/containers/StackTrace.js +++ b/packages/react-error-overlay/src/containers/StackTrace.js @@ -14,6 +14,8 @@ import Collapsible from '../components/Collapsible'; import { isInternalFile } from '../utils/isInternalFile'; import { isBultinErrorName } from '../utils/isBultinErrorName'; +import type { StackFrame as StackFrameType } from '../utils/stack-frame'; + const traceStyle = { fontSize: '1em', flex: '0 1 auto', @@ -21,7 +23,14 @@ const traceStyle = { overflow: 'auto', }; -class StackTrace extends Component { +type Props = {| + stackFrames: StackFrameType[], + errorName: string, + contextSize: number, + launchEditorEndpoint: ?string, +|}; + +class StackTrace extends Component<Props> { renderFrames() { const { stackFrames, diff --git a/packages/react-error-overlay/src/index.js b/packages/react-error-overlay/src/index.js index 168baa7ef6472698ad881a904637fda6bb0125f8..d44976713a6328e08d45a9725774430a6b2b1de2 100644 --- a/packages/react-error-overlay/src/index.js +++ b/packages/react-error-overlay/src/index.js @@ -9,6 +9,7 @@ /* @flow */ import React from 'react'; +import type { Element } from 'react'; import ReactDOM from 'react-dom'; import CompileErrorContainer from './containers/CompileErrorContainer'; import RuntimeErrorContainer from './containers/RuntimeErrorContainer'; @@ -27,7 +28,7 @@ type RuntimeReportingOptions = {| let iframe: null | HTMLIFrameElement = null; let isLoadingIframe: boolean = false; -let renderedElement: null | React.Element<any> = null; +let renderedElement: null | Element<any> = null; let currentBuildError: null | string = null; let currentRuntimeErrorRecords: Array<ErrorRecord> = []; let currentRuntimeErrorOptions: null | RuntimeReportingOptions = null; diff --git a/packages/react-error-overlay/src/utils/getSourceMap.js b/packages/react-error-overlay/src/utils/getSourceMap.js index 1d8405519bd613640521d601589bed7cda1f0853..5c9e3aa9eb7ee2e93737e8ae6eec688c201bf233 100644 --- a/packages/react-error-overlay/src/utils/getSourceMap.js +++ b/packages/react-error-overlay/src/utils/getSourceMap.js @@ -77,7 +77,10 @@ class SourceMap { } } -function extractSourceMapUrl(fileUri: string, fileContents: string) { +function extractSourceMapUrl( + fileUri: string, + fileContents: string +): Promise<string> { const regex = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$/gm; let match = null; for (;;) {