Repro
import * as path from "node:path";
console.log("dirname /:", path.dirname("/"));
console.log("join with trailing:", path.join("/foo/", "/bar/", "baz"));
console.log("matchesGlob:", path.matchesGlob("foo.txt", "*.txt"));
console.log("toNamespacedPath:", path.toNamespacedPath("/foo/bar"));
console.log("after toNamespacedPath:", "still alive");
Actual (Perry v0.5.894)
dirname /:
join with trailing: /bar/baz
matchesGlob: undefined
TypeError: value is not a function
at <anonymous>
(Then exits. The after toNamespacedPath line never prints.)
Expected (Node)
dirname /: /
join with trailing: /foo/bar/baz
matchesGlob: true
toNamespacedPath: /foo/bar
after toNamespacedPath: still alive
Four distinct bugs
1. path.dirname("/") returns empty string instead of "/"
Per spec, the dirname of the root is the root itself. Perry returns "".
2. path.join("/foo/", "/bar/", "baz") resets on absolute paths in the middle
Node returns /foo/bar/baz (trailing slashes are consumed, then all segments joined). Perry returns /bar/baz — looks like it resets on the second absolute segment.
Closely related to #681, which fixed the zero-args case (path.join() → "."). The non-zero-args trailing-slash case still differs.
3. path.matchesGlob(path, pattern) is undefined
Newer API (Node 22.5+). Perry doesn't have it. Calling it throws TypeError.
4. path.toNamespacedPath(path) throws TypeError: value is not a function, terminating the script
This is the worst of the four. Calling path.toNamespacedPath("/foo/bar") should be a no-op on POSIX (Windows-only effect) and return its input. Instead Perry throws an unhandled TypeError that terminates the script — so any code after it (including unrelated probes) is silently dropped.
This is what makes test-files/test_parity_path.ts end at 37 of 42 expected lines today: lines 38-42 (the path.delimiter / path.sep / posix.* / win32.* checks) never run because the throw escapes upward.
Impact
The first three are normal "method not implemented" gaps. The fourth is a footgun: any consumer who calls path.toNamespacedPath expecting a no-op gets their program terminated. Common in cross-platform path-handling code.
Together these four are the entire remaining diff in test-files/test_parity_path.ts. Fix them and the parity test reaches full byte-for-byte PASS (diff = 0, joining test_parity_os as the second module to fully match).
Acceptance
The 5-line repro above prints output matching Node, including the final "after toNamespacedPath" line proving the throw is gone.
Related
Repro
Actual (Perry v0.5.894)
(Then exits. The
after toNamespacedPathline never prints.)Expected (Node)
Four distinct bugs
1.
path.dirname("/")returns empty string instead of"/"Per spec, the dirname of the root is the root itself. Perry returns
"".2.
path.join("/foo/", "/bar/", "baz")resets on absolute paths in the middleNode returns
/foo/bar/baz(trailing slashes are consumed, then all segments joined). Perry returns/bar/baz— looks like it resets on the second absolute segment.Closely related to #681, which fixed the zero-args case (
path.join()→"."). The non-zero-args trailing-slash case still differs.3.
path.matchesGlob(path, pattern)is undefinedNewer API (Node 22.5+). Perry doesn't have it. Calling it throws
TypeError.4.
path.toNamespacedPath(path)throwsTypeError: value is not a function, terminating the scriptThis is the worst of the four. Calling
path.toNamespacedPath("/foo/bar")should be a no-op on POSIX (Windows-only effect) and return its input. Instead Perry throws an unhandled TypeError that terminates the script — so any code after it (including unrelated probes) is silently dropped.This is what makes
test-files/test_parity_path.tsend at 37 of 42 expected lines today: lines 38-42 (thepath.delimiter/path.sep/posix.*/win32.*checks) never run because the throw escapes upward.Impact
The first three are normal "method not implemented" gaps. The fourth is a footgun: any consumer who calls
path.toNamespacedPathexpecting a no-op gets their program terminated. Common in cross-platform path-handling code.Together these four are the entire remaining diff in
test-files/test_parity_path.ts. Fix them and the parity test reaches full byte-for-byte PASS (diff = 0, joining test_parity_os as the second module to fully match).Acceptance
The 5-line repro above prints output matching Node, including the final "after toNamespacedPath" line proving the throw is gone.
Related
path.join()(zero args) throws TypeError instead of returning.#681 (closed; only zero-argspath.join()case fixed).test-files/test_parity_path.ts(diff = 15 in v0.5.894 sweep).