@lvce-editor/pty-host 0.15.16 → 0.15.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -2
- package/src/parts/Assert/Assert.js +7 -5
- package/src/parts/AssertionError/AssertionError.js +6 -0
- package/src/parts/CleanStack/CleanStack.js +93 -0
- package/src/parts/Command/Command.js +9 -0
- package/src/parts/CommandMap/CommandMap.js +13 -0
- package/src/parts/CommandNotFoundError/CommandNotFoundError.js +9 -0
- package/src/parts/CommandState/CommandState.js +17 -0
- package/src/parts/EncodingType/EncodingType.js +1 -0
- package/src/parts/ErrorCodes/ErrorCodes.js +18 -0
- package/src/parts/FirstWebSocketEventType/FirstWebSocketEventType.js +2 -0
- package/src/parts/GetErrorResponse/GetErrorResponse.js +56 -0
- package/src/parts/GetFirstWebSocketEvent/GetFirstWebSocketEvent.js +41 -0
- package/src/parts/GetResponse/GetResponse.js +15 -0
- package/src/parts/GetSuccessResponse/GetSuccessResponse.js +12 -0
- package/src/parts/HandleElectronMessagePort/HandleElectronMessagePort.js +14 -0
- package/src/parts/HandleIpc/HandleIpc.js +13 -0
- package/src/parts/HandleNodeMessagePort/HandleNodeMessagePort.js +12 -0
- package/src/parts/HandleWebSocket/HandleWebSocket.js +18 -0
- package/src/parts/IpcChild/IpcChild.js +3 -2
- package/src/parts/IpcChildModule/IpcChildModule.js +8 -0
- package/src/parts/IpcChildType/IpcChildType.js +7 -0
- package/src/parts/IpcChildWithElectronMessagePort/IpcChildWithElectronMessagePort.js +39 -0
- package/src/parts/IpcChildWithElectronUtilityProcess/IpcChildWithElectronUtilityProcess.js +48 -0
- package/src/parts/IpcChildWithNodeForkedProcess/IpcChildWithNodeForkedProcess.js +20 -2
- package/src/parts/IpcChildWithNodeMessagePort/IpcChildWithNodeMessagePort.js +27 -0
- package/src/parts/IpcChildWithWebSocket/IpcChildWithWebSocket.js +51 -0
- package/src/parts/IpcError/IpcError.js +6 -0
- package/src/parts/IsMessagePort/IsMessagePort.js +3 -0
- package/src/parts/IsMessagePortMain/IsMessagePortMain.js +3 -0
- package/src/parts/IsWebSocketOpen/IsWebSocketOpen.js +5 -0
- package/src/parts/JoinLines/JoinLines.js +3 -0
- package/src/parts/Json/Json.js +17 -0
- package/src/parts/JsonError/JsonError.js +64 -0
- package/src/parts/JsonParsingError/JsonParsingError.js +17 -0
- package/src/parts/JsonRpcErrorCode/JsonRpcErrorCode.js +2 -0
- package/src/parts/JsonRpcVersion/JsonRpcVersion.js +1 -0
- package/src/parts/Logger/Logger.js +50 -0
- package/src/parts/Main/Main.js +11 -0
- package/src/parts/NodePty/NodePty.js +60 -0
- package/src/parts/PrettyError/PrettyError.js +139 -0
- package/src/parts/PrintPrettyError/PrintPrettyError.js +5 -0
- package/src/parts/Pty/Pty.js +1 -48
- package/src/parts/PtyController/PtyController.js +18 -9
- package/src/parts/RequiresSocket/RequiresSocket.js +5 -0
- package/src/parts/SplitLines/SplitLines.js +3 -0
- package/src/parts/WebSocketServer/WebSocketServer.ipc.js +7 -0
- package/src/parts/WebSocketServer/WebSocketServer.js +24 -0
- package/src/ptyHostMain.cjs +1 -0
- package/src/ptyHostMain.js +2 -21
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as GetFirstWebSocketEvent from '../GetFirstWebSocketEvent/GetFirstWebSocketEvent.js'
|
|
2
|
+
import * as IsWebSocketOpen from '../IsWebSocketOpen/IsWebSocketOpen.js'
|
|
3
|
+
|
|
4
|
+
export const listen = async ({ webSocket }) => {
|
|
5
|
+
if (!IsWebSocketOpen.isWebSocketOpen(webSocket)) {
|
|
6
|
+
const { type, event } = await GetFirstWebSocketEvent.getFirstWebSocketEvent(webSocket)
|
|
7
|
+
console.log({ type, event })
|
|
8
|
+
}
|
|
9
|
+
return webSocket
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class MessageEvent extends Event {
|
|
13
|
+
constructor(data, target) {
|
|
14
|
+
super('message')
|
|
15
|
+
this.data = data
|
|
16
|
+
this.target = target
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const wrap = (webSocket) => {
|
|
21
|
+
return {
|
|
22
|
+
webSocket,
|
|
23
|
+
/**
|
|
24
|
+
* @type {any}
|
|
25
|
+
*/
|
|
26
|
+
wrappedListener: undefined,
|
|
27
|
+
on(event, listener) {
|
|
28
|
+
switch (event) {
|
|
29
|
+
case 'message':
|
|
30
|
+
const wrappedListener = (message) => {
|
|
31
|
+
const data = JSON.parse(message.toString())
|
|
32
|
+
listener(data)
|
|
33
|
+
}
|
|
34
|
+
webSocket.on('message', wrappedListener)
|
|
35
|
+
break
|
|
36
|
+
default:
|
|
37
|
+
throw new Error('unknown event listener type')
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
off(event, listener) {
|
|
41
|
+
this.webSocket.off(event, listener)
|
|
42
|
+
},
|
|
43
|
+
send(message) {
|
|
44
|
+
const stringifiedMessage = JSON.stringify(message)
|
|
45
|
+
this.webSocket.send(stringifiedMessage)
|
|
46
|
+
},
|
|
47
|
+
dispose() {
|
|
48
|
+
this.webSocket.close()
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// parsing error handling based on https://github.com/sindresorhus/parse-json/blob/main/index.js
|
|
2
|
+
|
|
3
|
+
import { JsonParsingError } from '../JsonParsingError/JsonParsingError.js'
|
|
4
|
+
|
|
5
|
+
export const parse = async (string, filePath) => {
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(string)
|
|
8
|
+
} catch (error) {
|
|
9
|
+
const JsonError = await import('../JsonError/JsonError.js')
|
|
10
|
+
const errorProps = JsonError.getErrorPropsFromError(error, string, filePath)
|
|
11
|
+
throw new JsonParsingError(errorProps.message, errorProps.codeFrame, errorProps.stack)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const stringify = (value) => {
|
|
16
|
+
return JSON.stringify(value, null, 2) + '\n'
|
|
17
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { codeFrameColumns } from '@babel/code-frame'
|
|
2
|
+
import { LinesAndColumns } from 'lines-and-columns'
|
|
3
|
+
|
|
4
|
+
// parsing error handling based on https://github.com/sindresorhus/parse-json/blob/main/index.js
|
|
5
|
+
|
|
6
|
+
const emptyError = {
|
|
7
|
+
message: '',
|
|
8
|
+
stack: '',
|
|
9
|
+
codeFrame: '',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const getErrorPropsFromError = (error, string, filePath) => {
|
|
13
|
+
const indexMatch = error.message.match(/in JSON at position (\d+)/)
|
|
14
|
+
if (indexMatch && indexMatch.length > 0) {
|
|
15
|
+
const lines = new LinesAndColumns(string)
|
|
16
|
+
const index = Number(indexMatch[1])
|
|
17
|
+
const location = lines.locationForIndex(index)
|
|
18
|
+
if (location) {
|
|
19
|
+
const line = location.line + 1
|
|
20
|
+
const column = location.column + 1
|
|
21
|
+
const codeFrame = codeFrameColumns(string, { start: { line, column } }, { highlightCode: false })
|
|
22
|
+
return {
|
|
23
|
+
codeFrame,
|
|
24
|
+
message: 'Json Parsing Error',
|
|
25
|
+
stack: ` at ${filePath}:${line}:${column}`,
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (string.length === 0) {
|
|
30
|
+
return {
|
|
31
|
+
codeFrame: ``,
|
|
32
|
+
message: 'Json Parsing Error: Cannot parse empty string',
|
|
33
|
+
stack: ` at ${filePath}`,
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (error.message === 'Unexpected end of JSON input') {
|
|
38
|
+
const lines = new LinesAndColumns(string)
|
|
39
|
+
const index = string.length - 1
|
|
40
|
+
const location = lines.locationForIndex(index)
|
|
41
|
+
if (location) {
|
|
42
|
+
const codeFrame = codeFrameColumns(string, { start: { line: location.line + 1, column: location.column + 1 } }, { highlightCode: false })
|
|
43
|
+
return {
|
|
44
|
+
codeFrame,
|
|
45
|
+
message: 'Json Parsing Error',
|
|
46
|
+
stack: ` at ${filePath}`,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
codeFrame: ``,
|
|
52
|
+
message: 'Json Parsing Error',
|
|
53
|
+
stack: ` at ${filePath}`,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const getErrorProps = (string, filePath) => {
|
|
58
|
+
try {
|
|
59
|
+
JSON.parse(string)
|
|
60
|
+
return emptyError
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return getErrorPropsFromError(error, string, filePath)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as JoinLines from '../JoinLines/JoinLines.js'
|
|
2
|
+
import * as SplitLines from '../SplitLines/SplitLines.js'
|
|
3
|
+
|
|
4
|
+
export class JsonParsingError extends Error {
|
|
5
|
+
constructor(message, codeFrame, stack) {
|
|
6
|
+
super(message)
|
|
7
|
+
this.name = 'JsonParsingError'
|
|
8
|
+
if (codeFrame) {
|
|
9
|
+
this.codeFrame = codeFrame
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (stack) {
|
|
13
|
+
const parentStack = JoinLines.joinLines(SplitLines.splitLines(this.stack).slice(1))
|
|
14
|
+
this.stack = this.name + ': ' + this.message + '\n' + stack + '\n' + parentStack
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const Two = '2.0'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Console } from 'node:console'
|
|
2
|
+
import { createWriteStream } from 'node:fs'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
|
|
5
|
+
// TODO mock this module when used in unit tests
|
|
6
|
+
|
|
7
|
+
const state = {
|
|
8
|
+
/**
|
|
9
|
+
* @type {Console|undefined}
|
|
10
|
+
*/
|
|
11
|
+
console: undefined,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const createConsole = () => {
|
|
15
|
+
const logFile = `${tmpdir()}/log-terminal-process.txt`
|
|
16
|
+
const writeStream = createWriteStream(logFile)
|
|
17
|
+
const logger = new Console(writeStream)
|
|
18
|
+
return logger
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const getOrCreateLogger = () => {
|
|
22
|
+
if (!state.console) {
|
|
23
|
+
state.console = createConsole()
|
|
24
|
+
}
|
|
25
|
+
return state.console
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const log = (...args) => {
|
|
29
|
+
const logger = getOrCreateLogger()
|
|
30
|
+
logger.log(...args)
|
|
31
|
+
console.log(...args)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const info = (...args) => {
|
|
35
|
+
const logger = getOrCreateLogger()
|
|
36
|
+
logger.info(...args)
|
|
37
|
+
console.info(...args)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const warn = (...args) => {
|
|
41
|
+
const logger = getOrCreateLogger()
|
|
42
|
+
logger.warn(...args)
|
|
43
|
+
console.warn(...args)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const error = (...args) => {
|
|
47
|
+
const logger = getOrCreateLogger()
|
|
48
|
+
logger.error(...args)
|
|
49
|
+
console.error(...args)
|
|
50
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as CommandMap from '../CommandMap/CommandMap.js'
|
|
2
|
+
import * as CommandState from '../CommandState/CommandState.js'
|
|
3
|
+
import * as HandleIpc from '../HandleIpc/HandleIpc.js'
|
|
4
|
+
import * as IpcChild from '../IpcChild/IpcChild.js'
|
|
5
|
+
import * as IpcChildType from '../IpcChildType/IpcChildType.js'
|
|
6
|
+
|
|
7
|
+
export const main = async () => {
|
|
8
|
+
CommandState.registerCommands(CommandMap.commandMap)
|
|
9
|
+
const ipc = await IpcChild.listen({ method: IpcChildType.Auto() })
|
|
10
|
+
HandleIpc.handleIpc(ipc)
|
|
11
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { spawn } from 'node-pty'
|
|
2
|
+
import * as Platform from '../Platform/Platform.js'
|
|
3
|
+
import * as Assert from '../Assert/Assert.js'
|
|
4
|
+
import VError from 'verror'
|
|
5
|
+
|
|
6
|
+
const getSpawnOptions = () => {
|
|
7
|
+
if (Platform.isWindows) {
|
|
8
|
+
return {
|
|
9
|
+
command: 'powershell.exe',
|
|
10
|
+
args: [],
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
command: 'bash',
|
|
15
|
+
args: ['-i'],
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const create = ({ env = {}, cwd } = {}) => {
|
|
20
|
+
try {
|
|
21
|
+
Assert.string(cwd)
|
|
22
|
+
const spawnOptions = getSpawnOptions()
|
|
23
|
+
const pty = spawn(spawnOptions.command, spawnOptions.args, {
|
|
24
|
+
encoding: null,
|
|
25
|
+
cwd,
|
|
26
|
+
// cols: 10,
|
|
27
|
+
// rows: 10,
|
|
28
|
+
})
|
|
29
|
+
return pty
|
|
30
|
+
} catch (error) {
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
throw new VError(error, `Failed to create terminal`)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const onData = (pty, fn) => {
|
|
37
|
+
Assert.object(pty)
|
|
38
|
+
pty.onData(fn)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const write = (pty, data) => {
|
|
42
|
+
try {
|
|
43
|
+
Assert.object(pty)
|
|
44
|
+
pty.write(data)
|
|
45
|
+
} catch (error) {
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
throw new VError(error, `Failed to write data to terminal`)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const resize = (pty, columns, rows) => {
|
|
52
|
+
Assert.object(pty)
|
|
53
|
+
Assert.number(columns)
|
|
54
|
+
Assert.number(rows)
|
|
55
|
+
pty.resize(columns, rows)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const dispose = (pty) => {
|
|
59
|
+
pty.kill()
|
|
60
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { codeFrameColumns } from '@babel/code-frame'
|
|
2
|
+
import { LinesAndColumns } from 'lines-and-columns'
|
|
3
|
+
import { readFileSync } from 'node:fs'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { AssertionError } from '../AssertionError/AssertionError.js'
|
|
6
|
+
import * as CleanStack from '../CleanStack/CleanStack.js'
|
|
7
|
+
import * as EncodingType from '../EncodingType/EncodingType.js'
|
|
8
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
9
|
+
import * as JoinLines from '../JoinLines/JoinLines.js'
|
|
10
|
+
import * as Json from '../Json/Json.js'
|
|
11
|
+
import * as SplitLines from '../SplitLines/SplitLines.js'
|
|
12
|
+
|
|
13
|
+
const getActualPath = (fileUri) => {
|
|
14
|
+
if (fileUri.startsWith('file://')) {
|
|
15
|
+
return fileURLToPath(fileUri)
|
|
16
|
+
}
|
|
17
|
+
return fileUri
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const RE_MODULE_NOT_FOUND_STACK = /Cannot find package '([^']+)' imported from (.+)$/
|
|
21
|
+
|
|
22
|
+
const prepareModuleNotFoundError = (error) => {
|
|
23
|
+
const { message } = error
|
|
24
|
+
const match = message.match(RE_MODULE_NOT_FOUND_STACK)
|
|
25
|
+
if (!match) {
|
|
26
|
+
return {
|
|
27
|
+
message,
|
|
28
|
+
stack: error.stack,
|
|
29
|
+
codeFrame: '',
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const notFoundModule = match[1]
|
|
33
|
+
const importedFrom = match[2]
|
|
34
|
+
const rawLines = readFileSync(importedFrom, EncodingType.Utf8)
|
|
35
|
+
let line = 0
|
|
36
|
+
let column = 0
|
|
37
|
+
const splittedLines = SplitLines.splitLines(rawLines)
|
|
38
|
+
for (let i = 0; i < splittedLines.length; i++) {
|
|
39
|
+
const splittedLine = splittedLines[i]
|
|
40
|
+
const index = splittedLine.indexOf(notFoundModule)
|
|
41
|
+
if (index !== -1) {
|
|
42
|
+
line = i + 1
|
|
43
|
+
column = index
|
|
44
|
+
break
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const location = {
|
|
48
|
+
start: {
|
|
49
|
+
line,
|
|
50
|
+
column,
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
const codeFrame = codeFrameColumns(rawLines, location)
|
|
54
|
+
const stackLines = SplitLines.splitLines(error.stack)
|
|
55
|
+
const newStackLines = [stackLines[0], ` at ${importedFrom}:${line}:${column}`, ...stackLines.slice(1)]
|
|
56
|
+
const newStack = JoinLines.joinLines(newStackLines)
|
|
57
|
+
return {
|
|
58
|
+
message,
|
|
59
|
+
stack: newStack,
|
|
60
|
+
codeFrame,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const getStackLinesToCut = (error) => {
|
|
65
|
+
if (error instanceof AssertionError) {
|
|
66
|
+
return 1
|
|
67
|
+
}
|
|
68
|
+
return 0
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const prepare = (error) => {
|
|
72
|
+
if (error && error.code === ErrorCodes.ERR_MODULE_NOT_FOUND) {
|
|
73
|
+
return prepareModuleNotFoundError(error)
|
|
74
|
+
}
|
|
75
|
+
const { message } = error
|
|
76
|
+
if (error && error.cause) {
|
|
77
|
+
const cause = error.cause()
|
|
78
|
+
if (cause) {
|
|
79
|
+
error = cause
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const linesToCut = getStackLinesToCut(error)
|
|
83
|
+
const lines = CleanStack.cleanStack(error.stack).slice(linesToCut)
|
|
84
|
+
const file = lines[0]
|
|
85
|
+
let codeFrame = ''
|
|
86
|
+
if (error.codeFrame) {
|
|
87
|
+
codeFrame = error.codeFrame
|
|
88
|
+
} else if (file) {
|
|
89
|
+
let match = file.match(/\((.*):(\d+):(\d+)\)$/)
|
|
90
|
+
if (!match) {
|
|
91
|
+
match = file.match(/at (.*):(\d+):(\d+)$/)
|
|
92
|
+
}
|
|
93
|
+
if (match) {
|
|
94
|
+
const [_, path, line, column] = match
|
|
95
|
+
const actualPath = getActualPath(path)
|
|
96
|
+
const rawLines = readFileSync(actualPath, EncodingType.Utf8)
|
|
97
|
+
const location = {
|
|
98
|
+
start: {
|
|
99
|
+
line: Number.parseInt(line),
|
|
100
|
+
column: Number.parseInt(column),
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
codeFrame = codeFrameColumns(rawLines, location)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const relevantStack = JoinLines.joinLines(lines)
|
|
107
|
+
return {
|
|
108
|
+
message,
|
|
109
|
+
stack: relevantStack,
|
|
110
|
+
codeFrame,
|
|
111
|
+
type: error.constructor.name,
|
|
112
|
+
code: error.code,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const fixBackslashes = (string) => {
|
|
117
|
+
return string.replaceAll('\\\\', '\\')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const prepareJsonError = (json, property, message) => {
|
|
121
|
+
const string = fixBackslashes(Json.stringify(json))
|
|
122
|
+
const stringifiedPropertyName = `"${property}"`
|
|
123
|
+
const index = string.indexOf(stringifiedPropertyName) // TODO this could be wrong in some cases, find a better way
|
|
124
|
+
console.log({ string, index })
|
|
125
|
+
const jsonError = {
|
|
126
|
+
stack: '',
|
|
127
|
+
}
|
|
128
|
+
if (index !== -1) {
|
|
129
|
+
const lines = new LinesAndColumns(string)
|
|
130
|
+
const location = lines.locationForIndex(index + stringifiedPropertyName.length + 1)
|
|
131
|
+
const codeFrame = codeFrameColumns(string, {
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
start: { line: location.line + 1, column: location.column + 1 },
|
|
134
|
+
})
|
|
135
|
+
jsonError.codeFrame = codeFrame
|
|
136
|
+
}
|
|
137
|
+
// jsonError.stack = `${bottomMessage}\n at ${filePath}`
|
|
138
|
+
return jsonError
|
|
139
|
+
}
|
package/src/parts/Pty/Pty.js
CHANGED
|
@@ -1,48 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as Platform from '../Platform/Platform.js'
|
|
3
|
-
import * as Assert from '../Assert/Assert.js'
|
|
4
|
-
|
|
5
|
-
const getSpawnOptions = () => {
|
|
6
|
-
if (Platform.isWindows) {
|
|
7
|
-
return {
|
|
8
|
-
command: 'powershell.exe',
|
|
9
|
-
args: [],
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
return {
|
|
13
|
-
command: 'bash',
|
|
14
|
-
args: ['-i'],
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const create = ({ env = {}, cwd } = {}) => {
|
|
19
|
-
const spawnOptions = getSpawnOptions()
|
|
20
|
-
const pty = spawn(spawnOptions.command, spawnOptions.args, {
|
|
21
|
-
encoding: null,
|
|
22
|
-
cwd,
|
|
23
|
-
// cols: 10,
|
|
24
|
-
// rows: 10,
|
|
25
|
-
})
|
|
26
|
-
return pty
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const onData = (pty, fn) => {
|
|
30
|
-
Assert.object(pty)
|
|
31
|
-
pty.onData(fn)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export const write = (pty, data) => {
|
|
35
|
-
Assert.object(pty)
|
|
36
|
-
pty.write(data)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const resize = (pty, columns, rows) => {
|
|
40
|
-
Assert.object(pty)
|
|
41
|
-
Assert.number(columns)
|
|
42
|
-
Assert.number(rows)
|
|
43
|
-
pty.resize(columns, rows)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export const dispose = (pty) => {
|
|
47
|
-
pty.kill()
|
|
48
|
-
}
|
|
1
|
+
export * from '../NodePty/NodePty.js'
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import * as Pty from '../Pty/Pty.js'
|
|
2
2
|
import * as Debug from '../Debug/Debug.js'
|
|
3
|
+
import * as Assert from '../Assert/Assert.js'
|
|
3
4
|
|
|
4
5
|
export const state = {
|
|
5
6
|
ptyMap: Object.create(null),
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
// TODO maybe merge pty and pty controller
|
|
9
|
-
export const create = (id, cwd) => {
|
|
10
|
+
export const create = (id, cwd, ipc) => {
|
|
11
|
+
Assert.number(id)
|
|
12
|
+
Assert.string(cwd)
|
|
13
|
+
Assert.object(ipc)
|
|
10
14
|
Debug.debug(`create ${id} ${cwd}`)
|
|
11
15
|
const pty = Pty.create({ cwd })
|
|
12
16
|
const handleData = (data) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
})
|
|
19
|
-
}
|
|
17
|
+
ipc.send({
|
|
18
|
+
jsonrpc: '2.0',
|
|
19
|
+
method: 'Viewlet.send',
|
|
20
|
+
params: [id, 'handleData', data],
|
|
21
|
+
})
|
|
20
22
|
}
|
|
21
23
|
Pty.onData(pty, handleData)
|
|
22
24
|
state.ptyMap[id] = pty
|
|
@@ -24,11 +26,18 @@ export const create = (id, cwd) => {
|
|
|
24
26
|
|
|
25
27
|
export const write = (id, data) => {
|
|
26
28
|
const pty = state.ptyMap[id]
|
|
29
|
+
if (!pty) {
|
|
30
|
+
throw new Error(`pty ${id} not found`)
|
|
31
|
+
}
|
|
27
32
|
Pty.write(pty, data)
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
export const dispose = (id) => {
|
|
31
|
-
const
|
|
36
|
+
const { ptyMap } = state
|
|
37
|
+
const pty = ptyMap[id]
|
|
38
|
+
if (!pty) {
|
|
39
|
+
throw new Error(`pty ${id} not found`)
|
|
40
|
+
}
|
|
32
41
|
Pty.dispose(pty)
|
|
33
42
|
delete state.ptyMap[id]
|
|
34
43
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer'
|
|
2
|
+
import * as _ws from 'ws'
|
|
3
|
+
|
|
4
|
+
// workaround for jest or node bug
|
|
5
|
+
const WebSocketServer = _ws.WebSocketServer
|
|
6
|
+
? _ws.WebSocketServer
|
|
7
|
+
: // @ts-ignore
|
|
8
|
+
_ws.default.WebSocketServer
|
|
9
|
+
|
|
10
|
+
const webSocketServer = new WebSocketServer({
|
|
11
|
+
noServer: true,
|
|
12
|
+
|
|
13
|
+
// TODO not sure if ws compress is working at all
|
|
14
|
+
// perMessageDeflate: true
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export const handleUpgrade = (request, socket) => {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const upgradeCallback = (ws) => {
|
|
20
|
+
resolve(ws)
|
|
21
|
+
}
|
|
22
|
+
webSocketServer.handleUpgrade(request, socket, Buffer.alloc(0), upgradeCallback)
|
|
23
|
+
})
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import('./ptyHostMain.js')
|
package/src/ptyHostMain.js
CHANGED
|
@@ -1,26 +1,7 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import * as IpcChild from './parts/IpcChild/IpcChild.js'
|
|
3
|
-
import * as IpcChildType from './parts/IpcChildType/IpcChildType.js'
|
|
4
|
-
import * as PtyController from './parts/PtyController/PtyController.js'
|
|
5
|
-
|
|
6
|
-
const handleMessage = (message) => {
|
|
7
|
-
switch (message.method) {
|
|
8
|
-
case 'Terminal.create':
|
|
9
|
-
Debug.debug('create terminal')
|
|
10
|
-
PtyController.create(...message.params)
|
|
11
|
-
break
|
|
12
|
-
case 'Terminal.write':
|
|
13
|
-
PtyController.write(...message.params)
|
|
14
|
-
break
|
|
15
|
-
default:
|
|
16
|
-
console.warn('unknown message', message)
|
|
17
|
-
break
|
|
18
|
-
}
|
|
19
|
-
}
|
|
1
|
+
import * as Main from './parts/Main/Main.js'
|
|
20
2
|
|
|
21
3
|
const main = async () => {
|
|
22
|
-
|
|
23
|
-
ipc.on('message', handleMessage)
|
|
4
|
+
await Main.main()
|
|
24
5
|
}
|
|
25
6
|
|
|
26
7
|
main()
|