diff --git a/.vscode/settings.json b/.vscode/settings.json index 916fa0d..5ded7c3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ "**/node_modules/": true, "dist/": true, "util/": true, + "common/out": true, "webview/build/": true, ".yarn/": true, ".yarnrc.yml": true, diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a85aeb2..267b43e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,9 +6,10 @@ { "label": "Extension - Watch all", "group": "build", + "dependsOrder": "sequence", "dependsOn": [ - "Extension - Watch", - "Extension WebView - Watch" + "Extension Common - Watch", + "Extension - Watch non-Common" ], "problemMatcher": [], "isBackground": true, @@ -16,6 +17,33 @@ "runOn": "folderOpen" } }, + { + "label": "Extension - Watch non-Common", + "group": "build", + "dependsOrder": "parallel", + "dependsOn": [ + "Extension - Watch", + "Extension WebView - Watch" + ], + "problemMatcher": [], + "isBackground": true, + }, + { + "type": "shell", + "label": "Extension Common - Watch", + "command": "yarn watch", + "options": { + "cwd": "./common" + }, + "group": "build", + "problemMatcher": { + "base": "$tsc-watch", + "source": "tsc-watch", + "owner": "tsc-watch", + "applyTo": "allDocuments" + }, + "isBackground": true + }, { "type": "npm", "label": "Extension - Watch", diff --git a/.yarn/yarn.lock b/.yarn/yarn.lock index 5836a29..354e79f 100644 --- a/.yarn/yarn.lock +++ b/.yarn/yarn.lock @@ -2272,7 +2272,7 @@ __metadata: languageName: node linkType: hard -"@types/ssh2@npm:^0.5.41, @types/ssh2@npm:^0.5.47": +"@types/ssh2@npm:^0.5.41": version: 0.5.47 resolution: "@types/ssh2@npm:0.5.47" dependencies: @@ -3714,6 +3714,16 @@ __metadata: languageName: node linkType: hard +"common@workspace:*, common@workspace:common": + version: 0.0.0-use.local + resolution: "common@workspace:common" + dependencies: + "@types/node": ^12.7.12 + "@types/ssh2": ^0.5.41 + typescript: ~4.5.5 + languageName: unknown + linkType: soft + "commondir@npm:^1.0.1": version: 1.0.1 resolution: "commondir@npm:1.0.1" @@ -9505,6 +9515,7 @@ resolve@^2.0.0-next.3: "@types/vscode": ~1.49.0 "@types/webpack": ^4.4.25 "@types/winreg": ^1.2.30 + common: "workspace:*" event-stream: ^4.0.1 jsonc-parser: ^2.0.0 semver: ^7.3.5 @@ -9518,7 +9529,6 @@ resolve@^2.0.0-next.3: vsce: ^2.5.1 webpack: ^5.69.1 webpack-cli: ^4.7.2 - webview: "workspace:*" winreg: ^1.2.4 languageName: unknown linkType: soft @@ -9717,7 +9727,7 @@ resolve@^2.0.0-next.3: languageName: node linkType: hard -"webview@workspace:*, webview@workspace:webview": +"webview@workspace:webview": version: 0.0.0-use.local resolution: "webview@workspace:webview" dependencies: @@ -9727,12 +9737,12 @@ resolve@^2.0.0-next.3: "@types/react": ^17.0.18 "@types/react-dom": ^17.0.9 "@types/react-redux": ^7.1.7 - "@types/ssh2": ^0.5.47 "@typescript-eslint/eslint-plugin": ^4.5.0 "@typescript-eslint/parser": ^4.5.0 babel-eslint: ^10.1.0 babel-loader: 8.1.0 babel-preset-react-app: 10.0.0 + common: "workspace:*" css-loader: 4.3.0 css-minimizer-webpack-plugin: ^3.0.2 dotenv: 8.2.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index b7963d5..f113ea8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - All dependencies are upgraded within their (package.json-specified) ranges, to get latest patches - Update to Yarn 3.1.1 and TypeScript ~4.5.5 - Also ditched `@yarnpkg/plugin-version` which wasn't even really used in the first place +- Created a `common` module which now holds `fileSystemConfig.ts` and `webviewMessages.ts` ## v1.24.1 (2021-12-07) diff --git a/common/.gitignore b/common/.gitignore new file mode 100644 index 0000000..be4ea5a --- /dev/null +++ b/common/.gitignore @@ -0,0 +1,3 @@ + +# Build output +out/ diff --git a/common/package.json b/common/package.json new file mode 100644 index 0000000..cbcb46b --- /dev/null +++ b/common/package.json @@ -0,0 +1,25 @@ +{ + "name": "common", + "version": "0.1.0", + "private": true, + "exports": { + "./*": "./out/*" + }, + "typesVersions": { + ">=0": { + "*": [ + "out/*" + ] + } + }, + "scripts": { + "watch": "tsc -w", + "build": "tsc" + }, + "devDependencies": { + "@types/node": "^12.7.12", + "@types/ssh2": "^0.5.41", + "typescript": "~4.5.5" + }, + "packageManager": "yarn@3.1.1" +} diff --git a/src/fileSystemConfig.ts b/common/src/fileSystemConfig.ts similarity index 99% rename from src/fileSystemConfig.ts rename to common/src/fileSystemConfig.ts index 5a591da..f7669ba 100644 --- a/src/fileSystemConfig.ts +++ b/common/src/fileSystemConfig.ts @@ -10,8 +10,8 @@ export type ConfigLocation = number | string; /** Might support conditional stuff later, although ssh2/OpenSSH might not support that natively */ export interface EnvironmentVariable { - key: string; - value: string; + key: string; + value: string; } export function formatConfigLocation(location?: ConfigLocation): string { diff --git a/src/webviewMessages.ts b/common/src/webviewMessages.ts similarity index 100% rename from src/webviewMessages.ts rename to common/src/webviewMessages.ts diff --git a/common/tsconfig.json b/common/tsconfig.json new file mode 100644 index 0000000..75c656f --- /dev/null +++ b/common/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "strictNullChecks": true, + "module": "esnext", + "moduleResolution": "node", + "target": "ES2019", + "outDir": "out", + "lib": [ + "ES2019" + ], + "sourceMap": true, + "declaration": true, + "declarationMap": true, + "rootDir": "src" + }, + "compileOnSave": true, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/package.json b/package.json index f39ef9d..a798a9c 100644 --- a/package.json +++ b/package.json @@ -402,7 +402,7 @@ } }, "scripts": { - "vscode:prepublish": "yarn workspaces foreach -vip -j 2 run build", + "vscode:prepublish": "yarn workspaces foreach -tvip -j 2 run build", "build": "webpack --mode production", "compile": "webpack --mode development", "watch": "webpack --mode development --watch" @@ -424,19 +424,20 @@ "webpack-cli": "^4.7.2" }, "dependencies": { + "common": "workspace:*", "event-stream": "^4.0.1", "jsonc-parser": "^2.0.0", "semver": "^7.3.5", "socks": "^2.2.0", "ssh2": "^0.8.9", "ssh2-streams": "^0.4.10", - "webview": "workspace:*", "winreg": "^1.2.4" }, "resolutions": { "ssh2-streams": "Timmmm/ssh2-streams#patch-1" }, "workspaces": [ + "./common", "./webview" ], "packageManager": "yarn@3.1.1" diff --git a/src/config.ts b/src/config.ts index d321173..f84b8a3 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,11 +1,11 @@ +import { ConfigLocation, FileSystemConfig, invalidConfigName, parseConnectionString } from 'common/fileSystemConfig'; import { readFile, writeFile } from 'fs'; import { parse as parseJsonc, ParseError } from 'jsonc-parser'; +import * as semver from 'semver'; import * as vscode from 'vscode'; -import { ConfigLocation, FileSystemConfig, invalidConfigName, parseConnectionString } from './fileSystemConfig'; import { Logging } from './logging'; import { toPromise } from './utils'; -import * as semver from 'semver'; // Logger scope with default warning/error options (which enables stacktraces) disabled const logging = Logging.scope(undefined, false); diff --git a/src/connect.ts b/src/connect.ts index 1546073..f3764fa 100644 --- a/src/connect.ts +++ b/src/connect.ts @@ -1,3 +1,4 @@ +import type { FileSystemConfig } from 'common/fileSystemConfig'; import { readFile } from 'fs'; import { Socket } from 'net'; import { userInfo } from 'os'; @@ -5,7 +6,6 @@ import { Client, ClientChannel, ConnectConfig, SFTPWrapper as SFTPWrapperReal } import { SFTPStream } from 'ssh2-streams'; import * as vscode from 'vscode'; import { getConfig, getFlagBoolean } from './config'; -import type { FileSystemConfig } from './fileSystemConfig'; import { Logging } from './logging'; import type { PuttySession } from './putty'; import { toPromise, validatePort } from './utils'; diff --git a/src/connection.ts b/src/connection.ts index bdbb0d7..1b5b63c 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -1,9 +1,9 @@ +import type { EnvironmentVariable, FileSystemConfig } from 'common/fileSystemConfig'; import { posix as path } from 'path'; import * as readline from 'readline'; import type { Client, ClientChannel } from 'ssh2'; import * as vscode from 'vscode'; import { configMatches, getFlagBoolean, loadConfigs } from './config'; -import type { EnvironmentVariable, FileSystemConfig } from './fileSystemConfig'; import { Logging, LOGGING_NO_STACKTRACE } from './logging'; import type { SSHPseudoTerminal } from './pseudoTerminal'; import { calculateShellConfig, ShellConfig, tryEcho } from './shellConfig'; diff --git a/src/extension.ts b/src/extension.ts index b312934..2158ade 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,8 +1,8 @@ +import type { FileSystemConfig } from 'common/fileSystemConfig'; import * as vscode from 'vscode'; import { loadConfigs } from './config'; import type { Connection } from './connection'; -import type { FileSystemConfig } from './fileSystemConfig'; import { FileSystemRouter } from './fileSystemRouter'; import { Logging, setDebug } from './logging'; import { Manager } from './manager'; diff --git a/src/logging.ts b/src/logging.ts index a39ac9a..b219c0e 100644 --- a/src/logging.ts +++ b/src/logging.ts @@ -1,5 +1,5 @@ +import { FileSystemConfig, isFileSystemConfig } from 'common/fileSystemConfig'; import * as vscode from 'vscode'; -import { FileSystemConfig, isFileSystemConfig } from './fileSystemConfig'; // Since the Extension Development Host runs with debugger, we can use this to detect if we're debugging. // The only things it currently does is copying Logging messages to the console, while also enabling diff --git a/src/manager.ts b/src/manager.ts index 753ec1f..f394413 100644 --- a/src/manager.ts +++ b/src/manager.ts @@ -1,13 +1,13 @@ +import type { FileSystemConfig } from 'common/fileSystemConfig'; +import type { Navigation } from 'common/webviewMessages'; import * as vscode from 'vscode'; import { getConfig, getFlagBoolean, loadConfigsRaw } from './config'; import { Connection, ConnectionManager } from './connection'; -import type { FileSystemConfig } from './fileSystemConfig'; import { Logging, LOGGING_NO_STACKTRACE } from './logging'; import { isSSHPseudoTerminal, replaceVariables, replaceVariablesRecursive } from './pseudoTerminal'; import type { SSHFileSystem } from './sshFileSystem'; import { catchingPromise, joinCommands } from './utils'; -import type { Navigation } from './webviewMessages'; function commandArgumentToName(arg?: string | FileSystemConfig | Connection): string { if (!arg) return 'undefined'; diff --git a/src/proxy.ts b/src/proxy.ts index 1ac9152..d67dd81 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -1,8 +1,8 @@ +import type { FileSystemConfig } from 'common/fileSystemConfig'; import * as dns from 'dns'; import { request } from 'http'; import { SocksClient } from 'socks'; -import type { FileSystemConfig } from './fileSystemConfig'; import { Logging } from './logging'; import { toPromise, validatePort } from './utils'; diff --git a/src/pseudoTerminal.ts b/src/pseudoTerminal.ts index ec77621..50b35ae 100644 --- a/src/pseudoTerminal.ts +++ b/src/pseudoTerminal.ts @@ -1,9 +1,9 @@ +import type { EnvironmentVariable, FileSystemConfig } from "common/fileSystemConfig"; import * as path from 'path'; import type { ClientChannel, PseudoTtyOptions } from "ssh2"; import * as vscode from "vscode"; import { getFlagBoolean } from './config'; import type { Connection } from './connection'; -import type { EnvironmentVariable, FileSystemConfig } from "./fileSystemConfig"; import { Logging, LOGGING_NO_STACKTRACE } from "./logging"; import { environmentToExportString, joinCommands, mergeEnvironment, toPromise } from './utils'; diff --git a/src/sshFileSystem.ts b/src/sshFileSystem.ts index 5e99f37..20a5eff 100644 --- a/src/sshFileSystem.ts +++ b/src/sshFileSystem.ts @@ -1,10 +1,10 @@ +import type { FileSystemConfig } from 'common/fileSystemConfig'; import * as path from 'path'; import type * as ssh2 from 'ssh2'; import type * as ssh2s from 'ssh2-streams'; import * as vscode from 'vscode'; import { getFlagBoolean } from './config'; -import type { FileSystemConfig } from './fileSystemConfig'; import { Logger, Logging, LOGGING_NO_STACKTRACE, LOGGING_SINGLE_LINE_STACKTRACE, withStacktraceOffset } from './logging'; // This makes it report a single line of the stacktrace of where the e.g. logger.info() call happened diff --git a/src/treeViewManager.ts b/src/treeViewManager.ts index d0fbf52..849f636 100644 --- a/src/treeViewManager.ts +++ b/src/treeViewManager.ts @@ -1,8 +1,8 @@ +import { FileSystemConfig, getGroups } from 'common/fileSystemConfig'; import * as vscode from 'vscode'; import { getConfigs, UPDATE_LISTENERS } from './config'; import type { Connection, ConnectionManager } from './connection'; -import { FileSystemConfig, getGroups } from './fileSystemConfig'; import type { SSHPseudoTerminal } from './pseudoTerminal'; import type { SSHFileSystem } from './sshFileSystem'; import { formatItem } from './ui-utils'; diff --git a/src/ui-utils.ts b/src/ui-utils.ts index 2da0776..d7be044 100644 --- a/src/ui-utils.ts +++ b/src/ui-utils.ts @@ -1,8 +1,8 @@ +import { FileSystemConfig, parseConnectionString } from 'common/fileSystemConfig'; import * as vscode from 'vscode'; import { getConfigs } from './config'; import type { Connection, ConnectionManager } from './connection'; -import { FileSystemConfig, parseConnectionString } from './fileSystemConfig'; import type { Manager } from './manager'; import type { SSHPseudoTerminal } from './pseudoTerminal'; import type { SSHFileSystem } from './sshFileSystem'; diff --git a/src/utils.ts b/src/utils.ts index c6b9597..a26bab8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,5 @@ -import type { EnvironmentVariable } from "./fileSystemConfig"; -import { DEBUG } from "./logging"; +import type { EnvironmentVariable } from 'common/fileSystemConfig'; +import { DEBUG } from './logging'; function prepareStackTraceDefault(error: Error, stackTraces: NodeJS.CallSite[]): string { return stackTraces.reduce((s, c) => `${s}\n\tat ${c} (${c.getFunction()})`, `${error.name || "Error"}: ${error.message || ""}`); diff --git a/src/webview.ts b/src/webview.ts index 310d60c..7933849 100644 --- a/src/webview.ts +++ b/src/webview.ts @@ -1,12 +1,12 @@ +import { getLocations } from 'common/fileSystemConfig'; +import type { Message, Navigation } from 'common/webviewMessages'; import * as fs from 'fs'; import * as path from 'path'; import * as vscode from 'vscode'; import { deleteConfig, loadConfigsRaw, updateConfig } from './config'; -import { getLocations } from './fileSystemConfig'; import { DEBUG, Logging as _Logging, LOGGING_NO_STACKTRACE } from './logging'; import { toPromise } from './utils'; -import type { Message, Navigation } from './webviewMessages'; const Logging = _Logging.scope('WebView'); diff --git a/tsconfig.json b/tsconfig.json index 25531c3..9ebc08c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,9 +14,5 @@ "compileOnSave": true, "include": [ "src" - ], - "exclude": [ - "node_modules", - ".vscode-test" ] } \ No newline at end of file diff --git a/webview/package.json b/webview/package.json index 9ead52f..22335d1 100644 --- a/webview/package.json +++ b/webview/package.json @@ -13,7 +13,6 @@ "@types/react": "^17.0.18", "@types/react-dom": "^17.0.9", "@types/react-redux": "^7.1.7", - "@types/ssh2": "^0.5.47", "@typescript-eslint/eslint-plugin": "^4.5.0", "@typescript-eslint/parser": "^4.5.0", "babel-eslint": "^10.1.0", @@ -68,5 +67,8 @@ "presets": [ "react-app" ] + }, + "dependencies": { + "common": "workspace:*" } } diff --git a/webview/src/ConfigEditor/configGroupField.tsx b/webview/src/ConfigEditor/configGroupField.tsx index f1653dc..335e40f 100644 --- a/webview/src/ConfigEditor/configGroupField.tsx +++ b/webview/src/ConfigEditor/configGroupField.tsx @@ -1,6 +1,6 @@ +import { getGroups } from 'common/fileSystemConfig'; import { FieldDropdownWithInput } from '../FieldTypes/dropdownwithinput'; import { connect } from '../redux'; -import { getGroups } from '../types/fileSystemConfig'; export interface StateProps { values: string[]; diff --git a/webview/src/ConfigEditor/fields.tsx b/webview/src/ConfigEditor/fields.tsx index 4fe76de..3251f6d 100644 --- a/webview/src/ConfigEditor/fields.tsx +++ b/webview/src/ConfigEditor/fields.tsx @@ -1,3 +1,4 @@ +import { FileSystemConfig, invalidConfigName } from 'common/fileSystemConfig'; import * as React from 'react'; import { FieldCheckbox } from '../FieldTypes/checkbox'; import { FieldDropdown } from '../FieldTypes/dropdown'; @@ -6,7 +7,6 @@ import { FieldNumber } from '../FieldTypes/number'; import { FieldPath } from '../FieldTypes/path'; import { FieldString } from '../FieldTypes/string'; import { FieldUmask } from '../FieldTypes/umask'; -import { FileSystemConfig, invalidConfigName } from '../types/fileSystemConfig'; import FieldConfigGroup from './configGroupField'; import { PROXY_FIELD } from './proxyFields'; diff --git a/webview/src/ConfigEditor/index.tsx b/webview/src/ConfigEditor/index.tsx index 443a01d..fab52d2 100644 --- a/webview/src/ConfigEditor/index.tsx +++ b/webview/src/ConfigEditor/index.tsx @@ -1,7 +1,7 @@ +import { FileSystemConfig, formatConfigLocation } from 'common/fileSystemConfig'; import * as React from 'react'; import { FieldGroup } from '../FieldTypes/group'; import { connect, pickProperties } from '../redux'; -import { FileSystemConfig, formatConfigLocation } from '../types/fileSystemConfig'; import type { IConfigEditorState } from '../view'; import { configEditorSetNewConfig, configEditorSetStatusMessage, openStartScreen } from '../view/actions'; import { deleteConfig, saveConfig } from '../vscode'; diff --git a/webview/src/ConfigEditor/proxyFields.tsx b/webview/src/ConfigEditor/proxyFields.tsx index abfba19..72ba7ac 100644 --- a/webview/src/ConfigEditor/proxyFields.tsx +++ b/webview/src/ConfigEditor/proxyFields.tsx @@ -1,9 +1,9 @@ +import type { FileSystemConfig } from 'common/fileSystemConfig'; import * as React from 'react'; import { FieldConfig } from '../FieldTypes/config'; import { FieldDropdown } from '../FieldTypes/dropdown'; import { FieldNumber } from '../FieldTypes/number'; import { FieldString } from '../FieldTypes/string'; -import { FileSystemConfig } from '../types/fileSystemConfig'; import type { FieldFactory, FSCChanged, FSCChangedMultiple } from './fields'; function hostAndPort(config: FileSystemConfig, onChange: FSCChanged<'proxy'>): React.ReactElement { diff --git a/webview/src/ConfigList/index.tsx b/webview/src/ConfigList/index.tsx index 2b23cba..39b98a7 100644 --- a/webview/src/ConfigList/index.tsx +++ b/webview/src/ConfigList/index.tsx @@ -1,6 +1,6 @@ +import type { FileSystemConfig } from 'common/fileSystemConfig'; import * as React from 'react'; import { connect } from '../redux'; -import type { FileSystemConfig } from '../types/fileSystemConfig'; import { openConfigEditor } from '../view/actions'; import './index.css'; diff --git a/webview/src/ConfigLocator.tsx b/webview/src/ConfigLocator.tsx index 3a72301..cd758c3 100644 --- a/webview/src/ConfigLocator.tsx +++ b/webview/src/ConfigLocator.tsx @@ -1,7 +1,7 @@ +import { FileSystemConfig, formatConfigLocation } from 'common/fileSystemConfig'; import * as React from 'react'; import ConfigList from './ConfigList'; import { connect, pickProperties } from './redux'; -import { FileSystemConfig, formatConfigLocation } from './types/fileSystemConfig'; import type { IConfigLocatorState } from './view'; function displayName(config: FileSystemConfig) { diff --git a/webview/src/FieldTypes/config.tsx b/webview/src/FieldTypes/config.tsx index e413e1c..02c05ea 100644 --- a/webview/src/FieldTypes/config.tsx +++ b/webview/src/FieldTypes/config.tsx @@ -1,5 +1,5 @@ +import { FileSystemConfig, formatConfigLocation } from 'common/fileSystemConfig'; import { connect } from '../redux'; -import { FileSystemConfig, formatConfigLocation } from '../types/fileSystemConfig'; import type { Props as FieldBaseProps } from './base'; import { FieldDropdown, Props as FieldDropdownProps } from './dropdown'; diff --git a/webview/src/NewConfig.tsx b/webview/src/NewConfig.tsx index 3710739..b1a1740 100644 --- a/webview/src/NewConfig.tsx +++ b/webview/src/NewConfig.tsx @@ -1,9 +1,9 @@ +import { ConfigLocation, formatConfigLocation, invalidConfigName } from 'common/fileSystemConfig'; import * as React from 'react'; import { FieldDropdown } from './FieldTypes/dropdown'; import { FieldGroup } from './FieldTypes/group'; import { FieldString } from './FieldTypes/string'; import { connect, pickProperties, State } from './redux'; -import { ConfigLocation, formatConfigLocation, invalidConfigName } from './types/fileSystemConfig'; import type { INewConfigState } from './view'; import { newConfigSetLocation, newConfigSetName, openConfigEditor, openStartScreen } from './view/actions'; import { createConfig } from './vscode'; diff --git a/webview/src/Startscreen.tsx b/webview/src/Startscreen.tsx index 2cb398c..63b4aec 100644 --- a/webview/src/Startscreen.tsx +++ b/webview/src/Startscreen.tsx @@ -1,8 +1,8 @@ +import { ConfigLocation, FileSystemConfig, formatConfigLocation, groupByGroup, groupByLocation } from 'common/fileSystemConfig'; import * as React from 'react'; import ConfigList from './ConfigList'; import { receivedData } from './data/actions'; import { connect, pickProperties } from './redux'; -import { ConfigLocation, FileSystemConfig, formatConfigLocation, groupByGroup, groupByLocation } from './types/fileSystemConfig'; import type { IStartScreenState } from './view'; import { openNewConfig, openStartScreen } from './view/actions'; import { API } from './vscode'; diff --git a/webview/src/data/actions.ts b/webview/src/data/actions.ts index 9d331aa..2ee1c99 100644 --- a/webview/src/data/actions.ts +++ b/webview/src/data/actions.ts @@ -1,4 +1,4 @@ -import type { ConfigLocation, FileSystemConfig } from '../types/fileSystemConfig'; +import type { ConfigLocation, FileSystemConfig } from 'common/fileSystemConfig'; export enum ActionType { RECEIVED_DATA = 'RECEIVED_DATA', diff --git a/webview/src/data/state.ts b/webview/src/data/state.ts index 64e8847..38fa429 100644 --- a/webview/src/data/state.ts +++ b/webview/src/data/state.ts @@ -1,4 +1,4 @@ -import type { ConfigLocation, FileSystemConfig } from '../types/fileSystemConfig'; +import type { ConfigLocation, FileSystemConfig } from 'common/fileSystemConfig'; export interface IState { configs: FileSystemConfig[]; diff --git a/webview/src/types/fileSystemConfig.ts b/webview/src/types/fileSystemConfig.ts deleted file mode 100644 index 39dc8c8..0000000 --- a/webview/src/types/fileSystemConfig.ts +++ /dev/null @@ -1,161 +0,0 @@ -import type { ConnectConfig } from 'ssh2'; - -export interface ProxyConfig { - type: 'socks4' | 'socks5' | 'http'; - host: string; - port: number; -} - -export type ConfigLocation = number | string; - -/** Might support conditional stuff later, although ssh2/OpenSSH might not support that natively */ -export interface EnvironmentVariable { - key: string; - value: string; -} - -export function formatConfigLocation(location?: ConfigLocation): string { - if (!location) return 'Unknown location'; - if (typeof location === 'number') { - return `${[, 'Global', 'Workspace', 'WorkspaceFolder'][location] || 'Unknown'} settings.json`; - } - return location; -} - -export function getLocations(configs: FileSystemConfig[]): ConfigLocation[] { - const res: ConfigLocation[] = [1, 2 /*, 3*/]; // No WorkspaceFolder support (for now) - // TODO: Suggest creating sshfs.jsonc etc in current workspace folder(s) (UI feature?) - for (const { _location } of configs) { - if (!_location) continue; - if (!res.find(l => l === _location)) { - res.push(_location); - } - } - return res; -} - -export function getGroups(configs: FileSystemConfig[], expanded = false): string[] { - const res: string[] = []; - function addGroup(group: string) { - if (!res.find(l => l === group)) { - res.push(group); - } - } - for (const { group } of configs) { - if (!group) continue; - const groups = expanded ? group.split('.') : [group]; - groups.forEach((g, i) => addGroup([...groups.slice(0, i), g].join('.'))); - } - return res; -} - -export function groupByLocation(configs: FileSystemConfig[]): [ConfigLocation, FileSystemConfig[]][] { - const res: [ConfigLocation, FileSystemConfig[]][] = []; - function getForLoc(loc: ConfigLocation = 'Unknown') { - let found = res.find(([l]) => l === loc); - if (found) return found; - found = [loc, []]; - res.push(found); - return found; - } - for (const config of configs) { - getForLoc(config._location!)[1].push(config); - } - return res; -} - -export function groupByGroup(configs: FileSystemConfig[]): [string, FileSystemConfig[]][] { - const res: [string, FileSystemConfig[]][] = []; - function getForGroup(group: string = '') { - let found = res.find(([l]) => l === group); - if (found) return found; - found = [group, []]; - res.push(found); - return found; - } - for (const config of configs) { - getForGroup(config.group)[1].push(config); - } - return res; -} - -export interface FileSystemConfig extends ConnectConfig { - /** Name of the config. Can only exists of lowercase alphanumeric characters, slashes and any of these: _.+-@ */ - name: string; - /** Optional label to display in some UI places (e.g. popups) */ - label?: string; - /** Optional group for this config, to group configs together in some UI places. Allows subgroups, in the format "Group1.SubGroup1.Subgroup2" */ - group?: string; - /** Whether to merge this "lower" config (e.g. from workspace settings) into higher configs (e.g. from global settings) */ - merge?: boolean; - /** Path on the remote server that should be opened by default when creating a terminal or using the `Add as Workspace folder` command/button. Defaults to `/` */ - root?: string; - /** A name of a PuTTY session, or `true` to find the PuTTY session from the host address */ - putty?: string | boolean; - /** Optional object defining a proxy to use */ - proxy?: ProxyConfig; - /** Optional path to a private keyfile to authenticate with */ - privateKeyPath?: string; - /** A name of another config to use as a hop */ - hop?: string; - /** The command to run on the remote SSH session to start a SFTP session (defaults to sftp subsystem) */ - sftpCommand?: string; - /** Whether to use a sudo shell (and for which user) to run the sftpCommand in (sftpCommand defaults to /usr/lib/openssh/sftp-server if missing) */ - sftpSudo?: string | boolean; - /** The command(s) to run when a new SSH terminal gets created. Defaults to `$SHELL`. Internally the command `cd ...` is run first */ - terminalCommand?: string | string[]; - /** The command(s) to run when a `ssh-shell` task gets run. Defaults to the placeholder `$COMMAND`. Internally the command `cd ...` is run first */ - taskCommand?: string | string[]; - /** An object with environment variables to add to the SSH connection. Affects the whole connection thus all terminals */ - environment?: EnvironmentVariable[] | Record; - /** The filemode to assign to new files created using VS Code, not the terminal. Similar to umask. Defaults to `rw-rw-r--` (regardless of server config, whether you are root, ...) */ - newFileMode?: number | string; - /** Whether this config was created from an instant connection string. Enables fuzzy matching for e.g. PuTTY, config-by-host, ... */ - instantConnection?: boolean; - /** List of special flags to enable/disable certain fixes/features. Flags are usually used for issues or beta testing. Flags can disappear/change anytime! */ - flags?: string[]; - /** Internal property saying where this config comes from. Undefined if this config is merged or something */ - _location?: ConfigLocation; - /** Internal property keeping track of where this config comes from (including merges) */ - _locations: ConfigLocation[]; - /** Internal property keeping track of whether this config is an actually calculated one, and if so, which config it originates from (normally itself) */ - _calculated?: FileSystemConfig; -} - -export function invalidConfigName(name: string) { - if (!name) return 'Missing a name for this SSH FS'; - if (name.match(/^[\w_\\/.@\-+]+$/)) return null; - return `A SSH FS name can only exists of lowercase alphanumeric characters, slashes and any of these: _.+-@`; -} - -/** - * https://regexr.com/5m3gl (mostly based on https://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04) - * Supports several formats, the first one being the "full" format, with others being partial: - * - `user;abc=def,a-b=1-5@server.example.com:22/some/file.ext` - * - `user@server.example.com/directory` - * - `server:22/directory` - * - `test-user@server` - * - `server` - * - `@server/path` - Unlike OpenSSH, we allow a @ (and connection parameters) without a username - * - * The resulting FileSystemConfig will have as name basically the input, but without the path. If there is no - * username given, the name will start with `@`, as to differentiate between connection strings and config names. - */ -const CONNECTION_REGEX = /^((?[\w\-._]+)?(;[\w-]+=[\w\d-]+(,[\w\d-]+=[\w\d-]+)*)?@)?(?[^\s@\\/:,=]+)(:(?\d+))?(?\/\S*)?$/; - -export function parseConnectionString(input: string): [config: FileSystemConfig, path?: string] | string { - input = input.trim(); - const match = input.match(CONNECTION_REGEX); - if (!match) return 'Invalid format, expected something like "user@example.com:22/some/path"'; - const { user, host, path } = match.groups!; - const portStr = match.groups!.port; - const port = portStr ? Number.parseInt(portStr) : undefined; - if (portStr && (!port || port < 1 || port > 65535)) return `The string '${port}' is not a valid port number`; - const name = `${user || ''}@${host}${port ? `:${port}` : ''}${path || ''}`; - return [{ - name, host, port, - instantConnection: true, - username: user || '$USERNAME', - _locations: [], - }, path]; -} diff --git a/webview/src/types/webviewMessages.ts b/webview/src/types/webviewMessages.ts deleted file mode 100644 index a685b8f..0000000 --- a/webview/src/types/webviewMessages.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { ConfigLocation, FileSystemConfig } from './fileSystemConfig'; - -/* Type of messages*/ - -export interface RequestDataMessage { - type: 'requestData'; -} -export interface ResponseDataMessage { - type: 'responseData'; - configs: FileSystemConfig[]; - locations: ConfigLocation[]; -} - -export interface SaveConfigMessage { - type: 'saveConfig'; - config: FileSystemConfig; - name?: string; - uniqueId?: string; - remove?: boolean; -} -export interface SaveConfigResultMessage { - type: 'saveConfigResult'; - error?: string; - config: FileSystemConfig; - uniqueId?: string; -} - -export interface PromptPathMessage { - type: 'promptPath'; - uniqueId?: string; -} -export interface PromptPathResultMessage { - type: 'promptPathResult'; - error?: string; - path?: string; - uniqueId?: string; -} - -export interface NavigateMessage { - type: 'navigate'; - navigation: Navigation; -} -export interface NavigatedMessage { - type: 'navigated'; - view: string; -} - -export interface MessageTypes { - requestData: RequestDataMessage; - responseData: ResponseDataMessage; - saveConfig: SaveConfigMessage; - saveConfigResult: SaveConfigResultMessage; - promptPath: PromptPathMessage; - promptPathResult: PromptPathResultMessage; - navigate: NavigateMessage; - navigated: NavigatedMessage; -} - -export type Message = MessageTypes[keyof MessageTypes]; - -/* Types related to NavigateMessage */ - -export interface NewConfigNavigation { - type: 'newconfig'; -} -export interface EditConfigNavigation { - type: 'editconfig'; - config: FileSystemConfig | FileSystemConfig[]; -} -export type Navigation = NewConfigNavigation | EditConfigNavigation; diff --git a/webview/src/view/actions.ts b/webview/src/view/actions.ts index c495b0f..cd41154 100644 --- a/webview/src/view/actions.ts +++ b/webview/src/view/actions.ts @@ -1,4 +1,4 @@ -import type { ConfigLocation, FileSystemConfig } from '../types/fileSystemConfig'; +import type { ConfigLocation, FileSystemConfig } from 'common/fileSystemConfig'; export enum ActionType { // Startscreen diff --git a/webview/src/view/state.ts b/webview/src/view/state.ts index f23e81b..81f6fe3 100644 --- a/webview/src/view/state.ts +++ b/webview/src/view/state.ts @@ -1,4 +1,4 @@ -import type { ConfigLocation, FileSystemConfig } from '../types/fileSystemConfig'; +import type { ConfigLocation, FileSystemConfig } from 'common/fileSystemConfig'; interface IViewState { view: V; diff --git a/webview/src/vscode.ts b/webview/src/vscode.ts index 17c5bee..cbfbc5c 100644 --- a/webview/src/vscode.ts +++ b/webview/src/vscode.ts @@ -1,6 +1,6 @@ -import type { ConfigLocation, FileSystemConfig } from './types/fileSystemConfig'; -import type { Message, MessageTypes, PromptPathResultMessage, SaveConfigResultMessage } from './types/webviewMessages'; +import type { ConfigLocation, FileSystemConfig } from 'common/fileSystemConfig'; +import type { Message, MessageTypes, PromptPathResultMessage, SaveConfigResultMessage } from 'common/webviewMessages'; interface VSCodeAPI { postMessage(msg: Message): void;