diff --git a/.eslintrc.json b/.eslintrc.json index 0f9dec0d..1fa89a98 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,7 +3,9 @@ "react", "prettier", "@typescript-eslint", - "eslint-comments" + "eslint-comments", + "lodash", + "import" ], "extends": [ "eslint:recommended", @@ -32,7 +34,11 @@ "settings": { "react": { "version": "detect" - } + }, + "import/resolver": { + "typescript": {} + }, + "import/internal-regex": "^(electron|react)$" }, "rules": { "func-names": [ @@ -93,10 +99,30 @@ "@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/consistent-type-imports": [ + "@typescript-eslint/consistent-type-imports": [ "error", { "disallowTypeAnnotations": false } ], + "lodash/prop-shorthand": [ "error", "always" ], + "lodash/import-scope": [ "error", "method" ], + "lodash/collection-return": "error", + "lodash/collection-method-value": "error", + "import/no-extraneous-dependencies": "error", + "import/no-anonymous-default-export": "error", + "import/order": [ "error", { - "disallowTypeAnnotations": false + "groups": [ + "builtin", + "internal", + "external", + "parent", + "sibling", + "index" + ], + "newlines-between": "always", + "alphabetize": { + "order": "asc", + "orderImportKind": "desc", + "caseInsensitive": true + } } ] } diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f2597d2b..569dda76 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,11 +35,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -50,7 +50,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -64,4 +64,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/e2e_comment.yml b/.github/workflows/e2e_comment.yml index e1d9c5fc..573a4d59 100644 --- a/.github/workflows/e2e_comment.yml +++ b/.github/workflows/e2e_comment.yml @@ -14,14 +14,14 @@ jobs: WORKFLOW_RUN_INFO: ${{ toJSON(github.event.workflow_run) }} run: echo "$WORKFLOW_RUN_INFO" - name: Download Artifacts - uses: dawidd6/action-download-artifact@v2.27.0 + uses: dawidd6/action-download-artifact@v3.1.4 with: github_token: ${{ secrets.GITHUB_TOKEN }} workflow: nodejs.yml run_id: ${{ github.event.workflow_run.id }} name: e2e - name: Get PR number - uses: dawidd6/action-download-artifact@v2.27.0 + uses: dawidd6/action-download-artifact@v3.1.4 with: github_token: ${{ secrets.GITHUB_TOKEN }} workflow: nodejs.yml @@ -29,7 +29,7 @@ jobs: name: pr_num - name: Read the pr_num file id: pr_num_reader - uses: juliangruber/read-file-action@v1.1.6 + uses: juliangruber/read-file-action@v1.1.7 with: path: ./pr_num.txt - name: List images diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 01cb8e95..d42e2995 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -22,15 +22,17 @@ jobs: fail-fast: false steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} + - name: Fix node-gyp and Python + run: python3 -m pip install packaging setuptools - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - uses: actions/cache/restore@v3 + - uses: actions/cache/restore@v4 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', 'app/yarn.lock') }} @@ -83,8 +85,14 @@ jobs: - name: Run E2E Tests if: runner.os != 'Linux' run: yarn run test:e2e + - name: Run E2E Tests on Linux + if: runner.os == 'Linux' + uses: GabrielBB/xvfb-action@v1.6 + with: + run: yarn run test:e2e + env: + SHELL: /bin/bash - name: Archive E2E test screenshot - if: runner.os != 'Linux' uses: actions/upload-artifact@v3 with: name: e2e @@ -100,7 +108,7 @@ jobs: with: name: pr_num path: ./pr_num.txt - - uses: actions/cache/save@v3 + - uses: actions/cache/save@v4 if: github.event_name == 'push' with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} @@ -120,15 +128,17 @@ jobs: fail-fast: false steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} + - name: Fix node-gyp and Python + run: python3 -m pip install packaging setuptools - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - uses: actions/cache/restore@v3 + - uses: actions/cache/restore@v4 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', 'app/yarn.lock') }} diff --git a/app/auto-updater-linux.ts b/app/auto-updater-linux.ts index 4865fa4c..aa95c1d7 100644 --- a/app/auto-updater-linux.ts +++ b/app/auto-updater-linux.ts @@ -1,6 +1,7 @@ -import fetch from 'electron-fetch'; import {EventEmitter} from 'events'; +import fetch from 'electron-fetch'; + class AutoUpdater extends EventEmitter implements Electron.AutoUpdater { updateURL!: string; quitAndInstall() { @@ -46,4 +47,6 @@ class AutoUpdater extends EventEmitter implements Electron.AutoUpdater { } } -export default new AutoUpdater(); +const autoUpdaterLinux = new AutoUpdater(); + +export default autoUpdaterLinux; diff --git a/app/commands.ts b/app/commands.ts index e201355d..469a5a3d 100644 --- a/app/commands.ts +++ b/app/commands.ts @@ -1,5 +1,6 @@ -import type {BrowserWindow} from 'electron'; import {app, Menu} from 'electron'; +import type {BrowserWindow} from 'electron'; + import {openConfig, getConfig} from './config'; import {updatePlugins} from './plugins'; import {installCLI} from './utils/cli-install'; diff --git a/app/config.ts b/app/config.ts index 6c3d66cc..b4613d57 100644 --- a/app/config.ts +++ b/app/config.ts @@ -1,11 +1,14 @@ +import {app} from 'electron'; + import chokidar from 'chokidar'; -import notify from './notify'; + +import type {parsedConfig, configOptions} from '../typings/config'; + import {_import, getDefaultConfig} from './config/import'; import _openConfig from './config/open'; import {cfgPath, cfgDir} from './config/paths'; +import notify from './notify'; import {getColorMap} from './utils/colors'; -import type {parsedConfig, configOptions} from '../lib/config'; -import {app} from 'electron'; const watchers: Function[] = []; let cfg: parsedConfig = {} as any; diff --git a/app/config/import.ts b/app/config/import.ts index 13821c3b..b9965375 100644 --- a/app/config/import.ts +++ b/app/config/import.ts @@ -1,9 +1,11 @@ import {readFileSync, mkdirpSync} from 'fs-extra'; -import {defaultCfg, cfgPath, plugs, defaultPlatformKeyPath} from './paths'; -import {_init} from './init'; + +import type {rawConfig} from '../../typings/config'; import notify from '../notify'; -import type {rawConfig} from '../../lib/config'; + +import {_init} from './init'; import {migrateHyper3Config} from './migrate'; +import {defaultCfg, cfgPath, plugs, defaultPlatformKeyPath} from './paths'; let defaultConfig: rawConfig; diff --git a/app/config/init.ts b/app/config/init.ts index 00a58bbd..a41b864c 100644 --- a/app/config/init.ts +++ b/app/config/init.ts @@ -1,8 +1,10 @@ import vm from 'vm'; + +import merge from 'lodash/merge'; + +import type {parsedConfig, rawConfig, configOptions} from '../../typings/config'; import notify from '../notify'; import mapKeys from '../utils/map-keys'; -import type {parsedConfig, rawConfig, configOptions} from '../../lib/config'; -import _ from 'lodash'; const _extract = (script?: vm.Script): Record => { const module: Record = {}; @@ -19,7 +21,7 @@ const _syntaxValidation = (cfg: string) => { return new vm.Script(cfg, {filename: '.hyper.js'}); } catch (_err) { const err = _err as {name: string}; - notify(`Error loading config: ${err.name}`, `${err}`, {error: err}); + notify(`Error loading config: ${err.name}`, JSON.stringify(err), {error: err}); } }; @@ -44,7 +46,7 @@ const _init = (userCfg: rawConfig, defaultCfg: rawConfig): parsedConfig => { if (!conf.profiles.map((p) => p.name).includes(conf.defaultProfile)) { conf.defaultProfile = conf.profiles[0].name; } - return _.merge({}, defaultCfg.config, conf); + return merge({}, defaultCfg.config, conf); } else { notify('Error reading configuration: `config` key is missing'); return defaultCfg.config || ({} as configOptions); @@ -53,8 +55,8 @@ const _init = (userCfg: rawConfig, defaultCfg: rawConfig): parsedConfig => { // Merging platform specific keymaps with user defined keymaps keymaps: mapKeys({...defaultCfg.keymaps, ...userCfg?.keymaps}), // Ignore undefined values in plugin and localPlugins array Issue #1862 - plugins: (userCfg?.plugins && userCfg.plugins.filter(Boolean)) || [], - localPlugins: (userCfg?.localPlugins && userCfg.localPlugins.filter(Boolean)) || [] + plugins: userCfg?.plugins?.filter(Boolean) || [], + localPlugins: userCfg?.localPlugins?.filter(Boolean) || [] }; }; diff --git a/app/config/migrate.ts b/app/config/migrate.ts index b74a2603..522da1e9 100644 --- a/app/config/migrate.ts +++ b/app/config/migrate.ts @@ -1,14 +1,16 @@ -import {parse, prettyPrint} from 'recast'; -import {builders, namedTypes} from 'ast-types'; -import * as babelParser from 'recast/parsers/babel'; -import {copy, copySync, existsSync, readFileSync, writeFileSync} from 'fs-extra'; import {dirname, resolve} from 'path'; -import _ from 'lodash'; + +import {builders, namedTypes} from 'ast-types'; +import type {ExpressionKind} from 'ast-types/lib/gen/kinds'; +import {copy, copySync, existsSync, readFileSync, writeFileSync} from 'fs-extra'; +import merge from 'lodash/merge'; +import {parse, prettyPrint} from 'recast'; +import * as babelParser from 'recast/parsers/babel'; import notify from '../notify'; + import {_extractDefault} from './init'; import {cfgDir, cfgPath, defaultCfg, legacyCfgPath, plugs, schemaFile, schemaPath} from './paths'; -import type {ExpressionKind} from 'ast-types/lib/gen/kinds'; // function to remove all json serializable entries from an array expression function removeElements(node: namedTypes.ArrayExpression): namedTypes.ArrayExpression { @@ -166,7 +168,7 @@ export const migrateHyper3Config = () => { try { const legacyCfgRaw = readFileSync(legacyCfgPath, 'utf8'); const legacyCfgData = _extractDefault(legacyCfgRaw); - newCfgData = _.merge({}, defaultCfgData, legacyCfgData); + newCfgData = merge({}, defaultCfgData, legacyCfgData); const pluginCode = configToPlugin(legacyCfgRaw); if (pluginCode) { diff --git a/app/config/open.ts b/app/config/open.ts index 1d5047c9..264c2292 100644 --- a/app/config/open.ts +++ b/app/config/open.ts @@ -1,8 +1,11 @@ -import {shell} from 'electron'; -import {cfgPath} from './paths'; -import * as Registry from 'native-reg'; import {exec} from 'child_process'; +import {shell} from 'electron'; + +import * as Registry from 'native-reg'; + +import {cfgPath} from './paths'; + const getUserChoiceKey = () => { try { // Load FileExts keys for .js files @@ -57,7 +60,7 @@ const openNotepad = (file: string) => }); }); -export default () => { +const openConfig = () => { // Windows opens .js files with WScript.exe by default // If the user hasn't set up an editor for .js files, we fallback to notepad. if (process.platform === 'win32') { @@ -73,3 +76,5 @@ export default () => { } return shell.openPath(cfgPath).then((error) => error === ''); }; + +export default openConfig; diff --git a/app/config/paths.ts b/app/config/paths.ts index a0b6fa52..2c2ce283 100644 --- a/app/config/paths.ts +++ b/app/config/paths.ts @@ -1,8 +1,10 @@ // This module exports paths, names, and other metadata that is referenced -import {homedir} from 'os'; -import {app} from 'electron'; import {statSync} from 'fs'; +import {homedir} from 'os'; import {resolve, join} from 'path'; + +import {app} from 'electron'; + import isDev from 'electron-is-dev'; const cfgFile = 'hyper.json'; @@ -15,15 +17,15 @@ const homeDirectory = homedir(); let cfgDir = process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, 'Hyper') : process.platform === 'win32' - ? app.getPath('userData') - : join(homeDirectory, '.config', 'Hyper'); + ? app.getPath('userData') + : join(homeDirectory, '.config', 'Hyper'); const legacyCfgPath = join( process.env.XDG_CONFIG_HOME !== undefined ? join(process.env.XDG_CONFIG_HOME, 'hyper') : process.platform == 'win32' - ? app.getPath('userData') - : homedir(), + ? app.getPath('userData') + : homedir(), '.hyper.js' ); diff --git a/app/config/windows.ts b/app/config/windows.ts index 6c53249d..4cd6d500 100644 --- a/app/config/windows.ts +++ b/app/config/windows.ts @@ -1,6 +1,7 @@ -import Config from 'electron-store'; import type {BrowserWindow} from 'electron'; +import Config from 'electron-store'; + export const defaults = { windowPosition: [50, 50] as [number, number], windowSize: [540, 380] as [number, number] diff --git a/app/index.d.ts b/app/index.d.ts deleted file mode 100644 index 1349d7d9..00000000 --- a/app/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -// Dummy file, required by tsc diff --git a/app/index.ts b/app/index.ts index 9ad26c06..84a804a4 100644 --- a/app/index.ts +++ b/app/index.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line import/order import {cfgPath} from './config/paths'; // Print diagnostic information for a few arguments instead of running Hyper. @@ -11,28 +12,31 @@ if (['--help', '-v', '--version'].includes(process.argv[1])) { } // Enable remote module +// eslint-disable-next-line import/order import {initialize as remoteInitialize} from '@electron/remote/main'; remoteInitialize(); +// set up config +// eslint-disable-next-line import/order +import * as config from './config'; +config.setup(); + // Native import {resolve} from 'path'; // Packages import {app, BrowserWindow, Menu, screen} from 'electron'; -import {gitDescribe} from 'git-describe'; + import isDev from 'electron-is-dev'; -import * as config from './config'; - -// set up config -config.setup(); - -import * as plugins from './plugins'; -import {installCLI} from './utils/cli-install'; -import * as AppMenu from './menus/menu'; -import {newWindow} from './ui/window'; -import * as windowUtils from './utils/window-utils'; +import {gitDescribe} from 'git-describe'; import parseUrl from 'parse-url'; +import * as AppMenu from './menus/menu'; +import * as plugins from './plugins'; +import {newWindow} from './ui/window'; +import {installCLI} from './utils/cli-install'; +import * as windowUtils from './utils/window-utils'; + const windowSet = new Set([]); // expose to plugins diff --git a/app/menus/menu.ts b/app/menus/menu.ts index 93bb95ed..df877e69 100644 --- a/app/menus/menu.ts +++ b/app/menus/menu.ts @@ -1,21 +1,22 @@ // Packages -import type {BrowserWindow} from 'electron'; import {app, dialog, Menu} from 'electron'; +import type {BrowserWindow} from 'electron'; // Utilities +import {execCommand} from '../commands'; import {getConfig} from '../config'; import {icon} from '../config/paths'; -import viewMenu from './menus/view'; -import shellMenu from './menus/shell'; -import editMenu from './menus/edit'; -import toolsMenu from './menus/tools'; -import windowMenu from './menus/window'; -import helpMenu from './menus/help'; -import darwinMenu from './menus/darwin'; import {getDecoratedKeymaps} from '../plugins'; -import {execCommand} from '../commands'; import {getRendererTypes} from '../utils/renderer-utils'; +import darwinMenu from './menus/darwin'; +import editMenu from './menus/edit'; +import helpMenu from './menus/help'; +import shellMenu from './menus/shell'; +import toolsMenu from './menus/tools'; +import viewMenu from './menus/view'; +import windowMenu from './menus/window'; + const appName = app.name; const appVersion = app.getVersion(); diff --git a/app/menus/menus/darwin.ts b/app/menus/menus/darwin.ts index cd7d793a..59e514d1 100644 --- a/app/menus/menus/darwin.ts +++ b/app/menus/menus/darwin.ts @@ -1,9 +1,9 @@ // This menu label is overrided by OSX to be the appName // The label is set to appName here so it matches actual behavior -import type {BrowserWindow, MenuItemConstructorOptions} from 'electron'; import {app} from 'electron'; +import type {BrowserWindow, MenuItemConstructorOptions} from 'electron'; -export default ( +const darwinMenu = ( commandKeys: Record, execCommand: (command: string, focusedWindow?: BrowserWindow) => void, showAbout: () => void @@ -55,3 +55,5 @@ export default ( ] }; }; + +export default darwinMenu; diff --git a/app/menus/menus/edit.ts b/app/menus/menus/edit.ts index a56b2e97..a9040f6e 100644 --- a/app/menus/menus/edit.ts +++ b/app/menus/menus/edit.ts @@ -1,6 +1,6 @@ import type {BrowserWindow, MenuItemConstructorOptions} from 'electron'; -export default ( +const editMenu = ( commandKeys: Record, execCommand: (command: string, focusedWindow?: BrowserWindow) => void ) => { @@ -147,3 +147,5 @@ export default ( submenu }; }; + +export default editMenu; diff --git a/app/menus/menus/help.ts b/app/menus/menus/help.ts index a560622e..3c9214c1 100644 --- a/app/menus/menus/help.ts +++ b/app/menus/menus/help.ts @@ -1,11 +1,14 @@ import {release} from 'os'; -import type {MenuItemConstructorOptions} from 'electron'; + import {app, shell, dialog, clipboard} from 'electron'; +import type {MenuItemConstructorOptions} from 'electron'; + import {getConfig, getPlugins} from '../../config'; -const {arch, env, platform, versions} = process; import {version} from '../../package.json'; -export default (commands: Record, showAbout: () => void): MenuItemConstructorOptions => { +const {arch, env, platform, versions} = process; + +const helpMenu = (commands: Record, showAbout: () => void): MenuItemConstructorOptions => { const submenu: MenuItemConstructorOptions[] = [ { label: `${app.name} Website`, @@ -107,3 +110,5 @@ ${JSON.stringify(getPlugins(), null, 2)} submenu }; }; + +export default helpMenu; diff --git a/app/menus/menus/shell.ts b/app/menus/menus/shell.ts index 50613674..651f071c 100644 --- a/app/menus/menus/shell.ts +++ b/app/menus/menus/shell.ts @@ -1,6 +1,6 @@ import type {BrowserWindow, MenuItemConstructorOptions} from 'electron'; -export default ( +const shellMenu = ( commandKeys: Record, execCommand: (command: string, focusedWindow?: BrowserWindow) => void, profiles: string[] @@ -100,3 +100,5 @@ export default ( ] }; }; + +export default shellMenu; diff --git a/app/menus/menus/tools.ts b/app/menus/menus/tools.ts index 83b2463c..ac377728 100644 --- a/app/menus/menus/tools.ts +++ b/app/menus/menus/tools.ts @@ -1,6 +1,6 @@ import type {BrowserWindow, MenuItemConstructorOptions} from 'electron'; -export default ( +const toolsMenu = ( commands: Record, execCommand: (command: string, focusedWindow?: BrowserWindow) => void ): MenuItemConstructorOptions => { @@ -45,3 +45,5 @@ export default ( ] }; }; + +export default toolsMenu; diff --git a/app/menus/menus/view.ts b/app/menus/menus/view.ts index c21b1ee7..d0a2b071 100644 --- a/app/menus/menus/view.ts +++ b/app/menus/menus/view.ts @@ -1,6 +1,6 @@ import type {BrowserWindow, MenuItemConstructorOptions} from 'electron'; -export default ( +const viewMenu = ( commandKeys: Record, execCommand: (command: string, focusedWindow?: BrowserWindow) => void ): MenuItemConstructorOptions => { @@ -55,3 +55,5 @@ export default ( ] }; }; + +export default viewMenu; diff --git a/app/menus/menus/window.ts b/app/menus/menus/window.ts index 8779c8fe..7ae142a6 100644 --- a/app/menus/menus/window.ts +++ b/app/menus/menus/window.ts @@ -1,6 +1,6 @@ import type {BrowserWindow, MenuItemConstructorOptions} from 'electron'; -export default ( +const windowMenu = ( commandKeys: Record, execCommand: (command: string, focusedWindow?: BrowserWindow) => void ): MenuItemConstructorOptions => { @@ -94,3 +94,5 @@ export default ( ] }; }; + +export default windowMenu; diff --git a/app/notifications.ts b/app/notifications.ts index 4ed9bf02..1a7abb06 100644 --- a/app/notifications.ts +++ b/app/notifications.ts @@ -1,8 +1,10 @@ -import ms from 'ms'; -import fetch from 'electron-fetch'; -import {version} from './package.json'; import type {BrowserWindow} from 'electron'; +import fetch from 'electron-fetch'; +import ms from 'ms'; + +import {version} from './package.json'; + const NEWS_URL = 'https://hyper-news.now.sh'; export default function fetchNotifications(win: BrowserWindow) { diff --git a/app/notify.ts b/app/notify.ts index a31f0305..ce5544fc 100644 --- a/app/notify.ts +++ b/app/notify.ts @@ -1,4 +1,5 @@ import {app, Notification} from 'electron'; + import {icon} from './config/paths'; export default function notify(title: string, body = '', details: {error?: any} = {}) { diff --git a/app/package.json b/app/package.json index a0095d53..a7c6f60f 100644 --- a/app/package.json +++ b/app/package.json @@ -13,16 +13,18 @@ "postinstall": "npx patch-package" }, "dependencies": { - "@babel/parser": "7.22.7", - "@electron/remote": "2.0.10", + "@babel/parser": "7.24.4", + "@electron/remote": "2.1.2", + "ast-types": "^0.16.1", "async-retry": "1.3.3", - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "color": "4.2.3", "default-shell": "1.0.1", + "electron-devtools-installer": "3.2.0", "electron-fetch": "1.9.1", "electron-is-dev": "2.0.0", - "electron-store": "8.1.0", - "fs-extra": "11.1.1", + "electron-store": "8.2.0", + "fs-extra": "11.2.0", "git-describe": "4.1.1", "lodash": "4.17.21", "ms": "2.1.3", @@ -31,13 +33,13 @@ "os-locale": "5.0.0", "parse-url": "8.1.0", "queue": "6.0.2", - "react": "17.0.2", - "react-dom": "17.0.2", - "recast": "0.23.2", - "semver": "7.5.4", + "react": "18.2.0", + "react-dom": "18.2.0", + "recast": "0.23.6", + "semver": "7.6.0", "shell-env": "3.0.1", "sudo-prompt": "^9.2.1", - "uuid": "9.0.0" + "uuid": "9.0.1" }, "optionalDependencies": { "native-reg": "1.1.1" diff --git a/app/plugins.ts b/app/plugins.ts index a839c435..8e460119 100644 --- a/app/plugins.ts +++ b/app/plugins.ts @@ -1,24 +1,28 @@ /* eslint-disable eslint-comments/disable-enable-pair */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-call */ -import type {BrowserWindow, App, MenuItemConstructorOptions} from 'electron'; -import {app, dialog, ipcMain as _ipcMain} from 'electron'; -import {resolve, basename} from 'path'; +import {exec, execFile} from 'child_process'; import {writeFileSync} from 'fs'; +import {resolve, basename} from 'path'; +import {promisify} from 'util'; + +import {app, dialog, ipcMain as _ipcMain} from 'electron'; +import type {BrowserWindow, App, MenuItemConstructorOptions} from 'electron'; +import React from 'react'; + import Config from 'electron-store'; import ms from 'ms'; -import React from 'react'; import ReactDom from 'react-dom'; + +import type {IpcMainWithCommands} from '../typings/common'; +import type {configOptions} from '../typings/config'; + import * as config from './config'; +import {plugs} from './config/paths'; import notify from './notify'; import {availableExtensions} from './plugins/extensions'; import {install} from './plugins/install'; -import {plugs} from './config/paths'; import mapKeys from './utils/map-keys'; -import type {configOptions} from '../lib/config'; -import {promisify} from 'util'; -import {exec, execFile} from 'child_process'; -import type {IpcMainWithCommands} from '../common'; // local storage const cache = new Config(); @@ -467,3 +471,10 @@ ipcMain.handle('child_process.exec', (event, command, options) => { ipcMain.handle('child_process.execFile', (event, file, args, options) => { return promisify(execFile)(file, args, options); }); + +ipcMain.handle('getLoadedPluginVersions', () => getLoadedPluginVersions()); +ipcMain.handle('getPaths', () => getPaths()); +ipcMain.handle('getBasePaths', () => getBasePaths()); +ipcMain.handle('getDeprecatedConfig', () => getDeprecatedConfig()); +ipcMain.handle('getDecoratedConfig', (e, profile) => getDecoratedConfig(profile)); +ipcMain.handle('getDecoratedKeymaps', () => getDecoratedKeymaps()); diff --git a/app/plugins/install.ts b/app/plugins/install.ts index 61fec231..35ed7245 100644 --- a/app/plugins/install.ts +++ b/app/plugins/install.ts @@ -1,6 +1,8 @@ import cp from 'child_process'; -import queue from 'queue'; + import ms from 'ms'; +import queue from 'queue'; + import {yarn, plugs} from '../config/paths'; export const install = (fn: (err: string | null) => void) => { diff --git a/app/rpc.ts b/app/rpc.ts index 13f41e67..aead6363 100644 --- a/app/rpc.ts +++ b/app/rpc.ts @@ -1,8 +1,11 @@ import {EventEmitter} from 'events'; -import type {BrowserWindow, IpcMainEvent} from 'electron'; + import {ipcMain} from 'electron'; +import type {BrowserWindow, IpcMainEvent} from 'electron'; + import {v4 as uuidv4} from 'uuid'; -import type {TypedEmitter, MainEvents, RendererEvents, FilterNever} from '../common'; + +import type {TypedEmitter, MainEvents, RendererEvents, FilterNever} from '../typings/common'; export class Server { emitter: TypedEmitter; @@ -28,7 +31,7 @@ export class Server { // to support reloading the window and re-initializing // the channel this.wc.on('did-finish-load', () => { - this.wc.send('init', uid); + this.wc.send('init', uid, win.profileName); }); } @@ -73,6 +76,8 @@ export class Server { } } -export default (win: BrowserWindow) => { +const createRPC = (win: BrowserWindow) => { return new Server(win); }; + +export default createRPC; diff --git a/app/session.ts b/app/session.ts index a8a0f8b1..4b706b3d 100644 --- a/app/session.ts +++ b/app/session.ts @@ -1,14 +1,17 @@ import {EventEmitter} from 'events'; -import {StringDecoder} from 'string_decoder'; -import defaultShell from 'default-shell'; -import {getDecoratedEnv} from './plugins'; -import {productName, version} from './package.json'; -import * as config from './config'; -import type {IPty, IWindowsPtyForkOptions, spawn as npSpawn} from 'node-pty'; -import {cliScriptPath} from './config/paths'; import {dirname} from 'path'; -import shellEnv from 'shell-env'; +import {StringDecoder} from 'string_decoder'; + +import defaultShell from 'default-shell'; +import type {IPty, IWindowsPtyForkOptions, spawn as npSpawn} from 'node-pty'; import osLocale from 'os-locale'; +import shellEnv from 'shell-env'; + +import * as config from './config'; +import {cliScriptPath} from './config/paths'; +import {productName, version} from './package.json'; +import {getDecoratedEnv} from './plugins'; +import {getFallBackShellConfig} from './utils/shell-fallback'; const createNodePtyError = () => new Error( @@ -182,15 +185,32 @@ export default class Session extends EventEmitter { // this will inform users in case there are errors in the config instead of instant exit const runDuration = new Date().getTime() - this.initTimestamp; if (e.exitCode > 0 && runDuration < 1000) { - const defaultShellConfig = {shell: defaultShell, shellArgs: defaultShellArgs}; - const msg = ` + const fallBackShellConfig = getFallBackShellConfig(shell, shellArgs, defaultShell, defaultShellArgs); + if (fallBackShellConfig) { + const msg = ` shell exited in ${runDuration} ms with exit code ${e.exitCode} please check the shell config: ${JSON.stringify({shell, shellArgs}, undefined, 2)} -fallback to default shell config: ${JSON.stringify(defaultShellConfig, undefined, 2)} +using fallback shell config: ${JSON.stringify(fallBackShellConfig, undefined, 2)} `; - console.warn(msg); - this.batcher?.write(msg.replace(/\n/g, '\r\n')); - this.init({uid, rows, cols, cwd, ...defaultShellConfig, profile}); + console.warn(msg); + this.batcher?.write(msg.replace(/\n/g, '\r\n')); + this.init({ + uid, + rows, + cols, + cwd, + shell: fallBackShellConfig.shell, + shellArgs: fallBackShellConfig.shellArgs, + profile + }); + } else { + const msg = ` +shell exited in ${runDuration} ms with exit code ${e.exitCode} +No fallback available, please check the shell config. +`; + console.warn(msg); + this.batcher?.write(msg.replace(/\n/g, '\r\n')); + } } else { this.ended = true; this.emit('exit'); diff --git a/app/tsconfig.json b/app/tsconfig.json index d18cc80a..5c7450fd 100644 --- a/app/tsconfig.json +++ b/app/tsconfig.json @@ -7,6 +7,8 @@ }, "include": [ "./**/*", - "./package.json" + "./package.json", + "../typings/extend-electron.d.ts", + "../typings/ext-modules.d.ts" ] } diff --git a/app/ui/contextmenu.ts b/app/ui/contextmenu.ts index 5f0bc73d..634ea882 100644 --- a/app/ui/contextmenu.ts +++ b/app/ui/contextmenu.ts @@ -1,9 +1,11 @@ +import type {MenuItemConstructorOptions, BrowserWindow} from 'electron'; + +import {execCommand} from '../commands'; +import {getProfiles} from '../config'; import editMenu from '../menus/menus/edit'; import shellMenu from '../menus/menus/shell'; -import {execCommand} from '../commands'; import {getDecoratedKeymaps} from '../plugins'; -import type {MenuItemConstructorOptions, BrowserWindow} from 'electron'; -import {getProfiles} from '../config'; + const separator: MenuItemConstructorOptions = {type: 'separator'}; const getCommandKeys = (keymaps: Record): Record => @@ -21,7 +23,7 @@ const filterCutCopy = (selection: string, menuItem: MenuItemConstructorOptions) return menuItem; }; -export default ( +const contextMenuTemplate = ( createWindow: (fn?: (win: BrowserWindow) => void, options?: Record) => BrowserWindow, selection: string ) => { @@ -36,3 +38,5 @@ export default ( .concat(separator, _shell) .filter((menuItem) => !Object.prototype.hasOwnProperty.call(menuItem, 'enabled') || menuItem.enabled); }; + +export default contextMenuTemplate; diff --git a/app/ui/window.ts b/app/ui/window.ts index 519adb1c..87eba6d7 100644 --- a/app/ui/window.ts +++ b/app/ui/window.ts @@ -1,26 +1,30 @@ -import type {BrowserWindowConstructorOptions} from 'electron'; -import {app, BrowserWindow, shell, Menu} from 'electron'; +import {existsSync} from 'fs'; import {isAbsolute, normalize, sep} from 'path'; import {URL, fileURLToPath} from 'url'; -import {v4 as uuidv4} from 'uuid'; -import isDev from 'electron-is-dev'; -import updater from '../updater'; -import toElectronBackgroundColor from '../utils/to-electron-background-color'; -import {icon, homeDirectory} from '../config/paths'; -import createRPC from '../rpc'; -import notify from '../notify'; -import fetchNotifications from '../notifications'; -import Session from '../session'; -import contextMenuTemplate from './contextmenu'; -import {execCommand} from '../commands'; -import {setRendererType, unsetRendererType} from '../utils/renderer-utils'; -import {decorateSessionOptions, decorateSessionClass} from '../plugins'; + +import {app, BrowserWindow, shell, Menu} from 'electron'; +import type {BrowserWindowConstructorOptions} from 'electron'; + import {enable as remoteEnable} from '@electron/remote/main'; -import type {configOptions} from '../../lib/config'; +import isDev from 'electron-is-dev'; import {getWorkingDirectoryFromPID} from 'native-process-working-directory'; -import {existsSync} from 'fs'; -import type {sessionExtraOptions} from '../../common'; +import {v4 as uuidv4} from 'uuid'; + +import type {sessionExtraOptions} from '../../typings/common'; +import type {configOptions} from '../../typings/config'; +import {execCommand} from '../commands'; import {getDefaultProfile} from '../config'; +import {icon, homeDirectory} from '../config/paths'; +import fetchNotifications from '../notifications'; +import notify from '../notify'; +import {decorateSessionOptions, decorateSessionClass} from '../plugins'; +import createRPC from '../rpc'; +import Session from '../session'; +import updater from '../updater'; +import {setRendererType, unsetRendererType} from '../utils/renderer-utils'; +import toElectronBackgroundColor from '../utils/to-electron-background-color'; + +import contextMenuTemplate from './contextmenu'; export function newWindow( options_: BrowserWindowConstructorOptions, diff --git a/app/updater.ts b/app/updater.ts index e38f75bc..c7d07d4d 100644 --- a/app/updater.ts +++ b/app/updater.ts @@ -1,14 +1,15 @@ // Packages -import type {BrowserWindow, AutoUpdater} from 'electron'; import electron, {app} from 'electron'; -import ms from 'ms'; +import type {BrowserWindow, AutoUpdater} from 'electron'; + import retry from 'async-retry'; +import ms from 'ms'; // Utilities -import {version} from './package.json'; -import {getDecoratedConfig} from './plugins'; import autoUpdaterLinux from './auto-updater-linux'; import {getDefaultProfile} from './config'; +import {version} from './package.json'; +import {getDecoratedConfig} from './plugins'; const {platform} = process; const isLinux = platform === 'linux'; @@ -71,7 +72,7 @@ async function init() { isInit = true; } -export default (win: BrowserWindow) => { +const updater = (win: BrowserWindow) => { if (!isInit) { void init(); } @@ -115,3 +116,5 @@ export default (win: BrowserWindow) => { } }); }; + +export default updater; diff --git a/app/utils/cli-install.ts b/app/utils/cli-install.ts index 420bde39..3a5b9930 100644 --- a/app/utils/cli-install.ts +++ b/app/utils/cli-install.ts @@ -1,13 +1,16 @@ import {existsSync, readlink, symlink} from 'fs'; import path from 'path'; -import notify from '../notify'; -import {cliScriptPath, cliLinkPath} from '../config/paths'; +import {promisify} from 'util'; + +import {clipboard, dialog} from 'electron'; + +import {mkdirpSync} from 'fs-extra'; import * as Registry from 'native-reg'; import type {ValueType} from 'native-reg'; import sudoPrompt from 'sudo-prompt'; -import {clipboard, dialog} from 'electron'; -import {mkdirpSync} from 'fs-extra'; -import {promisify} from 'util'; + +import {cliScriptPath, cliLinkPath} from '../config/paths'; +import notify from '../notify'; const readLink = promisify(readlink); const symLink = promisify(symlink); diff --git a/app/utils/map-keys.ts b/app/utils/map-keys.ts index e9c79423..4bcb9a1d 100644 --- a/app/utils/map-keys.ts +++ b/app/utils/map-keys.ts @@ -11,7 +11,7 @@ const generatePrefixedCommand = (command: string, shortcuts: string[]) => { return result; }; -export default (config: Record) => { +const mapKeys = (config: Record) => { return Object.keys(config).reduce((keymap: Record, command: string) => { if (!command) { return keymap; @@ -39,3 +39,5 @@ export default (config: Record) => { return keymap; }, {}); }; + +export default mapKeys; diff --git a/app/utils/shell-fallback.ts b/app/utils/shell-fallback.ts new file mode 100644 index 00000000..0eb7df4b --- /dev/null +++ b/app/utils/shell-fallback.ts @@ -0,0 +1,25 @@ +export const getFallBackShellConfig = ( + shell: string, + shellArgs: string[], + defaultShell: string, + defaultShellArgs: string[] +): { + shell: string; + shellArgs: string[]; +} | null => { + if (shellArgs.length > 0) { + return { + shell, + shellArgs: [] + }; + } + + if (shell != defaultShell) { + return { + shell: defaultShell, + shellArgs: defaultShellArgs + }; + } + + return null; +}; diff --git a/app/utils/to-electron-background-color.ts b/app/utils/to-electron-background-color.ts index fc4a9799..a758f528 100644 --- a/app/utils/to-electron-background-color.ts +++ b/app/utils/to-electron-background-color.ts @@ -4,7 +4,7 @@ import Color from 'color'; // returns a background color that's in hex // format including the alpha channel (e.g.: `#00000050`) // input can be any css value (rgb, hsl, string…) -export default (bgColor: string) => { +const toElectronBackgroundColor = (bgColor: string) => { const color = Color(bgColor); if (color.alpha() === 1) { @@ -15,3 +15,5 @@ export default (bgColor: string) => { const alphaHex = Math.round(color.alpha() * 255).toString(16); return `#${alphaHex}${color.hex().toString().slice(1)}`; }; + +export default toElectronBackgroundColor; diff --git a/app/yarn.lock b/app/yarn.lock index c36909d9..8e654f1d 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -2,15 +2,15 @@ # yarn lockfile v1 -"@babel/parser@7.22.7": - version "7.22.7" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae" - integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== +"@babel/parser@7.24.4": + version "7.24.4" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" + integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== -"@electron/remote@2.0.10": - version "2.0.10" - resolved "https://registry.npmjs.org/@electron/remote/-/remote-2.0.10.tgz#133e2f607b1861ac249bd78b5abd1e961feed713" - integrity sha512-3SFKKaQXcyWgwmibud+UqJl/XlHOgLcI3fwtB9pNelPSJAcTxocOJrF6FaxBIQaj1+R05Di6xuAswZpXAW7xhA== +"@electron/remote@2.1.2": + version "2.1.2" + resolved "https://registry.npmjs.org/@electron/remote/-/remote-2.1.2.tgz#52a97c8faa5b769155b649ef262f2f8c851776e6" + integrity sha512-EPwNx+nhdrTBxyCqXt/pftoQg/ybtWDW3DUWHafejvnB1ZGGfMpv6e15D8KeempocjXe78T7WreyGGb3mlZxdA== "@types/semver@^7.3.8": version "7.3.8" @@ -47,16 +47,6 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -assert@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" - integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== - dependencies: - es6-object-assign "^1.1.0" - is-nan "^1.2.1" - object-is "^1.0.1" - util "^0.12.0" - ast-types@^0.16.1: version "0.16.1" resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz#7a9da1617c9081bc121faafe91711b4c8bb81da2" @@ -76,16 +66,24 @@ atomically@^1.7.0: resolved "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz#c07a0458432ea6dbc9a3506fffa424b48bccaafe" integrity sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w== -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== binary-extensions@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + braces@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -93,18 +91,10 @@ braces@~3.0.2: dependencies: fill-range "^7.0.1" -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -chokidar@^3.5.3: - version "3.5.3" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== +chokidar@^3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -144,6 +134,11 @@ color@4.2.3: color-convert "^2.0.1" color-string "^1.9.0" +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + conf@^10.2.0: version "10.2.0" resolved "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz#838e757be963f1a2386dfe048a98f8f69f7b55d6" @@ -160,6 +155,11 @@ conf@^10.2.0: pkg-up "^3.1.0" semver "^7.3.5" +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -192,14 +192,6 @@ default-shell@1.0.1, default-shell@^1.0.1: resolved "https://registry.npmjs.org/default-shell/-/default-shell-1.0.1.tgz#752304bddc6174f49eb29cb988feea0b8813c8bc" integrity sha1-dSMEvdxhdPSespy5iP7qC4gTyLw= -define-properties@^1.1.3: - version "1.1.4" - resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - dot-prop@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" @@ -207,6 +199,16 @@ dot-prop@^6.0.1: dependencies: is-obj "^2.0.0" +electron-devtools-installer@3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-3.2.0.tgz#acc48d24eb7033fe5af284a19667e73b78d406d0" + integrity sha512-t3UczsYugm4OAbqvdImMCImIMVdFzJAHgbwHpkl5jmfu1izVgUcP/mnrPqJIpEeCK1uZGpt+yHgWEN+9EwoYhQ== + dependencies: + rimraf "^3.0.2" + semver "^7.2.1" + tslib "^2.1.0" + unzip-crx-3 "^0.2.0" + electron-fetch@1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/electron-fetch/-/electron-fetch-1.9.1.tgz#e28bfe78d467de3f2dec884b1d72b8b05322f30f" @@ -219,10 +221,10 @@ electron-is-dev@2.0.0: resolved "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-2.0.0.tgz#833487a069b8dad21425c67a19847d9064ab19bd" integrity sha512-3X99K852Yoqu9AcW50qz3ibYBWY79/pBhlMCab8ToEWS48R0T9tyxRiQhwylE7zQdXrMnx2JKqUJyMPmt5FBqA== -electron-store@8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/electron-store/-/electron-store-8.1.0.tgz#46a398f2bd9aa83c4a9daaae28380e2b3b9c7597" - integrity sha512-2clHg/juMjOH0GT9cQ6qtmIvK183B39ZXR0bUoPwKwYHJsEF3quqyDzMFUAu+0OP8ijmN2CbPRAelhNbWUbzwA== +electron-store@8.2.0: + version "8.2.0" + resolved "https://registry.npmjs.org/electron-store/-/electron-store-8.2.0.tgz#114e6e453e8bb746ab4ccb542424d8c881ad2ca1" + integrity sha512-ukLL5Bevdil6oieAOXz3CMy+OgaItMiVBg701MNlG6W5RaC0AHN7rvlqTCmeb6O7jP0Qa1KKYTE0xV0xbhF4Hw== dependencies: conf "^10.2.0" type-fest "^2.17.0" @@ -246,11 +248,6 @@ env-paths@^2.2.1: resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -es6-object-assign@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" - integrity sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw== - esprima@~4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -303,41 +300,25 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -fs-extra@11.1.1: - version "11.1.1" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" - integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== +fs-extra@11.2.0: + version "11.2.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" + integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" universalify "^2.0.0" +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + fsevents@~2.3.2: version "2.3.2" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" - integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" - get-stream@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -369,44 +350,23 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: - get-intrinsic "^1.1.3" + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.4" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - human-signals@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -419,7 +379,20 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -inherits@^2.0.3, inherits@~2.0.3: +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -429,14 +402,6 @@ invert-kv@^3.0.0: resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.1.tgz#a93c7a3d4386a1dc8325b97da9bb1620c0282523" integrity sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw== -is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-arrayish@^0.3.1: version "0.3.2" resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" @@ -449,23 +414,11 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-callable@^1.1.3: - version "1.2.7" - resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-generator-function@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" @@ -473,14 +426,6 @@ is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-nan@^1.2.1: - version "1.3.2" - resolved "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" - integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -501,16 +446,10 @@ is-stream@^2.0.0: resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-typed-array@^1.1.10, is-typed-array@^1.1.3: - version "1.1.10" - resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" @@ -541,6 +480,16 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jszip@^3.1.0: + version "3.10.1" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + lcid@^3.0.0: version "3.1.1" resolved "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz#9030ec479a058fc36b5e8243ebaac8b6ac582fd0" @@ -548,6 +497,13 @@ lcid@^3.0.0: dependencies: invert-kv "^3.0.0" +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -606,6 +562,25 @@ mimic-fn@^3.0.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + ms@2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -671,28 +646,10 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-is@^1.0.1: - version "1.1.5" - resolved "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -once@^1.3.1, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" @@ -746,6 +703,11 @@ p-try@^2.0.0: resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pako@~1.0.2: + version "1.0.11" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + parse-path@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz#605a2d58d0a749c8594405d8cc3a2bf76d16099b" @@ -765,6 +727,11 @@ path-exists@^3.0.0: resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -787,6 +754,11 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + protocols@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" @@ -812,22 +784,33 @@ queue@6.0.2: dependencies: inherits "~2.0.3" -react-dom@17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== +react-dom@18.2.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" + scheduler "^0.23.0" -react@17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== +react@18.2.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" + +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" readdirp@~3.6.0: version "3.6.0" @@ -836,15 +819,15 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -recast@0.23.2: - version "0.23.2" - resolved "https://registry.npmjs.org/recast/-/recast-0.23.2.tgz#d3dda3e8f0a3366860d7508c00e34a338ac52b41" - integrity sha512-Qv6cPfVZyMOtPszK6PgW70pUgm7gPlFitAPf0Q69rlOA0zLw2XdDcNmPbVGYicFGT9O8I7TZ/0ryJD+6COvIPw== +recast@0.23.6: + version "0.23.6" + resolved "https://registry.npmjs.org/recast/-/recast-0.23.6.tgz#198fba74f66143a30acc81929302d214ce4e3bfa" + integrity sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ== dependencies: - assert "^2.0.0" ast-types "^0.16.1" esprima "~4.0.0" source-map "~0.6.1" + tiny-invariant "^1.3.3" tslib "^2.0.1" require-from-string@^2.0.2: @@ -857,23 +840,34 @@ retry@0.13.1: resolved "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" -semver@7.5.4, semver@^7.3.5: - version "7.5.4" - resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== +semver@7.6.0, semver@^7.2.1, semver@^7.3.5: + version "7.6.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== dependencies: lru-cache "^6.0.0" @@ -882,6 +876,11 @@ semver@^5.5.0, semver@^5.6.0: resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -937,6 +936,13 @@ source-map@~0.6.1: resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -959,6 +965,11 @@ sudo-prompt@^9.2.1: resolved "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd" integrity sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw== +tiny-invariant@^1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -966,10 +977,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tslib@^2.0.1: - version "2.4.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" - integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +tslib@^2.0.1, tslib@^2.1.0: + version "2.6.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== type-fest@^2.17.0: version "2.18.0" @@ -981,6 +992,15 @@ universalify@^2.0.0: resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unzip-crx-3@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz#d5324147b104a8aed9ae8639c95521f6f7cda292" + integrity sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ== + dependencies: + jszip "^3.1.0" + mkdirp "^0.5.1" + yaku "^0.16.6" + uri-js@^4.2.2: version "4.4.0" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" @@ -988,33 +1008,15 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util@^0.12.0: - version "0.12.5" - resolved "https://registry.npmjs.org/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" - integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - which-typed-array "^1.1.2" +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -uuid@9.0.0: - version "9.0.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" - integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== - -which-typed-array@^1.1.2: - version "1.1.9" - resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" +uuid@9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== which@^1.2.9: version "1.3.1" @@ -1035,6 +1037,11 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +yaku@^0.16.6: + version "0.16.7" + resolved "https://registry.npmjs.org/yaku/-/yaku-0.16.7.tgz#1d195c78aa9b5bf8479c895b9504fd4f0847984e" + integrity sha512-Syu3IB3rZvKvYk7yTiyl1bo/jiEFaaStrgv1V2TIJTqYPStSMQVO8EQjg/z+DRzLq/4LIIharNT3iH1hylEIRw== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" diff --git a/bin/snapshot-libs.js b/bin/snapshot-libs.js index df646315..791e8ec8 100644 --- a/bin/snapshot-libs.js +++ b/bin/snapshot-libs.js @@ -7,10 +7,6 @@ require('normalize-url'); require('parse-url'); require('php-escape-shell'); require('plist'); -require('react-deep-force-update'); -require('react-dom'); -require('react-redux'); -require('react'); require('redux-thunk'); require('redux'); require('reselect'); @@ -22,6 +18,9 @@ if (false) { require('args'); require('mousetrap'); require('open'); + require('react-dom'); + require('react-redux'); + require('react'); require('xterm-addon-fit'); require('xterm-addon-image'); require('xterm-addon-search'); diff --git a/cli/api.ts b/cli/api.ts index bc1bafc4..6c2a4347 100644 --- a/cli/api.ts +++ b/cli/api.ts @@ -2,18 +2,20 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ import fs from 'fs'; import os from 'os'; +import path from 'path'; + import got from 'got'; import registryUrlModule from 'registry-url'; + const registryUrl = registryUrlModule(); -import path from 'path'; // If the user defines XDG_CONFIG_HOME they definitely want their config there, // otherwise use the home directory in linux/mac and userdata in windows const applicationDirectory = process.env.XDG_CONFIG_HOME ? path.join(process.env.XDG_CONFIG_HOME, 'Hyper') : process.platform === 'win32' - ? path.join(process.env.APPDATA!, 'Hyper') - : path.join(os.homedir(), '.config', 'Hyper'); + ? path.join(process.env.APPDATA!, 'Hyper') + : path.join(os.homedir(), '.config', 'Hyper'); const devConfigFileName = path.join(__dirname, `../hyper.json`); diff --git a/cli/index.ts b/cli/index.ts index bb8d575c..86dbc414 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -1,17 +1,20 @@ // This is a CLI tool, using console is OK /* eslint no-console: 0 */ -import type {SpawnOptions} from 'child_process'; import {spawn, exec} from 'child_process'; -import {isAbsolute, resolve} from 'path'; +import type {SpawnOptions} from 'child_process'; import {existsSync} from 'fs'; -import {version} from '../app/package.json'; +import {isAbsolute, resolve} from 'path'; import {promisify} from 'util'; + import args from 'args'; import chalk from 'chalk'; -import open from 'open'; import _columnify from 'columnify'; import got from 'got'; +import open from 'open'; import ora from 'ora'; + +import {version} from '../app/package.json'; + import * as api from './api'; let commandPromise: Promise | undefined; diff --git a/lib/actions/config.ts b/lib/actions/config.ts index 8acd6511..7d1110cd 100644 --- a/lib/actions/config.ts +++ b/lib/actions/config.ts @@ -1,6 +1,6 @@ -import {CONFIG_LOAD, CONFIG_RELOAD} from '../constants/config'; -import type {HyperActions} from '../hyper'; -import type {configOptions} from '../config'; +import type {configOptions} from '../../typings/config'; +import {CONFIG_LOAD, CONFIG_RELOAD} from '../../typings/constants/config'; +import type {HyperActions} from '../../typings/hyper'; export function loadConfig(config: configOptions): HyperActions { return { diff --git a/lib/actions/header.ts b/lib/actions/header.ts index e4827977..771efa03 100644 --- a/lib/actions/header.ts +++ b/lib/actions/header.ts @@ -1,14 +1,15 @@ -import {CLOSE_TAB, CHANGE_TAB} from '../constants/tabs'; +import {CLOSE_TAB, CHANGE_TAB} from '../../typings/constants/tabs'; import { UI_WINDOW_MAXIMIZE, UI_WINDOW_UNMAXIMIZE, UI_OPEN_HAMBURGER_MENU, UI_WINDOW_MINIMIZE, UI_WINDOW_CLOSE -} from '../constants/ui'; +} from '../../typings/constants/ui'; +import type {HyperDispatch} from '../../typings/hyper'; import rpc from '../rpc'; + import {userExitTermGroup, setActiveGroup} from './term-groups'; -import type {HyperDispatch} from '../hyper'; export function closeTab(uid: string) { return (dispatch: HyperDispatch) => { diff --git a/lib/actions/index.ts b/lib/actions/index.ts index 7cef199a..192dd18b 100644 --- a/lib/actions/index.ts +++ b/lib/actions/index.ts @@ -1,6 +1,6 @@ +import {INIT} from '../../typings/constants'; +import type {HyperDispatch} from '../../typings/hyper'; import rpc from '../rpc'; -import {INIT} from '../constants'; -import type {HyperDispatch} from '../hyper'; export default function init() { return (dispatch: HyperDispatch) => { diff --git a/lib/actions/notifications.ts b/lib/actions/notifications.ts index 6604bb36..8433671f 100644 --- a/lib/actions/notifications.ts +++ b/lib/actions/notifications.ts @@ -1,5 +1,5 @@ -import {NOTIFICATION_MESSAGE, NOTIFICATION_DISMISS} from '../constants/notifications'; -import type {HyperActions} from '../hyper'; +import {NOTIFICATION_MESSAGE, NOTIFICATION_DISMISS} from '../../typings/constants/notifications'; +import type {HyperActions} from '../../typings/hyper'; export function dismissNotification(id: string): HyperActions { return { diff --git a/lib/actions/sessions.ts b/lib/actions/sessions.ts index f62e1317..4cb53f9d 100644 --- a/lib/actions/sessions.ts +++ b/lib/actions/sessions.ts @@ -1,6 +1,4 @@ -import rpc from '../rpc'; -import {keys} from '../utils/object'; -import findBySession from '../utils/term-groups'; +import type {Session} from '../../typings/common'; import { SESSION_ADD, SESSION_RESIZE, @@ -14,9 +12,11 @@ import { SESSION_USER_DATA, SESSION_SET_XTERM_TITLE, SESSION_SEARCH -} from '../constants/sessions'; -import type {HyperState, HyperDispatch, HyperActions} from '../hyper'; -import type {Session} from '../../common'; +} from '../../typings/constants/sessions'; +import type {HyperState, HyperDispatch, HyperActions} from '../../typings/hyper'; +import rpc from '../rpc'; +import {keys} from '../utils/object'; +import findBySession from '../utils/term-groups'; export function addSession({uid, shell, pid, cols = null, rows = null, splitDirection, activeUid, profile}: Session) { return (dispatch: HyperDispatch, getState: () => HyperState) => { diff --git a/lib/actions/term-groups.ts b/lib/actions/term-groups.ts index 45dd1327..6beeedd9 100644 --- a/lib/actions/term-groups.ts +++ b/lib/actions/term-groups.ts @@ -1,16 +1,17 @@ -import rpc from '../rpc'; +import {SESSION_REQUEST} from '../../typings/constants/sessions'; import { DIRECTION, TERM_GROUP_RESIZE, TERM_GROUP_REQUEST, TERM_GROUP_EXIT, TERM_GROUP_EXIT_ACTIVE -} from '../constants/term-groups'; -import {SESSION_REQUEST} from '../constants/sessions'; -import findBySession from '../utils/term-groups'; +} from '../../typings/constants/term-groups'; +import type {ITermState, ITermGroup, HyperState, HyperDispatch, HyperActions} from '../../typings/hyper'; +import rpc from '../rpc'; import {getRootGroups} from '../selectors'; +import findBySession from '../utils/term-groups'; + import {setActiveSession, ptyExitSession, userExitSession} from './sessions'; -import type {ITermState, ITermGroup, HyperState, HyperDispatch, HyperActions} from '../hyper'; function requestSplit(direction: 'VERTICAL' | 'HORIZONTAL') { return (_activeUid: string | undefined, _profile: string | undefined) => diff --git a/lib/actions/ui.ts b/lib/actions/ui.ts index bccc5279..92da4cee 100644 --- a/lib/actions/ui.ts +++ b/lib/actions/ui.ts @@ -1,10 +1,9 @@ +import {stat} from 'fs'; +import type {Stats} from 'fs'; + +import type parseUrl from 'parse-url'; import {php_escapeshellcmd as escapeShellCmd} from 'php-escape-shell'; -import {isExecutable} from '../utils/file'; -import {getRootGroups} from '../selectors'; -import findBySession from '../utils/term-groups'; -import notify from '../utils/notify'; -import rpc from '../rpc'; -import {requestSession, sendSessionData, setActiveSession} from './sessions'; + import { UI_FONT_SIZE_SET, UI_FONT_SIZE_INCR, @@ -24,13 +23,16 @@ import { UI_OPEN_SSH_URL, UI_CONTEXTMENU_OPEN, UI_COMMAND_EXEC -} from '../constants/ui'; +} from '../../typings/constants/ui'; +import type {HyperState, HyperDispatch, HyperActions, ITermGroups} from '../../typings/hyper'; +import rpc from '../rpc'; +import {getRootGroups} from '../selectors'; +import {isExecutable} from '../utils/file'; +import notify from '../utils/notify'; +import findBySession from '../utils/term-groups'; +import {requestSession, sendSessionData, setActiveSession} from './sessions'; import {setActiveGroup} from './term-groups'; -import type parseUrl from 'parse-url'; -import type {HyperState, HyperDispatch, HyperActions, ITermGroups} from '../hyper'; -import type {Stats} from 'fs'; -import {stat} from 'fs'; export function openContextMenu(uid: string, selection: string) { return (dispatch: HyperDispatch, getState: () => HyperState) => { diff --git a/lib/actions/updater.ts b/lib/actions/updater.ts index 8f116723..45490f7e 100644 --- a/lib/actions/updater.ts +++ b/lib/actions/updater.ts @@ -1,6 +1,6 @@ -import {UPDATE_INSTALL, UPDATE_AVAILABLE} from '../constants/updater'; +import {UPDATE_INSTALL, UPDATE_AVAILABLE} from '../../typings/constants/updater'; +import type {HyperActions} from '../../typings/hyper'; import rpc from '../rpc'; -import type {HyperActions} from '../hyper'; export function installUpdate(): HyperActions { return { diff --git a/lib/command-registry.ts b/lib/command-registry.ts index 27bbe172..f72c08c9 100644 --- a/lib/command-registry.ts +++ b/lib/command-registry.ts @@ -1,9 +1,7 @@ -import {require as remoteRequire} from '@electron/remote'; -import type {HyperDispatch} from './hyper'; -import {closeSearch} from './actions/sessions'; -// TODO: Should be updates to new async API https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31 +import type {HyperDispatch} from '../typings/hyper'; -const {getDecoratedKeymaps} = remoteRequire('./plugins') as typeof import('../app/plugins'); +import {closeSearch} from './actions/sessions'; +import {ipcRenderer} from './utils/ipc'; let commands: Record void> = { 'editor:search-close': (e, dispatch) => { @@ -12,8 +10,8 @@ let commands: Record void> = { } }; -export const getRegisteredKeys = () => { - const keymaps = getDecoratedKeymaps(); +export const getRegisteredKeys = async () => { + const keymaps = await ipcRenderer.invoke('getDecoratedKeymaps'); return Object.keys(keymaps).reduce((result: Record, actionName) => { const commandKeys = keymaps[actionName]; diff --git a/lib/components/header.tsx b/lib/components/header.tsx index 7eb05231..416ecbc5 100644 --- a/lib/components/header.tsx +++ b/lib/components/header.tsx @@ -1,27 +1,27 @@ -import React from 'react'; +import React, {forwardRef, useState} from 'react'; +import type {HeaderProps} from '../../typings/hyper'; import {decorate, getTabsProps} from '../utils/plugins'; import Tabs_ from './tabs'; -import type {HeaderProps} from '../hyper'; const Tabs = decorate(Tabs_, 'Tabs'); -export default class Header extends React.PureComponent { - headerMouseDownWindowX!: number; - headerMouseDownWindowY!: number; +const Header = forwardRef((props, ref) => { + const [headerMouseDownWindowX, setHeaderMouseDownWindowX] = useState(0); + const [headerMouseDownWindowY, setHeaderMouseDownWindowY] = useState(0); - onChangeIntent = (active: string) => { + const onChangeIntent = (active: string) => { // we ignore clicks if they're a byproduct of a drag // motion to move the window - if (window.screenX !== this.headerMouseDownWindowX || window.screenY !== this.headerMouseDownWindowY) { + if (window.screenX !== headerMouseDownWindowX || window.screenY !== headerMouseDownWindowY) { return; } - this.props.onChangeTab(active); + props.onChangeTab(active); }; - handleHeaderMouseDown = () => { + const handleHeaderMouseDown = () => { // the hack of all hacks, this prevents the term // iframe from losing focus, for example, when // the user drags the nav around @@ -30,43 +30,43 @@ export default class Header extends React.PureComponent { // persist start positions of a potential drag motion // to differentiate dragging from clicking - this.headerMouseDownWindowX = window.screenX; - this.headerMouseDownWindowY = window.screenY; + setHeaderMouseDownWindowX(window.screenX); + setHeaderMouseDownWindowY(window.screenY); }; - handleHamburgerMenuClick = (event: React.MouseEvent) => { + const handleHamburgerMenuClick = (event: React.MouseEvent) => { let {right: x, bottom: y} = event.currentTarget.getBoundingClientRect(); x -= 15; // to compensate padding y -= 12; // ^ same - this.props.openHamburgerMenu({x, y}); + props.openHamburgerMenu({x, y}); }; - handleMaximizeClick = () => { - if (this.props.maximized) { - this.props.unmaximize(); + const handleMaximizeClick = () => { + if (props.maximized) { + props.unmaximize(); } else { - this.props.maximize(); + props.maximize(); } }; - handleMinimizeClick = () => { - this.props.minimize(); + const handleMinimizeClick = () => { + props.minimize(); }; - handleCloseClick = () => { - this.props.close(); + const handleCloseClick = () => { + props.close(); }; - getWindowHeaderConfig() { - const {showHamburgerMenu, showWindowControls} = this.props; + const getWindowHeaderConfig = () => { + const {showHamburgerMenu, showWindowControls} = props; const defaults = { - hambMenu: !this.props.isMac, // show by default on windows and linux - winCtrls: !this.props.isMac // show by default on Windows and Linux + hambMenu: !props.isMac, // show by default on windows and linux + winCtrls: !props.isMac // show by default on Windows and Linux }; // don't allow the user to change defaults on macOS - if (this.props.isMac) { + if (props.isMac) { return defaults; } @@ -74,186 +74,187 @@ export default class Header extends React.PureComponent { hambMenu: showHamburgerMenu === '' ? defaults.hambMenu : showHamburgerMenu, winCtrls: showWindowControls === '' ? defaults.winCtrls : showWindowControls }; + }; + + const {isMac} = props; + const {borderColor} = props; + let title = 'Hyper'; + if (props.tabs.length === 1 && props.tabs[0].title) { + // if there's only one tab we use its title as the window title + title = props.tabs[0].title; } + const {hambMenu, winCtrls} = getWindowHeaderConfig(); + const left = winCtrls === 'left'; + const maxButtonHref = props.maximized + ? './renderer/assets/icons.svg#restore-window' + : './renderer/assets/icons.svg#maximize-window'; - render() { - const {isMac} = this.props; - const props = getTabsProps(this.props, { - tabs: this.props.tabs, - borderColor: this.props.borderColor, - backgroundColor: this.props.backgroundColor, - onClose: this.props.onCloseTab, - onChange: this.onChangeIntent, - fullScreen: this.props.fullScreen, - defaultProfile: this.props.defaultProfile, - profiles: this.props.profiles.asMutable({deep: true}), - openNewTab: this.props.openNewTab - }); - const {borderColor} = props; - let title = 'Hyper'; - if (props.tabs.length === 1 && props.tabs[0].title) { - // if there's only one tab we use its title as the window title - title = props.tabs[0].title; - } - const {hambMenu, winCtrls} = this.getWindowHeaderConfig(); - const left = winCtrls === 'left'; - const maxButtonHref = this.props.maximized - ? './renderer/assets/icons.svg#restore-window' - : './renderer/assets/icons.svg#maximize-window'; - - return ( -
window.focusActiveTerm()} - onDoubleClick={this.handleMaximizeClick} - > - {!isMac && ( -
1 ? 'header_windowHeaderWithBorder' : ''}`} - style={{borderColor}} - > - {hambMenu && ( - - - - )} - {title} - {winCtrls && ( -
-
- - - -
-
- - - -
-
- - - -
+ return ( +
window.focusActiveTerm()} + onDoubleClick={handleMaximizeClick} + ref={ref} + > + {!isMac && ( +
1 ? 'header_windowHeaderWithBorder' : ''}`} + style={{borderColor}} + > + {hambMenu && ( + + + + )} + {title} + {winCtrls && ( +
+
+ + +
- )} -
- )} - {this.props.customChildrenBefore} - - {this.props.customChildren} +
+ + + +
+
+ + + +
+
+ )} +
+ )} + {props.customChildrenBefore} + + {props.customChildren} - -
- ); - } -} + .header_closeWindow:active { + color: #fe354e; + } + `} + + ); +}); + +Header.displayName = 'Header'; + +export default Header; diff --git a/lib/components/new-tab.tsx b/lib/components/new-tab.tsx index 76ce6fa7..3fe99543 100644 --- a/lib/components/new-tab.tsx +++ b/lib/components/new-tab.tsx @@ -1,8 +1,10 @@ import React, {useRef, useState} from 'react'; + import {VscChevronDown} from '@react-icons/all-files/vsc/VscChevronDown'; -import type {configOptions} from '../config'; import useClickAway from 'react-use/lib/useClickAway'; +import type {configOptions} from '../../typings/config'; + interface Props { defaultProfile: string; profiles: configOptions['profiles']; diff --git a/lib/components/notification.tsx b/lib/components/notification.tsx index 21510a8e..68b7a2df 100644 --- a/lib/components/notification.tsx +++ b/lib/components/notification.tsx @@ -1,115 +1,110 @@ -import React from 'react'; -import type {NotificationProps, NotificationState} from '../hyper'; +import React, {forwardRef, useEffect, useRef, useState} from 'react'; -export default class Notification extends React.PureComponent { - dismissTimer!: NodeJS.Timeout; - constructor(props: NotificationProps) { - super(props); - this.state = { - dismissing: false - }; - } +import type {NotificationProps} from '../../typings/hyper'; - componentDidMount() { - if (this.props.dismissAfter) { - this.setDismissTimer(); - } - } +const Notification = forwardRef>((props, ref) => { + const dismissTimer = useRef(undefined); + const [dismissing, setDismissing] = useState(false); - componentDidUpdate(prevProps: NotificationProps, prevState: NotificationState) { + useEffect(() => { + setDismissTimer(); + }, []); + + useEffect(() => { // if we have a timer going and the notification text // changed we reset the timer - if (this.props.text !== prevProps.text) { - if (prevProps.dismissAfter) { - this.resetDismissTimer(); - } - if (prevState.dismissing) { - this.setState({dismissing: false}); - } - } - } + resetDismissTimer(); + setDismissing(false); + }, [props.text]); - handleDismiss = () => { - this.setState({dismissing: true}); + const handleDismiss = () => { + setDismissing(true); }; - onElement = (el: HTMLDivElement | null) => { + const onElement = (el: HTMLDivElement | null) => { if (el) { el.addEventListener('webkitTransitionEnd', () => { - if (this.state.dismissing) { - this.props.onDismiss(); + if (dismissing) { + props.onDismiss(); } }); - const {backgroundColor} = this.props; + const {backgroundColor} = props; if (backgroundColor) { el.style.setProperty('background-color', backgroundColor, 'important'); } + + if (ref) { + if (typeof ref === 'function') ref(el); + else ref.current = el; + } } }; - setDismissTimer() { - this.dismissTimer = setTimeout(() => { - this.handleDismiss(); - }, this.props.dismissAfter); - } + const setDismissTimer = () => { + if (typeof props.dismissAfter === 'number') { + dismissTimer.current = setTimeout(() => { + handleDismiss(); + }, props.dismissAfter); + } + }; - resetDismissTimer() { - clearTimeout(this.dismissTimer); - this.setDismissTimer(); - } + const resetDismissTimer = () => { + clearTimeout(dismissTimer.current); + setDismissTimer(); + }; - componentWillUnmount() { - clearTimeout(this.dismissTimer); - } + useEffect(() => { + return () => { + clearTimeout(dismissTimer.current); + }; + }, []); - render() { - const {backgroundColor, color} = this.props; - const opacity = this.state.dismissing ? 0 : 1; - return ( -
- {this.props.customChildrenBefore} - {this.props.children || this.props.text} - {this.props.userDismissable ? ( - - [x] - - ) : null} - {this.props.customChildren} + const {backgroundColor, color} = props; + const opacity = dismissing ? 0 : 1; + return ( +
+ {props.customChildrenBefore} + {props.children || props.text} + {props.userDismissable ? ( + + [x] + + ) : null} + {props.customChildren} - -
- ); - } -} + .notification_dismissLink:hover, + .notification_dismissLink:focus { + font-weight: 900; + } + `} +
+ ); +}); + +Notification.displayName = 'Notification'; + +export default Notification; diff --git a/lib/components/notifications.tsx b/lib/components/notifications.tsx index da63a70e..79e6ede3 100644 --- a/lib/components/notifications.tsx +++ b/lib/components/notifications.tsx @@ -1,132 +1,132 @@ -import React from 'react'; +import React, {forwardRef} from 'react'; +import type {NotificationsProps} from '../../typings/hyper'; import {decorate} from '../utils/plugins'; import Notification_ from './notification'; -import type {NotificationsProps} from '../hyper'; const Notification = decorate(Notification_, 'Notification'); -export default class Notifications extends React.PureComponent { - render() { - return ( -
- {this.props.customChildrenBefore} - {this.props.fontShowing && ( - - )} +const Notifications = forwardRef((props, ref) => { + return ( +
+ {props.customChildrenBefore} + {props.fontShowing && ( + + )} - {this.props.resizeShowing && ( - - )} + {props.resizeShowing && ( + + )} - {this.props.messageShowing && ( - - {this.props.messageURL - ? [ - this.props.messageText, - ' (', - { - void window.require('electron').shell.openExternal(ev.currentTarget.href); - ev.preventDefault(); - }} - href={this.props.messageURL} - > - more - , - ') ' - ] - : null} - - )} - - {this.props.updateShowing && ( - - Version {this.props.updateVersion} ready. - {this.props.updateNote && ` ${this.props.updateNote.trim().replace(/\.$/, '')}`} ( - { - void window.require('electron').shell.openExternal(ev.currentTarget.href); - ev.preventDefault(); - }} - href={`https://github.com/vercel/hyper/releases/tag/${this.props.updateVersion}`} - > - notes - - ).{' '} - {this.props.updateCanInstall ? ( + {props.messageShowing && ( + + {props.messageURL ? ( + <> + {props.messageText} ( - Restart - - ) : ( - { void window.require('electron').shell.openExternal(ev.currentTarget.href); ev.preventDefault(); }} - href={this.props.updateReleaseUrl!} + href={props.messageURL} > - Download + more - )} - .{' '} - - )} - {this.props.customChildren} + ) + + ) : null} + + )} - -
- ); - } -} + {props.updateShowing && ( + + Version {props.updateVersion} ready. + {props.updateNote && ` ${props.updateNote.trim().replace(/\.$/, '')}`} ( + { + void window.require('electron').shell.openExternal(ev.currentTarget.href); + ev.preventDefault(); + }} + href={`https://github.com/vercel/hyper/releases/tag/${props.updateVersion}`} + > + notes + + ).{' '} + {props.updateCanInstall ? ( + + Restart + + ) : ( + { + void window.require('electron').shell.openExternal(ev.currentTarget.href); + ev.preventDefault(); + }} + href={props.updateReleaseUrl!} + > + Download + + )} + .{' '} + + )} + {props.customChildren} + + +
+ ); +}); + +Notifications.displayName = 'Notifications'; + +export default Notifications; diff --git a/lib/components/searchBox.tsx b/lib/components/searchBox.tsx index b9ff6086..55a72f16 100644 --- a/lib/components/searchBox.tsx +++ b/lib/components/searchBox.tsx @@ -1,13 +1,15 @@ -import React, {useCallback, useRef, useEffect} from 'react'; -import type {SearchBoxProps} from '../hyper'; -import {VscArrowUp} from '@react-icons/all-files/vsc/VscArrowUp'; +import React, {useCallback, useRef, useEffect, forwardRef} from 'react'; + import {VscArrowDown} from '@react-icons/all-files/vsc/VscArrowDown'; -import {VscClose} from '@react-icons/all-files/vsc/VscClose'; +import {VscArrowUp} from '@react-icons/all-files/vsc/VscArrowUp'; import {VscCaseSensitive} from '@react-icons/all-files/vsc/VscCaseSensitive'; +import {VscClose} from '@react-icons/all-files/vsc/VscClose'; import {VscRegex} from '@react-icons/all-files/vsc/VscRegex'; import {VscWholeWord} from '@react-icons/all-files/vsc/VscWholeWord'; import clsx from 'clsx'; +import type {SearchBoxProps} from '../../typings/hyper'; + type SearchButtonColors = { foregroundColor: string; selectionColor: string; @@ -82,7 +84,7 @@ const SearchButton = ({ ); }; -const SearchBox = (props: SearchBoxProps) => { +const SearchBox = forwardRef((props, ref) => { const { caseSensitive, wholeWord, @@ -127,7 +129,7 @@ const SearchBox = (props: SearchBoxProps) => { }; return ( -
+
@@ -148,8 +150,8 @@ const SearchBox = (props: SearchBoxProps) => { {results === undefined ? '' : results.resultCount === 0 - ? 'No results' - : `${results.resultIndex + 1} of ${results.resultCount}`} + ? 'No results' + : `${results.resultIndex + 1} of ${results.resultCount}`}
@@ -228,6 +230,8 @@ const SearchBox = (props: SearchBoxProps) => {
); -}; +}); + +SearchBox.displayName = 'SearchBox'; export default SearchBox; diff --git a/lib/components/split-pane.tsx b/lib/components/split-pane.tsx index 6efb9bd8..aea53f6f 100644 --- a/lib/components/split-pane.tsx +++ b/lib/components/split-pane.tsx @@ -1,219 +1,191 @@ -import React from 'react'; -import _ from 'lodash'; -import type {SplitPaneProps} from '../hyper'; +import React, {useState, useEffect, useRef, forwardRef} from 'react'; -export default class SplitPane extends React.PureComponent { - dragPanePosition!: number; - dragTarget!: Element; - panes!: Element[]; - paneIndex!: number; - d1!: 'height' | 'width'; - d2!: 'top' | 'left'; - d3!: 'clientX' | 'clientY'; - panesSize!: number; - dragging!: boolean; - constructor(props: SplitPaneProps) { - super(props); - this.state = {dragging: false}; - } +import sum from 'lodash/sum'; - componentDidUpdate(prevProps: SplitPaneProps) { - if (this.state.dragging && prevProps.sizes !== this.props.sizes) { - // recompute positions for ongoing dragging - this.dragPanePosition = this.dragTarget.getBoundingClientRect()[this.d2]; - } - } +import type {SplitPaneProps} from '../../typings/hyper'; - setupPanes(ev: React.MouseEvent) { - const target = ev.target as HTMLDivElement; - this.panes = Array.from(target.parentElement?.children || []); - this.paneIndex = this.panes.indexOf(target); - this.paneIndex -= Math.ceil(this.paneIndex / 2); - } +const SplitPane = forwardRef((props, ref) => { + const dragPanePosition = useRef(0); + const dragTarget = useRef(null); + const paneIndex = useRef(0); + const d1 = props.direction === 'horizontal' ? 'height' : 'width'; + const d2 = props.direction === 'horizontal' ? 'top' : 'left'; + const d3 = props.direction === 'horizontal' ? 'clientY' : 'clientX'; + const panesSize = useRef(null); + const [dragging, setDragging] = useState(false); - handleAutoResize = (ev: React.MouseEvent) => { + const handleAutoResize = (ev: React.MouseEvent, index: number) => { ev.preventDefault(); - this.setupPanes(ev); + paneIndex.current = index; - const sizes_ = this.getSizes(); - sizes_[this.paneIndex] = 0; - sizes_[this.paneIndex + 1] = 0; + const sizes_ = getSizes(); + sizes_[paneIndex.current] = 0; + sizes_[paneIndex.current + 1] = 0; - const availableWidth = 1 - _.sum(sizes_); - sizes_[this.paneIndex] = availableWidth / 2; - sizes_[this.paneIndex + 1] = availableWidth / 2; + const availableWidth = 1 - sum(sizes_); + sizes_[paneIndex.current] = availableWidth / 2; + sizes_[paneIndex.current + 1] = availableWidth / 2; - this.props.onResize(sizes_); + props.onResize(sizes_); }; - handleDragStart = (ev: React.MouseEvent) => { + const handleDragStart = (ev: React.MouseEvent, index: number) => { ev.preventDefault(); - this.setState({dragging: true}); - window.addEventListener('mousemove', this.onDrag); - window.addEventListener('mouseup', this.onDragEnd); - - // dimensions to consider - if (this.props.direction === 'horizontal') { - this.d1 = 'height'; - this.d2 = 'top'; - this.d3 = 'clientY'; - } else { - this.d1 = 'width'; - this.d2 = 'left'; - this.d3 = 'clientX'; - } + setDragging(true); + window.addEventListener('mousemove', onDrag); + window.addEventListener('mouseup', onDragEnd); const target = ev.target as HTMLDivElement; - this.dragTarget = target; - this.dragPanePosition = this.dragTarget.getBoundingClientRect()[this.d2]; - this.panesSize = target.parentElement!.getBoundingClientRect()[this.d1]; - this.setupPanes(ev); + dragTarget.current = target; + dragPanePosition.current = dragTarget.current.getBoundingClientRect()[d2]; + panesSize.current = target.parentElement!.getBoundingClientRect()[d1]; + paneIndex.current = index; }; - getSizes() { - const {sizes} = this.props; + const getSizes = () => { + const {sizes} = props; let sizes_: number[]; if (sizes) { sizes_ = [...sizes.asMutable()]; } else { - const total = (this.props.children as React.ReactNodeArray).length; + const total = props.children.length; const count = new Array(total).fill(1 / total); sizes_ = count; } return sizes_; - } + }; - onDrag = (ev: MouseEvent) => { - const sizes_ = this.getSizes(); + const onDrag = (ev: MouseEvent) => { + const sizes_ = getSizes(); - const i = this.paneIndex; - const pos = ev[this.d3]; - const d = Math.abs(this.dragPanePosition - pos) / this.panesSize; - if (pos > this.dragPanePosition) { + const i = paneIndex.current; + const pos = ev[d3]; + const d = Math.abs(dragPanePosition.current - pos) / panesSize.current!; + if (pos > dragPanePosition.current) { sizes_[i] += d; sizes_[i + 1] -= d; } else { sizes_[i] -= d; sizes_[i + 1] += d; } - this.props.onResize(sizes_); + props.onResize(sizes_); }; - onDragEnd = () => { - if (this.state.dragging) { - window.removeEventListener('mousemove', this.onDrag); - window.removeEventListener('mouseup', this.onDragEnd); - this.setState({dragging: false}); - } + const onDragEnd = () => { + window.removeEventListener('mousemove', onDrag); + window.removeEventListener('mouseup', onDragEnd); + setDragging(false); }; - render() { - const children = this.props.children as React.ReactNodeArray; - const {direction, borderColor} = this.props; - const sizeProperty = direction === 'horizontal' ? 'height' : 'width'; - // workaround for the fact that if we don't specify - // sizes, sometimes flex fails to calculate the - // right height for the horizontal panes - const sizes = this.props.sizes || new Array(children.length).fill(1 / children.length); - return ( -
- {React.Children.map(children, (child, i) => { - const style = { - // flexBasis doesn't work for the first horizontal pane, height need to be specified - [sizeProperty]: `${sizes[i] * 100}%`, - flexBasis: `${sizes[i] * 100}%`, - flexGrow: 0 - }; - return [ -
+ useEffect(() => { + return () => { + onDragEnd(); + }; + }, []); + + const {children, direction, borderColor} = props; + const sizeProperty = direction === 'horizontal' ? 'height' : 'width'; + // workaround for the fact that if we don't specify + // sizes, sometimes flex fails to calculate the + // right height for the horizontal panes + const sizes = props.sizes || new Array(children.length).fill(1 / children.length); + return ( +
+ {children.map((child, i) => { + const style = { + // flexBasis doesn't work for the first horizontal pane, height need to be specified + [sizeProperty]: `${sizes[i] * 100}%`, + flexBasis: `${sizes[i] * 100}%`, + flexGrow: 0 + }; + + return ( + +
{child} -
, - i < children.length - 1 ? ( +
+ {i < children.length - 1 ? (
handleDragStart(e, i)} + onDoubleClick={(e) => handleAutoResize(e, i)} style={{backgroundColor: borderColor}} className={`splitpane_divider splitpane_divider_${direction}`} /> - ) : null - ]; - })} -
+ ) : null} + + ); + })} +
- -
- ); - } + /* + this shim is used to make sure mousemove events + trigger in all the draggable area of the screen + this is not the case due to hterm's