#Env Package Documentation

    This package provides utilities for interacting with the runtime environment, including access to command line arguments, current time, and working directory information.

    #Command Line Arguments

    Access command line arguments passed to your program:

    ///|
    test "command line arguments" {
    let arguments = @env.args()

    // The arguments array contains program arguments
    // In a test environment, this will typically be empty or contain test runner args
    inspect(arguments.length() >= 0, content="true")

    // Example of how you might process arguments in a real program:
    fn process_args(args : Array[String]) -> String {
    if args.length() == 0 {
    "No arguments provided"
    } else {
    "First argument: " + args[0]
    }
    }

    let result = process_args(arguments)
    inspect(result.length() > 0, content="true")
    }

    #Process Exit

    Use @env.exit(code) to terminate the process. Exit code 0 indicates success; a nonzero code indicates failure. The function never returns, so it can be used in a branch that otherwise produces a value.

    ///|
    fn main {
    println("Done")
    @env.exit(0)
    }

    On JavaScript, exit uses process.exit and panics if it is unavailable. WebAssembly hosts must provide WASI proc_exit for wasm or __moonbit_sys_unstable.exit for wasm-gc.

    #Current Time

    Get the current time in milliseconds since Unix epoch:

    ///|
    test "current time" {
    let timestamp = @env.now()

    // Timestamp should be a reasonable value (after year 2020)
    let year_2020_ms = 1577836800000UL // Jan 1, 2020 in milliseconds
    inspect(timestamp > year_2020_ms, content="true")

    // Demonstrate time-based operations
    fn format_timestamp(ts : UInt64) -> String {
    "Timestamp: " + ts.to_string()
    }

    let formatted = format_timestamp(timestamp)
    inspect(formatted.length() > 10, content="true") // Should contain timestamp data
    }

    #Working Directory

    Get the current working directory:

    ///|
    test "working directory" {
    let cwd = @env.current_dir()
    match cwd {
    Some(path) =>
    // We have a current directory
    inspect(path.length() > 0, content="true")
    None =>
    // Current directory unavailable (some platforms/environments)
    inspect(true, content="true") // This is also valid
    }
    }

    #Practical Usage Examples

    #Command Line Tool Pattern

    ///|
    test "command line tool pattern" {
    fn parse_command(args : Array[String]) -> String raise Failure {
    if args.length() < 2 {
    raise Failure("Usage: program <command> [args...]")
    }
    match args[1] {
    "help" => "Showing help information"
    "version" => "Version 1.0.0"
    "status" => "System is running"
    cmd => raise Failure("Unknown command: \{cmd}")
    }
    }

    // Test with mock arguments
    let test_args = ["program", "help"]
    let result = parse_command(test_args)
    inspect(result, content="Showing help information")
    try parse_command(["program", "invalid"]) |> ignore catch {
    Failure(msg) => inspect(msg, content="Unknown command: invalid")
    } noraise {
    _ => fail("expected parse_command to raise on unknown command")
    }
    }

    #Configuration Loading

    ///|
    test "configuration loading" {
    fn load_config_path() -> String {
    match @env.current_dir() {
    Some(cwd) => cwd + "/config.json"
    None => "./config.json" // Fallback
    }
    }

    let config_path = load_config_path()
    inspect(config_path.length() > 10, content="true") // Should have path with config.json
    }

    #Logging with Timestamps

    ///|
    test "logging with timestamps" {
    fn log_message(level : String, message : String) -> String {
    let timestamp = @env.now()
    "[" + timestamp.to_string() + "] " + level + ": " + message
    }

    let log_entry = log_message("INFO", "Application started")
    inspect(log_entry.length() > 20, content="true") // Should have timestamp and message
    inspect(log_entry.length() > 10, content="true") // Should have substantial content
    }

    #File Path Operations

    ///|
    test "file path operations" {
    fn resolve_relative_path(relative : String) -> String {
    match @env.current_dir() {
    Some(base) => base + "/" + relative
    None => relative
    }
    }

    let resolved = resolve_relative_path("data/input.txt")
    inspect(resolved.length() > 10, content="true") // Should have resolved path
    }

    #Platform Differences

    The env package behaves differently across platforms:

    #JavaScript Environment

    • args() returns arguments from the JavaScript environment
    • @env.now() uses Date.now()
    • @env.current_dir() may return None in browser environments

    #WebAssembly Environment

    • args() behavior depends on the WASM host
    • @env.now() provides millisecond precision timing
    • @env.current_dir() availability depends on host capabilities

    #Native Environment

    • args() returns actual command line arguments
    • @env.now() provides system time
    • @env.current_dir() uses system calls to get working directory

    #Error Handling

    Handle cases where environment information is unavailable:

    ///|
    test "error handling" {
    fn safe_get_cwd() -> String {
    match @env.current_dir() {
    Some(path) => path
    None =>
    // Fallback when current directory is unavailable
    "."
    }
    }

    let safe_cwd = safe_get_cwd()
    inspect(safe_cwd.length() > 0, content="true")
    fn validate_args(
    args : Array[String],
    min_count : Int32,
    ) -> Unit raise Failure {
    if args.length() < min_count {
    raise Failure("Insufficient arguments: expected at least \{min_count}")
    }
    }

    try validate_args(["prog"], 2) catch {
    Failure(msg) => inspect(msg.length() > 10, content="true") // Should have error message
    } noraise {
    _ => fail("expected validation to fail")
    }
    }

    #Best Practices

    #1. Handle Missing Environment Data Gracefully

    ///|
    test "graceful handling" {
    fn get_work_dir() -> String {
    match @env.current_dir() {
    Some(dir) => dir
    None => "." // Relative to the process working directory
    }
    }

    let work_dir = get_work_dir()
    inspect(work_dir.length() > 0, content="true")
    }

    #2. Validate Command Line Arguments

    ///|
    test "argument validation" {
    fn validate_and_parse_args(
    args : Array[String],
    ) -> (String, Array[String]) raise Failure {
    if args.length() == 0 {
    raise Failure("No program name available")
    } else if args.length() == 1 {
    (args[0], []) // Program name only, no arguments
    } else {
    let program = args[0]
    let arguments = Array()
    for i in 1..<args.length() {
    arguments.push(args[i])
    }
    (program, arguments)
    }
    }

    let (prog, args) = validate_and_parse_args(["myprogram", "arg1", "arg2"])
    inspect(prog, content="myprogram")
    inspect(args.length(), content="2")
    }

    #3. Use Timestamps for Labels

    now() returns wall-clock milliseconds. Calls can return the same value, and the clock can move backwards after a system clock adjustment. A timestamp alone is neither a unique identifier nor a monotonic timer.

    ///|
    test "timestamp label" {
    let label = "task_" + @env.now().to_string()
    inspect(label.has_prefix("task_"), content="true")
    }

    #Common Use Cases

    1. Command Line Tools: Parse arguments and provide help/usage information
    2. Configuration Management: Load config files relative to current directory
    3. Logging Systems: Add timestamps to log entries
    4. File Processing: Resolve relative file paths
    5. Debugging: Include environment information in error reports
    6. Build Tools: Determine working directory for relative path operations

    #Performance Considerations

    • args() is typically called once at program startup
    • @env.now() is lightweight but avoid calling in tight loops if high precision isn't needed
    • @env.current_dir() may involve system calls, so cache the result if used frequently
    • Environment functions are generally fast but platform-dependent

    The env package provides essential runtime environment access for building robust MoonBit applications that interact with their execution environment.

    args

    fn args() -> Array[String]

    Get the runtime command line, including its executable prefix. On JavaScript/Node this is process.argv, including both the Node executable and the script path. JavaScript environments without process.argv return an empty array. Other targets use the host-provided argument list.

    current_dir

    fn current_dir() -> String?

    Get the current working directory. On some platforms, this may return None if the current directory cannot be determined.

    exit

    fn[T] exit(code : Int) -> T

    Terminate the process with the given exit code. Zero indicates success; a nonzero code indicates failure. This function never returns.

    On JavaScript, uses process.exit and panics if it is unavailable. WebAssembly hosts must provide WASI proc_exit for wasm or __moonbit_sys_unstable.exit for wasm-gc.

    get_env_var

    fn get_env_var(key : String) -> String?

    Get an environment variable by key. Returns None if the key does not exist.

    get_env_vars

    fn get_env_vars() -> Map[String, String]

    Get all environment variables.

    now

    fn now() -> UInt64

    Get the current time in milliseconds since the Unix epoch.

    rand

    fn rand(n : Int) -> Bytes?

    Get n random bytes from a platform entropy source. Returns Some(bytes) when the platform can provide secure random bytes, and None when entropy is unsupported or the host reports a failure. For n <= 0, probes availability and returns Some(b"") on success.

    set_env_var

    fn set_env_var(key : String, value : String) -> Unit

    Set an environment variable.

    unset_env_var

    fn unset_env_var(key : String) -> Unit

    Unset an environment variable.

    Powered by MoonBit

    Site sourceReport issueModulesSkillsBuild queueStatistics

    © 2026 mooncakes.io