Skip to content

tty.ReadStream / tty.WriteStream class exports undefined; stdout.isTTY typeof is boolean when piped #742

Description

@proggeramlug

Repro

import * as tty from "node:tty";
console.log("tty.ReadStream typeof:", typeof tty.ReadStream);
console.log("tty.WriteStream typeof:", typeof tty.WriteStream);
console.log("tty.isatty typeof:", typeof tty.isatty);
console.log("tty.isatty(0):", tty.isatty(0));
console.log("process.stdout.isTTY typeof:", typeof process.stdout.isTTY);

Actual (Perry v0.5.894, with stdout piped to a file)

tty.ReadStream typeof: undefined
tty.WriteStream typeof: undefined
tty.isatty typeof: undefined
tty.isatty(0): false
process.stdout.isTTY typeof: boolean

Expected (Node, with stdout piped to a file)

tty.ReadStream typeof: function
tty.WriteStream typeof: function
tty.isatty typeof: function
tty.isatty(0): false
process.stdout.isTTY typeof: undefined

Three bugs

1. tty.ReadStream / tty.WriteStream class exports return undefined

The classes aren't exposed as properties on the tty namespace object. Code that does instanceof tty.ReadStream or checks typeof tty.WriteStream === "function" (common pattern for "is this a TTY stream?") fails.

2. tty.isatty typeof returns undefined even though calling it works

Subtle: typeof tty.isatty returns "undefined" but the call tty.isatty(0) works correctly and returns false. So Perry has the dispatch path wired for the call (probably via NATIVE_MODULE_TABLE) but the property-access path (typeof) doesn't see the function. Same family as #629 — namespace member visibility is incomplete.

3. process.stdout.isTTY typeof returns "boolean" instead of "undefined" when stdout is not a TTY

Per the Node spec: isTTY is true when the stream is a TTY, undefined otherwise (intentionally — it's a presence-test). Perry returns false (typeof boolean) when piped, which is a small but spec-divergent behavior.

Many libraries do if (process.stdout.isTTY) { ... } (truthy check works the same either way) but some do if ("isTTY" in process.stdout) or if (process.stdout.isTTY !== undefined) — those fail under Perry.

Impact

These are the entire remaining diff in test-files/test_parity_tty.ts (3 lines off Node). Fix them and the parity test reaches full byte-for-byte PASS — joining test_parity_os and (potentially) test_parity_path (#741) as the third module to fully match.

Acceptance

The 5-line repro prints output matching Node when stdout is piped.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions