Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/codegen_deno.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,11 @@ let () =
(fun a -> Printf.sprintf "__as_fs().statSync(%s).isFile()" (arg 0 a));
b "statIsDirectory"
(fun a -> Printf.sprintf "__as_fs().statSync(%s).isDirectory()" (arg 0 a));
(* Total existence test: false for a missing path, never a throw. The stat
predicates above keep their ENOENT contract (host_profile pins it); this
is the check to make before them (added for kyX). *)
b "pathExists"
(fun a -> Printf.sprintf "__as_fs().existsSync(%s)" (arg 0 a));
b "args" (fun _ -> "(globalThis.process?.argv?.slice(2) ?? [])");
b "exit"
(fun a -> Printf.sprintf "__as_process().exit(%s)" (arg 0 a));
Expand Down
4 changes: 4 additions & 0 deletions stdlib/Deno.affine
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ pub extern fn statIsFile(path: String) -> Bool;
/// Throws on a missing path (pair with `isNotFound` for the absent case).
pub extern fn statIsDirectory(path: String) -> Bool;

/// True if `path` exists (file, directory or other), false if it does not.
/// Never throws: the total check to make before the stat predicates above.
pub extern fn pathExists(path: String) -> Bool;

/// Recursive walk under `root` — every file path beneath it, depth-first.
/// Mirrors `std/fs/walk` for the common case (no glob filter; callers
/// filter by extension). Throws on a missing root via `Deno.readDirSync`.
Expand Down
2 changes: 2 additions & 0 deletions tests/codegen-bun/host_profile.affine
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extern fn mkdirRecursive(path: String) -> Int;
extern fn statSize(path: String) -> Int;
extern fn statIsFile(path: String) -> Bool;
extern fn statIsDirectory(path: String) -> Bool;
extern fn pathExists(path: String) -> Bool;
extern fn bytesLength(value: Bytes) -> Int;
extern fn bytesByteAt(value: Bytes, offset: Int) -> Int;
extern fn args() -> [String];
Expand All @@ -27,6 +28,7 @@ pub fn make_directory(path: String) -> Int { mkdirRecursive(path) }
pub fn file_size(path: String) -> Int { statSize(path) }
pub fn is_file(path: String) -> Bool { statIsFile(path) }
pub fn is_directory(path: String) -> Bool { statIsDirectory(path) }
pub fn exists(path: String) -> Bool { pathExists(path) }
pub fn argument_count() -> Int { len(args()) }

pub fn environment_value(name: String) -> String {
Expand Down
3 changes: 3 additions & 0 deletions tests/codegen-bun/host_profile.harness.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ try {
missingPathThrew = true;
}
if (!missingPathThrew) throw new Error("remove did not make path absent");
// pathExists is the total check: false for the removed file, never a throw.
if (subject.exists(file) !== false) throw new Error("pathExists on a missing path is not false");
if (subject.exists(nested) !== true) throw new Error("pathExists on a directory is not true");
} finally {
rmSync(root, { recursive: true, force: true });
}
Expand Down
Loading