mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
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
This commit is contained in:
parent
1acef755ca
commit
09204107d8
14 changed files with 325 additions and 177 deletions
|
@ -272,6 +272,7 @@ pub(crate) fn unstable_warn_cb(feature: &str) {
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
setup_panic_hook();
|
setup_panic_hook();
|
||||||
|
|
||||||
|
util::unix::prepare_stdio();
|
||||||
util::unix::raise_fd_limit();
|
util::unix::raise_fd_limit();
|
||||||
util::windows::ensure_stdio_open();
|
util::windows::ensure_stdio_open();
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|
|
@ -88,6 +88,7 @@
|
||||||
"test-querystring.js",
|
"test-querystring.js",
|
||||||
"test-readline-interface.js",
|
"test-readline-interface.js",
|
||||||
"test-stdin-from-file-spawn.js",
|
"test-stdin-from-file-spawn.js",
|
||||||
|
"test-ttywrap-invalid-fd.js",
|
||||||
"test-url-urltooptions.js",
|
"test-url-urltooptions.js",
|
||||||
"test-util-format.js",
|
"test-util-format.js",
|
||||||
"test-util-inspect-namespace.js",
|
"test-util-inspect-namespace.js",
|
||||||
|
@ -625,6 +626,7 @@
|
||||||
"test-timers-unref-throw-then-ref.js",
|
"test-timers-unref-throw-then-ref.js",
|
||||||
"test-timers-user-call.js",
|
"test-timers-user-call.js",
|
||||||
"test-timers-zero-timeout.js",
|
"test-timers-zero-timeout.js",
|
||||||
|
"test-tty-stdin-end.js",
|
||||||
"test-url-domain-ascii-unicode.js",
|
"test-url-domain-ascii-unicode.js",
|
||||||
"test-url-fileurltopath.js",
|
"test-url-fileurltopath.js",
|
||||||
"test-url-format-invalid-input.js",
|
"test-url-format-invalid-input.js",
|
||||||
|
|
14
cli/tests/node_compat/test/parallel/test-tty-stdin-end.js
Normal file
14
cli/tests/node_compat/test/parallel/test-tty-stdin-end.js
Normal file
|
@ -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');
|
|
@ -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'
|
||||||
|
}
|
||||||
|
);
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -270,6 +270,7 @@ deno_core::extension!(deno_node,
|
||||||
ops::require::op_require_read_package_scope<P>,
|
ops::require::op_require_read_package_scope<P>,
|
||||||
ops::require::op_require_package_imports_resolve<P>,
|
ops::require::op_require_package_imports_resolve<P>,
|
||||||
ops::require::op_require_break_on_next_statement,
|
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_entry_point = "ext:deno_node/02_init.js",
|
||||||
esm = [
|
esm = [
|
||||||
|
@ -490,7 +491,7 @@ deno_core::extension!(deno_node,
|
||||||
"timers.ts" with_specifier "node:timers",
|
"timers.ts" with_specifier "node:timers",
|
||||||
"timers/promises.ts" with_specifier "node:timers/promises",
|
"timers/promises.ts" with_specifier "node:timers/promises",
|
||||||
"tls.ts" with_specifier "node:tls",
|
"tls.ts" with_specifier "node:tls",
|
||||||
"tty.ts" with_specifier "node:tty",
|
"tty.js" with_specifier "node:tty",
|
||||||
"url.ts" with_specifier "node:url",
|
"url.ts" with_specifier "node:url",
|
||||||
"util.ts" with_specifier "node:util",
|
"util.ts" with_specifier "node:util",
|
||||||
"util/types.ts" with_specifier "node:util/types",
|
"util/types.ts" with_specifier "node:util/types",
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub mod http2;
|
||||||
pub mod idna;
|
pub mod idna;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
pub mod require;
|
pub mod require;
|
||||||
|
pub mod util;
|
||||||
pub mod v8;
|
pub mod v8;
|
||||||
pub mod winerror;
|
pub mod winerror;
|
||||||
pub mod zlib;
|
pub mod zlib;
|
||||||
|
|
83
ext/node/ops/util.rs
Normal file
83
ext/node/ops/util.rs
Normal file
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,9 +12,9 @@ import {
|
||||||
moveCursor,
|
moveCursor,
|
||||||
} from "ext:deno_node/internal/readline/callbacks.mjs";
|
} from "ext:deno_node/internal/readline/callbacks.mjs";
|
||||||
import { Duplex, Readable, Writable } from "node:stream";
|
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 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
|
// https://github.com/nodejs/node/blob/00738314828074243c9a52a228ab4c68b04259ef/lib/internal/bootstrap/switches/is_main_thread.js#L41
|
||||||
export function createWritableStdioStream(writer, name) {
|
export function createWritableStdioStream(writer, name) {
|
||||||
|
@ -95,60 +95,21 @@ export function createWritableStdioStream(writer, name) {
|
||||||
return stream;
|
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) {
|
function _guessStdinType(fd) {
|
||||||
if (typeof fd !== "number" || fd < 0) return "UNKNOWN";
|
if (typeof fd !== "number" || fd < 0) return "UNKNOWN";
|
||||||
if (Deno.isatty?.(fd)) return "TTY";
|
return guessHandleType(fd);
|
||||||
|
|
||||||
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";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _read = function (size) {
|
const _read = function (size) {
|
||||||
const p = Buffer.alloc(size || 16 * 1024);
|
const p = Buffer.alloc(size || 16 * 1024);
|
||||||
io.stdin?.read(p).then((length) => {
|
io.stdin?.read(p).then(
|
||||||
this.push(length === null ? null : p.slice(0, length));
|
(length) => {
|
||||||
}, (error) => {
|
this.push(length === null ? null : p.slice(0, length));
|
||||||
this.destroy(error);
|
},
|
||||||
});
|
(error) => {
|
||||||
|
this.destroy(error);
|
||||||
|
},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** https://nodejs.org/api/process.html#process_process_stdin */
|
/** https://nodejs.org/api/process.html#process_process_stdin */
|
||||||
|
@ -172,17 +133,12 @@ export const initStdin = () => {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "TTY":
|
case "TTY": {
|
||||||
|
stdin = new tty.ReadStream(fd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "PIPE":
|
case "PIPE":
|
||||||
case "TCP": {
|
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.
|
// For PIPE and TCP, `new Duplex()` should be replaced `new net.Socket()` if possible.
|
||||||
// There are two problems that need to be resolved.
|
// There are two problems that need to be resolved.
|
||||||
// 1. Using them here introduces a circular dependency.
|
// 1. Using them here introduces a circular dependency.
|
||||||
|
|
|
@ -28,10 +28,13 @@
|
||||||
// TODO(petamoriken): enable prefer-primordials for node polyfills
|
// TODO(petamoriken): enable prefer-primordials for node polyfills
|
||||||
// deno-lint-ignore-file prefer-primordials
|
// 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 {
|
const handleTypes = ["TCP", "TTY", "UDP", "FILE", "PIPE", "UNKNOWN"];
|
||||||
notImplemented("util.guessHandleType");
|
export function guessHandleType(fd: number): string {
|
||||||
|
const type = ops.op_node_guess_handle_type(fd);
|
||||||
|
return handleTypes[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ALL_PROPERTIES = 0;
|
export const ALL_PROPERTIES = 0;
|
||||||
|
|
|
@ -33,8 +33,6 @@ export { _nextTick as nextTick, chdir, cwd, env, version, versions };
|
||||||
import {
|
import {
|
||||||
createWritableStdioStream,
|
createWritableStdioStream,
|
||||||
initStdin,
|
initStdin,
|
||||||
Readable,
|
|
||||||
Writable,
|
|
||||||
} from "ext:deno_node/_process/streams.mjs";
|
} from "ext:deno_node/_process/streams.mjs";
|
||||||
import {
|
import {
|
||||||
enableNextTick,
|
enableNextTick,
|
||||||
|
@ -57,41 +55,9 @@ export let platform = "";
|
||||||
// TODO(kt3k): This should be set at start up time
|
// TODO(kt3k): This should be set at start up time
|
||||||
export let pid = 0;
|
export let pid = 0;
|
||||||
|
|
||||||
// We want streams to be as lazy as possible, but we cannot export a getter in a module. To
|
let stdin, stdout, stderr;
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
export let stderr = makeLazyStream(getStderr);
|
export { stderr, stdin, stdout };
|
||||||
export let stdin = makeLazyStream(getStdin);
|
|
||||||
export let stdout = makeLazyStream(getStdout);
|
|
||||||
|
|
||||||
import { getBinding } from "ext:deno_node/internal_binding/mod.ts";
|
import { getBinding } from "ext:deno_node/internal_binding/mod.ts";
|
||||||
import * as constants from "ext:deno_node/internal_binding/constants.ts";
|
import * as constants from "ext:deno_node/internal_binding/constants.ts";
|
||||||
|
@ -646,19 +612,13 @@ class Process extends EventEmitter {
|
||||||
memoryUsage = memoryUsage;
|
memoryUsage = memoryUsage;
|
||||||
|
|
||||||
/** https://nodejs.org/api/process.html#process_process_stderr */
|
/** https://nodejs.org/api/process.html#process_process_stderr */
|
||||||
get stderr(): Writable {
|
stderr = stderr;
|
||||||
return getStderr();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** https://nodejs.org/api/process.html#process_process_stdin */
|
/** https://nodejs.org/api/process.html#process_process_stdin */
|
||||||
get stdin(): Readable {
|
stdin = stdin;
|
||||||
return getStdin();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** https://nodejs.org/api/process.html#process_process_stdout */
|
/** https://nodejs.org/api/process.html#process_process_stdout */
|
||||||
get stdout(): Writable {
|
stdout = stdout;
|
||||||
return getStdout();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** https://nodejs.org/api/process.html#process_process_version */
|
/** https://nodejs.org/api/process.html#process_process_version */
|
||||||
version = version;
|
version = version;
|
||||||
|
@ -906,52 +866,24 @@ internals.__bootstrapNodeProcess = function (
|
||||||
core.setMacrotaskCallback(runNextTicks);
|
core.setMacrotaskCallback(runNextTicks);
|
||||||
enableNextTick();
|
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());
|
process.setStartTime(Date.now());
|
||||||
|
|
||||||
// @ts-ignore Remove setStartTime and #startTime is not modifiable
|
// @ts-ignore Remove setStartTime and #startTime is not modifiable
|
||||||
delete process.setStartTime;
|
delete process.setStartTime;
|
||||||
delete internals.__bootstrapNodeProcess;
|
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;
|
export default process;
|
||||||
|
|
83
ext/node/polyfills/tty.js
Normal file
83
ext/node/polyfills/tty.js
Normal file
|
@ -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 };
|
|
@ -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 };
|
|
|
@ -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.
|
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-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)
|
- [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-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-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-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-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-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)
|
- [parallel/test-ttywrap-stack.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-ttywrap-stack.js)
|
||||||
|
|
Loading…
Add table
Reference in a new issue