From 0fe8f046faafdacfd0d91c98c8a9c548aed34b41 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Thu, 24 Oct 2024 14:10:51 -0700 Subject: [PATCH] address review comments (#50) --- index.d.ts | 32 +++--- index.js | 265 +++++++++++++++++++++++++------------------------ package.json | 2 +- tsup.config.ts | 16 +-- wrapper.ts | 20 ++-- 5 files changed, 176 insertions(+), 159 deletions(-) diff --git a/index.d.ts b/index.d.ts index 544fd76..5aeee45 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5,40 +5,40 @@ /** The options that can be passed to the constructor of Pty. */ export interface PtyOptions { - command: string - args?: Array - envs?: Record - dir?: string - size?: Size - cgroupPath?: string - interactive?: boolean - onExit: (err: null | Error, exitCode: number) => void + command: string; + args?: Array; + envs?: Record; + dir?: string; + size?: Size; + cgroupPath?: string; + interactive?: boolean; + onExit: (err: null | Error, exitCode: number) => void; } /** A size struct to pass to resize. */ export interface Size { - cols: number - rows: number + cols: number; + rows: number; } /** Resize the terminal. */ -export function ptyResize(fd: number, size: Size): void +export function ptyResize(fd: number, size: Size): void; /** * Set the close-on-exec flag on a file descriptor. This is `fcntl(fd, F_SETFD, FD_CLOEXEC)` under * the covers. */ -export function setCloseOnExec(fd: number, closeOnExec: boolean): void +export function setCloseOnExec(fd: number, closeOnExec: boolean): void; /** * Get the close-on-exec flag on a file descriptor. This is `fcntl(fd, F_GETFD) & FD_CLOEXEC == *_CLOEXEC` under the covers. */ -export function getCloseOnExec(fd: number): boolean +export function getCloseOnExec(fd: number): boolean; export class Pty { /** The pid of the forked process. */ - pid: number - constructor(opts: PtyOptions) + pid: number; + constructor(opts: PtyOptions); /** * Transfers ownership of the file descriptor for the PTY controller. This can only be called * once (it will error the second time). The caller is responsible for closing the file * descriptor. */ - takeFd(): c_int + takeFd(): c_int; } diff --git a/index.js b/index.js index 0714276..824d2fb 100644 --- a/index.js +++ b/index.js @@ -5,28 +5,31 @@ /* auto-generated by NAPI-RS */ const { existsSync, readFileSync } = require('fs') -const { join } = require('path') -const { createRequire } = require('node:module') -require = createRequire(__filename) +const { join } = require('path'); +const { createRequire } = require('node:module'); +require = createRequire(__filename); -const { platform, arch } = process +const { platform, arch } = process; -let nativeBinding = null -let localFileExisted = false -let loadError = null +let nativeBinding = null; +let localFileExisted = false; +let loadError = null; function isMusl() { // For Node 10 if (!process.report || typeof process.report.getReport !== 'function') { try { - const lddPath = require('child_process').execSync('which ldd').toString().trim() - return readFileSync(lddPath, 'utf8').includes('musl') + const lddPath = require('child_process') + .execSync('which ldd') + .toString() + .trim(); + return readFileSync(lddPath, 'utf8').includes('musl'); } catch (e) { - return true + return true; } } else { - const { glibcVersionRuntime } = process.report.getReport().header - return !glibcVersionRuntime + const { glibcVersionRuntime } = process.report.getReport().header; + return !glibcVersionRuntime; } } @@ -34,287 +37,295 @@ switch (platform) { case 'android': switch (arch) { case 'arm64': - localFileExisted = existsSync(join(__dirname, 'ruspty.android-arm64.node')) + localFileExisted = existsSync( + join(__dirname, 'ruspty.android-arm64.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.android-arm64.node') + nativeBinding = require('./ruspty.android-arm64.node'); } else { - nativeBinding = require('@replit/ruspty-android-arm64') + nativeBinding = require('@replit/ruspty-android-arm64'); } } catch (e) { - loadError = e + loadError = e; } - break + break; case 'arm': - localFileExisted = existsSync(join(__dirname, 'ruspty.android-arm-eabi.node')) + localFileExisted = existsSync( + join(__dirname, 'ruspty.android-arm-eabi.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.android-arm-eabi.node') + nativeBinding = require('./ruspty.android-arm-eabi.node'); } else { - nativeBinding = require('@replit/ruspty-android-arm-eabi') + nativeBinding = require('@replit/ruspty-android-arm-eabi'); } } catch (e) { - loadError = e + loadError = e; } - break + break; default: - throw new Error(`Unsupported architecture on Android ${arch}`) + throw new Error(`Unsupported architecture on Android ${arch}`); } - break + break; case 'win32': switch (arch) { case 'x64': localFileExisted = existsSync( - join(__dirname, 'ruspty.win32-x64-msvc.node') - ) + join(__dirname, 'ruspty.win32-x64-msvc.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.win32-x64-msvc.node') + nativeBinding = require('./ruspty.win32-x64-msvc.node'); } else { - nativeBinding = require('@replit/ruspty-win32-x64-msvc') + nativeBinding = require('@replit/ruspty-win32-x64-msvc'); } } catch (e) { - loadError = e + loadError = e; } - break + break; case 'ia32': localFileExisted = existsSync( - join(__dirname, 'ruspty.win32-ia32-msvc.node') - ) + join(__dirname, 'ruspty.win32-ia32-msvc.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.win32-ia32-msvc.node') + nativeBinding = require('./ruspty.win32-ia32-msvc.node'); } else { - nativeBinding = require('@replit/ruspty-win32-ia32-msvc') + nativeBinding = require('@replit/ruspty-win32-ia32-msvc'); } } catch (e) { - loadError = e + loadError = e; } - break + break; case 'arm64': localFileExisted = existsSync( - join(__dirname, 'ruspty.win32-arm64-msvc.node') - ) + join(__dirname, 'ruspty.win32-arm64-msvc.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.win32-arm64-msvc.node') + nativeBinding = require('./ruspty.win32-arm64-msvc.node'); } else { - nativeBinding = require('@replit/ruspty-win32-arm64-msvc') + nativeBinding = require('@replit/ruspty-win32-arm64-msvc'); } } catch (e) { - loadError = e + loadError = e; } - break + break; default: - throw new Error(`Unsupported architecture on Windows: ${arch}`) + throw new Error(`Unsupported architecture on Windows: ${arch}`); } - break + break; case 'darwin': - localFileExisted = existsSync(join(__dirname, 'ruspty.darwin-universal.node')) + localFileExisted = existsSync( + join(__dirname, 'ruspty.darwin-universal.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.darwin-universal.node') + nativeBinding = require('./ruspty.darwin-universal.node'); } else { - nativeBinding = require('@replit/ruspty-darwin-universal') + nativeBinding = require('@replit/ruspty-darwin-universal'); } - break + break; } catch {} switch (arch) { case 'x64': - localFileExisted = existsSync(join(__dirname, 'ruspty.darwin-x64.node')) + localFileExisted = existsSync( + join(__dirname, 'ruspty.darwin-x64.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.darwin-x64.node') + nativeBinding = require('./ruspty.darwin-x64.node'); } else { - nativeBinding = require('@replit/ruspty-darwin-x64') + nativeBinding = require('@replit/ruspty-darwin-x64'); } } catch (e) { - loadError = e + loadError = e; } - break + break; case 'arm64': localFileExisted = existsSync( - join(__dirname, 'ruspty.darwin-arm64.node') - ) + join(__dirname, 'ruspty.darwin-arm64.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.darwin-arm64.node') + nativeBinding = require('./ruspty.darwin-arm64.node'); } else { - nativeBinding = require('@replit/ruspty-darwin-arm64') + nativeBinding = require('@replit/ruspty-darwin-arm64'); } } catch (e) { - loadError = e + loadError = e; } - break + break; default: - throw new Error(`Unsupported architecture on macOS: ${arch}`) + throw new Error(`Unsupported architecture on macOS: ${arch}`); } - break + break; case 'freebsd': if (arch !== 'x64') { - throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) + throw new Error(`Unsupported architecture on FreeBSD: ${arch}`); } - localFileExisted = existsSync(join(__dirname, 'ruspty.freebsd-x64.node')) + localFileExisted = existsSync(join(__dirname, 'ruspty.freebsd-x64.node')); try { if (localFileExisted) { - nativeBinding = require('./ruspty.freebsd-x64.node') + nativeBinding = require('./ruspty.freebsd-x64.node'); } else { - nativeBinding = require('@replit/ruspty-freebsd-x64') + nativeBinding = require('@replit/ruspty-freebsd-x64'); } } catch (e) { - loadError = e + loadError = e; } - break + break; case 'linux': switch (arch) { case 'x64': if (isMusl()) { localFileExisted = existsSync( - join(__dirname, 'ruspty.linux-x64-musl.node') - ) + join(__dirname, 'ruspty.linux-x64-musl.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.linux-x64-musl.node') + nativeBinding = require('./ruspty.linux-x64-musl.node'); } else { - nativeBinding = require('@replit/ruspty-linux-x64-musl') + nativeBinding = require('@replit/ruspty-linux-x64-musl'); } } catch (e) { - loadError = e + loadError = e; } } else { localFileExisted = existsSync( - join(__dirname, 'ruspty.linux-x64-gnu.node') - ) + join(__dirname, 'ruspty.linux-x64-gnu.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.linux-x64-gnu.node') + nativeBinding = require('./ruspty.linux-x64-gnu.node'); } else { - nativeBinding = require('@replit/ruspty-linux-x64-gnu') + nativeBinding = require('@replit/ruspty-linux-x64-gnu'); } } catch (e) { - loadError = e + loadError = e; } } - break + break; case 'arm64': if (isMusl()) { localFileExisted = existsSync( - join(__dirname, 'ruspty.linux-arm64-musl.node') - ) + join(__dirname, 'ruspty.linux-arm64-musl.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.linux-arm64-musl.node') + nativeBinding = require('./ruspty.linux-arm64-musl.node'); } else { - nativeBinding = require('@replit/ruspty-linux-arm64-musl') + nativeBinding = require('@replit/ruspty-linux-arm64-musl'); } } catch (e) { - loadError = e + loadError = e; } } else { localFileExisted = existsSync( - join(__dirname, 'ruspty.linux-arm64-gnu.node') - ) + join(__dirname, 'ruspty.linux-arm64-gnu.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.linux-arm64-gnu.node') + nativeBinding = require('./ruspty.linux-arm64-gnu.node'); } else { - nativeBinding = require('@replit/ruspty-linux-arm64-gnu') + nativeBinding = require('@replit/ruspty-linux-arm64-gnu'); } } catch (e) { - loadError = e + loadError = e; } } - break + break; case 'arm': if (isMusl()) { localFileExisted = existsSync( - join(__dirname, 'ruspty.linux-arm-musleabihf.node') - ) + join(__dirname, 'ruspty.linux-arm-musleabihf.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.linux-arm-musleabihf.node') + nativeBinding = require('./ruspty.linux-arm-musleabihf.node'); } else { - nativeBinding = require('@replit/ruspty-linux-arm-musleabihf') + nativeBinding = require('@replit/ruspty-linux-arm-musleabihf'); } } catch (e) { - loadError = e + loadError = e; } } else { localFileExisted = existsSync( - join(__dirname, 'ruspty.linux-arm-gnueabihf.node') - ) + join(__dirname, 'ruspty.linux-arm-gnueabihf.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.linux-arm-gnueabihf.node') + nativeBinding = require('./ruspty.linux-arm-gnueabihf.node'); } else { - nativeBinding = require('@replit/ruspty-linux-arm-gnueabihf') + nativeBinding = require('@replit/ruspty-linux-arm-gnueabihf'); } } catch (e) { - loadError = e + loadError = e; } } - break + break; case 'riscv64': if (isMusl()) { localFileExisted = existsSync( - join(__dirname, 'ruspty.linux-riscv64-musl.node') - ) + join(__dirname, 'ruspty.linux-riscv64-musl.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.linux-riscv64-musl.node') + nativeBinding = require('./ruspty.linux-riscv64-musl.node'); } else { - nativeBinding = require('@replit/ruspty-linux-riscv64-musl') + nativeBinding = require('@replit/ruspty-linux-riscv64-musl'); } } catch (e) { - loadError = e + loadError = e; } } else { localFileExisted = existsSync( - join(__dirname, 'ruspty.linux-riscv64-gnu.node') - ) + join(__dirname, 'ruspty.linux-riscv64-gnu.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.linux-riscv64-gnu.node') + nativeBinding = require('./ruspty.linux-riscv64-gnu.node'); } else { - nativeBinding = require('@replit/ruspty-linux-riscv64-gnu') + nativeBinding = require('@replit/ruspty-linux-riscv64-gnu'); } } catch (e) { - loadError = e + loadError = e; } } - break + break; case 's390x': localFileExisted = existsSync( - join(__dirname, 'ruspty.linux-s390x-gnu.node') - ) + join(__dirname, 'ruspty.linux-s390x-gnu.node'), + ); try { if (localFileExisted) { - nativeBinding = require('./ruspty.linux-s390x-gnu.node') + nativeBinding = require('./ruspty.linux-s390x-gnu.node'); } else { - nativeBinding = require('@replit/ruspty-linux-s390x-gnu') + nativeBinding = require('@replit/ruspty-linux-s390x-gnu'); } } catch (e) { - loadError = e + loadError = e; } - break + break; default: - throw new Error(`Unsupported architecture on Linux: ${arch}`) + throw new Error(`Unsupported architecture on Linux: ${arch}`); } - break + break; default: - throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) + throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`); } if (!nativeBinding) { if (loadError) { - throw loadError + throw loadError; } - throw new Error(`Failed to load native binding`) + throw new Error(`Failed to load native binding`); } -const { Pty, ptyResize, setCloseOnExec, getCloseOnExec } = nativeBinding +const { Pty, ptyResize, setCloseOnExec, getCloseOnExec } = nativeBinding; -module.exports.Pty = Pty -module.exports.ptyResize = ptyResize -module.exports.setCloseOnExec = setCloseOnExec -module.exports.getCloseOnExec = getCloseOnExec +module.exports.Pty = Pty; +module.exports.ptyResize = ptyResize; +module.exports.setCloseOnExec = setCloseOnExec; +module.exports.getCloseOnExec = getCloseOnExec; diff --git a/package.json b/package.json index 3687761..2f1b96c 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,6 @@ "universal": "napi universal", "version": "napi version", "release": "npm publish --access public", - "format": "npx prettier *.ts,*.js --write" + "format": "npx prettier *.{js,ts} --write" } } diff --git a/tsup.config.ts b/tsup.config.ts index 63be051..dccc3ca 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -1,18 +1,18 @@ -import { defineConfig } from 'tsup' -import { platformArchTriples } from '@napi-rs/triples' +import { defineConfig } from 'tsup'; +import { platformArchTriples } from '@napi-rs/triples'; -const triples: string[] = [] +const triples: string[] = []; for (const platform in platformArchTriples) { for (const arch in platformArchTriples[platform]) { for (const triple of platformArchTriples[platform][arch]) { - triples.push(triple.platformArchABI) + triples.push(triple.platformArchABI); } } } // they somehow forgot these -triples.push('darwin-universal') -triples.push('linux-riscv64-musl') +triples.push('darwin-universal'); +triples.push('linux-riscv64-musl'); export default defineConfig({ entry: ['wrapper.ts'], @@ -21,5 +21,5 @@ export default defineConfig({ dts: true, sourcemap: true, clean: true, - external: triples.map(triple => `./ruspty.${triple}.node`) -}) + external: triples.map((triple) => `./ruspty.${triple}.node`), +}); diff --git a/wrapper.ts b/wrapper.ts index 31e4484..e47f63f 100644 --- a/wrapper.ts +++ b/wrapper.ts @@ -50,11 +50,15 @@ export class Pty { #handledEndOfData: boolean = false; #socket: ReadStream; + #writable: Writable; + get read(): Readable { return this.#socket; } - write: Writable; + get write(): Writable { + return this.#writable; + } constructor(options: PtyOptions) { const realExit = options.onExit; @@ -79,8 +83,8 @@ export class Pty { // Transfer ownership of the FD to us. this.#fd = this.#pty.takeFd(); - this.#socket = new ReadStream(this.#fd) - this.write = new Writable({ + this.#socket = new ReadStream(this.#fd); + this.#writable = new Writable({ write: this.#socket.write.bind(this.#socket), }); @@ -95,8 +99,8 @@ export class Pty { // must wait for fd close and exit result before calling real exit await fdClosed; const result = await exitResult; - realExit(result.error, result.code) - } + realExit(result.error, result.code); + }; this.read.on('end', handleEnd); this.read.on('close', () => { @@ -114,8 +118,7 @@ export class Pty { // syscall due to it being interrupted by another syscall, and EAGAIN happens when there // is no more data to be read by the fd. return; - } - if (code.indexOf('EIO') !== -1) { + } else if (code.indexOf('EIO') !== -1) { // EIO only happens when the child dies. It is therefore our only true signal that there // is nothing left to read and we can start tearing things down. If we hadn't received an // error so far, we are considered to be in good standing. @@ -124,6 +127,9 @@ export class Pty { return; } } + + // if we haven't handled the error by now, we should throw it + throw err; }; this.read.on('error', handleError);