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
Repro
Actual (Perry v0.5.894, with stdout piped to a file)
Expected (Node, with stdout piped to a file)
Three bugs
1.
tty.ReadStream/tty.WriteStreamclass exports returnundefinedThe classes aren't exposed as properties on the
ttynamespace object. Code that doesinstanceof tty.ReadStreamor checkstypeof tty.WriteStream === "function"(common pattern for "is this a TTY stream?") fails.2.
tty.isattytypeof returnsundefinedeven though calling it worksSubtle:
typeof tty.isattyreturns"undefined"but the calltty.isatty(0)works correctly and returnsfalse. So Perry has the dispatch path wired for the call (probably viaNATIVE_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.isTTYtypeof returns"boolean"instead of"undefined"when stdout is not a TTYPer the Node spec:
isTTYistruewhen the stream is a TTY, undefined otherwise (intentionally — it's a presence-test). Perry returnsfalse(typeofboolean) 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 doif ("isTTY" in process.stdout)orif (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
true(TAG_TRUE) #629 (namespace property visibility — same root cause family).test-files/test_parity_tty.ts(diff = 6 in v0.5.894 sweep).