From d37e7d93e13db8ba0c511e5dae4c136c40ef4100 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Mon, 28 Sep 2020 21:06:02 -0400 Subject: [PATCH 01/25] chore(test): use @types/packages internally (#646) --- .../package.json | 2 + .../src/es6template.ts | 6 -- .../src/simple-diff.ts | 64 ------------------- yarn.lock | 17 +++-- 4 files changed, 13 insertions(+), 76 deletions(-) delete mode 100644 packages/redux-devtools-test-generator/src/es6template.ts delete mode 100644 packages/redux-devtools-test-generator/src/simple-diff.ts diff --git a/packages/redux-devtools-test-generator/package.json b/packages/redux-devtools-test-generator/package.json index 31684bd0..12fddd16 100644 --- a/packages/redux-devtools-test-generator/package.json +++ b/packages/redux-devtools-test-generator/package.json @@ -54,6 +54,7 @@ "simple-diff": "^1.6.0" }, "devDependencies": { + "@types/es6template": "^1.0.0", "@types/history": "^4.7.7", "@types/jsan": "^3.1.0", "@types/lodash.shuffle": "^4.2.6", @@ -61,6 +62,7 @@ "@types/react": "^16.9.46", "@types/react-router": "^5.1.8", "@types/redux-logger": "^3.0.8", + "@types/simple-diff": "^1.6.0", "connected-react-router": "^6.8.0", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.3", diff --git a/packages/redux-devtools-test-generator/src/es6template.ts b/packages/redux-devtools-test-generator/src/es6template.ts deleted file mode 100644 index 9828d0ef..00000000 --- a/packages/redux-devtools-test-generator/src/es6template.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'es6template' { - const _default: { - compile(template: string): (locals: Locals) => string; - }; - export default _default; -} diff --git a/packages/redux-devtools-test-generator/src/simple-diff.ts b/packages/redux-devtools-test-generator/src/simple-diff.ts deleted file mode 100644 index e5fcafff..00000000 --- a/packages/redux-devtools-test-generator/src/simple-diff.ts +++ /dev/null @@ -1,64 +0,0 @@ -declare module 'simple-diff' { - interface AddEvent { - oldPath: (string | number)[]; - newPath: (string | number)[]; - type: 'add'; - oldValue: undefined; - newValue: unknown; - } - - interface RemoveEvent { - oldPath: (string | number)[]; - newPath: (string | number)[]; - type: 'remove'; - oldValue: unknown; - newValue: undefined; - } - - interface ChangeEvent { - oldPath: (string | number)[]; - newPath: (string | number)[]; - type: 'change'; - oldValue: unknown; - newValue: unknown; - } - - interface AddItemEvent { - oldPath: (string | number)[]; - newPath: (string | number)[]; - type: 'add-item'; - oldIndex: -1; - curIndex: -1; - newIndex: number; - newValue: unknown; - } - - interface RemoveItemEvent { - oldPath: (string | number)[]; - newPath: (string | number)[]; - type: 'remove-item'; - oldIndex: number; - curIndex: number; - newIndex: -1; - oldValue: unknown; - } - - interface MoveItemEvent { - oldPath: (string | number)[]; - newPath: (string | number)[]; - type: 'move-item'; - oldIndex: number; - curIndex: number; - newIndex: number; - } - - export type Event = - | AddEvent - | RemoveEvent - | ChangeEvent - | AddItemEvent - | RemoveItemEvent - | MoveItemEvent; - - export default function (oldObj: unknown, newObj: unknown): Event[]; -} diff --git a/yarn.lock b/yarn.lock index 58a70246..c6d78b92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -395,7 +395,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import" "^7.8.0" -"@babel/plugin-proposal-export-default-from@^7.10.4", "@babel/plugin-proposal-export-default-from@^7.8.3": +"@babel/plugin-proposal-export-default-from@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.10.4.tgz#08f66eef0067cbf6a7bc036977dcdccecaf0c6c5" integrity sha512-G1l00VvDZ7Yk2yRlC5D8Ybvu3gmeHS3rCHoUYdjrqGYUtdeOBoRypnvDZ5KQqxyaiiGHWnVDeSEzA5F9ozItig== @@ -3385,6 +3385,11 @@ "@types/cheerio" "*" "@types/react" "*" +"@types/es6template@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/es6template/-/es6template-1.0.0.tgz#aeff9046c3332b587a65485a8383292afba82b10" + integrity sha512-wvlFvfUd3FAJyRhgjfibljYSPJ/XKmB3sSlPV+1P5dinRmdSE0lYOFXfJ/ZiWSfBN0Cex5MENBUw8kjsvft+8w== + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -3822,6 +3827,11 @@ "@types/express-serve-static-core" "*" "@types/mime" "*" +"@types/simple-diff@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@types/simple-diff/-/simple-diff-1.6.0.tgz#f27f0a9a849a97695795a46e5b91ad86bbe66986" + integrity sha512-qWru8xXShCbzXVk1YbQ1nomukLjTvF/FZ1BKxQBAp4UHuVxjsXvc6mur2WFXWHcRjDl9FAS7BygfCenDNjbsog== + "@types/simple-element-resize-detector@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@types/simple-element-resize-detector/-/simple-element-resize-detector-1.3.0.tgz#19b40d71fefa1876ac5d4ba585197ef438946353" @@ -14408,11 +14418,6 @@ react-popper@^1.3.7: typed-styles "^0.0.7" warning "^4.0.2" -react-pure-render@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/react-pure-render/-/react-pure-render-1.0.2.tgz#9d8a928c7f2c37513c2d064e57b3e3c356e9fabb" - integrity sha1-nYqSjH8sN1E8LQZOV7Pjw1bp+rs= - react-redux@^7.2.1: version "7.2.1" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985" From 03217001dfd28c79929b0917bf0bf0e5d0945247 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Tue, 29 Sep 2020 09:37:13 -0400 Subject: [PATCH 02/25] 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 --- .../package.json | 1 + .../redux-devtools-trace-monitor/.babelrc | 17 ++--- .../.eslintignore | 1 + .../redux-devtools-trace-monitor/.eslintrc.js | 21 ++++++ .../jest.config.js | 3 + .../redux-devtools-trace-monitor/package.json | 66 +++++++++++------- .../{StackTraceTab.js => StackTraceTab.tsx} | 66 ++++++++++++------ .../src/{openFile.js => openFile.ts} | 64 +++++++++-------- .../src/{presets.js => presets.ts} | 0 .../{CodeBlock.js => CodeBlock.tsx} | 13 ++-- .../{Collapsible.js => Collapsible.tsx} | 28 ++++---- .../{StackFrame.js => StackFrame.tsx} | 49 ++++++------- ...meCodeBlock.js => StackFrameCodeBlock.tsx} | 39 ++++------- .../{StackTrace.js => StackTrace.tsx} | 23 +++---- ...{absolutifyCaret.js => absolutifyCaret.ts} | 5 +- .../utils/dom/{css.js => css.ts} | 10 +-- ...enerateAnsiHTML.js => generateAnsiHTML.ts} | 26 ++++--- .../{getLinesAround.js => getLinesAround.ts} | 1 - .../{getPrettyURL.js => getPrettyURL.ts} | 21 +++--- .../{getSourceMap.js => getSourceMap.ts} | 19 +++--- .../{getStackFrames.js => getStackFrames.ts} | 17 +++-- ...ultinErrorName.js => isBultinErrorName.ts} | 3 +- .../{isInternalFile.js => isInternalFile.ts} | 6 +- .../utils/{mapper.js => mapper.ts} | 5 +- ...seCompileError.js => parseCompileError.ts} | 27 ++++---- .../utils/{parser.js => parser.ts} | 12 ++-- .../utils/{pollyfills.js => pollyfills.ts} | 1 + .../utils/{stack-frame.js => stack-frame.ts} | 8 +-- .../utils/{unmapper.js => unmapper.ts} | 11 ++- .../src/settle-promise.ts | 3 + .../test/StackTraceTab.spec.js | 55 --------------- .../test/StackTraceTab.spec.tsx | 68 +++++++++++++++++++ ...ec.js.snap => StackTraceTab.spec.tsx.snap} | 14 +--- .../test/tsconfig.json | 4 ++ .../tsconfig.json | 7 ++ tsconfig.base.json | 2 +- yarn.lock | 39 ++++++++++- 37 files changed, 434 insertions(+), 321 deletions(-) create mode 100644 packages/redux-devtools-trace-monitor/.eslintignore create mode 100644 packages/redux-devtools-trace-monitor/.eslintrc.js create mode 100644 packages/redux-devtools-trace-monitor/jest.config.js rename packages/redux-devtools-trace-monitor/src/{StackTraceTab.js => StackTraceTab.tsx} (66%) rename packages/redux-devtools-trace-monitor/src/{openFile.js => openFile.ts} (75%) rename packages/redux-devtools-trace-monitor/src/{presets.js => presets.ts} (100%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/components/{CodeBlock.js => CodeBlock.tsx} (82%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/components/{Collapsible.js => Collapsible.tsx} (81%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/{StackFrame.js => StackFrame.tsx} (80%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/{StackFrameCodeBlock.js => StackFrameCodeBlock.tsx} (76%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/{StackTrace.js => StackTrace.tsx} (86%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/{absolutifyCaret.js => absolutifyCaret.ts} (88%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/{css.js => css.ts} (84%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{generateAnsiHTML.js => generateAnsiHTML.ts} (75%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{getLinesAround.js => getLinesAround.ts} (98%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{getPrettyURL.js => getPrettyURL.ts} (71%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{getSourceMap.js => getSourceMap.ts} (90%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{getStackFrames.js => getStackFrames.ts} (76%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{isBultinErrorName.js => isBultinErrorName.ts} (88%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{isInternalFile.js => isInternalFile.ts} (81%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{mapper.js => mapper.ts} (95%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{parseCompileError.js => parseCompileError.ts} (71%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{parser.js => parser.ts} (92%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{pollyfills.js => pollyfills.ts} (91%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{stack-frame.js => stack-frame.ts} (95%) rename packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/{unmapper.js => unmapper.ts} (93%) create mode 100644 packages/redux-devtools-trace-monitor/src/settle-promise.ts delete mode 100644 packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.js create mode 100644 packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.tsx rename packages/redux-devtools-trace-monitor/test/__snapshots__/{StackTraceTab.spec.js.snap => StackTraceTab.spec.tsx.snap} (95%) create mode 100644 packages/redux-devtools-trace-monitor/test/tsconfig.json create mode 100644 packages/redux-devtools-trace-monitor/tsconfig.json diff --git a/packages/redux-devtools-test-generator/package.json b/packages/redux-devtools-test-generator/package.json index 12fddd16..d87a8255 100644 --- a/packages/redux-devtools-test-generator/package.json +++ b/packages/redux-devtools-test-generator/package.json @@ -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" } } diff --git a/packages/redux-devtools-trace-monitor/.babelrc b/packages/redux-devtools-trace-monitor/.babelrc index 2a38a7b6..0d42ef44 100644 --- a/packages/redux-devtools-trace-monitor/.babelrc +++ b/packages/redux-devtools-trace-monitor/.babelrc @@ -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"] } diff --git a/packages/redux-devtools-trace-monitor/.eslintignore b/packages/redux-devtools-trace-monitor/.eslintignore new file mode 100644 index 00000000..a65b4177 --- /dev/null +++ b/packages/redux-devtools-trace-monitor/.eslintignore @@ -0,0 +1 @@ +lib diff --git a/packages/redux-devtools-trace-monitor/.eslintrc.js b/packages/redux-devtools-trace-monitor/.eslintrc.js new file mode 100644 index 00000000..eca0de40 --- /dev/null +++ b/packages/redux-devtools-trace-monitor/.eslintrc.js @@ -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'], + }, + }, + ], +}; diff --git a/packages/redux-devtools-trace-monitor/jest.config.js b/packages/redux-devtools-trace-monitor/jest.config.js new file mode 100644 index 00000000..8824c114 --- /dev/null +++ b/packages/redux-devtools-trace-monitor/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: 'ts-jest', +}; diff --git a/packages/redux-devtools-trace-monitor/package.json b/packages/redux-devtools-trace-monitor/package.json index d00d1548..f88b764a 100644 --- a/packages/redux-devtools-trace-monitor/package.json +++ b/packages/redux-devtools-trace-monitor/package.json @@ -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 ", "contributors": [ "Mihail Diordiev (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" } } diff --git a/packages/redux-devtools-trace-monitor/src/StackTraceTab.js b/packages/redux-devtools-trace-monitor/src/StackTraceTab.tsx similarity index 66% rename from packages/redux-devtools-trace-monitor/src/StackTraceTab.js rename to packages/redux-devtools-trace-monitor/src/StackTraceTab.tsx index 17414b63..9d39ac14 100644 --- a/packages/redux-devtools-trace-monitor/src/StackTraceTab.js +++ b/packages/redux-devtools-trace-monitor/src/StackTraceTab.tsx @@ -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> extends TabComponentProps { + openFile: ( + fileName: string, + lineNumber: number, + stackFrame: StackFrame + ) => void; +} + +interface State { + stackFrames: StackFrame[]; + currentError?: Error; + showDocsLink?: boolean; +} + +export default class StackTraceTab< + S, + A extends Action +> extends Component, 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) { 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 = {}) => { // 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 = (e) => { e.stopPropagation(); window.open( 'https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/Features/Trace.md' diff --git a/packages/redux-devtools-trace-monitor/src/openFile.js b/packages/redux-devtools-trace-monitor/src/openFile.ts similarity index 75% rename from packages/redux-devtools-trace-monitor/src/openFile.js rename to packages/redux-devtools-trace-monitor/src/openFile.ts index 2e257edb..bbf11a91 100644 --- a/packages/redux-devtools-trace-monitor/src/openFile.js +++ b/packages/redux-devtools-trace-monitor/src/openFile.ts @@ -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); diff --git a/packages/redux-devtools-trace-monitor/src/presets.js b/packages/redux-devtools-trace-monitor/src/presets.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/presets.js rename to packages/redux-devtools-trace-monitor/src/presets.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/CodeBlock.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/CodeBlock.tsx similarity index 82% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/components/CodeBlock.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/components/CodeBlock.tsx index f9058424..2c3a1b2c 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/CodeBlock.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/CodeBlock.tsx @@ -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 }; diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/Collapsible.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/Collapsible.tsx similarity index 81% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/components/Collapsible.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/components/Collapsible.tsx index 6f6f565c..07e81b64 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/Collapsible.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/Collapsible.tsx @@ -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[], -|}; +interface Props { + collapsedByDefault?: boolean; + children: ReactNode[]; +} -type State = {| - collapsed: boolean, -|}; +interface State { + collapsed: boolean | undefined; +} class Collapsible extends Component { - state = { + state: State = { collapsed: undefined, }; @@ -53,7 +51,7 @@ class Collapsible extends Component { })); }; - isCollapsed = (state) => + isCollapsed = (state: State) => state.collapsed === undefined ? this.props.collapsedByDefault : state.collapsed; diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrame.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrame.tsx similarity index 80% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrame.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrame.tsx index ba3cbf4b..9ef06708 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrame.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrame.tsx @@ -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 { - state = { + state: State = { compiled: false, }; @@ -93,7 +92,9 @@ class StackFrame extends Component { this.props.editorHandler(errorLoc); }; - onKeyDown = (e /* : SyntheticKeyboardEvent<> */) => { + onKeyDown: React.KeyboardEventHandler = ( + e /* : SyntheticKeyboardEvent<> */ + ) => { if (e.key === 'Enter') { this.editorHandler(); } @@ -162,10 +163,10 @@ class StackFrame extends Component {
{functionName}
{url} @@ -173,8 +174,8 @@ class StackFrame extends Component { {codeBlockProps && ( diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrameCodeBlock.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrameCodeBlock.tsx similarity index 76% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrameCodeBlock.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrameCodeBlock.tsx index 4045ab5e..753c2e06 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrameCodeBlock.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrameCodeBlock.tsx @@ -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 = $Shape; -*/ - -function StackFrameCodeBlock( - props /* : Exact */ -) { +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; diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackTrace.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackTrace.tsx similarity index 86% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackTrace.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackTrace.tsx index 35963caf..6369fe96 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackTrace.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackTrace.tsx @@ -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 { 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 { const frameEle = ( { renderedFrames.push( {currentBundle} diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/absolutifyCaret.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/absolutifyCaret.ts similarity index 88% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/absolutifyCaret.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/absolutifyCaret.ts index 9049069c..7bebf317 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/absolutifyCaret.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/absolutifyCaret.ts @@ -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; diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/css.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/css.ts similarity index 84% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/css.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/css.ts index 3c71ba69..8791ecb2 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/css.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/css.ts @@ -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 +) { 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]!; } } diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/generateAnsiHTML.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/generateAnsiHTML.ts similarity index 75% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/generateAnsiHTML.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/generateAnsiHTML.ts index 747845a4..e35d7a29 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/generateAnsiHTML.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/generateAnsiHTML.ts @@ -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 += ''; 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 += '' + part + ''; } else { diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getLinesAround.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getLinesAround.ts similarity index 98% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getLinesAround.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getLinesAround.ts index 4a7ffc34..dcaba0ce 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getLinesAround.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getLinesAround.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -/* @flow */ import { ScriptLine } from './stack-frame'; /** diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getPrettyURL.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getPrettyURL.ts similarity index 71% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getPrettyURL.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getPrettyURL.ts index 1aa5dc77..894da6f3 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getPrettyURL.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getPrettyURL.ts @@ -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'; diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getSourceMap.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getSourceMap.ts similarity index 90% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getSourceMap.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getSourceMap.ts index 644847bb..0157204a 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getSourceMap.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getSourceMap.ts @@ -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 {@link https://github.com/mozilla/source-map SourceMapConsumer}. @@ -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; diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getStackFrames.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getStackFrames.ts similarity index 76% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getStackFrames.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getStackFrames.ts index f7d3984d..9021713a 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getStackFrames.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getStackFrames.ts @@ -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 { 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!) ); }); } diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isBultinErrorName.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isBultinErrorName.ts similarity index 88% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isBultinErrorName.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isBultinErrorName.ts index 570f72cf..f7a82b3a 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isBultinErrorName.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isBultinErrorName.ts @@ -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': diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isInternalFile.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isInternalFile.ts similarity index 81% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isInternalFile.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isInternalFile.ts index 97dbeaae..9c916d4b 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isInternalFile.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isInternalFile.ts @@ -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 === '' || diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/mapper.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/mapper.ts similarity index 95% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/mapper.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/mapper.ts index 3a20f538..d172e0c1 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/mapper.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/mapper.ts @@ -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 { 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; } diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parseCompileError.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parseCompileError.ts similarity index 71% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parseCompileError.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parseCompileError.ts index e87c4562..e0bab04d 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parseCompileError.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parseCompileError.ts @@ -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 = 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 = 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 diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parser.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parser.ts similarity index 92% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parser.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parser.ts index 5a8efd37..786d98e0 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parser.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parser.ts @@ -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; diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/pollyfills.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/pollyfills.ts similarity index 91% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/pollyfills.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/pollyfills.ts index ddd5aeb9..d740eff1 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/pollyfills.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/pollyfills.ts @@ -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'); } diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/stack-frame.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/stack-frame.ts similarity index 95% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/stack-frame.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/stack-frame.ts index cbbea6a0..4406aa7d 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/stack-frame.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/stack-frame.ts @@ -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); } diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/unmapper.js b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/unmapper.ts similarity index 93% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/unmapper.js rename to packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/unmapper.ts index 7b8ab87a..72c9b4b5 100644 --- a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/unmapper.js +++ b/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/unmapper.ts @@ -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 StackFrame. */ async function unmap( - _fileUri: string | { uri: string, contents: string }, + _fileUri: string | { uri: string; contents: string }, frames: StackFrame[], - contextLines: number = 3 + contextLines = 3 ): Promise { 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( diff --git a/packages/redux-devtools-trace-monitor/src/settle-promise.ts b/packages/redux-devtools-trace-monitor/src/settle-promise.ts new file mode 100644 index 00000000..4168e22b --- /dev/null +++ b/packages/redux-devtools-trace-monitor/src/settle-promise.ts @@ -0,0 +1,3 @@ +declare module 'settle-promise' { + export function settle(promises: Promise[]): Promise; +} diff --git a/packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.js b/packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.js deleted file mode 100644 index d8f21163..00000000 --- a/packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.js +++ /dev/null @@ -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(); - genAsyncSnapshot(component, done); - }); - - it('should render with props, but without stack', (done) => { - const component = mount( - - ); - genAsyncSnapshot(component, done); - }); - - it('should render the link to docs', (done) => { - const component = mount( - - ); - genAsyncSnapshot(component, done); - }); - - it('should render with trace stack', (done) => { - const component = mount( - - ); - genAsyncSnapshot(component, done); - }); -}); diff --git a/packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.tsx b/packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.tsx new file mode 100644 index 00000000..6e708d70 --- /dev/null +++ b/packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.tsx @@ -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, + 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(); + genAsyncSnapshot(component, done); + }); + }); + + it('should render with props, but without stack', () => { + return new Promise((done) => { + const component = mount( + + ); + genAsyncSnapshot(component, done); + }); + }); + + it('should render the link to docs', () => { + return new Promise((done) => { + const component = mount( + + ); + genAsyncSnapshot(component, done); + }); + }); + + it('should render with trace stack', () => { + return new Promise((done) => { + const component = mount( + + ); + genAsyncSnapshot(component, done); + }); + }); +}); diff --git a/packages/redux-devtools-trace-monitor/test/__snapshots__/StackTraceTab.spec.js.snap b/packages/redux-devtools-trace-monitor/test/__snapshots__/StackTraceTab.spec.tsx.snap similarity index 95% rename from packages/redux-devtools-trace-monitor/test/__snapshots__/StackTraceTab.spec.js.snap rename to packages/redux-devtools-trace-monitor/test/__snapshots__/StackTraceTab.spec.tsx.snap index 2788de7c..ce4cb318 100644 --- a/packages/redux-devtools-trace-monitor/test/__snapshots__/StackTraceTab.spec.js.snap +++ b/packages/redux-devtools-trace-monitor/test/__snapshots__/StackTraceTab.spec.tsx.snap @@ -301,12 +301,7 @@ exports[`StackTraceTab component should render with trace stack 1`] = ` } } > - + app.js:72:24
@@ -345,12 +340,7 @@ exports[`StackTraceTab component should render with trace stack 1`] = ` } } > - + app.js:84:31 diff --git a/packages/redux-devtools-trace-monitor/test/tsconfig.json b/packages/redux-devtools-trace-monitor/test/tsconfig.json new file mode 100644 index 00000000..ca19def4 --- /dev/null +++ b/packages/redux-devtools-trace-monitor/test/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../../tsconfig.react.base.json", + "include": ["../src", "."] +} diff --git a/packages/redux-devtools-trace-monitor/tsconfig.json b/packages/redux-devtools-trace-monitor/tsconfig.json new file mode 100644 index 00000000..7b7d1492 --- /dev/null +++ b/packages/redux-devtools-trace-monitor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.react.base.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["src"] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 2a17a794..55204414 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -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"] } } diff --git a/yarn.lock b/yarn.lock index c6d78b92..05fb37d5 100644 --- a/yarn.lock +++ b/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" From 9fdd298dc325126b1299728dd7d16c8e47f2f647 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sun, 4 Oct 2020 00:01:46 -0400 Subject: [PATCH 03/25] chore(test): rename test-generator to test-tab (#649) * chore(test): rename test-generator to test-tab * And those * Prettify --- packages/redux-devtools-core/package.json | 2 +- .../monitors/InspectorWrapper/index.js | 2 +- .../.babelrc | 0 .../.eslintignore | 0 .../.eslintrc.js | 0 .../CHANGELOG.md | 0 .../LICENSE.md | 0 .../README.md | 18 +++++++++--------- .../demo/config/tsconfig.json | 0 .../demo/config/webpack.config.ts | 0 .../demo/src/index.html | 0 .../demo/src/js/DemoApp.tsx | 0 .../demo/src/js/DevTools.tsx | 0 .../demo/src/js/getOptions.ts | 0 .../demo/src/js/index.tsx | 2 +- .../demo/src/js/reducers.ts | 0 .../demo/tsconfig.json | 0 .../jest.config.js | 0 .../package.json | 7 ++++--- .../src/TestGenerator.tsx | 0 .../src/index.tsx | 0 .../src/redux/ava/index.ts | 0 .../src/redux/ava/template.ts | 0 .../src/redux/jest/index.ts | 0 .../src/redux/jest/template.ts | 0 .../src/redux/mocha/index.ts | 0 .../src/redux/mocha/template.ts | 0 .../src/redux/tape/index.ts | 0 .../src/redux/tape/template.ts | 0 .../src/templateForm.ts | 0 .../src/types.ts | 0 .../src/vanilla/ava/index.ts | 0 .../src/vanilla/ava/template.ts | 0 .../src/vanilla/jest/index.ts | 0 .../src/vanilla/jest/template.ts | 0 .../src/vanilla/mocha/index.ts | 0 .../src/vanilla/mocha/template.ts | 0 .../src/vanilla/tape/index.ts | 0 .../src/vanilla/tape/template.ts | 0 .../test/TestGenerator.spec.tsx | 0 .../__snapshots__/TestGenerator.spec.tsx.snap | 0 .../test/assertions.spec.ts | 0 .../test/setup.ts | 0 .../test/tsconfig.json | 0 .../tsconfig.json | 0 .../redux-devtools-inspector-monitor/README.md | 2 +- 46 files changed, 17 insertions(+), 16 deletions(-) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/.babelrc (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/.eslintignore (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/.eslintrc.js (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/CHANGELOG.md (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/LICENSE.md (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/README.md (70%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/demo/config/tsconfig.json (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/demo/config/webpack.config.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/demo/src/index.html (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/demo/src/js/DemoApp.tsx (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/demo/src/js/DevTools.tsx (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/demo/src/js/getOptions.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/demo/src/js/index.tsx (97%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/demo/src/js/reducers.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/demo/tsconfig.json (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/jest.config.js (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/package.json (93%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/TestGenerator.tsx (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/index.tsx (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/redux/ava/index.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/redux/ava/template.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/redux/jest/index.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/redux/jest/template.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/redux/mocha/index.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/redux/mocha/template.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/redux/tape/index.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/redux/tape/template.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/templateForm.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/types.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/vanilla/ava/index.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/vanilla/ava/template.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/vanilla/jest/index.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/vanilla/jest/template.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/vanilla/mocha/index.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/vanilla/mocha/template.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/vanilla/tape/index.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/src/vanilla/tape/template.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/test/TestGenerator.spec.tsx (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/test/__snapshots__/TestGenerator.spec.tsx.snap (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/test/assertions.spec.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/test/setup.ts (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/test/tsconfig.json (100%) rename packages/{redux-devtools-test-generator => redux-devtools-inspector-monitor-test-tab}/tsconfig.json (100%) diff --git a/packages/redux-devtools-core/package.json b/packages/redux-devtools-core/package.json index e9042930..f753bd03 100644 --- a/packages/redux-devtools-core/package.json +++ b/packages/redux-devtools-core/package.json @@ -84,7 +84,7 @@ "redux-devtools-log-monitor": "^2.1.0", "redux-devtools-serialize": "^0.2.0", "redux-devtools-slider-monitor": "^2.0.0-5", - "redux-devtools-test-generator": "^0.6.2", + "redux-devtools-inspector-monitor-test-tab": "^0.6.2", "redux-devtools-trace-monitor": "^0.1.3", "redux-persist": "^4.10.2", "socketcluster-client": "^14.3.1", diff --git a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js index b281b065..d74dece2 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js +++ b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import InspectorMonitor from 'redux-devtools-inspector-monitor'; import StackTraceTab from 'redux-devtools-trace-monitor'; -import TestTab from 'redux-devtools-test-generator'; +import TestTab from 'redux-devtools-inspector-monitor-test-tab'; import { DATA_TYPE_KEY } from '../../../constants/dataTypes'; import SubTabs from './SubTabs'; diff --git a/packages/redux-devtools-test-generator/.babelrc b/packages/redux-devtools-inspector-monitor-test-tab/.babelrc similarity index 100% rename from packages/redux-devtools-test-generator/.babelrc rename to packages/redux-devtools-inspector-monitor-test-tab/.babelrc diff --git a/packages/redux-devtools-test-generator/.eslintignore b/packages/redux-devtools-inspector-monitor-test-tab/.eslintignore similarity index 100% rename from packages/redux-devtools-test-generator/.eslintignore rename to packages/redux-devtools-inspector-monitor-test-tab/.eslintignore diff --git a/packages/redux-devtools-test-generator/.eslintrc.js b/packages/redux-devtools-inspector-monitor-test-tab/.eslintrc.js similarity index 100% rename from packages/redux-devtools-test-generator/.eslintrc.js rename to packages/redux-devtools-inspector-monitor-test-tab/.eslintrc.js diff --git a/packages/redux-devtools-test-generator/CHANGELOG.md b/packages/redux-devtools-inspector-monitor-test-tab/CHANGELOG.md similarity index 100% rename from packages/redux-devtools-test-generator/CHANGELOG.md rename to packages/redux-devtools-inspector-monitor-test-tab/CHANGELOG.md diff --git a/packages/redux-devtools-test-generator/LICENSE.md b/packages/redux-devtools-inspector-monitor-test-tab/LICENSE.md similarity index 100% rename from packages/redux-devtools-test-generator/LICENSE.md rename to packages/redux-devtools-inspector-monitor-test-tab/LICENSE.md diff --git a/packages/redux-devtools-test-generator/README.md b/packages/redux-devtools-inspector-monitor-test-tab/README.md similarity index 70% rename from packages/redux-devtools-test-generator/README.md rename to packages/redux-devtools-inspector-monitor-test-tab/README.md index 7348f513..979fb899 100644 --- a/packages/redux-devtools-test-generator/README.md +++ b/packages/redux-devtools-inspector-monitor-test-tab/README.md @@ -3,7 +3,7 @@ ### Installation ``` -npm install --save-dev redux-devtools-test-generator +yarn add --dev redux-devtools-inspector-monitor-test-tab ``` ### Usage @@ -18,8 +18,8 @@ With [`redux-devtools`](https://github.com/reduxjs/redux-devtools) and [`redux-d import React from 'react'; import { createDevTools } from 'redux-devtools'; import InspectorMonitor from 'redux-devtools-inspector-monitor'; -import TestGenerator from 'redux-devtools-test-generator'; -import mochaTemplate from 'redux-devtools-test-generator/lib/redux/mocha'; // If using default tests. +import TestGenerator from 'redux-devtools-inspector-monitor-test-tab'; +import mochaTemplate from 'redux-devtools-inspector-monitor-test-tab/lib/redux/mocha'; // If using default tests. const testComponent = (props) => ( Date: Sun, 4 Oct 2020 00:11:22 -0400 Subject: [PATCH 04/25] chore(trace): rename trace-monitor to trace-tab (#650) * chore(trace): rename trace-monitor to test-tab * And that * Fix name --- packages/redux-devtools-core/package.json | 4 ++-- .../src/app/containers/monitors/InspectorWrapper/index.js | 4 ++-- .../.babelrc | 0 .../.eslintignore | 0 .../.eslintrc.js | 0 .../CHANGELOG.md | 0 .../LICENSE.md | 0 .../README.md | 4 ++-- .../jest.config.js | 0 .../package.json | 4 ++-- .../src/StackTraceTab.tsx | 0 .../src/openFile.ts | 0 .../src/presets.ts | 0 .../src/react-error-overlay/components/CodeBlock.tsx | 0 .../src/react-error-overlay/components/Collapsible.tsx | 0 .../src/react-error-overlay/containers/StackFrame.tsx | 0 .../react-error-overlay/containers/StackFrameCodeBlock.tsx | 0 .../src/react-error-overlay/containers/StackTrace.tsx | 0 .../src/react-error-overlay/utils/dom/absolutifyCaret.ts | 0 .../src/react-error-overlay/utils/dom/css.ts | 0 .../src/react-error-overlay/utils/generateAnsiHTML.ts | 0 .../src/react-error-overlay/utils/getLinesAround.ts | 0 .../src/react-error-overlay/utils/getPrettyURL.ts | 0 .../src/react-error-overlay/utils/getSourceMap.ts | 0 .../src/react-error-overlay/utils/getStackFrames.ts | 0 .../src/react-error-overlay/utils/isBultinErrorName.ts | 0 .../src/react-error-overlay/utils/isInternalFile.ts | 0 .../src/react-error-overlay/utils/mapper.ts | 0 .../src/react-error-overlay/utils/parseCompileError.ts | 0 .../src/react-error-overlay/utils/parser.ts | 0 .../src/react-error-overlay/utils/pollyfills.ts | 0 .../src/react-error-overlay/utils/stack-frame.ts | 0 .../src/react-error-overlay/utils/unmapper.ts | 0 .../src/settle-promise.ts | 0 .../test/StackTraceTab.spec.tsx | 0 .../test/__snapshots__/StackTraceTab.spec.tsx.snap | 0 .../test/tsconfig.json | 0 .../tsconfig.json | 0 38 files changed, 8 insertions(+), 8 deletions(-) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/.babelrc (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/.eslintignore (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/.eslintrc.js (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/CHANGELOG.md (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/LICENSE.md (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/README.md (93%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/jest.config.js (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/package.json (94%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/StackTraceTab.tsx (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/openFile.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/presets.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/components/CodeBlock.tsx (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/components/Collapsible.tsx (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/containers/StackFrame.tsx (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/containers/StackFrameCodeBlock.tsx (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/containers/StackTrace.tsx (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/dom/absolutifyCaret.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/dom/css.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/generateAnsiHTML.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/getLinesAround.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/getPrettyURL.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/getSourceMap.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/getStackFrames.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/isBultinErrorName.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/isInternalFile.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/mapper.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/parseCompileError.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/parser.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/pollyfills.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/stack-frame.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/react-error-overlay/utils/unmapper.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/src/settle-promise.ts (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/test/StackTraceTab.spec.tsx (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/test/__snapshots__/StackTraceTab.spec.tsx.snap (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/test/tsconfig.json (100%) rename packages/{redux-devtools-trace-monitor => redux-devtools-inspector-monitor-trace-tab}/tsconfig.json (100%) diff --git a/packages/redux-devtools-core/package.json b/packages/redux-devtools-core/package.json index f753bd03..8a9e2fb3 100644 --- a/packages/redux-devtools-core/package.json +++ b/packages/redux-devtools-core/package.json @@ -80,12 +80,12 @@ "redux-devtools": "^3.7.0", "redux-devtools-chart-monitor": "^1.7.2", "redux-devtools-inspector-monitor": "^0.14.0", + "redux-devtools-inspector-monitor-test-tab": "^0.6.2", + "redux-devtools-inspector-monitor-trace-tab": "^0.1.3", "redux-devtools-instrument": "^1.10.0", "redux-devtools-log-monitor": "^2.1.0", "redux-devtools-serialize": "^0.2.0", "redux-devtools-slider-monitor": "^2.0.0-5", - "redux-devtools-inspector-monitor-test-tab": "^0.6.2", - "redux-devtools-trace-monitor": "^0.1.3", "redux-persist": "^4.10.2", "socketcluster-client": "^14.3.1", "styled-components": "^5.1.1" diff --git a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js index d74dece2..f8ebd4cc 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js +++ b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import InspectorMonitor from 'redux-devtools-inspector-monitor'; -import StackTraceTab from 'redux-devtools-trace-monitor'; +import TraceTab from 'redux-devtools-inspector-monitor-trace-tab'; import TestTab from 'redux-devtools-inspector-monitor-test-tab'; import { DATA_TYPE_KEY } from '../../../constants/dataTypes'; import SubTabs from './SubTabs'; @@ -21,7 +21,7 @@ const DEFAULT_TABS = [ }, { name: 'Trace', - component: StackTraceTab, + component: TraceTab, }, ]; diff --git a/packages/redux-devtools-trace-monitor/.babelrc b/packages/redux-devtools-inspector-monitor-trace-tab/.babelrc similarity index 100% rename from packages/redux-devtools-trace-monitor/.babelrc rename to packages/redux-devtools-inspector-monitor-trace-tab/.babelrc diff --git a/packages/redux-devtools-trace-monitor/.eslintignore b/packages/redux-devtools-inspector-monitor-trace-tab/.eslintignore similarity index 100% rename from packages/redux-devtools-trace-monitor/.eslintignore rename to packages/redux-devtools-inspector-monitor-trace-tab/.eslintignore diff --git a/packages/redux-devtools-trace-monitor/.eslintrc.js b/packages/redux-devtools-inspector-monitor-trace-tab/.eslintrc.js similarity index 100% rename from packages/redux-devtools-trace-monitor/.eslintrc.js rename to packages/redux-devtools-inspector-monitor-trace-tab/.eslintrc.js diff --git a/packages/redux-devtools-trace-monitor/CHANGELOG.md b/packages/redux-devtools-inspector-monitor-trace-tab/CHANGELOG.md similarity index 100% rename from packages/redux-devtools-trace-monitor/CHANGELOG.md rename to packages/redux-devtools-inspector-monitor-trace-tab/CHANGELOG.md diff --git a/packages/redux-devtools-trace-monitor/LICENSE.md b/packages/redux-devtools-inspector-monitor-trace-tab/LICENSE.md similarity index 100% rename from packages/redux-devtools-trace-monitor/LICENSE.md rename to packages/redux-devtools-inspector-monitor-trace-tab/LICENSE.md diff --git a/packages/redux-devtools-trace-monitor/README.md b/packages/redux-devtools-inspector-monitor-trace-tab/README.md similarity index 93% rename from packages/redux-devtools-trace-monitor/README.md rename to packages/redux-devtools-inspector-monitor-trace-tab/README.md index 8aef3ba0..b2b3b8c7 100644 --- a/packages/redux-devtools-trace-monitor/README.md +++ b/packages/redux-devtools-inspector-monitor-trace-tab/README.md @@ -10,11 +10,11 @@ It's integrated in Redux DevTools browser extension. To use it separately with [ import React from 'react'; import { createDevTools } from 'redux-devtools'; import InspectorMonitor from 'redux-devtools-inspector-monitor'; -import TraceMonitor from 'redux-devtools-trace-monitor'; +import TraceTab from 'redux-devtools-inspector-monitor-trace-tab'; export default createDevTools( [...defaultTabs, { name: 'Trace', component: TraceMonitor }] + tabs: defaultTabs => [...defaultTabs, { name: 'Trace', component: TraceTab }] /> ); ``` diff --git a/packages/redux-devtools-trace-monitor/jest.config.js b/packages/redux-devtools-inspector-monitor-trace-tab/jest.config.js similarity index 100% rename from packages/redux-devtools-trace-monitor/jest.config.js rename to packages/redux-devtools-inspector-monitor-trace-tab/jest.config.js diff --git a/packages/redux-devtools-trace-monitor/package.json b/packages/redux-devtools-inspector-monitor-trace-tab/package.json similarity index 94% rename from packages/redux-devtools-trace-monitor/package.json rename to packages/redux-devtools-inspector-monitor-trace-tab/package.json index f88b764a..a928bb30 100644 --- a/packages/redux-devtools-trace-monitor/package.json +++ b/packages/redux-devtools-inspector-monitor-trace-tab/package.json @@ -1,8 +1,8 @@ { - "name": "redux-devtools-trace-monitor", + "name": "redux-devtools-inspector-monitor-trace-tab", "version": "0.1.3", "description": "Submonitor for Redux DevTools inspector to show stack traces.", - "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-trace-monitor", + "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-inspector-monitor-trace-tab", "license": "MIT", "author": "Mark Erikson ", "contributors": [ diff --git a/packages/redux-devtools-trace-monitor/src/StackTraceTab.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/StackTraceTab.tsx similarity index 100% rename from packages/redux-devtools-trace-monitor/src/StackTraceTab.tsx rename to packages/redux-devtools-inspector-monitor-trace-tab/src/StackTraceTab.tsx diff --git a/packages/redux-devtools-trace-monitor/src/openFile.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/openFile.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/openFile.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/openFile.ts diff --git a/packages/redux-devtools-trace-monitor/src/presets.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/presets.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/presets.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/presets.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/CodeBlock.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/CodeBlock.tsx similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/components/CodeBlock.tsx rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/CodeBlock.tsx diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/components/Collapsible.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/Collapsible.tsx similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/components/Collapsible.tsx rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/Collapsible.tsx diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrame.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrame.tsx similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrame.tsx rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrame.tsx diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrameCodeBlock.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrameCodeBlock.tsx similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackFrameCodeBlock.tsx rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrameCodeBlock.tsx diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackTrace.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackTrace.tsx similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/containers/StackTrace.tsx rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackTrace.tsx diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/absolutifyCaret.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/dom/absolutifyCaret.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/absolutifyCaret.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/dom/absolutifyCaret.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/css.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/dom/css.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/dom/css.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/dom/css.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/generateAnsiHTML.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/generateAnsiHTML.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/generateAnsiHTML.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/generateAnsiHTML.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getLinesAround.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getLinesAround.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getLinesAround.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getLinesAround.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getPrettyURL.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getPrettyURL.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getPrettyURL.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getPrettyURL.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getSourceMap.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getSourceMap.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getSourceMap.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getSourceMap.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getStackFrames.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getStackFrames.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/getStackFrames.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getStackFrames.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isBultinErrorName.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/isBultinErrorName.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isBultinErrorName.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/isBultinErrorName.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isInternalFile.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/isInternalFile.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/isInternalFile.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/isInternalFile.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/mapper.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/mapper.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/mapper.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/mapper.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parseCompileError.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/parseCompileError.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parseCompileError.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/parseCompileError.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parser.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/parser.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/parser.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/parser.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/pollyfills.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/pollyfills.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/pollyfills.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/pollyfills.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/stack-frame.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/stack-frame.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/stack-frame.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/stack-frame.ts diff --git a/packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/unmapper.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/unmapper.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/react-error-overlay/utils/unmapper.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/unmapper.ts diff --git a/packages/redux-devtools-trace-monitor/src/settle-promise.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/settle-promise.ts similarity index 100% rename from packages/redux-devtools-trace-monitor/src/settle-promise.ts rename to packages/redux-devtools-inspector-monitor-trace-tab/src/settle-promise.ts diff --git a/packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/test/StackTraceTab.spec.tsx similarity index 100% rename from packages/redux-devtools-trace-monitor/test/StackTraceTab.spec.tsx rename to packages/redux-devtools-inspector-monitor-trace-tab/test/StackTraceTab.spec.tsx diff --git a/packages/redux-devtools-trace-monitor/test/__snapshots__/StackTraceTab.spec.tsx.snap b/packages/redux-devtools-inspector-monitor-trace-tab/test/__snapshots__/StackTraceTab.spec.tsx.snap similarity index 100% rename from packages/redux-devtools-trace-monitor/test/__snapshots__/StackTraceTab.spec.tsx.snap rename to packages/redux-devtools-inspector-monitor-trace-tab/test/__snapshots__/StackTraceTab.spec.tsx.snap diff --git a/packages/redux-devtools-trace-monitor/test/tsconfig.json b/packages/redux-devtools-inspector-monitor-trace-tab/test/tsconfig.json similarity index 100% rename from packages/redux-devtools-trace-monitor/test/tsconfig.json rename to packages/redux-devtools-inspector-monitor-trace-tab/test/tsconfig.json diff --git a/packages/redux-devtools-trace-monitor/tsconfig.json b/packages/redux-devtools-inspector-monitor-trace-tab/tsconfig.json similarity index 100% rename from packages/redux-devtools-trace-monitor/tsconfig.json rename to packages/redux-devtools-inspector-monitor-trace-tab/tsconfig.json From 94f460531172852a920ccd92ad5f56dc917becef Mon Sep 17 00:00:00 2001 From: Jess Telford Date: Wed, 7 Oct 2020 01:16:21 +1100 Subject: [PATCH 05/25] docs(react-json-tree): correct link to base16 site (#651) --- packages/react-json-tree/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-json-tree/README.md b/packages/react-json-tree/README.md index dee87d6c..28adfac8 100644 --- a/packages/react-json-tree/README.md +++ b/packages/react-json-tree/README.md @@ -34,7 +34,7 @@ Check out [examples](examples) directory for more details. This component now uses [react-base16-styling](https://github.com/alexkuz/react-base16-styling) module, which allows to customize component via `theme` property, which can be the following: -- [base16](http://chriskempson.github.io/base16) theme data. [The example theme data can be found here](https://github.com/gaearon/redux-devtools/tree/75322b15ee7ba03fddf10ac3399881e302848874/src/react/themes). +- [base16](http://chriskempson.com/projects/base16/) theme data. [The example theme data can be found here](https://github.com/gaearon/redux-devtools/tree/75322b15ee7ba03fddf10ac3399881e302848874/src/react/themes). - object that contains style objects, strings (that treated as classnames) or functions. A function is used to extend its first argument `{ style, className }` and should return an object with the same structure. Other arguments depend on particular context (and should be described here). See [createStylingFromTheme.js](https://github.com/alexkuz/react-json-tree/blob/feature-refactor-styling/src/createStylingFromTheme.js) for the list of styling object keys. Also, this object can extend `base16` theme via `extend` property. Every theme has a light version, which is enabled with `invertTheme` prop. From 2db2d6024d3d923a6e68b8dc8bb4cd9290998c52 Mon Sep 17 00:00:00 2001 From: Edoardo Lincetto Date: Wed, 7 Oct 2020 02:33:25 +0200 Subject: [PATCH 06/25] chore(devui): upgrade react-jsonschema-form to @rjsf/core (#648) * chore(devui): upgrade react-jsonschema-form to @rjsf/core * chore(devui): remove @types/react-jsonschema-form Co-authored-by: Nathan Bierema --- packages/devui/package.json | 3 +- packages/devui/src/Form/Form.tsx | 4 +- packages/devui/src/Form/schema.ts | 4 +- packages/devui/src/Form/widgets.tsx | 2 +- yarn.lock | 146 ++++++++++++++++++++++------ 5 files changed, 121 insertions(+), 38 deletions(-) diff --git a/packages/devui/package.json b/packages/devui/package.json index e1322af3..36efc173 100755 --- a/packages/devui/package.json +++ b/packages/devui/package.json @@ -36,10 +36,10 @@ "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { + "@rjsf/core": "^2.4.0", "@types/base16": "^1.0.2", "@types/codemirror": "^0.0.97", "@types/prop-types": "^15.7.3", - "@types/react-jsonschema-form": "^1.7.4", "@types/react-select": "^3.0.19", "@types/redux-devtools-themes": "^1.0.0", "@types/simple-element-resize-detector": "^1.3.0", @@ -49,7 +49,6 @@ "color": "^3.1.2", "prop-types": "^15.7.2", "react-icons": "^3.10.0", - "react-jsonschema-form": "^1.8.1", "react-select": "^3.1.0", "redux-devtools-themes": "^1.0.0", "simple-element-resize-detector": "^1.3.0", diff --git a/packages/devui/src/Form/Form.tsx b/packages/devui/src/Form/Form.tsx index 4e8f651f..e9cf4f41 100644 --- a/packages/devui/src/Form/Form.tsx +++ b/packages/devui/src/Form/Form.tsx @@ -1,6 +1,6 @@ import React, { PureComponent, Component } from 'react'; import PropTypes from 'prop-types'; -import JSONSchemaForm, { FormProps } from 'react-jsonschema-form'; +import JSONSchemaForm, { FormProps } from '@rjsf/core'; import { Base16Theme } from 'base16'; import createStyledComponent from '../utils/createStyledComponent'; import styles from './styles'; @@ -18,7 +18,7 @@ export interface Props extends FormProps { } /** - * Wrapper around [`react-jsonschema-form`](https://github.com/mozilla-services/react-jsonschema-form) with custom widgets. + * Wrapper around [`react-jsonschema-form`](https://github.com/rjsf-team/react-jsonschema-form) with custom widgets. */ export default class Form extends (PureComponent || Component)> { render() { diff --git a/packages/devui/src/Form/schema.ts b/packages/devui/src/Form/schema.ts index 0cafe38d..66a5da07 100644 --- a/packages/devui/src/Form/schema.ts +++ b/packages/devui/src/Form/schema.ts @@ -1,6 +1,6 @@ -import { JSONSchema6 } from 'json-schema'; +import { JSONSchema7 } from 'json-schema'; -export const schema: JSONSchema6 = { +export const schema: JSONSchema7 = { title: 'Example form', description: 'A simple form example.', type: 'object', diff --git a/packages/devui/src/Form/widgets.tsx b/packages/devui/src/Form/widgets.tsx index 905148af..f4f5336b 100644 --- a/packages/devui/src/Form/widgets.tsx +++ b/packages/devui/src/Form/widgets.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { FieldProps, Widget, WidgetProps } from 'react-jsonschema-form'; +import { FieldProps, Widget, WidgetProps } from '@rjsf/core'; import Select from '../Select'; import Slider from '../Slider'; diff --git a/yarn.lock b/yarn.lock index 05fb37d5..12cddd14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1161,7 +1161,7 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime-corejs2@^7.4.5": +"@babel/runtime-corejs2@^7.8.7": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.11.2.tgz#700a03945ebad0d31ba6690fc8a6bcc9040faa47" integrity sha512-AC/ciV28adSSpEkBglONBWq4/Lvm6GAZuxIoyVtsnUpZMl0bxLtoChEnYAkP+47KyOCayZanojtflUEUJtR/6Q== @@ -2584,6 +2584,23 @@ lodash "^4.17.15" lodash-es "^4.17.15" +"@rjsf/core@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@rjsf/core/-/core-2.4.0.tgz#c50bcff0d8178948ce08123177399d8816d51929" + integrity sha512-8zlydBkGldOxGXFEwNGFa1gzTxpcxaYn7ofegcu8XHJ7IKMCfpnU3ABg+H3eml1KZCX3FODmj1tHFJKuTmfynw== + dependencies: + "@babel/runtime-corejs2" "^7.8.7" + "@types/json-schema" "^7.0.4" + ajv "^6.7.0" + core-js "^2.5.7" + json-schema-merge-allof "^0.6.0" + jsonpointer "^4.0.1" + lodash "^4.17.15" + prop-types "^15.7.2" + react-app-polyfill "^1.0.4" + react-is "^16.9.0" + shortid "^2.2.14" + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -3570,11 +3587,6 @@ resolved "https://registry.yarnpkg.com/@types/jsan/-/jsan-3.1.0.tgz#128fdb14a102134ede764b11682e795d1b380c43" integrity sha512-V5wfm0++TqM92D0ZkAhl9MDQHPTi88fXhMNVin5LV/Y3RnuU/FUv6wML4Vt/amZmPN9WaFTmDhKW+h58kAFmIg== -"@types/json-schema@*": - version "7.0.6" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" - integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== - "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5": version "7.0.5" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" @@ -3762,14 +3774,6 @@ dependencies: "@types/dragula" "*" -"@types/react-jsonschema-form@^1.7.4": - version "1.7.4" - resolved "https://registry.yarnpkg.com/@types/react-jsonschema-form/-/react-jsonschema-form-1.7.4.tgz#b9dded80f830bce11a623107633b13964a143cca" - integrity sha512-TSsntIuB8bfheC/ZpjUmgB6+m5cLR4Gbh8rnqpSYB6T4e2TwzNICuKC5AykZI0XTxqLJmShyVsJxuo4aih64Gw== - dependencies: - "@types/json-schema" "*" - "@types/react" "*" - "@types/react-native@*": version "0.63.8" resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.63.8.tgz#73ec087122c64c309eeaf150b565b8d755f0fb1f" @@ -4711,7 +4715,7 @@ arrify@^2.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -asap@^2.0.0: +asap@^2.0.0, asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -6280,6 +6284,25 @@ compression@^1.7.4: safe-buffer "5.1.2" vary "~1.1.2" +compute-gcd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/compute-gcd/-/compute-gcd-1.2.0.tgz#fc1ede5b65001e950226502f46543863e4fea10e" + integrity sha1-/B7eW2UAHpUCJlAvRlQ4Y+T+oQ4= + dependencies: + validate.io-array "^1.0.3" + validate.io-function "^1.0.2" + validate.io-integer-array "^1.0.0" + +compute-lcm@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/compute-lcm/-/compute-lcm-1.1.0.tgz#abd96d040b41b0a166f89944b5c8b7c511e21ad5" + integrity sha1-q9ltBAtBsKFm+JlEtci3xRHiGtU= + dependencies: + compute-gcd "^1.2.0" + validate.io-array "^1.0.3" + validate.io-function "^1.0.2" + validate.io-integer-array "^1.0.0" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -6507,7 +6530,7 @@ core-js@^2.5.3, core-js@^2.5.7, core-js@^2.6.5: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== -core-js@^3.0.1, core-js@^3.0.4, core-js@^3.6.5: +core-js@^3.0.1, core-js@^3.0.4, core-js@^3.5.0, core-js@^3.6.5: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== @@ -11085,6 +11108,22 @@ json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-bet resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== +json-schema-compare@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/json-schema-compare/-/json-schema-compare-0.2.2.tgz#dd601508335a90c7f4cfadb6b2e397225c908e56" + integrity sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ== + dependencies: + lodash "^4.17.4" + +json-schema-merge-allof@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/json-schema-merge-allof/-/json-schema-merge-allof-0.6.0.tgz#64d48820fec26b228db837475ce3338936bf59a5" + integrity sha512-LEw4VMQVRceOPLuGRWcxW5orTTiR9ZAtqTAe4rQUjNADTeR81bezBVFa0MqIwp0YmHIM1KkhSjZM7o+IQhaPbQ== + dependencies: + compute-lcm "^1.1.0" + json-schema-compare "^0.2.2" + lodash "^4.17.4" + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -11160,6 +11199,11 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= +jsonpointer@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.1.0.tgz#501fb89986a2389765ba09e6053299ceb4f2c2cc" + integrity sha512-CXcRvMyTlnR53xMcKnuMzfCA5i/nfblTnnr74CZb6C4vG39eu6w51t7nKmU5MfLfbTgGItliNyjO/ciNPDqClg== + jsonwebtoken@^8.3.0: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" @@ -13931,6 +13975,13 @@ promise.prototype.finally@^3.1.0: es-abstract "^1.17.0-next.0" function-bind "^1.1.1" +promise@^8.0.3: + version "8.1.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e" + integrity sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q== + dependencies: + asap "~2.0.6" + prompts@^2.0.1: version "2.3.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" @@ -14189,6 +14240,18 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-app-polyfill@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz#890f8d7f2842ce6073f030b117de9130a5f385f0" + integrity sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g== + dependencies: + core-js "^3.5.0" + object-assign "^4.1.1" + promise "^8.0.3" + raf "^3.4.1" + regenerator-runtime "^0.13.3" + whatwg-fetch "^3.0.0" + react-bootstrap@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-1.3.0.tgz#d9dde4ad554e9cd21d1465e8b5e5ef6679cae6a1" @@ -14394,25 +14457,11 @@ react-inspector@^5.0.1: is-dom "^1.1.0" prop-types "^15.6.1" -react-is@^16.12.0, react-is@^16.13.1, react-is@^16.3.2, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: +react-is@^16.12.0, react-is@^16.13.1, react-is@^16.3.2, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6, react-is@^16.9.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-jsonschema-form@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/react-jsonschema-form/-/react-jsonschema-form-1.8.1.tgz#9c962f29a55b3fe071d8edf2fc3430f05f1b7ed9" - integrity sha512-aaDloxNAcGXOOOcdKOxxqEEn5oDlPUZgWcs8unXXB9vjBRgCF8rCm/wVSv1u2G5ih0j/BX6Ewd/WjI2g00lPdg== - dependencies: - "@babel/runtime-corejs2" "^7.4.5" - ajv "^6.7.0" - core-js "^2.5.7" - lodash "^4.17.15" - prop-types "^15.5.8" - react-is "^16.8.4" - react-lifecycles-compat "^3.0.4" - shortid "^2.2.14" - react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -17509,6 +17558,36 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" +validate.io-array@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/validate.io-array/-/validate.io-array-1.0.6.tgz#5b5a2cafd8f8b85abb2f886ba153f2d93a27774d" + integrity sha1-W1osr9j4uFq7L4hroVPy2Tond00= + +validate.io-function@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/validate.io-function/-/validate.io-function-1.0.2.tgz#343a19802ed3b1968269c780e558e93411c0bad7" + integrity sha1-NDoZgC7TsZaCaceA5VjpNBHAutc= + +validate.io-integer-array@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz#2cabde033293a6bcbe063feafe91eaf46b13a089" + integrity sha1-LKveAzKTpry+Bj/q/pHq9GsToIk= + dependencies: + validate.io-array "^1.0.3" + validate.io-integer "^1.0.4" + +validate.io-integer@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/validate.io-integer/-/validate.io-integer-1.0.5.tgz#168496480b95be2247ec443f2233de4f89878068" + integrity sha1-FoSWSAuVviJH7EQ/IjPeT4mHgGg= + dependencies: + validate.io-number "^1.0.3" + +validate.io-number@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/validate.io-number/-/validate.io-number-1.0.3.tgz#f63ffeda248bf28a67a8d48e0e3b461a1665baf8" + integrity sha1-9j/+2iSL8opnqNSODjtGGhZluvg= + value-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" @@ -17804,6 +17883,11 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" +whatwg-fetch@^3.0.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz#e5f871572d6879663fa5674c8f833f15a8425ab3" + integrity sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ== + whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" From 94c2c28cad255de78a6f4cdf6bf48fa137f74499 Mon Sep 17 00:00:00 2001 From: Edoardo Lincetto Date: Sun, 11 Oct 2020 23:57:47 +0200 Subject: [PATCH 07/25] chore(redux-devtools-cli): upgrade graphql-server-express to apollo-server-express (#652) * chore(devui): upgrade react-jsonschema-form to @rjsf/core * chore(devui): remove @types/react-jsonschema-form * chore(redux-devtools-cli): upgrade graphql-server-express to apollo-server-express Co-authored-by: Nathan Bierema --- packages/redux-devtools-cli/README.md | 2 +- packages/redux-devtools-cli/package.json | 6 +- packages/redux-devtools-cli/src/api/schema.js | 2 +- .../src/middleware/graphiql.js | 13 - .../src/middleware/graphql.js | 30 +- packages/redux-devtools-cli/src/routes.js | 5 +- yarn.lock | 548 +++++++++++++++--- 7 files changed, 508 insertions(+), 98 deletions(-) delete mode 100644 packages/redux-devtools-cli/src/middleware/graphiql.js diff --git a/packages/redux-devtools-cli/README.md b/packages/redux-devtools-cli/README.md index 21add95f..e23f0d40 100644 --- a/packages/redux-devtools-cli/README.md +++ b/packages/redux-devtools-cli/README.md @@ -140,7 +140,7 @@ If you're still use Android 4.0, you should use `10.0.2.2` (Genymotion: `10.0.3. ### Save reports and logs -You can store reports via [`redux-remotedev`](https://github.com/zalmoxisus/redux-remotedev) and get them replicated with [Redux DevTools extension](https://github.com/zalmoxisus/redux-devtools-extension) or [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools). You can get action history right in the extension just by clicking the link from a report. Open `http://localhost:8000/graphiql` (assuming you're using `localhost` as host and `8000`) to explore in GraphQL. Reports are posted to `http://localhost:8000/`. See examples in [tests](https://github.com/zalmoxisus/remotedev-server/blob/937cfa1f0ac9dc12ebf7068eeaa8b03022ec33bc/test/integration.spec.js#L110-L165). +You can store reports via [`redux-remotedev`](https://github.com/zalmoxisus/redux-remotedev) and get them replicated with [Redux DevTools extension](https://github.com/zalmoxisus/redux-devtools-extension) or [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools). You can get action history right in the extension just by clicking the link from a report. Open `http://localhost:8000/graphql` (assuming you're using `localhost` as host and `8000`) to explore in GraphQL. Reports are posted to `http://localhost:8000/`. See examples in [tests](https://github.com/zalmoxisus/remotedev-server/blob/937cfa1f0ac9dc12ebf7068eeaa8b03022ec33bc/test/integration.spec.js#L110-L165). Redux DevTools server is database agnostic using `knex` schema. By default everything is stored in the memory using sqlite database. See [`defaultDbOptions.json`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-cli/defaultDbOptions.json) for example of sqlite. You can replace `"connection": { "filename": ":memory:" },` with your file name (instead of `:memory:`) to persist teh database. Here's an example for PostgreSQL: diff --git a/packages/redux-devtools-cli/package.json b/packages/redux-devtools-cli/package.json index 30d49903..b919984a 100644 --- a/packages/redux-devtools-cli/package.json +++ b/packages/redux-devtools-cli/package.json @@ -33,6 +33,8 @@ }, "homepage": "https://github.com/reduxjs/redux-devtools", "dependencies": { + "apollo-server": "^2.18.2", + "apollo-server-express": "^2.18.2", "body-parser": "^1.19.0", "chalk": "^4.1.0", "cors": "^2.8.5", @@ -40,9 +42,7 @@ "electron": "^9.2.0", "express": "^4.17.1", "getport": "^0.1.0", - "graphql": "^0.13.2", - "graphql-server-express": "^1.4.1", - "graphql-tools": "^4.0.8", + "graphql": "^15.3.0", "knex": "^0.19.5", "lodash": "^4.17.19", "minimist": "^1.2.5", diff --git a/packages/redux-devtools-cli/src/api/schema.js b/packages/redux-devtools-cli/src/api/schema.js index 81e26085..e92b624d 100644 --- a/packages/redux-devtools-cli/src/api/schema.js +++ b/packages/redux-devtools-cli/src/api/schema.js @@ -1,4 +1,4 @@ -var makeExecutableSchema = require('graphql-tools').makeExecutableSchema; +var makeExecutableSchema = require('apollo-server').makeExecutableSchema; var requireSchema = require('../utils/requireSchema'); var schema = requireSchema('./schema_def.graphql', require); diff --git a/packages/redux-devtools-cli/src/middleware/graphiql.js b/packages/redux-devtools-cli/src/middleware/graphiql.js deleted file mode 100644 index 75ddf747..00000000 --- a/packages/redux-devtools-cli/src/middleware/graphiql.js +++ /dev/null @@ -1,13 +0,0 @@ -var graphiqlExpress = require('graphql-server-express').graphiqlExpress; - -module.exports = graphiqlExpress({ - endpointURL: '/graphql', - query: - '{\n' + - ' reports {\n' + - ' id,\n' + - ' type,\n' + - ' title\n' + - ' }\n' + - '}', -}); diff --git a/packages/redux-devtools-cli/src/middleware/graphql.js b/packages/redux-devtools-cli/src/middleware/graphql.js index 8a518439..efd844d1 100644 --- a/packages/redux-devtools-cli/src/middleware/graphql.js +++ b/packages/redux-devtools-cli/src/middleware/graphql.js @@ -1,13 +1,27 @@ -var graphqlExpress = require('graphql-server-express').graphqlExpress; +var ApolloServer = require('apollo-server-express').ApolloServer; var schema = require('../api/schema'); module.exports = function (store) { - return graphqlExpress(function () { - return { - schema: schema, - context: { - store: store, - }, - }; + return new ApolloServer({ + schema, + context: { + store: store, + }, + playground: { + endpoint: '/graphql', + tabs: [ + { + endpoint: '/graphql', + query: + '{\n' + + ' reports {\n' + + ' id,\n' + + ' type,\n' + + ' title\n' + + ' }\n' + + '}', + }, + ], + }, }); }; diff --git a/packages/redux-devtools-cli/src/routes.js b/packages/redux-devtools-cli/src/routes.js index dcacadaa..8e7e9836 100644 --- a/packages/redux-devtools-cli/src/routes.js +++ b/packages/redux-devtools-cli/src/routes.js @@ -3,7 +3,6 @@ var express = require('express'); var morgan = require('morgan'); var bodyParser = require('body-parser'); var cors = require('cors'); -var graphiqlMiddleware = require('./middleware/graphiql'); var graphqlMiddleware = require('./middleware/graphql'); var app = express.Router(); @@ -26,7 +25,7 @@ function routes(options, store, scServer) { else app.use(morgan('combined')); } - app.use('/graphiql', graphiqlMiddleware); + graphqlMiddleware(store).applyMiddleware({ app }); serveUmdModule('react'); serveUmdModule('react-dom'); @@ -43,8 +42,6 @@ function routes(options, store, scServer) { app.use(bodyParser.json({ limit: limit })); app.use(bodyParser.urlencoded({ limit: limit, extended: false })); - app.use('/graphql', graphqlMiddleware(store)); - app.post('/', function (req, res) { if (!req.body) return res.status(404).end(); switch (req.body.op) { diff --git a/yarn.lock b/yarn.lock index 12cddd14..daf18650 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,39 @@ # yarn lockfile v1 +"@apollo/protobufjs@^1.0.3": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.0.5.tgz#a78b726147efc0795e74c8cb8a11aafc6e02f773" + integrity sha512-ZtyaBH1icCgqwIGb3zrtopV2D5Q8yxibkJzlaViM08eOhTQc7rACdYu0pfORFfhllvdMZ3aq69vifYHszY4gNA== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.0" + "@types/node" "^10.1.0" + long "^4.0.0" + +"@apollographql/apollo-tools@^0.4.3": + version "0.4.8" + resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.4.8.tgz#d81da89ee880c2345eb86bddb92b35291f6135ed" + integrity sha512-W2+HB8Y7ifowcf3YyPHgDI05izyRtOeZ4MqIr7LbTArtmJ0ZHULWpn84SGMW7NAvTV1tFExpHlveHhnXuJfuGA== + dependencies: + apollo-env "^0.6.5" + +"@apollographql/graphql-playground-html@1.6.26": + version "1.6.26" + resolved "https://registry.yarnpkg.com/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.26.tgz#2f7b610392e2a872722912fc342b43cf8d641cb3" + integrity sha512-XAwXOIab51QyhBxnxySdK3nuMEUohhDsHQ5Rbco/V1vjlP75zZ0ZLHD9dTpXTN8uxKxopb2lUvJTq+M4g2Q0HQ== + dependencies: + xss "^1.0.6" + "@babel/cli@^7.10.5": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.10.5.tgz#57df2987c8cf89d0fc7d4b157ec59d7619f1b77a" @@ -2561,6 +2594,59 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.4.4.tgz#11d5db19bd178936ec89cd84519c4de439574398" integrity sha512-1oO6+dN5kdIA3sKPZhRGJTfGVP4SWV6KqlMOwry4J3HfyD68sl/3KmG7DeYUzvN+RbhXDnv/D8vNNB8168tAMg== +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= + "@reach/router@^1.3.3": version "1.3.4" resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c" @@ -3263,6 +3349,13 @@ dependencies: defer-to-connect "^1.0.1" +"@types/accepts@*", "@types/accepts@^1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" + integrity sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ== + dependencies: + "@types/node" "*" + "@types/anymatch@*": version "1.3.1" resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" @@ -3311,7 +3404,7 @@ resolved "https://registry.yarnpkg.com/@types/base16/-/base16-1.0.2.tgz#eb3a07db52309bfefb9ba010dfdb3c0784971f65" integrity sha512-oYO/U4VD1DavwrKuCSQWdLG+5K22SLPem2OQaHmFcQuwHoVeGC+JGVRji2MUqZUAIQZHEonOeVfAX09hYiLsdg== -"@types/body-parser@*": +"@types/body-parser@*", "@types/body-parser@1.19.0": version "1.19.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== @@ -3385,6 +3478,28 @@ dependencies: "@types/node" "*" +"@types/content-disposition@*": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.3.tgz#0aa116701955c2faa0717fc69cd1596095e49d96" + integrity sha512-P1bffQfhD3O4LW0ioENXUhZ9OIa0Zn+P7M+pWgkCKaT53wVLSq0mrKksCID/FGHpFhRSxRGhgrQmfhRuzwtKdg== + +"@types/cookies@*": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.4.tgz#26dedf791701abc0e36b5b79a5722f40e455f87b" + integrity sha512-oTGtMzZZAVuEjTwCjIh8T8FrC8n/uwy+PG0yTvQcdZ7etoel7C7/3MSd7qrukENTgQtotG7gvBlBojuVs7X5rw== + dependencies: + "@types/connect" "*" + "@types/express" "*" + "@types/keygrip" "*" + "@types/node" "*" + +"@types/cors@2.8.7": + version "2.8.7" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.7.tgz#ab2f47f1cba93bce27dfd3639b006cc0e5600889" + integrity sha512-sOdDRU3oRS7LBNTIqwDkPJyq0lpHYcbMTt0TrjzsXbk/e37hcLTH6eZX7CdbDeN0yJJvzw9hFBZkbtCSbk/jAQ== + dependencies: + "@types/express" "*" + "@types/d3@^3.5.43": version "3.5.43" resolved "https://registry.yarnpkg.com/@types/d3/-/d3-3.5.43.tgz#e9b4992817e0b6c5efaa7d6e5bb2cee4d73eab58" @@ -3430,7 +3545,7 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g== -"@types/express-serve-static-core@*": +"@types/express-serve-static-core@*", "@types/express-serve-static-core@4.17.9": version "4.17.9" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz#2d7b34dcfd25ec663c25c85d76608f8b249667f1" integrity sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA== @@ -3439,7 +3554,7 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/express@*": +"@types/express@*", "@types/express@4.17.7": version "4.17.7" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.7.tgz#42045be6475636d9801369cd4418ef65cdb0dd59" integrity sha512-dCOT5lcmV/uC2J9k0rPafATeeyz+99xTt54ReX11/LObZgfzJqZNcW27zGhYyX+9iSEGXGt5qLPwRSvBZcLvtQ== @@ -3461,6 +3576,13 @@ resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3" integrity sha1-wFTor02d11205jq8dviFFocU1LM= +"@types/fs-capacitor@*": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz#17113e25817f584f58100fb7a08eed288b81956e" + integrity sha512-FKVPOCFbhCvZxpVAMhdBdTfVfXUpsh15wFHgqOKxh9N9vzWZVuWCSijZ5T4U34XYNnuj2oduh6xcs1i+LPI+BQ== + dependencies: + "@types/node" "*" + "@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" @@ -3481,6 +3603,16 @@ dependencies: "@types/node" "*" +"@types/graphql-upload@^8.0.0": + version "8.0.4" + resolved "https://registry.yarnpkg.com/@types/graphql-upload/-/graphql-upload-8.0.4.tgz#23a8ffb3d2fe6e0ee07e6f16ee9d9d5e995a2f4f" + integrity sha512-0TRyJD2o8vbkmJF8InppFcPVcXKk+Rvlg/xvpHBIndSJYpmDWfmtx/ZAtl4f3jR2vfarpTqYgj8MZuJssSoU7Q== + dependencies: + "@types/express" "*" + "@types/fs-capacitor" "*" + "@types/koa" "*" + graphql "^15.3.0" + "@types/har-format@*": version "1.2.4" resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.4.tgz#3275842095abb60d14b47fa798cc9ff708dab6d4" @@ -3521,6 +3653,16 @@ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880" integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA== +"@types/http-assert@*": + version "1.5.1" + resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.1.tgz#d775e93630c2469c2f980fc27e3143240335db3b" + integrity sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ== + +"@types/http-errors@*": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.0.tgz#682477dbbbd07cd032731cb3b0e7eaee3d026b69" + integrity sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA== + "@types/http-proxy-middleware@*": version "0.19.3" resolved "https://registry.yarnpkg.com/@types/http-proxy-middleware/-/http-proxy-middleware-0.19.3.tgz#b2eb96fbc0f9ac7250b5d9c4c53aade049497d03" @@ -3592,6 +3734,32 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== +"@types/keygrip@*": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" + integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw== + +"@types/koa-compose@*": + version "3.2.5" + resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.5.tgz#85eb2e80ac50be95f37ccf8c407c09bbe3468e9d" + integrity sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ== + dependencies: + "@types/koa" "*" + +"@types/koa@*": + version "2.11.4" + resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.11.4.tgz#8af02a069a9f8e08fa47b8da28d982e652f69cfb" + integrity sha512-Etqs0kdqbuAsNr5k6mlZQelpZKVwMu9WPRHVVTLnceZlhr0pYmblRNJbCgoCMzKWWePldydU0AYEOX4Q9fnGUQ== + dependencies: + "@types/accepts" "*" + "@types/content-disposition" "*" + "@types/cookies" "*" + "@types/http-assert" "*" + "@types/http-errors" "*" + "@types/keygrip" "*" + "@types/koa-compose" "*" + "@types/node" "*" + "@types/lodash.curry@^4.1.6": version "4.1.6" resolved "https://registry.yarnpkg.com/@types/lodash.curry/-/lodash.curry-4.1.6.tgz#f26c490c80c92d7cbaa2300d542e89781d44b1ff" @@ -3618,6 +3786,11 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.159.tgz#61089719dc6fdd9c5cb46efc827f2571d1517065" integrity sha512-gF7A72f7WQN33DpqOWw9geApQPh4M3PxluMtaHxWHXEGSN12/WbcEk/eNSqWNQcQhF66VSZ06vCF94CrHwXJDg== +"@types/long@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" + integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== + "@types/markdown-to-jsx@^6.11.0": version "6.11.2" resolved "https://registry.yarnpkg.com/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.2.tgz#05d1aaffbf15be7be12c70535fa4fed65cc7c64f" @@ -3654,7 +3827,7 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= -"@types/node-fetch@^2.5.4": +"@types/node-fetch@2.5.7", "@types/node-fetch@^2.5.4": version "2.5.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== @@ -3667,6 +3840,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1" integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g== +"@types/node@^10.1.0": + version "10.17.39" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.39.tgz#ce1122758d0608de8303667cebf171f44192629b" + integrity sha512-dJLCxrpQmgyxYGcl0Ae9MTsQgI22qHHcGFj/8VKu7McJA5zQpnuGjoksnxbo1JxSjW/Nahnl13W8MYZf01CZHA== + "@types/node@^12.0.12": version "12.12.54" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.54.tgz#a4b58d8df3a4677b6c08bfbc94b7ad7a7a5f82d1" @@ -3962,6 +4140,13 @@ "@types/webpack-sources" "*" source-map "^0.6.0" +"@types/ws@^7.0.0": + version "7.2.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.2.7.tgz#362ad1a1d62721bdb725e72c8cccf357078cf5a3" + integrity sha512-UUFC/xxqFLP17hTva8/lVT0SybLUrfSD9c+iapKb0fEiC8uoDbA+xuZ3pAN603eW+bY8ebSMLm9jXdIPnD0ZgA== + dependencies: + "@types/node" "*" + "@types/yargs-parser@*": version "15.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" @@ -4258,7 +4443,7 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: +accepts@^1.3.5, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== @@ -4493,12 +4678,39 @@ anymatch@^3.0.3, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -apollo-cache-control@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.1.1.tgz#173d14ceb3eb9e7cb53de7eb8b61bee6159d4171" - integrity sha512-XJQs167e9u+e5ybSi51nGYr70NPBbswdvTEHtbtXbwkZ+n9t0SLPvUcoqceayOSwjK1XYOdU/EKPawNdb3rLQA== +apollo-cache-control@^0.11.3: + version "0.11.3" + resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.11.3.tgz#caa409692bccc35da582cb133c023c0175b84e91" + integrity sha512-21GCeC9AIIa22uD0Vtqn/N0D5kOB4rY/Pa9aQhxVeLN+4f8Eu4nmteXhFypUD0LL1/58dmm8lS5embsfoIGjEA== dependencies: - graphql-extensions "^0.0.x" + apollo-server-env "^2.4.5" + apollo-server-plugin-base "^0.10.1" + +apollo-datasource@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-0.7.2.tgz#1662ee93453a9b89af6f73ce561bde46b41ebf31" + integrity sha512-ibnW+s4BMp4K2AgzLEtvzkjg7dJgCaw9M5b5N0YKNmeRZRnl/I/qBTQae648FsRKgMwTbRQIvBhQ0URUFAqFOw== + dependencies: + apollo-server-caching "^0.5.2" + apollo-server-env "^2.4.5" + +apollo-env@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/apollo-env/-/apollo-env-0.6.5.tgz#5a36e699d39e2356381f7203493187260fded9f3" + integrity sha512-jeBUVsGymeTHYWp3me0R2CZRZrFeuSZeICZHCeRflHTfnQtlmbSXdy5E0pOyRM9CU4JfQkKDC98S1YglQj7Bzg== + dependencies: + "@types/node-fetch" "2.5.7" + core-js "^3.0.1" + node-fetch "^2.2.0" + sha.js "^2.4.11" + +apollo-graphql@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/apollo-graphql/-/apollo-graphql-0.6.0.tgz#37bee7dc853213269137f4c60bfdf2ee28658669" + integrity sha512-BxTf5LOQe649e9BNTPdyCGItVv4Ll8wZ2BKnmiYpRAocYEXAVrQPWuSr3dO4iipqAU8X0gvle/Xu9mSqg5b7Qg== + dependencies: + apollo-env "^0.6.5" + lodash.sortby "^4.7.0" apollo-link@^1.2.14: version "1.2.14" @@ -4510,34 +4722,122 @@ apollo-link@^1.2.14: tslib "^1.9.3" zen-observable-ts "^0.8.21" -apollo-server-core@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-1.4.0.tgz#4faff7f110bfdd6c3f47008302ae24140f94c592" - integrity sha512-BP1Vh39krgEjkQxbjTdBURUjLHbFq1zeOChDJgaRsMxGtlhzuLWwwC6lLdPatN8jEPbeHq8Tndp9QZ3iQZOKKA== +apollo-reporting-protobuf@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.6.0.tgz#179e49e99229851d588b1fe6faff4ffdcf503224" + integrity sha512-AFLQIuO0QhkoCF+41Be/B/YU0C33BZ0opfyXorIjM3MNNiEDSyjZqmUozlB3LqgfhT9mn2IR5RSsA+1b4VovDQ== dependencies: - apollo-cache-control "^0.1.0" - apollo-tracing "^0.1.0" - graphql-extensions "^0.0.x" + "@apollo/protobufjs" "^1.0.3" -apollo-server-express@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-1.4.0.tgz#7d7c58d6d6f9892b83fe575669093bb66738b125" - integrity sha512-zkH00nxhLnJfO0HgnNPBTfZw8qI5ILaPZ5TecMCI9+Y9Ssr2b0bFr9pBRsXy9eudPhI+/O4yqegSUsnLdF/CPw== +apollo-server-caching@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-0.5.2.tgz#bef5d5e0d48473a454927a66b7bb947a0b6eb13e" + integrity sha512-HUcP3TlgRsuGgeTOn8QMbkdx0hLPXyEJehZIPrcof0ATz7j7aTPA4at7gaiFHCo8gk07DaWYGB3PFgjboXRcWQ== dependencies: - apollo-server-core "^1.4.0" - apollo-server-module-graphiql "^1.4.0" + lru-cache "^5.0.0" -apollo-server-module-graphiql@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/apollo-server-module-graphiql/-/apollo-server-module-graphiql-1.4.0.tgz#c559efa285578820709f1769bb85d3b3eed3d8ec" - integrity sha512-GmkOcb5he2x5gat+TuiTvabnBf1m4jzdecal3XbXBh/Jg+kx4hcvO3TTDFQ9CuTprtzdcVyA11iqG7iOMOt7vA== - -apollo-tracing@^0.1.0: - version "0.1.4" - resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.1.4.tgz#5b8ae1b01526b160ee6e552a7f131923a9aedcc7" - integrity sha512-Uv+1nh5AsNmC3m130i2u3IqbS+nrxyVV3KYimH5QKsdPjxxIQB3JAT+jJmpeDxBel8gDVstNmCh82QSLxLSIdQ== +apollo-server-core@^2.18.2: + version "2.18.2" + resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.18.2.tgz#1b8a625531a92e137f68c730bc42b9e3f7d7fcbb" + integrity sha512-phz57BFBukMa3Ta7ZVW7pj1pdUne9KYLbcBdEcITr+I0+nbhy+YM8gcgpOnjrokWYiEZgIe52XeM3m4BMLw5dg== dependencies: - graphql-extensions "~0.0.9" + "@apollographql/apollo-tools" "^0.4.3" + "@apollographql/graphql-playground-html" "1.6.26" + "@types/graphql-upload" "^8.0.0" + "@types/ws" "^7.0.0" + apollo-cache-control "^0.11.3" + apollo-datasource "^0.7.2" + apollo-graphql "^0.6.0" + apollo-reporting-protobuf "^0.6.0" + apollo-server-caching "^0.5.2" + apollo-server-env "^2.4.5" + apollo-server-errors "^2.4.2" + apollo-server-plugin-base "^0.10.1" + apollo-server-types "^0.6.0" + apollo-tracing "^0.11.4" + async-retry "^1.2.1" + fast-json-stable-stringify "^2.0.0" + graphql-extensions "^0.12.5" + graphql-tag "^2.9.2" + graphql-tools "^4.0.0" + graphql-upload "^8.0.2" + loglevel "^1.6.7" + lru-cache "^5.0.0" + sha.js "^2.4.11" + subscriptions-transport-ws "^0.9.11" + uuid "^8.0.0" + ws "^6.0.0" + +apollo-server-env@^2.4.5: + version "2.4.5" + resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-2.4.5.tgz#73730b4f0439094a2272a9d0caa4079d4b661d5f" + integrity sha512-nfNhmGPzbq3xCEWT8eRpoHXIPNcNy3QcEoBlzVMjeglrBGryLG2LXwBSPnVmTRRrzUYugX0ULBtgE3rBFNoUgA== + dependencies: + node-fetch "^2.1.2" + util.promisify "^1.0.0" + +apollo-server-errors@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-2.4.2.tgz#1128738a1d14da989f58420896d70524784eabe5" + integrity sha512-FeGxW3Batn6sUtX3OVVUm7o56EgjxDlmgpTLNyWcLb0j6P8mw9oLNyAm3B+deHA4KNdNHO5BmHS2g1SJYjqPCQ== + +apollo-server-express@^2.18.2: + version "2.18.2" + resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.18.2.tgz#eb5f1ba566268080dd56269d9a7dfade55ccded8" + integrity sha512-9P5YOSE2amcNdkXqxqU3oulp+lpwoIBdwS2vOP69kl6ix+n7vEWHde4ulHwwl4xLdtZ88yyxgdKJEIkhaepiNw== + dependencies: + "@apollographql/graphql-playground-html" "1.6.26" + "@types/accepts" "^1.3.5" + "@types/body-parser" "1.19.0" + "@types/cors" "2.8.7" + "@types/express" "4.17.7" + "@types/express-serve-static-core" "4.17.9" + accepts "^1.3.5" + apollo-server-core "^2.18.2" + apollo-server-types "^0.6.0" + body-parser "^1.18.3" + cors "^2.8.4" + express "^4.17.1" + graphql-subscriptions "^1.0.0" + graphql-tools "^4.0.0" + parseurl "^1.3.2" + subscriptions-transport-ws "^0.9.16" + type-is "^1.6.16" + +apollo-server-plugin-base@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.10.1.tgz#b053d43b1ff5f728735ed35095cf4427657bfa9f" + integrity sha512-XChCBDNyfByWqVXptsjPwrwrCj5cxMmNbchZZi8KXjtJ0hN2C/9BMNlInJd6bVGXvUbkRJYUakfKCfO5dZmwIg== + dependencies: + apollo-server-types "^0.6.0" + +apollo-server-types@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-0.6.0.tgz#6085f8389881b79911384dab6c0e8a8b91c0e1a2" + integrity sha512-usqXaz81bHxD2IZvKEQNnLpSbf2Z/BmobXZAjEefJEQv1ItNn+lJNUmSSEfGejHvHlg2A7WuAJKJWyDWcJrNnA== + dependencies: + apollo-reporting-protobuf "^0.6.0" + apollo-server-caching "^0.5.2" + apollo-server-env "^2.4.5" + +apollo-server@^2.18.2: + version "2.18.2" + resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-2.18.2.tgz#de55a8b7e90e6ddaba29331ecc9469d6945fff23" + integrity sha512-I8B7Zd7WrqUhOWAVMQRmKhgJkvdTlCY7C74WToCdkeOyHl1/myiA7tERKedgv111xOTpIMZHyBzcCRX5CH/oqQ== + dependencies: + apollo-server-core "^2.18.2" + apollo-server-express "^2.18.2" + express "^4.0.0" + graphql-subscriptions "^1.0.0" + graphql-tools "^4.0.0" + +apollo-tracing@^0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.11.4.tgz#e953547064bc50dfa337cbe56836271bfd2d2efc" + integrity sha512-zBu/SwQlXfbdpcKLzWARGVjrEkIZUW3W9Mb4CCIzv07HbBQ8IQpmf9w7HIJJefC7rBiBJYg6JBGyuro3N2lxCA== + dependencies: + apollo-server-env "^2.4.5" + apollo-server-plugin-base "^0.10.1" apollo-utilities@^1.0.1, apollo-utilities@^1.3.0: version "1.3.4" @@ -4781,6 +5081,13 @@ async-limiter@^1.0.0, async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== +async-retry@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.1.tgz#139f31f8ddce50c0870b0ba558a6079684aaed55" + integrity sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA== + dependencies: + retry "0.12.0" + async@0.9.x: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" @@ -5232,6 +5539,11 @@ babel-preset-jest@^26.2.0: babel-plugin-transform-undefined-to-void "^6.9.4" lodash "^4.17.11" +backo2@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + bail@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" @@ -5350,7 +5662,7 @@ bn.js@^5.1.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0" integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA== -body-parser@1.19.0, body-parser@^1.19.0: +body-parser@1.19.0, body-parser@^1.18.3, body-parser@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== @@ -5595,6 +5907,13 @@ builtins@^1.0.3: resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= +busboy@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b" + integrity sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw== + dependencies: + dicer "0.3.0" + byline@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" @@ -6221,7 +6540,7 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== -commander@^2.19.0, commander@^2.20.0: +commander@^2.19.0, commander@^2.20.0, commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -6525,7 +6844,7 @@ core-js-pure@^3.0.1: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== -core-js@^2.5.3, core-js@^2.5.7, core-js@^2.6.5: +core-js@^2.5.7, core-js@^2.6.5: version "2.6.11" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== @@ -6540,7 +6859,7 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cors@^2.8.5: +cors@^2.8.4, cors@^2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== @@ -6784,6 +7103,11 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== +cssfilter@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" + integrity sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4= + csso@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.3.tgz#0d9985dc852c7cc2b2cacfbbe1079014d1a8e903" @@ -7147,6 +7471,13 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" +dicer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872" + integrity sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA== + dependencies: + streamsearch "0.1.2" + diff-match-patch@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" @@ -8101,7 +8432,7 @@ expirymanager@^0.9.3: resolved "https://registry.yarnpkg.com/expirymanager/-/expirymanager-0.9.3.tgz#e5f6b3ba00d8d76cf63311c2b71d7dfc9bde3e4f" integrity sha1-5fazugDY12z2MxHCtx19/JvePk8= -express@^4.17.0, express@^4.17.1: +express@^4.0.0, express@^4.17.0, express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== @@ -8643,6 +8974,11 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" +fs-capacitor@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-2.0.4.tgz#5a22e72d40ae5078b4fe64fe4d08c0d3fc88ad3c" + integrity sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA== + fs-extra@6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" @@ -9166,22 +9502,28 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== -graphql-extensions@^0.0.x, graphql-extensions@~0.0.9: - version "0.0.10" - resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.0.10.tgz#34bdb2546d43f6a5bc89ab23c295ec0466c6843d" - integrity sha512-TnQueqUDCYzOSrpQb3q1ngDSP2otJSF+9yNLrQGPzkMsvnQ+v6e2d5tl+B35D4y+XpmvVnAn4T3ZK28mkILveA== +graphql-extensions@^0.12.5: + version "0.12.5" + resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.12.5.tgz#b0e6b218f26f5aafe9dd73642410fec6beac0575" + integrity sha512-mGyGaktGpK3TVBtM0ZoyPX6Xk0mN9GYX9DRyFzDU4k4A2w93nLX7Ebcp+9/O5nHRmgrc0WziYYSmoWq2WNIoUQ== dependencies: - core-js "^2.5.3" - source-map-support "^0.5.1" + "@apollographql/apollo-tools" "^0.4.3" + apollo-server-env "^2.4.5" + apollo-server-types "^0.6.0" -graphql-server-express@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/graphql-server-express/-/graphql-server-express-1.4.1.tgz#b096743fb8e3380a3e93cefbe635d0f18f7a57f5" - integrity sha512-7HEIz2USTCXgk4YMKIcOVUdVZQT429nZnPQr4Gqp5pydZ08KJM9Y2sl9+VU+3a91HGKyrtF04eUumuYeS2fDcg== +graphql-subscriptions@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-1.1.0.tgz#5f2fa4233eda44cf7570526adfcf3c16937aef11" + integrity sha512-6WzlBFC0lWmXJbIVE8OgFgXIP4RJi3OQgTPa0DVMsDXdpRDjTsM1K9wfl5HSYX7R87QAGlvcv2Y4BIZa/ItonA== dependencies: - apollo-server-express "^1.4.0" + iterall "^1.2.1" -graphql-tools@^4.0.8: +graphql-tag@^2.9.2: + version "2.11.0" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.11.0.tgz#1deb53a01c46a7eb401d6cb59dec86fa1cccbffd" + integrity sha512-VmsD5pJqWJnQZMUeRwrDhfgoyqcfwEkvtpANqcoUG8/tOLkwNgU9mzub/Mc78OJMhHjx7gfAMTxzdG43VGg3bA== + +graphql-tools@^4.0.0: version "4.0.8" resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-4.0.8.tgz#e7fb9f0d43408fb0878ba66b522ce871bafe9d30" integrity sha512-MW+ioleBrwhRjalKjYaLQbr+920pHBgy9vM/n47sswtns8+96sRn5M/G+J1eu7IMeKWiN/9p6tmwCHU7552VJg== @@ -9192,12 +9534,20 @@ graphql-tools@^4.0.8: iterall "^1.1.3" uuid "^3.1.0" -graphql@^0.13.2: - version "0.13.2" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.13.2.tgz#4c740ae3c222823e7004096f832e7b93b2108270" - integrity sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog== +graphql-upload@^8.0.2: + version "8.1.0" + resolved "https://registry.yarnpkg.com/graphql-upload/-/graphql-upload-8.1.0.tgz#6d0ab662db5677a68bfb1f2c870ab2544c14939a" + integrity sha512-U2OiDI5VxYmzRKw0Z2dmfk0zkqMRaecH9Smh1U277gVgVe9Qn+18xqf4skwr4YJszGIh7iQDZ57+5ygOK9sM/Q== dependencies: - iterall "^1.2.1" + busboy "^0.3.1" + fs-capacitor "^2.0.4" + http-errors "^1.7.3" + object-path "^0.11.4" + +graphql@^15.3.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278" + integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w== growly@^1.3.0: version "1.3.0" @@ -9602,6 +9952,17 @@ http-errors@1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" +http-errors@^1.7.3: + version "1.8.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507" + integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + http-errors@~1.6.2: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" @@ -11817,6 +12178,11 @@ log-symbols@^4.0.0: dependencies: chalk "^4.0.0" +loglevel@^1.6.7: + version "1.7.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0" + integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ== + loglevel@^1.6.8: version "1.6.8" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" @@ -11830,6 +12196,11 @@ loglevelnext@^1.0.1: es6-symbol "^3.1.1" object.assign "^4.1.0" +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + longest-streak@^2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" @@ -11875,7 +12246,7 @@ lowlight@1.12.1: fault "^1.0.2" highlight.js "~9.15.0" -lru-cache@^5.1.1: +lru-cache@^5.0.0, lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== @@ -12660,6 +13031,11 @@ node-fetch-npm@^2.0.2: json-parse-better-errors "^1.0.0" safe-buffer "^5.1.1" +node-fetch@^2.1.2, node-fetch@^2.2.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" @@ -13472,7 +13848,7 @@ parse5@^6.0.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parseurl@~1.3.2, parseurl@~1.3.3: +parseurl@^1.3.2, parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -15191,16 +15567,16 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +retry@0.12.0, retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + retry@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -15599,12 +15975,17 @@ setprototypeof@1.1.1: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + settle-promise@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/settle-promise/-/settle-promise-1.0.0.tgz#697adb58b821f387ce2757c06efc9de5f0ee33d8" integrity sha1-aXrbWLgh84fOJ1fAbvyd5fDuM9g= -sha.js@^2.4.0, sha.js@^2.4.8: +sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== @@ -15896,7 +16277,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.1, source-map-support@^0.5.16, source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.12: +source-map-support@^0.5.16, source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.12: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -16125,6 +16506,11 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== +streamsearch@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" + integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= + string-length@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" @@ -16461,6 +16847,17 @@ stylelint@^13.6.1: v8-compile-cache "^2.1.1" write-file-atomic "^3.0.3" +subscriptions-transport-ws@^0.9.11, subscriptions-transport-ws@^0.9.16: + version "0.9.18" + resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.18.tgz#bcf02320c911fbadb054f7f928e51c6041a37b97" + integrity sha512-tztzcBTNoEbuErsVQpTN2xUNN/efAZXyCyL5m3x4t6SKrEiTL2N8SaKWBFWM4u56pL79ULif3zjyeq+oV+nOaA== + dependencies: + backo2 "^1.0.2" + eventemitter3 "^3.1.0" + iterall "^1.2.1" + symbol-observable "^1.0.4" + ws "^5.2.0" + sugarss@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d" @@ -16567,7 +16964,7 @@ symbol-observable@1.0.1: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= -symbol-observable@^1.2.0: +symbol-observable@^1.0.4, symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== @@ -17118,7 +17515,7 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@~1.6.17, type-is@~1.6.18: +type-is@^1.6.16, type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -17468,7 +17865,7 @@ util.promisify@1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" -util.promisify@~1.0.0: +util.promisify@^1.0.0, util.promisify@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== @@ -18063,7 +18460,14 @@ ws@7.1.0: dependencies: async-limiter "^1.0.0" -ws@^6.2.1: +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + +ws@^6.0.0, ws@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== @@ -18085,6 +18489,14 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xss@^1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.8.tgz#32feb87feb74b3dcd3d404b7a68ababf10700535" + integrity sha512-3MgPdaXV8rfQ/pNn16Eio6VXYPTkqwa0vc7GkiymmY/DqR1SE/7VPAAVZz1GJsJFrllMYO3RHfEaiUGjab6TNw== + dependencies: + commander "^2.20.3" + cssfilter "0.0.10" + xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" From ee52c29a8d8053d57906a8254d079490dee07a20 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sun, 25 Oct 2020 19:32:04 -0400 Subject: [PATCH 08/25] chore(core): convert to TypeScript (#655) * Get started * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash --- .../d3-state-visualizer/src/charts/index.ts | 1 + .../src/charts/tree/tree.ts | 4 +- packages/d3-state-visualizer/src/index.ts | 1 + packages/devui/src/Tabs/index.ts | 1 + packages/devui/src/index.ts | 3 +- packages/devui/src/utils/theme.ts | 7 +- .../src/Chart.tsx | 2 + .../src/ChartMonitor.tsx | 2 + packages/redux-devtools-core/.babelrc | 6 +- packages/redux-devtools-core/.eslintignore | 2 + packages/redux-devtools-core/.eslintrc.js | 29 + packages/redux-devtools-core/jest.config.js | 4 + packages/redux-devtools-core/package.json | 100 +-- .../src/app/actions/index.js | 122 ---- .../src/app/actions/index.ts | 573 ++++++++++++++++++ .../{BottomButtons.js => BottomButtons.tsx} | 11 +- .../app/components/{Header.js => Header.tsx} | 27 +- .../src/app/components/InstanceSelector.js | 48 -- .../src/app/components/InstanceSelector.tsx | 43 ++ .../src/app/components/MonitorSelector.js | 45 -- .../src/app/components/MonitorSelector.tsx | 39 ++ .../{Connection.js => Connection.tsx} | 109 ++-- .../Settings/{Themes.js => Themes.tsx} | 32 +- .../src/app/components/Settings/index.js | 32 - .../src/app/components/Settings/index.tsx | 34 ++ .../{TopButtons.js => TopButtons.tsx} | 15 +- ...spatcherButton.js => DispatcherButton.tsx} | 27 +- .../app/components/buttons/ExportButton.js | 33 - .../app/components/buttons/ExportButton.tsx | 28 + .../app/components/buttons/ImportButton.js | 64 -- .../app/components/buttons/ImportButton.tsx | 54 ++ .../buttons/{LockButton.js => LockButton.tsx} | 24 +- .../{PersistButton.js => PersistButton.tsx} | 38 +- .../{PrintButton.js => PrintButton.tsx} | 14 +- .../{RecordButton.js => RecordButton.tsx} | 22 +- .../{SliderButton.js => SliderButton.tsx} | 27 +- .../src/app/components/buttons/SyncButton.js | 45 -- .../src/app/components/buttons/SyncButton.tsx | 39 ++ .../{actionTypes.js => actionTypes.ts} | 0 .../constants/{dataTypes.js => dataTypes.ts} | 0 ...ketActionTypes.js => socketActionTypes.ts} | 11 +- .../{socketOptions.js => socketOptions.ts} | 0 .../containers/{Actions.js => Actions.tsx} | 37 +- .../src/app/containers/{App.js => App.tsx} | 43 +- .../containers/{DevTools.js => DevTools.tsx} | 67 +- ...itorWrapper.js => ChartMonitorWrapper.tsx} | 35 +- .../{Dispatcher.js => Dispatcher.tsx} | 62 +- .../{ChartTab.js => ChartTab.tsx} | 66 +- .../{RawTab.js => RawTab.tsx} | 16 +- .../{SubTabs.js => SubTabs.tsx} | 59 +- .../{VisualDiffTab.js => VisualDiffTab.tsx} | 21 +- .../InspectorWrapper/{index.js => index.tsx} | 33 +- .../monitors/{Slider.js => Slider.tsx} | 23 +- .../src/app/{index.js => index.tsx} | 27 +- .../src/app/middlewares/{api.js => api.ts} | 104 +++- .../{exportState.js => exportState.ts} | 19 +- .../reducers/{connection.js => connection.ts} | 15 +- .../src/app/reducers/index.js | 22 - .../src/app/reducers/index.ts | 34 ++ .../reducers/{instances.js => instances.ts} | 103 +++- .../app/reducers/{monitor.js => monitor.ts} | 36 +- .../{notification.js => notification.ts} | 12 +- .../app/reducers/{reports.js => reports.ts} | 21 +- .../src/app/reducers/section.js | 8 - .../src/app/reducers/section.ts | 11 + .../src/app/reducers/{socket.js => socket.ts} | 25 +- .../src/app/reducers/theme.js | 15 - .../src/app/reducers/theme.ts | 27 + .../src/app/store/configureStore.js | 41 -- .../src/app/store/configureStore.ts | 60 ++ ...xcessActions.js => commitExcessActions.ts} | 4 +- .../utils/{getMonitor.js => getMonitor.tsx} | 2 +- .../{monitorActions.js => monitorActions.ts} | 18 +- .../app/utils/{parseJSON.js => parseJSON.ts} | 15 +- .../src/app/utils/stringifyJSON.js | 20 - .../src/app/utils/stringifyJSON.ts | 24 + .../utils/{updateState.js => updateState.ts} | 21 +- packages/redux-devtools-core/src/index.js | 8 - .../{index.js => src/index.tsx} | 2 +- .../src/utils/catchErrors.js | 42 -- .../src/utils/catchErrors.ts | 68 +++ .../src/utils/{filters.js => filters.ts} | 92 ++- .../src/utils/get-params.ts | 4 + .../src/utils/importState.js | 69 --- .../src/utils/importState.ts | 105 ++++ .../src/utils/{index.js => index.ts} | 130 +++- .../test/__mocks__/styleMock.js | 1 - .../test/{app.spec.js => app.spec.tsx} | 6 +- .../test/{setup.js => setup.ts} | 0 .../redux-devtools-core/test/tsconfig.json | 4 + packages/redux-devtools-core/tsconfig.json | 7 + .../redux-devtools-core/tsconfig.webpack.json | 4 + .../{webpack.config.js => webpack.config.ts} | 23 +- ...ck.config.umd.js => webpack.config.umd.ts} | 19 +- .../src/ActionPreview.tsx | 4 +- .../src/DevtoolsInspector.tsx | 6 +- .../src/redux.ts | 2 +- .../src/tabs/JSONDiff.tsx | 2 +- .../src/tabs/getItemString.tsx | 2 +- .../src/immutable/index.ts | 1 + .../redux-devtools-serialize/src/index.ts | 9 +- yarn.lock | 114 +++- 102 files changed, 2352 insertions(+), 1236 deletions(-) create mode 100644 packages/redux-devtools-core/.eslintignore create mode 100644 packages/redux-devtools-core/.eslintrc.js create mode 100644 packages/redux-devtools-core/jest.config.js delete mode 100644 packages/redux-devtools-core/src/app/actions/index.js create mode 100644 packages/redux-devtools-core/src/app/actions/index.ts rename packages/redux-devtools-core/src/app/components/{BottomButtons.js => BottomButtons.tsx} (85%) rename packages/redux-devtools-core/src/app/components/{Header.js => Header.tsx} (77%) delete mode 100644 packages/redux-devtools-core/src/app/components/InstanceSelector.js create mode 100644 packages/redux-devtools-core/src/app/components/InstanceSelector.tsx delete mode 100644 packages/redux-devtools-core/src/app/components/MonitorSelector.js create mode 100644 packages/redux-devtools-core/src/app/components/MonitorSelector.tsx rename packages/redux-devtools-core/src/app/components/Settings/{Connection.js => Connection.tsx} (55%) rename packages/redux-devtools-core/src/app/components/Settings/{Themes.js => Themes.tsx} (64%) delete mode 100644 packages/redux-devtools-core/src/app/components/Settings/index.js create mode 100644 packages/redux-devtools-core/src/app/components/Settings/index.tsx rename packages/redux-devtools-core/src/app/components/{TopButtons.js => TopButtons.tsx} (84%) rename packages/redux-devtools-core/src/app/components/buttons/{DispatcherButton.js => DispatcherButton.tsx} (53%) delete mode 100644 packages/redux-devtools-core/src/app/components/buttons/ExportButton.js create mode 100644 packages/redux-devtools-core/src/app/components/buttons/ExportButton.tsx delete mode 100644 packages/redux-devtools-core/src/app/components/buttons/ImportButton.js create mode 100644 packages/redux-devtools-core/src/app/components/buttons/ImportButton.tsx rename packages/redux-devtools-core/src/app/components/buttons/{LockButton.js => LockButton.tsx} (60%) rename packages/redux-devtools-core/src/app/components/buttons/{PersistButton.js => PersistButton.tsx} (52%) rename packages/redux-devtools-core/src/app/components/buttons/{PrintButton.js => PrintButton.tsx} (72%) rename packages/redux-devtools-core/src/app/components/buttons/{RecordButton.js => RecordButton.tsx} (61%) rename packages/redux-devtools-core/src/app/components/buttons/{SliderButton.js => SliderButton.tsx} (51%) delete mode 100644 packages/redux-devtools-core/src/app/components/buttons/SyncButton.js create mode 100644 packages/redux-devtools-core/src/app/components/buttons/SyncButton.tsx rename packages/redux-devtools-core/src/app/constants/{actionTypes.js => actionTypes.ts} (100%) rename packages/redux-devtools-core/src/app/constants/{dataTypes.js => dataTypes.ts} (100%) rename packages/redux-devtools-core/src/app/constants/{socketActionTypes.js => socketActionTypes.ts} (78%) rename packages/redux-devtools-core/src/app/constants/{socketOptions.js => socketOptions.ts} (100%) rename packages/redux-devtools-core/src/app/containers/{Actions.js => Actions.tsx} (72%) rename packages/redux-devtools-core/src/app/containers/{App.js => App.tsx} (54%) rename packages/redux-devtools-core/src/app/containers/{DevTools.js => DevTools.tsx} (53%) rename packages/redux-devtools-core/src/app/containers/monitors/{ChartMonitorWrapper.js => ChartMonitorWrapper.tsx} (56%) rename packages/redux-devtools-core/src/app/containers/monitors/{Dispatcher.js => Dispatcher.tsx} (77%) rename packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/{ChartTab.js => ChartTab.tsx} (53%) rename packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/{RawTab.js => RawTab.tsx} (57%) rename packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/{SubTabs.js => SubTabs.tsx} (62%) rename packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/{VisualDiffTab.js => VisualDiffTab.tsx} (93%) rename packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/{index.js => index.tsx} (58%) rename packages/redux-devtools-core/src/app/containers/monitors/{Slider.js => Slider.tsx} (58%) rename packages/redux-devtools-core/src/app/{index.js => index.tsx} (58%) rename packages/redux-devtools-core/src/app/middlewares/{api.js => api.ts} (70%) rename packages/redux-devtools-core/src/app/middlewares/{exportState.js => exportState.ts} (72%) rename packages/redux-devtools-core/src/app/reducers/{connection.js => connection.ts} (50%) delete mode 100644 packages/redux-devtools-core/src/app/reducers/index.js create mode 100644 packages/redux-devtools-core/src/app/reducers/index.ts rename packages/redux-devtools-core/src/app/reducers/{instances.js => instances.ts} (76%) rename packages/redux-devtools-core/src/app/reducers/{monitor.js => monitor.ts} (62%) rename packages/redux-devtools-core/src/app/reducers/{notification.js => notification.ts} (57%) rename packages/redux-devtools-core/src/app/reducers/{reports.js => reports.ts} (67%) delete mode 100644 packages/redux-devtools-core/src/app/reducers/section.js create mode 100644 packages/redux-devtools-core/src/app/reducers/section.ts rename packages/redux-devtools-core/src/app/reducers/{socket.js => socket.ts} (72%) delete mode 100644 packages/redux-devtools-core/src/app/reducers/theme.js create mode 100644 packages/redux-devtools-core/src/app/reducers/theme.ts delete mode 100644 packages/redux-devtools-core/src/app/store/configureStore.js create mode 100644 packages/redux-devtools-core/src/app/store/configureStore.ts rename packages/redux-devtools-core/src/app/utils/{commitExcessActions.js => commitExcessActions.ts} (89%) rename packages/redux-devtools-core/src/app/utils/{getMonitor.js => getMonitor.tsx} (90%) rename packages/redux-devtools-core/src/app/utils/{monitorActions.js => monitorActions.ts} (78%) rename packages/redux-devtools-core/src/app/utils/{parseJSON.js => parseJSON.ts} (70%) delete mode 100644 packages/redux-devtools-core/src/app/utils/stringifyJSON.js create mode 100644 packages/redux-devtools-core/src/app/utils/stringifyJSON.ts rename packages/redux-devtools-core/src/app/utils/{updateState.js => updateState.ts} (66%) delete mode 100644 packages/redux-devtools-core/src/index.js rename packages/redux-devtools-core/{index.js => src/index.tsx} (94%) delete mode 100644 packages/redux-devtools-core/src/utils/catchErrors.js create mode 100644 packages/redux-devtools-core/src/utils/catchErrors.ts rename packages/redux-devtools-core/src/utils/{filters.js => filters.ts} (55%) create mode 100644 packages/redux-devtools-core/src/utils/get-params.ts delete mode 100644 packages/redux-devtools-core/src/utils/importState.js create mode 100644 packages/redux-devtools-core/src/utils/importState.ts rename packages/redux-devtools-core/src/utils/{index.js => index.ts} (55%) delete mode 100644 packages/redux-devtools-core/test/__mocks__/styleMock.js rename packages/redux-devtools-core/test/{app.spec.js => app.spec.tsx} (92%) rename packages/redux-devtools-core/test/{setup.js => setup.ts} (100%) create mode 100644 packages/redux-devtools-core/test/tsconfig.json create mode 100644 packages/redux-devtools-core/tsconfig.json create mode 100644 packages/redux-devtools-core/tsconfig.webpack.json rename packages/redux-devtools-core/{webpack.config.js => webpack.config.ts} (72%) rename packages/redux-devtools-core/{webpack.config.umd.js => webpack.config.umd.ts} (74%) diff --git a/packages/d3-state-visualizer/src/charts/index.ts b/packages/d3-state-visualizer/src/charts/index.ts index 33abb024..aaf238e0 100644 --- a/packages/d3-state-visualizer/src/charts/index.ts +++ b/packages/d3-state-visualizer/src/charts/index.ts @@ -1 +1,2 @@ export { default as tree } from './tree/tree'; +export type { InputOptions, NodeWithId } from './tree/tree'; diff --git a/packages/d3-state-visualizer/src/charts/tree/tree.ts b/packages/d3-state-visualizer/src/charts/tree/tree.ts index 894eceb4..47ae5176 100644 --- a/packages/d3-state-visualizer/src/charts/tree/tree.ts +++ b/packages/d3-state-visualizer/src/charts/tree/tree.ts @@ -10,7 +10,7 @@ import { } from './utils'; import d3tooltip from 'd3tooltip'; -interface InputOptions { +export interface InputOptions { // eslint-disable-next-line @typescript-eslint/ban-types state?: {} | null; // eslint-disable-next-line @typescript-eslint/ban-types @@ -34,7 +34,7 @@ interface InputOptions { widthBetweenNodesCoeff: number; transitionDuration: number; blinkDuration: number; - onClickText: () => void; + onClickText: (datum: NodeWithId) => void; tooltipOptions: { disabled?: boolean; left?: number | undefined; diff --git a/packages/d3-state-visualizer/src/index.ts b/packages/d3-state-visualizer/src/index.ts index 78a37ac1..60b538ee 100644 --- a/packages/d3-state-visualizer/src/index.ts +++ b/packages/d3-state-visualizer/src/index.ts @@ -1,5 +1,6 @@ import * as charts from './charts'; export { tree } from './charts'; +export type { InputOptions, NodeWithId } from './charts'; export default charts; diff --git a/packages/devui/src/Tabs/index.ts b/packages/devui/src/Tabs/index.ts index bc6749b1..f58f9e2c 100644 --- a/packages/devui/src/Tabs/index.ts +++ b/packages/devui/src/Tabs/index.ts @@ -1 +1,2 @@ export { default } from './Tabs'; +export { Tab } from './TabsHeader'; diff --git a/packages/devui/src/index.ts b/packages/devui/src/index.ts index cf2dfa86..eabef90a 100644 --- a/packages/devui/src/index.ts +++ b/packages/devui/src/index.ts @@ -6,7 +6,7 @@ export { default as Editor } from './Editor'; export { default as Form } from './Form'; export { default as Select } from './Select'; export { default as Slider } from './Slider'; -export { default as Tabs } from './Tabs'; +export { default as Tabs, Tab } from './Tabs'; export { default as SegmentedControl } from './SegmentedControl'; export { default as Notification } from './Notification'; export * from './Toolbar'; @@ -14,3 +14,4 @@ export * from './Toolbar'; import color from './utils/color'; export const effects = { color }; export { default as createStyledComponent } from './utils/createStyledComponent'; +export { Theme, ThemeFromProvider, Scheme } from './utils/theme'; diff --git a/packages/devui/src/utils/theme.ts b/packages/devui/src/utils/theme.ts index 5bfd788c..b0180cb7 100644 --- a/packages/devui/src/utils/theme.ts +++ b/packages/devui/src/utils/theme.ts @@ -3,19 +3,22 @@ import { nicinabox as defaultDarkScheme } from 'redux-devtools-themes'; import * as baseSchemes from 'base16'; import * as additionalSchemes from '../colorSchemes'; import invertColors from '../utils/invertColors'; -import { Theme } from '../themes/default'; +import { Theme as ThemeBase } from '../themes/default'; export const schemes = { ...baseSchemes, ...additionalSchemes }; export const listSchemes = () => Object.keys(schemes).slice(1).sort(); // remove `__esModule` export const listThemes = () => Object.keys(themes); +export type Theme = keyof typeof themes; +export type Scheme = keyof typeof schemes; + export interface ThemeData { theme: keyof typeof themes; scheme: keyof typeof schemes; light: boolean; } -export interface ThemeFromProvider extends Theme { +export interface ThemeFromProvider extends ThemeBase { type: keyof typeof themes; light: boolean; } diff --git a/packages/redux-devtools-chart-monitor/src/Chart.tsx b/packages/redux-devtools-chart-monitor/src/Chart.tsx index 8b646f58..f0b6d098 100644 --- a/packages/redux-devtools-chart-monitor/src/Chart.tsx +++ b/packages/redux-devtools-chart-monitor/src/Chart.tsx @@ -7,6 +7,7 @@ import * as themes from 'redux-devtools-themes'; import { Base16Theme } from 'react-base16-styling'; import { ChartMonitorState } from './reducers'; import { Primitive } from 'd3'; +import { NodeWithId } from 'd3-state-visualizer/lib/charts/tree/tree'; const wrapperStyle = { width: '100%', @@ -25,6 +26,7 @@ export interface Props> isSorted: boolean; heightBetweenNodesCoeff: number; widthBetweenNodesCoeff: number; + onClickText: (datum: NodeWithId) => void; tooltipOptions: { disabled: boolean; offset: { diff --git a/packages/redux-devtools-chart-monitor/src/ChartMonitor.tsx b/packages/redux-devtools-chart-monitor/src/ChartMonitor.tsx index 8fe44c64..df609820 100644 --- a/packages/redux-devtools-chart-monitor/src/ChartMonitor.tsx +++ b/packages/redux-devtools-chart-monitor/src/ChartMonitor.tsx @@ -9,6 +9,7 @@ import { Base16Theme } from 'react-base16-styling'; import reducer, { ChartMonitorState } from './reducers'; import Chart, { Props } from './Chart'; import { Primitive } from 'd3'; +import { NodeWithId } from 'd3-state-visualizer/lib/charts/tree/tree'; // eslint-disable-next-line @typescript-eslint/unbound-method const { reset, rollback, commit, sweep, toggleAction } = ActionCreators; @@ -49,6 +50,7 @@ export interface ChartMonitorProps> isSorted: boolean; heightBetweenNodesCoeff: number; widthBetweenNodesCoeff: number; + onClickText: (datum: NodeWithId) => void; tooltipOptions: unknown; style: { width: number; diff --git a/packages/redux-devtools-core/.babelrc b/packages/redux-devtools-core/.babelrc index e60d3036..0d42ef44 100644 --- a/packages/redux-devtools-core/.babelrc +++ b/packages/redux-devtools-core/.babelrc @@ -1,4 +1,8 @@ { - "presets": ["@babel/preset-env", "@babel/preset-react"], + "presets": [ + "@babel/preset-env", + "@babel/preset-react", + "@babel/preset-typescript" + ], "plugins": ["@babel/plugin-proposal-class-properties"] } diff --git a/packages/redux-devtools-core/.eslintignore b/packages/redux-devtools-core/.eslintignore new file mode 100644 index 00000000..79681bfb --- /dev/null +++ b/packages/redux-devtools-core/.eslintignore @@ -0,0 +1,2 @@ +lib +umd diff --git a/packages/redux-devtools-core/.eslintrc.js b/packages/redux-devtools-core/.eslintrc.js new file mode 100644 index 00000000..ce28cd35 --- /dev/null +++ b/packages/redux-devtools-core/.eslintrc.js @@ -0,0 +1,29 @@ +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'], + }, + }, + { + files: ['webpack.config.ts', 'webpack.config.umd.ts'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.webpack.json'], + }, + }, + ], +}; diff --git a/packages/redux-devtools-core/jest.config.js b/packages/redux-devtools-core/jest.config.js new file mode 100644 index 00000000..547c49dd --- /dev/null +++ b/packages/redux-devtools-core/jest.config.js @@ -0,0 +1,4 @@ +module.exports = { + preset: 'ts-jest', + setupFilesAfterEnv: ['/test/setup.ts'], +}; diff --git a/packages/redux-devtools-core/package.json b/packages/redux-devtools-core/package.json index 8a9e2fb3..6b3a139f 100644 --- a/packages/redux-devtools-core/package.json +++ b/packages/redux-devtools-core/package.json @@ -2,65 +2,39 @@ "name": "redux-devtools-core", "version": "1.0.0-4", "description": "Reusable functions of Redux DevTools", - "scripts": { - "start": "webpack-dev-server --hot --inline --env.development --env.platform=web --progress", - "build:web": "rimraf ./build/web && webpack -p --env.platform=web --progress", - "build:umd": "rimraf ./umd && webpack --progress --config webpack.config.umd.js", - "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.js", - "build": "rimraf ./lib && babel ./src/app --out-dir lib", - "clean": "rimraf lib", - "test": "jest --no-cache", - "prepare": "npm run build && npm run build:umd && npm run build:umd:min", - "prepublishOnly": "npm run test && npm run build && npm run build:umd && npm run build:umd:min" + "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-core", + "bugs": { + "url": "https://github.com/reduxjs/redux-devtools/issues" }, - "main": "lib/index.js", + "license": "MIT", + "author": "Mihail Diordiev (https://github.com/zalmoxisus)", "files": [ "src", "lib", "umd" ], - "jest": { - "setupFilesAfterEnv": [ - "/test/setup.js" - ], - "moduleNameMapper": { - "\\.(css|scss)$": "/test/__mocks__/styleMock.js" - } - }, + "main": "lib/index.js", + "types": "lib/index.d.ts", "repository": { "type": "git", "url": "https://github.com/reduxjs/redux-devtools.git" }, - "author": "Mihail Diordiev (https://github.com/zalmoxisus)", - "license": "MIT", - "bugs": { - "url": "https://github.com/reduxjs/redux-devtools/issues" - }, - "homepage": "https://github.com/reduxjs/redux-devtools", - "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.1", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/preset-env": "^7.11.0", - "@babel/preset-react": "^7.10.4", - "babel-loader": "^8.1.0", - "css-loader": "^4.2.1", - "enzyme": "^3.11.0", - "enzyme-adapter-react-16": "^1.15.3", - "enzyme-to-json": "^3.5.0", - "file-loader": "^6.0.0", - "html-loader": "^1.1.0", - "html-webpack-plugin": "^4.3.0", - "jest": "^26.2.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "rimraf": "^3.0.2", - "style-loader": "^1.2.1", - "url-loader": "^4.1.0", - "webpack": "^4.44.1", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0", - "webpack-hot-middleware": "^2.25.0" + "scripts": { + "start": "webpack-dev-server --hot --inline --env.development --env.platform=web --progress", + "build": "npm run build:types && npm run build:js && npm run build:web && npm run build:umd && npm run build:umd:min", + "build:types": "tsc --emitDeclarationOnly", + "build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline", + "build:web": "rimraf ./build/web && webpack -p --env.platform=web --progress", + "build:umd": "rimraf ./umd && webpack --progress --config webpack.config.umd.ts", + "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.ts", + "clean": "rimraf lib", + "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": { "d3-state-visualizer": "^1.3.4", @@ -90,6 +64,34 @@ "socketcluster-client": "^14.3.1", "styled-components": "^5.1.1" }, + "devDependencies": { + "@babel/cli": "^7.10.5", + "@babel/core": "^7.11.1", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/preset-env": "^7.11.0", + "@babel/preset-react": "^7.10.4", + "@rjsf/core": "^2.4.0", + "@types/json-schema": "^7.0.6", + "@types/socketcluster-client": "^13.0.3", + "babel-loader": "^8.1.0", + "css-loader": "^4.2.1", + "enzyme": "^3.11.0", + "enzyme-adapter-react-16": "^1.15.3", + "enzyme-to-json": "^3.5.0", + "file-loader": "^6.0.0", + "html-loader": "^1.1.0", + "html-webpack-plugin": "^4.3.0", + "jest": "^26.2.2", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "rimraf": "^3.0.2", + "style-loader": "^1.2.1", + "url-loader": "^4.1.0", + "webpack": "^4.44.1", + "webpack-cli": "^3.3.12", + "webpack-dev-server": "^3.11.0", + "webpack-hot-middleware": "^2.25.0" + }, "peerDependencies": { "react": "^16.3.0" } diff --git a/packages/redux-devtools-core/src/app/actions/index.js b/packages/redux-devtools-core/src/app/actions/index.js deleted file mode 100644 index 9e568444..00000000 --- a/packages/redux-devtools-core/src/app/actions/index.js +++ /dev/null @@ -1,122 +0,0 @@ -import { - CHANGE_SECTION, - CHANGE_THEME, - SELECT_INSTANCE, - SELECT_MONITOR, - UPDATE_MONITOR_STATE, - LIFTED_ACTION, - MONITOR_ACTION, - EXPORT, - TOGGLE_SYNC, - TOGGLE_SLIDER, - TOGGLE_DISPATCHER, - TOGGLE_PERSIST, - GET_REPORT_REQUEST, - SHOW_NOTIFICATION, - CLEAR_NOTIFICATION, -} from '../constants/actionTypes'; -import { RECONNECT } from '../constants/socketActionTypes'; - -let monitorReducer; -let monitorProps = {}; - -export function changeSection(section) { - return { type: CHANGE_SECTION, section }; -} - -export function changeTheme(data) { - return { type: CHANGE_THEME, ...data.formData }; -} - -export function liftedDispatch(action) { - if (action.type[0] === '@') { - if (action.type === '@@INIT_MONITOR') { - monitorReducer = action.update; - monitorProps = action.monitorProps; - } - return { type: MONITOR_ACTION, action, monitorReducer, monitorProps }; - } - return { type: LIFTED_ACTION, message: 'DISPATCH', action }; -} - -export function selectInstance(selected) { - return { type: SELECT_INSTANCE, selected }; -} - -export function selectMonitor(monitor) { - return { type: SELECT_MONITOR, monitor }; -} - -export function selectMonitorWithState(value, monitorState) { - return { type: SELECT_MONITOR, monitor: value, monitorState }; -} - -export function selectMonitorTab(subTabName) { - return { type: UPDATE_MONITOR_STATE, nextState: { subTabName } }; -} - -export function updateMonitorState(nextState) { - return { type: UPDATE_MONITOR_STATE, nextState }; -} - -export function importState(state, preloadedState) { - return { type: LIFTED_ACTION, message: 'IMPORT', state, preloadedState }; -} - -export function exportState() { - return { type: EXPORT }; -} - -export function lockChanges(status) { - return { - type: LIFTED_ACTION, - message: 'DISPATCH', - action: { type: 'LOCK_CHANGES', status }, - toAll: true, - }; -} - -export function pauseRecording(status) { - return { - type: LIFTED_ACTION, - message: 'DISPATCH', - action: { type: 'PAUSE_RECORDING', status }, - toAll: true, - }; -} - -export function dispatchRemotely(action) { - return { type: LIFTED_ACTION, message: 'ACTION', action }; -} - -export function togglePersist() { - return { type: TOGGLE_PERSIST }; -} - -export function toggleSync() { - return { type: TOGGLE_SYNC }; -} - -export function toggleSlider() { - return { type: TOGGLE_SLIDER }; -} - -export function toggleDispatcher() { - return { type: TOGGLE_DISPATCHER }; -} - -export function saveSocketSettings(options) { - return { type: RECONNECT, options }; -} - -export function showNotification(message) { - return { type: SHOW_NOTIFICATION, notification: { type: 'error', message } }; -} - -export function clearNotification() { - return { type: CLEAR_NOTIFICATION }; -} - -export function getReport(report) { - return { type: GET_REPORT_REQUEST, report }; -} diff --git a/packages/redux-devtools-core/src/app/actions/index.ts b/packages/redux-devtools-core/src/app/actions/index.ts new file mode 100644 index 00000000..10617a12 --- /dev/null +++ b/packages/redux-devtools-core/src/app/actions/index.ts @@ -0,0 +1,573 @@ +import { Scheme, Theme } from 'devui'; +import { AuthStates, States } from 'socketcluster-client/lib/scclientsocket'; +import { + CHANGE_SECTION, + CHANGE_THEME, + SELECT_INSTANCE, + SELECT_MONITOR, + UPDATE_MONITOR_STATE, + LIFTED_ACTION, + MONITOR_ACTION, + EXPORT, + TOGGLE_SYNC, + TOGGLE_SLIDER, + TOGGLE_DISPATCHER, + TOGGLE_PERSIST, + GET_REPORT_REQUEST, + SHOW_NOTIFICATION, + CLEAR_NOTIFICATION, + UPDATE_STATE, + UPDATE_REPORTS, + REMOVE_INSTANCE, + SET_STATE, + GET_REPORT_ERROR, + GET_REPORT_SUCCESS, + ERROR, +} from '../constants/actionTypes'; +import { + AUTH_ERROR, + AUTH_REQUEST, + AUTH_SUCCESS, + CONNECT_ERROR, + CONNECT_REQUEST, + CONNECT_SUCCESS, + DEAUTHENTICATE, + DISCONNECTED, + EMIT, + RECONNECT, + SUBSCRIBE_ERROR, + SUBSCRIBE_REQUEST, + SUBSCRIBE_SUCCESS, + UNSUBSCRIBE, +} from '../constants/socketActionTypes'; +import { Action } from 'redux'; +import { Features, State } from '../reducers/instances'; +import { MonitorStateMonitorState } from '../reducers/monitor'; +import { LiftedAction } from 'redux-devtools-instrument'; +import { Data } from '../reducers/reports'; + +let monitorReducer: ( + monitorProps: unknown, + state: unknown | undefined, + action: Action +) => unknown; +let monitorProps: unknown = {}; + +interface ChangeSectionAction { + readonly type: typeof CHANGE_SECTION; + readonly section: string; +} +export function changeSection(section: string): ChangeSectionAction { + return { type: CHANGE_SECTION, section }; +} + +interface ChangeThemeFormData { + readonly theme: Theme; + readonly scheme: Scheme; + readonly dark: boolean; +} +interface ChangeThemeData { + readonly formData: ChangeThemeFormData; +} +interface ChangeThemeAction { + readonly type: typeof CHANGE_THEME; + readonly theme: Theme; + readonly scheme: Scheme; + readonly dark: boolean; +} +export function changeTheme(data: ChangeThemeData): ChangeThemeAction { + return { type: CHANGE_THEME, ...data.formData }; +} + +export interface InitMonitorAction { + type: '@@INIT_MONITOR'; + newMonitorState: unknown; + update: ( + monitorProps: unknown, + state: unknown | undefined, + action: Action + ) => unknown; + monitorProps: unknown; +} +export interface MonitorActionAction { + type: typeof MONITOR_ACTION; + action: InitMonitorAction; + monitorReducer: ( + monitorProps: unknown, + state: unknown | undefined, + action: Action + ) => unknown; + monitorProps: unknown; +} +export interface JumpToStateAction { + type: 'JUMP_TO_STATE'; + index: number; + actionId: number; +} +export interface JumpToActionAction { + type: 'JUMP_TO_ACTION'; + index: number; + actionId: number; +} +export interface PauseRecordingAction { + type: 'PAUSE_RECORDING'; + status: boolean; +} +export interface LockChangesAction { + type: 'LOCK_CHANGES'; + status: boolean; +} +export interface ToggleActionAction { + type: 'TOGGLE_ACTION'; +} +export interface RollbackAction { + type: 'ROLLBACK'; +} +export interface SweepAction { + type: 'SWEEP'; +} +export type DispatchAction = + | JumpToStateAction + | JumpToActionAction + | PauseRecordingAction + | LockChangesAction + | ToggleActionAction + | RollbackAction + | SweepAction; +interface LiftedActionActionBase { + action?: DispatchAction | string | CustomAction; + state?: string; + toAll?: boolean; +} +export interface LiftedActionDispatchAction extends LiftedActionActionBase { + type: typeof LIFTED_ACTION; + message: 'DISPATCH'; + action: DispatchAction; + toAll?: boolean; +} +interface LiftedActionImportAction extends LiftedActionActionBase { + type: typeof LIFTED_ACTION; + message: 'IMPORT'; + state: string; + preloadedState: unknown | undefined; +} +interface LiftedActionActionAction extends LiftedActionActionBase { + type: typeof LIFTED_ACTION; + message: 'ACTION'; + action: string | CustomAction; +} +interface LiftedActionExportAction extends LiftedActionActionBase { + type: typeof LIFTED_ACTION; + message: 'EXPORT'; + toExport: boolean; +} +export type LiftedActionAction = + | LiftedActionDispatchAction + | LiftedActionImportAction + | LiftedActionActionAction + | LiftedActionExportAction; +export function liftedDispatch( + action: + | InitMonitorAction + | JumpToStateAction + | JumpToActionAction + | LiftedAction, unknown> +): MonitorActionAction | LiftedActionDispatchAction { + if (action.type[0] === '@') { + if (action.type === '@@INIT_MONITOR') { + monitorReducer = action.update; + monitorProps = action.monitorProps; + } + return { + type: MONITOR_ACTION, + action, + monitorReducer, + monitorProps, + } as MonitorActionAction; + } + return { + type: LIFTED_ACTION, + message: 'DISPATCH', + action, + } as LiftedActionDispatchAction; +} + +interface SelectInstanceAction { + type: typeof SELECT_INSTANCE; + selected: string; +} +export function selectInstance(selected: string): SelectInstanceAction { + return { type: SELECT_INSTANCE, selected }; +} + +interface SelectMonitorAction { + type: typeof SELECT_MONITOR; + monitor: string; + monitorState?: MonitorStateMonitorState; +} +export function selectMonitor(monitor: string): SelectMonitorAction { + return { type: SELECT_MONITOR, monitor }; +} +export function selectMonitorWithState( + value: string, + monitorState: MonitorStateMonitorState +): SelectMonitorAction { + return { type: SELECT_MONITOR, monitor: value, monitorState }; +} + +interface NextState { + subTabName: string; + inspectedStatePath?: string[]; +} +interface UpdateMonitorStateAction { + type: typeof UPDATE_MONITOR_STATE; + nextState: NextState; +} +export function selectMonitorTab(subTabName: string): UpdateMonitorStateAction { + return { type: UPDATE_MONITOR_STATE, nextState: { subTabName } }; +} + +export function updateMonitorState( + nextState: NextState +): UpdateMonitorStateAction { + return { type: UPDATE_MONITOR_STATE, nextState }; +} + +export function importState( + state: string, + preloadedState?: unknown +): LiftedActionImportAction { + return { type: LIFTED_ACTION, message: 'IMPORT', state, preloadedState }; +} + +interface ExportAction { + type: typeof EXPORT; +} +export function exportState(): ExportAction { + return { type: EXPORT }; +} + +export function lockChanges(status: boolean): LiftedActionDispatchAction { + return { + type: LIFTED_ACTION, + message: 'DISPATCH', + action: { type: 'LOCK_CHANGES', status }, + toAll: true, + }; +} + +export function pauseRecording(status: boolean): LiftedActionDispatchAction { + return { + type: LIFTED_ACTION, + message: 'DISPATCH', + action: { type: 'PAUSE_RECORDING', status }, + toAll: true, + }; +} + +export interface CustomAction { + name: string; + selected: number; + args: (string | undefined)[]; + rest: string; +} +export function dispatchRemotely( + action: string | CustomAction +): LiftedActionActionAction { + return { type: LIFTED_ACTION, message: 'ACTION', action }; +} + +interface TogglePersistAction { + type: typeof TOGGLE_PERSIST; +} +export function togglePersist(): TogglePersistAction { + return { type: TOGGLE_PERSIST }; +} + +interface ToggleSyncAction { + type: typeof TOGGLE_SYNC; +} +export function toggleSync(): ToggleSyncAction { + return { type: TOGGLE_SYNC }; +} + +interface ToggleSliderAction { + type: typeof TOGGLE_SLIDER; +} +export function toggleSlider(): ToggleSliderAction { + return { type: TOGGLE_SLIDER }; +} + +interface ToggleDispatcherAction { + type: typeof TOGGLE_DISPATCHER; +} +export function toggleDispatcher(): ToggleDispatcherAction { + return { type: TOGGLE_DISPATCHER }; +} + +export type ConnectionType = 'disabled' | 'remotedev' | 'custom'; +export interface ConnectionOptions { + readonly type: ConnectionType; + readonly hostname: string; + readonly port: number; + readonly secure: boolean; +} +interface ReconnectAction { + readonly type: typeof RECONNECT; + readonly options: ConnectionOptions; +} +export function saveSocketSettings( + options: ConnectionOptions +): ReconnectAction { + return { type: RECONNECT, options }; +} + +interface Notification { + readonly type: 'error'; + readonly message: string; +} +interface ShowNotificationAction { + readonly type: typeof SHOW_NOTIFICATION; + readonly notification: Notification; +} +export function showNotification(message: string): ShowNotificationAction { + return { type: SHOW_NOTIFICATION, notification: { type: 'error', message } }; +} + +interface ClearNotificationAction { + readonly type: typeof CLEAR_NOTIFICATION; +} +export function clearNotification(): ClearNotificationAction { + return { type: CLEAR_NOTIFICATION }; +} + +interface GetReportRequest { + readonly type: typeof GET_REPORT_REQUEST; + readonly report: unknown; +} +export function getReport(report: unknown): GetReportRequest { + return { type: GET_REPORT_REQUEST, report }; +} + +export interface ActionCreator { + args: string[]; + name: string; +} + +interface LibConfig { + actionCreators?: string; + name?: string; + type?: string; + features?: Features; + serialize?: boolean; +} + +export interface RequestBase { + id: string; + instanceId?: string; + action?: string; + name?: string; + libConfig?: LibConfig; + actionsById?: string; + computedStates?: string; + // eslint-disable-next-line @typescript-eslint/ban-types + payload?: {} | string; + liftedState?: Partial; +} +interface InitRequest extends RequestBase { + type: 'INIT'; + action: string; +} +interface ActionRequest extends RequestBase { + type: 'ACTION'; + isExcess: boolean; + nextActionId: number; + maxAge: number; + batched: boolean; +} +interface StateRequest extends RequestBase { + type: 'STATE'; + committedState: unknown; +} +interface PartialStateRequest extends RequestBase { + type: 'PARTIAL_STATE'; + committedState: unknown; + maxAge: number; +} +interface LiftedRequest extends RequestBase { + type: 'LIFTED'; +} +export interface ExportRequest extends RequestBase { + type: 'EXPORT'; + committedState: unknown; +} +export type Request = + | InitRequest + | ActionRequest + | StateRequest + | PartialStateRequest + | LiftedRequest + | ExportRequest; + +interface UpdateStateAction { + type: typeof UPDATE_STATE; + request?: Request; + id?: string; +} + +interface SetStateAction { + type: typeof SET_STATE; + newState: State; +} + +interface RemoveInstanceAction { + type: typeof REMOVE_INSTANCE; + id: string; +} + +interface ConnectRequestAction { + type: typeof CONNECT_REQUEST; + options: ConnectionOptions; +} + +interface ConnectSuccessPayload { + id: string; + authState: AuthStates; + socketState: States; +} +interface ConnectSuccessAction { + type: typeof CONNECT_SUCCESS; + payload: ConnectSuccessPayload; + error: Error | undefined; +} + +interface ConnectErrorAction { + type: typeof CONNECT_ERROR; + error: Error | undefined; +} + +interface AuthRequestAction { + type: typeof AUTH_REQUEST; +} + +interface AuthSuccessAction { + type: typeof AUTH_SUCCESS; + baseChannel: string; +} + +interface AuthErrorAction { + type: typeof AUTH_ERROR; + error: Error; +} + +interface DisconnectedAction { + type: typeof DISCONNECTED; + code: number; +} + +interface DeauthenticateAction { + type: typeof DEAUTHENTICATE; +} + +interface SubscribeRequestAction { + type: typeof SUBSCRIBE_REQUEST; + channel: string; + subscription: typeof UPDATE_STATE | typeof UPDATE_REPORTS; +} + +interface SubscribeSuccessAction { + type: typeof SUBSCRIBE_SUCCESS; + channel: string; +} + +interface SubscribeErrorAction { + type: typeof SUBSCRIBE_ERROR; + error: Error; + status: string; +} + +interface UnsubscribeAction { + type: typeof UNSUBSCRIBE; + channel: string; +} + +export interface EmitAction { + type: typeof EMIT; + message: string; + id?: string | false; + instanceId?: string; + action?: unknown; + state?: unknown; +} + +interface ListRequest { + type: 'list'; + data: Data[]; +} +interface AddRequest { + type: 'add'; + data: Data; +} +interface RemoveRequest { + type: 'remove'; + data: Data; + id: unknown; +} +export type UpdateReportsRequest = ListRequest | AddRequest | RemoveRequest; +interface UpdateReportsAction { + type: typeof UPDATE_REPORTS; + request: UpdateReportsRequest; +} + +interface GetReportError { + type: typeof GET_REPORT_ERROR; + error: Error; +} + +interface GetReportSuccess { + type: typeof GET_REPORT_SUCCESS; + data: { payload: string }; +} + +interface ErrorAction { + type: typeof ERROR; + payload: string; +} + +export type StoreAction = + | ChangeSectionAction + | ChangeThemeAction + | MonitorActionAction + | LiftedActionAction + | SelectInstanceAction + | SelectMonitorAction + | UpdateMonitorStateAction + | ExportAction + | TogglePersistAction + | ToggleSyncAction + | ToggleSliderAction + | ToggleDispatcherAction + | ReconnectAction + | ShowNotificationAction + | ClearNotificationAction + | GetReportRequest + | SetStateAction + | UpdateStateAction + | RemoveInstanceAction + | ConnectRequestAction + | ConnectSuccessAction + | ConnectErrorAction + | AuthRequestAction + | AuthSuccessAction + | AuthErrorAction + | DisconnectedAction + | DeauthenticateAction + | SubscribeRequestAction + | SubscribeSuccessAction + | SubscribeErrorAction + | UnsubscribeAction + | EmitAction + | UpdateReportsAction + | GetReportError + | GetReportSuccess + | ErrorAction; diff --git a/packages/redux-devtools-core/src/app/components/BottomButtons.js b/packages/redux-devtools-core/src/app/components/BottomButtons.tsx similarity index 85% rename from packages/redux-devtools-core/src/app/components/BottomButtons.js rename to packages/redux-devtools-core/src/app/components/BottomButtons.tsx index d7e0f33b..da8788a9 100644 --- a/packages/redux-devtools-core/src/app/components/BottomButtons.js +++ b/packages/redux-devtools-core/src/app/components/BottomButtons.tsx @@ -8,15 +8,22 @@ import PrintButton from './buttons/PrintButton'; import DispatcherButton from './buttons/DispatcherButton'; import SliderButton from './buttons/SliderButton'; import MonitorSelector from './MonitorSelector'; +import { Options } from '../reducers/instances'; -export default class BottomButtons extends Component { +interface Props { + dispatcherIsOpen: boolean; + sliderIsOpen: boolean; + options: Options; +} + +export default class BottomButtons extends Component { static propTypes = { dispatcherIsOpen: PropTypes.bool, sliderIsOpen: PropTypes.bool, options: PropTypes.object.isRequired, }; - shouldComponentUpdate(nextProps) { + shouldComponentUpdate(nextProps: Props) { return ( nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen || nextProps.sliderIsOpen !== this.props.sliderIsOpen || diff --git a/packages/redux-devtools-core/src/app/components/Header.js b/packages/redux-devtools-core/src/app/components/Header.tsx similarity index 77% rename from packages/redux-devtools-core/src/app/components/Header.js rename to packages/redux-devtools-core/src/app/components/Header.tsx index ff80d2b8..c9a42bd2 100644 --- a/packages/redux-devtools-core/src/app/components/Header.js +++ b/packages/redux-devtools-core/src/app/components/Header.tsx @@ -1,8 +1,6 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import { Tabs, Toolbar, Button, Divider } from 'devui'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; +import { connect, ResolveThunks } from 'react-redux'; import { GoBook } from 'react-icons/go'; import { IoMdText } from 'react-icons/io'; import { TiSocialTwitter } from 'react-icons/ti'; @@ -11,13 +9,14 @@ import { changeSection } from '../actions'; const tabs = [{ name: 'Actions' }, { name: 'Reports' }, { name: 'Settings' }]; -class Header extends Component { - static propTypes = { - section: PropTypes.string.isRequired, - changeSection: PropTypes.func.isRequired, - }; +type DispatchProps = ResolveThunks; +interface OwnProps { + readonly section: string; +} +type Props = DispatchProps & OwnProps; - openLink = (url) => () => { +class Header extends Component { + openLink = (url: string) => () => { window.open(url); }; @@ -69,10 +68,8 @@ class Header extends Component { } } -function mapDispatchToProps(dispatch) { - return { - changeSection: bindActionCreators(changeSection, dispatch), - }; -} +const actionCreators = { + changeSection, +}; -export default connect(null, mapDispatchToProps)(Header); +export default connect(null, actionCreators)(Header); diff --git a/packages/redux-devtools-core/src/app/components/InstanceSelector.js b/packages/redux-devtools-core/src/app/components/InstanceSelector.js deleted file mode 100644 index 3cd30bac..00000000 --- a/packages/redux-devtools-core/src/app/components/InstanceSelector.js +++ /dev/null @@ -1,48 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { Select } from 'devui'; -import { selectInstance } from '../actions'; - -class InstanceSelector extends Component { - static propTypes = { - selected: PropTypes.string, - instances: PropTypes.object.isRequired, - onSelect: PropTypes.func.isRequired, - }; - - render() { - this.select = [{ value: '', label: 'Autoselect instances' }]; - const instances = this.props.instances; - let name; - Object.keys(instances).forEach((key) => { - name = instances[key].name; - if (name !== undefined) - this.select.push({ value: key, label: instances[key].name }); - }); - - return ( - + ); + } +} + +const mapStateToProps = (state: StoreState) => ({ + selected: state.instances.selected, + instances: state.instances.options, +}); + +const actionCreators = { + onSelect: selectInstance, +}; + +export default connect(mapStateToProps, actionCreators)(InstanceSelector); diff --git a/packages/redux-devtools-core/src/app/components/MonitorSelector.js b/packages/redux-devtools-core/src/app/components/MonitorSelector.js deleted file mode 100644 index f0167385..00000000 --- a/packages/redux-devtools-core/src/app/components/MonitorSelector.js +++ /dev/null @@ -1,45 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { Tabs } from 'devui'; -import { monitors } from '../utils/getMonitor'; -import { selectMonitor } from '../actions'; - -class MonitorSelector extends Component { - static propTypes = { - selected: PropTypes.string, - selectMonitor: PropTypes.func.isRequired, - }; - - shouldComponentUpdate(nextProps) { - return nextProps.selected !== this.props.selected; - } - - render() { - return ( - - ); - } -} - -function mapStateToProps(state) { - return { - selected: state.monitor.selected, - }; -} - -function mapDispatchToProps(dispatch) { - return { - selectMonitor: bindActionCreators(selectMonitor, dispatch), - }; -} - -export default connect(mapStateToProps, mapDispatchToProps)(MonitorSelector); diff --git a/packages/redux-devtools-core/src/app/components/MonitorSelector.tsx b/packages/redux-devtools-core/src/app/components/MonitorSelector.tsx new file mode 100644 index 00000000..e606008b --- /dev/null +++ b/packages/redux-devtools-core/src/app/components/MonitorSelector.tsx @@ -0,0 +1,39 @@ +import React, { Component } from 'react'; +import { connect, ResolveThunks } from 'react-redux'; +import { Tabs } from 'devui'; +import { monitors } from '../utils/getMonitor'; +import { selectMonitor } from '../actions'; +import { StoreState } from '../reducers'; + +type StateProps = ReturnType; +type DispatchProps = ResolveThunks; +type Props = StateProps & DispatchProps; + +class MonitorSelector extends Component { + shouldComponentUpdate(nextProps: Props) { + return nextProps.selected !== this.props.selected; + } + + render() { + return ( + + ); + } +} + +const mapStateToProps = (state: StoreState) => ({ + selected: state.monitor.selected, +}); + +const actionCreators = { + selectMonitor, +}; + +export default connect(mapStateToProps, actionCreators)(MonitorSelector); diff --git a/packages/redux-devtools-core/src/app/components/Settings/Connection.js b/packages/redux-devtools-core/src/app/components/Settings/Connection.tsx similarity index 55% rename from packages/redux-devtools-core/src/app/components/Settings/Connection.js rename to packages/redux-devtools-core/src/app/components/Settings/Connection.tsx index cb46281e..9b1e1ac9 100644 --- a/packages/redux-devtools-core/src/app/components/Settings/Connection.js +++ b/packages/redux-devtools-core/src/app/components/Settings/Connection.tsx @@ -1,11 +1,32 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; +import { connect, ResolveThunks } from 'react-redux'; import { Container, Form } from 'devui'; -import { saveSocketSettings } from '../../actions'; +import { + JSONSchema7, + JSONSchema7Definition, + JSONSchema7Type, + JSONSchema7TypeName, +} from 'json-schema'; +import { ConnectionType, saveSocketSettings } from '../../actions'; +import { StoreState } from '../../reducers'; +import { ConnectionOptions } from '../../reducers/connection'; +import { IChangeEvent, ISubmitEvent } from '@rjsf/core'; -const defaultSchema = { +declare module 'json-schema' { + export interface JSONSchema7 { + enumNames?: JSONSchema7Type[]; + } +} + +interface Schema { + type: JSONSchema7TypeName; + required?: string[]; + properties: { + [key: string]: JSONSchema7Definition; + }; +} + +const defaultSchema: Schema = { type: 'object', required: [], properties: { @@ -37,37 +58,24 @@ const uiSchema = { }, }; -class Connection extends Component { - static propTypes = { - saveSettings: PropTypes.func.isRequired, - options: PropTypes.object.isRequired, - type: PropTypes.string, - }; +type StateProps = ReturnType; +type DispatchProps = ResolveThunks; +type Props = StateProps & DispatchProps; - constructor(props) { - super(props); - this.state = this.setFormData(props.type); - } +interface FormData extends ConnectionOptions { + readonly type: ConnectionType; +} - shouldComponentUpdate(nextProps, nextState) { - return this.state !== nextState; - } +interface State { + readonly formData: FormData; + readonly type: ConnectionType; + readonly schema: Schema; + readonly changed: boolean | undefined; +} - UNSAFE_componentWillReceiveProps(nextProps) { - if (this.props.options !== nextProps.options) { - this.setState({ - formData: { ...nextProps.options, type: nextProps.type }, - }); - } - } - - handleSave = (data) => { - this.props.saveSettings(data.formData); - this.setState({ changed: false }); - }; - - setFormData = (type, changed) => { - let schema; +export class Connection extends Component { + setFormData = (type: ConnectionType, changed?: boolean) => { + let schema: Schema; if (type !== 'custom') { schema = { type: 'object', @@ -87,7 +95,26 @@ class Connection extends Component { }; }; - handleChange = (data) => { + state: State = this.setFormData(this.props.type); + + shouldComponentUpdate(nextProps: Props, nextState: State) { + return this.state !== nextState; + } + + UNSAFE_componentWillReceiveProps(nextProps: Props) { + if (this.props.options !== nextProps.options) { + this.setState({ + formData: { ...nextProps.options, type: nextProps.type }, + }); + } + } + + handleSave = (data: ISubmitEvent) => { + this.props.saveSettings(data.formData); + this.setState({ changed: false }); + }; + + handleChange = (data: IChangeEvent) => { const formData = data.formData; const type = formData.type; if (type !== this.state.type) { @@ -119,14 +146,10 @@ class Connection extends Component { } } -function mapStateToProps(state) { - return state.connection; -} +const mapStateToProps = (state: StoreState) => state.connection; -function mapDispatchToProps(dispatch) { - return { - saveSettings: bindActionCreators(saveSocketSettings, dispatch), - }; -} +const actionCreators = { + saveSettings: saveSocketSettings, +}; -export default connect(mapStateToProps, mapDispatchToProps)(Connection); +export default connect(mapStateToProps, actionCreators)(Connection); diff --git a/packages/redux-devtools-core/src/app/components/Settings/Themes.js b/packages/redux-devtools-core/src/app/components/Settings/Themes.tsx similarity index 64% rename from packages/redux-devtools-core/src/app/components/Settings/Themes.js rename to packages/redux-devtools-core/src/app/components/Settings/Themes.tsx index e528dd55..7762454e 100644 --- a/packages/redux-devtools-core/src/app/components/Settings/Themes.js +++ b/packages/redux-devtools-core/src/app/components/Settings/Themes.tsx @@ -1,17 +1,15 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; +import { connect, ResolveThunks } from 'react-redux'; import { Container, Form } from 'devui'; import { listSchemes, listThemes } from 'devui/lib/utils/theme'; import { changeTheme } from '../../actions'; +import { StoreState } from '../../reducers'; -class Themes extends Component { - static propTypes = { - changeTheme: PropTypes.func.isRequired, - theme: PropTypes.object.isRequired, - }; +type StateProps = ReturnType; +type DispatchProps = ResolveThunks; +type Props = StateProps & DispatchProps; +export class Themes extends Component { render() { const theme = this.props.theme; const formData = { @@ -49,16 +47,12 @@ class Themes extends Component { } } -function mapStateToProps(state) { - return { - theme: state.theme, - }; -} +const mapStateToProps = (state: StoreState) => ({ + theme: state.theme, +}); -function mapDispatchToProps(dispatch) { - return { - changeTheme: bindActionCreators(changeTheme, dispatch), - }; -} +const actionCreators = { + changeTheme, +}; -export default connect(mapStateToProps, mapDispatchToProps)(Themes); +export default connect(mapStateToProps, actionCreators)(Themes); diff --git a/packages/redux-devtools-core/src/app/components/Settings/index.js b/packages/redux-devtools-core/src/app/components/Settings/index.js deleted file mode 100644 index 47b62874..00000000 --- a/packages/redux-devtools-core/src/app/components/Settings/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import React, { Component } from 'react'; -import { Tabs } from 'devui'; -import Connection from './Connection'; -import Themes from './Themes'; - -class Settings extends Component { - constructor(props) { - super(props); - this.tabs = [ - { name: 'Connection', component: Connection }, - { name: 'Themes', component: Themes }, - ]; - this.state = { selected: 'Connection' }; - } - - handleSelect = (selected) => { - this.setState({ selected }); - }; - - render() { - return ( - - ); - } -} - -export default Settings; diff --git a/packages/redux-devtools-core/src/app/components/Settings/index.tsx b/packages/redux-devtools-core/src/app/components/Settings/index.tsx new file mode 100644 index 00000000..ae18464a --- /dev/null +++ b/packages/redux-devtools-core/src/app/components/Settings/index.tsx @@ -0,0 +1,34 @@ +import React, { Component } from 'react'; +import { Tabs } from 'devui'; +import Connection from './Connection'; +import Themes from './Themes'; + +interface State { + selected: string; +} + +// eslint-disable-next-line @typescript-eslint/ban-types +class Settings extends Component<{}, State> { + tabs = [ + { name: 'Connection', component: Connection }, + { name: 'Themes', component: Themes }, + ]; + state: State = { selected: 'Connection' }; + + handleSelect = (selected: string) => { + this.setState({ selected }); + }; + + render() { + return ( + // eslint-disable-next-line @typescript-eslint/ban-types + + tabs={this.tabs as any} + selected={this.state.selected} + onClick={this.handleSelect} + /> + ); + } +} + +export default Settings; diff --git a/packages/redux-devtools-core/src/app/components/TopButtons.js b/packages/redux-devtools-core/src/app/components/TopButtons.tsx similarity index 84% rename from packages/redux-devtools-core/src/app/components/TopButtons.js rename to packages/redux-devtools-core/src/app/components/TopButtons.tsx index 7c2f3fc8..e183742a 100644 --- a/packages/redux-devtools-core/src/app/components/TopButtons.js +++ b/packages/redux-devtools-core/src/app/components/TopButtons.tsx @@ -1,16 +1,25 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { ActionCreators } from 'redux-devtools-instrument'; +import { ActionCreators, LiftedAction } from 'redux-devtools-instrument'; import { Button, Toolbar, Divider } from 'devui'; +import { Action } from 'redux'; import RecordButton from './buttons/RecordButton'; import PersistButton from './buttons/PersistButton'; import LockButton from './buttons/LockButton'; import InstanceSelector from './InstanceSelector'; import SyncButton from './buttons/SyncButton'; +import { Options, State } from '../reducers/instances'; +// eslint-disable-next-line @typescript-eslint/unbound-method const { reset, rollback, commit, sweep } = ActionCreators; -export default class TopButtons extends Component { +interface Props { + dispatch: (action: LiftedAction, unknown>) => void; + liftedState: State; + options: Options; +} + +export default class TopButtons extends Component { static propTypes = { // shouldSync: PropTypes.bool, liftedState: PropTypes.object.isRequired, @@ -18,7 +27,7 @@ export default class TopButtons extends Component { options: PropTypes.object.isRequired, }; - shouldComponentUpdate(nextProps) { + shouldComponentUpdate(nextProps: Props) { return ( nextProps.options !== this.props.options || nextProps.liftedState !== this.props.liftedState diff --git a/packages/redux-devtools-core/src/app/components/buttons/DispatcherButton.js b/packages/redux-devtools-core/src/app/components/buttons/DispatcherButton.tsx similarity index 53% rename from packages/redux-devtools-core/src/app/components/buttons/DispatcherButton.js rename to packages/redux-devtools-core/src/app/components/buttons/DispatcherButton.tsx index 77f054ae..f148f0c6 100644 --- a/packages/redux-devtools-core/src/app/components/buttons/DispatcherButton.js +++ b/packages/redux-devtools-core/src/app/components/buttons/DispatcherButton.tsx @@ -1,18 +1,17 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; +import { connect, ResolveThunks } from 'react-redux'; import { Button } from 'devui'; import { FaTerminal } from 'react-icons/fa'; import { toggleDispatcher } from '../../actions'; -class DispatcherButton extends Component { - static propTypes = { - dispatcherIsOpen: PropTypes.bool, - toggleDispatcher: PropTypes.func.isRequired, - }; +type DispatchProps = ResolveThunks; +interface OwnProps { + dispatcherIsOpen: boolean; +} +type Props = DispatchProps & OwnProps; - shouldComponentUpdate(nextProps) { +class DispatcherButton extends Component { + shouldComponentUpdate(nextProps: Props) { return nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen; } @@ -32,10 +31,8 @@ class DispatcherButton extends Component { } } -function mapDispatchToProps(dispatch) { - return { - toggleDispatcher: bindActionCreators(toggleDispatcher, dispatch), - }; -} +const actionCreators = { + toggleDispatcher, +}; -export default connect(null, mapDispatchToProps)(DispatcherButton); +export default connect(null, actionCreators)(DispatcherButton); diff --git a/packages/redux-devtools-core/src/app/components/buttons/ExportButton.js b/packages/redux-devtools-core/src/app/components/buttons/ExportButton.js deleted file mode 100644 index 92659c95..00000000 --- a/packages/redux-devtools-core/src/app/components/buttons/ExportButton.js +++ /dev/null @@ -1,33 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { Button } from 'devui'; -import { TiDownload } from 'react-icons/ti'; -import { exportState } from '../../actions'; - -class ExportButton extends Component { - static propTypes = { - exportState: PropTypes.func.isRequired, - }; - - shouldComponentUpdate() { - return false; - } - - render() { - return ( - - ); - } -} - -function mapDispatchToProps(dispatch) { - return { - exportState: bindActionCreators(exportState, dispatch), - }; -} - -export default connect(null, mapDispatchToProps)(ExportButton); diff --git a/packages/redux-devtools-core/src/app/components/buttons/ExportButton.tsx b/packages/redux-devtools-core/src/app/components/buttons/ExportButton.tsx new file mode 100644 index 00000000..0276d94a --- /dev/null +++ b/packages/redux-devtools-core/src/app/components/buttons/ExportButton.tsx @@ -0,0 +1,28 @@ +import React, { Component } from 'react'; +import { connect, ResolveThunks } from 'react-redux'; +import { Button } from 'devui'; +import { TiDownload } from 'react-icons/ti'; +import { exportState } from '../../actions'; + +type DispatchProps = ResolveThunks; +type Props = DispatchProps; + +class ExportButton extends Component { + shouldComponentUpdate() { + return false; + } + + render() { + return ( + + ); + } +} + +const actionCreators = { + exportState, +}; + +export default connect(null, actionCreators)(ExportButton); diff --git a/packages/redux-devtools-core/src/app/components/buttons/ImportButton.js b/packages/redux-devtools-core/src/app/components/buttons/ImportButton.js deleted file mode 100644 index 89cd7d70..00000000 --- a/packages/redux-devtools-core/src/app/components/buttons/ImportButton.js +++ /dev/null @@ -1,64 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { Button } from 'devui'; -import { TiUpload } from 'react-icons/ti'; -import { importState } from '../../actions'; - -class ImportButton extends Component { - static propTypes = { - importState: PropTypes.func.isRequired, - }; - - constructor() { - super(); - this.handleImport = this.handleImport.bind(this); - this.handleImportFile = this.handleImportFile.bind(this); - this.mapRef = this.mapRef.bind(this); - } - - shouldComponentUpdate() { - return false; - } - - mapRef(node) { - this.fileInput = node; - } - - handleImport() { - this.fileInput.click(); - } - - handleImportFile(e) { - const file = e.target.files[0]; - const reader = new FileReader(); - reader.onload = () => { - this.props.importState(reader.result); - }; - reader.readAsText(file); - e.target.value = ''; // eslint-disable-line no-param-reassign - } - - render() { - return ( - - ); - } -} - -function mapDispatchToProps(dispatch) { - return { - importState: bindActionCreators(importState, dispatch), - }; -} - -export default connect(null, mapDispatchToProps)(ImportButton); diff --git a/packages/redux-devtools-core/src/app/components/buttons/ImportButton.tsx b/packages/redux-devtools-core/src/app/components/buttons/ImportButton.tsx new file mode 100644 index 00000000..0b33a042 --- /dev/null +++ b/packages/redux-devtools-core/src/app/components/buttons/ImportButton.tsx @@ -0,0 +1,54 @@ +import React, { ChangeEventHandler, Component, RefCallback } from 'react'; +import { connect, ResolveThunks } from 'react-redux'; +import { Button } from 'devui'; +import { TiUpload } from 'react-icons/ti'; +import { importState } from '../../actions'; + +type DispatchProps = ResolveThunks; +type Props = DispatchProps; + +class ImportButton extends Component { + fileInput?: HTMLInputElement | null; + + shouldComponentUpdate() { + return false; + } + + mapRef: RefCallback = (node) => { + this.fileInput = node; + }; + + handleImport = () => { + this.fileInput!.click(); + }; + + handleImportFile: ChangeEventHandler = (e) => { + const file = e.target.files![0]; + const reader = new FileReader(); + reader.onload = () => { + this.props.importState(reader.result as string); + }; + reader.readAsText(file); + e.target.value = ''; + }; + + render() { + return ( + + ); + } +} + +const actionCreators = { + importState, +}; + +export default connect(null, actionCreators)(ImportButton); diff --git a/packages/redux-devtools-core/src/app/components/buttons/LockButton.js b/packages/redux-devtools-core/src/app/components/buttons/LockButton.tsx similarity index 60% rename from packages/redux-devtools-core/src/app/components/buttons/LockButton.js rename to packages/redux-devtools-core/src/app/components/buttons/LockButton.tsx index 0bd642f7..bf338f68 100644 --- a/packages/redux-devtools-core/src/app/components/buttons/LockButton.js +++ b/packages/redux-devtools-core/src/app/components/buttons/LockButton.tsx @@ -1,18 +1,19 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { Button } from 'devui'; import { IoIosLock } from 'react-icons/io'; -import { lockChanges } from '../../actions'; +import { lockChanges, StoreAction } from '../../actions'; +import { Dispatch } from 'redux'; -class LockButton extends Component { - static propTypes = { - locked: PropTypes.bool, - disabled: PropTypes.bool, - lockChanges: PropTypes.func.isRequired, - }; +type DispatchProps = ReturnType; +interface OwnProps { + locked: boolean | undefined; + disabled: boolean; +} +type Props = DispatchProps & OwnProps; - shouldComponentUpdate(nextProps) { +class LockButton extends Component { + shouldComponentUpdate(nextProps: Props) { return nextProps.locked !== this.props.locked; } @@ -31,7 +32,10 @@ class LockButton extends Component { } } -function mapDispatchToProps(dispatch, ownProps) { +function mapDispatchToProps( + dispatch: Dispatch, + ownProps: OwnProps +) { return { lockChanges: () => dispatch(lockChanges(!ownProps.locked)), }; diff --git a/packages/redux-devtools-core/src/app/components/buttons/PersistButton.js b/packages/redux-devtools-core/src/app/components/buttons/PersistButton.tsx similarity index 52% rename from packages/redux-devtools-core/src/app/components/buttons/PersistButton.js rename to packages/redux-devtools-core/src/app/components/buttons/PersistButton.tsx index da1c0590..e78349a5 100644 --- a/packages/redux-devtools-core/src/app/components/buttons/PersistButton.js +++ b/packages/redux-devtools-core/src/app/components/buttons/PersistButton.tsx @@ -1,26 +1,26 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; +import { connect, ResolveThunks } from 'react-redux'; import { Button } from 'devui'; import { FaThumbtack } from 'react-icons/fa'; import { togglePersist } from '../../actions'; +import { StoreState } from '../../reducers'; -class LockButton extends Component { - static propTypes = { - persisted: PropTypes.bool, - disabled: PropTypes.bool, - onClick: PropTypes.func.isRequired, - }; +type StateProps = ReturnType; +type DispatchProps = ResolveThunks; +interface OwnProps { + disabled?: boolean; +} +type Props = StateProps & DispatchProps & OwnProps; - shouldComponentUpdate(nextProps) { +class LockButton extends Component { + shouldComponentUpdate(nextProps: Props) { return nextProps.persisted !== this.props.persisted; } render() { return ( - ); - } -} - -function mapStateToProps(state) { - return { - sync: state.instances.sync, - }; -} - -function mapDispatchToProps(dispatch) { - return { - onClick: bindActionCreators(toggleSync, dispatch), - }; -} - -export default connect(mapStateToProps, mapDispatchToProps)(SyncButton); diff --git a/packages/redux-devtools-core/src/app/components/buttons/SyncButton.tsx b/packages/redux-devtools-core/src/app/components/buttons/SyncButton.tsx new file mode 100644 index 00000000..5c8a8e4d --- /dev/null +++ b/packages/redux-devtools-core/src/app/components/buttons/SyncButton.tsx @@ -0,0 +1,39 @@ +import React, { Component } from 'react'; +import { connect, ResolveThunks } from 'react-redux'; +import { Button } from 'devui'; +import { TiArrowSync } from 'react-icons/ti'; +import { toggleSync } from '../../actions'; +import { StoreState } from '../../reducers'; + +type StateProps = ReturnType; +type DispatchProps = ResolveThunks; +type Props = StateProps & DispatchProps; + +class SyncButton extends Component { + shouldComponentUpdate(nextProps: Props) { + return nextProps.sync !== this.props.sync; + } + + render() { + return ( + + ); + } +} + +const mapStateToProps = (state: StoreState) => ({ + sync: state.instances.sync, +}); + +const actionCreators = { + onClick: toggleSync, +}; + +export default connect(mapStateToProps, actionCreators)(SyncButton); diff --git a/packages/redux-devtools-core/src/app/constants/actionTypes.js b/packages/redux-devtools-core/src/app/constants/actionTypes.ts similarity index 100% rename from packages/redux-devtools-core/src/app/constants/actionTypes.js rename to packages/redux-devtools-core/src/app/constants/actionTypes.ts diff --git a/packages/redux-devtools-core/src/app/constants/dataTypes.js b/packages/redux-devtools-core/src/app/constants/dataTypes.ts similarity index 100% rename from packages/redux-devtools-core/src/app/constants/dataTypes.js rename to packages/redux-devtools-core/src/app/constants/dataTypes.ts diff --git a/packages/redux-devtools-core/src/app/constants/socketActionTypes.js b/packages/redux-devtools-core/src/app/constants/socketActionTypes.ts similarity index 78% rename from packages/redux-devtools-core/src/app/constants/socketActionTypes.js rename to packages/redux-devtools-core/src/app/constants/socketActionTypes.ts index 95e00b6a..825dbb77 100644 --- a/packages/redux-devtools-core/src/app/constants/socketActionTypes.js +++ b/packages/redux-devtools-core/src/app/constants/socketActionTypes.ts @@ -1,5 +1,14 @@ import socketCluster from 'socketcluster-client'; +interface States { + CLOSED: 'closed'; + CONNECTING: 'connecting'; + OPEN: 'open'; + AUTHENTICATED: 'authenticated'; + PENDING: 'pending'; + UNAUTHENTICATED: 'unauthenticated'; +} + export const { CLOSED, CONNECTING, @@ -7,7 +16,7 @@ export const { AUTHENTICATED, PENDING, UNAUTHENTICATED, -} = socketCluster.SCClientSocket; +} = (socketCluster.SCClientSocket as unknown) as States; export const CONNECT_REQUEST = 'socket/CONNECT_REQUEST'; export const CONNECT_SUCCESS = 'socket/CONNECT_SUCCESS'; export const CONNECT_ERROR = 'socket/CONNECT_ERROR'; diff --git a/packages/redux-devtools-core/src/app/constants/socketOptions.js b/packages/redux-devtools-core/src/app/constants/socketOptions.ts similarity index 100% rename from packages/redux-devtools-core/src/app/constants/socketOptions.js rename to packages/redux-devtools-core/src/app/constants/socketOptions.ts diff --git a/packages/redux-devtools-core/src/app/containers/Actions.js b/packages/redux-devtools-core/src/app/containers/Actions.tsx similarity index 72% rename from packages/redux-devtools-core/src/app/containers/Actions.js rename to packages/redux-devtools-core/src/app/containers/Actions.tsx index 85b6a0ca..d813203c 100644 --- a/packages/redux-devtools-core/src/app/containers/Actions.js +++ b/packages/redux-devtools-core/src/app/containers/Actions.tsx @@ -1,7 +1,5 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; +import { connect, ResolveThunks } from 'react-redux'; import { Container } from 'devui'; import SliderMonitor from './monitors/Slider'; import { liftedDispatch as liftedDispatchAction, getReport } from '../actions'; @@ -10,8 +8,13 @@ import DevTools from '../containers/DevTools'; import Dispatcher from './monitors/Dispatcher'; import TopButtons from '../components/TopButtons'; import BottomButtons from '../components/BottomButtons'; +import { StoreState } from '../reducers'; -class Actions extends Component { +type StateProps = ReturnType; +type DispatchProps = ResolveThunks; +type Props = StateProps & DispatchProps; + +class Actions extends Component { render() { const { monitor, @@ -51,17 +54,7 @@ class Actions extends Component { } } -Actions.propTypes = { - liftedDispatch: PropTypes.func.isRequired, - liftedState: PropTypes.object.isRequired, - monitorState: PropTypes.object, - options: PropTypes.object.isRequired, - monitor: PropTypes.string, - dispatcherIsOpen: PropTypes.bool, - sliderIsOpen: PropTypes.bool, -}; - -function mapStateToProps(state) { +const mapStateToProps = (state: StoreState) => { const instances = state.instances; const id = getActiveInstance(instances); return { @@ -73,13 +66,11 @@ function mapStateToProps(state) { sliderIsOpen: state.monitor.sliderIsOpen, reports: state.reports.data, }; -} +}; -function mapDispatchToProps(dispatch) { - return { - liftedDispatch: bindActionCreators(liftedDispatchAction, dispatch), - getReport: bindActionCreators(getReport, dispatch), - }; -} +const actionCreators = { + liftedDispatch: liftedDispatchAction, + getReport, +}; -export default connect(mapStateToProps, mapDispatchToProps)(Actions); +export default connect(mapStateToProps, actionCreators)(Actions); diff --git a/packages/redux-devtools-core/src/app/containers/App.js b/packages/redux-devtools-core/src/app/containers/App.tsx similarity index 54% rename from packages/redux-devtools-core/src/app/containers/App.js rename to packages/redux-devtools-core/src/app/containers/App.tsx index c456800a..9417bd5c 100644 --- a/packages/redux-devtools-core/src/app/containers/App.js +++ b/packages/redux-devtools-core/src/app/containers/App.tsx @@ -1,14 +1,17 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; +import { connect, ResolveThunks } from 'react-redux'; import { Container, Notification } from 'devui'; import { clearNotification } from '../actions'; import Header from '../components/Header'; import Actions from '../containers/Actions'; import Settings from '../components/Settings'; +import { StoreState } from '../reducers'; -class App extends Component { +type StateProps = ReturnType; +type DispatchProps = ResolveThunks; +type Props = StateProps & DispatchProps; + +class App extends Component { render() { const { section, theme, notification } = this.props; let body; @@ -37,28 +40,14 @@ class App extends Component { } } -App.propTypes = { - section: PropTypes.string.isRequired, - theme: PropTypes.object.isRequired, - notification: PropTypes.shape({ - message: PropTypes.string, - type: PropTypes.string, - }), - clearNotification: PropTypes.func, +const mapStateToProps = (state: StoreState) => ({ + section: state.section, + theme: state.theme, + notification: state.notification, +}); + +const actionCreators = { + clearNotification, }; -function mapStateToProps(state) { - return { - section: state.section, - theme: state.theme, - notification: state.notification, - }; -} - -function mapDispatchToProps(dispatch) { - return { - clearNotification: bindActionCreators(clearNotification, dispatch), - }; -} - -export default connect(mapStateToProps, mapDispatchToProps)(App); +export default connect(mapStateToProps, actionCreators)(App); diff --git a/packages/redux-devtools-core/src/app/containers/DevTools.js b/packages/redux-devtools-core/src/app/containers/DevTools.tsx similarity index 53% rename from packages/redux-devtools-core/src/app/containers/DevTools.js rename to packages/redux-devtools-core/src/app/containers/DevTools.tsx index 5009a06d..cbfff2de 100644 --- a/packages/redux-devtools-core/src/app/containers/DevTools.js +++ b/packages/redux-devtools-core/src/app/containers/DevTools.tsx @@ -1,20 +1,49 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import { withTheme } from 'styled-components'; +import { LiftedAction, LiftedState } from 'redux-devtools-instrument'; +import { Action } from 'redux'; import getMonitor from '../utils/getMonitor'; +import { InitMonitorAction } from '../actions'; +import { Features, State } from '../reducers/instances'; +import { MonitorStateMonitorState } from '../reducers/monitor'; +import { ThemeFromProvider } from 'devui'; -class DevTools extends Component { - constructor(props) { +interface Props { + monitor: string; + liftedState: State; + monitorState: MonitorStateMonitorState | undefined; + dispatch: ( + action: LiftedAction, unknown> | InitMonitorAction + ) => void; + features: Features | undefined; + theme: ThemeFromProvider; +} + +class DevTools extends Component { + monitorProps: unknown; + Monitor?: React.ComponentType< + LiftedState, unknown> + > & { + update( + monitorProps: unknown, + state: unknown | undefined, + action: Action + ): unknown; + }; + preventRender?: boolean; + + constructor(props: Props) { super(props); this.getMonitor(props, props.monitorState); } - getMonitor(props, skipUpdate) { + getMonitor(props: Props, skipUpdate?: unknown) { const monitorElement = getMonitor(props); this.monitorProps = monitorElement.props; this.Monitor = monitorElement.type; - const update = this.Monitor.update; + // eslint-disable-next-line @typescript-eslint/unbound-method + const update = this.Monitor!.update; if (update) { let newMonitorState; const monitorState = props.monitorState; @@ -24,7 +53,11 @@ class DevTools extends Component { ) { newMonitorState = monitorState; } else { - newMonitorState = update(this.monitorProps, undefined, {}); + newMonitorState = update( + this.monitorProps, + undefined, + {} as Action + ); if (newMonitorState !== monitorState) { this.preventRender = true; } @@ -38,21 +71,23 @@ class DevTools extends Component { } } - UNSAFE_componentWillUpdate(nextProps) { + UNSAFE_componentWillUpdate(nextProps: Props) { if (nextProps.monitor !== this.props.monitor) this.getMonitor(nextProps); } - shouldComponentUpdate(nextProps) { + shouldComponentUpdate(nextProps: Props) { return ( nextProps.monitor !== this.props.monitor || nextProps.liftedState !== this.props.liftedState || - nextProps.monitorState !== this.props.liftedState || + nextProps.monitorState !== this.props.monitorState || nextProps.features !== this.props.features || nextProps.theme.scheme !== this.props.theme.scheme ); } - dispatch = (action) => { + dispatch = ( + action: LiftedAction, unknown> | InitMonitorAction + ) => { this.props.dispatch(action); }; @@ -66,9 +101,10 @@ class DevTools extends Component { ...this.props.liftedState, monitorState: this.props.monitorState, }; + const MonitorAsAny = this.Monitor as any; return (
- ; +type Props = DispatchProps; + +class ChartMonitorWrapper extends Component { static update = ChartMonitor.update; - onClickText = (data) => { - const inspectedStatePath = []; + onClickText = (data: NodeWithId) => { + const inspectedStatePath: string[] = []; getPath(data, inspectedStatePath); this.props.selectMonitorWithState('InspectorMonitor', { inspectedStatePath, @@ -33,6 +35,8 @@ class ChartMonitorWrapper extends Component { render() { return ( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ; +interface OwnProps { + options: Options; +} +type Props = DispatchProps & OwnProps; - state = { +interface State { + selected: 'default' | number; + customAction: string; + args: (string | undefined)[]; + rest: string; + changed: boolean; +} + +class Dispatcher extends Component { + state: State = { selected: 'default', customAction: this.props.options.lib === 'redux' ? "{\n type: ''\n}" : 'this.', @@ -62,7 +70,7 @@ class Dispatcher extends Component { changed: false, }; - UNSAFE_componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { if ( this.state.selected !== 'default' && !nextProps.options.actionCreators @@ -74,14 +82,14 @@ class Dispatcher extends Component { } } - shouldComponentUpdate(nextProps, nextState) { + shouldComponentUpdate(nextProps: Props, nextState: State) { return ( nextState !== this.state || nextProps.options.actionCreators !== this.props.options.actionCreators ); } - selectActionCreator = (selected) => { + selectActionCreator = (selected: 'default' | 'actions-help' | number) => { if (selected === 'actions-help') { window.open( 'https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/' + @@ -90,14 +98,14 @@ class Dispatcher extends Component { return; } - const args = []; + const args: string[] = []; if (selected !== 'default') { - args.length = this.props.options.actionCreators[selected].args.length; + args.length = this.props.options.actionCreators![selected].args.length; } this.setState({ selected, args, rest: '[]', changed: false }); }; - handleArg = (argIndex) => (value) => { + handleArg = (argIndex: number) => (value: string) => { const args = [ ...this.state.args.slice(0, argIndex), value || undefined, @@ -106,26 +114,26 @@ class Dispatcher extends Component { this.setState({ args, changed: true }); }; - handleRest = (rest) => { + handleRest = (rest: string) => { this.setState({ rest, changed: true }); }; - handleCustomAction = (customAction) => { + handleCustomAction = (customAction: string) => { this.setState({ customAction, changed: true }); }; dispatchAction = () => { const { selected, customAction, args, rest } = this.state; - if (this.state.selected !== 'default') { + if (selected !== 'default') { // remove trailing `undefined` arguments let i = args.length - 1; while (i >= 0 && typeof args[i] === 'undefined') { - args.pop(i); + args.pop(); i--; } this.props.dispatch({ - name: this.props.options.actionCreators[selected].name, + name: this.props.options.actionCreators![selected].name, selected, args, rest, @@ -174,7 +182,9 @@ class Dispatcher extends Component { ); } - let options = [{ value: 'default', label: 'Custom action' }]; + let options: { value: string | number; label: string }[] = [ + { value: 'default', label: 'Custom action' }, + ]; if (actionCreators && actionCreators.length > 0) { options = options.concat( actionCreators.map(({ name, args }, i) => ({ @@ -208,10 +218,8 @@ class Dispatcher extends Component { } } -function mapDispatchToProps(dispatch) { - return { - dispatch: bindActionCreators(dispatchRemotely, dispatch), - }; -} +const actionCreators = { + dispatch: dispatchRemotely, +}; -export default connect(null, mapDispatchToProps)(Dispatcher); +export default connect(null, actionCreators)(Dispatcher); diff --git a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.js b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.tsx similarity index 53% rename from packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.js rename to packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.tsx index d3e4ff49..f2fc0b60 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.js +++ b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.tsx @@ -1,18 +1,28 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; +import React, { Component, RefCallback } from 'react'; +import { connect, ResolveThunks } from 'react-redux'; import { withTheme } from 'styled-components'; -import { tree } from 'd3-state-visualizer'; +import { InputOptions, NodeWithId, tree } from 'd3-state-visualizer'; import { getPath } from '../ChartMonitorWrapper'; import { updateMonitorState } from '../../../actions'; +import { ThemeFromProvider } from 'devui'; const style = { width: '100%', height: '100%', }; -class ChartTab extends Component { +type DispatchProps = ResolveThunks; +interface OwnProps { + data: unknown; + theme: ThemeFromProvider; +} +type Props = DispatchProps & OwnProps; + +class ChartTab extends Component { + node?: HTMLDivElement | null; + // eslint-disable-next-line @typescript-eslint/ban-types + renderChart?: (nextState?: {} | null | undefined) => void; + shouldComponentUpdate() { return false; } @@ -21,28 +31,30 @@ class ChartTab extends Component { this.createChart(this.props); } - UNSAFE_componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { if ( this.props.theme.scheme !== nextProps.theme.scheme || nextProps.theme.light !== this.props.theme.light ) { - this.node.innerHTML = ''; + this.node!.innerHTML = ''; this.createChart(nextProps); } else if (nextProps.data !== this.props.data) { - this.renderChart(nextProps.data); + // eslint-disable-next-line @typescript-eslint/ban-types + this.renderChart!(nextProps.data as {} | null | undefined); } } - getRef = (node) => { + getRef: RefCallback = (node) => { this.node = node; }; - createChart(props) { - this.renderChart = tree(this.node, this.getChartTheme(props.theme)); - this.renderChart(props.data); + createChart(props: Props) { + this.renderChart = tree(this.node!, this.getChartTheme(props.theme)); + // eslint-disable-next-line @typescript-eslint/ban-types + this.renderChart(props.data as {} | null | undefined); } - getChartTheme(theme) { + getChartTheme(theme: ThemeFromProvider): Partial { return { heightBetweenNodesCoeff: 1, widthBetweenNodesCoeff: 1.3, @@ -60,27 +72,27 @@ class ChartTab extends Component { style: { width: '100%', height: '100%', - node: { + node: ({ colors: { default: theme.base0B, collapsed: theme.base0B, parent: theme.base0E, }, radius: 7, - }, - text: { + } as unknown) as string, + text: ({ colors: { default: theme.base0D, hover: theme.base06, }, - }, + } as unknown) as string, }, onClickText: this.onClickText, }; } - onClickText = (data) => { - const inspectedStatePath = []; + onClickText = (data: NodeWithId) => { + const inspectedStatePath: string[] = []; getPath(data, inspectedStatePath); this.props.updateMonitorState({ inspectedStatePath, @@ -93,17 +105,9 @@ class ChartTab extends Component { } } -ChartTab.propTypes = { - data: PropTypes.object, - updateMonitorState: PropTypes.func.isRequired, - theme: PropTypes.object.isRequired, +const actionCreators = { + updateMonitorState, }; -function mapDispatchToProps(dispatch) { - return { - updateMonitorState: bindActionCreators(updateMonitorState, dispatch), - }; -} - -const ConnectedChartTab = connect(null, mapDispatchToProps)(ChartTab); +const ConnectedChartTab = connect(null, actionCreators)(ChartTab); export default withTheme(ConnectedChartTab); diff --git a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/RawTab.js b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/RawTab.tsx similarity index 57% rename from packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/RawTab.js rename to packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/RawTab.tsx index 68fd5cb5..15cead09 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/RawTab.js +++ b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/RawTab.tsx @@ -2,21 +2,27 @@ import React, { Component } from 'react'; import { Editor } from 'devui'; import { stringify } from 'javascript-stringify'; -export default class RawTab extends Component { - constructor(props) { +interface Props { + data: unknown; +} + +export default class RawTab extends Component { + value?: string | undefined; + + constructor(props: Props) { super(props); this.stringifyData(props); } - shouldComponentUpdate(nextProps) { + shouldComponentUpdate(nextProps: Props) { return nextProps.data !== this.value; } - UNSAFE_componentWillUpdate(nextProps) { + UNSAFE_componentWillUpdate(nextProps: Props) { this.stringifyData(nextProps); } - stringifyData(props) { + stringifyData(props: Props) { this.value = stringify(props.data, null, 2); } diff --git a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.js b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.tsx similarity index 62% rename from packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.js rename to packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.tsx index f5d31cde..a70b2eae 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.js +++ b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.tsx @@ -1,8 +1,8 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { Tabs } from 'devui'; +import { connect, ResolveThunks } from 'react-redux'; +import { Tab, Tabs } from 'devui'; +import { TabComponentProps } from 'redux-devtools-inspector-monitor'; +import { Action } from 'redux'; import StateTree from 'redux-devtools-inspector-monitor/lib/tabs/StateTab'; import ActionTree from 'redux-devtools-inspector-monitor/lib/tabs/ActionTab'; import DiffTree from 'redux-devtools-inspector-monitor/lib/tabs/DiffTab'; @@ -10,14 +10,24 @@ import { selectMonitorTab } from '../../../actions'; import RawTab from './RawTab'; import ChartTab from './ChartTab'; import VisualDiffTab from './VisualDiffTab'; +import { StoreState } from '../../../reducers'; +import { Delta } from 'jsondiffpatch'; -class SubTabs extends Component { - constructor(props) { +type StateProps = ReturnType; +type DispatchProps = ResolveThunks; +type Props = StateProps & + DispatchProps & + TabComponentProps>; + +class SubTabs extends Component { + tabs?: (Tab | Tab<{ data: unknown }> | Tab<{ data?: Delta }>)[]; + + constructor(props: Props) { super(props); this.updateTabs(props); } - UNSAFE_componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { if (nextProps.parentTab !== this.props.parentTab) { this.updateTabs(nextProps); } @@ -34,7 +44,7 @@ class SubTabs extends Component { } }; - updateTabs(props) { + updateTabs(props: Props) { const parentTab = props.parentTab; if (parentTab === 'Diff') { @@ -47,7 +57,7 @@ class SubTabs extends Component { { name: 'Raw', component: VisualDiffTab, - selector: this.selector, + selector: this.selector as () => { data?: Delta }, }, ]; return; @@ -79,7 +89,7 @@ class SubTabs extends Component { return ( @@ -87,26 +97,13 @@ class SubTabs extends Component { } } -SubTabs.propTypes = { - selected: PropTypes.string, - parentTab: PropTypes.string, - selectMonitorTab: PropTypes.func.isRequired, - action: PropTypes.object, - delta: PropTypes.object, - nextState: PropTypes.object, +const mapStateToProps = (state: StoreState) => ({ + parentTab: state.monitor.monitorState!.tabName, + selected: state.monitor.monitorState!.subTabName, +}); + +const actionCreators = { + selectMonitorTab, }; -function mapStateToProps(state) { - return { - parentTab: state.monitor.monitorState.tabName, - selected: state.monitor.monitorState.subTabName, - }; -} - -function mapDispatchToProps(dispatch) { - return { - selectMonitorTab: bindActionCreators(selectMonitorTab, dispatch), - }; -} - -export default connect(mapStateToProps, mapDispatchToProps)(SubTabs); +export default connect(mapStateToProps, actionCreators)(SubTabs); diff --git a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/VisualDiffTab.js b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/VisualDiffTab.tsx similarity index 93% rename from packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/VisualDiffTab.js rename to packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/VisualDiffTab.tsx index d2fb3d49..f48e0c55 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/VisualDiffTab.js +++ b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/VisualDiffTab.tsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { formatters } from 'jsondiffpatch'; +import { Delta, formatters } from 'jsondiffpatch'; import styled from 'styled-components'; import { effects } from 'devui'; @@ -218,22 +217,22 @@ export const StyledContainer = styled.div` } `; -export default class VisualDiffTab extends Component { - shouldComponentUpdate(nextProps) { +interface Props { + data?: Delta; +} + +export default class VisualDiffTab extends Component { + shouldComponentUpdate(nextProps: Props) { return this.props.data !== nextProps.data; } render() { - let __html; + let __html: string | undefined; const data = this.props.data; if (data) { - __html = formatters.html.format(data); + __html = formatters.html.format(data, undefined); } - return ; + return ; } } - -VisualDiffTab.propTypes = { - data: PropTypes.object, -}; diff --git a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.tsx similarity index 58% rename from packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js rename to packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.tsx index f8ebd4cc..63239de8 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.js +++ b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/index.tsx @@ -1,10 +1,10 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import InspectorMonitor from 'redux-devtools-inspector-monitor'; +import InspectorMonitor, { Tab } from 'redux-devtools-inspector-monitor'; import TraceTab from 'redux-devtools-inspector-monitor-trace-tab'; import TestTab from 'redux-devtools-inspector-monitor-test-tab'; import { DATA_TYPE_KEY } from '../../../constants/dataTypes'; import SubTabs from './SubTabs'; +import { Action } from 'redux'; const DEFAULT_TABS = [ { @@ -25,25 +25,38 @@ const DEFAULT_TABS = [ }, ]; -class InspectorWrapper extends Component { +interface Features { + test?: boolean; + skip?: boolean; +} +interface Props { + features?: Features; +} + +class InspectorWrapper extends Component { static update = InspectorMonitor.update; render() { const { features, ...rest } = this.props; - let tabs; + let tabs: () => Tab>[]; if (features && features.test) { - tabs = () => [...DEFAULT_TABS, { name: 'Test', component: TestTab }]; + tabs = () => [ + ...(DEFAULT_TABS as Tab>[]), + ({ name: 'Test', component: TestTab } as unknown) as Tab< + unknown, + Action + >, + ]; } else { - tabs = () => DEFAULT_TABS; + tabs = () => DEFAULT_TABS as Tab>[]; } return ( @@ -51,8 +64,4 @@ class InspectorWrapper extends Component { } } -InspectorWrapper.propTypes = { - features: PropTypes.object, -}; - export default InspectorWrapper; diff --git a/packages/redux-devtools-core/src/app/containers/monitors/Slider.js b/packages/redux-devtools-core/src/app/containers/monitors/Slider.tsx similarity index 58% rename from packages/redux-devtools-core/src/app/containers/monitors/Slider.js rename to packages/redux-devtools-core/src/app/containers/monitors/Slider.tsx index 8363108c..03a5fe4f 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/Slider.js +++ b/packages/redux-devtools-core/src/app/containers/monitors/Slider.tsx @@ -1,7 +1,10 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import styled, { withTheme } from 'styled-components'; import SliderMonitor from 'redux-devtools-slider-monitor'; +import { LiftedAction } from 'redux-devtools-instrument'; +import { Action } from 'redux'; +import { ThemeFromProvider } from 'devui'; +import { State } from '../../reducers/instances'; const SliderWrapper = styled.div` border-color: ${(props) => props.theme.base02}; @@ -9,8 +12,14 @@ const SliderWrapper = styled.div` border-width: 1px 0; `; -class Slider extends Component { - shouldComponentUpdate(nextProps) { +interface Props { + liftedState: State; + dispatch: (action: LiftedAction, unknown>) => void; + theme: ThemeFromProvider; +} + +class Slider extends Component { + shouldComponentUpdate(nextProps: Props) { return ( nextProps.liftedState !== this.props.liftedState || nextProps.theme.scheme !== this.props.theme.scheme @@ -21,6 +30,8 @@ class Slider extends Component { { + store?: Store; -class Root extends Component { UNSAFE_componentWillMount() { configureStore((store, preloadedState) => { this.store = store; store.dispatch({ type: CONNECT_REQUEST, - options: preloadedState.connection || this.props.socketOptions, + options: (preloadedState!.connection || + this.props.socketOptions) as ConnectionOptions, }); this.forceUpdate(); }); @@ -20,21 +29,13 @@ class Root extends Component { render() { if (!this.store) return null; + const AppAsAny = App as any; return ( - + ); } } -Root.propTypes = { - socketOptions: PropTypes.shape({ - hostname: PropTypes.string, - port: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - autoReconnect: PropTypes.bool, - secure: PropTypes.bool, - }), -}; - export default Root; diff --git a/packages/redux-devtools-core/src/app/middlewares/api.js b/packages/redux-devtools-core/src/app/middlewares/api.ts similarity index 70% rename from packages/redux-devtools-core/src/app/middlewares/api.js rename to packages/redux-devtools-core/src/app/middlewares/api.ts index 7a6bedd4..bc303987 100644 --- a/packages/redux-devtools-core/src/app/middlewares/api.js +++ b/packages/redux-devtools-core/src/app/middlewares/api.ts @@ -1,5 +1,6 @@ -import socketCluster from 'socketcluster-client'; +import socketCluster, { SCClientSocket } from 'socketcluster-client'; import { stringify } from 'jsan'; +import { Dispatch, MiddlewareAPI } from 'redux'; import socketOptions from '../constants/socketOptions'; import * as actions from '../constants/socketActionTypes'; import { getActiveInstance } from '../reducers/instances'; @@ -12,22 +13,37 @@ import { GET_REPORT_ERROR, GET_REPORT_SUCCESS, } from '../constants/actionTypes'; -import { showNotification, importState } from '../actions'; +import { + showNotification, + importState, + StoreAction, + EmitAction, + LiftedActionAction, + Request, + DispatchAction, + UpdateReportsRequest, +} from '../actions'; import { nonReduxDispatch } from '../utils/monitorActions'; +import { StoreState } from '../reducers'; -let socket; -let store; +let socket: SCClientSocket; +let store: MiddlewareAPI, StoreState>; -function emit({ message: type, id, instanceId, action, state }) { +function emit({ message: type, id, instanceId, action, state }: EmitAction) { socket.emit(id ? 'sc-' + id : 'respond', { type, action, state, instanceId }); } -function startMonitoring(channel) { +function startMonitoring(channel: string) { if (channel !== store.getState().socket.baseChannel) return; store.dispatch({ type: actions.EMIT, message: 'START' }); } -function dispatchRemoteAction({ message, action, state, toAll }) { +function dispatchRemoteAction({ + message, + action, + state, + toAll, +}: LiftedActionAction) { const instances = store.getState().instances; const instanceId = getActiveInstance(instances); const id = !toAll && instances.options[instanceId].connectionId; @@ -39,7 +55,7 @@ function dispatchRemoteAction({ message, action, state, toAll }) { store, message, instanceId, - action, + action as DispatchAction, state, instances ), @@ -48,7 +64,32 @@ function dispatchRemoteAction({ message, action, state, toAll }) { }); } -function monitoring(request) { +interface RequestBase { + id?: string; + instanceId?: string; +} +interface DisconnectedAction extends RequestBase { + type: 'DISCONNECTED'; + id: string; +} +interface StartAction extends RequestBase { + type: 'START'; + id: string; +} +interface ErrorAction extends RequestBase { + type: 'ERROR'; + payload: string; +} +interface RequestWithData extends RequestBase { + data: Request; +} +type MonitoringRequest = + | DisconnectedAction + | StartAction + | ErrorAction + | Request; + +function monitoring(request: MonitoringRequest) { if (request.type === 'DISCONNECTED') { store.dispatch({ type: REMOVE_INSTANCE, @@ -68,7 +109,9 @@ function monitoring(request) { store.dispatch({ type: UPDATE_STATE, - request: request.data ? { ...request.data, id: request.id } : request, + request: ((request as unknown) as RequestWithData).data + ? { ...((request as unknown) as RequestWithData).data, id: request.id } + : request, }); const instances = store.getState().instances; @@ -87,11 +130,14 @@ function monitoring(request) { } } -function subscribe(channelName, subscription) { +function subscribe( + channelName: string, + subscription: typeof UPDATE_STATE | typeof UPDATE_REPORTS +) { const channel = socket.subscribe(channelName); if (subscription === UPDATE_STATE) channel.watch(monitoring); else { - const watcher = (request) => { + const watcher = (request: UpdateReportsRequest) => { store.dispatch({ type: subscription, request }); }; channel.watch(watcher); @@ -150,7 +196,7 @@ function connect() { socket = socketCluster.create( connection.type === 'remotedev' ? socketOptions : connection.options ); - handleConnection(store); + handleConnection(); } catch (error) { store.dispatch({ type: actions.CONNECT_ERROR, error }); store.dispatch(showNotification(error.message || error)); @@ -163,7 +209,7 @@ function disconnect() { } function login() { - socket.emit('login', {}, (error, baseChannel) => { + socket.emit('login', {}, (error: Error, baseChannel: string) => { if (error) { store.dispatch({ type: actions.AUTH_ERROR, error }); return; @@ -182,24 +228,28 @@ function login() { }); } -function getReport(reportId) { - socket.emit('getReport', reportId, (error, data) => { - if (error) { - store.dispatch({ type: GET_REPORT_ERROR, error }); - return; +function getReport(reportId: unknown) { + socket.emit( + 'getReport', + reportId, + (error: Error, data: { payload: string }) => { + if (error) { + store.dispatch({ type: GET_REPORT_ERROR, error }); + return; + } + store.dispatch({ type: GET_REPORT_SUCCESS, data }); + store.dispatch(importState(data.payload)); } - store.dispatch({ type: GET_REPORT_SUCCESS, data }); - store.dispatch(importState(data.payload)); - }); + ); } -export default function api(inStore) { +export default function api( + inStore: MiddlewareAPI, StoreState> +) { store = inStore; - return (next) => (action) => { + return (next: Dispatch) => (action: StoreAction) => { const result = next(action); - switch ( - action.type // eslint-disable-line default-case - ) { + switch (action.type) { case actions.CONNECT_REQUEST: connect(); break; diff --git a/packages/redux-devtools-core/src/app/middlewares/exportState.js b/packages/redux-devtools-core/src/app/middlewares/exportState.ts similarity index 72% rename from packages/redux-devtools-core/src/app/middlewares/exportState.js rename to packages/redux-devtools-core/src/app/middlewares/exportState.ts index d0609022..58cb9315 100644 --- a/packages/redux-devtools-core/src/app/middlewares/exportState.js +++ b/packages/redux-devtools-core/src/app/middlewares/exportState.ts @@ -1,14 +1,17 @@ import stringifyJSON from '../utils/stringifyJSON'; import { UPDATE_STATE, LIFTED_ACTION, EXPORT } from '../constants/actionTypes'; import { getActiveInstance } from '../reducers/instances'; +import { Dispatch, MiddlewareAPI } from 'redux'; +import { ExportRequest, StoreAction } from '../actions'; +import { StoreState } from '../reducers'; -let toExport; +let toExport: string | undefined; -function download(state) { +function download(state: string) { const blob = new Blob([state], { type: 'octet/stream' }); const href = window.URL.createObjectURL(blob); const a = document.createElement('a'); - a.style = 'display: none'; + a.style.display = 'none'; a.download = 'state.json'; a.href = href; document.body.appendChild(a); @@ -19,15 +22,17 @@ function download(state) { }, 0); } -const exportState = (store) => (next) => (action) => { +const exportState = ( + store: MiddlewareAPI, StoreState> +) => (next: Dispatch) => (action: StoreAction) => { const result = next(action); if ( toExport && action.type === UPDATE_STATE && - action.request.type === 'EXPORT' + action.request!.type === 'EXPORT' ) { - const request = action.request; + const request = action.request!; const id = request.instanceId || request.id; if (id === toExport) { toExport = undefined; @@ -35,7 +40,7 @@ const exportState = (store) => (next) => (action) => { JSON.stringify( { payload: request.payload, - preloadedState: request.committedState, + preloadedState: (request as ExportRequest).committedState, }, null, '\t' diff --git a/packages/redux-devtools-core/src/app/reducers/connection.js b/packages/redux-devtools-core/src/app/reducers/connection.ts similarity index 50% rename from packages/redux-devtools-core/src/app/reducers/connection.js rename to packages/redux-devtools-core/src/app/reducers/connection.ts index a9e64411..65c609a8 100644 --- a/packages/redux-devtools-core/src/app/reducers/connection.js +++ b/packages/redux-devtools-core/src/app/reducers/connection.ts @@ -1,11 +1,22 @@ import { RECONNECT } from '../constants/socketActionTypes'; +import { ConnectionType, StoreAction } from '../actions'; + +export interface ConnectionOptions { + readonly hostname: string; + readonly port: number; + readonly secure: boolean; +} +export interface ConnectionState { + readonly options: ConnectionOptions; + readonly type: ConnectionType; +} export default function connection( - state = { + state: ConnectionState = { options: { hostname: 'localhost', port: 8000, secure: false }, type: 'remotedev', }, - action + action: StoreAction ) { if (action.type === RECONNECT) { const { type, ...options } = action.options; diff --git a/packages/redux-devtools-core/src/app/reducers/index.js b/packages/redux-devtools-core/src/app/reducers/index.js deleted file mode 100644 index ae099180..00000000 --- a/packages/redux-devtools-core/src/app/reducers/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import { combineReducers } from 'redux'; -import section from './section'; -import connection from './connection'; -import socket from './socket'; -import monitor from './monitor'; -import notification from './notification'; -import instances from './instances'; -import reports from './reports'; -import theme from './theme'; - -const rootReducer = combineReducers({ - section, - theme, - connection, - socket, - monitor, - instances, - reports, - notification, -}); - -export default rootReducer; diff --git a/packages/redux-devtools-core/src/app/reducers/index.ts b/packages/redux-devtools-core/src/app/reducers/index.ts new file mode 100644 index 00000000..6b47effd --- /dev/null +++ b/packages/redux-devtools-core/src/app/reducers/index.ts @@ -0,0 +1,34 @@ +import { combineReducers } from 'redux'; +import section, { SectionState } from './section'; +import connection, { ConnectionState } from './connection'; +import socket, { SocketState } from './socket'; +import monitor, { MonitorState } from './monitor'; +import notification, { NotificationState } from './notification'; +import instances, { InstancesState } from './instances'; +import reports, { ReportsState } from './reports'; +import theme, { ThemeState } from './theme'; +import { StoreAction } from '../actions'; + +export interface StoreState { + readonly section: SectionState; + readonly theme: ThemeState; + readonly connection: ConnectionState; + readonly socket: SocketState; + readonly monitor: MonitorState; + readonly instances: InstancesState; + readonly reports: ReportsState; + readonly notification: NotificationState; +} + +const rootReducer = combineReducers({ + section, + theme, + connection, + socket, + monitor, + instances, + reports, + notification, +}); + +export default rootReducer; diff --git a/packages/redux-devtools-core/src/app/reducers/instances.js b/packages/redux-devtools-core/src/app/reducers/instances.ts similarity index 76% rename from packages/redux-devtools-core/src/app/reducers/instances.js rename to packages/redux-devtools-core/src/app/reducers/instances.ts index 519e750a..aa98f2c3 100644 --- a/packages/redux-devtools-core/src/app/reducers/instances.js +++ b/packages/redux-devtools-core/src/app/reducers/instances.ts @@ -1,3 +1,5 @@ +import { PerformAction } from 'redux-devtools-instrument'; +import { Action } from 'redux'; import { UPDATE_STATE, SET_STATE, @@ -10,8 +12,60 @@ import { import { DISCONNECTED } from '../constants/socketActionTypes'; import parseJSON from '../utils/parseJSON'; import { recompute } from '../utils/updateState'; +import { + ActionCreator, + LiftedActionDispatchAction, + Request, + StoreAction, +} from '../actions'; -export const initialState = { +export interface Features { + lock?: boolean; + export?: string | boolean; + import?: string | boolean; + persist?: boolean; + pause?: boolean; + reorder?: boolean; + jump?: boolean; + skip?: boolean; + dispatch?: boolean; + sync?: boolean; + test?: boolean; +} + +export interface Options { + name?: string; + connectionId?: string; + explicitLib?: string; + lib?: string; + actionCreators?: ActionCreator[]; + features: Features; + serialize?: boolean; +} + +export interface State { + actionsById: { [actionId: number]: PerformAction> }; + computedStates: { state: unknown; error?: string }[]; + currentStateIndex: number; + nextActionId: number; + skippedActionIds: number[]; + stagedActionIds: number[]; + committedState?: unknown; + isLocked?: boolean; + isPaused?: boolean; +} + +export interface InstancesState { + selected: string | null; + current: string; + sync: boolean; + connections: { [id: string]: string[] }; + options: { [id: string]: Options }; + states: { [id: string]: State }; + persisted?: boolean; +} + +export const initialState: InstancesState = { selected: null, current: 'default', sync: false, @@ -29,35 +83,42 @@ export const initialState = { }, }; -function updateState(state, request, id, serialize) { - let payload = request.payload; +function updateState( + state: { [id: string]: State }, + request: Request, + id: string, + serialize: boolean | undefined +) { + let payload: State = request.payload as State; const actionsById = request.actionsById; if (actionsById) { payload = { + // eslint-disable-next-line @typescript-eslint/ban-types ...payload, actionsById: parseJSON(actionsById, serialize), computedStates: parseJSON(request.computedStates, serialize), - }; + } as State; if (request.type === 'STATE' && request.committedState) { payload.committedState = payload.computedStates[0].state; } } else { - payload = parseJSON(payload, serialize); + payload = parseJSON((payload as unknown) as string, serialize) as State; } let newState; const liftedState = state[id] || state.default; - const action = (request.action && parseJSON(request.action, serialize)) || {}; + const action = ((request.action && parseJSON(request.action, serialize)) || + {}) as PerformAction>; switch (request.type) { case 'INIT': newState = recompute(state.default, payload, { action: { type: '@@INIT' }, - timestamp: action.timestamp || Date.now(), + timestamp: (action as { timestamp?: number }).timestamp || Date.now(), }); break; case 'ACTION': { - let isExcess = request.isExcess; + const isExcess = request.isExcess; const nextActionId = request.nextActionId || liftedState.nextActionId + 1; const maxAge = request.maxAge; if (Array.isArray(action)) { @@ -66,7 +127,7 @@ function updateState(state, request, id, serialize) { for (let i = 0; i < action.length; i++) { newState = recompute( newState, - request.batched ? payload : payload[i], + request.batched ? payload : ((payload as unknown) as State[])[i], action[i], newState.nextActionId + 1, maxAge, @@ -148,7 +209,10 @@ function updateState(state, request, id, serialize) { return { ...state, [id]: newState }; } -export function dispatchAction(state, { action }) { +export function dispatchAction( + state: InstancesState, + { action }: LiftedActionDispatchAction +) { if (action.type === 'JUMP_TO_STATE' || action.type === 'JUMP_TO_ACTION') { const id = state.selected || state.current; const liftedState = state.states[id]; @@ -167,7 +231,7 @@ export function dispatchAction(state, { action }) { return state; } -function removeState(state, connectionId) { +function removeState(state: InstancesState, connectionId: string) { const instanceIds = state.connections[connectionId]; if (!instanceIds) return state; @@ -202,7 +266,11 @@ function removeState(state, connectionId) { }; } -function init({ type, action, name, libConfig = {} }, connectionId, current) { +function init( + { type, action, name, libConfig = {} }: Request, + connectionId: string, + current: string +): Options { let lib; let actionCreators; let creators = libConfig.actionCreators || action; @@ -234,7 +302,10 @@ function init({ type, action, name, libConfig = {} }, connectionId, current) { }; } -export default function instances(state = initialState, action) { +export default function instances( + state = initialState, + action: StoreAction +): InstancesState { switch (action.type) { case UPDATE_STATE: { const { request } = action; @@ -293,7 +364,7 @@ export default function instances(state = initialState, action) { ...state, states: { ...state.states, - [id]: parseJSON(action.state), + [id]: parseJSON(action.state) as State, }, }; } @@ -307,7 +378,5 @@ export default function instances(state = initialState, action) { } } -/* eslint-disable no-shadow */ -export const getActiveInstance = (instances) => +export const getActiveInstance = (instances: InstancesState) => instances.selected || instances.current; -/* eslint-enable */ diff --git a/packages/redux-devtools-core/src/app/reducers/monitor.js b/packages/redux-devtools-core/src/app/reducers/monitor.ts similarity index 62% rename from packages/redux-devtools-core/src/app/reducers/monitor.js rename to packages/redux-devtools-core/src/app/reducers/monitor.ts index f07e2197..8293d847 100644 --- a/packages/redux-devtools-core/src/app/reducers/monitor.js +++ b/packages/redux-devtools-core/src/app/reducers/monitor.ts @@ -5,28 +5,50 @@ import { TOGGLE_SLIDER, TOGGLE_DISPATCHER, } from '../constants/actionTypes'; +import { MonitorActionAction, StoreAction } from '../actions'; -const initialState = { +export interface MonitorStateMonitorState { + inspectedStatePath?: string[]; + tabName?: string; + subTabName?: string; + selectedActionId?: number | null; + startActionId?: number | null; + inspectedActionPath?: string[]; + __overwritten__?: string; +} +export interface MonitorState { + selected: string; + monitorState: MonitorStateMonitorState | undefined; + sliderIsOpen: boolean; + dispatcherIsOpen: boolean; +} + +const initialState: MonitorState = { selected: 'InspectorMonitor', monitorState: undefined, sliderIsOpen: true, dispatcherIsOpen: false, }; -export function dispatchMonitorAction(state, action) { +export function dispatchMonitorAction( + state: MonitorState, + action: MonitorActionAction +): MonitorState { return { ...state, - monitorState: - action.action.newMonitorState || + monitorState: (action.action.newMonitorState || action.monitorReducer( action.monitorProps, state.monitorState, action.action - ), + )) as MonitorStateMonitorState, }; } -export default function monitor(state = initialState, action) { +export default function monitor( + state = initialState, + action: StoreAction +): MonitorState { switch (action.type) { case MONITOR_ACTION: return dispatchMonitorAction(state, action); @@ -45,7 +67,7 @@ export default function monitor(state = initialState, action) { }; } case UPDATE_MONITOR_STATE: { - let inspectedStatePath = state.monitorState.inspectedStatePath; + let inspectedStatePath = state.monitorState!.inspectedStatePath!; if (action.nextState.inspectedStatePath) { inspectedStatePath = [ ...inspectedStatePath.slice(0, -1), diff --git a/packages/redux-devtools-core/src/app/reducers/notification.js b/packages/redux-devtools-core/src/app/reducers/notification.ts similarity index 57% rename from packages/redux-devtools-core/src/app/reducers/notification.js rename to packages/redux-devtools-core/src/app/reducers/notification.ts index cf2e59f1..c42e1ee9 100644 --- a/packages/redux-devtools-core/src/app/reducers/notification.js +++ b/packages/redux-devtools-core/src/app/reducers/notification.ts @@ -4,8 +4,18 @@ import { LIFTED_ACTION, ERROR, } from '../constants/actionTypes'; +import { StoreAction } from '../actions'; -export default function notification(state = null, action) { +interface Notification { + readonly type: 'error'; + readonly message: string; +} +export type NotificationState = Notification | null; + +export default function notification( + state: NotificationState = null, + action: StoreAction +): NotificationState { switch (action.type) { case SHOW_NOTIFICATION: return action.notification; diff --git a/packages/redux-devtools-core/src/app/reducers/reports.js b/packages/redux-devtools-core/src/app/reducers/reports.ts similarity index 67% rename from packages/redux-devtools-core/src/app/reducers/reports.js rename to packages/redux-devtools-core/src/app/reducers/reports.ts index 5f825572..a085461c 100644 --- a/packages/redux-devtools-core/src/app/reducers/reports.js +++ b/packages/redux-devtools-core/src/app/reducers/reports.ts @@ -1,12 +1,24 @@ import { UPDATE_REPORTS /* , GET_REPORT_SUCCESS */, } from '../constants/actionTypes'; +import { StoreAction } from '../actions'; -const initialState = { +export interface Data { + id: unknown; +} + +export interface ReportsState { + data: Data[]; +} + +const initialState: ReportsState = { data: [], }; -export default function reports(state = initialState, action) { +export default function reports( + state = initialState, + action: StoreAction +): ReportsState { /* if (action.type === GET_REPORT_SUCCESS) { const id = action.data.id; return { @@ -19,17 +31,16 @@ export default function reports(state = initialState, action) { return state; const request = action.request; - const data = request.data; switch (request.type) { case 'list': return { ...state, - data, + data: request.data, }; case 'add': return { ...state, - data: [...state.data, data], + data: [...state.data, request.data], }; case 'remove': return { diff --git a/packages/redux-devtools-core/src/app/reducers/section.js b/packages/redux-devtools-core/src/app/reducers/section.js deleted file mode 100644 index 252bdfbb..00000000 --- a/packages/redux-devtools-core/src/app/reducers/section.js +++ /dev/null @@ -1,8 +0,0 @@ -import { CHANGE_SECTION } from '../constants/actionTypes'; - -export default function section(state = 'Actions', action) { - if (action.type === CHANGE_SECTION) { - return action.section; - } - return state; -} diff --git a/packages/redux-devtools-core/src/app/reducers/section.ts b/packages/redux-devtools-core/src/app/reducers/section.ts new file mode 100644 index 00000000..3497384f --- /dev/null +++ b/packages/redux-devtools-core/src/app/reducers/section.ts @@ -0,0 +1,11 @@ +import { CHANGE_SECTION } from '../constants/actionTypes'; +import { StoreAction } from '../actions'; + +export type SectionState = string; + +export default function section(state = 'Actions', action: StoreAction) { + if (action.type === CHANGE_SECTION) { + return action.section; + } + return state; +} diff --git a/packages/redux-devtools-core/src/app/reducers/socket.js b/packages/redux-devtools-core/src/app/reducers/socket.ts similarity index 72% rename from packages/redux-devtools-core/src/app/reducers/socket.js rename to packages/redux-devtools-core/src/app/reducers/socket.ts index 9d1e9192..ae8fc1b3 100644 --- a/packages/redux-devtools-core/src/app/reducers/socket.js +++ b/packages/redux-devtools-core/src/app/reducers/socket.ts @@ -1,15 +1,29 @@ +import { AuthStates, States } from 'socketcluster-client/lib/scclientsocket'; import * as actions from '../constants/socketActionTypes'; +import { StoreAction } from '../actions'; -const initialState = { +export interface SocketState { + id: string | null; + channels: string[]; + socketState: States; + authState: AuthStates | 'pending'; + error: Error | undefined; + baseChannel?: string; + authToken?: null; +} + +const initialState: SocketState = { id: null, channels: [], socketState: actions.CLOSED, authState: actions.PENDING, - authToken: null, error: undefined, }; -export default function socket(state = initialState, action) { +export default function socket( + state = initialState, + action: StoreAction +): SocketState { switch (action.type) { case actions.CONNECT_REQUEST: { return { @@ -39,7 +53,6 @@ export default function socket(state = initialState, action) { return { ...state, authState: actions.AUTHENTICATED, - authToken: action.authToken, baseChannel: action.baseChannel, }; case actions.AUTH_ERROR: @@ -57,13 +70,13 @@ export default function socket(state = initialState, action) { case actions.SUBSCRIBE_SUCCESS: return { ...state, - channels: [...state.channels, action.channelName], + channels: [...state.channels, action.channel], }; case actions.UNSUBSCRIBE: return { ...state, channels: state.channels.filter( - (channel) => channel !== action.channelName + (channel) => channel !== action.channel ), }; case actions.DISCONNECTED: diff --git a/packages/redux-devtools-core/src/app/reducers/theme.js b/packages/redux-devtools-core/src/app/reducers/theme.js deleted file mode 100644 index 1fb50905..00000000 --- a/packages/redux-devtools-core/src/app/reducers/theme.js +++ /dev/null @@ -1,15 +0,0 @@ -import { CHANGE_THEME } from '../constants/actionTypes'; - -export default function theme( - state = { theme: 'default', scheme: 'default', light: true }, - action -) { - if (action.type === CHANGE_THEME) { - return { - theme: action.theme, - scheme: action.scheme, - light: !action.dark, - }; - } - return state; -} diff --git a/packages/redux-devtools-core/src/app/reducers/theme.ts b/packages/redux-devtools-core/src/app/reducers/theme.ts new file mode 100644 index 00000000..1c6618ad --- /dev/null +++ b/packages/redux-devtools-core/src/app/reducers/theme.ts @@ -0,0 +1,27 @@ +import { Scheme, Theme } from 'devui'; +import { CHANGE_THEME } from '../constants/actionTypes'; +import { StoreAction } from '../actions'; + +export interface ThemeState { + readonly theme: Theme; + readonly scheme: Scheme; + readonly light: boolean; +} + +export default function theme( + state: ThemeState = { + theme: 'default' as const, + scheme: 'default' as const, + light: true, + }, + action: StoreAction +) { + if (action.type === CHANGE_THEME) { + return { + theme: action.theme, + scheme: action.scheme, + light: !action.dark, + }; + } + return state; +} diff --git a/packages/redux-devtools-core/src/app/store/configureStore.js b/packages/redux-devtools-core/src/app/store/configureStore.js deleted file mode 100644 index 9bcb0c1b..00000000 --- a/packages/redux-devtools-core/src/app/store/configureStore.js +++ /dev/null @@ -1,41 +0,0 @@ -import { createStore, compose, applyMiddleware } from 'redux'; -import localForage from 'localforage'; -import { getStoredState, createPersistor } from 'redux-persist'; -import api from '../middlewares/api'; -import exportState from '../middlewares/exportState'; -import rootReducer from '../reducers'; - -export default function configureStore(callback, key) { - const persistConfig = { - keyPrefix: `redux-devtools${key || ''}:`, - blacklist: ['instances', 'socket'], - storage: localForage, - serialize: (data) => data, - deserialize: (data) => data, - }; - - getStoredState(persistConfig, (err, restoredState) => { - let composeEnhancers = compose; - if (process.env.NODE_ENV !== 'production') { - if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) { - composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; - } - if (module.hot) { - // Enable Webpack hot module replacement for reducers - module.hot.accept('../reducers', () => { - const nextReducer = require('../reducers'); // eslint-disable-line global-require - store.replaceReducer(nextReducer); - }); - } - } - - const store = createStore( - rootReducer, - restoredState, - composeEnhancers(applyMiddleware(exportState, api)) - ); - const persistor = createPersistor(store, persistConfig); - callback(store, restoredState); - if (err) persistor.purge(); - }); -} diff --git a/packages/redux-devtools-core/src/app/store/configureStore.ts b/packages/redux-devtools-core/src/app/store/configureStore.ts new file mode 100644 index 00000000..fc8be313 --- /dev/null +++ b/packages/redux-devtools-core/src/app/store/configureStore.ts @@ -0,0 +1,60 @@ +import { createStore, compose, applyMiddleware, Store } from 'redux'; +import localForage from 'localforage'; +import { + getStoredState, + createPersistor, + PersistorConfig, +} from 'redux-persist'; +import api from '../middlewares/api'; +import exportState from '../middlewares/exportState'; +import rootReducer, { StoreState } from '../reducers'; +import { StoreAction } from '../actions'; + +export default function configureStore( + callback: ( + store: Store, + restoredState: Partial | undefined + ) => void, + key?: string +) { + const persistConfig: PersistorConfig = ({ + keyPrefix: `redux-devtools${key || ''}:`, + blacklist: ['instances', 'socket'], + storage: localForage, + serialize: (data: unknown) => data, + deserialize: (data: unknown) => data, + } as unknown) as PersistorConfig; + + // eslint-disable-next-line @typescript-eslint/no-floating-promises + getStoredState(persistConfig, (err, restoredState) => { + let composeEnhancers = compose; + if (process.env.NODE_ENV !== 'production') { + if ( + ((window as unknown) as { + __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose; + }).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ) { + composeEnhancers = ((window as unknown) as { + __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: typeof compose; + }).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; + } + if (module.hot) { + // Enable Webpack hot module replacement for reducers + module.hot.accept('../reducers', () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const nextReducer = require('../reducers'); // eslint-disable-line global-require + store.replaceReducer(nextReducer); + }); + } + } + + const store = createStore( + rootReducer, + restoredState, + composeEnhancers(applyMiddleware(exportState, api)) + ); + const persistor = createPersistor(store, persistConfig); + callback(store, restoredState); + if (err) persistor.purge(); + }); +} diff --git a/packages/redux-devtools-core/src/app/utils/commitExcessActions.js b/packages/redux-devtools-core/src/app/utils/commitExcessActions.ts similarity index 89% rename from packages/redux-devtools-core/src/app/utils/commitExcessActions.js rename to packages/redux-devtools-core/src/app/utils/commitExcessActions.ts index 76b5c15f..ff7f8fdb 100644 --- a/packages/redux-devtools-core/src/app/utils/commitExcessActions.js +++ b/packages/redux-devtools-core/src/app/utils/commitExcessActions.ts @@ -1,7 +1,9 @@ // Based on https://github.com/gaearon/redux-devtools/pull/241 /* eslint-disable no-param-reassign */ -export default function commitExcessActions(liftedState, n = 1) { +import { State } from '../reducers/instances'; + +export default function commitExcessActions(liftedState: State, n = 1) { // Auto-commits n-number of excess actions. let excess = n; let idsToDelete = liftedState.stagedActionIds.slice(1, excess + 1); diff --git a/packages/redux-devtools-core/src/app/utils/getMonitor.js b/packages/redux-devtools-core/src/app/utils/getMonitor.tsx similarity index 90% rename from packages/redux-devtools-core/src/app/utils/getMonitor.js rename to packages/redux-devtools-core/src/app/utils/getMonitor.tsx index 32a9ea5c..55379e1d 100644 --- a/packages/redux-devtools-core/src/app/utils/getMonitor.js +++ b/packages/redux-devtools-core/src/app/utils/getMonitor.tsx @@ -9,7 +9,7 @@ export const monitors = [ { value: 'ChartMonitor', name: 'Chart' }, ]; -export default function getMonitor({ monitor }) { +export default function getMonitor({ monitor }: { monitor: string }) { switch (monitor) { case 'LogMonitor': return ( diff --git a/packages/redux-devtools-core/src/app/utils/monitorActions.js b/packages/redux-devtools-core/src/app/utils/monitorActions.ts similarity index 78% rename from packages/redux-devtools-core/src/app/utils/monitorActions.js rename to packages/redux-devtools-core/src/app/utils/monitorActions.ts index 4cc58517..1e5fc604 100644 --- a/packages/redux-devtools-core/src/app/utils/monitorActions.js +++ b/packages/redux-devtools-core/src/app/utils/monitorActions.ts @@ -2,8 +2,12 @@ import difference from 'lodash/difference'; import omit from 'lodash/omit'; import stringifyJSON from './stringifyJSON'; import { SET_STATE } from '../constants/actionTypes'; +import { InstancesState, State } from '../reducers/instances'; +import { Dispatch, MiddlewareAPI } from 'redux'; +import { DispatchAction, StoreAction } from '../actions'; +import { StoreState } from '../reducers'; -export function sweep(state) { +export function sweep(state: State): State { return { ...state, actionsById: omit(state.actionsById, state.skippedActionIds), @@ -17,12 +21,12 @@ export function sweep(state) { } export function nonReduxDispatch( - store, - message, - instanceId, - action, - initialState, - preInstances + store: MiddlewareAPI, StoreState>, + message: string, + instanceId: string, + action: DispatchAction, + initialState: string | undefined, + preInstances: InstancesState ) { const instances = preInstances || store.getState().instances; const state = instances.states[instanceId]; diff --git a/packages/redux-devtools-core/src/app/utils/parseJSON.js b/packages/redux-devtools-core/src/app/utils/parseJSON.ts similarity index 70% rename from packages/redux-devtools-core/src/app/utils/parseJSON.js rename to packages/redux-devtools-core/src/app/utils/parseJSON.ts index 63370feb..3288fc20 100644 --- a/packages/redux-devtools-core/src/app/utils/parseJSON.js +++ b/packages/redux-devtools-core/src/app/utils/parseJSON.ts @@ -1,17 +1,17 @@ import jsan from 'jsan'; import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes'; -export function reviver(key, value) { +export function reviver(key: string, value: unknown) { if ( typeof value === 'object' && value !== null && '__serializedType__' in value && - typeof value.data === 'object' + typeof (value as any).data === 'object' ) { - const data = value.data; - data[DATA_TYPE_KEY] = value.__serializedType__; + const data = (value as any).data; + data[DATA_TYPE_KEY] = (value as any).__serializedType__; if ('__serializedRef__' in value) - data[DATA_REF_KEY] = value.__serializedRef__; + data[DATA_REF_KEY] = (value as any).__serializedRef__; /* if (Array.isArray(data)) { data.__serializedType__ = value.__serializedType__; @@ -26,7 +26,10 @@ export function reviver(key, value) { return value; } -export default function parseJSON(data, serialize) { +export default function parseJSON( + data: string | undefined, + serialize?: boolean +) { if (typeof data !== 'string') return data; try { return serialize ? jsan.parse(data, reviver) : jsan.parse(data); diff --git a/packages/redux-devtools-core/src/app/utils/stringifyJSON.js b/packages/redux-devtools-core/src/app/utils/stringifyJSON.js deleted file mode 100644 index d3191612..00000000 --- a/packages/redux-devtools-core/src/app/utils/stringifyJSON.js +++ /dev/null @@ -1,20 +0,0 @@ -import jsan from 'jsan'; -import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes'; - -function replacer(key, value) { - if (typeof value === 'object' && value !== null && DATA_TYPE_KEY in value) { - const __serializedType__ = value[DATA_TYPE_KEY]; - const clone = { ...value }; - delete clone[DATA_TYPE_KEY]; // eslint-disable-line no-param-reassign - const r = { data: clone, __serializedType__ }; - if (DATA_REF_KEY in value) r.__serializedRef__ = clone[DATA_REF_KEY]; - return r; - } - return value; -} - -export default function stringifyJSON(data, serialize) { - return serialize - ? jsan.stringify(data, replacer, null, true) - : jsan.stringify(data); -} diff --git a/packages/redux-devtools-core/src/app/utils/stringifyJSON.ts b/packages/redux-devtools-core/src/app/utils/stringifyJSON.ts new file mode 100644 index 00000000..403e621e --- /dev/null +++ b/packages/redux-devtools-core/src/app/utils/stringifyJSON.ts @@ -0,0 +1,24 @@ +import jsan from 'jsan'; +import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes'; + +function replacer(key: string, value: unknown) { + if (typeof value === 'object' && value !== null && DATA_TYPE_KEY in value) { + const __serializedType__ = (value as any)[DATA_TYPE_KEY]; + const clone = { ...value }; + delete (clone as any)[DATA_TYPE_KEY]; // eslint-disable-line no-param-reassign + const r = { data: clone, __serializedType__ }; + if (DATA_REF_KEY in value) + (r as any).__serializedRef__ = (clone as any)[DATA_REF_KEY]; + return r; + } + return value; +} + +export default function stringifyJSON( + data: unknown, + serialize: boolean | undefined +) { + return serialize + ? jsan.stringify(data, replacer, (null as unknown) as undefined, true) + : jsan.stringify(data); +} diff --git a/packages/redux-devtools-core/src/app/utils/updateState.js b/packages/redux-devtools-core/src/app/utils/updateState.ts similarity index 66% rename from packages/redux-devtools-core/src/app/utils/updateState.js rename to packages/redux-devtools-core/src/app/utils/updateState.ts index 7157da99..eb2ba394 100644 --- a/packages/redux-devtools-core/src/app/utils/updateState.js +++ b/packages/redux-devtools-core/src/app/utils/updateState.ts @@ -1,12 +1,17 @@ import commitExcessActions from './commitExcessActions'; +import { State } from '../reducers/instances'; +import { Action } from 'redux'; +import { PerformAction } from 'redux-devtools-instrument'; export function recompute( - previousLiftedState, - storeState, - action, + previousLiftedState: State, + storeState: State, + action: + | PerformAction> + | { action: Action; timestamp?: number; stack?: string }, nextActionId = 1, - maxAge, - isExcess + maxAge?: number, + isExcess?: boolean ) { const actionId = nextActionId - 1; const liftedState = { ...previousLiftedState }; @@ -19,8 +24,10 @@ export function recompute( } liftedState.stagedActionIds = [...liftedState.stagedActionIds, actionId]; liftedState.actionsById = { ...liftedState.actionsById }; - if (action.type === 'PERFORM_ACTION') { - liftedState.actionsById[actionId] = action; + if ((action as PerformAction>).type === 'PERFORM_ACTION') { + liftedState.actionsById[actionId] = action as PerformAction< + Action + >; } else { liftedState.actionsById[actionId] = { action: action.action || action, diff --git a/packages/redux-devtools-core/src/index.js b/packages/redux-devtools-core/src/index.js deleted file mode 100644 index 29d541ff..00000000 --- a/packages/redux-devtools-core/src/index.js +++ /dev/null @@ -1,8 +0,0 @@ -function injectedScript() { - /* eslint-disable-next-line no-console */ - console.error( - "Not implemented yet. WIP. If you're looking for utils, import `redux-devtools-core/lib/utils`." - ); -} - -export default injectedScript; diff --git a/packages/redux-devtools-core/index.js b/packages/redux-devtools-core/src/index.tsx similarity index 94% rename from packages/redux-devtools-core/index.js rename to packages/redux-devtools-core/src/index.tsx index bd23dae6..c40f8b2a 100644 --- a/packages/redux-devtools-core/index.js +++ b/packages/redux-devtools-core/src/index.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { render } from 'react-dom'; -import App from './src/app'; +import App from './app'; render(, document.getElementById('root')); diff --git a/packages/redux-devtools-core/src/utils/catchErrors.js b/packages/redux-devtools-core/src/utils/catchErrors.js deleted file mode 100644 index b6d42219..00000000 --- a/packages/redux-devtools-core/src/utils/catchErrors.js +++ /dev/null @@ -1,42 +0,0 @@ -const ERROR = '@@redux-devtools/ERROR'; - -export default function catchErrors(sendError) { - if (typeof window === 'object' && typeof window.onerror === 'object') { - window.onerror = function (message, url, lineNo, columnNo, error) { - const errorAction = { type: ERROR, message, url, lineNo, columnNo }; - if (error && error.stack) errorAction.stack = error.stack; - sendError(errorAction); - return false; - }; - } else if (typeof global !== 'undefined' && global.ErrorUtils) { - global.ErrorUtils.setGlobalHandler((error, isFatal) => { - sendError({ type: ERROR, error, isFatal }); - }); - } - - /* eslint-disable no-console */ - if ( - typeof console === 'object' && - typeof console.error === 'function' && - !console.beforeRemotedev - ) { - console.beforeRemotedev = console.error.bind(console); - console.error = function () { - let errorAction = { type: ERROR }; - const error = arguments[0]; - errorAction.message = error.message ? error.message : error; - if (error.sourceURL) { - errorAction = { - ...errorAction, - sourceURL: error.sourceURL, - line: error.line, - column: error.column, - }; - } - if (error.stack) errorAction.stack = error.stack; - sendError(errorAction); - console.beforeRemotedev.apply(null, arguments); - }; - } - /* eslint-enable no-console */ -} diff --git a/packages/redux-devtools-core/src/utils/catchErrors.ts b/packages/redux-devtools-core/src/utils/catchErrors.ts new file mode 100644 index 00000000..a04d2148 --- /dev/null +++ b/packages/redux-devtools-core/src/utils/catchErrors.ts @@ -0,0 +1,68 @@ +const ERROR = '@@redux-devtools/ERROR'; + +interface ErrorAction { + type: typeof ERROR; + message?: Event | string; + url?: string | undefined; + lineNo?: number | undefined; + columnNo?: number | undefined; + stack?: string; + error?: Error; + isFatal?: boolean; + sourceURL?: string; + line?: number; + column?: number; +} + +export default function catchErrors( + sendError: (errorAction: ErrorAction) => void +) { + if (typeof window === 'object' && typeof window.onerror === 'object') { + window.onerror = function (message, url, lineNo, columnNo, error) { + const errorAction: ErrorAction = { + type: ERROR, + message, + url, + lineNo, + columnNo, + }; + if (error && error.stack) errorAction.stack = error.stack; + sendError(errorAction); + return false; + }; + } else if (typeof global !== 'undefined' && (global as any).ErrorUtils) { + (global as any).ErrorUtils.setGlobalHandler( + (error: Error, isFatal: boolean) => { + sendError({ type: ERROR, error, isFatal }); + } + ); + } + + /* eslint-disable no-console */ + if ( + typeof console === 'object' && + typeof console.error === 'function' && + !(console as any).beforeRemotedev + ) { + (console as any).beforeRemotedev = console.error.bind(console); + console.error = function () { + let errorAction: ErrorAction = { type: ERROR }; + // eslint-disable-next-line prefer-rest-params + const error = arguments[0]; + errorAction.message = error.message ? error.message : error; + if (error.sourceURL) { + errorAction = { + ...errorAction, + sourceURL: error.sourceURL, + line: error.line, + column: error.column, + }; + } + if (error.stack) errorAction.stack = error.stack; + sendError(errorAction); + // eslint-disable-next-line prefer-rest-params + (console as any).beforeRemotedev.apply(null, arguments); + }; + } + /* eslint-enable no-console */ +} diff --git a/packages/redux-devtools-core/src/utils/filters.js b/packages/redux-devtools-core/src/utils/filters.ts similarity index 55% rename from packages/redux-devtools-core/src/utils/filters.js rename to packages/redux-devtools-core/src/utils/filters.ts index d6607f6b..9c9644b1 100644 --- a/packages/redux-devtools-core/src/utils/filters.js +++ b/packages/redux-devtools-core/src/utils/filters.ts @@ -1,4 +1,7 @@ import mapValues from 'lodash/mapValues'; +import { PerformAction } from 'redux-devtools-instrument'; +import { Action } from 'redux'; +import { State } from '../app/reducers/instances'; export const FilterState = { DO_NOT_FILTER: 'DO_NOT_FILTER', @@ -6,19 +9,25 @@ export const FilterState = { WHITELIST_SPECIFIC: 'WHITELIST_SPECIFIC', }; -export function arrToRegex(v) { +export function arrToRegex(v: string | string[]) { return typeof v === 'string' ? v : v.join('|'); } -function filterActions(actionsById, actionsFilter) { +function filterActions( + actionsById: { [actionId: number]: PerformAction> }, + actionsFilter: (action: Action, id: number) => Action +) { if (!actionsFilter) return actionsById; - return mapValues(actionsById, (action, id) => ({ + return mapValues(actionsById, (action, id: number) => ({ ...action, action: actionsFilter(action.action, id), })); } -function filterStates(computedStates, statesFilter) { +function filterStates( + computedStates: { state: unknown; error?: string | undefined }[], + statesFilter: (state: unknown, actionId: number) => unknown +) { if (!statesFilter) return computedStates; return computedStates.map((state, idx) => ({ ...state, @@ -26,7 +35,17 @@ function filterStates(computedStates, statesFilter) { })); } -export function getLocalFilter(config) { +interface Config { + actionsBlacklist?: string[]; + actionsWhitelist?: string[]; +} + +interface LocalFilter { + whitelist?: string; + blacklist?: string; +} + +export function getLocalFilter(config: Config): LocalFilter | undefined { if (config.actionsBlacklist || config.actionsWhitelist) { return { whitelist: config.actionsWhitelist && config.actionsWhitelist.join('|'), @@ -36,33 +55,53 @@ export function getLocalFilter(config) { return undefined; } +interface DevToolsOptions { + filter?: + | typeof FilterState.DO_NOT_FILTER + | typeof FilterState.BLACKLIST_SPECIFIC + | typeof FilterState.WHITELIST_SPECIFIC; + whitelist?: string; + blacklist?: string; +} function getDevToolsOptions() { - return (typeof window !== 'undefined' && window.devToolsOptions) || {}; + return ( + (typeof window !== 'undefined' && + (window as { devToolsOptions?: DevToolsOptions }).devToolsOptions) || + {} + ); } -export function isFiltered(action, localFilter) { - const { type } = action.action || action; +export function isFiltered( + action: PerformAction> | Action, + localFilter?: LocalFilter +) { + const { type } = (action as PerformAction>).action || action; const opts = getDevToolsOptions(); if ( (!localFilter && opts.filter && opts.filter === FilterState.DO_NOT_FILTER) || - (type && typeof type.match !== 'function') + (type && typeof (type as string).match !== 'function') ) return false; const { whitelist, blacklist } = localFilter || opts; return ( - (whitelist && !type.match(whitelist)) || - (blacklist && type.match(blacklist)) + // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec + (whitelist && !(type as string).match(whitelist)) || + // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec + (blacklist && (type as string).match(blacklist)) ); } -export function filterStagedActions(state, filters) { +export function filterStagedActions(state: State, filters: LocalFilter) { if (!filters) return state; - const filteredStagedActionIds = []; - const filteredComputedStates = []; + const filteredStagedActionIds: number[] = []; + const filteredComputedStates: { + state: unknown; + error?: string | undefined; + }[] = []; state.stagedActionIds.forEach((id, idx) => { if (!isFiltered(state.actionsById[id], filters)) { @@ -79,13 +118,13 @@ export function filterStagedActions(state, filters) { } export function filterState( - state, - type, - localFilter, - stateSanitizer, - actionSanitizer, - nextActionId, - predicate + state: State, + type: string, + localFilter: LocalFilter, + stateSanitizer: (state: unknown, actionId: number) => unknown, + actionSanitizer: (action: Action, id: number) => Action, + nextActionId: number, + predicate: (currState: unknown, currAction: Action) => boolean ) { if (type === 'ACTION') return !stateSanitizer ? state : stateSanitizer(state, nextActionId - 1); @@ -97,9 +136,14 @@ export function filterState( localFilter || (filter && filter !== FilterState.DO_NOT_FILTER) ) { - const filteredStagedActionIds = []; - const filteredComputedStates = []; - const sanitizedActionsById = actionSanitizer && {}; + const filteredStagedActionIds: number[] = []; + const filteredComputedStates: { + state: unknown; + error?: string | undefined; + }[] = []; + const sanitizedActionsById: { + [id: number]: PerformAction>; + } = actionSanitizer && {}; const { actionsById } = state; const { computedStates } = state; diff --git a/packages/redux-devtools-core/src/utils/get-params.ts b/packages/redux-devtools-core/src/utils/get-params.ts new file mode 100644 index 00000000..417ec500 --- /dev/null +++ b/packages/redux-devtools-core/src/utils/get-params.ts @@ -0,0 +1,4 @@ +declare module 'get-params' { + function getParams(func: (...args: any[]) => unknown): string[]; + export default getParams; +} diff --git a/packages/redux-devtools-core/src/utils/importState.js b/packages/redux-devtools-core/src/utils/importState.js deleted file mode 100644 index 11cf3222..00000000 --- a/packages/redux-devtools-core/src/utils/importState.js +++ /dev/null @@ -1,69 +0,0 @@ -import mapValues from 'lodash/mapValues'; -import jsan from 'jsan'; -import seralizeImmutable from 'remotedev-serialize/immutable/serialize'; - -function deprecate(param) { - // eslint-disable-next-line no-console - console.warn( - `\`${param}\` parameter for Redux DevTools Extension is deprecated. Use \`serialize\` parameter instead:` + - ' https://github.com/zalmoxisus/redux-devtools-extension/releases/tag/v2.12.1' - ); -} - -export default function importState( - state, - { deserializeState, deserializeAction, serialize } -) { - if (!state) return undefined; - let parse = jsan.parse; - if (serialize) { - if (serialize.immutable) { - parse = (v) => - jsan.parse( - v, - seralizeImmutable(serialize.immutable, serialize.refs).reviver - ); - } else if (serialize.reviver) { - parse = (v) => jsan.parse(v, serialize.reviver); - } - } - - let preloadedState; - let nextLiftedState = parse(state); - if (nextLiftedState.payload) { - if (nextLiftedState.preloadedState) - preloadedState = parse(nextLiftedState.preloadedState); - nextLiftedState = parse(nextLiftedState.payload); - } - if (deserializeState) { - deprecate('deserializeState'); - if (typeof nextLiftedState.computedStates !== 'undefined') { - nextLiftedState.computedStates = nextLiftedState.computedStates.map( - (computedState) => ({ - ...computedState, - state: deserializeState(computedState.state), - }) - ); - } - if (typeof nextLiftedState.committedState !== 'undefined') { - nextLiftedState.committedState = deserializeState( - nextLiftedState.committedState - ); - } - if (typeof preloadedState !== 'undefined') { - preloadedState = deserializeState(preloadedState); - } - } - if (deserializeAction) { - deprecate('deserializeAction'); - nextLiftedState.actionsById = mapValues( - nextLiftedState.actionsById, - (liftedAction) => ({ - ...liftedAction, - action: deserializeAction(liftedAction.action), - }) - ); - } - - return { nextLiftedState, preloadedState }; -} diff --git a/packages/redux-devtools-core/src/utils/importState.ts b/packages/redux-devtools-core/src/utils/importState.ts new file mode 100644 index 00000000..1afe997f --- /dev/null +++ b/packages/redux-devtools-core/src/utils/importState.ts @@ -0,0 +1,105 @@ +import mapValues from 'lodash/mapValues'; +import jsan from 'jsan'; +import { immutableSerialize } from 'redux-devtools-serialize'; +import { Action } from 'redux'; +import Immutable from 'immutable'; +import { State } from '../app/reducers/instances'; + +function deprecate(param: string) { + // eslint-disable-next-line no-console + console.warn( + `\`${param}\` parameter for Redux DevTools Extension is deprecated. Use \`serialize\` parameter instead:` + + ' https://github.com/zalmoxisus/redux-devtools-extension/releases/tag/v2.12.1' + ); +} + +export default function importState( + state: string, + { + deserializeState, + deserializeAction, + serialize, + }: { + deserializeState?: (state: string) => unknown; + deserializeAction?: (action: string) => Action; + serialize?: { + immutable?: typeof Immutable; + refs?: (new (data: any) => unknown)[] | null; + reviver?: (key: string, value: unknown) => unknown; + }; + } +) { + if (!state) return undefined; + let parse = jsan.parse; + if (serialize) { + if (serialize.immutable) { + parse = (v) => + jsan.parse( + v, + immutableSerialize(serialize.immutable!, serialize.refs).reviver + ); + } else if (serialize.reviver) { + parse = (v) => jsan.parse(v, serialize.reviver); + } + } + + let preloadedState: State | undefined; + let nextLiftedState: State = parse(state) as State; + if ( + ((nextLiftedState as unknown) as { + payload?: string; + preloadedState?: string; + }).payload + ) { + if ( + ((nextLiftedState as unknown) as { + payload: string; + preloadedState?: string; + }).preloadedState + ) + preloadedState = parse( + ((nextLiftedState as unknown) as { + payload: string; + preloadedState: string; + }).preloadedState + ) as State; + nextLiftedState = parse( + ((nextLiftedState as unknown) as { + payload: string; + }).payload + ) as State; + } + if (deserializeState) { + deprecate('deserializeState'); + if (typeof nextLiftedState.computedStates !== 'undefined') { + nextLiftedState.computedStates = nextLiftedState.computedStates.map( + (computedState) => ({ + ...computedState, + state: deserializeState(computedState.state as string), + }) + ); + } + if (typeof nextLiftedState.committedState !== 'undefined') { + nextLiftedState.committedState = deserializeState( + nextLiftedState.committedState as string + ); + } + if (typeof preloadedState !== 'undefined') { + preloadedState = deserializeState( + (preloadedState as unknown) as string + ) as State; + } + } + if (deserializeAction) { + deprecate('deserializeAction'); + nextLiftedState.actionsById = mapValues( + nextLiftedState.actionsById, + (liftedAction) => ({ + ...liftedAction, + action: deserializeAction((liftedAction.action as unknown) as string), + }) + ); + } + + return { nextLiftedState, preloadedState }; +} diff --git a/packages/redux-devtools-core/src/utils/index.js b/packages/redux-devtools-core/src/utils/index.ts similarity index 55% rename from packages/redux-devtools-core/src/utils/index.js rename to packages/redux-devtools-core/src/utils/index.ts index 45bd643c..c343b293 100644 --- a/packages/redux-devtools-core/src/utils/index.js +++ b/packages/redux-devtools-core/src/utils/index.ts @@ -1,14 +1,24 @@ import getParams from 'get-params'; import jsan from 'jsan'; import { nanoid } from 'nanoid/non-secure'; -import seralizeImmutable from 'remotedev-serialize/immutable/serialize'; +import { immutableSerialize } from 'redux-devtools-serialize'; +import Immutable from 'immutable'; +import { Action } from 'redux'; -export function generateId(id) { +export function generateId(id: string | undefined) { return id || nanoid(7); } -function flatTree(obj, namespace = '') { - let functions = []; +// eslint-disable-next-line @typescript-eslint/ban-types +function flatTree( + obj: { [key: string]: (...args: any[]) => unknown }, + namespace = '' +) { + let functions: { + name: string; + func: (...args: any[]) => unknown; + args: string[]; + }[] = []; Object.keys(obj).forEach((key) => { const prop = obj[key]; if (typeof prop === 'function') { @@ -24,18 +34,23 @@ function flatTree(obj, namespace = '') { return functions; } -export function getMethods(obj) { +export function getMethods(obj: unknown) { if (typeof obj !== 'object') return undefined; - let functions; - let m; - if (obj.__proto__) m = obj.__proto__.__proto__; - if (!m) m = obj; + let functions: + | { + name: string; + args: string[]; + }[] + | undefined; + let m: { [key: string]: (...args: any[]) => unknown } | undefined; + if ((obj as any).__proto__) m = (obj as any).__proto__.__proto__; + if (!m) m = obj as any; Object.getOwnPropertyNames(m).forEach((key) => { const propDescriptor = Object.getOwnPropertyDescriptor(m, key); if (!propDescriptor || 'get' in propDescriptor || 'set' in propDescriptor) return; - const prop = m[key]; + const prop = m![key]; if (typeof prop === 'function' && key !== 'constructor') { if (!functions) functions = []; functions.push({ @@ -47,15 +62,17 @@ export function getMethods(obj) { return functions; } -export function getActionsArray(actionCreators) { +export function getActionsArray(actionCreators: { + [key: string]: (...args: any[]) => unknown; +}) { if (Array.isArray(actionCreators)) return actionCreators; return flatTree(actionCreators); } -/* eslint-disable no-new-func */ -const interpretArg = (arg) => new Function('return ' + arg)(); +// eslint-disable-next-line @typescript-eslint/no-implied-eval +const interpretArg = (arg: string) => new Function('return ' + arg)(); -function evalArgs(inArgs, restArgs) { +function evalArgs(inArgs: string[], restArgs: string) { const args = inArgs.map(interpretArg); if (!restArgs) return args; const rest = interpretArg(restArgs); @@ -63,8 +80,14 @@ function evalArgs(inArgs, restArgs) { throw new Error('rest must be an array'); } -export function evalAction(action, actionCreators) { +export function evalAction( + action: string | { args: string[]; rest: string; selected: string }, + actionCreators: { + [selected: string]: { func: (...args: any[]) => Action }; + } +) { if (typeof action === 'string') { + // eslint-disable-next-line @typescript-eslint/no-implied-eval return new Function('return ' + action)(); } @@ -73,12 +96,17 @@ export function evalAction(action, actionCreators) { return actionCreator(...args); } -export function evalMethod(action, obj) { +export function evalMethod( + action: string | { args: string[]; rest: string; name: string }, + obj: unknown +) { if (typeof action === 'string') { + // eslint-disable-next-line @typescript-eslint/no-implied-eval return new Function('return ' + action).call(obj); } const args = evalArgs(action.args, action.rest); + // eslint-disable-next-line @typescript-eslint/no-implied-eval return new Function('args', `return this.${action.name}(args)`).apply( obj, args @@ -86,7 +114,7 @@ export function evalMethod(action, obj) { } /* eslint-enable */ -function tryCatchStringify(obj) { +function tryCatchStringify(obj: unknown) { try { return JSON.stringify(obj); } catch (err) { @@ -94,11 +122,26 @@ function tryCatchStringify(obj) { if (process.env.NODE_ENV !== 'production') console.log('Failed to stringify', err); /* eslint-enable no-console */ - return jsan.stringify(obj, null, null, { circular: '[CIRCULAR]' }); + return jsan.stringify( + obj, + (null as unknown) as undefined, + (null as unknown) as undefined, + ({ + circular: '[CIRCULAR]', + } as unknown) as boolean + ); } } -export function stringify(obj, serialize) { +export function stringify( + obj: unknown, + serialize?: + | { + replacer?: (key: string, value: unknown) => unknown; + options?: unknown | boolean; + } + | true +) { if (typeof serialize === 'undefined') { return tryCatchStringify(obj); } @@ -106,23 +149,44 @@ export function stringify(obj, serialize) { return jsan.stringify( obj, function (key, value) { - if (value && typeof value.toJS === 'function') return value.toJS(); + if (value && typeof (value as any).toJS === 'function') + return (value as any).toJS(); return value; }, - null, + (null as unknown) as undefined, true ); } - return jsan.stringify(obj, serialize.replacer, null, serialize.options); + return jsan.stringify( + obj, + serialize.replacer, + (null as unknown) as undefined, + serialize.options as boolean + ); } -export function getSeralizeParameter(config, param) { +export function getSeralizeParameter( + config: { + serialize?: { + immutable?: typeof Immutable; + refs?: (new (data: any) => unknown)[] | null; + replacer?: (key: string, value: unknown) => unknown; + options?: unknown | boolean; + }; + }, + param: string +): + | { + replacer?: (key: string, value: unknown) => unknown; + options: unknown | boolean; + } + | undefined { const serialize = config.serialize; if (serialize) { if (serialize === true) return { options: true }; if (serialize.immutable) { return { - replacer: seralizeImmutable(serialize.immutable, serialize.refs) + replacer: immutableSerialize(serialize.immutable, serialize.refs) .replacer, options: serialize.options || true, }; @@ -131,7 +195,12 @@ export function getSeralizeParameter(config, param) { return { replacer: serialize.replacer, options: serialize.options || true }; } - const value = config[param]; + const value = (config as { + [param: string]: { + replacer?: (key: string, value: unknown) => unknown; + options: unknown | boolean; + }; + })[param]; if (typeof value === 'undefined') return undefined; // eslint-disable-next-line no-console console.warn( @@ -139,12 +208,15 @@ export function getSeralizeParameter(config, param) { ' https://github.com/zalmoxisus/redux-devtools-extension/releases/tag/v2.12.1' ); - if (typeof serializeState === 'boolean') return { options: value }; - if (typeof serializeState === 'function') return { replacer: value }; return value; } -export function getStackTrace(config, toExcludeFromTrace) { +export function getStackTrace( + // eslint-disable-next-line @typescript-eslint/ban-types + config: { trace?: () => {}; traceLimit: number }, + // eslint-disable-next-line @typescript-eslint/ban-types + toExcludeFromTrace?: Function | undefined +) { if (!config.trace) return undefined; if (typeof config.trace === 'function') return config.trace(); @@ -169,7 +241,7 @@ export function getStackTrace(config, toExcludeFromTrace) { typeof Error.stackTraceLimit !== 'number' || Error.stackTraceLimit > traceLimit ) { - const frames = stack.split('\n'); + const frames = stack!.split('\n'); if (frames.length > traceLimit) { stack = frames .slice(0, traceLimit + extraFrames + (frames[0] === 'Error' ? 1 : 0)) diff --git a/packages/redux-devtools-core/test/__mocks__/styleMock.js b/packages/redux-devtools-core/test/__mocks__/styleMock.js deleted file mode 100644 index f053ebf7..00000000 --- a/packages/redux-devtools-core/test/__mocks__/styleMock.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; diff --git a/packages/redux-devtools-core/test/app.spec.js b/packages/redux-devtools-core/test/app.spec.tsx similarity index 92% rename from packages/redux-devtools-core/test/app.spec.js rename to packages/redux-devtools-core/test/app.spec.tsx index 71b42159..d7ce85ee 100644 --- a/packages/redux-devtools-core/test/app.spec.js +++ b/packages/redux-devtools-core/test/app.spec.tsx @@ -1,7 +1,7 @@ -import React from 'react'; +import React, { Component } from 'react'; import { Provider } from 'react-redux'; import { createStore, applyMiddleware } from 'redux'; -import { mount } from 'enzyme'; +import { mount, ReactWrapper } from 'enzyme'; // import { mountToJson } from 'enzyme-to-json'; import App from '../src/app/containers/App'; import api from '../src/app/middlewares/api'; @@ -10,7 +10,7 @@ import rootReducer from '../src/app/reducers'; import { DATA_TYPE_KEY } from '../src/app/constants/dataTypes'; import stringifyJSON from '../src/app/utils/stringifyJSON'; -let wrapper; +let wrapper: ReactWrapper; const store = createStore(rootReducer, applyMiddleware(exportState, api)); diff --git a/packages/redux-devtools-core/test/setup.js b/packages/redux-devtools-core/test/setup.ts similarity index 100% rename from packages/redux-devtools-core/test/setup.js rename to packages/redux-devtools-core/test/setup.ts diff --git a/packages/redux-devtools-core/test/tsconfig.json b/packages/redux-devtools-core/test/tsconfig.json new file mode 100644 index 00000000..ca19def4 --- /dev/null +++ b/packages/redux-devtools-core/test/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../../tsconfig.react.base.json", + "include": ["../src", "."] +} diff --git a/packages/redux-devtools-core/tsconfig.json b/packages/redux-devtools-core/tsconfig.json new file mode 100644 index 00000000..7b7d1492 --- /dev/null +++ b/packages/redux-devtools-core/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.react.base.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["src"] +} diff --git a/packages/redux-devtools-core/tsconfig.webpack.json b/packages/redux-devtools-core/tsconfig.webpack.json new file mode 100644 index 00000000..6ab34185 --- /dev/null +++ b/packages/redux-devtools-core/tsconfig.webpack.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["webpack.config.ts", "webpack.config.umd.ts"] +} diff --git a/packages/redux-devtools-core/webpack.config.js b/packages/redux-devtools-core/webpack.config.ts similarity index 72% rename from packages/redux-devtools-core/webpack.config.js rename to packages/redux-devtools-core/webpack.config.ts index ed75e5f7..75d1c5ef 100644 --- a/packages/redux-devtools-core/webpack.config.js +++ b/packages/redux-devtools-core/webpack.config.ts @@ -1,14 +1,15 @@ -const path = require('path'); -const webpack = require('webpack'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); +import * as path from 'path'; +import * as webpack from 'webpack'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; -module.exports = (env = {}) => ({ +module.exports = (env: { development?: boolean; platform?: string } = {}) => ({ mode: env.development ? 'development' : 'production', entry: { - app: './index.js', + app: './src/index', }, output: { - path: path.resolve(__dirname, 'build/' + env.platform), + path: path.resolve(__dirname, `build/${env.platform as string}`), publicPath: '', filename: 'js/[name].js', sourceMapFilename: 'js/[name].map', @@ -16,7 +17,7 @@ module.exports = (env = {}) => ({ module: { rules: [ { - test: /\.js$/, + test: /\.(js|ts)x?$/, loader: 'babel-loader', exclude: /node_modules/, }, @@ -44,6 +45,9 @@ module.exports = (env = {}) => ({ }, ], }, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, plugins: [ new webpack.DefinePlugin({ 'process.env': { @@ -56,6 +60,11 @@ module.exports = (env = {}) => ({ new HtmlWebpackPlugin({ template: 'assets/index.html', }), + new ForkTsCheckerWebpackPlugin({ + typescript: { + configFile: 'tsconfig.json', + }, + }), ], optimization: { minimize: false, diff --git a/packages/redux-devtools-core/webpack.config.umd.js b/packages/redux-devtools-core/webpack.config.umd.ts similarity index 74% rename from packages/redux-devtools-core/webpack.config.umd.js rename to packages/redux-devtools-core/webpack.config.umd.ts index 8e31df45..99abaf62 100644 --- a/packages/redux-devtools-core/webpack.config.umd.js +++ b/packages/redux-devtools-core/webpack.config.umd.ts @@ -1,10 +1,11 @@ -const path = require('path'); -const webpack = require('webpack'); +import * as path from 'path'; +import * as webpack from 'webpack'; +import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; -module.exports = (env = {}) => ({ +module.exports = (env: { production?: boolean } = {}) => ({ mode: env.production ? 'production' : 'development', entry: { - app: ['./src/app/index.js'], + app: ['./src/app/index'], }, output: { library: 'ReduxDevTools', @@ -18,7 +19,7 @@ module.exports = (env = {}) => ({ module: { rules: [ { - test: /\.js$/, + test: /\.(js|ts)x?$/, loader: 'babel-loader', exclude: /node_modules/, }, @@ -41,6 +42,9 @@ module.exports = (env = {}) => ({ }, ], }, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, plugins: [ new webpack.DefinePlugin({ 'process.env': { @@ -48,6 +52,11 @@ module.exports = (env = {}) => ({ PLATFORM: JSON.stringify('web'), }, }), + new ForkTsCheckerWebpackPlugin({ + typescript: { + configFile: 'tsconfig.json', + }, + }), ], externals: { react: { diff --git a/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx b/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx index 37c7d887..71b3f0c2 100644 --- a/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx +++ b/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx @@ -25,7 +25,7 @@ export interface TabComponentProps> { base16Theme: Base16Theme; invertTheme: boolean; isWideLayout: boolean; - dataTypeKey: string | undefined; + dataTypeKey: string | symbol | undefined; delta: Delta | null | undefined | false; action: A; nextState: S; @@ -67,7 +67,7 @@ interface Props> { actions: { [actionId: number]: PerformAction }; selectedActionId: number | null; startActionId: number | null; - dataTypeKey: string | undefined; + dataTypeKey: string | symbol | undefined; monitorState: DevtoolsInspectorState; updateMonitorState: (monitorState: Partial) => void; styling: StylingFunction; diff --git a/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx b/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx index 5800feab..a5714b20 100644 --- a/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx +++ b/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx @@ -128,7 +128,7 @@ function createThemeState>( return { base16Theme, styling }; } -interface ExternalProps> { +export interface ExternalProps> { dispatch: Dispatch< DevtoolsInspectorAction | LiftedAction >; @@ -142,7 +142,7 @@ interface ExternalProps> { hideMainButtons?: boolean; hideActionButtons?: boolean; invertTheme: boolean; - dataTypeKey?: string; + dataTypeKey?: string | symbol; tabs: Tab[] | ((tabs: Tab[]) => Tab[]); } @@ -169,7 +169,7 @@ export interface DevtoolsInspectorProps> hideMainButtons?: boolean; hideActionButtons?: boolean; invertTheme: boolean; - dataTypeKey?: string; + dataTypeKey?: string | symbol; tabs: Tab[] | ((tabs: Tab[]) => Tab[]); } diff --git a/packages/redux-devtools-inspector-monitor/src/redux.ts b/packages/redux-devtools-inspector-monitor/src/redux.ts index e7f14c87..93b2835d 100644 --- a/packages/redux-devtools-inspector-monitor/src/redux.ts +++ b/packages/redux-devtools-inspector-monitor/src/redux.ts @@ -4,7 +4,7 @@ import { DevtoolsInspectorProps } from './DevtoolsInspector'; const UPDATE_MONITOR_STATE = '@@redux-devtools-inspector-monitor/UPDATE_MONITOR_STATE'; -interface UpdateMonitorStateAction { +export interface UpdateMonitorStateAction { type: typeof UPDATE_MONITOR_STATE; monitorState: Partial; } diff --git a/packages/redux-devtools-inspector-monitor/src/tabs/JSONDiff.tsx b/packages/redux-devtools-inspector-monitor/src/tabs/JSONDiff.tsx index efcd8038..74213aaa 100644 --- a/packages/redux-devtools-inspector-monitor/src/tabs/JSONDiff.tsx +++ b/packages/redux-devtools-inspector-monitor/src/tabs/JSONDiff.tsx @@ -60,7 +60,7 @@ interface Props { expandable: boolean ) => React.ReactNode; isWideLayout: boolean; - dataTypeKey: string | undefined; + dataTypeKey: string | symbol | undefined; } interface State { diff --git a/packages/redux-devtools-inspector-monitor/src/tabs/getItemString.tsx b/packages/redux-devtools-inspector-monitor/src/tabs/getItemString.tsx index 85eb261a..515643ea 100644 --- a/packages/redux-devtools-inspector-monitor/src/tabs/getItemString.tsx +++ b/packages/redux-devtools-inspector-monitor/src/tabs/getItemString.tsx @@ -73,7 +73,7 @@ const getItemString = ( styling: StylingFunction, type: string, data: any, - dataTypeKey: string | undefined, + dataTypeKey: string | symbol | undefined, isWideLayout: boolean, isDiff?: boolean ) => ( diff --git a/packages/redux-devtools-serialize/src/immutable/index.ts b/packages/redux-devtools-serialize/src/immutable/index.ts index b8fd874b..08382573 100644 --- a/packages/redux-devtools-serialize/src/immutable/index.ts +++ b/packages/redux-devtools-serialize/src/immutable/index.ts @@ -35,3 +35,4 @@ export default function ( serialize: serialize, }; } +export { default as serialize } from './serialize'; diff --git a/packages/redux-devtools-serialize/src/index.ts b/packages/redux-devtools-serialize/src/index.ts index 600d22c0..c2f42ae8 100644 --- a/packages/redux-devtools-serialize/src/index.ts +++ b/packages/redux-devtools-serialize/src/index.ts @@ -1,5 +1,4 @@ -import immutable from './immutable'; - -module.exports = { - immutable: immutable, -}; +export { + default as immutable, + serialize as immutableSerialize, +} from './immutable'; diff --git a/yarn.lock b/yarn.lock index daf18650..80e9176d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3361,6 +3361,11 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/async@*": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.3.tgz#c56f5e0fc02f8b37196f79239cc857e789b97bb4" + integrity sha512-deXFjLZc1h6SOh3hicVgD+S2EAkhSBGX/vdlD4nTzCjjOFQ+bfNiXocQ21xJjFAUwqaCeyvOQMgrnbg4QEV63A== + "@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" @@ -3463,6 +3468,11 @@ dependencies: "@types/color-convert" "*" +"@types/component-emitter@*": + version "1.2.10" + resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.10.tgz#ef5b1589b9f16544642e473db5ea5639107ef3ea" + integrity sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg== + "@types/connect-history-api-fallback@*": version "1.3.3" resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.3.tgz#4772b79b8b53185f0f4c9deab09236baf76ee3b4" @@ -3545,6 +3555,11 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g== +"@types/expirymanager@*": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@types/expirymanager/-/expirymanager-0.9.0.tgz#b2ca7610e517924e26b27221603cbe5f92c0e8fc" + integrity sha512-xulG8b5SiBhpRE1Arfx3ji428mfhwQdas6/i+1IJhTLkyFifJ4rF+vve522ds2ZTiBKCUv9WHNuVF/V9PJCa2Q== + "@types/express-serve-static-core@*", "@types/express-serve-static-core@4.17.9": version "4.17.9" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz#2d7b34dcfd25ec663c25c85d76608f8b249667f1" @@ -3576,6 +3591,11 @@ resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3" integrity sha1-wFTor02d11205jq8dviFFocU1LM= +"@types/fleximap@*": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@types/fleximap/-/fleximap-0.9.0.tgz#8f084b26bf7284800ee82d960df97324888f555d" + integrity sha512-7VsHgMM7l3jY+MXptDgzvROcEoikVgIxu+8d/qT0WijDl6RXdwAbAQYxu5sBCwUvlf0cEQwiDC4rOvkcm3h+hw== + "@types/fs-capacitor@*": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz#17113e25817f584f58100fb7a08eed288b81956e" @@ -3734,6 +3754,18 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== +"@types/json-schema@^7.0.6": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" + integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== + +"@types/jsonwebtoken@*": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz#2531d5e300803aa63279b232c014acf780c981c5" + integrity sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg== + dependencies: + "@types/node" "*" + "@types/keygrip@*": version "1.0.2" resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" @@ -3827,6 +3859,13 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= +"@types/ncom@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/ncom/-/ncom-1.0.0.tgz#8e33d06fc4914c941ba40ceca042081b947ba699" + integrity sha512-9fmYuP/lvEVfzY+5nZ61ewM/ub9mDINn88BBflTyHX6D7wH5b8oFR3GXrmYjelx79shuogHhHMOtXODDBatVPQ== + dependencies: + "@types/node" "*" + "@types/node-fetch@2.5.7", "@types/node-fetch@^2.5.4": version "2.5.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" @@ -4036,6 +4075,47 @@ dependencies: redux "^4.0.0" +"@types/sc-auth@*": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/sc-auth/-/sc-auth-5.0.0.tgz#b9bca82783419233ed938f59e37ae940bfdb454a" + integrity sha512-V+wuOweEJDrVCMduXmS7zc60O6HGyd5Xm3ClzEXKJfQdrSuhoqvhDjOwbtRZAXCjHll12lBXECb2sht5Glp/6A== + dependencies: + "@types/jsonwebtoken" "*" + +"@types/sc-broker-cluster@^6": + version "6.1.3" + resolved "https://registry.yarnpkg.com/@types/sc-broker-cluster/-/sc-broker-cluster-6.1.3.tgz#b6b0c3cedb635b1ee5098ebd1453e121c6a3d2cc" + integrity sha512-ttxBDnqq+Kcd3lMRQKW471sbv8KBXhJNaKHfFGrRRjWnSpSMa/zhhyAf/ew7/r8S7ZKuR4MFYmKYOwMXv5mm3g== + dependencies: + "@types/async" "*" + "@types/expirymanager" "*" + "@types/fleximap" "*" + "@types/sc-broker" "*" + "@types/sc-channel" "^1" + "@types/socketcluster" "*" + "@types/socketcluster-server" "^14" + +"@types/sc-broker@*": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@types/sc-broker/-/sc-broker-8.0.1.tgz#7dcf741386ab08ca9ca39ea6eb9af7fbb77faff2" + integrity sha512-JacbIkcjKs3PIMyw8yuM3rrJf2kw39GMoT83tNyJfvhF0DBLU26OBsO4kxmi82SdnVUubeiSN4/whC4lhOpAYg== + dependencies: + "@types/expirymanager" "*" + "@types/fleximap" "*" + "@types/ncom" "*" + +"@types/sc-channel@^1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@types/sc-channel/-/sc-channel-1.2.1.tgz#82e7f50155699b751a7150b679960ca363bfa0b1" + integrity sha512-RYT2V1XlViii3CmPqlZQfv3ADaCzxGPhZfk6MWPfnv3z1dR9wCE/c9lehLtuCz0TYPJYPV48PoocvIdaPAMsUA== + dependencies: + "@types/component-emitter" "*" + +"@types/sc-errors@*": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@types/sc-errors/-/sc-errors-1.4.0.tgz#dba1309b695ee8aafc3f574dfedfe4f3c5153419" + integrity sha512-WfBEiw/SVja1ZvJRdt37dOJFxp2llV35n9cPiDCDsFRSvTTYlO4iMFg+NyeEhiWBk1O4bvmyYpAEYzJx1DbHHQ== + "@types/serve-static@*": version "1.13.5" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53" @@ -4054,6 +4134,38 @@ resolved "https://registry.yarnpkg.com/@types/simple-element-resize-detector/-/simple-element-resize-detector-1.3.0.tgz#19b40d71fefa1876ac5d4ba585197ef438946353" integrity sha512-z89ForrCNg+4uwTHjwBCM9LjcsXYC/4O8u3tSi+82v2LCbfiYFpkjH/qQVkDewFBK6FUG7RRV7jw78EGs2maoQ== +"@types/socketcluster-client@^13.0.3": + version "13.0.4" + resolved "https://registry.yarnpkg.com/@types/socketcluster-client/-/socketcluster-client-13.0.4.tgz#945593f0a67d09d51b8fb39ea1f750fb6c19aea1" + integrity sha512-kJcm1V+iu09O7+zHY+zkdokNsvu2D965yqs8NhswgWxWU9ctk5f3IcbqMWnNqIe28aEFhvseJrlNM+NCjAEIwQ== + dependencies: + "@types/component-emitter" "*" + "@types/sc-auth" "*" + "@types/sc-channel" "^1" + "@types/sc-errors" "*" + "@types/socketcluster-server" "^14" + "@types/ws" "*" + +"@types/socketcluster-server@^14": + version "14.2.5" + resolved "https://registry.yarnpkg.com/@types/socketcluster-server/-/socketcluster-server-14.2.5.tgz#ed323b27e29de8a68dee851096d5fe2d164a8fd1" + integrity sha512-mDdLtv8R43mh6K4w/HmHEkZZMlCKN/B1Cm/seh6NSPBtVxbHhH0hN0KV4em4eY+2+S7FoNi9sFYINDPitOaBwA== + dependencies: + "@types/component-emitter" "*" + "@types/jsonwebtoken" "*" + "@types/sc-auth" "*" + "@types/sc-broker-cluster" "^6" + "@types/ws" "*" + +"@types/socketcluster@*": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@types/socketcluster/-/socketcluster-14.0.3.tgz#62a89c3c08c2ee0fca5c265263e3a15fb544dd83" + integrity sha512-E+myXJK1zKtqydI+qWUxthvi4Z76+Ovzz5ijIa/yR8hfOvk1K7VhsbyNrnrk8KWLtJFpostisbPp8eLBAQrnkA== + dependencies: + "@types/sc-auth" "*" + "@types/sc-broker-cluster" "^6" + "@types/socketcluster-server" "^14" + "@types/source-list-map@*": version "0.1.2" resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" @@ -4140,7 +4252,7 @@ "@types/webpack-sources" "*" source-map "^0.6.0" -"@types/ws@^7.0.0": +"@types/ws@*", "@types/ws@^7.0.0": version "7.2.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.2.7.tgz#362ad1a1d62721bdb725e72c8cccf357078cf5a3" integrity sha512-UUFC/xxqFLP17hTva8/lVT0SybLUrfSD9c+iapKb0fEiC8uoDbA+xuZ3pAN603eW+bY8ebSMLm9jXdIPnD0ZgA== From c91471a41da39fa1ee366cfade9d088906b2723a Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Mon, 26 Oct 2020 01:57:34 -0400 Subject: [PATCH 09/25] chore(cli): convert to TypeScript (#656) * chore(cli): convert to TypeScript * Fix knex usage * Fix eslintrc * Ignore dist --- packages/redux-devtools-cli/.eslintignore | 2 + packages/redux-devtools-cli/.eslintrc.js | 21 ++ .../redux-devtools-cli/bin/injectServer.js | 95 ------- .../redux-devtools-cli/bin/redux-devtools.js | 93 +------ packages/redux-devtools-cli/jest.config.js | 3 + packages/redux-devtools-cli/package.json | 46 ++-- packages/redux-devtools-cli/src/api/schema.js | 21 -- packages/redux-devtools-cli/src/api/schema.ts | 33 +++ .../src/bin/injectServer.ts | 104 ++++++++ .../{bin/openApp.js => src/bin/openApp.ts} | 19 +- .../src/bin/redux-devtools.ts | 97 +++++++ .../src/db/{connector.js => connector.ts} | 17 +- .../src/db/migrations/{index.js => index.ts} | 10 +- .../src/db/seeds/{index.js => index.ts} | 6 +- packages/redux-devtools-cli/src/getport.ts | 6 + .../{index.js => src/index.ts} | 40 +-- .../src/middleware/{graphql.js => graphql.ts} | 9 +- packages/redux-devtools-cli/src/options.js | 33 --- packages/redux-devtools-cli/src/options.ts | 63 +++++ .../src/{routes.js => routes.ts} | 41 +-- packages/redux-devtools-cli/src/store.js | 106 -------- packages/redux-devtools-cli/src/store.ts | 164 ++++++++++++ .../src/utils/requireSchema.js | 6 - .../src/{worker.js => worker.ts} | 33 +-- .../test/integration.spec.js | 199 --------------- .../test/integration.spec.ts | 241 ++++++++++++++++++ .../redux-devtools-cli/test/tsconfig.json | 4 + packages/redux-devtools-cli/tsconfig.json | 7 + yarn.lock | 58 ++++- 29 files changed, 934 insertions(+), 643 deletions(-) create mode 100644 packages/redux-devtools-cli/.eslintignore create mode 100644 packages/redux-devtools-cli/.eslintrc.js delete mode 100644 packages/redux-devtools-cli/bin/injectServer.js mode change 100755 => 100644 packages/redux-devtools-cli/bin/redux-devtools.js create mode 100644 packages/redux-devtools-cli/jest.config.js delete mode 100644 packages/redux-devtools-cli/src/api/schema.js create mode 100644 packages/redux-devtools-cli/src/api/schema.ts create mode 100644 packages/redux-devtools-cli/src/bin/injectServer.ts rename packages/redux-devtools-cli/{bin/openApp.js => src/bin/openApp.ts} (62%) create mode 100644 packages/redux-devtools-cli/src/bin/redux-devtools.ts rename packages/redux-devtools-cli/src/db/{connector.js => connector.ts} (61%) rename packages/redux-devtools-cli/src/db/migrations/{index.js => index.ts} (95%) rename packages/redux-devtools-cli/src/db/seeds/{index.js => index.ts} (74%) create mode 100644 packages/redux-devtools-cli/src/getport.ts rename packages/redux-devtools-cli/{index.js => src/index.ts} (53%) rename packages/redux-devtools-cli/src/middleware/{graphql.js => graphql.ts} (70%) delete mode 100644 packages/redux-devtools-cli/src/options.js create mode 100644 packages/redux-devtools-cli/src/options.ts rename packages/redux-devtools-cli/src/{routes.js => routes.ts} (67%) delete mode 100644 packages/redux-devtools-cli/src/store.js create mode 100644 packages/redux-devtools-cli/src/store.ts delete mode 100644 packages/redux-devtools-cli/src/utils/requireSchema.js rename packages/redux-devtools-cli/src/{worker.js => worker.ts} (72%) delete mode 100644 packages/redux-devtools-cli/test/integration.spec.js create mode 100644 packages/redux-devtools-cli/test/integration.spec.ts create mode 100644 packages/redux-devtools-cli/test/tsconfig.json create mode 100644 packages/redux-devtools-cli/tsconfig.json diff --git a/packages/redux-devtools-cli/.eslintignore b/packages/redux-devtools-cli/.eslintignore new file mode 100644 index 00000000..d827b1ac --- /dev/null +++ b/packages/redux-devtools-cli/.eslintignore @@ -0,0 +1,2 @@ +dist +umd diff --git a/packages/redux-devtools-cli/.eslintrc.js b/packages/redux-devtools-cli/.eslintrc.js new file mode 100644 index 00000000..486b7fd4 --- /dev/null +++ b/packages/redux-devtools-cli/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + extends: '../../.eslintrc', + overrides: [ + { + files: ['*.ts', '*.tsx'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + }, + { + files: ['test/*.ts', 'test/*.tsx'], + extends: '../../eslintrc.ts.jest.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./test/tsconfig.json'], + }, + }, + ], +}; diff --git a/packages/redux-devtools-cli/bin/injectServer.js b/packages/redux-devtools-cli/bin/injectServer.js deleted file mode 100644 index 8a4816b6..00000000 --- a/packages/redux-devtools-cli/bin/injectServer.js +++ /dev/null @@ -1,95 +0,0 @@ -var fs = require('fs'); -var path = require('path'); -var semver = require('semver'); - -var name = 'redux-devtools-cli'; -var startFlag = '/* ' + name + ' start */'; -var endFlag = '/* ' + name + ' end */'; -var serverFlags = { - 'react-native': { - '0.0.1': ' _server(argv, config, resolve, reject);', - '0.31.0': - " runServer(args, config, () => console.log('\\nReact packager ready.\\n'));", - '0.44.0-rc.0': ' runServer(args, config, startedCallback, readyCallback);', - '0.46.0-rc.0': - ' runServer(runServerArgs, configT, startedCallback, readyCallback);', - '0.57.0': ' runServer(args, configT);', - }, - 'react-native-desktop': { - '0.0.1': ' _server(argv, config, resolve, reject);', - }, -}; - -function getModuleVersion(modulePath) { - return JSON.parse( - fs.readFileSync(path.join(modulePath, 'package.json'), 'utf-8') - ).version; -} - -function getServerFlag(moduleName, version) { - var flags = serverFlags[moduleName || 'react-native']; - var versions = Object.keys(flags); - var flag; - for (var i = 0; i < versions.length; i++) { - if (semver.gte(version, versions[i])) { - flag = flags[versions[i]]; - } - } - return flag; -} - -exports.dir = 'local-cli/server'; -exports.file = 'server.js'; -exports.fullPath = path.join(exports.dir, exports.file); - -exports.inject = function (modulePath, options, moduleName) { - var filePath = path.join(modulePath, exports.fullPath); - if (!fs.existsSync(filePath)) return false; - - var serverFlag = getServerFlag(moduleName, getModuleVersion(modulePath)); - var code = [ - startFlag, - ' require("' + name + '")(' + JSON.stringify(options) + ')', - ' .then(_remotedev =>', - ' _remotedev.on("ready", () => {', - ' if (!_remotedev.portAlreadyUsed) console.log("-".repeat(80));', - ' ' + serverFlag, - ' })', - ' );', - endFlag, - ].join('\n'); - - var serverCode = fs.readFileSync(filePath, 'utf-8'); - var start = serverCode.indexOf(startFlag); // already injected ? - var end = serverCode.indexOf(endFlag) + endFlag.length; - if (start === -1) { - start = serverCode.indexOf(serverFlag); - end = start + serverFlag.length; - } - fs.writeFileSync( - filePath, - serverCode.substr(0, start) + - code + - serverCode.substr(end, serverCode.length) - ); - return true; -}; - -exports.revert = function (modulePath, moduleName) { - var filePath = path.join(modulePath, exports.fullPath); - if (!fs.existsSync(filePath)) return false; - - var serverFlag = getServerFlag(moduleName, getModuleVersion(modulePath)); - var serverCode = fs.readFileSync(filePath, 'utf-8'); - var start = serverCode.indexOf(startFlag); // already injected ? - var end = serverCode.indexOf(endFlag) + endFlag.length; - if (start !== -1) { - fs.writeFileSync( - filePath, - serverCode.substr(0, start) + - serverFlag + - serverCode.substr(end, serverCode.length) - ); - } - return true; -}; diff --git a/packages/redux-devtools-cli/bin/redux-devtools.js b/packages/redux-devtools-cli/bin/redux-devtools.js old mode 100755 new mode 100644 index 093829f2..91be0e79 --- a/packages/redux-devtools-cli/bin/redux-devtools.js +++ b/packages/redux-devtools-cli/bin/redux-devtools.js @@ -1,94 +1,3 @@ #! /usr/bin/env node -var fs = require('fs'); -var path = require('path'); -var argv = require('minimist')(process.argv.slice(2)); -var chalk = require('chalk'); -var injectServer = require('./injectServer'); -var getOptions = require('./../src/options'); -var server = require('../index'); -var openApp = require('./openApp'); -var options = getOptions(argv); - -function readFile(filePath) { - return fs.readFileSync(path.resolve(process.cwd(), filePath), 'utf-8'); -} - -if (argv.protocol === 'https') { - argv.key = argv.key ? readFile(argv.key) : null; - argv.cert = argv.cert ? readFile(argv.cert) : null; -} - -function log(pass, msg) { - var prefix = pass ? chalk.green.bgBlack('PASS') : chalk.red.bgBlack('FAIL'); - var color = pass ? chalk.blue : chalk.red; - console.log(prefix, color(msg)); // eslint-disable-line no-console -} - -function getModuleName(type) { - switch (type) { - case 'macos': - return 'react-native-macos'; - // react-native-macos is renamed from react-native-desktop - case 'desktop': - return 'react-native-desktop'; - case 'reactnative': - default: - return 'react-native'; - } -} - -function getModulePath(moduleName) { - return path.join(process.cwd(), 'node_modules', moduleName); -} - -function getModule(type) { - var moduleName = getModuleName(type); - var modulePath = getModulePath(moduleName); - if (type === 'desktop' && !fs.existsSync(modulePath)) { - moduleName = getModuleName('macos'); - modulePath = getModulePath(moduleName); - } - return { - name: moduleName, - path: modulePath, - }; -} - -function injectRN(type, msg) { - var module = getModule(type); - var fn = type === 'revert' ? injectServer.revert : injectServer.inject; - var pass = fn(module.path, options, module.name); - log( - pass, - msg + - (pass - ? '.' - : ', the file `' + - path.join(module.name, injectServer.fullPath) + - '` not found.') - ); - - process.exit(pass ? 0 : 1); -} - -if (argv.revert) { - injectRN( - argv.revert, - 'Revert injection of ReduxDevTools server from React Native local server' - ); -} -if (argv.injectserver) { - injectRN( - argv.injectserver, - 'Inject ReduxDevTools server into React Native local server' - ); -} - -server(argv).then(function (r) { - if (argv.open && argv.open !== 'false') { - r.on('ready', function () { - openApp(argv.open, options); - }); - } -}); +require('../dist/bin/redux-devtools.js'); diff --git a/packages/redux-devtools-cli/jest.config.js b/packages/redux-devtools-cli/jest.config.js new file mode 100644 index 00000000..8824c114 --- /dev/null +++ b/packages/redux-devtools-cli/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: 'ts-jest', +}; diff --git a/packages/redux-devtools-cli/package.json b/packages/redux-devtools-cli/package.json index b919984a..fb02714e 100644 --- a/packages/redux-devtools-cli/package.json +++ b/packages/redux-devtools-cli/package.json @@ -2,10 +2,12 @@ "name": "redux-devtools-cli", "version": "1.0.0-4", "description": "CLI for remote debugging with Redux DevTools.", - "main": "index.js", - "bin": { - "redux-devtools": "bin/redux-devtools.js" + "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-cli", + "bugs": { + "url": "https://github.com/reduxjs/redux-devtools/issues" }, + "license": "MIT", + "author": "Mihail Diordiev (https://github.com/zalmoxisus)", "files": [ "bin", "src", @@ -13,25 +15,31 @@ "index.js", "defaultDbOptions.json" ], - "scripts": { - "start": "node ./bin/redux-devtools.js", - "start:electron": "node ./bin/redux-devtools.js --open", - "test": "jest", - "prepublishOnly": "npm run test" + "main": "dist/index.js", + "types": "dist/index.d.ts", + "bin": { + "redux-devtools": "bin/redux-devtools.js" }, "repository": { "type": "git", "url": "https://github.com/reduxjs/redux-devtools.git" }, + "scripts": { + "build": "tsc && ncp ./src/api/schema_def.graphql ./dist/api/schema_def.graphql", + "start": "node ./bin/redux-devtools.js", + "start:electron": "node ./bin/redux-devtools.js --open", + "clean": "rimraf dist", + "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" + }, "engines": { - "node": ">=6.0.0" + "node": ">=10.0.0" }, - "author": "Mihail Diordiev (https://github.com/zalmoxisus)", - "license": "MIT", - "bugs": { - "url": "https://github.com/reduxjs/redux-devtools/issues" - }, - "homepage": "https://github.com/reduxjs/redux-devtools", "dependencies": { "apollo-server": "^2.18.2", "apollo-server-express": "^2.18.2", @@ -42,7 +50,7 @@ "electron": "^9.2.0", "express": "^4.17.1", "getport": "^0.1.0", - "graphql": "^15.3.0", + "graphql": "^14.7.0", "knex": "^0.19.5", "lodash": "^4.17.19", "minimist": "^1.2.5", @@ -57,7 +65,13 @@ "uuid": "^8.3.0" }, "devDependencies": { + "@types/cross-spawn": "^6.0.2", + "@types/morgan": "^1.9.1", + "@types/semver": "^7.3.4", + "@types/supertest": "^2.0.10", + "@types/uuid": "^8.3.0", "jest": "^26.2.2", + "ncp": "^2.0.0", "socketcluster-client": "^14.3.1", "supertest": "^4.0.2" } diff --git a/packages/redux-devtools-cli/src/api/schema.js b/packages/redux-devtools-cli/src/api/schema.js deleted file mode 100644 index e92b624d..00000000 --- a/packages/redux-devtools-cli/src/api/schema.js +++ /dev/null @@ -1,21 +0,0 @@ -var makeExecutableSchema = require('apollo-server').makeExecutableSchema; -var requireSchema = require('../utils/requireSchema'); -var schema = requireSchema('./schema_def.graphql', require); - -var resolvers = { - Query: { - reports: function report(source, args, context) { - return context.store.listAll(); - }, - report: function report(source, args, context) { - return context.store.get(args.id); - }, - }, -}; - -var executableSchema = makeExecutableSchema({ - typeDefs: schema, - resolvers: resolvers, -}); - -module.exports = executableSchema; diff --git a/packages/redux-devtools-cli/src/api/schema.ts b/packages/redux-devtools-cli/src/api/schema.ts new file mode 100644 index 00000000..a5236cd2 --- /dev/null +++ b/packages/redux-devtools-cli/src/api/schema.ts @@ -0,0 +1,33 @@ +import fs from 'fs'; +import { makeExecutableSchema } from 'apollo-server'; +import { Store } from '../store'; + +const schema = fs + .readFileSync(require.resolve('./schema_def.graphql')) + .toString(); + +const resolvers = { + Query: { + reports: function report( + source: unknown, + args: unknown, + context: { store: Store } + ) { + return context.store.listAll(); + }, + report: function report( + source: unknown, + args: { id: string }, + context: { store: Store } + ) { + return context.store.get(args.id); + }, + }, +}; + +const executableSchema = makeExecutableSchema({ + typeDefs: schema, + resolvers: resolvers, +}); + +export default executableSchema; diff --git a/packages/redux-devtools-cli/src/bin/injectServer.ts b/packages/redux-devtools-cli/src/bin/injectServer.ts new file mode 100644 index 00000000..c5d04acf --- /dev/null +++ b/packages/redux-devtools-cli/src/bin/injectServer.ts @@ -0,0 +1,104 @@ +import fs from 'fs'; +import path from 'path'; +import semver from 'semver'; +import { Options } from '../options'; + +const name = 'redux-devtools-cli'; +const startFlag = '/* ' + name + ' start */'; +const endFlag = '/* ' + name + ' end */'; +const serverFlags: { [moduleName: string]: { [version: string]: string } } = { + 'react-native': { + '0.0.1': ' _server(argv, config, resolve, reject);', + '0.31.0': + " runServer(args, config, () => console.log('\\nReact packager ready.\\n'));", + '0.44.0-rc.0': ' runServer(args, config, startedCallback, readyCallback);', + '0.46.0-rc.0': + ' runServer(runServerArgs, configT, startedCallback, readyCallback);', + '0.57.0': ' runServer(args, configT);', + }, + 'react-native-desktop': { + '0.0.1': ' _server(argv, config, resolve, reject);', + }, +}; + +function getModuleVersion(modulePath: string) { + return JSON.parse( + fs.readFileSync(path.join(modulePath, 'package.json'), 'utf-8') + ).version; +} + +function getServerFlag(moduleName: string, version: string): string { + const flags = serverFlags[moduleName || 'react-native']; + const versions = Object.keys(flags); + let flag; + for (let i = 0; i < versions.length; i++) { + if (semver.gte(version, versions[i])) { + flag = flags[versions[i]]; + } + } + return flag as string; +} + +export const dir = 'local-cli/server'; +export const file = 'server.js'; +export const fullPath = path.join(exports.dir, exports.file); + +export function inject( + modulePath: string, + options: Options, + moduleName: string +) { + const filePath = path.join(modulePath, exports.fullPath); + if (!fs.existsSync(filePath)) return false; + + const serverFlag = getServerFlag(moduleName, getModuleVersion(modulePath)); + const code = [ + startFlag, + ' require("' + name + '")(' + JSON.stringify(options) + ')', + ' .then(_remotedev =>', + ' _remotedev.on("ready", () => {', + ' if (!_remotedev.portAlreadyUsed) console.log("-".repeat(80));', + ' ' + serverFlag, + ' })', + ' );', + endFlag, + ].join('\n'); + + const serverCode = fs.readFileSync(filePath, 'utf-8'); + let start = serverCode.indexOf(startFlag); // already injected ? + let end = serverCode.indexOf(endFlag) + endFlag.length; + if (start === -1) { + start = serverCode.indexOf(serverFlag); + end = start + serverFlag.length; + } + fs.writeFileSync( + filePath, + serverCode.substr(0, start) + + code + + serverCode.substr(end, serverCode.length) + ); + return true; +} + +export function revert( + modulePath: string, + options: Options, + moduleName: string +) { + const filePath = path.join(modulePath, exports.fullPath); + if (!fs.existsSync(filePath)) return false; + + const serverFlag = getServerFlag(moduleName, getModuleVersion(modulePath)); + const serverCode = fs.readFileSync(filePath, 'utf-8'); + const start = serverCode.indexOf(startFlag); // already injected ? + const end = serverCode.indexOf(endFlag) + endFlag.length; + if (start !== -1) { + fs.writeFileSync( + filePath, + serverCode.substr(0, start) + + serverFlag + + serverCode.substr(end, serverCode.length) + ); + } + return true; +} diff --git a/packages/redux-devtools-cli/bin/openApp.js b/packages/redux-devtools-cli/src/bin/openApp.ts similarity index 62% rename from packages/redux-devtools-cli/bin/openApp.js rename to packages/redux-devtools-cli/src/bin/openApp.ts index f6c47184..1d48ac81 100644 --- a/packages/redux-devtools-cli/bin/openApp.js +++ b/packages/redux-devtools-cli/src/bin/openApp.ts @@ -1,11 +1,13 @@ -var open = require('open'); -var path = require('path'); -var spawn = require('cross-spawn'); +import open from 'open'; +import path from 'path'; +import spawn from 'cross-spawn'; +import { Options } from '../options'; -function openApp(app, options) { +export default function openApp(app: boolean | string, options: Options) { if (app === true || app === 'electron') { try { - var port = options.port ? '--port=' + options.port : ''; + const port = options.port ? `--port=${options.port}` : ''; + // eslint-disable-next-line @typescript-eslint/no-var-requires spawn.sync(require('electron'), [ path.join(__dirname, '..', 'app'), port, @@ -29,10 +31,9 @@ function openApp(app, options) { } return; } + // eslint-disable-next-line @typescript-eslint/no-floating-promises open( - 'http://localhost:' + options.port + '/', - app !== 'browser' ? { app: app } : undefined + `http://localhost:${options.port}/`, + app !== 'browser' ? { app: app as string } : undefined ); } - -module.exports = openApp; diff --git a/packages/redux-devtools-cli/src/bin/redux-devtools.ts b/packages/redux-devtools-cli/src/bin/redux-devtools.ts new file mode 100644 index 00000000..dd8570eb --- /dev/null +++ b/packages/redux-devtools-cli/src/bin/redux-devtools.ts @@ -0,0 +1,97 @@ +#! /usr/bin/env node +import fs from 'fs'; +import path from 'path'; +import parseArgs from 'minimist'; +import chalk from 'chalk'; +import * as injectServer from './injectServer'; +import getOptions from '../options'; +import server from '../index'; +import openApp from './openApp'; + +const argv = parseArgs(process.argv.slice(2)); + +const options = getOptions(argv); + +function readFile(filePath: string) { + return fs.readFileSync(path.resolve(process.cwd(), filePath), 'utf-8'); +} + +if (argv.protocol === 'https') { + argv.key = argv.key ? readFile(argv.key) : null; + argv.cert = argv.cert ? readFile(argv.cert) : null; +} + +function log(pass: boolean, msg: string) { + const prefix = pass ? chalk.green.bgBlack('PASS') : chalk.red.bgBlack('FAIL'); + const color = pass ? chalk.blue : chalk.red; + console.log(prefix, color(msg)); // eslint-disable-line no-console +} + +function getModuleName(type: string) { + switch (type) { + case 'macos': + return 'react-native-macos'; + // react-native-macos is renamed from react-native-desktop + case 'desktop': + return 'react-native-desktop'; + case 'reactnative': + default: + return 'react-native'; + } +} + +function getModulePath(moduleName: string) { + return path.join(process.cwd(), 'node_modules', moduleName); +} + +function getModule(type: string) { + let moduleName = getModuleName(type); + let modulePath = getModulePath(moduleName); + if (type === 'desktop' && !fs.existsSync(modulePath)) { + moduleName = getModuleName('macos'); + modulePath = getModulePath(moduleName); + } + return { + name: moduleName, + path: modulePath, + }; +} + +function injectRN(type: string, msg: string) { + const module = getModule(type); + const fn = type === 'revert' ? injectServer.revert : injectServer.inject; + const pass = fn(module.path, options, module.name); + log( + pass, + msg + + (pass + ? '.' + : ', the file `' + + path.join(module.name, injectServer.fullPath) + + '` not found.') + ); + + process.exit(pass ? 0 : 1); +} + +if (argv.revert) { + injectRN( + argv.revert, + 'Revert injection of ReduxDevTools server from React Native local server' + ); +} +if (argv.injectserver) { + injectRN( + argv.injectserver, + 'Inject ReduxDevTools server into React Native local server' + ); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +server(argv).then(function (r) { + if (argv.open && argv.open !== 'false') { + r.on('ready', function () { + openApp(argv.open, options); + }); + } +}); diff --git a/packages/redux-devtools-cli/src/db/connector.js b/packages/redux-devtools-cli/src/db/connector.ts similarity index 61% rename from packages/redux-devtools-cli/src/db/connector.js rename to packages/redux-devtools-cli/src/db/connector.ts index 84567527..e162ef1e 100644 --- a/packages/redux-devtools-cli/src/db/connector.js +++ b/packages/redux-devtools-cli/src/db/connector.ts @@ -1,8 +1,9 @@ -var path = require('path'); -var knexModule = require('knex'); +import path from 'path'; +import knexModule from 'knex'; +import { SCServer } from 'socketcluster-server'; -module.exports = function connector(options) { - var dbOptions = options.dbOptions; +export default function connector(options: SCServer.SCServerOptions) { + const dbOptions = options.dbOptions; dbOptions.useNullAsDefault = true; if (!dbOptions.migrate) { return knexModule(dbOptions); @@ -10,13 +11,13 @@ module.exports = function connector(options) { dbOptions.migrations = { directory: path.resolve(__dirname, 'migrations') }; dbOptions.seeds = { directory: path.resolve(__dirname, 'seeds') }; - var knex = knexModule(dbOptions); + const knex = knexModule(dbOptions); /* eslint-disable no-console */ knex.migrate - .latest() + .latest({ loadExtensions: ['.js'] }) .then(function () { - return knex.seed.run(); + return knex.seed.run({ loadExtensions: ['.js'] }); }) .then(function () { console.log(' \x1b[0;32m[Done]\x1b[0m Migrations are finished\n'); @@ -27,4 +28,4 @@ module.exports = function connector(options) { /* eslint-enable no-console */ return knex; -}; +} diff --git a/packages/redux-devtools-cli/src/db/migrations/index.js b/packages/redux-devtools-cli/src/db/migrations/index.ts similarity index 95% rename from packages/redux-devtools-cli/src/db/migrations/index.js rename to packages/redux-devtools-cli/src/db/migrations/index.ts index 6d0beb8d..2795edc3 100644 --- a/packages/redux-devtools-cli/src/db/migrations/index.js +++ b/packages/redux-devtools-cli/src/db/migrations/index.ts @@ -1,4 +1,6 @@ -exports.up = function (knex) { +import type knexModule from 'knex'; + +export function up(knex: knexModule) { return Promise.all([ knex.schema.createTable('remotedev_reports', function (table) { table.uuid('id').primary(); @@ -75,11 +77,11 @@ exports.up = function (knex) { .onUpdate('CASCADE'); }), ]); -}; +} -exports.down = function (knex) { +export function down(knex: knexModule) { return Promise.all([ knex.schema.dropTable('remotedev_reports'), knex.schema.dropTable('remotedev_apps'), ]); -}; +} diff --git a/packages/redux-devtools-cli/src/db/seeds/index.js b/packages/redux-devtools-cli/src/db/seeds/index.ts similarity index 74% rename from packages/redux-devtools-cli/src/db/seeds/index.js rename to packages/redux-devtools-cli/src/db/seeds/index.ts index a829ef67..85eb9266 100644 --- a/packages/redux-devtools-cli/src/db/seeds/index.js +++ b/packages/redux-devtools-cli/src/db/seeds/index.ts @@ -1,4 +1,6 @@ -exports.seed = function (knex) { +import type knexModule from 'knex'; + +export function seed(knex: knexModule) { return Promise.all([knex('remotedev_apps').del()]).then(function () { return Promise.all([ knex('remotedev_apps').insert({ @@ -7,4 +9,4 @@ exports.seed = function (knex) { }), ]); }); -}; +} diff --git a/packages/redux-devtools-cli/src/getport.ts b/packages/redux-devtools-cli/src/getport.ts new file mode 100644 index 00000000..dc6dc87f --- /dev/null +++ b/packages/redux-devtools-cli/src/getport.ts @@ -0,0 +1,6 @@ +declare module 'getport' { + export default function getport( + start: number, + callback: (e: Error | undefined, port: number) => void + ): void; +} diff --git a/packages/redux-devtools-cli/index.js b/packages/redux-devtools-cli/src/index.ts similarity index 53% rename from packages/redux-devtools-cli/index.js rename to packages/redux-devtools-cli/src/index.ts index 71c5cd5b..4b042f89 100644 --- a/packages/redux-devtools-cli/index.js +++ b/packages/redux-devtools-cli/src/index.ts @@ -1,19 +1,29 @@ -var getPort = require('getport'); -var SocketCluster = require('socketcluster'); -var getOptions = require('./src/options'); +import getPort from 'getport'; +import SocketCluster from 'socketcluster'; +import getOptions, { Options } from './options'; // var LOG_LEVEL_NONE = 0; -var LOG_LEVEL_ERROR = 1; -var LOG_LEVEL_WARN = 2; -var LOG_LEVEL_INFO = 3; +const LOG_LEVEL_ERROR = 1; +const LOG_LEVEL_WARN = 2; +const LOG_LEVEL_INFO = 3; -module.exports = function (argv) { - var options = Object.assign(getOptions(argv), { - workerController: __dirname + '/src/worker.js', +export interface ExtendedOptions extends Options { + workerController: string; + allowClientPublish: boolean; +} + +export default function (argv: { + [arg: string]: any; +}): Promise<{ + portAlreadyUsed?: boolean; + on: (status: 'ready', cb: () => void) => void; +}> { + const options = Object.assign(getOptions(argv), { + workerController: __dirname + '/worker.js', allowClientPublish: false, }); - var port = options.port; - var logLevel = + const port = options.port; + const logLevel = options.logLevel === undefined ? LOG_LEVEL_INFO : options.logLevel; return new Promise(function (resolve) { // Check port already used @@ -27,13 +37,11 @@ module.exports = function (argv) { } if (port !== p) { if (logLevel >= LOG_LEVEL_WARN) { - console.log( - '[ReduxDevTools] Server port ' + port + ' is already used.' - ); + console.log(`[ReduxDevTools] Server port ${port} is already used.`); } resolve({ portAlreadyUsed: true, - on: function (status, cb) { + on: function (status: string, cb: () => void) { cb(); }, }); @@ -47,4 +55,4 @@ module.exports = function (argv) { /* eslint-enable no-console */ }); }); -}; +} diff --git a/packages/redux-devtools-cli/src/middleware/graphql.js b/packages/redux-devtools-cli/src/middleware/graphql.ts similarity index 70% rename from packages/redux-devtools-cli/src/middleware/graphql.js rename to packages/redux-devtools-cli/src/middleware/graphql.ts index efd844d1..4bf5b00f 100644 --- a/packages/redux-devtools-cli/src/middleware/graphql.js +++ b/packages/redux-devtools-cli/src/middleware/graphql.ts @@ -1,7 +1,8 @@ -var ApolloServer = require('apollo-server-express').ApolloServer; -var schema = require('../api/schema'); +import { ApolloServer } from 'apollo-server-express'; +import schema from '../api/schema'; +import { Store } from '../store'; -module.exports = function (store) { +export default function (store: Store) { return new ApolloServer({ schema, context: { @@ -24,4 +25,4 @@ module.exports = function (store) { ], }, }); -}; +} diff --git a/packages/redux-devtools-cli/src/options.js b/packages/redux-devtools-cli/src/options.js deleted file mode 100644 index dbf5049e..00000000 --- a/packages/redux-devtools-cli/src/options.js +++ /dev/null @@ -1,33 +0,0 @@ -var path = require('path'); - -module.exports = function getOptions(argv) { - var dbOptions = argv.dbOptions; - if (typeof dbOptions === 'string') { - dbOptions = require(path.resolve(process.cwd(), argv.dbOptions)); - } else if (typeof dbOptions === 'undefined') { - dbOptions = require('../defaultDbOptions.json'); - } - - return { - host: argv.hostname || process.env.npm_package_remotedev_hostname || null, - port: Number(argv.port || process.env.npm_package_remotedev_port) || 8000, - protocol: - argv.protocol || process.env.npm_package_remotedev_protocol || 'http', - protocolOptions: !(argv.protocol === 'https') - ? null - : { - key: argv.key || process.env.npm_package_remotedev_key || null, - cert: argv.cert || process.env.npm_package_remotedev_cert || null, - passphrase: - argv.passphrase || - process.env.npm_package_remotedev_passphrase || - null, - }, - dbOptions: dbOptions, - maxRequestBody: argv.passphrase || '16mb', - logHTTPRequests: argv.logHTTPRequests, - logLevel: argv.logLevel || 3, - wsEngine: - argv.wsEngine || process.env.npm_package_remotedev_wsengine || 'ws', - }; -}; diff --git a/packages/redux-devtools-cli/src/options.ts b/packages/redux-devtools-cli/src/options.ts new file mode 100644 index 00000000..fed19ca5 --- /dev/null +++ b/packages/redux-devtools-cli/src/options.ts @@ -0,0 +1,63 @@ +import path from 'path'; + +interface ProtocolOptions { + key: string | undefined; + cert: string | undefined; + passphrase: string | undefined; +} + +interface DbOptions { + client: string; + connection: { + filename: string; + }; + useNullAsDefault: boolean; + debug: boolean; + migrate: boolean; +} + +export interface Options { + host: string | undefined; + port: number; + protocol: 'http' | 'https'; + protocolOptions: ProtocolOptions | undefined; + dbOptions: DbOptions; + maxRequestBody: string; + logHTTPRequests?: boolean; + logLevel: 0 | 1 | 3 | 2; + wsEngine: string; +} + +export default function getOptions(argv: { [arg: string]: any }): Options { + let dbOptions = argv.dbOptions; + if (typeof dbOptions === 'string') { + dbOptions = require(path.resolve(process.cwd(), argv.dbOptions)); + } else if (typeof dbOptions === 'undefined') { + dbOptions = require('../defaultDbOptions.json'); + } + + return { + host: + argv.hostname || process.env.npm_package_remotedev_hostname || undefined, + port: Number(argv.port || process.env.npm_package_remotedev_port) || 8000, + protocol: + argv.protocol || process.env.npm_package_remotedev_protocol || 'http', + protocolOptions: !(argv.protocol === 'https') + ? undefined + : { + key: argv.key || process.env.npm_package_remotedev_key || undefined, + cert: + argv.cert || process.env.npm_package_remotedev_cert || undefined, + passphrase: + argv.passphrase || + process.env.npm_package_remotedev_passphrase || + undefined, + }, + dbOptions: dbOptions, + maxRequestBody: argv.passphrase || '16mb', + logHTTPRequests: argv.logHTTPRequests, + logLevel: argv.logLevel || 3, + wsEngine: + argv.wsEngine || process.env.npm_package_remotedev_wsengine || 'ws', + }; +} diff --git a/packages/redux-devtools-cli/src/routes.js b/packages/redux-devtools-cli/src/routes.ts similarity index 67% rename from packages/redux-devtools-cli/src/routes.js rename to packages/redux-devtools-cli/src/routes.ts index 8e7e9836..686fa5d8 100644 --- a/packages/redux-devtools-cli/src/routes.js +++ b/packages/redux-devtools-cli/src/routes.ts @@ -1,13 +1,15 @@ -var path = require('path'); -var express = require('express'); -var morgan = require('morgan'); -var bodyParser = require('body-parser'); -var cors = require('cors'); -var graphqlMiddleware = require('./middleware/graphql'); +import path from 'path'; +import express from 'express'; +import morgan from 'morgan'; +import bodyParser from 'body-parser'; +import cors from 'cors'; +import { SCServer } from 'socketcluster-server'; +import graphqlMiddleware from './middleware/graphql'; +import { ReportBaseFields, Store } from './store'; -var app = express.Router(); +const app = express.Router(); -function serveUmdModule(name) { +function serveUmdModule(name: string) { app.use( express.static( path.dirname(require.resolve(name + '/package.json')) + '/umd' @@ -15,9 +17,13 @@ function serveUmdModule(name) { ); } -function routes(options, store, scServer) { - var limit = options.maxRequestBody; - var logHTTPRequests = options.logHTTPRequests; +function routes( + options: SCServer.SCServerOptions, + store: Store, + scServer: SCServer +) { + const limit = options.maxRequestBody; + const logHTTPRequests = options.logHTTPRequests; if (logHTTPRequests) { if (typeof logHTTPRequests === 'object') @@ -25,14 +31,16 @@ function routes(options, store, scServer) { else app.use(morgan('combined')); } - graphqlMiddleware(store).applyMiddleware({ app }); + graphqlMiddleware(store).applyMiddleware({ app } as { + app: express.Application; + }); serveUmdModule('react'); serveUmdModule('react-dom'); serveUmdModule('redux-devtools-core'); app.get('/port.js', function (req, res) { - res.send('reduxDevToolsPort = ' + options.port); + res.send(`reduxDevToolsPort = ${options.port!}`); }); app.get('*', function (req, res) { res.sendFile(path.join(__dirname, '../app/index.html')); @@ -71,7 +79,10 @@ function routes(options, store, scServer) { store .add(req.body) .then(function (r) { - res.send({ id: r.id, error: r.error }); + res.send({ + id: (r as ReportBaseFields).id, + error: (r as { error: string }).error, + }); scServer.exchange.publish('report', { type: 'add', data: r, @@ -86,4 +97,4 @@ function routes(options, store, scServer) { return app; } -module.exports = routes; +export default routes; diff --git a/packages/redux-devtools-cli/src/store.js b/packages/redux-devtools-cli/src/store.js deleted file mode 100644 index 3d2df8f4..00000000 --- a/packages/redux-devtools-cli/src/store.js +++ /dev/null @@ -1,106 +0,0 @@ -var { v4: uuidV4 } = require('uuid'); -var pick = require('lodash/pick'); -var connector = require('./db/connector'); - -var reports = 'remotedev_reports'; -// var payloads = 'remotedev_payloads'; -var knex; - -var baseFields = ['id', 'title', 'added']; - -function error(msg) { - return new Promise(function (resolve) { - return resolve({ error: msg }); - }); -} - -function list(query, fields) { - var r = knex.select(fields || baseFields).from(reports); - if (query) return r.where(query); - return r; -} - -function listAll(query) { - var r = knex.select().from(reports); - if (query) return r.where(query); - return r; -} - -function get(id) { - if (!id) return error('No id specified.'); - - return knex(reports).where('id', id).first(); -} - -function add(data) { - if (!data.type || !data.payload) { - return error("Required parameters aren't specified."); - } - if (data.type !== 'ACTIONS' && data.type !== 'STATE') { - return error('Type ' + data.type + ' is not supported yet.'); - } - - var reportId = uuidV4(); - var report = { - id: reportId, - type: data.type, - title: - data.title || (data.exception && data.exception.message) || data.action, - description: data.description, - action: data.action, - payload: data.payload, - preloadedState: data.preloadedState, - screenshot: data.screenshot, - version: data.version, - userAgent: data.userAgent, - user: data.user, - userId: typeof data.user === 'object' ? data.user.id : data.user, - instanceId: data.instanceId, - meta: data.meta, - exception: composeException(data.exception), - added: new Date().toISOString(), - }; - if (data.appId) report.appId = data.appId; // TODO check if the id exists and we have access to link it - /* - var payload = { - id: uuid.v4(), - reportId: reportId, - state: data.payload - }; - */ - - return knex - .insert(report) - .into(reports) - .then(function () { - return byBaseFields(report); - }); -} - -function byBaseFields(data) { - return pick(data, baseFields); -} - -function createStore(options) { - knex = connector(options); - - return { - list: list, - listAll: listAll, - get: get, - add: add, - }; -} - -function composeException(exception) { - var message = ''; - - if (exception) { - message = 'Exception thrown: '; - if (exception.message) message += exception.message; - if (exception.stack) message += '\n' + exception.stack; - } - return message; -} - -module.exports = createStore; diff --git a/packages/redux-devtools-cli/src/store.ts b/packages/redux-devtools-cli/src/store.ts new file mode 100644 index 00000000..01f3f61f --- /dev/null +++ b/packages/redux-devtools-cli/src/store.ts @@ -0,0 +1,164 @@ +import { v4 as uuidV4 } from 'uuid'; +import pick from 'lodash/pick'; +import { SCServer } from 'socketcluster-server'; +import knexModule from 'knex'; +import connector from './db/connector'; + +const reports = 'remotedev_reports'; +// var payloads = 'remotedev_payloads'; +let knex: knexModule; + +const baseFields = ['id', 'title', 'added']; + +function error(msg: string): Promise<{ error: string }> { + return new Promise(function (resolve) { + return resolve({ error: msg }); + }); +} + +type ReportType = 'STATE' | 'ACTION' | 'STATES' | 'ACTIONS'; + +interface Report { + id: string; + type: ReportType | null; + title: string | null; + description: string | null; + action: string | null; + payload: string; + preloadedState: string | null; + screenshot: string | null; + userAgent: string | null; + version: string | null; + userId: string | null; + user: string | null; + meta: string | null; + exception: string | null; + instanceId: string | null; + added: string | null; + appId?: string | null; +} + +export interface ReportBaseFields { + id: string; + title: string | null; + added: string | null; +} + +function list(query?: unknown, fields?: string[]): Promise { + const r = knex.select(fields || baseFields).from(reports); + if (query) return r.where(query); + return r; +} + +function listAll(query: unknown): Promise { + const r = knex.select().from(reports); + if (query) return r.where(query); + return r; +} + +function get(id: string): Promise { + if (!id) return error('No id specified.'); + + return knex(reports).where('id', id).first(); +} + +interface AddData { + type: ReportType | null; + title: string | null; + description: string | null; + action: string | null; + payload: string; + preloadedState: string | null; + screenshot: string | null; + version: string | null; + userAgent: string | null; + userId: string | null; + user: { id: string } | string | null; + instanceId: string | null; + meta: string | null; + exception?: Error; + appId?: string | null; +} + +function add(data: AddData): Promise { + if (!data.type || !data.payload) { + return error("Required parameters aren't specified."); + } + if (data.type !== 'ACTIONS' && data.type !== 'STATE') { + return error('Type ' + data.type + ' is not supported yet.'); + } + + const reportId = uuidV4(); + const report: Report = { + id: reportId, + type: data.type, + title: + data.title || (data.exception && data.exception.message) || data.action, + description: data.description, + action: data.action, + payload: data.payload, + preloadedState: data.preloadedState, + screenshot: data.screenshot, + version: data.version, + userAgent: data.userAgent, + user: data.user as string, + userId: + typeof data.user === 'object' + ? (data.user as { id: string }).id + : data.user, + instanceId: data.instanceId, + meta: data.meta, + exception: composeException(data.exception), + added: new Date().toISOString(), + }; + if (data.appId) report.appId = data.appId; // TODO check if the id exists and we have access to link it + /* + var payload = { + id: uuid.v4(), + reportId: reportId, + state: data.payload + }; + */ + + return knex + .insert(report) + .into(reports) + .then(function () { + return byBaseFields(report); + }); +} + +function byBaseFields(data: Report): ReportBaseFields { + return pick(data, baseFields) as ReportBaseFields; +} + +export interface Store { + list: (query?: unknown, fields?: string[]) => Promise; + listAll: (query?: unknown) => Promise; + get: (id: string) => Promise; + add: (data: AddData) => Promise; +} + +function createStore(options: SCServer.SCServerOptions): Store { + knex = connector(options); + + return { + list: list, + listAll: listAll, + get: get, + add: add, + }; +} + +function composeException(exception: Error | undefined) { + let message = ''; + + if (exception) { + message = 'Exception thrown: '; + if (exception.message) message += exception.message; + if (exception.stack) message += '\n' + exception.stack; + } + return message; +} + +export default createStore; diff --git a/packages/redux-devtools-cli/src/utils/requireSchema.js b/packages/redux-devtools-cli/src/utils/requireSchema.js deleted file mode 100644 index 08d0a75b..00000000 --- a/packages/redux-devtools-cli/src/utils/requireSchema.js +++ /dev/null @@ -1,6 +0,0 @@ -var fs = require('fs'); - -module.exports = function (name, require) { - return fs.readFileSync(require.resolve(name)).toString(); - // return GraphQL.buildSchema(schema); -}; diff --git a/packages/redux-devtools-cli/src/worker.js b/packages/redux-devtools-cli/src/worker.ts similarity index 72% rename from packages/redux-devtools-cli/src/worker.js rename to packages/redux-devtools-cli/src/worker.ts index 3bf0929a..4c1e3fa3 100644 --- a/packages/redux-devtools-cli/src/worker.js +++ b/packages/redux-devtools-cli/src/worker.ts @@ -1,23 +1,24 @@ -var SCWorker = require('socketcluster/scworker'); -var express = require('express'); -var app = express(); -var routes = require('./routes'); -var createStore = require('./store'); +import SCWorker from 'socketcluster/scworker'; +import express from 'express'; +import routes from './routes'; +import createStore from './store'; + +const app = express(); class Worker extends SCWorker { run() { - var httpServer = this.httpServer; - var scServer = this.scServer; - var options = this.options; - var store = createStore(options); + const httpServer = this.httpServer; + const scServer = this.scServer; + const options = this.options; + const store = createStore(options); httpServer.on('request', app); app.use(routes(options, store, scServer)); scServer.addMiddleware(scServer.MIDDLEWARE_EMIT, function (req, next) { - var channel = req.event; - var data = req.data; + const channel = req.event; + const data = req.data; if ( channel.substr(0, 3) === 'sc-' || channel === 'respond' || @@ -36,7 +37,7 @@ class Worker extends SCWorker { store .list() .then(function (data) { - req.socket.emit(req.channel, { type: 'list', data: data }); + req.socket.emit(req.channel!, { type: 'list', data: data }); }) .catch(function (error) { console.error(error); // eslint-disable-line no-console @@ -45,8 +46,8 @@ class Worker extends SCWorker { }); scServer.on('connection', function (socket) { - var channelToWatch, channelToEmit; - socket.on('login', function (credentials, respond) { + let channelToWatch: string, channelToEmit: string; + socket.on('login', function (this: Worker, credentials, respond) { if (credentials === 'master') { channelToWatch = 'respond'; channelToEmit = 'log'; @@ -69,8 +70,8 @@ class Worker extends SCWorker { console.error(error); // eslint-disable-line no-console }); }); - socket.on('disconnect', function () { - var channel = this.exchange.channel('sc-' + socket.id); + socket.on('disconnect', function (this: Worker) { + const channel = this.exchange.channel('sc-' + socket.id); channel.unsubscribe(); channel.destroy(); scServer.exchange.publish(channelToEmit, { diff --git a/packages/redux-devtools-cli/test/integration.spec.js b/packages/redux-devtools-cli/test/integration.spec.js deleted file mode 100644 index c70556e3..00000000 --- a/packages/redux-devtools-cli/test/integration.spec.js +++ /dev/null @@ -1,199 +0,0 @@ -var childProcess = require('child_process'); -var request = require('supertest'); -var scClient = require('socketcluster-client'); - -describe('Server', function () { - var scServer; - beforeAll(function (done) { - scServer = childProcess.fork(__dirname + '/../bin/redux-devtools.js'); - setTimeout(done, 3000); - }); - - afterAll(function () { - if (scServer) { - scServer.kill(); - } - }); - - describe('Express backend', function () { - it('loads main page', function (done) { - request('http://localhost:8000') - .get('/') - .expect('Content-Type', /text\/html/) - .expect(200) - .then(function (res) { - expect(res.text).toMatch(/Redux DevTools<\/title>/); - done(); - }); - }); - - it('resolves an inexistent url', function (done) { - request('http://localhost:8000/jreerfr/123') - .get('/') - .expect('Content-Type', /text\/html/) - .expect(200, done); - }); - }); - - describe('Realtime monitoring', function () { - var socket, socket2, channel; - beforeAll(function () { - socket = scClient.connect({ hostname: 'localhost', port: 8000 }); - socket.connect(); - socket.on('error', function (error) { - console.error('Socket1 error', error); // eslint-disable-line no-console - }); - socket2 = scClient.connect({ hostname: 'localhost', port: 8000 }); - socket2.connect(); - socket.on('error', function (error) { - console.error('Socket2 error', error); // eslint-disable-line no-console - }); - }); - - afterAll(function () { - socket.disconnect(); - socket2.disconnect(); - }); - - it('should connect', function (done) { - socket.on('connect', function (status) { - expect(status.id).toBeTruthy(); - done(); - }); - }); - - it('should login', function () { - socket.emit('login', 'master', function (error, channelName) { - if (error) { - /* eslint-disable-next-line no-console */ - console.log(error); - return; - } - expect(channelName).toBe('respond'); - channel = socket.subscribe(channelName); - expect(channel.SUBSCRIBED).toBe('subscribed'); - }); - }); - - it('should send message', function (done) { - var data = { - type: 'ACTION', - payload: { - todos: 'do some', - }, - action: { - timestamp: 1483349708506, - action: { - type: 'ADD_TODO', - text: 'hggg', - }, - }, - instanceId: 'tAmA7H5fclyWhvizAAAi', - name: 'LoggerInstance', - id: 'tAmA7H5fclyWhvizAAAi', - }; - - socket2.emit('login', '', function (error, channelName) { - if (error) { - /* eslint-disable-next-line no-console */ - console.log(error); - return; - } - expect(channelName).toBe('log'); - var channel2 = socket2.subscribe(channelName); - expect(channel2.SUBSCRIBED).toBe('subscribed'); - channel2.on('subscribe', function () { - channel2.watch(function (message) { - expect(message).toEqual(data); - done(); - }); - socket.emit(channelName, data); - }); - }); - }); - }); - - describe('REST backend', function () { - var id; - var report = { - type: 'ACTIONS', - title: 'Test report', - description: 'Test body report', - action: 'SOME_FINAL_ACTION', - payload: '[{"type":"ADD_TODO","text":"hi"},{"type":"SOME_FINAL_ACTION"}]', - preloadedState: - '{"todos":[{"text":"Use Redux","completed":false,"id":0}]}', - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) ' + - 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36', - }; - it('should add a report', function (done) { - request('http://localhost:8000') - .post('/') - .send(report) - .set('Accept', 'application/json') - .expect('Content-Type', /application\/json/) - .expect(200) - .then(function (res) { - id = res.body.id; - expect(id).toBeTruthy(); - done(); - }); - }); - - it('should get the report', function (done) { - request('http://localhost:8000') - .post('/') - .send({ - op: 'get', - id: id, - }) - .set('Accept', 'application/json') - .expect('Content-Type', /application\/json/) - .expect(200) - .then(function (res) { - expect.objectContaining(res.body, report); - done(); - }); - }); - - it('should list reports', function (done) { - request('http://localhost:8000') - .post('/') - .send({ - op: 'list', - }) - .set('Accept', 'application/json') - .expect('Content-Type', /application\/json/) - .expect(200) - .then(function (res) { - expect(res.body.length).toBe(1); - expect(res.body[0].id).toBe(id); - expect(res.body[0].title).toBe('Test report'); - expect(res.body[0].added).toBeTruthy(); - done(); - }); - }); - }); - - describe('GraphQL backend', function () { - it('should get the report', function (done) { - request('http://localhost:8000') - .post('/graphql') - .send({ - query: '{ reports { id, type, title } }', - }) - .set('Accept', 'application/json') - .expect('Content-Type', /application\/json/) - .expect(200) - .then(function (res) { - var reports = res.body.data.reports; - expect(reports.length).toBe(1); - expect(reports[0].id).toBeTruthy(); - expect(reports[0].title).toBe('Test report'); - expect(reports[0].type).toBe('ACTIONS'); - done(); - }); - }); - }); -}); diff --git a/packages/redux-devtools-cli/test/integration.spec.ts b/packages/redux-devtools-cli/test/integration.spec.ts new file mode 100644 index 00000000..ed2c04c6 --- /dev/null +++ b/packages/redux-devtools-cli/test/integration.spec.ts @@ -0,0 +1,241 @@ +import childProcess from 'child_process'; +import request from 'supertest'; +import scClient from 'socketcluster-client'; + +describe('Server', function () { + let scServer: childProcess.ChildProcess; + beforeAll(function (done) { + scServer = childProcess.fork(__dirname + '/../bin/redux-devtools.js'); + setTimeout(done, 3000); + }); + + afterAll(function () { + if (scServer) { + scServer.kill(); + } + }); + + describe('Express backend', function () { + it('loads main page', function () { + return new Promise((done) => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + request('http://localhost:8000') + .get('/') + .expect('Content-Type', /text\/html/) + .expect(200) + .then(function (res: { text: string }) { + expect(res.text).toMatch(/<title>Redux DevTools<\/title>/); + done(); + }); + }); + }); + + it('resolves an inexistent url', function () { + return new Promise((done) => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + request('http://localhost:8000/jreerfr/123') + .get('/') + .expect('Content-Type', /text\/html/) + .expect(200, done); + }); + }); + }); + + describe('Realtime monitoring', function () { + let socket: scClient.SCClientSocket, + socket2: scClient.SCClientSocket, + channel; + beforeAll(function () { + socket = scClient.connect({ hostname: 'localhost', port: 8000 }); + socket.connect(); + socket.on('error', function (error) { + console.error('Socket1 error', error); // eslint-disable-line no-console + }); + socket2 = scClient.connect({ hostname: 'localhost', port: 8000 }); + socket2.connect(); + socket.on('error', function (error) { + console.error('Socket2 error', error); // eslint-disable-line no-console + }); + }); + + afterAll(function () { + socket.disconnect(); + socket2.disconnect(); + }); + + it('should connect', function () { + return new Promise((done) => { + socket.on('connect', function (status) { + expect(status.id).toBeTruthy(); + done(); + }); + }); + }); + + it('should login', function () { + socket.emit('login', 'master', function ( + error: Error | undefined, + channelName: string + ) { + if (error) { + /* eslint-disable-next-line no-console */ + console.log(error); + return; + } + expect(channelName).toBe('respond'); + channel = socket.subscribe(channelName); + expect(channel.SUBSCRIBED).toBe('subscribed'); + }); + }); + + it('should send message', function () { + return new Promise((done) => { + const data = { + type: 'ACTION', + payload: { + todos: 'do some', + }, + action: { + timestamp: 1483349708506, + action: { + type: 'ADD_TODO', + text: 'hggg', + }, + }, + instanceId: 'tAmA7H5fclyWhvizAAAi', + name: 'LoggerInstance', + id: 'tAmA7H5fclyWhvizAAAi', + }; + + socket2.emit('login', '', function ( + error: Error | undefined, + channelName: string + ) { + if (error) { + /* eslint-disable-next-line no-console */ + console.log(error); + return; + } + expect(channelName).toBe('log'); + const channel2 = socket2.subscribe(channelName); + expect(channel2.SUBSCRIBED).toBe('subscribed'); + channel2.on('subscribe', function () { + channel2.watch(function (message) { + expect(message).toEqual(data); + done(); + }); + socket.emit(channelName, data); + }); + }); + }); + }); + }); + + describe('REST backend', function () { + let id: string; + const report = { + type: 'ACTIONS', + title: 'Test report', + description: 'Test body report', + action: 'SOME_FINAL_ACTION', + payload: '[{"type":"ADD_TODO","text":"hi"},{"type":"SOME_FINAL_ACTION"}]', + preloadedState: + '{"todos":[{"text":"Use Redux","completed":false,"id":0}]}', + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) ' + + 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36', + }; + it('should add a report', function () { + return new Promise((done) => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + request('http://localhost:8000') + .post('/') + .send(report) + .set('Accept', 'application/json') + .expect('Content-Type', /application\/json/) + .expect(200) + .then(function (res: { body: { id: string } }) { + id = res.body.id; + expect(id).toBeTruthy(); + done(); + }); + }); + }); + + it('should get the report', function () { + return new Promise((done) => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + request('http://localhost:8000') + .post('/') + .send({ + op: 'get', + id: id, + }) + .set('Accept', 'application/json') + .expect('Content-Type', /application\/json/) + .expect(200) + .then(function (res: { body: unknown }) { + expect(res.body).toMatchObject(report); + done(); + }); + }); + }); + + it('should list reports', function () { + return new Promise((done) => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + request('http://localhost:8000') + .post('/') + .send({ + op: 'list', + }) + .set('Accept', 'application/json') + .expect('Content-Type', /application\/json/) + .expect(200) + .then(function (res: { + body: { id: string; title: string | null; added: string | null }[]; + }) { + expect(res.body).toHaveLength(1); + expect(res.body[0].id).toBe(id); + expect(res.body[0].title).toBe('Test report'); + expect(res.body[0].added).toBeTruthy(); + done(); + }); + }); + }); + }); + + describe('GraphQL backend', function () { + it('should get the report', function () { + return new Promise((done) => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + request('http://localhost:8000') + .post('/graphql') + .send({ + query: '{ reports { id, type, title } }', + }) + .set('Accept', 'application/json') + .expect('Content-Type', /application\/json/) + .expect(200) + .then(function (res: { + body: { + data: { + reports: { + id: string; + title: string | null; + type: string | null; + }[]; + }; + }; + }) { + const reports = res.body.data.reports; + expect(reports).toHaveLength(1); + expect(reports[0].id).toBeTruthy(); + expect(reports[0].title).toBe('Test report'); + expect(reports[0].type).toBe('ACTIONS'); + done(); + }); + }); + }); + }); +}); diff --git a/packages/redux-devtools-cli/test/tsconfig.json b/packages/redux-devtools-cli/test/tsconfig.json new file mode 100644 index 00000000..b55532d2 --- /dev/null +++ b/packages/redux-devtools-cli/test/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["../src", "."] +} diff --git a/packages/redux-devtools-cli/tsconfig.json b/packages/redux-devtools-cli/tsconfig.json new file mode 100644 index 00000000..1e20cd95 --- /dev/null +++ b/packages/redux-devtools-cli/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["src"] +} diff --git a/yarn.lock b/yarn.lock index 80e9176d..97717fda 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3493,6 +3493,11 @@ resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.3.tgz#0aa116701955c2faa0717fc69cd1596095e49d96" integrity sha512-P1bffQfhD3O4LW0ioENXUhZ9OIa0Zn+P7M+pWgkCKaT53wVLSq0mrKksCID/FGHpFhRSxRGhgrQmfhRuzwtKdg== +"@types/cookiejar@*": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" + integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== + "@types/cookies@*": version "0.7.4" resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.4.tgz#26dedf791701abc0e36b5b79a5722f40e455f87b" @@ -3510,6 +3515,13 @@ dependencies: "@types/express" "*" +"@types/cross-spawn@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.2.tgz#168309de311cd30a2b8ae720de6475c2fbf33ac7" + integrity sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw== + dependencies: + "@types/node" "*" + "@types/d3@^3.5.43": version "3.5.43" resolved "https://registry.yarnpkg.com/@types/d3/-/d3-3.5.43.tgz#e9b4992817e0b6c5efaa7d6e5bb2cee4d73eab58" @@ -3859,6 +3871,13 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= +"@types/morgan@^1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.1.tgz#6457872df95647c1dbc6b3741e8146b71ece74bf" + integrity sha512-2j5IKrgJpEP6xw/uiVb2Xfga0W0sSVD9JP9t7EZLvpBENdB0OKgcnoKS8IsjNeNnZ/86robdZ61Orl0QCFGOXg== + dependencies: + "@types/node" "*" + "@types/ncom@*": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/ncom/-/ncom-1.0.0.tgz#8e33d06fc4914c941ba40ceca042081b947ba699" @@ -4116,6 +4135,11 @@ resolved "https://registry.yarnpkg.com/@types/sc-errors/-/sc-errors-1.4.0.tgz#dba1309b695ee8aafc3f574dfedfe4f3c5153419" integrity sha512-WfBEiw/SVja1ZvJRdt37dOJFxp2llV35n9cPiDCDsFRSvTTYlO4iMFg+NyeEhiWBk1O4bvmyYpAEYzJx1DbHHQ== +"@types/semver@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb" + integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ== + "@types/serve-static@*": version "1.13.5" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53" @@ -4186,6 +4210,21 @@ "@types/react-native" "*" csstype "^3.0.2" +"@types/superagent@*": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.10.tgz#5e2cc721edf58f64fe9b819f326ee74803adee86" + integrity sha512-xAgkb2CMWUMCyVc/3+7iQfOEBE75NvuZeezvmixbUw3nmENf2tCnQkW5yQLTYqvXUQ+R6EXxdqKKbal2zM5V/g== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + +"@types/supertest@^2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.10.tgz#630d79b4d82c73e043e43ff777a9ca98d457cab7" + integrity sha512-Xt8TbEyZTnD5Xulw95GLMOkmjGICrOQyJ2jqgkSjAUR3mm7pAIzSR0NFBaMcwlzVvlpCjNwbATcWWwjNiZiFrQ== + dependencies: + "@types/superagent" "*" + "@types/tapable@*", "@types/tapable@^1.0.5": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.6.tgz#a9ca4b70a18b270ccb2bc0aaafefd1d486b7ea74" @@ -4210,6 +4249,11 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== +"@types/uuid@^8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" + integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== + "@types/warning@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52" @@ -9656,6 +9700,13 @@ graphql-upload@^8.0.2: http-errors "^1.7.3" object-path "^0.11.4" +graphql@^14.7.0: + version "14.7.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.7.0.tgz#7fa79a80a69be4a31c27dda824dc04dac2035a72" + integrity sha512-l0xWZpoPKpppFzMfvVyFmp9vLN7w/ZZJPefUicMCepfJeQ8sMcztloGYY9DfjVPo6tIUDzU5Hw3MUbIjj9AVVA== + dependencies: + iterall "^1.2.2" + graphql@^15.3.0: version "15.3.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278" @@ -11028,7 +11079,7 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -iterall@^1.1.3, iterall@^1.2.1: +iterall@^1.1.3, iterall@^1.2.1, iterall@^1.2.2: version "1.3.0" resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== @@ -13074,6 +13125,11 @@ ncom@^1.0.2: dependencies: sc-formatter "~3.0.1" +ncp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= + nearley@^2.7.10: version "2.19.5" resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.19.5.tgz#6be78e4942eeb9a043b17c563413111d4ad849b7" From 7ae485b035e0da9ca2895a988f99b2c8aa099a2f Mon Sep 17 00:00:00 2001 From: Nathan Bierema <nbierema@gmail.com> Date: Mon, 26 Oct 2020 02:43:20 -0400 Subject: [PATCH 10/25] chore(extension): move npm package (#657) * Start adding extension * prettier --- packages/redux-devtools-extension/README.md | 50 +++++ .../developmentOnly.d.ts | 1 + .../developmentOnly.js | 26 +++ packages/redux-devtools-extension/index.d.ts | 174 ++++++++++++++++++ packages/redux-devtools-extension/index.js | 22 +++ .../redux-devtools-extension/logOnly.d.ts | 1 + packages/redux-devtools-extension/logOnly.js | 60 ++++++ .../logOnlyInProduction.d.ts | 1 + .../logOnlyInProduction.js | 28 +++ .../redux-devtools-extension/package.json | 16 ++ .../redux-devtools-extension/utils/assign.js | 24 +++ 11 files changed, 403 insertions(+) create mode 100644 packages/redux-devtools-extension/README.md create mode 100644 packages/redux-devtools-extension/developmentOnly.d.ts create mode 100644 packages/redux-devtools-extension/developmentOnly.js create mode 100644 packages/redux-devtools-extension/index.d.ts create mode 100644 packages/redux-devtools-extension/index.js create mode 100644 packages/redux-devtools-extension/logOnly.d.ts create mode 100644 packages/redux-devtools-extension/logOnly.js create mode 100644 packages/redux-devtools-extension/logOnlyInProduction.d.ts create mode 100644 packages/redux-devtools-extension/logOnlyInProduction.js create mode 100644 packages/redux-devtools-extension/package.json create mode 100644 packages/redux-devtools-extension/utils/assign.js diff --git a/packages/redux-devtools-extension/README.md b/packages/redux-devtools-extension/README.md new file mode 100644 index 00000000..fdc90a1a --- /dev/null +++ b/packages/redux-devtools-extension/README.md @@ -0,0 +1,50 @@ +# Redux DevTools Extension's helper + +[![Join the chat at https://gitter.im/zalmoxisus/redux-devtools-extension](https://badges.gitter.im/zalmoxisus/redux-devtools-extension.svg)](https://gitter.im/zalmoxisus/redux-devtools-extension?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +## Usage + +Install: + +``` +npm install --save redux-devtools-extension +``` + +and use like that: + +```js +import { createStore, applyMiddleware } from 'redux'; +import { composeWithDevTools } from 'redux-devtools-extension'; + +const store = createStore( + reducer, + composeWithDevTools( + applyMiddleware(...middleware) + // other store enhancers if any + ) +); +``` + +or if needed to apply [extension’s options](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md#windowdevtoolsextensionconfig): + +```js +import { createStore, applyMiddleware } from 'redux'; +import { composeWithDevTools } from 'redux-devtools-extension'; + +const composeEnhancers = composeWithDevTools({ + // Specify here name, actionsBlacklist, actionsCreators and other options +}); +const store = createStore( + reducer, + composeEnhancers( + applyMiddleware(...middleware) + // other store enhancers if any + ) +); +``` + +There’re just [few lines of code](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/npm-package/index.js). If you don’t want to allow the extension in production, just use ‘redux-devtools-extension/developmentOnly’ instead of ‘redux-devtools-extension’. + +## License + +MIT diff --git a/packages/redux-devtools-extension/developmentOnly.d.ts b/packages/redux-devtools-extension/developmentOnly.d.ts new file mode 100644 index 00000000..e45b4859 --- /dev/null +++ b/packages/redux-devtools-extension/developmentOnly.d.ts @@ -0,0 +1 @@ +export * from 'redux-devtools-extension'; diff --git a/packages/redux-devtools-extension/developmentOnly.js b/packages/redux-devtools-extension/developmentOnly.js new file mode 100644 index 00000000..0294f1f9 --- /dev/null +++ b/packages/redux-devtools-extension/developmentOnly.js @@ -0,0 +1,26 @@ +'use strict'; + +var compose = require('redux').compose; + +exports.__esModule = true; +exports.composeWithDevTools = + process.env.NODE_ENV !== 'production' && + typeof window !== 'undefined' && + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + : function () { + if (arguments.length === 0) return undefined; + if (typeof arguments[0] === 'object') return compose; + return compose.apply(null, arguments); + }; + +exports.devToolsEnhancer = + process.env.NODE_ENV !== 'production' && + typeof window !== 'undefined' && + window.__REDUX_DEVTOOLS_EXTENSION__ + ? window.__REDUX_DEVTOOLS_EXTENSION__ + : function () { + return function (noop) { + return noop; + }; + }; diff --git a/packages/redux-devtools-extension/index.d.ts b/packages/redux-devtools-extension/index.d.ts new file mode 100644 index 00000000..f2e43cb5 --- /dev/null +++ b/packages/redux-devtools-extension/index.d.ts @@ -0,0 +1,174 @@ +import { Action, ActionCreator, StoreEnhancer, compose } from 'redux'; + +export interface EnhancerOptions { + /** + * the instance name to be showed on the monitor page. Default value is `document.title`. + * If not specified and there's no document title, it will consist of `tabId` and `instanceId`. + */ + name?: string; + /** + * action creators functions to be available in the Dispatcher. + */ + actionCreators?: ActionCreator<any>[] | { [key: string]: ActionCreator<any> }; + /** + * if more than one action is dispatched in the indicated interval, all new actions will be collected and sent at once. + * It is the joint between performance and speed. When set to `0`, all actions will be sent instantly. + * Set it to a higher value when experiencing perf issues (also `maxAge` to a lower value). + * + * @default 500 ms. + */ + latency?: number; + /** + * (> 1) - maximum allowed actions to be stored in the history tree. The oldest actions are removed once maxAge is reached. It's critical for performance. + * + * @default 50 + */ + maxAge?: number; + /** + * - `undefined` - will use regular `JSON.stringify` to send data (it's the fast mode). + * - `false` - will handle also circular references. + * - `true` - will handle also date, regex, undefined, error objects, symbols, maps, sets and functions. + * - object, which contains `date`, `regex`, `undefined`, `error`, `symbol`, `map`, `set` and `function` keys. + * For each of them you can indicate if to include (by setting as `true`). + * For `function` key you can also specify a custom function which handles serialization. + * See [`jsan`](https://github.com/kolodny/jsan) for more details. + */ + serialize?: + | boolean + | { + date?: boolean; + regex?: boolean; + undefined?: boolean; + error?: boolean; + symbol?: boolean; + map?: boolean; + set?: boolean; + function?: boolean | Function; + }; + /** + * function which takes `action` object and id number as arguments, and should return `action` object back. + */ + actionSanitizer?: <A extends Action>(action: A, id: number) => A; + /** + * function which takes `state` object and index as arguments, and should return `state` object back. + */ + stateSanitizer?: <S>(state: S, index: number) => S; + /** + * *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers). + * If `actionsWhitelist` specified, `actionsBlacklist` is ignored. + */ + actionsBlacklist?: string | string[]; + /** + * *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers). + * If `actionsWhitelist` specified, `actionsBlacklist` is ignored. + */ + actionsWhitelist?: string | string[]; + /** + * called for every action before sending, takes `state` and `action` object, and returns `true` in case it allows sending the current data to the monitor. + * Use it as a more advanced version of `actionsBlacklist`/`actionsWhitelist` parameters. + */ + predicate?: <S, A extends Action>(state: S, action: A) => boolean; + /** + * if specified as `false`, it will not record the changes till clicking on `Start recording` button. + * Available only for Redux enhancer, for others use `autoPause`. + * + * @default true + */ + shouldRecordChanges?: boolean; + /** + * if specified, whenever clicking on `Pause recording` button and there are actions in the history log, will add this action type. + * If not specified, will commit when paused. Available only for Redux enhancer. + * + * @default "@@PAUSED"" + */ + pauseActionType?: string; + /** + * auto pauses when the extension’s window is not opened, and so has zero impact on your app when not in use. + * Not available for Redux enhancer (as it already does it but storing the data to be sent). + * + * @default false + */ + autoPause?: boolean; + /** + * if specified as `true`, it will not allow any non-monitor actions to be dispatched till clicking on `Unlock changes` button. + * Available only for Redux enhancer. + * + * @default false + */ + shouldStartLocked?: boolean; + /** + * if set to `false`, will not recompute the states on hot reloading (or on replacing the reducers). Available only for Redux enhancer. + * + * @default true + */ + shouldHotReload?: boolean; + /** + * if specified as `true`, whenever there's an exception in reducers, the monitors will show the error message, and next actions will not be dispatched. + * + * @default false + */ + shouldCatchErrors?: boolean; + /** + * If you want to restrict the extension, specify the features you allow. + * If not specified, all of the features are enabled. When set as an object, only those included as `true` will be allowed. + * Note that except `true`/`false`, `import` and `export` can be set as `custom` (which is by default for Redux enhancer), meaning that the importing/exporting occurs on the client side. + * Otherwise, you'll get/set the data right from the monitor part. + */ + features?: { + /** + * start/pause recording of dispatched actions + */ + pause?: boolean; + /** + * lock/unlock dispatching actions and side effects + */ + lock?: boolean; + /** + * persist states on page reloading + */ + persist?: boolean; + /** + * export history of actions in a file + */ + export?: boolean | 'custom'; + /** + * import history of actions from a file + */ + import?: boolean | 'custom'; + /** + * jump back and forth (time travelling) + */ + jump?: boolean; + /** + * skip (cancel) actions + */ + skip?: boolean; + /** + * drag and drop actions in the history list + */ + reorder?: boolean; + /** + * dispatch custom actions or action creators + */ + dispatch?: boolean; + /** + * generate tests for the selected actions + */ + test?: boolean; + }; + /** + * Set to true or a stacktrace-returning function to record call stack traces for dispatched actions. + * Defaults to false. + */ + trace?: boolean | (<A extends Action>(action: A) => string); + /** + * The maximum number of stack trace entries to record per action. Defaults to 10. + */ + traceLimit?: number; +} + +export function composeWithDevTools<StoreExt, StateExt>( + ...funcs: Array<StoreEnhancer<StoreExt>> +): StoreEnhancer<StoreExt>; +export function composeWithDevTools(options: EnhancerOptions): typeof compose; +export function devToolsEnhancer(options: EnhancerOptions): StoreEnhancer<any>; diff --git a/packages/redux-devtools-extension/index.js b/packages/redux-devtools-extension/index.js new file mode 100644 index 00000000..02fca412 --- /dev/null +++ b/packages/redux-devtools-extension/index.js @@ -0,0 +1,22 @@ +'use strict'; + +var compose = require('redux').compose; + +exports.__esModule = true; +exports.composeWithDevTools = + typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + : function () { + if (arguments.length === 0) return undefined; + if (typeof arguments[0] === 'object') return compose; + return compose.apply(null, arguments); + }; + +exports.devToolsEnhancer = + typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ + ? window.__REDUX_DEVTOOLS_EXTENSION__ + : function () { + return function (noop) { + return noop; + }; + }; diff --git a/packages/redux-devtools-extension/logOnly.d.ts b/packages/redux-devtools-extension/logOnly.d.ts new file mode 100644 index 00000000..e45b4859 --- /dev/null +++ b/packages/redux-devtools-extension/logOnly.d.ts @@ -0,0 +1 @@ +export * from 'redux-devtools-extension'; diff --git a/packages/redux-devtools-extension/logOnly.js b/packages/redux-devtools-extension/logOnly.js new file mode 100644 index 00000000..8aa4237b --- /dev/null +++ b/packages/redux-devtools-extension/logOnly.js @@ -0,0 +1,60 @@ +'use strict'; + +var assign = require('./utils/assign'); +var compose = require('redux').compose; + +function enhancer() { + var config = arguments[0] || {}; + config.features = { pause: true, export: true, test: true }; + config.type = 'redux'; + if (config.autoPause === undefined) config.autoPause = true; + if (config.latency === undefined) config.latency = 500; + + return function (createStore) { + return function (reducer, preloadedState, enhancer) { + var store = createStore(reducer, preloadedState, enhancer); + var origDispatch = store.dispatch; + + var devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect(config); + devTools.init(store.getState()); + + var dispatch = function (action) { + var r = origDispatch(action); + devTools.send(action, store.getState()); + return r; + }; + + if (Object.assign) return Object.assign(store, { dispatch: dispatch }); + return assign(store, 'dispatch', dispatch); + }; + }; +} + +function composeWithEnhancer(config) { + return function () { + return compose(compose.apply(null, arguments), enhancer(config)); + }; +} + +exports.__esModule = true; +exports.composeWithDevTools = function () { + if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) { + if (arguments.length === 0) return enhancer(); + if (typeof arguments[0] === 'object') + return composeWithEnhancer(arguments[0]); + return composeWithEnhancer().apply(null, arguments); + } + + if (arguments.length === 0) return undefined; + if (typeof arguments[0] === 'object') return compose; + return compose.apply(null, arguments); +}; + +exports.devToolsEnhancer = + typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ + ? enhancer + : function () { + return function (noop) { + return noop; + }; + }; diff --git a/packages/redux-devtools-extension/logOnlyInProduction.d.ts b/packages/redux-devtools-extension/logOnlyInProduction.d.ts new file mode 100644 index 00000000..e45b4859 --- /dev/null +++ b/packages/redux-devtools-extension/logOnlyInProduction.d.ts @@ -0,0 +1 @@ +export * from 'redux-devtools-extension'; diff --git a/packages/redux-devtools-extension/logOnlyInProduction.js b/packages/redux-devtools-extension/logOnlyInProduction.js new file mode 100644 index 00000000..3c18b389 --- /dev/null +++ b/packages/redux-devtools-extension/logOnlyInProduction.js @@ -0,0 +1,28 @@ +'use strict'; + +var compose = require('redux').compose; +var logOnly = require('./logOnly'); + +exports.__esModule = true; +exports.composeWithDevTools = + process.env.NODE_ENV === 'production' + ? logOnly.composeWithDevTools + : typeof window !== 'undefined' && + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + : function () { + if (arguments.length === 0) return undefined; + if (typeof arguments[0] === 'object') return compose; + return compose.apply(null, arguments); + }; + +exports.devToolsEnhancer = + process.env.NODE_ENV === 'production' + ? logOnly.devToolsEnhancer + : typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ + ? window.__REDUX_DEVTOOLS_EXTENSION__ + : function () { + return function (noop) { + return noop; + }; + }; diff --git a/packages/redux-devtools-extension/package.json b/packages/redux-devtools-extension/package.json new file mode 100644 index 00000000..17f92c3e --- /dev/null +++ b/packages/redux-devtools-extension/package.json @@ -0,0 +1,16 @@ +{ + "name": "redux-devtools-extension", + "version": "2.13.8", + "description": "Wrappers for Redux DevTools Extension.", + "main": "index.js", + "repository": { + "type": "git", + "url": "https://github.com/zalmoxisus/redux-devtools-extension" + }, + "homepage": "https://github.com/zalmoxisus/redux-devtools-extension", + "author": "Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)", + "license": "MIT", + "peerDependencies": { + "redux": "^3.1.0 || ^4.0.0" + } +} diff --git a/packages/redux-devtools-extension/utils/assign.js b/packages/redux-devtools-extension/utils/assign.js new file mode 100644 index 00000000..75b70438 --- /dev/null +++ b/packages/redux-devtools-extension/utils/assign.js @@ -0,0 +1,24 @@ +var objectKeys = + Object.keys || + function (obj) { + var keys = []; + for (var key in obj) { + if ({}.hasOwnProperty.call(obj, key)) keys.push(key); + } + return keys; + }; + +function assign(obj, newKey, newValue) { + var keys = objectKeys(obj); + var copy = {}; + + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + copy[key] = obj[key]; + } + + copy[newKey] = newValue; + return copy; +} + +module.exports = assign; From 6782f4ae414c681e7ee733d21a678f6cd2f12f1d Mon Sep 17 00:00:00 2001 From: Nathan Bierema <nbierema@gmail.com> Date: Mon, 26 Oct 2020 08:18:23 -0400 Subject: [PATCH 11/25] chore(extension): add extension (#658) * Move extension * prettier --- extension/.babelrc | 4 + extension/.bookignore | 8 + extension/.eslintignore | 8 + extension/.eslintrc | 30 + extension/.gitignore | 9 + extension/.travis.yml | 32 + extension/CHANGELOG.md | 4 + extension/CODE_OF_CONDUCT.md | 63 + extension/LICENSE | 21 + extension/README.md | 325 + extension/SUMMARY.md | 1 + extension/appveyor.yml | 18 + extension/book.json | 18 + extension/docs/API/Arguments.md | 324 + extension/docs/API/Methods.md | 93 + extension/docs/API/README.md | 4 + extension/docs/Articles.md | 5 + extension/docs/Credits.md | 11 + extension/docs/FAQ.md | 45 + extension/docs/Features/Trace.md | 13 + extension/docs/Feedback.md | 5 + extension/docs/Integrations.md | 302 + extension/docs/README.md | 21 + extension/docs/Recipes.md | 78 + extension/docs/Troubleshooting.md | 129 + extension/docs/Videos.md | 6 + extension/examples/buildAll.js | 36 + extension/examples/counter/.babelrc | 3 + extension/examples/counter/actions/counter.js | 37 + .../examples/counter/components/Counter.js | 32 + extension/examples/counter/containers/App.js | 16 + extension/examples/counter/index.html | 10 + extension/examples/counter/index.js | 14 + extension/examples/counter/package.json | 41 + .../examples/counter/reducers/counter.js | 12 + extension/examples/counter/reducers/index.js | 8 + extension/examples/counter/server.js | 32 + .../examples/counter/store/configureStore.js | 28 + .../counter/test/actions/counter.spec.js | 73 + .../counter/test/components/Counter.spec.js | 53 + .../counter/test/containers/App.spec.js | 53 + .../counter/test/reducers/counter.spec.js | 23 + extension/examples/counter/test/setup.js | 5 + extension/examples/counter/webpack.config.js | 23 + .../examples/react-counter-messaging/.babelrc | 3 + .../components/Counter.js | 62 + .../react-counter-messaging/index.html | 10 + .../examples/react-counter-messaging/index.js | 5 + .../react-counter-messaging/package.json | 33 + .../react-counter-messaging/webpack.config.js | 25 + extension/examples/router/.babelrc | 4 + extension/examples/router/actions/todos.js | 25 + .../examples/router/components/Footer.js | 76 + .../examples/router/components/Header.js | 30 + .../examples/router/components/MainSection.js | 94 + .../examples/router/components/TodoItem.js | 75 + .../router/components/TodoTextInput.js | 59 + .../examples/router/constants/ActionTypes.js | 6 + .../examples/router/constants/TodoFilters.js | 3 + extension/examples/router/containers/App.js | 38 + extension/examples/router/containers/Root.js | 21 + .../examples/router/containers/Wrapper.js | 68 + extension/examples/router/index.html | 10 + extension/examples/router/index.js | 16 + extension/examples/router/package.json | 53 + extension/examples/router/reducers/index.js | 10 + extension/examples/router/reducers/todos.js | 61 + extension/examples/router/server.js | 32 + .../examples/router/store/configureStore.js | 28 + .../router/test/actions/todos.spec.js | 46 + .../router/test/components/Footer.spec.js | 108 + .../router/test/components/Header.spec.js | 50 + .../test/components/MainSection.spec.js | 150 + .../router/test/components/TodoItem.spec.js | 118 + .../test/components/TodoTextInput.spec.js | 84 + .../router/test/reducers/todos.spec.js | 325 + extension/examples/router/test/setup.js | 5 + extension/examples/router/webpack.config.js | 32 + extension/examples/saga-counter/.babelrc | 3 + extension/examples/saga-counter/index.html | 13 + extension/examples/saga-counter/package.json | 37 + .../saga-counter/src/components/Counter.js | 27 + extension/examples/saga-counter/src/main.js | 43 + .../saga-counter/src/reducers/index.js | 12 + .../examples/saga-counter/src/sagas/index.js | 14 + .../examples/saga-counter/webpack.config.js | 25 + extension/examples/todomvc/.babelrc | 3 + extension/examples/todomvc/actions/index.js | 1 + extension/examples/todomvc/actions/todos.js | 25 + .../examples/todomvc/components/Footer.js | 77 + .../examples/todomvc/components/Header.js | 30 + .../todomvc/components/MainSection.js | 95 + .../examples/todomvc/components/TodoItem.js | 76 + .../todomvc/components/TodoTextInput.js | 60 + .../examples/todomvc/constants/ActionTypes.js | 6 + .../examples/todomvc/constants/TodoFilters.js | 3 + extension/examples/todomvc/containers/App.js | 38 + extension/examples/todomvc/index.html | 10 + extension/examples/todomvc/index.js | 16 + extension/examples/todomvc/package.json | 42 + extension/examples/todomvc/reducers/index.js | 8 + extension/examples/todomvc/reducers/todos.js | 67 + extension/examples/todomvc/server.js | 32 + .../examples/todomvc/store/configureStore.js | 30 + .../todomvc/test/actions/todos.spec.js | 46 + .../todomvc/test/components/Footer.spec.js | 108 + .../todomvc/test/components/Header.spec.js | 50 + .../test/components/MainSection.spec.js | 150 + .../todomvc/test/components/TodoItem.spec.js | 118 + .../test/components/TodoTextInput.spec.js | 84 + .../todomvc/test/reducers/todos.spec.js | 325 + extension/examples/todomvc/test/setup.js | 5 + extension/examples/todomvc/webpack.config.js | 28 + extension/gulpfile.babel.js | 195 + extension/package.json | 92 + extension/src/app/api/filters.js | 179 + extension/src/app/api/generateInstanceId.js | 5 + extension/src/app/api/importState.js | 72 + extension/src/app/api/index.js | 389 + extension/src/app/api/notifyErrors.js | 47 + extension/src/app/api/openWindow.js | 10 + extension/src/app/containers/App.js | 201 + extension/src/app/middlewares/api.js | 264 + .../src/app/middlewares/instanceSelector.js | 41 + extension/src/app/middlewares/panelSync.js | 31 + extension/src/app/middlewares/windowSync.js | 23 + .../src/app/reducers/background/index.js | 10 + .../app/reducers/background/persistStates.js | 4 + extension/src/app/reducers/panel/index.js | 16 + extension/src/app/reducers/window/index.js | 18 + .../src/app/reducers/window/instances.js | 23 + extension/src/app/service/Monitor.js | 52 + extension/src/app/stores/backgroundStore.js | 18 + extension/src/app/stores/createStore.js | 5 + extension/src/app/stores/enhancerStore.js | 30 + extension/src/app/stores/panelStore.js | 14 + extension/src/app/stores/windowStore.js | 47 + extension/src/assets/img/loading.svg | 42 + extension/src/assets/img/logo/128x128.png | Bin 0 -> 20670 bytes extension/src/assets/img/logo/16x16.png | Bin 0 -> 1883 bytes extension/src/assets/img/logo/38x38.png | Bin 0 -> 4877 bytes extension/src/assets/img/logo/48x48.png | Bin 0 -> 6320 bytes extension/src/assets/img/logo/error.png | Bin 0 -> 1751 bytes extension/src/assets/img/logo/gray.png | Bin 0 -> 3640 bytes extension/src/assets/img/logo/scalable.png | Bin 0 -> 12915 bytes .../extension/background/contextMenus.js | 37 + .../extension/background/getPreloadedState.js | 34 + .../src/browser/extension/background/index.js | 28 + .../browser/extension/background/logging.js | 37 + .../extension/background/openWindow.js | 66 + .../src/browser/extension/chromeAPIMock.js | 92 + .../src/browser/extension/devpanel/index.js | 102 + .../src/browser/extension/devtools/index.js | 17 + .../browser/extension/inject/contentScript.js | 130 + .../extension/inject/deprecatedWarn.js | 7 + .../src/browser/extension/inject/index.js | 20 + .../browser/extension/inject/pageScript.js | 478 + .../extension/inject/pageScriptWrap.js | 15 + extension/src/browser/extension/manifest.json | 73 + .../extension/options/AllowToRunGroup.js | 52 + .../extension/options/ContextMenuGroup.js | 25 + .../browser/extension/options/EditorGroup.js | 82 + .../browser/extension/options/FilterGroup.js | 70 + .../extension/options/MiscellaneousGroup.js | 53 + .../src/browser/extension/options/Options.js | 38 + .../src/browser/extension/options/index.js | 23 + .../browser/extension/options/syncOptions.js | 109 + .../src/browser/extension/window/index.js | 36 + .../src/browser/extension/window/remote.js | 35 + extension/src/browser/firefox/manifest.json | 65 + extension/src/browser/views/devpanel.pug | 15 + extension/src/browser/views/devtools.pug | 10 + .../src/browser/views/includes/style.pug | 64 + extension/src/browser/views/options.pug | 93 + extension/src/browser/views/remote.pug | 11 + extension/src/browser/views/window.pug | 17 + extension/test/.eslintrc | 11 + extension/test/app/containers/App.spec.js | 25 + extension/test/app/inject/api.spec.js | 98 + extension/test/app/inject/enhancer.spec.js | 217 + extension/test/app/setup.js | 31 + extension/test/chrome/extension.spec.js | 88 + extension/test/electron/devpanel.spec.js | 109 + extension/test/electron/fixture/index.html | 13 + extension/test/electron/fixture/main.js | 18 + extension/test/electron/fixture/package.json | 6 + extension/test/electron/fixture/renderer.js | 34 + extension/test/perf/data.js | 3660 +++++++ extension/test/perf/send.spec.js | 26 + extension/test/utils/e2e.js | 47 + extension/test/utils/inject.js | 17 + extension/webpack/base.config.js | 84 + extension/webpack/dev.config.js | 20 + extension/webpack/prod.config.js | 11 + .../replace/JsonpMainTemplate.runtime.js | 76 + extension/webpack/replace/log-apply-result.js | 36 + extension/webpack/wrap.config.js | 14 + extension/yarn.lock | 9676 +++++++++++++++++ 198 files changed, 23627 insertions(+) create mode 100644 extension/.babelrc create mode 100644 extension/.bookignore create mode 100644 extension/.eslintignore create mode 100644 extension/.eslintrc create mode 100644 extension/.gitignore create mode 100644 extension/.travis.yml create mode 100644 extension/CHANGELOG.md create mode 100644 extension/CODE_OF_CONDUCT.md create mode 100644 extension/LICENSE create mode 100644 extension/README.md create mode 100644 extension/SUMMARY.md create mode 100644 extension/appveyor.yml create mode 100644 extension/book.json create mode 100644 extension/docs/API/Arguments.md create mode 100644 extension/docs/API/Methods.md create mode 100644 extension/docs/API/README.md create mode 100644 extension/docs/Articles.md create mode 100644 extension/docs/Credits.md create mode 100644 extension/docs/FAQ.md create mode 100644 extension/docs/Features/Trace.md create mode 100644 extension/docs/Feedback.md create mode 100644 extension/docs/Integrations.md create mode 100644 extension/docs/README.md create mode 100644 extension/docs/Recipes.md create mode 100644 extension/docs/Troubleshooting.md create mode 100644 extension/docs/Videos.md create mode 100644 extension/examples/buildAll.js create mode 100644 extension/examples/counter/.babelrc create mode 100644 extension/examples/counter/actions/counter.js create mode 100644 extension/examples/counter/components/Counter.js create mode 100644 extension/examples/counter/containers/App.js create mode 100644 extension/examples/counter/index.html create mode 100644 extension/examples/counter/index.js create mode 100644 extension/examples/counter/package.json create mode 100644 extension/examples/counter/reducers/counter.js create mode 100644 extension/examples/counter/reducers/index.js create mode 100644 extension/examples/counter/server.js create mode 100644 extension/examples/counter/store/configureStore.js create mode 100644 extension/examples/counter/test/actions/counter.spec.js create mode 100644 extension/examples/counter/test/components/Counter.spec.js create mode 100644 extension/examples/counter/test/containers/App.spec.js create mode 100644 extension/examples/counter/test/reducers/counter.spec.js create mode 100644 extension/examples/counter/test/setup.js create mode 100644 extension/examples/counter/webpack.config.js create mode 100644 extension/examples/react-counter-messaging/.babelrc create mode 100644 extension/examples/react-counter-messaging/components/Counter.js create mode 100644 extension/examples/react-counter-messaging/index.html create mode 100644 extension/examples/react-counter-messaging/index.js create mode 100644 extension/examples/react-counter-messaging/package.json create mode 100644 extension/examples/react-counter-messaging/webpack.config.js create mode 100644 extension/examples/router/.babelrc create mode 100644 extension/examples/router/actions/todos.js create mode 100644 extension/examples/router/components/Footer.js create mode 100644 extension/examples/router/components/Header.js create mode 100644 extension/examples/router/components/MainSection.js create mode 100644 extension/examples/router/components/TodoItem.js create mode 100644 extension/examples/router/components/TodoTextInput.js create mode 100644 extension/examples/router/constants/ActionTypes.js create mode 100644 extension/examples/router/constants/TodoFilters.js create mode 100644 extension/examples/router/containers/App.js create mode 100644 extension/examples/router/containers/Root.js create mode 100644 extension/examples/router/containers/Wrapper.js create mode 100644 extension/examples/router/index.html create mode 100644 extension/examples/router/index.js create mode 100644 extension/examples/router/package.json create mode 100644 extension/examples/router/reducers/index.js create mode 100644 extension/examples/router/reducers/todos.js create mode 100644 extension/examples/router/server.js create mode 100644 extension/examples/router/store/configureStore.js create mode 100644 extension/examples/router/test/actions/todos.spec.js create mode 100644 extension/examples/router/test/components/Footer.spec.js create mode 100644 extension/examples/router/test/components/Header.spec.js create mode 100644 extension/examples/router/test/components/MainSection.spec.js create mode 100644 extension/examples/router/test/components/TodoItem.spec.js create mode 100644 extension/examples/router/test/components/TodoTextInput.spec.js create mode 100644 extension/examples/router/test/reducers/todos.spec.js create mode 100644 extension/examples/router/test/setup.js create mode 100644 extension/examples/router/webpack.config.js create mode 100644 extension/examples/saga-counter/.babelrc create mode 100644 extension/examples/saga-counter/index.html create mode 100644 extension/examples/saga-counter/package.json create mode 100644 extension/examples/saga-counter/src/components/Counter.js create mode 100644 extension/examples/saga-counter/src/main.js create mode 100644 extension/examples/saga-counter/src/reducers/index.js create mode 100644 extension/examples/saga-counter/src/sagas/index.js create mode 100644 extension/examples/saga-counter/webpack.config.js create mode 100644 extension/examples/todomvc/.babelrc create mode 100644 extension/examples/todomvc/actions/index.js create mode 100644 extension/examples/todomvc/actions/todos.js create mode 100644 extension/examples/todomvc/components/Footer.js create mode 100644 extension/examples/todomvc/components/Header.js create mode 100644 extension/examples/todomvc/components/MainSection.js create mode 100644 extension/examples/todomvc/components/TodoItem.js create mode 100644 extension/examples/todomvc/components/TodoTextInput.js create mode 100644 extension/examples/todomvc/constants/ActionTypes.js create mode 100644 extension/examples/todomvc/constants/TodoFilters.js create mode 100644 extension/examples/todomvc/containers/App.js create mode 100644 extension/examples/todomvc/index.html create mode 100644 extension/examples/todomvc/index.js create mode 100644 extension/examples/todomvc/package.json create mode 100644 extension/examples/todomvc/reducers/index.js create mode 100644 extension/examples/todomvc/reducers/todos.js create mode 100644 extension/examples/todomvc/server.js create mode 100644 extension/examples/todomvc/store/configureStore.js create mode 100644 extension/examples/todomvc/test/actions/todos.spec.js create mode 100644 extension/examples/todomvc/test/components/Footer.spec.js create mode 100644 extension/examples/todomvc/test/components/Header.spec.js create mode 100644 extension/examples/todomvc/test/components/MainSection.spec.js create mode 100644 extension/examples/todomvc/test/components/TodoItem.spec.js create mode 100644 extension/examples/todomvc/test/components/TodoTextInput.spec.js create mode 100644 extension/examples/todomvc/test/reducers/todos.spec.js create mode 100644 extension/examples/todomvc/test/setup.js create mode 100644 extension/examples/todomvc/webpack.config.js create mode 100644 extension/gulpfile.babel.js create mode 100644 extension/package.json create mode 100644 extension/src/app/api/filters.js create mode 100644 extension/src/app/api/generateInstanceId.js create mode 100644 extension/src/app/api/importState.js create mode 100644 extension/src/app/api/index.js create mode 100644 extension/src/app/api/notifyErrors.js create mode 100644 extension/src/app/api/openWindow.js create mode 100644 extension/src/app/containers/App.js create mode 100644 extension/src/app/middlewares/api.js create mode 100644 extension/src/app/middlewares/instanceSelector.js create mode 100644 extension/src/app/middlewares/panelSync.js create mode 100644 extension/src/app/middlewares/windowSync.js create mode 100644 extension/src/app/reducers/background/index.js create mode 100644 extension/src/app/reducers/background/persistStates.js create mode 100644 extension/src/app/reducers/panel/index.js create mode 100644 extension/src/app/reducers/window/index.js create mode 100644 extension/src/app/reducers/window/instances.js create mode 100644 extension/src/app/service/Monitor.js create mode 100644 extension/src/app/stores/backgroundStore.js create mode 100644 extension/src/app/stores/createStore.js create mode 100644 extension/src/app/stores/enhancerStore.js create mode 100644 extension/src/app/stores/panelStore.js create mode 100644 extension/src/app/stores/windowStore.js create mode 100644 extension/src/assets/img/loading.svg create mode 100644 extension/src/assets/img/logo/128x128.png create mode 100644 extension/src/assets/img/logo/16x16.png create mode 100644 extension/src/assets/img/logo/38x38.png create mode 100644 extension/src/assets/img/logo/48x48.png create mode 100644 extension/src/assets/img/logo/error.png create mode 100644 extension/src/assets/img/logo/gray.png create mode 100644 extension/src/assets/img/logo/scalable.png create mode 100644 extension/src/browser/extension/background/contextMenus.js create mode 100644 extension/src/browser/extension/background/getPreloadedState.js create mode 100644 extension/src/browser/extension/background/index.js create mode 100644 extension/src/browser/extension/background/logging.js create mode 100644 extension/src/browser/extension/background/openWindow.js create mode 100644 extension/src/browser/extension/chromeAPIMock.js create mode 100644 extension/src/browser/extension/devpanel/index.js create mode 100644 extension/src/browser/extension/devtools/index.js create mode 100644 extension/src/browser/extension/inject/contentScript.js create mode 100644 extension/src/browser/extension/inject/deprecatedWarn.js create mode 100644 extension/src/browser/extension/inject/index.js create mode 100644 extension/src/browser/extension/inject/pageScript.js create mode 100644 extension/src/browser/extension/inject/pageScriptWrap.js create mode 100644 extension/src/browser/extension/manifest.json create mode 100644 extension/src/browser/extension/options/AllowToRunGroup.js create mode 100644 extension/src/browser/extension/options/ContextMenuGroup.js create mode 100644 extension/src/browser/extension/options/EditorGroup.js create mode 100644 extension/src/browser/extension/options/FilterGroup.js create mode 100644 extension/src/browser/extension/options/MiscellaneousGroup.js create mode 100644 extension/src/browser/extension/options/Options.js create mode 100644 extension/src/browser/extension/options/index.js create mode 100644 extension/src/browser/extension/options/syncOptions.js create mode 100644 extension/src/browser/extension/window/index.js create mode 100644 extension/src/browser/extension/window/remote.js create mode 100644 extension/src/browser/firefox/manifest.json create mode 100644 extension/src/browser/views/devpanel.pug create mode 100644 extension/src/browser/views/devtools.pug create mode 100644 extension/src/browser/views/includes/style.pug create mode 100644 extension/src/browser/views/options.pug create mode 100644 extension/src/browser/views/remote.pug create mode 100644 extension/src/browser/views/window.pug create mode 100644 extension/test/.eslintrc create mode 100644 extension/test/app/containers/App.spec.js create mode 100644 extension/test/app/inject/api.spec.js create mode 100644 extension/test/app/inject/enhancer.spec.js create mode 100644 extension/test/app/setup.js create mode 100644 extension/test/chrome/extension.spec.js create mode 100644 extension/test/electron/devpanel.spec.js create mode 100644 extension/test/electron/fixture/index.html create mode 100644 extension/test/electron/fixture/main.js create mode 100644 extension/test/electron/fixture/package.json create mode 100644 extension/test/electron/fixture/renderer.js create mode 100644 extension/test/perf/data.js create mode 100644 extension/test/perf/send.spec.js create mode 100644 extension/test/utils/e2e.js create mode 100644 extension/test/utils/inject.js create mode 100644 extension/webpack/base.config.js create mode 100644 extension/webpack/dev.config.js create mode 100644 extension/webpack/prod.config.js create mode 100644 extension/webpack/replace/JsonpMainTemplate.runtime.js create mode 100644 extension/webpack/replace/log-apply-result.js create mode 100644 extension/webpack/wrap.config.js create mode 100644 extension/yarn.lock diff --git a/extension/.babelrc b/extension/.babelrc new file mode 100644 index 00000000..6cc845b9 --- /dev/null +++ b/extension/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["es2015", "stage-0", "react"], + "plugins": ["add-module-exports", "transform-decorators-legacy"] +} diff --git a/extension/.bookignore b/extension/.bookignore new file mode 100644 index 00000000..91baa0de --- /dev/null +++ b/extension/.bookignore @@ -0,0 +1,8 @@ +src/ +build/ +dev/ +examples/ +npm-package/ +test/ +package.json +webpack/ \ No newline at end of file diff --git a/extension/.eslintignore b/extension/.eslintignore new file mode 100644 index 00000000..4a232330 --- /dev/null +++ b/extension/.eslintignore @@ -0,0 +1,8 @@ +node_modules +build +dev +webpack/replace +examples +test/app/setup.js +npm-package +_book diff --git a/extension/.eslintrc b/extension/.eslintrc new file mode 100644 index 00000000..7cbb31e0 --- /dev/null +++ b/extension/.eslintrc @@ -0,0 +1,30 @@ +{ + "extends": "eslint-config-airbnb", + "globals": { + "chrome": true, + "__DEVELOPMENT__": true + }, + "env": { + "browser": true, + "node": true + }, + "rules": { + "react/jsx-uses-react": 2, + "react/jsx-uses-vars": 2, + "react/react-in-jsx-scope": 2, + "react/jsx-quotes": 0, + "block-scoped-var": 0, + "padded-blocks": 0, + "quotes": [1, "single"], + "comma-style": [2, "last"], + "no-use-before-define": [0, "nofunc"], + "func-names": 0, + "prefer-const": 0, + "comma-dangle": 0, + "id-length": 0, + "indent": [2, 2, { "SwitchCase": 1 }], + "new-cap": [2, { "capIsNewExceptions": ["Test"] }], + "default-case": 0 + }, + "plugins": ["react"] +} diff --git a/extension/.gitignore b/extension/.gitignore new file mode 100644 index 00000000..bbe0a464 --- /dev/null +++ b/extension/.gitignore @@ -0,0 +1,9 @@ +node_modules +npm-debug.log +.DS_Store +.idea/ +dist/ +build/ +dev/ +tmp/ +_book diff --git a/extension/.travis.yml b/extension/.travis.yml new file mode 100644 index 00000000..d03640f9 --- /dev/null +++ b/extension/.travis.yml @@ -0,0 +1,32 @@ +sudo: required +dist: trusty +language: node_js +node_js: + - '6' +cache: + directories: + - $HOME/.yarn-cache + - node_modules +env: + - CXX=g++-4.8 +addons: + apt: + sources: + - google-chrome + - ubuntu-toolchain-r-test + packages: + - google-chrome-stable + - g++-4.8 + +install: + - '/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16' + - npm install -g yarn + - yarn install + +before_script: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start & + - sleep 3 + +script: + - yarn test diff --git a/extension/CHANGELOG.md b/extension/CHANGELOG.md new file mode 100644 index 00000000..00b64307 --- /dev/null +++ b/extension/CHANGELOG.md @@ -0,0 +1,4 @@ +# Change Log + +This project adheres to [Semantic Versioning](http://semver.org/). +Every release, along with the migration instructions, is documented on the Github [Releases](https://github.com/zalmoxisus/redux-devtools-extension/releases) page. diff --git a/extension/CODE_OF_CONDUCT.md b/extension/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..c44e8369 --- /dev/null +++ b/extension/CODE_OF_CONDUCT.md @@ -0,0 +1,63 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/extension/LICENSE b/extension/LICENSE new file mode 100644 index 00000000..b34f2934 --- /dev/null +++ b/extension/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-present Mihail Diordiev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/extension/README.md b/extension/README.md new file mode 100644 index 00000000..74167cce --- /dev/null +++ b/extension/README.md @@ -0,0 +1,325 @@ +# Redux DevTools Extension + +[![Join the chat at https://gitter.im/zalmoxisus/redux-devtools-extension](https://badges.gitter.im/zalmoxisus/redux-devtools-extension.svg)](https://gitter.im/zalmoxisus/redux-devtools-extension?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=round-square)](http://makeapullrequest.com) +[![OpenCollective](https://opencollective.com/redux-devtools-extension/backers/badge.svg)](#backers) +[![OpenCollective](https://opencollective.com/redux-devtools-extension/sponsors/badge.svg)](#sponsors) + +![Demo](https://cloud.githubusercontent.com/assets/7957859/18002950/aacb82fc-6b93-11e6-9ae9-609862c18302.png) + +## Installation + +### 1. For Chrome + +- from [Chrome Web Store](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd); +- or download `extension.zip` from [last releases](https://github.com/zalmoxisus/redux-devtools-extension/releases), unzip, open `chrome://extensions` url and turn on developer mode from top left and then click; on `Load Unpacked` and select the extracted folder for use +- or build it with `npm i && npm run build:extension` and [load the extension's folder](https://developer.chrome.com/extensions/getstarted#unpacked) `./build/extension`; +- or run it in dev mode with `npm i && npm start` and [load the extension's folder](https://developer.chrome.com/extensions/getstarted#unpacked) `./dev`. + +### 2. For Firefox + +- from [Mozilla Add-ons](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/); +- or build it with `npm i && npm run build:firefox` and [load the extension's folder](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox) `./build/firefox` (just select a file from inside the dir). + +### 3. For Electron + +- just specify `REDUX_DEVTOOLS` in [`electron-devtools-installer`](https://github.com/GPMDP/electron-devtools-installer). + +### 4. For other browsers and non-browser environment + +- use [`remote-redux-devtools`](https://github.com/zalmoxisus/remote-redux-devtools). + +## Usage + +> Note that starting from v2.7, `window.devToolsExtension` was renamed to `window.__REDUX_DEVTOOLS_EXTENSION__` / `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__`. + +## 1. With Redux + +### 1.1 Basic store + +For a basic [Redux store](https://redux.js.org/api/createstore#createstorereducer-preloadedstate-enhancer) simply add: + +```diff + const store = createStore( + reducer, /* preloadedState, */ ++ window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() + ); +``` + +Note that [`preloadedState`](https://redux.js.org/api/createstore#createstorereducer-preloadedstate-enhancer) argument is optional in Redux's [`createStore`](https://redux.js.org/api/createstore#createstorereducer-preloadedstate-enhancer). + +> For universal ("isomorphic") apps, prefix it with `typeof window !== 'undefined' &&`. + +```js +const composeEnhancers = + (typeof window !== 'undefined' && + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || + compose; +``` + +> For TypeScript use [`redux-devtools-extension` npm package](#13-use-redux-devtools-extension-package-from-npm), which contains all the definitions, or just use `(window as any)` (see [Recipes](/docs/Recipes.md#using-in-a-typescript-project) for an example). + +```js +const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; +``` + +In case ESLint is configured to not allow using the underscore dangle, wrap it like so: + +```diff ++ /* eslint-disable no-underscore-dangle */ + const store = createStore( + reducer, /* preloadedState, */ + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() + ); ++ /* eslint-enable */ +``` + +> **Note**: Passing enhancer as last argument requires **redux@>=3.1.0**. For older versions apply it like [here](https://github.com/zalmoxisus/redux-devtools-extension/blob/v0.4.2/examples/todomvc/store/configureStore.js) or [here](https://github.com/zalmoxisus/redux-devtools-extension/blob/v0.4.2/examples/counter/store/configureStore.js#L7-L12). Don't mix the old Redux API with the new one. + +> You don't need to npm install [`redux-devtools`](https://github.com/gaearon/redux-devtools) when using the extension (that's a different lib). + +### 1.2 Advanced store setup + +If you setup your store with [middleware and enhancers](http://redux.js.org/docs/api/applyMiddleware.html), change: + +```diff + import { createStore, applyMiddleware, compose } from 'redux'; + ++ const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; ++ const store = createStore(reducer, /* preloadedState, */ composeEnhancers( +- const store = createStore(reducer, /* preloadedState, */ compose( + applyMiddleware(...middleware) + )); +``` + +> Note that when the extension is not installed, we’re using Redux compose here. + +To specify [extension’s options](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md), use it like so: + +```js +const composeEnhancers = + typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ + // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize... + }) + : compose; + +const enhancer = composeEnhancers( + applyMiddleware(...middleware) + // other store enhancers if any +); +const store = createStore(reducer, enhancer); +``` + +> [See the post for more details](https://medium.com/@zalmoxis/improve-your-development-workflow-with-redux-devtools-extension-f0379227ff83). + +### 1.3 Use `redux-devtools-extension` package from npm + +To make things easier, there's an npm package to install: + +``` +npm install --save redux-devtools-extension +``` + +and to use like so: + +```js +import { createStore, applyMiddleware } from 'redux'; +import { composeWithDevTools } from 'redux-devtools-extension'; + +const store = createStore( + reducer, + composeWithDevTools( + applyMiddleware(...middleware) + // other store enhancers if any + ) +); +``` + +To specify [extension’s options](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md#windowdevtoolsextensionconfig): + +```js +import { createStore, applyMiddleware } from 'redux'; +import { composeWithDevTools } from 'redux-devtools-extension'; + +const composeEnhancers = composeWithDevTools({ + // Specify name here, actionsBlacklist, actionsCreators and other options if needed +}); +const store = createStore( + reducer, + /* preloadedState, */ composeEnhancers( + applyMiddleware(...middleware) + // other store enhancers if any + ) +); +``` + +> There’re just [few lines of code](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/npm-package/index.js) added to your bundle. + +In case you don't include other enhancers and middlewares, just use `devToolsEnhancer`: + +```js +import { createStore } from 'redux'; +import { devToolsEnhancer } from 'redux-devtools-extension'; + +const store = createStore( + reducer, + /* preloadedState, */ devToolsEnhancer() + // Specify name here, actionsBlacklist, actionsCreators and other options if needed +); +``` + +### 1.4 Using in production + +It's useful to include the extension in production as well. Usually you [can use it for development](https://medium.com/@zalmoxis/using-redux-devtools-in-production-4c5b56c5600f). + +If you want to restrict it there, use `redux-devtools-extension/logOnlyInProduction`: + +```js +import { createStore } from 'redux'; +import { devToolsEnhancer } from 'redux-devtools-extension/logOnlyInProduction'; + +const store = createStore( + reducer, + /* preloadedState, */ devToolsEnhancer() + // options like actionSanitizer, stateSanitizer +); +``` + +or with middlewares and enhancers: + +```js +import { createStore, applyMiddleware } from 'redux'; +import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction'; + +const composeEnhancers = composeWithDevTools({ + // options like actionSanitizer, stateSanitizer +}); +const store = createStore( + reducer, + /* preloadedState, */ composeEnhancers( + applyMiddleware(...middleware) + // other store enhancers if any + ) +); +``` + +> You'll have to add `'process.env.NODE_ENV': JSON.stringify('production')` in your Webpack config for the production bundle ([to envify](https://github.com/gaearon/redux-devtools/blob/master/docs/Walkthrough.md#exclude-devtools-from-production-builds)). If you use `create-react-app`, [it already does it for you.](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/config/webpack.config.prod.js#L253-L257) + +If you're already checking `process.env.NODE_ENV` when creating the store, include `redux-devtools-extension/logOnly` for production environment. + +If you don’t want to allow the extension in production, just use `redux-devtools-extension/developmentOnly`. + +> See [the article](https://medium.com/@zalmoxis/using-redux-devtools-in-production-4c5b56c5600f) for more details. + +### 1.5 For React Native, hybrid, desktop and server side Redux apps + +For React Native we can use [`react-native-debugger`](https://github.com/jhen0409/react-native-debugger), which already included [the same API](https://github.com/jhen0409/react-native-debugger/blob/master/docs/redux-devtools-integration.md) with Redux DevTools Extension. + +For most platforms, include [`Remote Redux DevTools`](https://github.com/zalmoxisus/remote-redux-devtools)'s store enhancer, and from the extension's context menu choose 'Open Remote DevTools' for remote monitoring. + +## 2. Without Redux + +See [integrations](docs/Integrations.md) and [the blog post](https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f) for more details on how to use the extension with any architecture. + +## Docs + +- [Options (arguments)](docs/API/Arguments.md) +- [Methods (advanced API)](docs/API/Methods.md) +- [FAQ](docs/FAQ.md) +- Features + - [Trace actions calls](/docs/Features/Trace.md) +- [Troubleshooting](docs/Troubleshooting.md) +- [Articles](docs/Articles.md) +- [Videos](docs/Videos.md) +- [Feedback](docs/Feedback.md) + +## Demo + +Live demos to use the extension with: + +- [Counter](http://zalmoxisus.github.io/examples/counter/) +- [TodoMVC](http://zalmoxisus.github.io/examples/todomvc/) +- [Redux Form](http://redux-form.com/6.5.0/examples/simple/) +- [React Tetris](https://chvin.github.io/react-tetris/?lan=en) +- [Book Collection (Angular ngrx store)](https://ngrx.github.io/platform/example-app/) + +Also see [`./examples` folder](https://github.com/zalmoxisus/redux-devtools-extension/tree/master/examples). + +## Backers + +Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/redux-devtools-extension#backer)] + +<a href="https://opencollective.com/redux-devtools-extension/backer/0/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/0/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/1/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/1/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/2/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/2/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/3/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/3/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/4/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/4/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/5/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/5/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/6/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/6/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/7/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/7/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/8/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/8/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/9/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/9/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/10/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/10/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/11/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/11/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/12/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/12/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/13/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/13/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/14/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/14/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/15/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/15/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/16/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/16/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/17/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/17/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/18/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/18/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/19/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/19/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/20/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/20/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/21/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/21/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/22/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/22/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/23/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/23/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/24/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/24/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/25/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/25/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/26/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/26/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/27/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/27/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/28/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/28/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/backer/29/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/backer/29/avatar.svg"></a> + +## Sponsors + +Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/redux-devtools-extension#sponsor)] + +<a href="https://opencollective.com/redux-devtools-extension/sponsor/0/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/0/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/1/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/1/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/2/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/2/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/3/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/3/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/4/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/4/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/5/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/5/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/6/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/6/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/7/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/7/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/8/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/8/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/9/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/9/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/10/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/10/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/11/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/11/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/12/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/12/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/13/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/13/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/14/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/14/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/15/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/15/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/16/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/16/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/17/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/17/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/18/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/18/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/19/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/19/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/20/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/20/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/21/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/21/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/22/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/22/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/23/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/23/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/24/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/24/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/25/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/25/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/26/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/26/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/27/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/27/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/28/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/28/avatar.svg"></a> +<a href="https://opencollective.com/redux-devtools-extension/sponsor/29/website" target="_blank"><img src="https://opencollective.com/redux-devtools-extension/sponsor/29/avatar.svg"></a> + +## License + +MIT + +## Created By + +If you like this, follow [@mdiordiev](https://twitter.com/mdiordiev) on twitter. diff --git a/extension/SUMMARY.md b/extension/SUMMARY.md new file mode 100644 index 00000000..542612fd --- /dev/null +++ b/extension/SUMMARY.md @@ -0,0 +1 @@ +./docs/README.md diff --git a/extension/appveyor.yml b/extension/appveyor.yml new file mode 100644 index 00000000..884e5b13 --- /dev/null +++ b/extension/appveyor.yml @@ -0,0 +1,18 @@ +environment: + matrix: + - nodejs_version: '6' + +cache: + - '%LOCALAPPDATA%/Yarn' + - node_modules + +install: + - ps: Install-Product node $env:nodejs_version + - yarn install + +test_script: + - node --version + - yarn --version + - yarn test + +build: off diff --git a/extension/book.json b/extension/book.json new file mode 100644 index 00000000..d7f27743 --- /dev/null +++ b/extension/book.json @@ -0,0 +1,18 @@ +{ + "gitbook": "3.2.2", + "title": "Redux DevTools Extension", + "plugins": ["edit-link", "prism", "-highlight", "github", "anchorjs"], + "pluginsConfig": { + "edit-link": { + "base": "https://github.com/zalmoxisus/redux-devtools-extension/tree/master", + "label": "Edit This Page" + }, + "github": { + "url": "https://github.com/zalmoxisus/redux-devtools-extension/" + }, + "sharing": { + "facebook": true, + "twitter": true + } + } +} diff --git a/extension/docs/API/Arguments.md b/extension/docs/API/Arguments.md new file mode 100644 index 00000000..fe632424 --- /dev/null +++ b/extension/docs/API/Arguments.md @@ -0,0 +1,324 @@ +# Options + +Use with + +- `window.__REDUX_DEVTOOLS_EXTENSION__([options])` +- `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__([options])()` +- `window.__REDUX_DEVTOOLS_EXTENSION__.connect([options])` +- `redux-devtools-extension` npm package: + +```js +import { composeWithDevTools } from 'redux-devtools-extension'; + +const composeEnhancers = composeWithDevTools(options); +const store = createStore( + reducer, + /* preloadedState, */ composeEnhancers( + applyMiddleware(...middleware) + // other store enhancers if any + ) +); +``` + +The `options` object is optional, and can include any of the following. + +### `name` + +_string_ - the instance name to be shown on the monitor page. Default value is `document.title`. If not specified and there's no document title, it will consist of `tabId` and `instanceId`. + +### `actionCreators` + +_array_ or _object_ - action creators functions to be available in the Dispatcher. See [the example](https://github.com/zalmoxisus/redux-devtools-extension/commit/477e69d8649dfcdc9bf84dd45605dab7d9775c03). + +### `latency` + +_number (in ms)_ - if more than one action is dispatched in the indicated interval, all new actions will be collected and sent at once. It is the joint between performance and speed. When set to `0`, all actions will be sent instantly. Set it to a higher value when experiencing perf issues (also `maxAge` to a lower value). Default is `500 ms`. + +### `maxAge` + +_number_ (>1) - maximum allowed actions to be stored in the history tree. The oldest actions are removed once maxAge is reached. It's critical for performance. Default is `50`. + +### `trace` + +_boolean_ or _function_ - if set to `true`, will include stack trace for every dispatched action, so you can see it in trace tab jumping directly to that part of code ([more details](../Features/Trace.md)). You can use a function (with action object as argument) which should return `new Error().stack` string, getting the stack outside of reducers. Default to `false`. + +### `traceLimit` + +_number_ - maximum stack trace frames to be stored (in case `trace` option was provided as `true`). By default it's `10`. Note that, because extension's calls are excluded, the resulted frames could be 1 less. If `trace` option is a function, `traceLimit` will have no effect, as it's supposed to be handled there. + +### `serialize` + +_boolean_ or _object_ which contains: + +- **options** `object or boolean`: + + - `undefined` - will use regular `JSON.stringify` to send data (it's the fast mode). + - `false` - will handle also circular references. + - `true` - will handle also date, regex, undefined, primitives, error objects, symbols, maps, sets and functions. + - object, which contains `date`, `regex`, `undefined`, `nan`, `infinity`, `error`, `symbol`, `map`, `set` and `function` keys. For each of them you can indicate if to include (by setting as `true`). For `function` key you can also specify a custom function which handles serialization. See [`jsan`](https://github.com/kolodny/jsan) for more details. Example: + + ```js + const store = Redux.createStore( + reducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && + window.__REDUX_DEVTOOLS_EXTENSION__({ + serialize: { + options: { + undefined: true, + function: function (fn) { + return fn.toString(); + }, + }, + }, + }) + ); + ``` + +- **replacer** `function(key, value)` - [JSON `replacer` function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter) used for both actions and states stringify. + + Example of usage with [mori data structures](https://github.com/swannodette/mori): + + ```js + const store = Redux.createStore( + reducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && + window.__REDUX_DEVTOOLS_EXTENSION__({ + serialize: { + replacer: (key, value) => + value && mori.isMap(value) ? mori.toJs(value) : value, + }, + }) + ); + ``` + + In addition, you can specify a data type by adding a [`__serializedType__`](https://github.com/zalmoxisus/remotedev-serialize/blob/master/helpers/index.js#L4) key. So you can deserialize it back while importing or persisting data. Moreover, it will also [show a nice preview showing the provided custom type](https://cloud.githubusercontent.com/assets/7957859/21814330/a17d556a-d761-11e6-85ef-159dd12f36c5.png): + + ```js + const store = Redux.createStore( + reducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && + window.__REDUX_DEVTOOLS_EXTENSION__({ + serialize: { + replacer: (key, value) => { + if (Immutable.List.isList(value)) { + // use your custom data type checker + return { + data: value.toArray(), // ImmutableJS custom method to get JS data as array + __serializedType__: 'ImmutableList', // mark you custom data type to show and retrieve back + }; + } + }, + }, + }) + ); + ``` + +- **reviver** `function(key, value)` - [JSON `reviver` function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter) used for parsing the imported actions and states. See [`remotedev-serialize`](https://github.com/zalmoxisus/remotedev-serialize/blob/master/immutable/serialize.js#L8-L41) as an example on how to serialize special data types and get them back: + + ```js + const store = Redux.createStore( + reducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && + window.__REDUX_DEVTOOLS_EXTENSION__({ + serialize: { + reviver: (key, value) => { + if ( + typeof value === 'object' && + value !== null && + '__serializedType__' in value + ) { + switch (value.__serializedType__) { + case 'ImmutableList': + return Immutable.List(value.data); + } + } + }, + }, + }) + ); + ``` + +- **immutable** `object` - automatically serialize/deserialize immutablejs via [remotedev-serialize](https://github.com/zalmoxisus/remotedev-serialize). Just pass the Immutable library like so: + + ```js + import Immutable from 'immutable'; // https://facebook.github.io/immutable-js/ + // ... + // Like above, only showing off compose this time. Reminder you might not want this in prod. + const composeEnhancers = + typeof window === 'object' && + typeof window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ !== 'undefined' + ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ + serialize: { + immutable: Immutable, + }, + }) + : compose; + ``` + + It will support all ImmutableJS structures. You can even export them into a file and get them back. The only exception is `Record` class, for which you should pass in addition the references to your classes in `refs`. + +- **refs** `array` - ImmutableJS `Record` classes used to make possible restore its instances back when importing, persisting... Example of usage: + + ```js + import Immutable from 'immutable'; + // ... + + const ABRecord = Immutable.Record({ a: 1, b: 2 }); + const myRecord = new ABRecord({ b: 3 }); // used in the reducers + + const store = createStore( + rootReducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && + window.__REDUX_DEVTOOLS_EXTENSION__({ + serialize: { + immutable: Immutable, + refs: [ABRecord], + }, + }) + ); + ``` + +Also you can specify alternative values right in the state object (in the initial state of the reducer) by adding `toJSON` function: + +In the example bellow it will always send `{ component: '[React]' }`, regardless of the state's `component` value (useful when you don't want to send lots of unnecessary data): + +```js +function component( + state = { component: null, toJSON: () => ({ component: '[React]' }) }, + action +) { + switch (action.type) { + case 'ADD_COMPONENT': + return { component: action.component }; + default: + return state; + } +} +``` + +You could also alter the value. For example when state is `{ count: 1 }`, we'll send `{ counter: 10 }` (notice we don't have an arrow function this time to use the object's `this`): + +```js +function counter( + state = { + count: 0, + toJSON: function () { + return { conter: this.count * 10 }; + }, + }, + action +) { + switch (action.type) { + case 'INCREMENT': + return { count: state.count + 1 }; + default: + return state; + } +} +``` + +### `actionSanitizer` / `stateSanitizer` + +- **actionSanitizer** (_function_) - function which takes `action` object and id number as arguments, and should return `action` object back. See the example bellow. +- **stateSanitizer** (_function_) - function which takes `state` object and index as arguments, and should return `state` object back. + +Example of usage: + +```js +const actionSanitizer = (action) => + action.type === 'FILE_DOWNLOAD_SUCCESS' && action.data + ? { ...action, data: '<<LONG_BLOB>>' } + : action; +const store = createStore( + rootReducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && + window.__REDUX_DEVTOOLS_EXTENSION__({ + actionSanitizer, + stateSanitizer: (state) => + state.data ? { ...state, data: '<<LONG_BLOB>>' } : state, + }) +); +``` + +### `actionsBlacklist` / `actionsWhitelist` + +_string or array of strings as regex_ - actions types to be hidden / shown in the monitors (while passed to the reducers). If `actionsWhitelist` specified, `actionsBlacklist` is ignored. + +Example: + +```js +createStore( + reducer, + remotedev({ + sendTo: 'http://localhost:8000', + actionsBlacklist: 'SOME_ACTION', + // or actionsBlacklist: ['SOME_ACTION', 'SOME_OTHER_ACTION'] + // or just actionsBlacklist: 'SOME_' to omit both + }) +); +``` + +### `predicate` + +_function_ - called for every action before sending, takes `state` and `action` object, and returns `true` in case it allows sending the current data to the monitor. Use it as a more advanced version of `actionsBlacklist`/`actionsWhitelist` parameters. +Example of usage: + +```js +const store = createStore( + rootReducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && + window.__REDUX_DEVTOOLS_EXTENSION__({ + predicate: (state, action) => + state.dev.logLevel === VERBOSE && !action.forwarded, + }) +); +``` + +### `shouldRecordChanges` + +_boolean_ - if specified as `false`, it will not record the changes till clicking on `Start recording` button. Default is `true`. Available only for Redux enhancer, for others use `autoPause`. + +### `pauseActionType` + +_string_ - if specified, whenever clicking on `Pause recording` button and there are actions in the history log, will add this action type. If not specified, will commit when paused. Available only for Redux enhancer. Default is `@@PAUSED`. + +### `autoPause` + +_boolean_ - auto pauses when the extension’s window is not opened, and so has zero impact on your app when not in use. Not available for Redux enhancer (as it already does it but storing the data to be sent). Default is `false`. + +### `shouldStartLocked` + +_boolean_ - if specified as `true`, it will not allow any non-monitor actions to be dispatched till clicking on `Unlock changes` button. Available only for Redux enhancer. Default is `false`. + +### `shouldHotReload` + +_boolean_ - if set to `false`, will not recompute the states on hot reloading (or on replacing the reducers). Available only for Redux enhancer. Default to `true`. + +### `shouldCatchErrors` + +_boolean_ - if specified as `true`, whenever there's an exception in reducers, the monitors will show the error message, and next actions will not be dispatched. + +### `features` + +If you want to restrict the extension, just specify the features you allow: + +```js +const composeEnhancers = composeWithDevTools({ + features: { + pause: true, // start/pause recording of dispatched actions + lock: true, // lock/unlock dispatching actions and side effects + persist: true, // persist states on page reloading + export: true, // export history of actions in a file + import: 'custom', // import history of actions from a file + jump: true, // jump back and forth (time travelling) + skip: true, // skip (cancel) actions + reorder: true, // drag and drop actions in the history list + dispatch: true, // dispatch custom actions or action creators + test: true, // generate tests for the selected actions + }, + // other options like actionSanitizer, stateSanitizer +}); +``` + +If not specified, all of the features are enabled. When set as an object, only those included as `true` will be allowed. +Note that except `true`/`false`, `import` and `export` can be set as `custom` (which is by default for Redux enhancer), meaning that the importing/exporting occurs on the client side. Otherwise, you'll get/set the data right from the monitor part. diff --git a/extension/docs/API/Methods.md b/extension/docs/API/Methods.md new file mode 100644 index 00000000..3d637601 --- /dev/null +++ b/extension/docs/API/Methods.md @@ -0,0 +1,93 @@ +## Communicate with the extension directly + +> Note this is advanced API, which you usually don't need to use with Redux enhancer. + +Use the following methods of `window.__REDUX_DEVTOOLS_EXTENSION__`: + +- [connect](#connect) +- [disconnect](#disconnect) +- [send](#send) +- [listen](#listen) +- [open](#open) +- [notifyErrors](#notifyerrors) + +<a id="connect"></a> + +### connect([options]) + +##### Arguments + +- [`options`] _Object_ - [see the available options](Arguments.md). + +##### Returns + +_Object_ containing the following methods: + +- `subscribe(listener)` - adds a change listener. It will be called any time an action is dispatched from the monitor. Returns a function to unsubscribe the current listener. +- `unsubscribe()` - unsubscribes all listeners. +- `send(action, state)` - sends a new action and state manually to be shown on the monitor. If action is `null` then we suppose we send `liftedState`. +- `init(state)` - sends the initial state to the monitor. +- `error(message)` - sends the error message to be shown in the extension's monitor. + +Example of usage: + +```js +const devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect(config); +devTools.subscribe((message) => { + if (message.type === 'DISPATCH' && message.state) { + console.log('DevTools requested to change the state to', message.state); + } +}); +devTools.init({ value: 'initial state' }); +devTools.send('change state', { value: 'state changed' }); +``` + +See [redux enhancer's example](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/npm-package/logOnly.js), [react example](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/examples/react-counter-messaging/components/Counter.js) and [blog post](https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f) for more details. + +### disconnect() + +Remove extensions listener and disconnect extensions background script connection. Usually just unsubscribing the listener inside the `connect` is enough. + +<a id="send"></a> + +### send(action, state, [options, instanceId]) + +Send a new action and state manually to be shown on the monitor. It's recommended to use [`connect`](connect), unless you want to hook into an already created instance. + +##### Arguments + +- `action` _String_ (action type) or _Object_ with required `type` key. +- `state` _any_ - usually object to expand. +- [`options`] _Object_ - [see the available options](Arguments.md). +- [`instanceId`] _String_ - instance id for which to include the log. If not specified and not present in the `options` object, will be the first available instance. + +<a id="listen"></a> + +### listen(onMessage, instanceId) + +Listen for messages dispatched for specific `instanceId`. For most cases it's better to use `subcribe` inside the [`connect`](connect). + +##### Arguments + +- `onMessage` _Function_ to call when there's an action from the monitor. +- `instanceId` _String_ - instance id for which to handle actions. + +<a id="open"></a> + +### open([position]) + +Open the extension's window. This should be conditional (usually you don't need to open extension's window automatically). + +##### Arguments + +- [`position`] _String_ - window position: `left`, `right`, `bottom`. Also can be `panel` to [open it in a Chrome panel](../FAQ.md#how-to-keep-devtools-window-focused-all-the-time-in-a-chrome-panel). Or `remote` to [open remote monitor](../FAQ.md#how-to-get-it-work-with-webworkers-react-native-hybrid-desktop-and-server-side-apps). By default is `left`. + +<a id="notifyErrors"></a> + +### notifyErrors([onError]) + +When called, the extension will listen for uncaught exceptions on the page, and, if any, will show native notifications. Optionally, you can provide a function to be called when an exception occurs. + +##### Arguments + +- [`onError`] _Function_ to call when there's an exceptions. diff --git a/extension/docs/API/README.md b/extension/docs/API/README.md new file mode 100644 index 00000000..13781355 --- /dev/null +++ b/extension/docs/API/README.md @@ -0,0 +1,4 @@ +# API Reference + +- [Parameters](Arguments.md) +- [Methods](Methods.md) diff --git a/extension/docs/Articles.md b/extension/docs/Articles.md new file mode 100644 index 00000000..09de66ad --- /dev/null +++ b/extension/docs/Articles.md @@ -0,0 +1,5 @@ +# Articles + +- [Improve your development workflow with Redux DevTools Extension](https://medium.com/@zalmoxis/improve-your-development-workflow-with-redux-devtools-extension-f0379227ff83) +- [Using Redux DevTools in production](https://medium.com/@zalmoxis/using-redux-devtools-in-production-4c5b56c5600f) +- [Redux DevTools without Redux](https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f) diff --git a/extension/docs/Credits.md b/extension/docs/Credits.md new file mode 100644 index 00000000..f7ec16de --- /dev/null +++ b/extension/docs/Credits.md @@ -0,0 +1,11 @@ +# Credits + +- Built using [Crossbuilder](https://github.com/zalmoxisus/crossbuilder) boilerplate. +- Includes [Dan Abramov](https://github.com/gaearon)'s [redux-devtools](https://github.com/gaearon/redux-devtools) and the following monitors: + - [Log Monitor](https://github.com/gaearon/redux-devtools-log-monitor) + - [Inspector](https://github.com/alexkuz/redux-devtools-inspector) + - [Dispatch](https://github.com/YoruNoHikage/redux-devtools-dispatch) + - [Slider](https://github.com/calesce/redux-slider-monitor) + - [Chart](https://github.com/romseguy/redux-devtools-chart-monitor) +- [The logo icon](https://github.com/reactjs/redux/issues/151) made by [Keith Yong](https://github.com/keithyong) . +- Examples from [Redux](https://github.com/rackt/redux/tree/master/examples). diff --git a/extension/docs/FAQ.md b/extension/docs/FAQ.md new file mode 100644 index 00000000..d46253b5 --- /dev/null +++ b/extension/docs/FAQ.md @@ -0,0 +1,45 @@ +# Redux DevTools Extension FAQ + +## Table of Contents + +- [How to get it work](#how-to-get-it-work) +- [How to disable/enable it in production](#how-to-disable-it-in-production) +- [How to persist debug sessions across page reloads](#how-to-persist-debug-sessions-across-page-reloads) +- [How to open DevTools programmatically](#how-to-open-devtools-programmatically) +- [How to enable/disable errors notifying](#how-to-enabledisable-errors-notifying) +- [How to get it work with WebWorkers, React Native, hybrid, desktop and server side apps](#how-to-get-it-work-with-webworkers-react-native-hybrid-desktop-and-server-side-apps) +- [Keyboard shortcuts](#keyboard-shortcuts) + +#### How to get it work + +- Check the extension with [Counter](http://zalmoxisus.github.io/examples/counter/) or [TodoMVC](http://zalmoxisus.github.io/examples/todomvc/) demo. +- Reload the extension on the extensions page (`chrome://extensions/`). +- If something goes wrong, [open an issue](https://github.com/zalmoxisus/redux-devtools-extension/issues) or tweet me: [@mdiordiev](https://twitter.com/mdiordiev). + +#### How to disable it in production + +Usually you don't have to. See [the article for details on how to include it in production](https://medium.com/@zalmoxis/using-redux-devtools-in-production-4c5b56c5600f). + +#### How to persist debug sessions across page reloads + +Just click the `Persist` button or add `?debug_session=<session_name>` to the url. + +#### How to open DevTools programmatically + +```js +window.__REDUX_DEVTOOLS_EXTENSION__.open(); +``` + +Make sure to have it conditionally. Auto opening windows is a bad DX. See the [API](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Methods.md#open) for details. + +#### How to enable/disable errors notifying + +Just find `Redux DevTools` on the extensions page (`chrome://extensions/`) and click the `Options` link to customize everything. The errors notifying is disabled by default. If enabled, it works only when the store enhancer is called (in order not to show notifications for any sites you visit). In case you want notifications for a non-redux app, init it explicitly by calling `window.__REDUX_DEVTOOLS_EXTENSION__.notifyErrors()` (probably you'll check if `window.__REDUX_DEVTOOLS_EXTENSION__` exists before calling it). + +#### How to get it work with WebWorkers, React Native, hybrid, desktop and server side apps + +It is not possible to inject extension's script there and to communicate directly. To solve this, use [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools). After including it inside the app, click `Remote` button for remote monitoring. + +#### Keyboard shortcuts + +To set/change the keyboard shortcuts, click "Keyboard shortcuts" button on the bottom of the extensions page (`chrome://extensions/`). By default only `Cmd` (`Ctrl`) + `Shift` + `E` is available, which will open the extension popup (only when the Redux store is available in the current page). diff --git a/extension/docs/Features/Trace.md b/extension/docs/Features/Trace.md new file mode 100644 index 00000000..1aa2505b --- /dev/null +++ b/extension/docs/Features/Trace.md @@ -0,0 +1,13 @@ +## Trace actions calls + +![trace-demo](https://user-images.githubusercontent.com/7957859/50161148-a1639300-02e3-11e9-80e7-18d3215a0bf8.gif) + +One of the features of Redux DevTools is to select an action in the history and see the callstack that triggered it. It aims to solve the problem of finding the source of events in the event list. + +By default it's disabled as, depending of the use case, generating and serializing stack traces for every action can impact the performance. To enable it, set `trace` option to `true` as in [examples](https://github.com/zalmoxisus/redux-devtools-extension/commit/64717bb9b3534ff616d9db56c2be680627c7b09d). See [the API](../API/Arguments.md#trace) for more details. + +For some edge cases where stack trace cannot be obtained with just `Error().stack`, you can pass a function as `trace` with your implementation. It's useful for cases where the stack is broken, like, for example, [when calling `setTimeout`](https://github.com/zalmoxisus/redux-devtools-instrument/blob/e7c05c98e7e9654cb7db92a2f56c6b5f3ff2452b/test/instrument.spec.js#L735-L737). It takes `action` object as argument and should return `stack` string. This way it can be also used to provide stack conditionally only for certain actions. + +There's also an optional `traceLimit` parameter, which is `10` by default, to prevent consuming too much memory and serializing large stacks and also allows you to get larger stacks than limited by the browser (it will overpass default limit of `10` imposed by Chrome in `Error.stackTraceLimit`). If `trace` option is a function, `traceLimit` will have no effect, that should be handled there like so: `trace: () => new Error().stack.split('\n').slice(0, limit+1).join('\n')` (`+1` is needed for Chrome where's an extra 1st frame for `Error\n`). + +Apart from opening resources in Chrome DevTools, as seen in the demo above, it can open the file (and jump to the line-column) right in your editor. Pretty useful for debugging, and also as an alternative when it's not possible to use openResource (for Firefox or when using the extension from window or for remote debugging). You can click Settings button and enable that, also adding the path to your project root directory to use. It works out of the box for VSCode, Atom, Webstorm/Phpstorm/IntelliJ, Sublime, Emacs, MacVim, Textmate on Mac and Windows. For Linux you can use [`atom-url-handler`](https://github.com/eclemens/atom-url-handler). diff --git a/extension/docs/Feedback.md b/extension/docs/Feedback.md new file mode 100644 index 00000000..d31b7e6d --- /dev/null +++ b/extension/docs/Feedback.md @@ -0,0 +1,5 @@ +# Feedback wanted + +[File an issue](https://github.com/zalmoxisus/redux-devtools-extension/issues) or [submit a PR](https://github.com/zalmoxisus/redux-devtools-extension/pulls) if you have suggestions, rate us and leave a review on [Chrome Store](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd/reviews), post feature requests and bug reports on [Product Pains](https://productpains.com/product/redux-devtools-extension), or ping me on Twitter as [@mdiordiev](https://twitter.com/mdiordiev). + +<iframe width="100%" height="400px" scrolling="no" style="border:0" src="https://productpains.com/widget.html?token=fc7887ce-f3f9-105a-e5cb-43b9eeb668d5"></iframe><script type="text/javascript" src="https://productpains.com/js/lib/iframeResizer.min.js"></script> diff --git a/extension/docs/Integrations.md b/extension/docs/Integrations.md new file mode 100644 index 00000000..ae27c64f --- /dev/null +++ b/extension/docs/Integrations.md @@ -0,0 +1,302 @@ +# Integrations for js and non-js frameworks + +Mostly functional: + +- [React](#react) +- [Angular](#angular) +- [Cycle](#cycle) +- [Ember](#ember) +- [Fable](#fable) +- [Freezer](#freezer) +- [Mobx](#mobx) +- [PureScript](#purescript) +- [Reductive](#reductive) +- [Aurelia](#aurelia) + +In progress: + +- [ClojureScript](#clojurescript) +- [Horizon](#horizon) +- [Python](#python) +- [Swift](#swift) + +### [React](https://github.com/facebook/react) + +#### Inspect React props + +##### [`react-inspect-props`](https://github.com/lucasconstantino/react-inspect-props) + +```js +import { compose, withState } from 'recompose'; +import { inspectProps } from 'react-inspect-props'; + +compose( + withState('count', 'setCount', 0), + inspectProps('Counter inspector') +)(Counter); +``` + +#### Inspect React states + +##### [`remotedev-react-state`](https://github.com/jhen0409/remotedev-react-state) + +```js +import connectToDevTools from 'remotedev-react-state' + +componentWillMount() { + // Connect to devtools after setup initial state + connectToDevTools(this/*, options */) + } +``` + +#### Inspect React hooks (useState and useReducer) + +##### [`reinspect`](https://github.com/troch/reinspect) + +```js +import { useState } from 'reinspect'; + +export function CounterWithUseState({ id }) { + const [count, setCount] = useState(0, id); + // ... +} +``` + +### [Mobx](https://github.com/mobxjs/mobx) + +#### [`mobx-remotedev`](https://github.com/zalmoxisus/mobx-remotedev) + +```js +import remotedev from 'mobx-remotedev'; +// or import remotedev from 'mobx-remotedev/lib/dev' +// in case you want to use it in production or don't have process.env.NODE_ENV === 'development' + +const appStore = observable({ + // ... +}); + +// Or +class appStore { + // ... +} + +export default remotedev(appStore); +``` + +### [Angular](https://github.com/angular/angular) + +#### [ng2-redux](https://github.com/angular-redux/ng2-redux) + +```js +import { NgReduxModule, NgRedux, DevToolsExtension } from 'ng2-redux'; + +@NgModule({ + /* ... */ + imports: [ /* ... */, NgReduxModule ] +})export class AppModule { + constructor( + private ngRedux: NgRedux, + private devTools: DevToolsExtension) { + + let enhancers = []; + // ... add whatever other enhancers you want. + + // You probably only want to expose this tool in devMode. + if (__DEVMODE__ && devTools.isEnabled()) { + enhancers = [ ...enhancers, devTools.enhancer() ]; + } + + this.ngRedux.configureStore( + rootReducer, + initialState, + [], + enhancers); + } +} +``` + +For Angular 1 see [ng-redux](https://github.com/angular-redux/ng-redux). + +#### [Angular @ngrx/store](https://ngrx.io/) + [`@ngrx/store-devtools`](https://ngrx.io/guide/store-devtools) + +```js +import { StoreDevtoolsModule } from '@ngrx/store-devtools'; + +@NgModule({ + imports: [ + StoreModule.forRoot(rootReducer), + // Instrumentation must be imported after importing StoreModule (config is optional) + StoreDevtoolsModule.instrument({ + maxAge: 5, + }), + ], +}) +export class AppModule {} +``` + +[`Example of integration`](https://github.com/ngrx/platform/tree/master/projects/example-app/) ([live demo](https://ngrx.github.io/platform/example-app/)). + +### [Ember](http://emberjs.com/) + +#### [`ember-redux`](https://github.com/ember-redux/ember-redux) + +```js +//app/enhancers/index.js +import { compose } from 'redux'; +var devtools = window.__REDUX_DEVTOOLS_EXTENSION__ + ? window.__REDUX_DEVTOOLS_EXTENSION__() + : (f) => f; +export default compose(devtools); +``` + +### [Cycle](https://github.com/cyclejs/cyclejs) + +#### [`@culli/store`](https://github.com/milankinen/culli/tree/master/packages/store) + +```js +import { run } from '@cycle/most-run'; +import { makeDOMDriver as DOM } from '@cycle/dom'; +import Store, { ReduxDevtools } from '@culli/store'; +import App, { newId } from './App'; + +run(App, { + DOM: DOM('#app'), + Store: Store( + ReduxDevtools({ + items: [ + { id: newId(), num: 0 }, + { id: newId(), num: 0 }, + ], + }) + ), +}); +``` + +### [Freezer](https://github.com/arqex/freezer) + +#### [`freezer-redux-devtools`](https://github.com/arqex/freezer-redux-devtools) + +```js +import React, { Component } from 'react'; +import { supportChromeExtension } from 'freezer-redux-devtools/freezer-redux-middleware'; +import Freezer from 'freezer-js'; + +// Our state is a freezer object +var State = new Freezer({ hello: 'world' }); + +// Enable the extension +supportChromeExtension(State); +``` + +### [Horizon](https://github.com/rethinkdb/horizon) + +#### [`horizon-remotedev`](https://github.com/zalmoxisus/horizon-remotedev) + +```js +// import hzRemotedev from 'horizon-remotedev'; +// or import hzRemotedev from 'horizon-remotedev/lib/dev' +// in case you want to use it in production or don't have process.env.NODE_ENV === 'development' + +//Setup Horizon connection +const horizon = Horizon(); + +// ... +// Specify the horizon instance to monitor +hzRemotedev(horizon('react_messages')); +``` + +### [Fable](https://github.com/fable-compiler/Fable) + +#### [`fable-elmish/debugger`](https://github.com/fable-elmish/debugger) + +```fsharp +open Elmish.Debug + +Program.mkProgram init update view +|> Program.withDebugger // connect to a devtools monitor via Chrome extension if available +|> Program.run + +``` + +or + +```fsharp +open Elmish.Debug + +Program.mkProgram init update view +|> Program.withDebuggerAt (Remote("localhost",8000)) // connect to a server running on localhost:8000 +|> Program.run +``` + +### [PureScript](https://github.com/purescript/purescript) + +#### [`purescript-react-redux`](https://github.com/ethul/purescript-react-redux) + +[`Example of integration`](https://github.com/ethul/purescript-react-redux-example). + +### [ClojureScript](https://github.com/clojure/clojurescript) + +[`Example of integration`](http://gitlab.xet.ru:9999/publicpr/clojurescript-redux/tree/master#dev-setup) + +### [Python](https://www.python.org/) + +#### [`pyredux`](https://github.com/peterpeter5/pyredux) + +[WIP](https://github.com/zalmoxisus/remotedev-server/issues/34) + +### [Swift](https://github.com/apple/swift) + +#### [`katanaMonitor`](https://github.com/bolismauro/katanaMonitor-lib-swift) for [`katana-swift`](https://github.com/BendingSpoons/katana-swift) + +```swift +import KatanaMonitor + +var middleware: [StoreMiddleware] = [ +// other middleware +] + +#if DEBUG +middleware.append(MonitorMiddleware.create(using: .defaultConfiguration)) +#endif +``` + +### [Reductive](https://github.com/reasonml-community/reductive) + +#### [`reductive-dev-tools`](https://github.com/ambientlight/reductive-dev-tools) + +```reason +let storeEnhancer = + ReductiveDevTools.( + Connectors.reductiveEnhancer( + Extension.enhancerOptions(~name="MyApp", ()), + ) + ); + +let storeCreator = storeEnhancer @@ Reductive.Store.create; +``` + +### [Aurelia](http://aurelia.io) + +#### [`aurelia-store`](https://aurelia.io/docs/plugins/store) + +```ts +import {Aurelia} from 'aurelia-framework'; +import {initialState} from './state'; + +export function configure(aurelia: Aurelia) { + aurelia.use + .standardConfiguration() + .feature('resources'); + + ... + + aurelia.use.plugin('aurelia-store', { + initialState, + devToolsOptions: { // optional + ... // see https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md + }, + }); + + aurelia.start().then(() => aurelia.setRoot()); +} +``` diff --git a/extension/docs/README.md b/extension/docs/README.md new file mode 100644 index 00000000..f6df934a --- /dev/null +++ b/extension/docs/README.md @@ -0,0 +1,21 @@ +# Documentation + +- [Extension](/README.md) + - [Installation](/README.md#installation) + - [Usage](/README.md#usage) + - [Demo](/README.md#demo) +- [API Reference](/docs/API/README.md) + - [Options (arguments)](/docs/API/Arguments.md) + - [Methods (advanced API)](/docs/API/Methods.md) +- Features + - [Trace actions calls](/docs/Features/Trace.md) +- [Integrations](/docs/Integrations.md) +- [FAQ](/docs/FAQ.md) +- [Troubleshooting](/docs/Troubleshooting.md) +- [Recipes](/docs/Recipes.md) +- [Articles](/docs/Articles.md) +- [Videos](/docs/Videos.md) +- [Credits](/docs/Credits.md) +- [Support us](/README.md#backers) +- [Feedback](/docs/Feedback.md) +- [Change Log](https://github.com/zalmoxisus/redux-devtools-extension/releases) diff --git a/extension/docs/Recipes.md b/extension/docs/Recipes.md new file mode 100644 index 00000000..5bc8e751 --- /dev/null +++ b/extension/docs/Recipes.md @@ -0,0 +1,78 @@ +# Recipes + +### Using in a typescript project + +The recommended way is to use [`redux-devtools-extension` npm package](/README.md#13-use-redux-devtools-extension-package-from-npm), which contains all typescript definitions. Or you can just use `window as any`: + +```js +const store = createStore( + rootReducer, + initialState, + (window as any).__REDUX_DEVTOOLS_EXTENSION__ && + (window as any).__REDUX_DEVTOOLS_EXTENSION__() +); +``` + +Note that you many need to set `no-any` to false in your `tslint.json` file. + +Alternatively you can use typeguard in order to avoid +casting to any. + +```typescript +import { createStore, StoreEnhancer } from 'redux'; + +// ... + +type WindowWithDevTools = Window & { + __REDUX_DEVTOOLS_EXTENSION__: () => StoreEnhancer<unknown, {}>; +}; + +const isReduxDevtoolsExtenstionExist = ( + arg: Window | WindowWithDevTools +): arg is WindowWithDevTools => { + return '__REDUX_DEVTOOLS_EXTENSION__' in arg; +}; + +// ... + +const store = createStore( + rootReducer, + initialState, + isReduxDevtoolsExtenstionExist(window) + ? window.__REDUX_DEVTOOLS_EXTENSION__() + : undefined +); +``` + +### Export from browser console or from application + +```js +store.liftedStore.getState(); +``` + +The extension is not sharing `store` object, so you should take care of that. + +### Applying multiple times with different sets of options + +We're [not allowing that from instrumentation part](https://github.com/zalmoxisus/redux-devtools-instrument/blob/master/src/instrument.js#L676), because that would re-dispatch every app action in case we'd have many liftedStores, but there's [a helper for logging only](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/npm-package/logOnly.js), which can be used it like so: + +```js +import { createStore, compose } from 'redux'; +import { devToolsEnhancer } from 'redux-devtools-extension/logOnly'; + +const store = createStore( + reducer, + /* preloadedState, */ compose( + devToolsEnhancer({ + instaceID: 1, + name: 'Blacklisted', + actionsBlacklist: '...', + }), + devToolsEnhancer({ + instaceID: 2, + name: 'Whitelisted', + actionsWhitelist: '...', + }) + ) +); +``` diff --git a/extension/docs/Troubleshooting.md b/extension/docs/Troubleshooting.md new file mode 100644 index 00000000..e3cf226f --- /dev/null +++ b/extension/docs/Troubleshooting.md @@ -0,0 +1,129 @@ +# Troubleshooting + +### I just see empty log or "No store found" + +Make sure you [applied the enhancer](https://github.com/zalmoxisus/redux-devtools-extension#2-use-with-redux). Note that passing enhancer as last argument requires redux@>=3.1.0. For older versions apply it like [here](https://github.com/zalmoxisus/redux-devtools-extension/blob/v0.4.2/examples/todomvc/store/configureStore.js) or [here](https://github.com/zalmoxisus/redux-devtools-extension/blob/v0.4.2/examples/counter/store/configureStore.js#L7-L12). + +Don't mix the old Redux API with the new one. Pass enhancers and applyMiddleware as last createStore argument. + +### Access file url (`file:///`) + +If you develop on your local filesystem, make sure to allow Redux DevTools access to `file:///` URLs in the settings of this extension: + +<img width="746" alt="extensions" src="https://cloud.githubusercontent.com/assets/7957859/19075220/a0fad99e-8a4c-11e6-8b87-757f2dc179cb.png"> + +### It shows only the `@@INIT` action or moving back and forth doesn't update the state + +Most likely you mutate the state. Check it by [adding `redux-immutable-state-invariant` middleware](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/examples/counter/store/configureStore.js#L3). + +### @@INIT or REPLACE action resets the state of the app or last actions RE-APPLIED + +`@@redux/REPLACE` (or `@@INIT`) is used internally when the application is hot reloaded. When you use `store.replaceReducer` the effect will be the same as for hot-reloading, where the extension is recomputing all the history again. To avoid that set [`shouldHotReload`](/docs/API/Arguments.md#shouldhotreload) parameter to `false`. + +### It doesn't work with other store enhancers + +Usually the extension's store enhancer should be last in the compose. When you're using [`window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__`](/README.md#12-advanced-store-setup) or [`composeWithDevTools`](/README.md#13-use-redux-devtools-extension-package-from-npm) helper you don't have to worry about the enhancers order. However some enhancers ([like `redux-batched-subscribe`](https://github.com/zalmoxisus/redux-devtools-extension/issues/261)) also have this requirement to be the last in the compose. In this case you can use it like so: + +```js +const store = createStore( + reducer, + preloadedState, + compose( + // applyMiddleware(thunk), + window.__REDUX_DEVTOOLS_EXTENSION__ + ? window.__REDUX_DEVTOOLS_EXTENSION__() + : (noop) => noop, + batchedSubscribe(/* ... */) + ) +); +``` + +Where `batchedSubscribe` is `redux-batched-subscribe` store enhancer. + +### Excessive use of memory and CPU + +That is happening due to serialization of some huge objects included in the state or action. The solution is to [sanitize them](/docs/API/Arguments.md#actionsanitizer--statesanitizer). + +You can do that by including/omitting data containing specific values, having specific types... In the example below we're omitting parts of action and state objects with the key `data` (in case of action only when was dispatched action `FILE_DOWNLOAD_SUCCESS`): + +```js +const actionSanitizer = (action) => + action.type === 'FILE_DOWNLOAD_SUCCESS' && action.data + ? { ...action, data: '<<LONG_BLOB>>' } + : action; +const store = createStore( + rootReducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && + window.__REDUX_DEVTOOLS_EXTENSION__({ + actionSanitizer, + stateSanitizer: (state) => + state.data ? { ...state, data: '<<LONG_BLOB>>' } : state, + }) +); +``` + +There's a more advanced [example on how to implement that for `ui-router`](https://github.com/zalmoxisus/redux-devtools-extension/issues/455#issuecomment-404538385). + +The extension is in different process and cannot access the store object directly, unlike vanilla [`redux-devtools`](https://github.com/reduxjs/redux-devtools) which doesn't have this issue. In case sanitizing doesn't fit your use case, you might consider including it directly as a react component, so there will be no need to serialize the data, but it would add some complexity. + +### It fails to serialize data when [passing synthetic events](https://github.com/zalmoxisus/redux-devtools-extension/issues/275) or [calling an action directly with `redux-actions`](https://github.com/zalmoxisus/redux-devtools-extension/issues/287) + +React synthetic event cannot be reused for performance reason. So, it's not possible to serialize event objects you pass to action payloads. + +1. The best solution is **not to pass the whole event object to reducers, but the data you need**: + +```diff +function click(event) { + return { + type: ELEMENT_CLICKED, +- event: event ++ value: event.target.value + }; +} +``` + +2. If you cannot pick data from the event object or, for some reason, you need the whole object, use `event.persist()` as suggested in [React Docs](https://facebook.github.io/react/docs/events.html#event-pooling), but it will consume RAM while not needed. + + ```diff + function increment(event) { + + event.persist(); + return { + type: ELEMENT_CLICKED, + event: event, + }; + } + ``` + +3. A workaround, to pass the whole object and at the same time not to persist it, is to override this key of the stringified payload in your action creator. Add a custom `toJSON` function right in the action object (which will be called by the extension before accessing the object): + + ```diff + function increment(event) { + return { + type: ELEMENT_CLICKED, + event: event, + + toJSON: function (){ + + return { ...this, event: '[Event]' }; + + } + }; + } + ``` + + Note that it shouldn't be arrow function as we want to have access to the function's `this`. + + As we don't have access to the original object, skipping and recomputing actions during hot reloading will not work in this case. We recommend to use the first solution whenever possible. + +### Symbols or other unserializable data not shown + +To get data which cannot be serialized by `JSON.stringify`, set [`serialize` parameter](/docs/API/Arguments.md#serialize): + +```js +const store = Redux.createStore( + reducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && + window.__REDUX_DEVTOOLS_EXTENSION__({ + serialize: true, + }) +); +``` + +It will handle also date, regex, undefined, error objects, symbols, maps, sets and functions. diff --git a/extension/docs/Videos.md b/extension/docs/Videos.md new file mode 100644 index 00000000..bb4fbb82 --- /dev/null +++ b/extension/docs/Videos.md @@ -0,0 +1,6 @@ +# Videos + +- [Debugging flux applications in production at React Europe 2016](https://youtu.be/YU8jQ2HtqH4) +- [Hot Reloading with Time Travel at React Europe 2015](https://youtu.be/xsSnOQynTHs) +- [Getting Started with Redux DevTools Extension](https://egghead.io/lessons/javascript-getting-started-with-redux-dev-tools) +- [React & Redux With ExpressJS](https://www.youtube.com/watch?v=6ygcbRpZFR4) diff --git a/extension/examples/buildAll.js b/extension/examples/buildAll.js new file mode 100644 index 00000000..3a558760 --- /dev/null +++ b/extension/examples/buildAll.js @@ -0,0 +1,36 @@ +/** + * Runs an ordered set of commands within each of the build directories. + */ + +import fs from 'fs'; +import path from 'path'; +import { spawnSync } from 'child_process'; + +var exampleDirs = fs.readdirSync(__dirname).filter((file) => { + return fs.statSync(path.join(__dirname, file)).isDirectory(); +}); + +// Ordering is important here. `npm install` must come first. +var cmdArgs = [ + { cmd: 'npm', args: ['install'] }, + { cmd: 'webpack', args: ['index.js'] }, +]; + +for (const dir of exampleDirs) { + for (const cmdArg of cmdArgs) { + // declare opts in this scope to avoid https://github.com/joyent/node/issues/9158 + const opts = { + cwd: path.join(__dirname, dir), + stdio: 'inherit', + }; + let result = {}; + if (process.platform === 'win32') { + result = spawnSync(cmdArg.cmd + '.cmd', cmdArg.args, opts); + } else { + result = spawnSync(cmdArg.cmd, cmdArg.args, opts); + } + if (result.status !== 0) { + throw new Error('Building examples exited with non-zero'); + } + } +} diff --git a/extension/examples/counter/.babelrc b/extension/examples/counter/.babelrc new file mode 100644 index 00000000..9b7d435a --- /dev/null +++ b/extension/examples/counter/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "stage-0", "react"] +} diff --git a/extension/examples/counter/actions/counter.js b/extension/examples/counter/actions/counter.js new file mode 100644 index 00000000..94fcdca1 --- /dev/null +++ b/extension/examples/counter/actions/counter.js @@ -0,0 +1,37 @@ +export const INCREMENT_COUNTER = 'INCREMENT_COUNTER'; +export const DECREMENT_COUNTER = 'DECREMENT_COUNTER'; + +let t; + +export function increment() { + return { + type: INCREMENT_COUNTER, + }; +} + +export function decrement() { + return { + type: DECREMENT_COUNTER, + }; +} + +export function autoIncrement(delay = 10) { + return (dispatch) => { + if (t) { + clearInterval(t); + t = undefined; + return; + } + t = setInterval(() => { + dispatch(increment()); + }, delay); + }; +} + +export function incrementAsync(delay = 1000) { + return (dispatch) => { + setTimeout(() => { + dispatch(increment()); + }, delay); + }; +} diff --git a/extension/examples/counter/components/Counter.js b/extension/examples/counter/components/Counter.js new file mode 100644 index 00000000..08a0fcdb --- /dev/null +++ b/extension/examples/counter/components/Counter.js @@ -0,0 +1,32 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +class Counter extends Component { + render() { + const { + increment, + autoIncrement, + incrementAsync, + decrement, + counter, + } = this.props; + return ( + <p> + Clicked: {counter} times <button onClick={increment}>+</button>{' '} + <button onClick={decrement}>-</button>{' '} + <button onClick={incrementAsync}>Increment async</button>{' '} + <button onClick={autoIncrement}>Auto increment</button> + </p> + ); + } +} + +Counter.propTypes = { + increment: PropTypes.func.isRequired, + autoIncrement: PropTypes.func.isRequired, + incrementAsync: PropTypes.func.isRequired, + decrement: PropTypes.func.isRequired, + counter: PropTypes.number.isRequired, +}; + +export default Counter; diff --git a/extension/examples/counter/containers/App.js b/extension/examples/counter/containers/App.js new file mode 100644 index 00000000..47287ecf --- /dev/null +++ b/extension/examples/counter/containers/App.js @@ -0,0 +1,16 @@ +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import Counter from '../components/Counter'; +import * as CounterActions from '../actions/counter'; + +function mapStateToProps(state) { + return { + counter: state.counter, + }; +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators(CounterActions, dispatch); +} + +export default connect(mapStateToProps, mapDispatchToProps)(Counter); diff --git a/extension/examples/counter/index.html b/extension/examples/counter/index.html new file mode 100644 index 00000000..0f963144 --- /dev/null +++ b/extension/examples/counter/index.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> + <head> + <title>Redux counter example + + +
+ + + diff --git a/extension/examples/counter/index.js b/extension/examples/counter/index.js new file mode 100644 index 00000000..0ab7fd0f --- /dev/null +++ b/extension/examples/counter/index.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { render } from 'react-dom'; +import { Provider } from 'react-redux'; +import App from './containers/App'; +import configureStore from './store/configureStore'; + +const store = configureStore(); + +render( + + + , + document.getElementById('root') +); diff --git a/extension/examples/counter/package.json b/extension/examples/counter/package.json new file mode 100644 index 00000000..73fb3ab2 --- /dev/null +++ b/extension/examples/counter/package.json @@ -0,0 +1,41 @@ +{ + "name": "redux-counter-example", + "version": "0.0.0", + "description": "Redux counter example", + "scripts": { + "start": "node server.js", + "test": "NODE_ENV=test mocha --recursive --compilers js:babel-core/register --require ./test/setup.js", + "test:watch": "npm test -- --watch" + }, + "repository": { + "type": "git", + "url": "https://github.com/rackt/redux.git" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/rackt/redux/issues" + }, + "homepage": "http://rackt.github.io/redux", + "dependencies": { + "prop-types": "^15.6.2", + "react": "^16.7.0", + "react-dom": "^16.7.0", + "react-redux": "^6.0.0", + "redux": "^4.0.1", + "redux-devtools-extension": "^2.13.7", + "redux-thunk": "^2.3.0" + }, + "devDependencies": { + "babel-cli": "^6.3.17", + "babel-core": "^6.3.17", + "babel-loader": "^7.0.0", + "babel-preset-es2015": "^6.0.0", + "babel-preset-react": "6.3.13", + "babel-preset-stage-0": "^6.3.13", + "express": "^4.13.3", + "redux-immutable-state-invariant": "^2.1.0", + "webpack": "^4.0.0", + "webpack-dev-server": "^3.0.0", + "webpack-hot-middleware": "^2.2.0" + } +} diff --git a/extension/examples/counter/reducers/counter.js b/extension/examples/counter/reducers/counter.js new file mode 100644 index 00000000..c16e5d44 --- /dev/null +++ b/extension/examples/counter/reducers/counter.js @@ -0,0 +1,12 @@ +import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../actions/counter'; + +export default function counter(state = 0, action) { + switch (action.type) { + case INCREMENT_COUNTER: + return state + 1; + case DECREMENT_COUNTER: + return state - 1; + default: + return state; + } +} diff --git a/extension/examples/counter/reducers/index.js b/extension/examples/counter/reducers/index.js new file mode 100644 index 00000000..eba07a15 --- /dev/null +++ b/extension/examples/counter/reducers/index.js @@ -0,0 +1,8 @@ +import { combineReducers } from 'redux'; +import counter from './counter'; + +const rootReducer = combineReducers({ + counter, +}); + +export default rootReducer; diff --git a/extension/examples/counter/server.js b/extension/examples/counter/server.js new file mode 100644 index 00000000..7e993c75 --- /dev/null +++ b/extension/examples/counter/server.js @@ -0,0 +1,32 @@ +var webpack = require('webpack'); +var webpackDevMiddleware = require('webpack-dev-middleware'); +var webpackHotMiddleware = require('webpack-hot-middleware'); +var config = require('./webpack.config'); + +var app = new require('express')(); +var port = 4001; + +var compiler = webpack(config); +app.use( + webpackDevMiddleware(compiler, { + noInfo: true, + publicPath: config.output.publicPath, + }) +); +app.use(webpackHotMiddleware(compiler)); + +app.get('/', function (req, res) { + res.sendFile(__dirname + '/index.html'); +}); + +app.listen(port, function (error) { + if (error) { + console.error(error); + } else { + console.info( + '==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.', + port, + port + ); + } +}); diff --git a/extension/examples/counter/store/configureStore.js b/extension/examples/counter/store/configureStore.js new file mode 100644 index 00000000..a36c0d53 --- /dev/null +++ b/extension/examples/counter/store/configureStore.js @@ -0,0 +1,28 @@ +import { createStore, applyMiddleware, compose } from 'redux'; +import { composeWithDevTools } from 'redux-devtools-extension'; +import thunk from 'redux-thunk'; +import invariant from 'redux-immutable-state-invariant'; +import reducer from '../reducers'; +import * as actionCreators from '../actions/counter'; + +export default function configureStore(preloadedState) { + const composeEnhancers = composeWithDevTools({ + actionCreators, + trace: true, + traceLimit: 25, + }); + const store = createStore( + reducer, + preloadedState, + composeEnhancers(applyMiddleware(invariant(), thunk)) + ); + + if (module.hot) { + // Enable Webpack hot module replacement for reducers + module.hot.accept('../reducers', () => { + store.replaceReducer(require('../reducers').default); + }); + } + + return store; +} diff --git a/extension/examples/counter/test/actions/counter.spec.js b/extension/examples/counter/test/actions/counter.spec.js new file mode 100644 index 00000000..c65cc240 --- /dev/null +++ b/extension/examples/counter/test/actions/counter.spec.js @@ -0,0 +1,73 @@ +import expect from 'expect'; +import { applyMiddleware } from 'redux'; +import thunk from 'redux-thunk'; +import * as actions from '../../actions/counter'; + +const middlewares = [thunk]; + +/* + * Creates a mock of Redux store with middleware. + */ +function mockStore(getState, expectedActions, onLastAction) { + if (!Array.isArray(expectedActions)) { + throw new Error('expectedActions should be an array of expected actions.'); + } + if ( + typeof onLastAction !== 'undefined' && + typeof onLastAction !== 'function' + ) { + throw new Error('onLastAction should either be undefined or function.'); + } + + function mockStoreWithoutMiddleware() { + return { + getState() { + return typeof getState === 'function' ? getState() : getState; + }, + + dispatch(action) { + const expectedAction = expectedActions.shift(); + expect(action).toEqual(expectedAction); + if (onLastAction && !expectedActions.length) { + onLastAction(); + } + return action; + }, + }; + } + + const mockStoreWithMiddleware = applyMiddleware(...middlewares)( + mockStoreWithoutMiddleware + ); + + return mockStoreWithMiddleware(); +} + +describe('actions', () => { + it('increment should create increment action', () => { + expect(actions.increment()).toEqual({ type: actions.INCREMENT_COUNTER }); + }); + + it('decrement should create decrement action', () => { + expect(actions.decrement()).toEqual({ type: actions.DECREMENT_COUNTER }); + }); + + it('incrementIfOdd should create increment action', (done) => { + const expectedActions = [{ type: actions.INCREMENT_COUNTER }]; + const store = mockStore({ counter: 1 }, expectedActions, done); + store.dispatch(actions.incrementIfOdd()); + }); + + it('incrementIfOdd shouldnt create increment action if counter is even', (done) => { + const expectedActions = []; + const store = mockStore({ counter: 2 }, expectedActions); + store.dispatch(actions.incrementIfOdd()); + done(); + }); + + it('incrementAsync should create increment action', (done) => { + const expectedActions = [{ type: actions.INCREMENT_COUNTER }]; + const store = mockStore({ counter: 0 }, expectedActions, done); + store.dispatch(actions.incrementAsync(100)); + }); +}); diff --git a/extension/examples/counter/test/components/Counter.spec.js b/extension/examples/counter/test/components/Counter.spec.js new file mode 100644 index 00000000..85f0e163 --- /dev/null +++ b/extension/examples/counter/test/components/Counter.spec.js @@ -0,0 +1,53 @@ +import expect from 'expect'; +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; +import Counter from '../../components/Counter'; + +function setup() { + const actions = { + increment: expect.createSpy(), + incrementIfOdd: expect.createSpy(), + incrementAsync: expect.createSpy(), + decrement: expect.createSpy(), + }; + const component = TestUtils.renderIntoDocument( + + ); + return { + component: component, + actions: actions, + buttons: TestUtils.scryRenderedDOMComponentsWithTag(component, 'button'), + p: TestUtils.findRenderedDOMComponentWithTag(component, 'p'), + }; +} + +describe('Counter component', () => { + it('should display count', () => { + const { p } = setup(); + expect(p.textContent).toMatch(/^Clicked: 1 times/); + }); + + it('first button should call increment', () => { + const { buttons, actions } = setup(); + TestUtils.Simulate.click(buttons[0]); + expect(actions.increment).toHaveBeenCalled(); + }); + + it('second button should call decrement', () => { + const { buttons, actions } = setup(); + TestUtils.Simulate.click(buttons[1]); + expect(actions.decrement).toHaveBeenCalled(); + }); + + it('third button should call incrementIfOdd', () => { + const { buttons, actions } = setup(); + TestUtils.Simulate.click(buttons[2]); + expect(actions.incrementIfOdd).toHaveBeenCalled(); + }); + + it('fourth button should call incrementAsync', () => { + const { buttons, actions } = setup(); + TestUtils.Simulate.click(buttons[3]); + expect(actions.incrementAsync).toHaveBeenCalled(); + }); +}); diff --git a/extension/examples/counter/test/containers/App.spec.js b/extension/examples/counter/test/containers/App.spec.js new file mode 100644 index 00000000..bfa4d73d --- /dev/null +++ b/extension/examples/counter/test/containers/App.spec.js @@ -0,0 +1,53 @@ +import expect from 'expect'; +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; +import { Provider } from 'react-redux'; +import App from '../../containers/App'; +import configureStore from '../../store/configureStore'; + +function setup(initialState) { + const store = configureStore(initialState); + const app = TestUtils.renderIntoDocument( + + + + ); + return { + app: app, + buttons: TestUtils.scryRenderedDOMComponentsWithTag(app, 'button'), + p: TestUtils.findRenderedDOMComponentWithTag(app, 'p'), + }; +} + +describe('containers', () => { + describe('App', () => { + it('should display initial count', () => { + const { p } = setup(); + expect(p.textContent).toMatch(/^Clicked: 0 times/); + }); + + it('should display updated count after increment button click', () => { + const { buttons, p } = setup(); + TestUtils.Simulate.click(buttons[0]); + expect(p.textContent).toMatch(/^Clicked: 1 times/); + }); + + it('should display updated count after decrement button click', () => { + const { buttons, p } = setup(); + TestUtils.Simulate.click(buttons[1]); + expect(p.textContent).toMatch(/^Clicked: -1 times/); + }); + + it('shouldnt change if even and if odd button clicked', () => { + const { buttons, p } = setup(); + TestUtils.Simulate.click(buttons[2]); + expect(p.textContent).toMatch(/^Clicked: 0 times/); + }); + + it('should change if odd and if odd button clicked', () => { + const { buttons, p } = setup({ counter: 1 }); + TestUtils.Simulate.click(buttons[2]); + expect(p.textContent).toMatch(/^Clicked: 2 times/); + }); + }); +}); diff --git a/extension/examples/counter/test/reducers/counter.spec.js b/extension/examples/counter/test/reducers/counter.spec.js new file mode 100644 index 00000000..45861187 --- /dev/null +++ b/extension/examples/counter/test/reducers/counter.spec.js @@ -0,0 +1,23 @@ +import expect from 'expect'; +import counter from '../../reducers/counter'; +import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../../actions/counter'; + +describe('reducers', () => { + describe('counter', () => { + it('should handle initial state', () => { + expect(counter(undefined, {})).toBe(0); + }); + + it('should handle INCREMENT_COUNTER', () => { + expect(counter(1, { type: INCREMENT_COUNTER })).toBe(2); + }); + + it('should handle DECREMENT_COUNTER', () => { + expect(counter(1, { type: DECREMENT_COUNTER })).toBe(0); + }); + + it('should handle unknown action type', () => { + expect(counter(1, { type: 'unknown' })).toBe(1); + }); + }); +}); diff --git a/extension/examples/counter/test/setup.js b/extension/examples/counter/test/setup.js new file mode 100644 index 00000000..b4e5ab07 --- /dev/null +++ b/extension/examples/counter/test/setup.js @@ -0,0 +1,5 @@ +import { jsdom } from 'jsdom'; + +global.document = jsdom(''); +global.window = document.defaultView; +global.navigator = global.window.navigator; diff --git a/extension/examples/counter/webpack.config.js b/extension/examples/counter/webpack.config.js new file mode 100644 index 00000000..d7aff9b1 --- /dev/null +++ b/extension/examples/counter/webpack.config.js @@ -0,0 +1,23 @@ +var path = require('path'); +var webpack = require('webpack'); + +module.exports = { + mode: 'development', + devtool: 'source-map', + entry: ['webpack-hot-middleware/client', './index'], + output: { + path: path.join(__dirname, 'dist'), + filename: 'bundle.js', + publicPath: '/static/', + }, + plugins: [new webpack.HotModuleReplacementPlugin()], + module: { + rules: [ + { + test: /\.js$/, + loaders: ['babel-loader'], + exclude: /node_modules/, + }, + ], + }, +}; diff --git a/extension/examples/react-counter-messaging/.babelrc b/extension/examples/react-counter-messaging/.babelrc new file mode 100644 index 00000000..9b7d435a --- /dev/null +++ b/extension/examples/react-counter-messaging/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "stage-0", "react"] +} diff --git a/extension/examples/react-counter-messaging/components/Counter.js b/extension/examples/react-counter-messaging/components/Counter.js new file mode 100644 index 00000000..97eda01c --- /dev/null +++ b/extension/examples/react-counter-messaging/components/Counter.js @@ -0,0 +1,62 @@ +import React, { Component } from 'react'; + +const withDevTools = + // process.env.NODE_ENV === 'development' && + typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__; + +class Counter extends Component { + constructor() { + super(); + this.state = { counter: 0 }; + + this.increment = this.increment.bind(this); + this.decrement = this.decrement.bind(this); + } + + componentWillMount() { + if (withDevTools) { + this.devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect(); + this.unsubscribe = this.devTools.subscribe((message) => { + // Implement monitors actions. + // For example time traveling: + if ( + message.type === 'DISPATCH' && + message.payload.type === 'JUMP_TO_STATE' + ) { + this.setState(message.state); + } + }); + } + } + + componentWillUnmount() { + if (withDevTools) { + this.unsubscribe(); // Use if you have other subscribers from other components. + window.__REDUX_DEVTOOLS_EXTENSION__.disconnect(); // If there aren't other subscribers. + } + } + + increment() { + const state = { counter: this.state.counter + 1 }; + if (withDevTools) this.devTools.send('increment', state); + this.setState(state); + } + + decrement() { + const state = { counter: this.state.counter - 1 }; + if (withDevTools) this.devTools.send('decrement', state); + this.setState(state); + } + + render() { + const { counter } = this.state; + return ( +

+ Clicked: {counter} times {' '} + +

+ ); + } +} + +export default Counter; diff --git a/extension/examples/react-counter-messaging/index.html b/extension/examples/react-counter-messaging/index.html new file mode 100644 index 00000000..f877ce0b --- /dev/null +++ b/extension/examples/react-counter-messaging/index.html @@ -0,0 +1,10 @@ + + + + React counter example + + +
+ + + diff --git a/extension/examples/react-counter-messaging/index.js b/extension/examples/react-counter-messaging/index.js new file mode 100644 index 00000000..988779bb --- /dev/null +++ b/extension/examples/react-counter-messaging/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import { render } from 'react-dom'; +import Counter from './components/Counter'; + +render(, document.getElementById('root')); diff --git a/extension/examples/react-counter-messaging/package.json b/extension/examples/react-counter-messaging/package.json new file mode 100644 index 00000000..97db9897 --- /dev/null +++ b/extension/examples/react-counter-messaging/package.json @@ -0,0 +1,33 @@ +{ + "name": "react-counter-example", + "version": "0.0.0", + "description": "React counter example", + "scripts": { + "start": "webpack-dev-server --progress" + }, + "repository": { + "type": "git", + "url": "https://github.com/zalmoxisus/redux-devtools-extension.git" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/zalmoxisus/redux-devtools-extension/issues" + }, + "homepage": "https://github.com/zalmoxisus/redux-devtools-extension", + "dependencies": { + "react": "^16.0.0", + "react-dom": "^16.0.0" + }, + "devDependencies": { + "babel-cli": "^6.3.17", + "babel-core": "^6.3.17", + "babel-loader": "^7.0.0", + "babel-preset-es2015": "^6.0.0", + "babel-preset-react": "6.3.13", + "babel-preset-stage-0": "^6.3.13", + "webpack": "^4.0.0", + "webpack-cli": "^3.2.0", + "webpack-dev-server": "^3.0.0", + "webpack-hot-middleware": "^2.2.0" + } +} diff --git a/extension/examples/react-counter-messaging/webpack.config.js b/extension/examples/react-counter-messaging/webpack.config.js new file mode 100644 index 00000000..43f3ab5b --- /dev/null +++ b/extension/examples/react-counter-messaging/webpack.config.js @@ -0,0 +1,25 @@ +var path = require('path'); +var webpack = require('webpack'); + +module.exports = { + mode: 'development', + devtool: 'source-map', + entry: ['./index'], + output: { + path: path.join(__dirname, 'dist'), + filename: 'bundle.js', + publicPath: '/static/', + }, + module: { + rules: [ + { + test: /\.js$/, + loaders: ['babel-loader'], + exclude: /node_modules/, + }, + ], + }, + devServer: { + port: 4004, + }, +}; diff --git a/extension/examples/router/.babelrc b/extension/examples/router/.babelrc new file mode 100644 index 00000000..6cc845b9 --- /dev/null +++ b/extension/examples/router/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["es2015", "stage-0", "react"], + "plugins": ["add-module-exports", "transform-decorators-legacy"] +} diff --git a/extension/examples/router/actions/todos.js b/extension/examples/router/actions/todos.js new file mode 100644 index 00000000..64247221 --- /dev/null +++ b/extension/examples/router/actions/todos.js @@ -0,0 +1,25 @@ +import * as types from '../constants/ActionTypes'; + +export function addTodo(text) { + return { type: types.ADD_TODO, text }; +} + +export function deleteTodo(id) { + return { type: types.DELETE_TODO, id }; +} + +export function editTodo(id, text) { + return { type: types.EDIT_TODO, id, text }; +} + +export function completeTodo(id) { + return { type: types.COMPLETE_TODO, id }; +} + +export function completeAll() { + return { type: types.COMPLETE_ALL }; +} + +export function clearCompleted() { + return { type: types.CLEAR_COMPLETED }; +} diff --git a/extension/examples/router/components/Footer.js b/extension/examples/router/components/Footer.js new file mode 100644 index 00000000..8972bd8a --- /dev/null +++ b/extension/examples/router/components/Footer.js @@ -0,0 +1,76 @@ +import React, { PropTypes, Component } from 'react'; +import classnames from 'classnames'; +import { + SHOW_ALL, + SHOW_COMPLETED, + SHOW_ACTIVE, +} from '../constants/TodoFilters'; + +const FILTER_TITLES = { + [SHOW_ALL]: 'All', + [SHOW_ACTIVE]: 'Active', + [SHOW_COMPLETED]: 'Completed', +}; + +class Footer extends Component { + renderTodoCount() { + const { activeCount } = this.props; + const itemWord = activeCount === 1 ? 'item' : 'items'; + + return ( + + {activeCount || 'No'} {itemWord} left + + ); + } + + renderFilterLink(filter) { + const title = FILTER_TITLES[filter]; + const { filter: selectedFilter, onShow } = this.props; + + return ( +
onShow(filter)} + > + {title} + + ); + } + + renderClearButton() { + const { completedCount, onClearCompleted } = this.props; + if (completedCount > 0) { + return ( + + ); + } + } + + render() { + return ( +
+ {this.renderTodoCount()} +
    + {[SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED].map((filter) => ( +
  • {this.renderFilterLink(filter)}
  • + ))} +
+ {this.renderClearButton()} +
+ ); + } +} + +Footer.propTypes = { + completedCount: PropTypes.number.isRequired, + activeCount: PropTypes.number.isRequired, + filter: PropTypes.string.isRequired, + onClearCompleted: PropTypes.func.isRequired, + onShow: PropTypes.func.isRequired, +}; + +export default Footer; diff --git a/extension/examples/router/components/Header.js b/extension/examples/router/components/Header.js new file mode 100644 index 00000000..e09a2e27 --- /dev/null +++ b/extension/examples/router/components/Header.js @@ -0,0 +1,30 @@ +import React, { PropTypes, Component } from 'react'; +import TodoTextInput from './TodoTextInput'; + +class Header extends Component { + handleSave(text) { + if (text.length !== 0) { + this.props.addTodo(text); + } + } + + render() { + const { path } = this.props; + return ( +
+

{path}

+ +
+ ); + } +} + +Header.propTypes = { + addTodo: PropTypes.func.isRequired, +}; + +export default Header; diff --git a/extension/examples/router/components/MainSection.js b/extension/examples/router/components/MainSection.js new file mode 100644 index 00000000..51b86378 --- /dev/null +++ b/extension/examples/router/components/MainSection.js @@ -0,0 +1,94 @@ +import React, { Component, PropTypes } from 'react'; +import TodoItem from './TodoItem'; +import Footer from './Footer'; +import { + SHOW_ALL, + SHOW_COMPLETED, + SHOW_ACTIVE, +} from '../constants/TodoFilters'; + +const TODO_FILTERS = { + [SHOW_ALL]: () => true, + [SHOW_ACTIVE]: (todo) => !todo.completed, + [SHOW_COMPLETED]: (todo) => todo.completed, +}; + +class MainSection extends Component { + constructor(props, context) { + super(props, context); + this.state = { filter: SHOW_ALL }; + } + + handleClearCompleted() { + const atLeastOneCompleted = this.props.todos.some((todo) => todo.completed); + if (atLeastOneCompleted) { + this.props.actions.clearCompleted(); + } + } + + handleShow(filter) { + this.setState({ filter }); + } + + renderToggleAll(completedCount) { + const { todos, actions } = this.props; + if (todos.length > 0) { + return ( + + ); + } + } + + renderFooter(completedCount) { + const { todos } = this.props; + const { filter } = this.state; + const activeCount = todos.length - completedCount; + + if (todos.length) { + return ( +