mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-10 19:56:54 +03:00
feat(trace): convert to TypeScript (#647)
* get started * progress * finish test * Revert that file * Move types to dev * Add enzyme types * Bump that version * prettier
This commit is contained in:
parent
d37e7d93e1
commit
03217001df
|
@ -84,6 +84,7 @@
|
|||
"peerDependencies": {
|
||||
"@types/react": "^16.3.18",
|
||||
"react": "^16.3.0",
|
||||
"redux": "^3.4.0 || ^4.0.0",
|
||||
"redux-devtools-inspector-monitor": "^0.14.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-flow"],
|
||||
"plugins": [
|
||||
[
|
||||
"@babel/plugin-transform-runtime",
|
||||
{
|
||||
"regenerator": true
|
||||
}
|
||||
],
|
||||
["@babel/plugin-proposal-decorators", { "legacy": true }],
|
||||
"@babel/plugin-proposal-class-properties"
|
||||
]
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript"
|
||||
],
|
||||
"plugins": ["@babel/plugin-proposal-class-properties"]
|
||||
}
|
||||
|
|
1
packages/redux-devtools-trace-monitor/.eslintignore
Normal file
1
packages/redux-devtools-trace-monitor/.eslintignore
Normal file
|
@ -0,0 +1 @@
|
|||
lib
|
21
packages/redux-devtools-trace-monitor/.eslintrc.js
Normal file
21
packages/redux-devtools-trace-monitor/.eslintrc.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
module.exports = {
|
||||
extends: '../../.eslintrc',
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: '../../eslintrc.ts.react.base.json',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['test/*.ts', 'test/*.tsx'],
|
||||
extends: '../../eslintrc.ts.react.jest.base.json',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./test/tsconfig.json'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
3
packages/redux-devtools-trace-monitor/jest.config.js
Normal file
3
packages/redux-devtools-trace-monitor/jest.config.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
};
|
|
@ -2,47 +2,61 @@
|
|||
"name": "redux-devtools-trace-monitor",
|
||||
"version": "0.1.3",
|
||||
"description": "Submonitor for Redux DevTools inspector to show stack traces.",
|
||||
"repository": "https://github.com/reduxjs/redux-devtools",
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools",
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-trace-monitor",
|
||||
"license": "MIT",
|
||||
"author": "Mark Erikson <mark@isquaredsoftware.com>",
|
||||
"contributors": [
|
||||
"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "lib/StackTraceTab.js",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"main": "lib/StackTraceTab.js",
|
||||
"types": "lib/StackTraceTab.d.ts",
|
||||
"repository": "https://github.com/reduxjs/redux-devtools",
|
||||
"scripts": {
|
||||
"build": "npm run build:types && npm run build:js",
|
||||
"build:types": "tsc --emitDeclarationOnly",
|
||||
"build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline",
|
||||
"clean": "rimraf lib",
|
||||
"build": "babel src --out-dir lib",
|
||||
"test": "jest --no-cache",
|
||||
"prepare": "npm run clean && npm run build",
|
||||
"prepublishOnly": "npm run test && npm run clean && npm run build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.10.5",
|
||||
"@babel/core": "^7.11.1",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||
"@babel/plugin-proposal-decorators": "^7.10.5",
|
||||
"@babel/plugin-transform-runtime": "^7.11.0",
|
||||
"@babel/preset-env": "^7.11.0",
|
||||
"@babel/preset-flow": "^7.10.4",
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.3",
|
||||
"enzyme-to-json": "^3.5.0",
|
||||
"jest": "^26.2.2",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-test-renderer": "^16.13.1",
|
||||
"rimraf": "^3.0.2"
|
||||
"test": "jest",
|
||||
"lint": "eslint . --ext .ts,.tsx",
|
||||
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
||||
"type-check": "tsc --noEmit",
|
||||
"type-check:watch": "npm run type-check -- --watch",
|
||||
"preversion": "npm run type-check && npm run lint && npm run test",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"@types/chrome": "^0.0.124",
|
||||
"anser": "^1.4.9",
|
||||
"html-entities": "^1.3.1",
|
||||
"react": "^16.13.1",
|
||||
"redux-devtools-themes": "^1.0.0",
|
||||
"settle-promise": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/babel__code-frame": "^7.0.2",
|
||||
"@types/enzyme": "^3.10.5",
|
||||
"@types/enzyme-adapter-react-16": "^1.0.6",
|
||||
"@types/html-entities": "^1.2.16",
|
||||
"@types/react": "^16.9.46",
|
||||
"@types/redux-devtools-themes": "^1.0.0",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.3",
|
||||
"enzyme-to-json": "^3.5.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-test-renderer": "^16.13.1",
|
||||
"redux": "^4.0.5",
|
||||
"redux-devtools": "^3.7.0",
|
||||
"redux-devtools-inspector-monitor": "^0.14.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.3.18",
|
||||
"react": "^16.3.0",
|
||||
"redux": "^3.4.0 || ^4.0.0",
|
||||
"redux-devtools": "^3.4.0",
|
||||
"redux-devtools-inspector-monitor": "^0.14.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,26 +3,45 @@ import React, { Component } from 'react';
|
|||
import { getStackFrames } from './react-error-overlay/utils/getStackFrames';
|
||||
import StackTrace from './react-error-overlay/containers/StackTrace';
|
||||
import openFile from './openFile';
|
||||
import { Action } from 'redux';
|
||||
import { TabComponentProps } from 'redux-devtools-inspector-monitor';
|
||||
import StackFrame from './react-error-overlay/utils/stack-frame';
|
||||
import { ErrorLocation } from './react-error-overlay/utils/parseCompileError';
|
||||
|
||||
const rootStyle = { padding: '5px 10px' };
|
||||
|
||||
export default class StackTraceTab extends Component {
|
||||
interface Props<S, A extends Action<unknown>> extends TabComponentProps<S, A> {
|
||||
openFile: (
|
||||
fileName: string,
|
||||
lineNumber: number,
|
||||
stackFrame: StackFrame
|
||||
) => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
stackFrames: StackFrame[];
|
||||
currentError?: Error;
|
||||
showDocsLink?: boolean;
|
||||
}
|
||||
|
||||
export default class StackTraceTab<
|
||||
S,
|
||||
A extends Action<unknown>
|
||||
> extends Component<Props<S, A>, State> {
|
||||
static defaultProps = {
|
||||
openFile,
|
||||
};
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
stackFrames: [],
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
stackFrames: [],
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
// console.log("StackTraceTab mounted");
|
||||
this.checkForStackTrace();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps: Props<S, A>) {
|
||||
const { action, actions } = prevProps;
|
||||
|
||||
if (action !== this.props.action || actions !== this.props.actions) {
|
||||
|
@ -47,25 +66,32 @@ export default class StackTraceTab extends Component {
|
|||
stack: liftedAction.stack,
|
||||
});
|
||||
|
||||
getStackFrames(deserializedError).then((stackFrames) => {
|
||||
/* eslint-disable no-console */
|
||||
if (process.env.NODE_ENV === 'development')
|
||||
console.log('Stack frames: ', stackFrames);
|
||||
/* eslint-enable no-console */
|
||||
this.setState({ stackFrames, currentError: deserializedError });
|
||||
});
|
||||
getStackFrames(deserializedError)
|
||||
.then((stackFrames) => {
|
||||
/* eslint-disable no-console */
|
||||
if (process.env.NODE_ENV === 'development')
|
||||
console.log('Stack frames: ', stackFrames);
|
||||
/* eslint-enable no-console */
|
||||
this.setState({
|
||||
stackFrames: stackFrames!,
|
||||
currentError: deserializedError,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
// noop
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
stackFrames: [],
|
||||
showDocsLink:
|
||||
liftedAction.action &&
|
||||
liftedAction.action.type &&
|
||||
liftedAction.action.type !== '@@INIT',
|
||||
liftedAction!.action &&
|
||||
liftedAction!.action.type &&
|
||||
liftedAction!.action.type !== '@@INIT',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onStackLocationClicked = (fileLocation = {}) => {
|
||||
onStackLocationClicked = (fileLocation: Partial<ErrorLocation> = {}) => {
|
||||
// console.log("Stack location args: ", ...args);
|
||||
|
||||
const { fileName, lineNumber } = fileLocation;
|
||||
|
@ -93,7 +119,7 @@ export default class StackTraceTab extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
openDocs = (e) => {
|
||||
openDocs: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
|
||||
e.stopPropagation();
|
||||
window.open(
|
||||
'https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/Features/Trace.md'
|
|
@ -1,31 +1,35 @@
|
|||
import StackFrame from './react-error-overlay/utils/stack-frame';
|
||||
|
||||
const isFF = navigator.userAgent.indexOf('Firefox') !== -1;
|
||||
|
||||
function openResource(fileName, lineNumber, stackFrame) {
|
||||
function openResource(
|
||||
fileName: string,
|
||||
lineNumber: number,
|
||||
stackFrame: StackFrame
|
||||
) {
|
||||
const adjustedLineNumber = Math.max(lineNumber - 1, 0);
|
||||
chrome.devtools.panels.openResource(
|
||||
fileName,
|
||||
adjustedLineNumber,
|
||||
(result) => {
|
||||
//console.log("openResource callback args: ", callbackArgs);
|
||||
if (result.isError) {
|
||||
const {
|
||||
fileName: finalFileName,
|
||||
lineNumber: finalLineNumber,
|
||||
} = stackFrame;
|
||||
const adjustedLineNumber = Math.max(finalLineNumber - 1, 0);
|
||||
chrome.devtools.panels.openResource(
|
||||
finalFileName,
|
||||
adjustedLineNumber,
|
||||
(/* result */) => {
|
||||
// console.log("openResource result: ", result);
|
||||
}
|
||||
);
|
||||
}
|
||||
chrome.devtools.panels.openResource(fileName, adjustedLineNumber, ((result: {
|
||||
isError?: boolean;
|
||||
}) => {
|
||||
//console.log("openResource callback args: ", callbackArgs);
|
||||
if (result.isError) {
|
||||
const {
|
||||
fileName: finalFileName,
|
||||
lineNumber: finalLineNumber,
|
||||
} = stackFrame;
|
||||
const adjustedLineNumber = Math.max(finalLineNumber! - 1, 0);
|
||||
chrome.devtools.panels.openResource(
|
||||
finalFileName!,
|
||||
adjustedLineNumber,
|
||||
(/* result */) => {
|
||||
// console.log("openResource result: ", result);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}) as () => void);
|
||||
}
|
||||
|
||||
function openAndCloseTab(url) {
|
||||
function openAndCloseTab(url: string) {
|
||||
chrome.tabs.create({ url }, (tab) => {
|
||||
const removeTab = () => {
|
||||
chrome.windows.onFocusChanged.removeListener(removeTab);
|
||||
|
@ -45,19 +49,19 @@ function openAndCloseTab(url) {
|
|||
});
|
||||
}
|
||||
|
||||
function openInIframe(url) {
|
||||
function openInIframe(url: string) {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = url;
|
||||
iframe.style = 'display:none';
|
||||
iframe.style.display = 'none';
|
||||
document.body.appendChild(iframe);
|
||||
setTimeout(() => iframe.parentNode.removeChild(iframe), 3000);
|
||||
setTimeout(() => iframe.parentNode!.removeChild(iframe), 3000);
|
||||
}
|
||||
|
||||
function openInEditor(editor, path, stackFrame) {
|
||||
function openInEditor(editor: string, path: string, stackFrame: StackFrame) {
|
||||
const projectPath = path.replace(/\/$/, '');
|
||||
const file =
|
||||
stackFrame._originalFileName ||
|
||||
stackFrame.finalFileName ||
|
||||
((stackFrame as unknown) as { finalFileName: string }).finalFileName ||
|
||||
stackFrame.fileName ||
|
||||
'';
|
||||
let filePath = /^https?:\/\//.test(file)
|
||||
|
@ -95,7 +99,11 @@ function openInEditor(editor, path, stackFrame) {
|
|||
}
|
||||
}
|
||||
|
||||
export default function openFile(fileName, lineNumber, stackFrame) {
|
||||
export default function openFile(
|
||||
fileName: string,
|
||||
lineNumber: number,
|
||||
stackFrame: StackFrame
|
||||
) {
|
||||
if (process.env.NODE_ENV === 'development')
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(fileName, lineNumber, stackFrame);
|
|
@ -5,10 +5,9 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import React from 'react';
|
||||
import React, { CSSProperties } from 'react';
|
||||
|
||||
const preStyle = {
|
||||
const preStyle: CSSProperties = {
|
||||
position: 'relative',
|
||||
display: 'block',
|
||||
backgroundColor: '#000',
|
||||
|
@ -24,10 +23,10 @@ const codeStyle = {
|
|||
fontFamily: 'Consolas, Menlo, monospace',
|
||||
};
|
||||
|
||||
type CodeBlockPropsType = {|
|
||||
main: boolean,
|
||||
codeHTML: string,
|
||||
|};
|
||||
interface CodeBlockPropsType {
|
||||
main: boolean;
|
||||
codeHTML: string;
|
||||
}
|
||||
|
||||
function CodeBlock(props: CodeBlockPropsType) {
|
||||
const codeBlock = { __html: props.codeHTML };
|
|
@ -5,13 +5,10 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component, CSSProperties, ReactNode } from 'react';
|
||||
import { nicinabox as theme } from 'redux-devtools-themes';
|
||||
|
||||
import type { Element as ReactElement } from 'react';
|
||||
|
||||
const _collapsibleStyle = {
|
||||
const _collapsibleStyle: CSSProperties = {
|
||||
color: theme.base06,
|
||||
backgroundColor: theme.base01,
|
||||
cursor: 'pointer',
|
||||
|
@ -24,26 +21,27 @@ const _collapsibleStyle = {
|
|||
lineHeight: '1.5',
|
||||
};
|
||||
|
||||
const collapsibleCollapsedStyle = {
|
||||
const collapsibleCollapsedStyle: CSSProperties = {
|
||||
..._collapsibleStyle,
|
||||
marginBottom: '1.5em',
|
||||
};
|
||||
|
||||
const collapsibleExpandedStyle = {
|
||||
const collapsibleExpandedStyle: CSSProperties = {
|
||||
..._collapsibleStyle,
|
||||
marginBottom: '0.6em',
|
||||
};
|
||||
|
||||
type Props = {|
|
||||
children: ReactElement<any>[],
|
||||
|};
|
||||
interface Props {
|
||||
collapsedByDefault?: boolean;
|
||||
children: ReactNode[];
|
||||
}
|
||||
|
||||
type State = {|
|
||||
collapsed: boolean,
|
||||
|};
|
||||
interface State {
|
||||
collapsed: boolean | undefined;
|
||||
}
|
||||
|
||||
class Collapsible extends Component<Props, State> {
|
||||
state = {
|
||||
state: State = {
|
||||
collapsed: undefined,
|
||||
};
|
||||
|
||||
|
@ -53,7 +51,7 @@ class Collapsible extends Component<Props, State> {
|
|||
}));
|
||||
};
|
||||
|
||||
isCollapsed = (state) =>
|
||||
isCollapsed = (state: State) =>
|
||||
state.collapsed === undefined
|
||||
? this.props.collapsedByDefault
|
||||
: state.collapsed;
|
|
@ -5,8 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component, CSSProperties } from 'react';
|
||||
import CodeBlock from './StackFrameCodeBlock';
|
||||
import { getPrettyURL } from '../utils/getPrettyURL';
|
||||
import { nicinabox as theme } from 'redux-devtools-themes';
|
||||
|
@ -14,22 +13,22 @@ import { nicinabox as theme } from 'redux-devtools-themes';
|
|||
import type { StackFrame as StackFrameType } from '../utils/stack-frame';
|
||||
import type { ErrorLocation } from '../utils/parseCompileError';
|
||||
|
||||
const linkStyle = {
|
||||
const linkStyle: CSSProperties = {
|
||||
fontSize: '0.9em',
|
||||
marginBottom: '0.9em',
|
||||
};
|
||||
|
||||
const anchorStyle = {
|
||||
const anchorStyle: CSSProperties = {
|
||||
textDecoration: 'none',
|
||||
color: theme.base05,
|
||||
cursor: 'pointer',
|
||||
};
|
||||
|
||||
const codeAnchorStyle = {
|
||||
const codeAnchorStyle: CSSProperties = {
|
||||
cursor: 'pointer',
|
||||
};
|
||||
|
||||
const toggleStyle = {
|
||||
const toggleStyle: CSSProperties = {
|
||||
marginBottom: '1.5em',
|
||||
color: theme.base05,
|
||||
cursor: 'pointer',
|
||||
|
@ -44,20 +43,20 @@ const toggleStyle = {
|
|||
lineHeight: '1.5',
|
||||
};
|
||||
|
||||
type Props = {|
|
||||
frame: StackFrameType,
|
||||
contextSize: number,
|
||||
critical: boolean,
|
||||
showCode: boolean,
|
||||
editorHandler: (errorLoc: ErrorLocation) => void,
|
||||
|};
|
||||
interface Props {
|
||||
frame: StackFrameType;
|
||||
contextSize: number;
|
||||
critical: boolean;
|
||||
showCode: boolean;
|
||||
editorHandler: (errorLoc: ErrorLocation) => void;
|
||||
}
|
||||
|
||||
type State = {|
|
||||
compiled: boolean,
|
||||
|};
|
||||
interface State {
|
||||
compiled: boolean;
|
||||
}
|
||||
|
||||
class StackFrame extends Component<Props, State> {
|
||||
state = {
|
||||
state: State = {
|
||||
compiled: false,
|
||||
};
|
||||
|
||||
|
@ -93,7 +92,9 @@ class StackFrame extends Component<Props, State> {
|
|||
this.props.editorHandler(errorLoc);
|
||||
};
|
||||
|
||||
onKeyDown = (e /* : SyntheticKeyboardEvent<> */) => {
|
||||
onKeyDown: React.KeyboardEventHandler<HTMLSpanElement> = (
|
||||
e /* : SyntheticKeyboardEvent<> */
|
||||
) => {
|
||||
if (e.key === 'Enter') {
|
||||
this.editorHandler();
|
||||
}
|
||||
|
@ -162,10 +163,10 @@ class StackFrame extends Component<Props, State> {
|
|||
<div>{functionName}</div>
|
||||
<div style={linkStyle}>
|
||||
<span
|
||||
style={canOpenInEditor ? anchorStyle : null}
|
||||
onClick={canOpenInEditor ? this.editorHandler : null}
|
||||
onKeyDown={canOpenInEditor ? this.onKeyDown : null}
|
||||
tabIndex={canOpenInEditor ? '0' : null}
|
||||
style={canOpenInEditor ? anchorStyle : undefined}
|
||||
onClick={canOpenInEditor ? this.editorHandler : undefined}
|
||||
onKeyDown={canOpenInEditor ? this.onKeyDown : undefined}
|
||||
tabIndex={canOpenInEditor ? 0 : undefined}
|
||||
>
|
||||
{url}
|
||||
</span>
|
||||
|
@ -173,8 +174,8 @@ class StackFrame extends Component<Props, State> {
|
|||
{codeBlockProps && (
|
||||
<span>
|
||||
<span
|
||||
onClick={canOpenInEditor ? this.editorHandler : null}
|
||||
style={canOpenInEditor ? codeAnchorStyle : null}
|
||||
onClick={canOpenInEditor ? this.editorHandler : undefined}
|
||||
style={canOpenInEditor ? codeAnchorStyle : undefined}
|
||||
>
|
||||
<CodeBlock {...codeBlockProps} />
|
||||
</span>
|
|
@ -5,40 +5,31 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import React from 'react';
|
||||
import CodeBlock from '../components/CodeBlock';
|
||||
import { applyStyles } from '../utils/dom/css';
|
||||
import { absolutifyCaret } from '../utils/dom/absolutifyCaret';
|
||||
// import type { ScriptLine } from '../utils/stack-frame';
|
||||
import { ScriptLine } from '../utils/stack-frame';
|
||||
import generateAnsiHTML from '../utils/generateAnsiHTML';
|
||||
|
||||
import { codeFrameColumns } from '@babel/code-frame';
|
||||
import { nicinabox as theme } from 'redux-devtools-themes';
|
||||
|
||||
/*
|
||||
type StackFrameCodeBlockPropsType = {|
|
||||
lines: ScriptLine[],
|
||||
lineNum: number,
|
||||
columnNum: ?number,
|
||||
contextSize: number,
|
||||
main: boolean,
|
||||
|};
|
||||
interface StackFrameCodeBlockPropsType {
|
||||
lines: ScriptLine[];
|
||||
lineNum: number;
|
||||
columnNum: number | null | undefined;
|
||||
contextSize: number;
|
||||
main: boolean;
|
||||
}
|
||||
|
||||
// Exact type workaround for spread operator.
|
||||
// See: https://github.com/facebook/flow/issues/2405
|
||||
type Exact<T> = $Shape<T>;
|
||||
*/
|
||||
|
||||
function StackFrameCodeBlock(
|
||||
props /* : Exact<StackFrameCodeBlockPropsType> */
|
||||
) {
|
||||
function StackFrameCodeBlock(props: StackFrameCodeBlockPropsType) {
|
||||
const { lines, lineNum, columnNum, contextSize, main } = props;
|
||||
const sourceCode = [];
|
||||
const sourceCode: string[] = [];
|
||||
let whiteSpace = Infinity;
|
||||
lines.forEach(function (e) {
|
||||
const { content: text } = e;
|
||||
const m = text.match(/^\s*/);
|
||||
const m = /^\s*/.exec(text);
|
||||
if (text === '') {
|
||||
return;
|
||||
}
|
||||
|
@ -86,16 +77,16 @@ function StackFrameCodeBlock(
|
|||
const ccn2 = node.childNodes;
|
||||
for (let index2 = 0; index2 < ccn2.length; ++index2) {
|
||||
const lineNode = ccn2[index2];
|
||||
const text = lineNode.innerText;
|
||||
const text = (lineNode as HTMLElement).innerText;
|
||||
if (text == null) {
|
||||
continue;
|
||||
}
|
||||
if (text.indexOf(' ' + lineNum + ' |') === -1) {
|
||||
if (text.indexOf(` ${lineNum} |`) === -1) {
|
||||
continue;
|
||||
}
|
||||
// $FlowFixMe
|
||||
applyStyles(node, {
|
||||
'background-color': main ? theme.base02 : theme.base01,
|
||||
applyStyles(node as HTMLElement, {
|
||||
backgroundColor: main ? theme.base02 : theme.base01,
|
||||
});
|
||||
// eslint-disable-next-line
|
||||
break oLoop;
|
|
@ -5,8 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component, ReactElement } from 'react';
|
||||
import StackFrame from './StackFrame';
|
||||
import Collapsible from '../components/Collapsible';
|
||||
import { isInternalFile } from '../utils/isInternalFile';
|
||||
|
@ -22,19 +21,19 @@ const traceStyle = {
|
|||
overflow: 'auto',
|
||||
};
|
||||
|
||||
type Props = {|
|
||||
stackFrames: StackFrameType[],
|
||||
errorName: string,
|
||||
contextSize: number,
|
||||
editorHandler: (errorLoc: ErrorLocation) => void,
|
||||
|};
|
||||
interface Props {
|
||||
stackFrames: StackFrameType[];
|
||||
errorName: string;
|
||||
contextSize: number;
|
||||
editorHandler: (errorLoc: ErrorLocation) => void;
|
||||
}
|
||||
|
||||
class StackTrace extends Component<Props> {
|
||||
renderFrames() {
|
||||
const { stackFrames, errorName, contextSize, editorHandler } = this.props;
|
||||
const renderedFrames = [];
|
||||
const renderedFrames: ReactElement[] = [];
|
||||
let hasReachedAppCode = false,
|
||||
currentBundle = [],
|
||||
currentBundle: ReactElement[] = [],
|
||||
bundleCount = 0,
|
||||
anyNodeExpanded = false;
|
||||
|
||||
|
@ -55,7 +54,7 @@ class StackTrace extends Component<Props> {
|
|||
|
||||
const frameEle = (
|
||||
<StackFrame
|
||||
key={'frame-' + index}
|
||||
key={`frame-${index}`}
|
||||
frame={frame}
|
||||
contextSize={contextSize}
|
||||
critical={index === 0}
|
||||
|
@ -77,7 +76,7 @@ class StackTrace extends Component<Props> {
|
|||
renderedFrames.push(
|
||||
<Collapsible
|
||||
collapsedByDefault={anyNodeExpanded}
|
||||
key={'bundle-' + bundleCount}
|
||||
key={`bundle-${bundleCount}`}
|
||||
>
|
||||
{currentBundle}
|
||||
</Collapsible>
|
|
@ -5,8 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
function removeNextBr(parent, component: ?Element) {
|
||||
function removeNextBr(parent: Node, component: Element | null | undefined) {
|
||||
while (component != null && component.tagName.toLowerCase() !== 'br') {
|
||||
component = component.nextElementSibling;
|
||||
}
|
||||
|
@ -18,7 +17,7 @@ function removeNextBr(parent, component: ?Element) {
|
|||
function absolutifyCaret(component: Node) {
|
||||
const ccn = component.childNodes;
|
||||
for (let index = 0; index < ccn.length; ++index) {
|
||||
const c = ccn[index];
|
||||
const c = ccn[index] as HTMLElement;
|
||||
// $FlowFixMe
|
||||
if (c.tagName.toLowerCase() !== 'span') {
|
||||
continue;
|
|
@ -5,9 +5,8 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
let injectedCount = 0;
|
||||
const injectedCache = {};
|
||||
const injectedCache: { [key: number]: HTMLStyleElement } = {};
|
||||
|
||||
function getHead(document: Document) {
|
||||
return document.head || document.getElementsByTagName('head')[0];
|
||||
|
@ -33,14 +32,17 @@ function removeCss(document: Document, ref: number) {
|
|||
delete injectedCache[ref];
|
||||
}
|
||||
|
||||
function applyStyles(element: HTMLElement, styles: Object) {
|
||||
function applyStyles(
|
||||
element: HTMLElement,
|
||||
styles: Partial<CSSStyleDeclaration>
|
||||
) {
|
||||
element.setAttribute('style', '');
|
||||
for (const key in styles) {
|
||||
if (!Object.prototype.hasOwnProperty.call(styles, key)) {
|
||||
continue;
|
||||
}
|
||||
// $FlowFixMe
|
||||
element.style[key] = styles[key];
|
||||
element.style[key] = styles[key]!;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,15 +5,13 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
|
||||
import Anser from 'anser';
|
||||
import { nicinabox as theme } from 'redux-devtools-themes';
|
||||
import { AllHtmlEntities as Entities } from 'html-entities';
|
||||
|
||||
var entities = new Entities();
|
||||
const entities = new Entities();
|
||||
|
||||
var anserMap = {
|
||||
const anserMap = {
|
||||
'ansi-bright-black': theme.base03,
|
||||
'ansi-bright-yellow': theme.base0A,
|
||||
'ansi-yellow': theme.base0B,
|
||||
|
@ -29,25 +27,25 @@ var anserMap = {
|
|||
};
|
||||
|
||||
function generateAnsiHTML(txt: string): string {
|
||||
var arr = new Anser().ansiToJson(entities.encode(txt), {
|
||||
const arr = new Anser().ansiToJson(entities.encode(txt), {
|
||||
use_classes: true,
|
||||
});
|
||||
|
||||
var result = '';
|
||||
var open = false;
|
||||
for (var index = 0; index < arr.length; ++index) {
|
||||
var c = arr[index];
|
||||
var content = c.content,
|
||||
let result = '';
|
||||
let open = false;
|
||||
for (let index = 0; index < arr.length; ++index) {
|
||||
const c = arr[index];
|
||||
const content = c.content,
|
||||
fg = c.fg;
|
||||
|
||||
var contentParts = content.split('\n');
|
||||
for (var _index = 0; _index < contentParts.length; ++_index) {
|
||||
const contentParts = content.split('\n');
|
||||
for (let _index = 0; _index < contentParts.length; ++_index) {
|
||||
if (!open) {
|
||||
result += '<span data-ansi-line="true">';
|
||||
open = true;
|
||||
}
|
||||
var part = contentParts[_index].replace('\r', '');
|
||||
var color = anserMap[fg];
|
||||
const part = contentParts[_index].replace('\r', '');
|
||||
const color = anserMap[fg as keyof typeof anserMap];
|
||||
if (color != null) {
|
||||
result += '<span style="color: ' + color + ';">' + part + '</span>';
|
||||
} else {
|
|
@ -5,7 +5,6 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import { ScriptLine } from './stack-frame';
|
||||
|
||||
/**
|
|
@ -5,14 +5,13 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
function getPrettyURL(
|
||||
sourceFileName: ?string,
|
||||
sourceLineNumber: ?number,
|
||||
sourceColumnNumber: ?number,
|
||||
fileName: ?string,
|
||||
lineNumber: ?number,
|
||||
columnNumber: ?number,
|
||||
sourceFileName: string | null | undefined,
|
||||
sourceLineNumber: number | null | undefined,
|
||||
sourceColumnNumber: number | null | undefined,
|
||||
fileName: string | null | undefined,
|
||||
lineNumber: number | null | undefined,
|
||||
columnNumber: number | null | undefined,
|
||||
compiled: boolean
|
||||
): string {
|
||||
let prettyURL;
|
||||
|
@ -26,16 +25,16 @@ function getPrettyURL(
|
|||
} else {
|
||||
prettyURL = sourceFileName;
|
||||
}
|
||||
prettyURL += ':' + sourceLineNumber;
|
||||
prettyURL += `:${sourceLineNumber}`;
|
||||
// Note: we intentionally skip 0's because they're produced by cheap Webpack maps
|
||||
if (sourceColumnNumber) {
|
||||
prettyURL += ':' + sourceColumnNumber;
|
||||
prettyURL += `:${sourceColumnNumber}`;
|
||||
}
|
||||
} else if (fileName && typeof lineNumber === 'number') {
|
||||
prettyURL = fileName + ':' + lineNumber;
|
||||
prettyURL = `${fileName}:${lineNumber}`;
|
||||
// Note: we intentionally skip 0's because they're produced by cheap Webpack maps
|
||||
if (columnNumber) {
|
||||
prettyURL += ':' + columnNumber;
|
||||
prettyURL += `:${columnNumber}`;
|
||||
}
|
||||
} else {
|
||||
prettyURL = 'unknown';
|
|
@ -5,8 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import { SourceMapConsumer } from 'source-map';
|
||||
import { RawSourceMap, SourceMapConsumer } from 'source-map';
|
||||
|
||||
/**
|
||||
* A wrapped instance of a <code>{@link https://github.com/mozilla/source-map SourceMapConsumer}</code>.
|
||||
|
@ -16,7 +15,7 @@ import { SourceMapConsumer } from 'source-map';
|
|||
class SourceMap {
|
||||
__source_map: SourceMapConsumer;
|
||||
|
||||
constructor(sourceMap) {
|
||||
constructor(sourceMap: SourceMapConsumer) {
|
||||
this.__source_map = sourceMap;
|
||||
}
|
||||
|
||||
|
@ -28,7 +27,7 @@ class SourceMap {
|
|||
getOriginalPosition(
|
||||
line: number,
|
||||
column: number
|
||||
): { source: string, line: number, column: number } {
|
||||
): { source: string; line: number; column: number } {
|
||||
const {
|
||||
line: l,
|
||||
column: c,
|
||||
|
@ -50,7 +49,7 @@ class SourceMap {
|
|||
source: string,
|
||||
line: number,
|
||||
column: number
|
||||
): { line: number, column: number } {
|
||||
): { line: number; column: number } {
|
||||
const { line: l, column: c } = this.__source_map.generatedPositionFor({
|
||||
source,
|
||||
line,
|
||||
|
@ -71,7 +70,7 @@ class SourceMap {
|
|||
}
|
||||
|
||||
getSources(): string[] {
|
||||
return this.__source_map.sources;
|
||||
return ((this.__source_map as unknown) as { sources: string[] }).sources;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +81,7 @@ function extractSourceMapUrl(
|
|||
const regex = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$/gm;
|
||||
let match = null;
|
||||
for (;;) {
|
||||
let next = regex.exec(fileContents);
|
||||
const next = regex.exec(fileContents);
|
||||
if (next == null) {
|
||||
break;
|
||||
}
|
||||
|
@ -107,7 +106,7 @@ async function getSourceMap(
|
|||
let sm = await extractSourceMapUrl(fileUri, fileContents);
|
||||
if (sm.indexOf('data:') === 0) {
|
||||
const base64 = /^data:application\/json;([\w=:"-]+;)*base64,/;
|
||||
const match2 = sm.match(base64);
|
||||
const match2 = base64.exec(sm);
|
||||
if (!match2) {
|
||||
throw new Error(
|
||||
'Sorry, non-base64 inline source-map encoding is not supported.'
|
||||
|
@ -116,7 +115,9 @@ async function getSourceMap(
|
|||
sm = sm.substring(match2[0].length);
|
||||
sm = window.atob(sm);
|
||||
sm = JSON.parse(sm);
|
||||
return new SourceMap(new SourceMapConsumer(sm));
|
||||
return new SourceMap(
|
||||
new SourceMapConsumer((sm as unknown) as RawSourceMap)
|
||||
);
|
||||
} else {
|
||||
const index = fileUri.lastIndexOf('/');
|
||||
const url = fileUri.substring(0, index + 1) + sm;
|
|
@ -5,7 +5,6 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import type { StackFrame } from './stack-frame';
|
||||
import { parse } from './parser';
|
||||
import { map } from './mapper';
|
||||
|
@ -14,15 +13,21 @@ import { toExclude } from '../../presets';
|
|||
|
||||
function getStackFrames(
|
||||
error: Error,
|
||||
unhandledRejection: boolean = false, // eslint-disable-line no-unused-vars
|
||||
contextSize: number = 3
|
||||
unhandledRejection = false, // eslint-disable-line no-unused-vars
|
||||
contextSize = 3
|
||||
): Promise<StackFrame[] | null> {
|
||||
const parsedFrames = parse(error);
|
||||
let enhancedFramesPromise;
|
||||
if (error.__unmap_source) {
|
||||
if (
|
||||
((error as unknown) as {
|
||||
__unmap_source: string | { uri: string; contents: string };
|
||||
}).__unmap_source
|
||||
) {
|
||||
enhancedFramesPromise = unmap(
|
||||
// $FlowFixMe
|
||||
error.__unmap_source,
|
||||
((error as unknown) as {
|
||||
__unmap_source: string | { uri: string; contents: string };
|
||||
}).__unmap_source,
|
||||
parsedFrames,
|
||||
contextSize
|
||||
);
|
||||
|
@ -44,7 +49,7 @@ function getStackFrames(
|
|||
(functionName == null ||
|
||||
functionName.indexOf('__stack_frame_overlay_proxy_console__') ===
|
||||
-1) &&
|
||||
!toExclude.test(fileName)
|
||||
!toExclude.test(fileName!)
|
||||
);
|
||||
});
|
||||
}
|
|
@ -5,8 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
function isBultinErrorName(errorName: ?string) {
|
||||
function isBultinErrorName(errorName: string | null | undefined) {
|
||||
switch (errorName) {
|
||||
case 'EvalError':
|
||||
case 'InternalError':
|
|
@ -5,8 +5,10 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
function isInternalFile(sourceFileName: ?string, fileName: ?string) {
|
||||
function isInternalFile(
|
||||
sourceFileName: string | null | undefined,
|
||||
fileName: string | null | undefined
|
||||
) {
|
||||
return (
|
||||
sourceFileName == null ||
|
||||
sourceFileName === '' ||
|
|
@ -5,7 +5,6 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import StackFrame from './stack-frame';
|
||||
import { getSourceMap } from './getSourceMap';
|
||||
import { getLinesAround } from './getLinesAround';
|
||||
|
@ -18,7 +17,7 @@ import { settle } from 'settle-promise';
|
|||
*/
|
||||
async function map(
|
||||
frames: StackFrame[],
|
||||
contextLines: number = 3
|
||||
contextLines = 3
|
||||
): Promise<StackFrame[]> {
|
||||
const cache: any = {};
|
||||
const files: string[] = [];
|
||||
|
@ -41,7 +40,7 @@ async function map(
|
|||
);
|
||||
return frames.map((frame) => {
|
||||
const { functionName, fileName, lineNumber, columnNumber } = frame;
|
||||
let { map, fileSource } = cache[fileName] || {};
|
||||
const { map, fileSource } = cache[fileName!] || {};
|
||||
if (map == null || lineNumber == null) {
|
||||
return frame;
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
// @flow
|
||||
import Anser from 'anser';
|
||||
|
||||
export type ErrorLocation = {|
|
||||
fileName: string,
|
||||
lineNumber: number,
|
||||
colNumber?: number,
|
||||
|};
|
||||
export interface ErrorLocation {
|
||||
fileName: string;
|
||||
lineNumber: number;
|
||||
colNumber?: number;
|
||||
}
|
||||
|
||||
const filePathRegex = /^\.(\/[^/\n ]+)+\.[^/\n ]+$/;
|
||||
|
||||
|
@ -22,11 +21,11 @@ const lineNumberRegexes = [
|
|||
|
||||
// Based on error formatting of webpack
|
||||
// https://github.com/webpack/webpack/blob/v3.5.5/lib/Stats.js#L183-L217
|
||||
function parseCompileError(message: string): ?ErrorLocation {
|
||||
const lines: Array<string> = message.split('\n');
|
||||
let fileName: string = '';
|
||||
let lineNumber: number = 0;
|
||||
let colNumber: number = 0;
|
||||
function parseCompileError(message: string): ErrorLocation | null | undefined {
|
||||
const lines: string[] = message.split('\n');
|
||||
let fileName = '';
|
||||
let lineNumber = 0;
|
||||
let colNumber = 0;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line: string = Anser.ansiToText(lines[i]).trim();
|
||||
|
@ -34,13 +33,15 @@ function parseCompileError(message: string): ?ErrorLocation {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!fileName && line.match(filePathRegex)) {
|
||||
if (!fileName && filePathRegex.exec(line)) {
|
||||
fileName = line;
|
||||
}
|
||||
|
||||
let k = 0;
|
||||
while (k < lineNumberRegexes.length) {
|
||||
const match: ?Array<string> = line.match(lineNumberRegexes[k]);
|
||||
const match: string[] | null | undefined = lineNumberRegexes[k].exec(
|
||||
line
|
||||
);
|
||||
if (match) {
|
||||
lineNumber = parseInt(match[1], 10);
|
||||
// colNumber starts with 0 and hence add 1
|
|
@ -5,14 +5,13 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import StackFrame from './stack-frame';
|
||||
|
||||
const regexExtractLocation = /\(?(.+?)(?::(\d+))?(?::(\d+))?\)?$/;
|
||||
|
||||
function extractLocation(token: string): [string, number, number] {
|
||||
return regexExtractLocation
|
||||
.exec(token)
|
||||
.exec(token)!
|
||||
.slice(1)
|
||||
.map((v) => {
|
||||
const p = Number(v);
|
||||
|
@ -20,7 +19,7 @@ function extractLocation(token: string): [string, number, number] {
|
|||
return p;
|
||||
}
|
||||
return v;
|
||||
});
|
||||
}) as [string, number, number];
|
||||
}
|
||||
|
||||
const regexValidFrame_Chrome = /^\s*(at|in)\s.+(:\d+)/;
|
||||
|
@ -46,7 +45,7 @@ function parseStack(stack: string[]): StackFrame[] {
|
|||
const last = data.pop();
|
||||
return new StackFrame(
|
||||
data.join('@') || (isEval ? 'eval' : null),
|
||||
...extractLocation(last)
|
||||
...extractLocation(last!)
|
||||
);
|
||||
} else {
|
||||
// Strip eval, we don't care about it
|
||||
|
@ -58,7 +57,10 @@ function parseStack(stack: string[]): StackFrame[] {
|
|||
}
|
||||
const data = e.trim().split(/\s+/g).slice(1);
|
||||
const last = data.pop();
|
||||
return new StackFrame(data.join(' ') || null, ...extractLocation(last));
|
||||
return new StackFrame(
|
||||
data.join(' ') || null,
|
||||
...extractLocation(last!)
|
||||
);
|
||||
}
|
||||
});
|
||||
return frames;
|
|
@ -9,6 +9,7 @@ if (typeof Promise === 'undefined') {
|
|||
// Rejection tracking prevents a common issue where React gets into an
|
||||
// inconsistent state due to an error, but it gets swallowed by a Promise,
|
||||
// and the user has no idea what causes React's erratic future behavior.
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
require('promise/lib/rejection-tracking').enable();
|
||||
window.Promise = require('promise/lib/es6-extensions.js');
|
||||
}
|
|
@ -5,8 +5,6 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
|
||||
/** A container holding a script line. */
|
||||
class ScriptLine {
|
||||
/** The line number of this line of source. */
|
||||
|
@ -16,7 +14,7 @@ class ScriptLine {
|
|||
/** Whether or not this line should be highlighted. Particularly useful for error reporting with context. */
|
||||
highlight: boolean;
|
||||
|
||||
constructor(lineNumber: number, content: string, highlight: boolean = false) {
|
||||
constructor(lineNumber: number, content: string, highlight = false) {
|
||||
this.lineNumber = lineNumber;
|
||||
this.content = content;
|
||||
this.highlight = highlight;
|
||||
|
@ -98,10 +96,10 @@ class StackFrame {
|
|||
str += this.fileName + ':';
|
||||
}
|
||||
if (this.lineNumber != null) {
|
||||
str += this.lineNumber + ':';
|
||||
str += `${this.lineNumber}:`;
|
||||
}
|
||||
if (this.columnNumber != null) {
|
||||
str += this.columnNumber + ':';
|
||||
str += `${this.columnNumber}:`;
|
||||
}
|
||||
return str.slice(0, -1);
|
||||
}
|
|
@ -5,7 +5,6 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import StackFrame from './stack-frame';
|
||||
import { getSourceMap } from './getSourceMap';
|
||||
import { getLinesAround } from './getLinesAround';
|
||||
|
@ -32,16 +31,16 @@ function count(search: string, string: string): number {
|
|||
* @param {number} [fileContents=3] The number of lines to provide before and after the line specified in the <code>StackFrame</code>.
|
||||
*/
|
||||
async function unmap(
|
||||
_fileUri: string | { uri: string, contents: string },
|
||||
_fileUri: string | { uri: string; contents: string },
|
||||
frames: StackFrame[],
|
||||
contextLines: number = 3
|
||||
contextLines = 3
|
||||
): Promise<StackFrame[]> {
|
||||
let fileContents = typeof _fileUri === 'object' ? _fileUri.contents : null;
|
||||
let fileUri = typeof _fileUri === 'object' ? _fileUri.uri : _fileUri;
|
||||
const fileUri = typeof _fileUri === 'object' ? _fileUri.uri : _fileUri;
|
||||
if (fileContents == null) {
|
||||
fileContents = await fetch(fileUri).then((res) => res.text());
|
||||
}
|
||||
const map = await getSourceMap(fileUri, fileContents);
|
||||
const map = await getSourceMap(fileUri, fileContents!);
|
||||
return frames.map((frame) => {
|
||||
const {
|
||||
functionName,
|
||||
|
@ -104,7 +103,7 @@ async function unmap(
|
|||
sourceT,
|
||||
lineNumber,
|
||||
// $FlowFixMe
|
||||
columnNumber
|
||||
columnNumber!
|
||||
);
|
||||
const originalSource = map.getSource(sourceT);
|
||||
return new StackFrame(
|
|
@ -0,0 +1,3 @@
|
|||
declare module 'settle-promise' {
|
||||
export function settle(promises: Promise<void>[]): Promise<void>;
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
import React from 'react';
|
||||
import { configure, mount } from 'enzyme';
|
||||
import toJson from 'enzyme-to-json';
|
||||
import StackTraceTab from '../src/StackTraceTab';
|
||||
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
configure({ adapter: new Adapter() });
|
||||
|
||||
function genAsyncSnapshot(component, done) {
|
||||
setTimeout(() => {
|
||||
component.update();
|
||||
expect(toJson(component)).toMatchSnapshot();
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
const actions = {
|
||||
0: { type: 'PERFORM_ACTION', action: { type: '@@INIT' } },
|
||||
1: { type: 'PERFORM_ACTION', action: { type: 'INCREMENT_COUNTER' } },
|
||||
2: {
|
||||
type: 'PERFORM_ACTION',
|
||||
action: { type: 'INCREMENT_COUNTER' },
|
||||
stack:
|
||||
'Error\n at fn1 (app.js:72:24)\n at fn2 (app.js:84:31)\n ' +
|
||||
'at fn3 (chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljd/js/page.bundle.js:1269:80)',
|
||||
},
|
||||
};
|
||||
|
||||
describe('StackTraceTab component', () => {
|
||||
it('should render with no props', (done) => {
|
||||
const component = mount(<StackTraceTab />);
|
||||
genAsyncSnapshot(component, done);
|
||||
});
|
||||
|
||||
it('should render with props, but without stack', (done) => {
|
||||
const component = mount(
|
||||
<StackTraceTab actions={actions} action={actions[0].action} />
|
||||
);
|
||||
genAsyncSnapshot(component, done);
|
||||
});
|
||||
|
||||
it('should render the link to docs', (done) => {
|
||||
const component = mount(
|
||||
<StackTraceTab actions={actions} action={actions[1].action} />
|
||||
);
|
||||
genAsyncSnapshot(component, done);
|
||||
});
|
||||
|
||||
it('should render with trace stack', (done) => {
|
||||
const component = mount(
|
||||
<StackTraceTab actions={actions} action={actions[2].action} />
|
||||
);
|
||||
genAsyncSnapshot(component, done);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,68 @@
|
|||
import React, { ReactComponentElement } from 'react';
|
||||
import { configure, mount, ReactWrapper } from 'enzyme';
|
||||
import toJson from 'enzyme-to-json';
|
||||
import StackTraceTab from '../src/StackTraceTab';
|
||||
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
configure({ adapter: new Adapter() });
|
||||
|
||||
function genAsyncSnapshot(
|
||||
component: ReactWrapper<any, any, any>,
|
||||
done: () => void
|
||||
) {
|
||||
setTimeout(() => {
|
||||
component.update();
|
||||
expect(toJson(component)).toMatchSnapshot();
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
const actions = {
|
||||
0: { type: 'PERFORM_ACTION', action: { type: '@@INIT' } },
|
||||
1: { type: 'PERFORM_ACTION', action: { type: 'INCREMENT_COUNTER' } },
|
||||
2: {
|
||||
type: 'PERFORM_ACTION',
|
||||
action: { type: 'INCREMENT_COUNTER' },
|
||||
stack:
|
||||
'Error\n at fn1 (app.js:72:24)\n at fn2 (app.js:84:31)\n ' +
|
||||
'at fn3 (chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljd/js/page.bundle.js:1269:80)',
|
||||
},
|
||||
};
|
||||
|
||||
const StackTraceTabAsAny = StackTraceTab as any;
|
||||
|
||||
describe('StackTraceTab component', () => {
|
||||
it('should render with no props', () => {
|
||||
return new Promise((done) => {
|
||||
const component = mount(<StackTraceTabAsAny />);
|
||||
genAsyncSnapshot(component, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render with props, but without stack', () => {
|
||||
return new Promise((done) => {
|
||||
const component = mount(
|
||||
<StackTraceTabAsAny actions={actions} action={actions[0].action} />
|
||||
);
|
||||
genAsyncSnapshot(component, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the link to docs', () => {
|
||||
return new Promise((done) => {
|
||||
const component = mount(
|
||||
<StackTraceTabAsAny actions={actions} action={actions[1].action} />
|
||||
);
|
||||
genAsyncSnapshot(component, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render with trace stack', () => {
|
||||
return new Promise((done) => {
|
||||
const component = mount(
|
||||
<StackTraceTabAsAny actions={actions} action={actions[2].action} />
|
||||
);
|
||||
genAsyncSnapshot(component, done);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -301,12 +301,7 @@ exports[`StackTraceTab component should render with trace stack 1`] = `
|
|||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
onClick={null}
|
||||
onKeyDown={null}
|
||||
style={null}
|
||||
tabIndex={null}
|
||||
>
|
||||
<span>
|
||||
app.js:72:24
|
||||
</span>
|
||||
</div>
|
||||
|
@ -345,12 +340,7 @@ exports[`StackTraceTab component should render with trace stack 1`] = `
|
|||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
onClick={null}
|
||||
onKeyDown={null}
|
||||
style={null}
|
||||
tabIndex={null}
|
||||
>
|
||||
<span>
|
||||
app.js:84:31
|
||||
</span>
|
||||
</div>
|
4
packages/redux-devtools-trace-monitor/test/tsconfig.json
Normal file
4
packages/redux-devtools-trace-monitor/test/tsconfig.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.react.base.json",
|
||||
"include": ["../src", "."]
|
||||
}
|
7
packages/redux-devtools-trace-monitor/tsconfig.json
Normal file
7
packages/redux-devtools-trace-monitor/tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "../../tsconfig.react.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
|
@ -8,6 +8,6 @@
|
|||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
// See https://github.com/DefinitelyTyped/DefinitelyTyped/issues/33311
|
||||
"types": ["node", "jest", "webpack-env"]
|
||||
"types": ["node", "jest", "webpack-env", "chrome"]
|
||||
}
|
||||
}
|
||||
|
|
39
yarn.lock
39
yarn.lock
|
@ -378,7 +378,7 @@
|
|||
"@babel/helper-create-class-features-plugin" "^7.10.4"
|
||||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
|
||||
"@babel/plugin-proposal-decorators@^7.10.5", "@babel/plugin-proposal-decorators@^7.8.3":
|
||||
"@babel/plugin-proposal-decorators@^7.8.3":
|
||||
version "7.10.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.5.tgz#42898bba478bc4b1ae242a703a953a7ad350ffb4"
|
||||
integrity sha512-Sc5TAQSZuLzgY0664mMDn24Vw2P8g/VhyLyGPaWiHahhgLqeZvcGeyBZOrJW0oSKIK2mvQ22a1ENXBIQLhrEiQ==
|
||||
|
@ -1110,7 +1110,7 @@
|
|||
levenary "^1.1.1"
|
||||
semver "^5.5.0"
|
||||
|
||||
"@babel/preset-flow@^7.0.0", "@babel/preset-flow@^7.10.4":
|
||||
"@babel/preset-flow@^7.0.0":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.10.4.tgz#e0d9c72f8cb02d1633f6a5b7b16763aa2edf659f"
|
||||
integrity sha512-XI6l1CptQCOBv+ZKYwynyswhtOKwpZZp5n0LG1QKCo8erRhqjoQV6nvx61Eg30JHpysWQSBwA2AWRU3pBbSY5g==
|
||||
|
@ -3251,6 +3251,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
|
||||
integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==
|
||||
|
||||
"@types/babel__code-frame@^7.0.2":
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__code-frame/-/babel__code-frame-7.0.2.tgz#e0c0f1648cbc09a9d4e5b4ed2ae9a6f7c8f5aeb0"
|
||||
integrity sha512-imO+jT/yjOKOAS5GQZ8SDtwiIloAGGr6OaZDKB0V5JVaSfGZLat5K5/ZRtyKW6R60XHV3RHYPTFfhYb+wDKyKg==
|
||||
|
||||
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
|
||||
version "7.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.9.tgz#77e59d438522a6fb898fa43dc3455c6e72f3963d"
|
||||
|
@ -3309,6 +3314,14 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/chrome@^0.0.124":
|
||||
version "0.0.124"
|
||||
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.124.tgz#1cdb8e1c1ddb04b15844f5a71b9907f73bbb84a2"
|
||||
integrity sha512-0UmDQ6A9gaahvztKryIonSTyUMEhuhKNyyJAnBB7ZJN/YXP7YRkL4onPFSTxnIbXcMnYsQFo8TxsGP8jY2mdEw==
|
||||
dependencies:
|
||||
"@types/filesystem" "*"
|
||||
"@types/har-format" "*"
|
||||
|
||||
"@types/classnames@^2.2.10":
|
||||
version "2.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999"
|
||||
|
@ -3419,6 +3432,18 @@
|
|||
"@types/qs" "*"
|
||||
"@types/serve-static" "*"
|
||||
|
||||
"@types/filesystem@*":
|
||||
version "0.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.29.tgz#ee3748eb5be140dcf980c3bd35f11aec5f7a3748"
|
||||
integrity sha512-85/1KfRedmfPGsbK8YzeaQUyV1FQAvMPMTuWFQ5EkLd2w7szhNO96bk3Rh/SKmOfd9co2rCLf0Voy4o7ECBOvw==
|
||||
dependencies:
|
||||
"@types/filewriter" "*"
|
||||
|
||||
"@types/filewriter@*":
|
||||
version "0.0.28"
|
||||
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3"
|
||||
integrity sha1-wFTor02d11205jq8dviFFocU1LM=
|
||||
|
||||
"@types/glob-base@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob-base/-/glob-base-0.3.0.tgz#a581d688347e10e50dd7c17d6f2880a10354319d"
|
||||
|
@ -3439,6 +3464,11 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/har-format@*":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.4.tgz#3275842095abb60d14b47fa798cc9ff708dab6d4"
|
||||
integrity sha512-iUxzm1meBm3stxUMzRqgOVHjj4Kgpgu5w9fm4X7kPRfSgVRzythsucEN7/jtOo8SQzm+HfcxWWzJS0mJDH/3DQ==
|
||||
|
||||
"@types/hast@^2.0.0":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.1.tgz#b16872f2a6144c7025f296fb9636a667ebb79cd9"
|
||||
|
@ -3464,6 +3494,11 @@
|
|||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
"@types/html-entities@^1.2.16":
|
||||
version "1.2.16"
|
||||
resolved "https://registry.yarnpkg.com/@types/html-entities/-/html-entities-1.2.16.tgz#4d1fe208c4c33727ac4657e6f5d92bfe52427023"
|
||||
integrity sha512-CI6fHfFvkTtX2Nlr4JBA6yIFTfA4p9E6w9ky64X6PrfXiTALhUh/SOa+Sxvv2p87m+y5AH71lAUrx0lSYx4hKQ==
|
||||
|
||||
"@types/html-minifier-terser@^5.0.0":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880"
|
||||
|
|
Loading…
Reference in New Issue
Block a user