summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDivy Srivastava <dj.srivastava23@gmail.com>2023-10-30 08:53:08 -0700
committerGitHub <noreply@github.com>2023-10-30 15:53:08 +0000
commit09204107d85351dae07a45f6a9684b5b6e573652 (patch)
tree5a04f3a877e677e382e34684784ddf832838bd77
parent1acef755ca8a0a0433a98e4a66433c63ee0a3b09 (diff)
fix: implement node:tty (#20892)
Fixes #21012 Closes https://github.com/denoland/deno/issues/20855 Fixes https://github.com/denoland/deno/issues/20890 Fixes https://github.com/denoland/deno/issues/20611 Fixes https://github.com/denoland/deno/issues/20336 Fixes `create-svelte` from https://github.com/denoland/deno/issues/17248 Fixes more reports here: - https://github.com/denoland/deno/issues/6529#issuecomment-1432690559 - https://github.com/denoland/deno/issues/6529#issuecomment-1522059006 - https://github.com/denoland/deno/issues/6529#issuecomment-1695803570
-rw-r--r--cli/main.rs1
-rw-r--r--cli/tests/node_compat/config.jsonc2
-rw-r--r--cli/tests/node_compat/test/parallel/test-tty-stdin-end.js14
-rw-r--r--cli/tests/node_compat/test/parallel/test-ttywrap-invalid-fd.js74
-rw-r--r--cli/util/unix.rs24
-rw-r--r--ext/node/lib.rs3
-rw-r--r--ext/node/ops/mod.rs1
-rw-r--r--ext/node/ops/util.rs83
-rw-r--r--ext/node/polyfills/_process/streams.mjs74
-rw-r--r--ext/node/polyfills/internal_binding/util.ts9
-rw-r--r--ext/node/polyfills/process.ts106
-rw-r--r--ext/node/polyfills/tty.js83
-rw-r--r--ext/node/polyfills/tty.ts25
-rw-r--r--tools/node_compat/TODO.md3
14 files changed, 325 insertions, 177 deletions
diff --git a/cli/main.rs b/cli/main.rs
index 0817c0984..dbd3b470b 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -272,6 +272,7 @@ pub(crate) fn unstable_warn_cb(feature: &str) {
pub fn main() {
setup_panic_hook();
+ util::unix::prepare_stdio();
util::unix::raise_fd_limit();
util::windows::ensure_stdio_open();
#[cfg(windows)]
diff --git a/cli/tests/node_compat/config.jsonc b/cli/tests/node_compat/config.jsonc
index 8a31f4dc2..93a51b671 100644
--- a/cli/tests/node_compat/config.jsonc
+++ b/cli/tests/node_compat/config.jsonc
@@ -88,6 +88,7 @@
"test-querystring.js",
"test-readline-interface.js",
"test-stdin-from-file-spawn.js",
+ "test-ttywrap-invalid-fd.js",
"test-url-urltooptions.js",
"test-util-format.js",
"test-util-inspect-namespace.js",
@@ -625,6 +626,7 @@
"test-timers-unref-throw-then-ref.js",
"test-timers-user-call.js",
"test-timers-zero-timeout.js",
+ "test-tty-stdin-end.js",
"test-url-domain-ascii-unicode.js",
"test-url-fileurltopath.js",
"test-url-format-invalid-input.js",
diff --git a/cli/tests/node_compat/test/parallel/test-tty-stdin-end.js b/cli/tests/node_compat/test/parallel/test-tty-stdin-end.js
new file mode 100644
index 000000000..ee38cbd2c
--- /dev/null
+++ b/cli/tests/node_compat/test/parallel/test-tty-stdin-end.js
@@ -0,0 +1,14 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test ensures that Node.js doesn't crash on `process.stdin.emit("end")`.
+// https://github.com/nodejs/node/issues/1068
+
+process.stdin.emit('end');
diff --git a/cli/tests/node_compat/test/parallel/test-ttywrap-invalid-fd.js b/cli/tests/node_compat/test/parallel/test-ttywrap-invalid-fd.js
new file mode 100644
index 000000000..95b9bffe6
--- /dev/null
+++ b/cli/tests/node_compat/test/parallel/test-ttywrap-invalid-fd.js
@@ -0,0 +1,74 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+
+// const common = require('../common');
+const tty = require('tty');
+// const { internalBinding } = require('internal/test/binding');
+// const {
+// UV_EBADF,
+// UV_EINVAL
+// } = internalBinding('uv');
+const assert = require('assert');
+
+assert.throws(
+ () => new tty.WriteStream(-1),
+ {
+ code: 'ERR_INVALID_FD',
+ name: 'RangeError',
+ message: '"fd" must be a positive integer: -1'
+ }
+);
+
+// {
+// const info = {
+// code: common.isWindows ? 'EBADF' : 'EINVAL',
+// message: common.isWindows ? 'bad file descriptor' : 'invalid argument',
+// errno: common.isWindows ? UV_EBADF : UV_EINVAL,
+// syscall: 'uv_tty_init'
+// };
+
+// const suffix = common.isWindows ?
+// 'EBADF (bad file descriptor)' : 'EINVAL (invalid argument)';
+// const message = `TTY initialization failed: uv_tty_init returned ${suffix}`;
+
+// assert.throws(
+// () => {
+// common.runWithInvalidFD((fd) => {
+// new tty.WriteStream(fd);
+// });
+// }, {
+// code: 'ERR_TTY_INIT_FAILED',
+// name: 'SystemError',
+// message,
+// info
+// }
+// );
+
+// assert.throws(
+// () => {
+// common.runWithInvalidFD((fd) => {
+// new tty.ReadStream(fd);
+// });
+// }, {
+// code: 'ERR_TTY_INIT_FAILED',
+// name: 'SystemError',
+// message,
+// info
+// });
+// }
+
+assert.throws(
+ () => new tty.ReadStream(-1),
+ {
+ code: 'ERR_INVALID_FD',
+ name: 'RangeError',
+ message: '"fd" must be a positive integer: -1'
+ }
+);
diff --git a/cli/util/unix.rs b/cli/util/unix.rs
index fd0c94ea6..2fa3c2063 100644
--- a/cli/util/unix.rs
+++ b/cli/util/unix.rs
@@ -43,3 +43,27 @@ pub fn raise_fd_limit() {
}
}
}
+
+pub fn prepare_stdio() {
+ #[cfg(unix)]
+ // SAFETY: Save current state of stdio and restore it when we exit.
+ unsafe {
+ use libc::atexit;
+ use libc::tcgetattr;
+ use libc::tcsetattr;
+ use libc::termios;
+
+ let mut termios = std::mem::zeroed::<termios>();
+ if tcgetattr(libc::STDIN_FILENO, &mut termios) == 0 {
+ static mut ORIG_TERMIOS: Option<termios> = None;
+ ORIG_TERMIOS = Some(termios);
+
+ extern "C" fn reset_stdio() {
+ // SAFETY: Reset the stdio state.
+ unsafe { tcsetattr(libc::STDIN_FILENO, 0, &ORIG_TERMIOS.unwrap()) };
+ }
+
+ atexit(reset_stdio);
+ }
+ }
+}
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index 6d7e85ec4..730554f2d 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -270,6 +270,7 @@ deno_core::extension!(deno_node,
ops::require::op_require_read_package_scope<P>,
ops::require::op_require_package_imports_resolve<P>,
ops::require::op_require_break_on_next_statement,
+ ops::util::op_node_guess_handle_type,
],
esm_entry_point = "ext:deno_node/02_init.js",
esm = [
@@ -490,7 +491,7 @@ deno_core::extension!(deno_node,
"timers.ts" with_specifier "node:timers",
"timers/promises.ts" with_specifier "node:timers/promises",
"tls.ts" with_specifier "node:tls",
- "tty.ts" with_specifier "node:tty",
+ "tty.js" with_specifier "node:tty",
"url.ts" with_specifier "node:url",
"util.ts" with_specifier "node:util",
"util/types.ts" with_specifier "node:util/types",
diff --git a/ext/node/ops/mod.rs b/ext/node/ops/mod.rs
index cf4abf3dd..d1bb4b7f4 100644
--- a/ext/node/ops/mod.rs
+++ b/ext/node/ops/mod.rs
@@ -6,6 +6,7 @@ pub mod http2;
pub mod idna;
pub mod os;
pub mod require;
+pub mod util;
pub mod v8;
pub mod winerror;
pub mod zlib;
diff --git a/ext/node/ops/util.rs b/ext/node/ops/util.rs
new file mode 100644
index 000000000..1cb80e0e3
--- /dev/null
+++ b/ext/node/ops/util.rs
@@ -0,0 +1,83 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+use deno_core::error::AnyError;
+use deno_core::op2;
+use deno_core::OpState;
+use deno_core::ResourceHandle;
+use deno_core::ResourceHandleFd;
+
+#[repr(u32)]
+enum HandleType {
+ #[allow(dead_code)]
+ Tcp = 0,
+ Tty,
+ #[allow(dead_code)]
+ Udp,
+ File,
+ Pipe,
+ Unknown,
+}
+
+#[op2(fast)]
+pub fn op_node_guess_handle_type(
+ state: &mut OpState,
+ rid: u32,
+) -> Result<u32, AnyError> {
+ let handle = state.resource_table.get_handle(rid)?;
+
+ let handle_type = match handle {
+ ResourceHandle::Fd(handle) => guess_handle_type(handle),
+ _ => HandleType::Unknown,
+ };
+
+ Ok(handle_type as u32)
+}
+
+#[cfg(windows)]
+fn guess_handle_type(handle: ResourceHandleFd) -> HandleType {
+ use winapi::um::consoleapi::GetConsoleMode;
+ use winapi::um::fileapi::GetFileType;
+ use winapi::um::winbase::FILE_TYPE_CHAR;
+ use winapi::um::winbase::FILE_TYPE_DISK;
+ use winapi::um::winbase::FILE_TYPE_PIPE;
+
+ // SAFETY: Call to win32 fileapi. `handle` is a valid fd.
+ match unsafe { GetFileType(handle) } {
+ FILE_TYPE_DISK => HandleType::File,
+ FILE_TYPE_CHAR => {
+ let mut mode = 0;
+ // SAFETY: Call to win32 consoleapi. `handle` is a valid fd.
+ // `mode` is a valid pointer.
+ if unsafe { GetConsoleMode(handle, &mut mode) } == 1 {
+ HandleType::Tty
+ } else {
+ HandleType::File
+ }
+ }
+ FILE_TYPE_PIPE => HandleType::Pipe,
+ _ => HandleType::Unknown,
+ }
+}
+
+#[cfg(unix)]
+fn guess_handle_type(handle: ResourceHandleFd) -> HandleType {
+ use std::io::IsTerminal;
+ // SAFETY: The resource remains open for the duration of borrow_raw.
+ if unsafe { std::os::fd::BorrowedFd::borrow_raw(handle).is_terminal() } {
+ return HandleType::Tty;
+ }
+
+ // SAFETY: It is safe to zero-initialize a `libc::stat` struct.
+ let mut s = unsafe { std::mem::zeroed() };
+ // SAFETY: Call to libc
+ if unsafe { libc::fstat(handle, &mut s) } == 1 {
+ return HandleType::Unknown;
+ }
+
+ match s.st_mode & 61440 {
+ libc::S_IFREG | libc::S_IFCHR => HandleType::File,
+ libc::S_IFIFO => HandleType::Pipe,
+ libc::S_IFSOCK => HandleType::Tcp,
+ _ => HandleType::Unknown,
+ }
+}
diff --git a/ext/node/polyfills/_process/streams.mjs b/ext/node/polyfills/_process/streams.mjs
index b6efef65e..39ee89a82 100644
--- a/ext/node/polyfills/_process/streams.mjs
+++ b/ext/node/polyfills/_process/streams.mjs
@@ -12,9 +12,9 @@ import {
moveCursor,
} from "ext:deno_node/internal/readline/callbacks.mjs";
import { Duplex, Readable, Writable } from "node:stream";
-import { isWindows } from "ext:deno_node/_util/os.ts";
-import { fs as fsConstants } from "ext:deno_node/internal_binding/constants.ts";
import * as io from "ext:deno_io/12_io.js";
+import * as tty from "node:tty";
+import { guessHandleType } from "ext:deno_node/internal_binding/util.ts";
// https://github.com/nodejs/node/blob/00738314828074243c9a52a228ab4c68b04259ef/lib/internal/bootstrap/switches/is_main_thread.js#L41
export function createWritableStdioStream(writer, name) {
@@ -95,60 +95,21 @@ export function createWritableStdioStream(writer, name) {
return stream;
}
-// TODO(PolarETech): This function should be replaced by
-// `guessHandleType()` in "../internal_binding/util.ts".
-// https://github.com/nodejs/node/blob/v18.12.1/src/node_util.cc#L257
function _guessStdinType(fd) {
if (typeof fd !== "number" || fd < 0) return "UNKNOWN";
- if (Deno.isatty?.(fd)) return "TTY";
-
- try {
- const fileInfo = Deno.fstatSync?.(fd);
-
- // https://github.com/nodejs/node/blob/v18.12.1/deps/uv/src/unix/tty.c#L333
- if (!isWindows) {
- switch (fileInfo.mode & fsConstants.S_IFMT) {
- case fsConstants.S_IFREG:
- case fsConstants.S_IFCHR:
- return "FILE";
- case fsConstants.S_IFIFO:
- return "PIPE";
- case fsConstants.S_IFSOCK:
- // TODO(PolarETech): Need a better way to identify "TCP".
- // Currently, unable to exclude UDP.
- return "TCP";
- default:
- return "UNKNOWN";
- }
- }
-
- // https://github.com/nodejs/node/blob/v18.12.1/deps/uv/src/win/handle.c#L31
- if (fileInfo.isFile) {
- // TODO(PolarETech): Need a better way to identify a piped stdin on Windows.
- // On Windows, `Deno.fstatSync(rid).isFile` returns true even for a piped stdin.
- // Therefore, a piped stdin cannot be distinguished from a file by this property.
- // The mtime, atime, and birthtime of the file are "2339-01-01T00:00:00.000Z",
- // so use the property as a workaround.
- if (fileInfo.birthtime.valueOf() === 11644473600000) return "PIPE";
- return "FILE";
- }
- } catch (e) {
- // TODO(PolarETech): Need a better way to identify a character file on Windows.
- // "EISDIR" error occurs when stdin is "null" on Windows,
- // so use the error as a workaround.
- if (isWindows && e.code === "EISDIR") return "FILE";
- }
-
- return "UNKNOWN";
+ return guessHandleType(fd);
}
const _read = function (size) {
const p = Buffer.alloc(size || 16 * 1024);
- io.stdin?.read(p).then((length) => {
- this.push(length === null ? null : p.slice(0, length));
- }, (error) => {
- this.destroy(error);
- });
+ io.stdin?.read(p).then(
+ (length) => {
+ this.push(length === null ? null : p.slice(0, length));
+ },
+ (error) => {
+ this.destroy(error);
+ },
+ );
};
/** https://nodejs.org/api/process.html#process_process_stdin */
@@ -172,17 +133,12 @@ export const initStdin = () => {
});
break;
}
- case "TTY":
+ case "TTY": {
+ stdin = new tty.ReadStream(fd);
+ break;
+ }
case "PIPE":
case "TCP": {
- // TODO(PolarETech):
- // For TTY, `new Duplex()` should be replaced `new tty.ReadStream()` if possible.
- // There are two problems that need to be resolved.
- // 1. Using them here introduces a circular dependency.
- // 2. Creating a tty.ReadStream() is not currently supported.
- // https://github.com/nodejs/node/blob/v18.12.1/lib/internal/bootstrap/switches/is_main_thread.js#L194
- // https://github.com/nodejs/node/blob/v18.12.1/lib/tty.js#L47
-
// For PIPE and TCP, `new Duplex()` should be replaced `new net.Socket()` if possible.
// There are two problems that need to be resolved.
// 1. Using them here introduces a circular dependency.
diff --git a/ext/node/polyfills/internal_binding/util.ts b/ext/node/polyfills/internal_binding/util.ts
index a2d355c1e..38eeebee0 100644
--- a/ext/node/polyfills/internal_binding/util.ts
+++ b/ext/node/polyfills/internal_binding/util.ts
@@ -28,10 +28,13 @@
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
-import { notImplemented } from "ext:deno_node/_utils.ts";
+const core = globalThis.Deno.core;
+const ops = core.ops;
-export function guessHandleType(_fd: number): string {
- notImplemented("util.guessHandleType");
+const handleTypes = ["TCP", "TTY", "UDP", "FILE", "PIPE", "UNKNOWN"];
+export function guessHandleType(fd: number): string {
+ const type = ops.op_node_guess_handle_type(fd);
+ return handleTypes[type];
}
export const ALL_PROPERTIES = 0;
diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts
index 618f92d3f..a4fc3317d 100644
--- a/ext/node/polyfills/process.ts
+++ b/ext/node/polyfills/process.ts
@@ -33,8 +33,6 @@ export { _nextTick as nextTick, chdir, cwd, env, version, versions };
import {
createWritableStdioStream,
initStdin,
- Readable,
- Writable,
} from "ext:deno_node/_process/streams.mjs";
import {
enableNextTick,
@@ -57,41 +55,9 @@ export let platform = "";
// TODO(kt3k): This should be set at start up time
export let pid = 0;
-// We want streams to be as lazy as possible, but we cannot export a getter in a module. To
-// work around this we make these proxies that eagerly instantiate the underlying object on
-// first access of any property/method.
-function makeLazyStream<T>(objectFactory: () => T): T {
- return new Proxy({}, {
- get: function (_, prop, receiver) {
- // deno-lint-ignore no-explicit-any
- return Reflect.get(objectFactory() as any, prop, receiver);
- },
- has: function (_, prop) {
- // deno-lint-ignore no-explicit-any
- return Reflect.has(objectFactory() as any, prop);
- },
- ownKeys: function (_) {
- // deno-lint-ignore no-explicit-any
- return Reflect.ownKeys(objectFactory() as any);
- },
- set: function (_, prop, value, receiver) {
- // deno-lint-ignore no-explicit-any
- return Reflect.set(objectFactory() as any, prop, value, receiver);
- },
- getPrototypeOf: function (_) {
- // deno-lint-ignore no-explicit-any
- return Reflect.getPrototypeOf(objectFactory() as any);
- },
- getOwnPropertyDescriptor(_, prop) {
- // deno-lint-ignore no-explicit-any
- return Reflect.getOwnPropertyDescriptor(objectFactory() as any, prop);
- },
- }) as T;
-}
+let stdin, stdout, stderr;
-export let stderr = makeLazyStream(getStderr);
-export let stdin = makeLazyStream(getStdin);
-export let stdout = makeLazyStream(getStdout);
+export { stderr, stdin, stdout };
import { getBinding } from "ext:deno_node/internal_binding/mod.ts";
import * as constants from "ext:deno_node/internal_binding/constants.ts";
@@ -646,19 +612,13 @@ class Process extends EventEmitter {
memoryUsage = memoryUsage;
/** https://nodejs.org/api/process.html#process_process_stderr */
- get stderr(): Writable {
- return getStderr();
- }
+ stderr = stderr;
/** https://nodejs.org/api/process.html#process_process_stdin */
- get stdin(): Readable {
- return getStdin();
- }
+ stdin = stdin;
/** https://nodejs.org/api/process.html#process_process_stdout */
- get stdout(): Writable {
- return getStdout();
- }
+ stdout = stdout;
/** https://nodejs.org/api/process.html#process_process_version */
version = version;
@@ -906,52 +866,24 @@ internals.__bootstrapNodeProcess = function (
core.setMacrotaskCallback(runNextTicks);
enableNextTick();
+ stdin = process.stdin = initStdin();
+ /** https://nodejs.org/api/process.html#process_process_stdout */
+ stdout = process.stdout = createWritableStdioStream(
+ io.stdout,
+ "stdout",
+ );
+
+ /** https://nodejs.org/api/process.html#process_process_stderr */
+ stderr = process.stderr = createWritableStdioStream(
+ io.stderr,
+ "stderr",
+ );
+
process.setStartTime(Date.now());
+
// @ts-ignore Remove setStartTime and #startTime is not modifiable
delete process.setStartTime;
delete internals.__bootstrapNodeProcess;
};
-// deno-lint-ignore no-explicit-any
-let stderr_ = null as any;
-// deno-lint-ignore no-explicit-any
-let stdin_ = null as any;
-// deno-lint-ignore no-explicit-any
-let stdout_ = null as any;
-
-function getStdin(): Readable {
- if (!stdin_) {
- stdin_ = initStdin();
- stdin = stdin_;
- Object.defineProperty(process, "stdin", { get: () => stdin_ });
- }
- return stdin_;
-}
-
-/** https://nodejs.org/api/process.html#process_process_stdout */
-function getStdout(): Writable {
- if (!stdout_) {
- stdout_ = createWritableStdioStream(
- io.stdout,
- "stdout",
- );
- stdout = stdout_;
- Object.defineProperty(process, "stdout", { get: () => stdout_ });
- }
- return stdout_;
-}
-
-/** https://nodejs.org/api/process.html#process_process_stderr */
-function getStderr(): Writable {
- if (!stderr_) {
- stderr_ = createWritableStdioStream(
- io.stderr,
- "stderr",
- );
- stderr = stderr_;
- Object.defineProperty(process, "stderr", { get: () => stderr_ });
- }
- return stderr_;
-}
-
export default process;
diff --git a/ext/node/polyfills/tty.js b/ext/node/polyfills/tty.js
new file mode 100644
index 000000000..54f8f6eae
--- /dev/null
+++ b/ext/node/polyfills/tty.js
@@ -0,0 +1,83 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+import { ERR_INVALID_FD } from "ext:deno_node/internal/errors.ts";
+import { LibuvStreamWrap } from "ext:deno_node/internal_binding/stream_wrap.ts";
+import { providerType } from "ext:deno_node/internal_binding/async_wrap.ts";
+import { Duplex } from "node:stream";
+const { Error } = globalThis.__bootstrap.primordials;
+
+// Returns true when the given numeric fd is associated with a TTY and false otherwise.
+function isatty(fd) {
+ if (typeof fd !== "number") {
+ return false;
+ }
+ try {
+ return Deno.isatty(fd);
+ } catch (_) {
+ return false;
+ }
+}
+
+class TTY extends LibuvStreamWrap {
+ constructor(handle) {
+ super(providerType.TTYWRAP, handle);
+ }
+}
+
+export class ReadStream extends Duplex {
+ constructor(fd, options) {
+ if (fd >> 0 !== fd || fd < 0) {
+ throw new ERR_INVALID_FD(fd);
+ }
+
+ // We only support `stdin`.
+ if (fd != 0) throw new Error("Only fd 0 is supported.");
+
+ const tty = new TTY(Deno.stdin);
+ super({
+ readableHighWaterMark: 0,
+ handle: tty,
+ manualStart: true,
+ ...options,
+ });
+
+ this.isRaw = false;
+ this.isTTY = true;
+ }
+
+ setRawMode(flag) {
+ flag = !!flag;
+ this._handle.setRaw(flag);
+
+ this.isRaw = flag;
+ return this;
+ }
+}
+
+export class WriteStream extends Duplex {
+ constructor(fd) {
+ if (fd >> 0 !== fd || fd < 0) {
+ throw new ERR_INVALID_FD(fd);
+ }
+
+ // We only support `stdin`, `stdout` and `stderr`.
+ if (fd > 2) throw new Error("Only fd 0, 1 and 2 are supported.");
+
+ const tty = new TTY(
+ fd === 0 ? Deno.stdin : fd === 1 ? Deno.stdout : Deno.stderr,
+ );
+
+ super({
+ readableHighWaterMark: 0,
+ handle: tty,
+ manualStart: true,
+ });
+
+ const { columns, rows } = Deno.consoleSize();
+ this.columns = columns;
+ this.rows = rows;
+ }
+}
+
+export { isatty };
+export default { isatty, WriteStream, ReadStream };
diff --git a/ext/node/polyfills/tty.ts b/ext/node/polyfills/tty.ts
deleted file mode 100644
index d33f779ca..000000000
--- a/ext/node/polyfills/tty.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-import { Socket } from "node:net";
-
-// Returns true when the given numeric fd is associated with a TTY and false otherwise.
-function isatty(fd: number) {
- if (typeof fd !== "number") {
- return false;
- }
- try {
- return Deno.isatty(fd);
- } catch (_) {
- return false;
- }
-}
-
-// TODO(kt3k): Implement tty.ReadStream class
-export class ReadStream extends Socket {
-}
-// TODO(kt3k): Implement tty.WriteStream class
-export class WriteStream extends Socket {
-}
-
-export { isatty };
-export default { isatty, WriteStream, ReadStream };
diff --git a/tools/node_compat/TODO.md b/tools/node_compat/TODO.md
index 41dfb70b0..b4c971d89 100644
--- a/tools/node_compat/TODO.md
+++ b/tools/node_compat/TODO.md
@@ -3,7 +3,7 @@
NOTE: This file should not be manually edited. Please edit `cli/tests/node_compat/config.json` and run `deno task setup` in `tools/node_compat` dir instead.
-Total: 2924
+Total: 2923
- [abort/test-abort-backtrace.js](https://github.com/nodejs/node/tree/v18.12.1/test/abort/test-abort-backtrace.js)
- [abort/test-abort-fatal-error.js](https://github.com/nodejs/node/tree/v18.12.1/test/abort/test-abort-fatal-error.js)
@@ -2356,7 +2356,6 @@ Total: 2924
- [parallel/test-trace-exit.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-trace-exit.js)
- [parallel/test-tracing-no-crash.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-tracing-no-crash.js)
- [parallel/test-tty-backwards-api.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-tty-backwards-api.js)
-- [parallel/test-tty-stdin-end.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-tty-stdin-end.js)
- [parallel/test-tty-stdin-pipe.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-tty-stdin-pipe.js)
- [parallel/test-ttywrap-invalid-fd.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-ttywrap-invalid-fd.js)
- [parallel/test-ttywrap-stack.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-ttywrap-stack.js)