diff --git a/.vscode/settings.json b/.vscode/settings.json index 7fef8b16..2c1653d3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "chat.tools.terminal.autoApprove": { "npm run build": true, "npm run esbuild": true, + "npm run dev": true, "npm run lint": true, "npm run lint-fix": true, "npm run lint-api": true, diff --git a/bin/esbuild.mjs b/bin/esbuild.mjs index 1727defe..b1e9e88f 100644 --- a/bin/esbuild.mjs +++ b/bin/esbuild.mjs @@ -12,6 +12,7 @@ const config = { isProd: argv.includes('--prod'), isWatch: argv.includes('--watch'), isDemoClient: argv.includes('--demo-client'), + isDemoServer: argv.includes('--demo-server'), isHeadless: argv.includes('--headless'), addon: argv.find(e => e.startsWith('--addon='))?.replace(/^--addon=/, ''), }; @@ -126,7 +127,7 @@ if (config.addon) { } else if (config.isDemoClient) { bundleConfig = { ...bundleConfig, - entryPoints: [`demo/client.ts`], + entryPoints: [`demo/client/client.ts`], outfile: 'demo/dist/client-bundle.js', external: ['util', 'os', 'fs', 'path', 'stream', 'Terminal'], alias: { @@ -152,6 +153,19 @@ if (config.addon) { "@xterm/addon-ligatures": "./addons/addon-ligatures/out-esbuild/LigaturesAddon", } } + skipOut = true; + skipOutTest = true; +} else if (config.isDemoServer) { + bundleConfig = { + ...bundleConfig, + entryPoints: [`demo/server/server.ts`], + outfile: 'demo/dist/server-bundle.js', + format: 'cjs', + platform: 'node', + external: ['node-pty'], + } + skipOut = true; + skipOutTest = true; } else if (config.isHeadless) { bundleConfig = { ...bundleConfig, diff --git a/demo/client.ts b/demo/client/client.ts similarity index 100% rename from demo/client.ts rename to demo/client/client.ts diff --git a/demo/components/controlBar.ts b/demo/client/components/controlBar.ts similarity index 100% rename from demo/components/controlBar.ts rename to demo/client/components/controlBar.ts diff --git a/demo/components/window/addonsWindow.ts b/demo/client/components/window/addonsWindow.ts similarity index 100% rename from demo/components/window/addonsWindow.ts rename to demo/client/components/window/addonsWindow.ts diff --git a/demo/components/window/baseWindow.ts b/demo/client/components/window/baseWindow.ts similarity index 100% rename from demo/components/window/baseWindow.ts rename to demo/client/components/window/baseWindow.ts diff --git a/demo/components/window/gpuWindow.ts b/demo/client/components/window/gpuWindow.ts similarity index 100% rename from demo/components/window/gpuWindow.ts rename to demo/client/components/window/gpuWindow.ts diff --git a/demo/components/window/optionsWindow.ts b/demo/client/components/window/optionsWindow.ts similarity index 100% rename from demo/components/window/optionsWindow.ts rename to demo/client/components/window/optionsWindow.ts diff --git a/demo/components/window/styleWindow.ts b/demo/client/components/window/styleWindow.ts similarity index 100% rename from demo/components/window/styleWindow.ts rename to demo/client/components/window/styleWindow.ts diff --git a/demo/components/window/testWindow.ts b/demo/client/components/window/testWindow.ts similarity index 99% rename from demo/components/window/testWindow.ts rename to demo/client/components/window/testWindow.ts index 99efbad4..bb542595 100644 --- a/demo/components/window/testWindow.ts +++ b/demo/client/components/window/testWindow.ts @@ -3,9 +3,9 @@ * @license MIT */ -/// +/// -import { writeUnicodeTable } from 'unicodeTable'; +import { writeUnicodeTable } from '../../unicodeTable'; import type { IControlWindow } from '../controlBar'; import { BaseWindow } from './baseWindow'; import type { IDisposable, Terminal } from '@xterm/xterm'; diff --git a/demo/components/window/vtWindow.ts b/demo/client/components/window/vtWindow.ts similarity index 100% rename from demo/components/window/vtWindow.ts rename to demo/client/components/window/vtWindow.ts diff --git a/demo/client/tsconfig.json b/demo/client/tsconfig.json new file mode 100644 index 00000000..7676cd37 --- /dev/null +++ b/demo/client/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2021", + "rootDir": ".", + "sourceMap": true, + "baseUrl": ".", + "paths": { + "@xterm/addon-attach": ["../../addons/addon-attach"], + "@xterm/addon-clipboard": ["../../addons/addon-clipboard"], + "@xterm/addon-fit": ["../../addons/addon-fit"], + "@xterm/addon-image": ["../../addons/addon-image"], + "@xterm/addon-progress": ["../../addons/addon-progress"], + "@xterm/addon-search": ["../../addons/addon-search"], + "@xterm/addon-serialize": ["../../addons/addon-serialize"], + "@xterm/addon-web-links": ["../../addons/addon-web-links"], + "@xterm/addon-webgl": ["../../addons/addon-webgl"], + "@xterm/addon-unicode11": ["../../addons/addon-unicode11"], + "@xterm/addon-unicode-graphemes": ["../../addons/addon-unicode-graphemes"], + "@xterm/addon-ligatures": ["../../addons/addon-ligatures"] + } + }, + "include": [ + "client.ts", + "../../typings/xterm.d.ts" + ] +} diff --git a/demo/unicodeTable.ts b/demo/client/unicodeTable.ts similarity index 100% rename from demo/unicodeTable.ts rename to demo/client/unicodeTable.ts diff --git a/demo/server.js b/demo/server/server.ts similarity index 78% rename from demo/server.js rename to demo/server/server.ts index 4537d501..cefb343e 100644 --- a/demo/server.js +++ b/demo/server/server.ts @@ -4,54 +4,58 @@ * demo to the public as is would introduce security risks for the host. **/ -// @ts-check +import * as express from 'express'; +import * as expressWs from 'express-ws'; +import * as os from 'os'; +import * as pty from 'node-pty'; +import * as path from 'path'; +import type { IPty } from 'node-pty'; -const express = require('express'); -const expressWs = require('express-ws'); -const os = require('os'); -const pty = require('node-pty'); +interface IDisposable { + dispose(): void; +} /** Whether to use binary transport. */ const USE_BINARY = os.platform() !== "win32"; -function startServer() { +const demoRoot = path.join(__dirname, '..'); + +function startServer(): void { const app = express(); const appWs = expressWs(app).app; - const terminals = {}; - const unsentOutput = {}; - const temporaryDisposable = {}; + const terminals: { [pid: number]: IPty } = {}; + const unsentOutput: { [pid: number]: string } = {}; + const temporaryDisposable: { [pid: number]: IDisposable } = {}; - app.use('/xterm.css', express.static(__dirname + '/../css/xterm.css')); + app.use('/xterm.css', express.static(demoRoot + '/../css/xterm.css')); app.get('/logo.png', (req, res) => { - res.sendFile(__dirname + '/logo.png'); + res.sendFile(demoRoot + '/logo.png'); }); app.get('/', (req, res) => { - res.sendFile(__dirname + '/index.html'); + res.sendFile(demoRoot + '/index.html'); }); app.get('/test', (req, res) => { - res.sendFile(__dirname + '/test.html'); + res.sendFile(demoRoot + '/test.html'); }); app.get('/index.css', (req, res) => { - res.sendFile(__dirname + '/index.css'); + res.sendFile(demoRoot + '/index.css'); }); - app.use('/dist', express.static(__dirname + '/dist')); - app.use('/src', express.static(__dirname + '/src')); + app.use('/dist', express.static(demoRoot + '/dist')); + app.use('/src', express.static(demoRoot + '/src')); app.post('/terminals', (req, res) => { - /** @type {{ [key: string]: string }} */ - const env = {}; + const env: { [key: string]: string } = {}; for (const k of Object.keys(process.env)) { const v = process.env[k]; if (v) { env[k] = v; } } - // const env = Object.assign({}, process.env); env['COLORTERM'] = 'truecolor'; if (typeof req.query.cols !== 'string' || typeof req.query.rows !== 'string') { console.error({ req }); @@ -108,10 +112,10 @@ function startServer() { let userInput = false; // string message buffering - function buffer(socket, timeout, maxSize) { + function buffer(socket: typeof ws, timeout: number, maxSize: number) { let s = ''; - let sender = null; - return (data) => { + let sender: ReturnType | null = null; + return (data: string) => { s += data; if (s.length > maxSize || userInput) { userInput = false; @@ -131,11 +135,11 @@ function startServer() { }; } // binary message buffering - function bufferUtf8(socket, timeout, maxSize) { - const chunks = []; + function bufferUtf8(socket: typeof ws, timeout: number, maxSize: number) { + const chunks: Buffer[] = []; let length = 0; - let sender = null; - return (data) => { + let sender: ReturnType | null = null; + return (data: Buffer) => { chunks.push(data); length += data.length; if (length > maxSize || userInput) { @@ -164,13 +168,13 @@ function startServer() { // the problem and how to implement flow control at https://xtermjs.org/docs/guides/flowcontrol/ term.onData(function(data) { try { - send(data); + send(data as string & Buffer); } catch (ex) { // The WebSocket is not open, ignore } }); ws.on('message', function(msg) { - term.write(msg); + term.write(msg.toString()); userInput = true; }); ws.on('close', function () { @@ -196,4 +200,4 @@ process.on('uncaughtException', (error) => { } }); -module.exports = startServer; +export default startServer; diff --git a/demo/server/tsconfig.json b/demo/server/tsconfig.json new file mode 100644 index 00000000..ed5c6a90 --- /dev/null +++ b/demo/server/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2021", + "rootDir": ".", + "sourceMap": true + }, + "include": [ + "server.ts" + ] +} diff --git a/demo/start.js b/demo/start.js index b240966f..08f9c059 100644 --- a/demo/start.js +++ b/demo/start.js @@ -5,6 +5,6 @@ // @ts-check -const startServer = require('./server.js'); +const startServer = require('./dist/server-bundle.js').default; startServer(); diff --git a/demo/tsconfig.json b/demo/tsconfig.json index 405dbf0f..e9e26053 100644 --- a/demo/tsconfig.json +++ b/demo/tsconfig.json @@ -1,27 +1,7 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es2021", - "rootDir": ".", - "sourceMap": true, - "baseUrl": ".", - "paths": { - "@xterm/addon-attach": ["../addons/addon-attach"], - "@xterm/addon-clipboard": ["../addons/addon-clipboard"], - "@xterm/addon-fit": ["../addons/addon-fit"], - "@xterm/addon-image": ["../addons/addon-image"], - "@xterm/addon-progress": ["../addons/addon-progress"], - "@xterm/addon-search": ["../addons/addon-search"], - "@xterm/addon-serialize": ["../addons/addon-serialize"], - "@xterm/addon-web-links": ["../addons/addon-web-links"], - "@xterm/addon-webgl": ["../addons/addon-webgl"], - "@xterm/addon-unicode11": ["../addons/addon-unicode11"], - "@xterm/addon-unicode-graphemes": ["../addons/addon-unicode-graphemes"], - "@xterm/addon-ligatures": ["../addons/addon-ligatures"] - } - }, - "include": [ - "client.ts", - "../typings/xterm.d.ts" - ] + "references": [ + { "path": "./client" }, + { "path": "./server" } + ], + "files": [] }