// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
#external
priv type FsStats
///|
#external
priv type FsOptions
///|
#external
priv type FsBytesResult
///|
extern "js" fn FsBytesResult::is_ok(self : Self) -> Bool =
#| (res) => res.ok
///|
extern "js" fn FsBytesResult::content(self : Self) -> Bytes =
#| (res) => res.content
///|
extern "js" fn FsBytesResult::error_message(self : Self) -> String =
#| (res) => res.content
///|
#external
priv type FsStringArrayResult
///|
extern "js" fn FsStringArrayResult::is_ok(self : Self) -> Bool =
#| (res) => res.ok
///|
extern "js" fn FsStringArrayResult::content(self : Self) -> Array[String] =
#| (res) => res.content
///|
extern "js" fn FsStringArrayResult::error_message(self : Self) -> String =
#| (res) => res.content
///|
#external
priv type FsBoolResult
///|
extern "js" fn FsBoolResult::is_ok(self : Self) -> Bool =
#| (res) => res.ok
///|
extern "js" fn FsBoolResult::content(self : Self) -> Bool =
#| (res) => res.content
///|
extern "js" fn FsBoolResult::error_message(self : Self) -> String =
#| (res) => res.content
///|
#external
priv type FsUnitResult
///|
extern "js" fn FsUnitResult::is_ok(self : Self) -> Bool =
#| (res) => res.ok
///|
extern "js" fn FsUnitResult::error_message(self : Self) -> String =
#| (res) => res.content
///|
#module("node:fs")
extern "js" fn read_file_sync(path : String) -> Bytes = "readFileSync"
///|
extern "js" fn read_file_ffi(
read_file : (String) -> Bytes,
path : String,
) -> FsBytesResult =
#| function(readFile, path) {
#| try {
#| const content = readFile(path);
#| return { ok: true, content };
#| } catch (error) {
#| return { ok: false, content: error.message };
#| }
#| }
///|
#module("node:fs")
extern "js" fn write_file_sync(path : String, content : Bytes) -> Unit = "writeFileSync"
///|
extern "js" fn write_file_ffi(
write_file : (String, Bytes) -> Unit,
path : String,
content : Bytes,
) -> FsUnitResult =
#| function(writeFile, path, content) {
#| try {
#| writeFile(path, Buffer.from(content));
#| return { ok: true, content: "" };
#| } catch (error) {
#| return { ok: false, content: error.message };
#| }
#| }
///|
fn read_file_to_bytes_internal(path : String) -> Bytes raise IOError {
let res = read_file_ffi(read_file_sync, path)
if !res.is_ok() {
raise IOError(res.error_message())
}
res.content()
}
///|
fn read_file_to_string_internal(
path : String,
encoding? : String = "utf8",
) -> String raise IOError {
guard encoding == "utf8" else {
raise IOError(
"Unsupported encoding: \{encoding}, only utf8 is supported for now",
)
}
let bytes = read_file_to_bytes_internal(path)
@ffi.utf8_bytes_to_mbt_string(bytes)
}
///|
fn write_bytes_to_file_internal(
path : String,
content : Bytes,
) -> Unit raise IOError {
let res = write_file_ffi(write_file_sync, path, content)
if !res.is_ok() {
raise IOError(res.error_message())
}
}
///|
fn write_string_to_file_internal(
path : String,
content : String,
encoding? : String = "utf8",
) -> Unit raise IOError {
guard encoding == "utf8" else {
raise IOError(
"Unsupported encoding: \{encoding}, only utf8 is supported for now",
)
}
let bytes = @ffi.mbt_string_to_utf8_bytes(content, false)
write_bytes_to_file_internal(path, bytes)
}
///|
#module("node:fs")
extern "js" fn path_exists_ffi(path : String) -> Bool = "existsSync"
///|
pub fn path_exists_internal(path : String) -> Bool {
path_exists_ffi(path)
}
///|
#module("node:fs")
extern "js" fn read_dir_sync(path : String) -> Array[String] = "readdirSync"
///|
extern "js" fn read_dir_ffi(
read_dir : (String) -> Array[String],
path : String,
) -> FsStringArrayResult =
#| function(readDir, path) {
#| try {
#| const files = readDir(path);
#| return { ok: true, content: files };
#| } catch (error) {
#| return { ok: false, content: error.message };
#| }
#| }
///|
fn read_dir_internal(path : String) -> Array[String] raise IOError {
let res = read_dir_ffi(read_dir_sync, path)
if !res.is_ok() {
raise IOError(res.error_message())
}
res.content()
}
///|
#module("node:fs")
extern "js" fn create_dir_sync(path : String, options : FsOptions) -> Unit = "mkdirSync"
///|
extern "js" fn create_dir_ffi(
create_dir : (String, FsOptions) -> Unit,
path : String,
) -> FsUnitResult =
#| function(createDir, path) {
#| try {
#| createDir(path, { recursive: true });
#| return { ok: true, content: "" };
#| } catch (error) {
#| return { ok: false, content: error.message };
#| }
#| }
///|
fn create_dir_internal(path : String) -> Unit raise IOError {
let res = create_dir_ffi(create_dir_sync, path)
if !res.is_ok() {
raise IOError(res.error_message())
}
}
///|
#module("node:fs")
extern "js" fn stat_sync(path : String) -> FsStats = "statSync"
///|
extern "js" fn is_dir_ffi(
stat : (String) -> FsStats,
path : String,
) -> FsBoolResult =
#| function(stat, path) {
#| try {
#| const stats = stat(path);
#| return { ok: true, content: stats.isDirectory() };
#| } catch (error) {
#| return { ok: false, content: error.message };
#| }
#| }
///|
fn is_dir_internal(path : String) -> Bool raise IOError {
let res = is_dir_ffi(stat_sync, path)
if !res.is_ok() {
raise IOError(res.error_message())
}
res.content()
}
///|
extern "js" fn is_file_ffi(
stat : (String) -> FsStats,
path : String,
) -> FsBoolResult =
#| function(stat, path) {
#| try {
#| const stats = stat(path);
#| return { ok: true, content: stats.isFile() };
#| } catch (error) {
#| return { ok: false, content: error.message };
#| }
#| }
///|
fn is_file_internal(path : String) -> Bool raise IOError {
let res = is_file_ffi(stat_sync, path)
if !res.is_ok() {
raise IOError(res.error_message())
}
res.content()
}
///|
#module("node:fs")
extern "js" fn remove_dir_sync(path : String, options : FsOptions) -> Unit = "rmSync"
///|
extern "js" fn remove_dir_ffi(
remove_dir : (String, FsOptions) -> Unit,
path : String,
) -> FsUnitResult =
#| function(removeDir, path) {
#| try {
#| removeDir(path, { recursive: true });
#| return { ok: true, content: "" };
#| } catch (error) {
#| return { ok: false, content: error.message };
#| }
#| }
///|
fn remove_dir_internal(path : String) -> Unit raise IOError {
let res = remove_dir_ffi(remove_dir_sync, path)
if !res.is_ok() {
raise IOError(res.error_message())
}
}
///|
#module("node:fs")
extern "js" fn remove_file_sync(path : String) -> Unit = "unlinkSync"
///|
extern "js" fn remove_file_ffi(
remove_file : (String) -> Unit,
path : String,
) -> FsUnitResult =
#| function(removeFile, path) {
#| try {
#| removeFile(path);
#| return { ok: true, content: "" };
#| } catch (error) {
#| return { ok: false, content: error.message };
#| }
#| }
///|
fn remove_file_internal(path : String) -> Unit raise IOError {
let res = remove_file_ffi(remove_file_sync, path)
if !res.is_ok() {
raise IOError(res.error_message())
}
}