rong_fs 0.3.1

Filesystem module for RongJS
//! `rong_fs` exposes a layered filesystem API:
//!
//! - `Rong.file(path)` returns a `RongFile`, which is a lazy path reference for
//!   high-level whole-file operations such as `text()`, `json()`, `bytes()`,
//!   `stat()`, and `exists()`.
//! - `RongFile.open()` returns a `FileHandle`, which represents an opened file
//!   descriptor for random access, seek/truncate, and readable/writable streams.
//! - `RongFile.writer()` returns a `FileSink`, which is a write-only sink for
//!   append and incremental streaming writes when full handle semantics are not
//!   needed.
//!
//! `Rong.write(...)` is the convenience entry point for one-shot writes, while
//! directory/path operations stay on the top-level `Rong` namespace.

use rong::*;
use std::path::PathBuf;

mod dir;
mod file;
mod misc;
mod rong_file;
mod sink;
mod stat;
mod write;

/// Internal function to resolve file paths.
fn grant_file_access(path: &str) -> JSResult<PathBuf> {
    Ok(PathBuf::from(path))
}

pub fn init(ctx: &JSContext) -> JSResult<()> {
    // Ensure stream classes are registered for readable/writable support
    rong_stream::init(ctx)?;
    stat::init(ctx)?;
    sink::init(ctx)?;
    file::init(ctx)?;
    rong_file::init(ctx)?;
    write::init(ctx)?;
    dir::init(ctx)?;
    misc::init(ctx)?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use rong_test::*;
    use std::env;

    #[test]
    fn test_filesystem() {
        async_run!(|ctx: JSContext| async move {
            rong_encoding::init(&ctx)?;
            rong_console::init(&ctx)?;
            rong_assert::init(&ctx)?;
            rong_abort::init(&ctx)?;
            rong_exception::init(&ctx)?;
            init(&ctx)?;

            // Get workspace root path
            let workspace_root = env::current_dir()
                .map_err(|e| {
                    HostError::new(
                        rong::error::E_INTERNAL,
                        format!("Failed to get current dir: {}", e),
                    )
                })?
                .parent()
                .and_then(|p| p.parent()) // Go up two levels
                .ok_or_else(|| {
                    HostError::new(rong::error::E_INTERNAL, "Failed to get workspace root")
                })?
                .to_string_lossy()
                .into_owned();

            // Inject workspace root into JavaScript environment
            ctx.global().set("WORKSPACE_ROOT", workspace_root)?;

            let passed_fs = UnitJSRunner::load_script(&ctx, "filesystem.js")
                .await?
                .run()
                .await?;
            assert!(passed_fs);

            Ok(())
        });
    }
}