From eed708a822d6cf3ff17b665b093a2c23a50f6b15 Mon Sep 17 00:00:00 2001
From: Luca <duvet86@gmail.com>
Date: Tue, 12 Sep 2017 00:20:50 +0800
Subject: [PATCH] Updated react-error-overlay to latest Flow (0.54.0) (#3065)

* Updated react-error-overlay to latest Flow (0.54.0)

* Revert "Updated react-error-overlay to latest Flow (0.54.0)"

This reverts commit 6deaffbdb0b2e7c72a7f4053a299f28db174383b.

* Fixed unit tests.

* Updated code as per code review.

* Fixed code as per code review.

* Updated the code as per review.
---
 packages/react-error-overlay/package.json     |  2 +-
 .../src/components/Collapsible.js             | 12 ++++++-
 .../src/components/ErrorOverlay.js            | 15 ++++++--
 .../src/containers/CompileErrorContainer.js   |  6 +++-
 .../src/containers/RuntimeError.js            |  3 +-
 .../src/containers/RuntimeErrorContainer.js   | 14 +++++++-
 .../src/containers/StackFrame.js              | 36 +++++++++++++------
 .../src/containers/StackFrameCodeBlock.js     |  8 +++--
 .../src/containers/StackTrace.js              | 11 +++++-
 packages/react-error-overlay/src/index.js     |  3 +-
 .../src/utils/getSourceMap.js                 |  5 ++-
 11 files changed, 93 insertions(+), 22 deletions(-)

diff --git a/packages/react-error-overlay/package.json b/packages/react-error-overlay/package.json
index 289f72126..11ee85894 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 92f1de429..095428813 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 446105dad..2f706f242 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 a3e89fe59..9eb8c029b 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 c64824137..b21360d5e 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 1e09724df..dafd2af27 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 1dfcbb437..991662356 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 2ed685cff..58a2c0d53 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 8d81cc942..8d4a487dc 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 168baa7ef..d44976713 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 1d8405519..5c9e3aa9e 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 (;;) {
-- 
GitLab