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
7 changes: 7 additions & 0 deletions lib/codegen_deno.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,13 @@ let () =
is the check to make before them (added for kyX). *)
b "pathExists"
(fun a -> Printf.sprintf "__as_fs().existsSync(%s)" (arg 0 a));
(* Total write and rename: true on success, false on any host error
(permission, missing directory, disk full), never a throw. They let a
program stage outputs and publish them all or none (added for kyX). *)
b "tryWriteTextFile"
(fun a -> Printf.sprintf "((p, c) => { try { __as_fs().writeFileSync(p, c, \"utf8\"); return true; } catch (_e) { return false; } })(%s, %s)" (arg 0 a) (arg 1 a));
b "tryRenamePath"
(fun a -> Printf.sprintf "((f, t) => { try { __as_fs().renameSync(f, t); return true; } catch (_e) { return false; } })(%s, %s)" (arg 0 a) (arg 1 a));
b "args" (fun _ -> "(globalThis.process?.argv?.slice(2) ?? [])");
b "exit"
(fun a -> Printf.sprintf "__as_process().exit(%s)" (arg 0 a));
Expand Down
8 changes: 8 additions & 0 deletions stdlib/Deno.affine
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ pub extern fn statIsDirectory(path: String) -> Bool;
/// Never throws: the total check to make before the stat predicates above.
pub extern fn pathExists(path: String) -> Bool;

/// Write `content` to `path` as UTF-8. True on success, false on any host
/// error (permission, missing directory, disk full); never throws.
pub extern fn tryWriteTextFile(path: String, content: String) -> Bool;

/// Rename `from` to `to` (replacing `to` when it exists). True on success,
/// false on any host error; never throws.
pub extern fn tryRenamePath(from: String, to: 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
4 changes: 4 additions & 0 deletions tests/codegen-bun/host_profile.affine
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ 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 tryWriteTextFile(path: String, content: String) -> Bool;
extern fn tryRenamePath(from: String, to: String) -> Bool;
extern fn bytesLength(value: Bytes) -> Int;
extern fn bytesByteAt(value: Bytes, offset: Int) -> Int;
extern fn args() -> [String];
Expand All @@ -29,6 +31,8 @@ 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 try_write(path: String, content: String) -> Bool { tryWriteTextFile(path, content) }
pub fn try_rename(from: String, to: String) -> Bool { tryRenamePath(from, to) }
pub fn argument_count() -> Int { len(args()) }

pub fn environment_value(name: String) -> String {
Expand Down
10 changes: 10 additions & 0 deletions tests/codegen-bun/host_profile.harness.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ try {
// 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");
// tryWriteTextFile / tryRenamePath are total: false on a host error, never a throw.
const staged = join(nested, "staged.tmp");
const published = join(nested, "published.txt");
if (subject.try_write(staged, "v1") !== true) throw new Error("tryWriteTextFile failed on a writable path");
if (subject.try_write(join(root, "no-such-dir", "x"), "v") !== false) throw new Error("tryWriteTextFile into a missing directory is not false");
if (subject.try_write(published, "old") !== true) throw new Error("tryWriteTextFile could not create the target");
if (subject.try_rename(staged, published) !== true) throw new Error("tryRenamePath failed");
if (subject.read_text(published) !== "v1") throw new Error("tryRenamePath did not replace the target");
if (subject.exists(staged) !== false) throw new Error("tryRenamePath left the source behind");
if (subject.try_rename(staged, published) !== false) throw new Error("tryRenamePath of a missing source is not false");
} finally {
rmSync(root, { recursive: true, force: true });
}
Expand Down
Loading