diff --git a/crates/cli/src/bin/installer.rs b/crates/cli/src/bin/installer.rs index e6e4ddd..c5a51c9 100644 --- a/crates/cli/src/bin/installer.rs +++ b/crates/cli/src/bin/installer.rs @@ -1,6 +1,8 @@ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +#![allow(clippy::result_large_err)] + use andromeda::{CliError, CliResult}; use clap::{Args, Parser as ClapParser, Subcommand}; use serde::Deserialize; @@ -125,7 +127,8 @@ fn install_andromeda(args: InstallArgs) -> CliResult<()> { // Create installation directory if !install_dir.exists() { print_info("Creating installation directory..."); - fs::create_dir_all(&install_dir).map_err(CliError::Io)?; + fs::create_dir_all(&install_dir) + .map_err(|e| CliError::runtime_error_simple(format!("IO error: {}", e)))?; } // Check if already installed @@ -173,7 +176,8 @@ fn install_andromeda(args: InstallArgs) -> CliResult<()> { // Install binary print_info("Installing binary..."); - fs::write(&binary_path, binary_data).map_err(CliError::Io)?; + fs::write(&binary_path, binary_data) + .map_err(|e| CliError::runtime_error_simple(format!("IO error: {}", e)))?; print_success(&format!( "Andromeda installed to: {}", @@ -227,12 +231,13 @@ fn get_latest_version(verbose: bool) -> CliResult { &format!("andromeda-installer/{}", env!("CARGO_PKG_VERSION")), ) .call() - .map_err(|e| CliError::TestExecution(format!("Failed to fetch release info: {e}")))?; + .map_err(|e| { + CliError::runtime_error_simple(format!("Failed to fetch release info: {e}")) + })?; - let release: GitHubRelease = response - .body_mut() - .read_json() - .map_err(|e| CliError::TestExecution(format!("Failed to parse release info: {e}")))?; + let release: GitHubRelease = response.body_mut().read_json().map_err(|e| { + CliError::runtime_error_simple(format!("Failed to parse release info: {e}")) + })?; Ok(release.tag_name) } @@ -249,7 +254,7 @@ fn detect_platform() -> CliResult { ("macos", "x86_64") => "andromeda-macos-amd64", ("macos", "aarch64") => "andromeda-macos-arm64", _ => { - return Err(CliError::Config(format!( + return Err(CliError::runtime_error_simple(format!( "Unsupported platform: {os} {arch}" ))); } @@ -269,14 +274,14 @@ fn download_file(url: &str, verbose: bool) -> CliResult> { &format!("andromeda-installer/{}", env!("CARGO_PKG_VERSION")), ) .call() - .map_err(|e| CliError::TestExecution(format!("Failed to download file: {e}")))?; + .map_err(|e| CliError::runtime_error_simple(format!("Failed to download file: {e}")))?; let mut bytes = Vec::new(); response .body_mut() .as_reader() .read_to_end(&mut bytes) - .map_err(CliError::Io)?; + .map_err(|e| CliError::runtime_error_simple(format!("IO error: {}", e)))?; if verbose { print_info(&format!("Downloaded {} bytes", bytes.len())); @@ -371,7 +376,8 @@ fn install_satellites(satellites: Vec, args: InstallArgs) -> CliResult<( // Create installation directory if !install_dir.exists() { print_info("Creating installation directory..."); - fs::create_dir_all(&install_dir).map_err(CliError::Io)?; + fs::create_dir_all(&install_dir) + .map_err(|e| CliError::runtime_error_simple(format!("IO error: {}", e)))?; } // Parse satellite list @@ -386,7 +392,10 @@ fn install_satellites(satellites: Vec, args: InstallArgs) -> CliResult<( sat, AVAILABLE_SATELLITES.join("\n - ") )); - return Err(CliError::Config(format!("Unknown satellite: {}", sat))); + return Err(CliError::runtime_error_simple(format!( + "Unknown satellite: {}", + sat + ))); } } satellites @@ -476,8 +485,8 @@ fn install_single_satellite( // Check if already installed if binary_path.exists() && !args.force { - return Err(CliError::Config( - "already installed (use --force to reinstall)".to_string(), + return Err(CliError::runtime_error_simple( + "already installed (use --force to reinstall)", )); } @@ -496,24 +505,26 @@ fn install_single_satellite( let binary_data = download_file(&download_url, args.verbose)?; // Install binary - fs::write(&binary_path, binary_data).map_err(CliError::Io)?; + fs::write(&binary_path, binary_data) + .map_err(|e| CliError::runtime_error_simple(format!("IO error: {}", e)))?; // Make executable on Unix systems #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let mut perms = fs::metadata(&binary_path) - .map_err(CliError::Io)? + .map_err(|e| CliError::runtime_error_simple(format!("IO error: {}", e)))? .permissions(); perms.set_mode(0o755); - fs::set_permissions(&binary_path, perms).map_err(CliError::Io)?; + fs::set_permissions(&binary_path, perms) + .map_err(|e| CliError::runtime_error_simple(format!("IO error: {}", e)))?; } // Verify installation if let Ok(output) = Command::new(&binary_path).arg("--version").output() && !output.status.success() { - return Err(CliError::Config("verification failed".to_string())); + return Err(CliError::runtime_error_simple("verification failed")); } Ok(()) @@ -531,7 +542,7 @@ fn detect_rust_target() -> CliResult { ("macos", "x86_64") => "x86_64-apple-darwin", ("macos", "aarch64") => "aarch64-apple-darwin", _ => { - return Err(CliError::Config(format!( + return Err(CliError::runtime_error_simple(format!( "Unsupported platform: {} {}", os, arch ))); diff --git a/crates/cli/src/bin/satellite_bundle.rs b/crates/cli/src/bin/satellite_bundle.rs index a5783bc..f3b1096 100644 --- a/crates/cli/src/bin/satellite_bundle.rs +++ b/crates/cli/src/bin/satellite_bundle.rs @@ -1,6 +1,8 @@ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +#![allow(clippy::result_large_err)] + /// Andromeda Satellite - Bundle /// /// A minimal executable focused solely on bundling and minifying JavaScript/TypeScript files. @@ -29,7 +31,7 @@ fn main() -> CliResult<()> { let cli = Cli::parse(); andromeda::bundle::bundle(cli.input.to_str().unwrap(), cli.output.to_str().unwrap()) - .map_err(|e| CliError::TestExecution(format!("Bundle failed: {e}")))?; + .map_err(|e| CliError::runtime_error_simple(format!("Bundle failed: {e}")))?; println!("✅ Successfully bundled and minified to {:?}", cli.output); diff --git a/crates/cli/src/bin/satellite_check.rs b/crates/cli/src/bin/satellite_check.rs index fc56b7a..fdc6462 100644 --- a/crates/cli/src/bin/satellite_check.rs +++ b/crates/cli/src/bin/satellite_check.rs @@ -1,6 +1,8 @@ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +#![allow(clippy::result_large_err)] + /// Andromeda Satellite - Check /// /// A minimal executable focused solely on type-checking TypeScript files. @@ -27,7 +29,7 @@ fn main() -> CliResult<()> { let config = andromeda::config::ConfigManager::load_or_default(None); andromeda::check::check_files_with_config(&cli.paths, Some(config)) - .map_err(|e| CliError::TestExecution(format!("{e}")))?; + .map_err(|e| CliError::runtime_error_simple(format!("{e}")))?; Ok(()) } diff --git a/crates/cli/src/bin/satellite_compile.rs b/crates/cli/src/bin/satellite_compile.rs index b6d1f19..3fae9ec 100644 --- a/crates/cli/src/bin/satellite_compile.rs +++ b/crates/cli/src/bin/satellite_compile.rs @@ -1,6 +1,8 @@ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +#![allow(clippy::result_large_err)] + /// Andromeda Satellite - Compile /// /// A minimal executable focused solely on compiling JavaScript/TypeScript files into executables. @@ -42,7 +44,7 @@ fn main() -> CliResult<()> { cli.verbose, cli.no_strict, ) - .map_err(|e| CliError::TestExecution(format!("Compilation failed: {e}")))?; + .map_err(|e| CliError::runtime_error_simple(format!("Compilation failed: {e}")))?; let mut config_info = Vec::new(); if cli.verbose { diff --git a/crates/cli/src/bin/satellite_fmt.rs b/crates/cli/src/bin/satellite_fmt.rs index 2b15098..4b152a2 100644 --- a/crates/cli/src/bin/satellite_fmt.rs +++ b/crates/cli/src/bin/satellite_fmt.rs @@ -1,6 +1,8 @@ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +#![allow(clippy::result_large_err)] + /// Andromeda Satellite - Format /// /// A minimal executable focused solely on formatting JavaScript/TypeScript files. @@ -29,7 +31,7 @@ fn main() -> CliResult<()> { let files_to_format = andromeda::helper::find_formattable_files_for_format(&cli.paths, &config.format) - .map_err(|e| CliError::TestExecution(format!("{e}")))?; + .map_err(|e| CliError::runtime_error_simple(format!("{e}")))?; if files_to_format.is_empty() { let warning = Style::new().yellow().bold().apply_to("⚠️"); @@ -49,7 +51,7 @@ fn main() -> CliResult<()> { for path in &files_to_format { match andromeda::format::format_file(path) - .map_err(|e| CliError::TestExecution(format!("{e}")))? + .map_err(|e| CliError::runtime_error_simple(format!("{e}")))? { andromeda::format::FormatResult::Changed => formatted_count += 1, andromeda::format::FormatResult::AlreadyFormatted => already_formatted_count += 1, diff --git a/crates/cli/src/bin/satellite_lint.rs b/crates/cli/src/bin/satellite_lint.rs index 95ab858..2a119f0 100644 --- a/crates/cli/src/bin/satellite_lint.rs +++ b/crates/cli/src/bin/satellite_lint.rs @@ -1,6 +1,8 @@ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +#![allow(clippy::result_large_err)] + /// Andromeda Satellite - Lint /// /// A minimal executable focused solely on linting JavaScript/TypeScript files. @@ -28,7 +30,7 @@ fn main() -> CliResult<()> { let files_to_lint = andromeda::helper::find_formattable_files_for_lint(&cli.paths, &config.lint) - .map_err(|e| CliError::TestExecution(format!("{e}")))?; + .map_err(|e| CliError::runtime_error_simple(format!("{e}")))?; if files_to_lint.is_empty() { println!("No lintable files found."); @@ -46,7 +48,7 @@ fn main() -> CliResult<()> { } if had_issues { - return Err(CliError::TestExecution( + return Err(CliError::runtime_error_simple( "Linting completed with errors".to_string(), )); } diff --git a/crates/cli/src/bin/satellite_run.rs b/crates/cli/src/bin/satellite_run.rs index 9e60a7e..90cf5e7 100644 --- a/crates/cli/src/bin/satellite_run.rs +++ b/crates/cli/src/bin/satellite_run.rs @@ -1,6 +1,8 @@ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +#![allow(clippy::result_large_err)] + /// Andromeda Satellite - Run /// /// A minimal executable focused solely on running JavaScript/TypeScript files. @@ -44,7 +46,7 @@ fn main() -> CliResult<()> { .collect(); andromeda::run::run(cli.verbose, cli.no_strict, runtime_files) - .map_err(|e| CliError::TestExecution(format!("{e}")))?; + .map_err(|e| CliError::runtime_error_simple(format!("{e}")))?; Ok(()) } diff --git a/crates/cli/src/bin/wpt.rs b/crates/cli/src/bin/wpt.rs index e6bdf5f..084f3b2 100644 --- a/crates/cli/src/bin/wpt.rs +++ b/crates/cli/src/bin/wpt.rs @@ -1,3 +1,5 @@ +#![allow(clippy::result_large_err)] + use andromeda::{CliError, CliResult}; use clap::{Args, Parser as ClapParser}; use std::num::NonZeroUsize; @@ -76,7 +78,9 @@ fn run_wpt_tests(args: RunArgs) -> CliResult<()> { // In CI mode, automatically use expectations let use_expectations = args.use_expectations || args.ci_mode; - let current_dir = std::env::current_dir().map_err(CliError::Io)?; + let current_dir = std::env::current_dir().map_err(|e| { + CliError::runtime_error_simple(format!("Failed to get current directory: {e}")) + })?; let in_tests_dir = current_dir.ends_with("tests"); let wpt_dir = if args.wpt_dir.is_absolute() { @@ -248,12 +252,12 @@ fn run_wpt_tests(args: RunArgs) -> CliResult<()> { } } - let status = cmd - .status() - .map_err(|e| CliError::TestExecution(format!("Failed to run WPT test runner: {e}")))?; + let status = cmd.status().map_err(|e| { + CliError::runtime_error_simple(format!("Failed to run WPT test runner: {e}")) + })?; if !status.success() { - return Err(CliError::TestExecution(format!( + return Err(CliError::runtime_error_simple(format!( "WPT test runner failed with exit code: {}", status.code().unwrap_or(1) ))); diff --git a/crates/cli/src/check.rs b/crates/cli/src/check.rs index a066a7f..19611a1 100644 --- a/crates/cli/src/check.rs +++ b/crates/cli/src/check.rs @@ -2,7 +2,7 @@ // If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::config::AndromedaConfig; -use crate::error::{AndromedaError, Result}; +use crate::error::{CliError, CliResult}; use crate::helper::find_formattable_files; use console::Style; use miette as oxc_miette; @@ -268,9 +268,9 @@ impl std::error::Error for TypeCheckError {} pub fn check_file_with_config( path: &PathBuf, config_override: Option, -) -> Result> { +) -> CliResult> { let content = - fs::read_to_string(path).map_err(|e| AndromedaError::file_read_error(path.clone(), e))?; + fs::read_to_string(path).map_err(|e| CliError::file_read_error(path.clone(), e))?; check_file_content_with_config(path, &content, config_override) } @@ -281,7 +281,7 @@ pub fn check_file_content_with_config( path: &PathBuf, content: &str, _config_override: Option, -) -> Result> { +) -> CliResult> { let allocator = Allocator::default(); let source_type = SourceType::from_path(path).unwrap_or_default(); @@ -592,7 +592,7 @@ fn extract_type_mismatch_info(error_message: &str) -> (Option, Option, -) -> Result<()> { +) -> CliResult<()> { let files_to_check: Vec = if paths.is_empty() { // If no paths provided, check all TypeScript files in current directory find_formattable_files(&[PathBuf::from(".")]) @@ -666,12 +666,8 @@ pub fn check_files_with_config( let error_count = Style::new().red().bold().apply_to(total_errors); let file_count = Style::new().red().bold().apply_to(files_with_errors); println!("{warning} {complete_msg}: Found {error_count} error(s) in {file_count} file(s)"); - return Err(AndromedaError::runtime_error( - "Type checking completed with errors".to_string(), - None, - None, - None, - None, + return Err(CliError::runtime_error_simple( + "Type checking completed with errors", )); } diff --git a/crates/cli/src/compile.rs b/crates/cli/src/compile.rs index 7ba172d..240d9dd 100644 --- a/crates/cli/src/compile.rs +++ b/crates/cli/src/compile.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use crate::error::{AndromedaError, Result, read_file_with_context}; +use crate::error::{CliError, CliResult, read_file_with_context}; use libsui::{Elf, Macho, PortableExecutable}; use serde::{Deserialize, Serialize}; use std::{env::current_exe, fs::File, path::Path}; @@ -24,10 +24,10 @@ pub fn compile( input_file: &Path, verbose: bool, no_strict: bool, -) -> Result<()> { +) -> CliResult<()> { // Validate input file exists and is readable if !input_file.exists() { - return Err(AndromedaError::file_not_found( + return Err(CliError::file_not_found( input_file.to_path_buf(), std::io::Error::new(std::io::ErrorKind::NotFound, "Input file not found"), )); @@ -38,7 +38,7 @@ pub fn compile( // Validate JS content is not empty if js_content.trim().is_empty() { - return Err(AndromedaError::invalid_argument( + return Err(CliError::invalid_argument( "input_file".to_string(), "non-empty JavaScript/TypeScript file".to_string(), "empty file".to_string(), @@ -47,22 +47,22 @@ pub fn compile( // Get current executable let exe_path = current_exe().map_err(|e| { - AndromedaError::config_error( + CliError::config_error( "Failed to get current executable path".to_string(), None, Some(Box::new(e)), ) })?; - let exe = std::fs::read(&exe_path) - .map_err(|e| AndromedaError::file_read_error(exe_path.clone(), e))?; + let exe = + std::fs::read(&exe_path).map_err(|e| CliError::file_read_error(exe_path.clone(), e))?; let js = js_content.into_bytes(); // Create embedded config let config = EmbeddedConfig { verbose, no_strict }; let config_json = serde_json::to_vec(&config).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( "Failed to serialize embedded config".to_string(), None, Some(Box::new(e)), @@ -74,7 +74,7 @@ pub fn compile( && !parent.exists() { std::fs::create_dir_all(parent).map_err(|e| { - AndromedaError::permission_denied( + CliError::permission_denied( format!("creating output directory {}", parent.display()), Some(parent.to_path_buf()), e, @@ -83,7 +83,7 @@ pub fn compile( } let mut out = File::create(result_name).map_err(|e| { - AndromedaError::permission_denied( + CliError::permission_denied( format!("creating output file {}", result_name.display()), Some(result_name.to_path_buf()), e, @@ -97,7 +97,7 @@ pub fn compile( // First pass: write JS code section Macho::from(exe) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to parse macOS executable".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -106,7 +106,7 @@ pub fn compile( })? .write_section(ANDROMEDA_JS_CODE_SECTION, js) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to write JavaScript section to macOS executable".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -115,7 +115,7 @@ pub fn compile( })? .build_and_sign(&mut out) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to build and sign macOS executable (first pass)".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -125,9 +125,9 @@ pub fn compile( // Second pass: re-read and add config section let exe_with_js = std::fs::read(result_name) - .map_err(|e| AndromedaError::file_read_error(result_name.to_path_buf(), e))?; + .map_err(|e| CliError::file_read_error(result_name.to_path_buf(), e))?; let mut out = File::create(result_name).map_err(|e| { - AndromedaError::permission_denied( + CliError::permission_denied( format!("creating output file {}", result_name.display()), Some(result_name.to_path_buf()), e, @@ -135,7 +135,7 @@ pub fn compile( })?; Macho::from(exe_with_js) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to parse macOS executable (second pass)".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -144,7 +144,7 @@ pub fn compile( })? .write_section(ANDROMEDA_CONFIG_SECTION, config_json) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to write config section to macOS executable".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -153,7 +153,7 @@ pub fn compile( })? .build_and_sign(&mut out) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to build and sign macOS executable (second pass)".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -165,7 +165,7 @@ pub fn compile( let elf = Elf::new(&exe); elf.append(ANDROMEDA_JS_CODE_SECTION, &js, &mut out) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to append JavaScript section to Linux executable".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -175,9 +175,9 @@ pub fn compile( // Note: libsui's Elf doesn't support multiple appends in sequence // We need to re-read the file and append the config section let exe_with_js = std::fs::read(result_name) - .map_err(|e| AndromedaError::file_read_error(result_name.to_path_buf(), e))?; + .map_err(|e| CliError::file_read_error(result_name.to_path_buf(), e))?; let mut out = File::create(result_name).map_err(|e| { - AndromedaError::permission_denied( + CliError::permission_denied( format!("creating output file {}", result_name.display()), Some(result_name.to_path_buf()), e, @@ -186,7 +186,7 @@ pub fn compile( Elf::new(&exe_with_js) .append(ANDROMEDA_CONFIG_SECTION, &config_json, &mut out) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to append config section to Linux executable".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -197,7 +197,7 @@ pub fn compile( "windows" => { PortableExecutable::from(&exe) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to parse Windows executable".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -206,7 +206,7 @@ pub fn compile( })? .write_resource(ANDROMEDA_JS_CODE_SECTION, js) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to write JavaScript resource to Windows executable".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -215,7 +215,7 @@ pub fn compile( })? .write_resource(ANDROMEDA_CONFIG_SECTION, config_json) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to write config resource to Windows executable".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -224,7 +224,7 @@ pub fn compile( })? .build(&mut out) .map_err(|e| { - AndromedaError::compile_error( + CliError::compile_error( "Failed to build Windows executable".to_string(), input_file.to_path_buf(), result_name.to_path_buf(), @@ -233,7 +233,7 @@ pub fn compile( })?; } _ => { - return Err(AndromedaError::unsupported_platform(os.to_string())); + return Err(CliError::unsupported_platform(os.to_string())); } } @@ -245,7 +245,7 @@ pub fn compile( if matches!(os, "macos" | "linux") { let metadata = metadata(result_name).map_err(|e| { - AndromedaError::permission_denied( + CliError::permission_denied( format!("reading permissions for {}", result_name.display()), Some(result_name.to_path_buf()), e, @@ -254,7 +254,7 @@ pub fn compile( let mut perms = metadata.permissions(); perms.set_mode(0o755); // rwxr-xr-x permissions set_permissions(result_name, perms).map_err(|e| { - AndromedaError::permission_denied( + CliError::permission_denied( format!( "setting executable permissions for {}", result_name.display() diff --git a/crates/cli/src/config.rs b/crates/cli/src/config.rs index 8a74ea1..53e72f3 100644 --- a/crates/cli/src/config.rs +++ b/crates/cli/src/config.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use crate::error::{AndromedaError, Result}; +use crate::error::{CliError, CliResult}; use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; @@ -269,9 +269,9 @@ impl ConfigManager { /// Load configuration from a file #[allow(clippy::result_large_err)] - pub fn load_config(path: &Path) -> Result { + pub fn load_config(path: &Path) -> CliResult { let content = std::fs::read_to_string(path).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( format!("Failed to read config file: {}", path.display()), Some(path.to_path_buf()), Some(e), @@ -283,7 +283,7 @@ impl ConfigManager { .and_then(|ext| ext.to_str()) .and_then(ConfigFormat::from_extension) .ok_or_else(|| { - AndromedaError::config_error( + CliError::config_error( format!("Unsupported config file format: {}", path.display()), Some(path.to_path_buf()), None::, @@ -314,24 +314,28 @@ impl ConfigManager { /// Parse configuration from string content #[allow(clippy::result_large_err)] - fn parse_config(content: &str, format: ConfigFormat, path: &Path) -> Result { + fn parse_config( + content: &str, + format: ConfigFormat, + path: &Path, + ) -> CliResult { let config = match format { ConfigFormat::Json => serde_json::from_str(content).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( format!("Invalid JSON in config file: {e}"), Some(path.to_path_buf()), Some(e), ) }), ConfigFormat::Toml => toml::from_str(content).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( format!("Invalid TOML in config file: {e}"), Some(path.to_path_buf()), Some(e), ) }), ConfigFormat::Yaml => serde_yaml::from_str(content).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( format!("Invalid YAML in config file: {e}"), Some(path.to_path_buf()), Some(e), @@ -344,24 +348,28 @@ impl ConfigManager { /// Save configuration to a file #[allow(clippy::result_large_err)] - pub fn save_config(config: &AndromedaConfig, path: &Path, format: ConfigFormat) -> Result<()> { + pub fn save_config( + config: &AndromedaConfig, + path: &Path, + format: ConfigFormat, + ) -> CliResult<()> { let content = match format { ConfigFormat::Json => serde_json::to_string_pretty(config).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( format!("Failed to serialize config as JSON: {e}"), Some(path.to_path_buf()), Some(e), ) }), ConfigFormat::Toml => toml::to_string_pretty(config).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( format!("Failed to serialize config as TOML: {e}"), Some(path.to_path_buf()), Some(e), ) }), ConfigFormat::Yaml => serde_yaml::to_string(config).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( format!("Failed to serialize config as YAML: {e}"), Some(path.to_path_buf()), Some(e), @@ -372,7 +380,7 @@ impl ConfigManager { // Create parent directory if it doesn't exist if let Some(parent) = path.parent() { std::fs::create_dir_all(parent).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( format!("Failed to create config directory: {}", parent.display()), Some(path.to_path_buf()), Some(e), @@ -381,7 +389,7 @@ impl ConfigManager { } std::fs::write(path, content).map_err(|e| { - AndromedaError::config_error( + CliError::config_error( format!("Failed to write config file: {}", path.display()), Some(path.to_path_buf()), Some(e), @@ -393,7 +401,7 @@ impl ConfigManager { /// Create a new config file with default values #[allow(clippy::result_large_err)] - pub fn create_default_config(path: &Path, format: ConfigFormat) -> Result<()> { + pub fn create_default_config(path: &Path, format: ConfigFormat) -> CliResult<()> { let config = AndromedaConfig::default(); Self::save_config(&config, path, format)?; println!("✅ Created default config file: {}", path.display()); @@ -402,12 +410,12 @@ impl ConfigManager { /// Validate configuration #[allow(clippy::result_large_err)] - pub fn validate_config(config: &AndromedaConfig) -> Result<()> { + pub fn validate_config(config: &AndromedaConfig) -> CliResult<()> { // Validate runtime configuration if let Some(timeout) = config.runtime.timeout && timeout == 0 { - return Err(AndromedaError::config_error( + return Err(CliError::config_error( "Runtime timeout cannot be zero".to_string(), None, None::, @@ -416,7 +424,7 @@ impl ConfigManager { // Validate format configuration if config.format.line_width < 20 || config.format.line_width > 500 { - return Err(AndromedaError::config_error( + return Err(CliError::config_error( "Format line width must be between 20 and 500".to_string(), None, None::, @@ -424,7 +432,7 @@ impl ConfigManager { } if config.format.tab_width == 0 || config.format.tab_width > 16 { - return Err(AndromedaError::config_error( + return Err(CliError::config_error( "Tab width must be between 1 and 16".to_string(), None, None::, @@ -435,7 +443,7 @@ impl ConfigManager { if let Some(max_warnings) = config.lint.max_warnings && max_warnings == 0 { - return Err(AndromedaError::config_error( + return Err(CliError::config_error( "Maximum warnings cannot be zero".to_string(), None, None::, @@ -446,7 +454,7 @@ impl ConfigManager { for config_file in &config.import_map_files { let path = Path::new(config_file); if !path.exists() { - return Err(AndromedaError::config_error( + return Err(CliError::config_error( format!("Import map config file not found: {config_file}"), Some(path.to_path_buf()), None::, diff --git a/crates/cli/src/error.rs b/crates/cli/src/error.rs index 4aa3a5d..3409e8f 100644 --- a/crates/cli/src/error.rs +++ b/crates/cli/src/error.rs @@ -4,18 +4,22 @@ #![allow(clippy::result_large_err)] -use miette::{Diagnostic, MietteHandlerOpts, NamedSource, SourceSpan}; +use andromeda_core::RuntimeError; +use miette::{Diagnostic, NamedSource, SourceSpan}; use oxc_diagnostics::OxcDiagnostic; use std::path::PathBuf; use thiserror::Error; -/// Comprehensive error types for the Andromeda CLI +/// Comprehensive error types for the Andromeda CLI. +/// +/// These errors are designed for user-facing CLI interactions and provide +/// helpful messages and diagnostics for common CLI operations. #[derive(Error, Diagnostic, Debug)] #[allow(clippy::result_large_err)] -pub enum AndromedaError { +pub enum CliError { #[error("📁 File not found: {}", path.display())] #[diagnostic( - code(andromeda::file_not_found), + code(andromeda::cli::file_not_found), help("💡 Make sure the file exists and you have permission to read it"), url("https://doc.rust-lang.org/std/fs/fn.read_to_string.html") )] @@ -27,7 +31,7 @@ pub enum AndromedaError { #[error("📄 File reading error: {}", path.display())] #[diagnostic( - code(andromeda::file_read_error), + code(andromeda::cli::file_read_error), help("💡 Check file permissions and ensure the file is not corrupted") )] FileReadError { @@ -38,7 +42,7 @@ pub enum AndromedaError { #[error("🚨 JavaScript/TypeScript parsing failed in {file_path}")] #[diagnostic( - code(andromeda::parse_error), + code(andromeda::cli::parse_error), help("💡 Syntax errors detected. Check for missing semicolons, brackets, or quotes."), url("https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types") )] @@ -52,7 +56,7 @@ pub enum AndromedaError { #[error("⚡ JavaScript runtime error: {message}")] #[diagnostic( - code(andromeda::runtime_error), + code(andromeda::cli::runtime_error), help("💡 Check the stack trace for the exact error location and cause"), url("https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors") )] @@ -69,7 +73,7 @@ pub enum AndromedaError { #[error("Compilation failed: {reason}")] #[diagnostic( - code(andromeda::compile_error), + code(andromeda::cli::compile_error), help("Try checking if you have write permissions for the output directory") )] CompileError { @@ -82,7 +86,7 @@ pub enum AndromedaError { #[error("REPL error: {message}")] #[diagnostic( - code(andromeda::repl_error), + code(andromeda::cli::repl_error), help("Try typing 'help' for available commands") )] ReplError { @@ -93,14 +97,14 @@ pub enum AndromedaError { #[error("Unsupported platform: {platform}")] #[diagnostic( - code(andromeda::unsupported_platform), + code(andromeda::cli::unsupported_platform), help("Andromeda currently supports Windows, macOS, and Linux") )] UnsupportedPlatform { platform: String }, #[error("Permission denied: {operation}")] #[diagnostic( - code(andromeda::permission_denied), + code(andromeda::cli::permission_denied), help("Try running with appropriate permissions or check file ownership") )] PermissionDenied { @@ -112,7 +116,7 @@ pub enum AndromedaError { #[error("Invalid argument: {argument}")] #[diagnostic( - code(andromeda::invalid_argument), + code(andromeda::cli::invalid_argument), help("Use --help to see valid arguments and their formats") )] InvalidArgument { @@ -123,7 +127,7 @@ pub enum AndromedaError { #[error("Configuration error: {message}")] #[diagnostic( - code(andromeda::config_error), + code(andromeda::cli::config_error), help("Check your configuration file format and values") )] ConfigError { @@ -135,7 +139,7 @@ pub enum AndromedaError { #[error("Formatting error: {message}")] #[diagnostic( - code(andromeda::format_error), + code(andromeda::cli::format_error), help( "Check that the file is valid JavaScript/TypeScript and that dprint is configured correctly" ) @@ -145,13 +149,24 @@ pub enum AndromedaError { #[source] source: Option>, }, + + #[error("Task error: {message}")] + #[diagnostic( + code(andromeda::cli::task_error), + help("Check your task configuration in andromeda.toml") + )] + TaskError { + message: String, + task_name: Option, + }, } -impl AndromedaError { +impl CliError { /// Create a file not found error with context pub fn file_not_found(path: PathBuf, source: std::io::Error) -> Self { Self::FileNotFound { path, source } } + /// Create a file read error with context pub fn file_read_error(path: PathBuf, source: std::io::Error) -> Self { Self::FileReadError { path, source } @@ -182,6 +197,7 @@ impl AndromedaError { error_spans, } } + /// Create a runtime error with optional source location pub fn runtime_error( message: String, @@ -211,6 +227,18 @@ impl AndromedaError { } } + /// Create a simple runtime error with just a message + pub fn runtime_error_simple(message: impl Into) -> Self { + Self::RuntimeError { + message: message.into(), + file_path: None, + line: None, + column: None, + source_code: None, + error_span: None, + } + } + /// Create a compilation error pub fn compile_error( reason: String, @@ -263,6 +291,7 @@ impl AndromedaError { received, } } + /// Create a configuration error pub fn config_error( message: String, @@ -286,41 +315,192 @@ impl AndromedaError { source: source.map(|e| Box::new(e) as Box), } } + + /// Create a task error + pub fn task_error(message: String, task_name: Option) -> Self { + Self::TaskError { message, task_name } + } } -pub type Result = std::result::Result; +impl From> for CliError { + fn from(err: Box) -> Self { + (*err).into() + } +} + +impl From for CliError { + fn from(err: RuntimeError) -> Self { + match err { + RuntimeError::FsError { + path, + error_message, + .. + } => CliError::FileReadError { + path: PathBuf::from(path), + source: std::io::Error::other(error_message), + }, + RuntimeError::ParseError { + errors, + source_path, + .. + } => CliError::ParseError { + diagnostics: errors, + file_path: source_path.clone(), + source_code: NamedSource::new(source_path, String::new()), + error_spans: vec![], + }, + RuntimeError::RuntimeError { message, .. } => CliError::RuntimeError { + message, + file_path: None, + line: None, + column: None, + source_code: None, + error_span: None, + }, + RuntimeError::ExtensionError { + extension_name, + message, + .. + } => CliError::RuntimeError { + message: format!("Extension '{}' error: {}", extension_name, message), + file_path: None, + line: None, + column: None, + source_code: None, + error_span: None, + }, + RuntimeError::ResourceError { + rid, + operation, + message, + .. + } => CliError::RuntimeError { + message: format!("Resource {} error during {}: {}", rid, operation, message), + file_path: None, + line: None, + column: None, + source_code: None, + error_span: None, + }, + RuntimeError::TaskError { + task_id, message, .. + } => CliError::TaskError { + message: format!("Task {} error: {}", task_id, message), + task_name: Some(format!("task_{}", task_id)), + }, + RuntimeError::NetworkError { + url, error_message, .. + } => CliError::RuntimeError { + message: format!("Network error for {}: {}", url, error_message), + file_path: None, + line: None, + column: None, + source_code: None, + error_span: None, + }, + RuntimeError::EncodingError { + format, message, .. + } => CliError::RuntimeError { + message: format!("Encoding error ({}): {}", format, message), + file_path: None, + line: None, + column: None, + source_code: None, + error_span: None, + }, + RuntimeError::ConfigError { field, message, .. } => CliError::ConfigError { + message: format!("Field '{}': {}", field, message), + config_path: None, + source: None, + }, + RuntimeError::TypeError { + message, + expected_type, + actual_type, + .. + } => CliError::RuntimeError { + message: format!( + "Type error: {} (expected {}, got {})", + message, expected_type, actual_type + ), + file_path: None, + line: None, + column: None, + source_code: None, + error_span: None, + }, + RuntimeError::MemoryError { + message, operation, .. + } => CliError::RuntimeError { + message: format!("Memory error during {}: {}", operation, message), + file_path: None, + line: None, + column: None, + source_code: None, + error_span: None, + }, + } + } +} + +/// Result type alias for CLI operations +pub type CliResult = std::result::Result; +/// Extension trait for converting `RuntimeResult` to `CliResult`. +/// +/// This allows seamless conversion of core runtime errors to CLI errors. +/// +/// # Example +/// +/// ``` +/// use andromeda::error::{CliResult, IntoCliResult}; +/// use andromeda_core::RuntimeResult; +/// +/// fn run_something() -> RuntimeResult<()> { +/// Ok(()) +/// } +/// +/// fn cli_command() -> CliResult<()> { +/// run_something().into_cli_result() +/// } +/// ``` +#[allow(dead_code)] +pub trait IntoCliResult { + fn into_cli_result(self) -> CliResult; +} + +impl IntoCliResult for andromeda_core::RuntimeResult { + fn into_cli_result(self) -> CliResult { + self.map_err(CliError::from) + } +} + +/// Initialize error reporting with miette. +/// +/// This delegates to the shared error reporting module in `andromeda_core`. +/// It's safe to call this multiple times - only the first call has effect. pub fn init_error_reporting() { - if miette::set_hook(Box::new(|_| { - Box::new( - MietteHandlerOpts::new() - .terminal_links(true) - .unicode(true) - .color(true) - .context_lines(5) - .tab_width(4) - .force_graphical(true) - .build(), - ) - })) - .is_err() - {} + andromeda_core::init_error_reporting_default(); } -pub fn print_error(error: AndromedaError) { +/// Print a CLI error to stderr with miette formatting. +pub fn print_error(error: CliError) { eprintln!("{:?}", miette::Report::new(error)); } -/// Handle file reading with proper error context +/// Handle file reading with proper error context. +/// +/// This function reads a file and converts I/O errors to appropriate +/// `CliError` variants based on the error kind. #[allow(clippy::result_large_err)] -pub fn read_file_with_context(path: &std::path::Path) -> Result { +pub fn read_file_with_context(path: &std::path::Path) -> CliResult { std::fs::read_to_string(path).map_err(|e| match e.kind() { - std::io::ErrorKind::NotFound => AndromedaError::file_not_found(path.to_path_buf(), e), - std::io::ErrorKind::PermissionDenied => AndromedaError::permission_denied( + std::io::ErrorKind::NotFound => CliError::file_not_found(path.to_path_buf(), e), + std::io::ErrorKind::PermissionDenied => CliError::permission_denied( format!("reading file {}", path.display()), Some(path.to_path_buf()), e, ), - _ => AndromedaError::file_read_error(path.to_path_buf(), e), + _ => CliError::file_read_error(path.to_path_buf(), e), }) } diff --git a/crates/cli/src/format.rs b/crates/cli/src/format.rs index 175fec3..32aac62 100644 --- a/crates/cli/src/format.rs +++ b/crates/cli/src/format.rs @@ -3,7 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::config::{ConfigManager, FormatConfig}; -use crate::error::{AndromedaError, Result}; +use crate::error::{CliError, CliResult}; use console::Style; use dprint_core::configuration::{ConfigKeyValue, GlobalConfiguration, NewLineKind}; use dprint_plugin_json::{configuration as json_config, format_text as json_format}; @@ -104,12 +104,12 @@ fn create_json_dprint_config() -> IndexMap { /// Determines the file type based on the file extension #[allow(clippy::result_large_err)] -fn get_file_info(path: &std::path::Path) -> Result { +fn get_file_info(path: &std::path::Path) -> CliResult { let extension = path .extension() .and_then(|ext| ext.to_str()) .ok_or_else(|| { - AndromedaError::format_error( + CliError::format_error( format!("Could not determine file type for: {}", path.display()), None::, ) @@ -119,7 +119,7 @@ fn get_file_info(path: &std::path::Path) -> Result { "ts" | "tsx" | "mts" | "cts" => Ok(FileType::TypeScript), "js" | "jsx" | "mjs" | "cjs" => Ok(FileType::JavaScript), "json" | "jsonc" => Ok(FileType::Json), - _ => Err(AndromedaError::format_error( + _ => Err(CliError::format_error( format!("Unsupported file type: .{extension}"), None::, )), @@ -138,7 +138,7 @@ pub enum FormatResult { /// Formats a JavaScript, TypeScript, or JSON file using dprint. #[allow(clippy::result_large_err)] #[hotpath::measure] -pub fn format_file(path: &PathBuf) -> Result { +pub fn format_file(path: &PathBuf) -> CliResult { format_file_with_config(path, None) } @@ -147,9 +147,9 @@ pub fn format_file(path: &PathBuf) -> Result { pub fn format_file_with_config( path: &PathBuf, config_override: Option, -) -> Result { +) -> CliResult { let original_content = - fs::read_to_string(path).map_err(|e| AndromedaError::file_read_error(path.clone(), e))?; + fs::read_to_string(path).map_err(|e| CliError::file_read_error(path.clone(), e))?; let file_type = get_file_info(path)?; @@ -175,8 +175,7 @@ pub fn format_file_with_config( match formatted_content { Some(content) if content != original_content => { - fs::write(path, &content) - .map_err(|e| AndromedaError::file_read_error(path.clone(), e))?; + fs::write(path, &content).map_err(|e| CliError::file_read_error(path.clone(), e))?; let formatted_icon = Style::new().green().apply_to("📄"); let file_path = Style::new().cyan().apply_to(path.display()); println!(" {formatted_icon} {file_path}"); @@ -197,7 +196,7 @@ fn format_ts_js_file( original_content: &str, global_config: &GlobalConfiguration, format_config: &FormatConfig, -) -> Result> { +) -> CliResult> { let config = create_ts_dprint_config(format_config); let resolved_config = ts_config::resolve_config(config, global_config); @@ -208,7 +207,7 @@ fn format_ts_js_file( .map(|d| format!("{d}")) .collect::>() .join(", "); - return Err(AndromedaError::format_error( + return Err(CliError::format_error( format!("Failed to resolve dprint TS configuration: {error_msg}"), None::, )); @@ -224,7 +223,7 @@ fn format_ts_js_file( }; ts_format(format_options).map_err(|e| { - AndromedaError::format_error( + CliError::format_error( format!("Failed to format TS/JS file {}: {}", path.display(), e), None::, ) @@ -237,7 +236,7 @@ fn format_json_file( path: &PathBuf, original_content: &str, global_config: &GlobalConfiguration, -) -> Result> { +) -> CliResult> { let config = create_json_dprint_config(); let resolved_config = json_config::resolve_config(config, global_config); @@ -248,7 +247,7 @@ fn format_json_file( .map(|d| format!("{d}")) .collect::>() .join(", "); - return Err(AndromedaError::format_error( + return Err(CliError::format_error( format!("Failed to resolve dprint JSON configuration: {error_msg}"), None::, )); @@ -257,7 +256,7 @@ fn format_json_file( let config = resolved_config.config; json_format(path.as_ref(), original_content, &config).map_err(|e| { - AndromedaError::format_error( + CliError::format_error( format!("Failed to format JSON file {}: {}", path.display(), e), None::, ) diff --git a/crates/cli/src/helper.rs b/crates/cli/src/helper.rs index ad9e4ba..50f64f2 100644 --- a/crates/cli/src/helper.rs +++ b/crates/cli/src/helper.rs @@ -3,14 +3,14 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::config::{FormatConfig, LintConfig}; -use crate::error::{AndromedaError, Result}; +use crate::error::{CliError, CliResult}; use glob::Pattern; use std::fs; use std::path::{Path, PathBuf}; /// Recursively finds all JavaScript, TypeScript, and JSON files in the given directories #[allow(clippy::result_large_err)] -pub fn find_formattable_files(paths: &[PathBuf]) -> Result> { +pub fn find_formattable_files(paths: &[PathBuf]) -> CliResult> { let mut files = Vec::new(); // If no paths provided, use current directory @@ -30,7 +30,7 @@ pub fn find_formattable_files(paths: &[PathBuf]) -> Result> { // If it's a directory, recursively find all supported files find_files_in_directory(&path, &mut files)?; } else { - return Err(AndromedaError::format_error( + return Err(CliError::format_error( format!("Path does not exist: {}", path.display()), None::, )); @@ -44,9 +44,9 @@ pub fn find_formattable_files(paths: &[PathBuf]) -> Result> { /// Recursively searches a directory for formattable files #[allow(clippy::result_large_err)] -fn find_files_in_directory(dir: &PathBuf, files: &mut Vec) -> Result<()> { +fn find_files_in_directory(dir: &PathBuf, files: &mut Vec) -> CliResult<()> { let entries = fs::read_dir(dir).map_err(|e| { - AndromedaError::format_error( + CliError::format_error( format!("Failed to read directory {}: {}", dir.display(), e), Some(e), ) @@ -54,7 +54,7 @@ fn find_files_in_directory(dir: &PathBuf, files: &mut Vec) -> Result<() for entry in entries { let entry = entry.map_err(|e| { - AndromedaError::format_error( + CliError::format_error( format!("Failed to read directory entry in {}: {}", dir.display(), e), Some(e), ) @@ -119,7 +119,7 @@ pub fn apply_include_exclude_filters( files: Vec, include_patterns: &[String], exclude_patterns: &[String], -) -> Result> { +) -> CliResult> { let mut filtered_files = Vec::new(); for file in files { @@ -137,7 +137,7 @@ fn should_include_file( file_path: &Path, include_patterns: &[String], exclude_patterns: &[String], -) -> Result { +) -> CliResult { let path_str = file_path.to_string_lossy(); let is_included = if include_patterns.is_empty() { @@ -162,7 +162,7 @@ fn should_include_file( // Handle negated patterns (un-exclude) starting with "!" if let Some(negated_pattern) = pattern_str.strip_prefix('!') { let pattern = Pattern::new(negated_pattern).map_err(|e| { - AndromedaError::format_error( + CliError::format_error( format!("Invalid glob pattern '{negated_pattern}': {e}"), None::, ) @@ -176,7 +176,7 @@ fn should_include_file( } } else { let pattern = Pattern::new(pattern_str).map_err(|e| { - AndromedaError::format_error( + CliError::format_error( format!("Invalid glob pattern '{pattern_str}': {e}"), None::, ) @@ -198,7 +198,7 @@ pub fn find_formattable_files_with_filters( paths: &[PathBuf], include_patterns: &[String], exclude_patterns: &[String], -) -> Result> { +) -> CliResult> { let all_files = find_formattable_files(paths)?; apply_include_exclude_filters(all_files, include_patterns, exclude_patterns) @@ -209,7 +209,7 @@ pub fn find_formattable_files_with_filters( pub fn find_formattable_files_for_format( paths: &[PathBuf], format_config: &FormatConfig, -) -> Result> { +) -> CliResult> { find_formattable_files_with_filters(paths, &format_config.include, &format_config.exclude) } @@ -218,6 +218,6 @@ pub fn find_formattable_files_for_format( pub fn find_formattable_files_for_lint( paths: &[PathBuf], lint_config: &LintConfig, -) -> Result> { +) -> CliResult> { find_formattable_files_with_filters(paths, &lint_config.include, &lint_config.exclude) } diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 0842817..d68b051 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -1,4 +1,11 @@ -use std::fmt; +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Andromeda CLI library. +//! +//! This crate provides the command-line interface functionality for Andromeda, +//! including running, compiling, formatting, linting, and bundling JavaScript/TypeScript code. pub mod bundle; pub mod check; @@ -8,51 +15,20 @@ pub mod error; pub mod format; pub mod helper; pub mod lint; +pub mod lsp; +pub mod repl; pub mod run; +pub mod styles; +pub mod task; -#[derive(Debug)] -pub enum CliError { - Io(std::io::Error), - Json(serde_json::Error), - TestExecution(String), - Config(String), - InvalidPath(String), - Timeout(String), -} - -impl fmt::Display for CliError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - CliError::Io(err) => write!(f, "I/O error: {err}"), - CliError::Json(err) => write!(f, "JSON error: {err}"), - CliError::TestExecution(msg) => write!(f, "Test execution error: {msg}"), - CliError::Config(msg) => write!(f, "Configuration error: {msg}"), - CliError::InvalidPath(msg) => write!(f, "Invalid path: {msg}"), - CliError::Timeout(msg) => write!(f, "Timeout: {msg}"), - } - } -} - -impl std::error::Error for CliError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - CliError::Io(err) => Some(err), - CliError::Json(err) => Some(err), - _ => None, - } - } -} - -impl From for CliError { - fn from(err: std::io::Error) -> Self { - CliError::Io(err) - } -} +// Re-export error types for convenience +pub use error::{CliError, CliResult, IntoCliResult}; -impl From for CliError { - fn from(err: serde_json::Error) -> Self { - CliError::Json(err) - } -} +// Keep old names for backwards compatibility +#[doc(hidden)] +#[deprecated(since = "0.2.0", note = "Use CliError instead")] +pub use error::CliError as AndromedaError; -pub type CliResult = Result; +#[doc(hidden)] +#[deprecated(since = "0.2.0", note = "Use CliResult instead")] +pub use error::CliResult as Result; diff --git a/crates/cli/src/lint.rs b/crates/cli/src/lint.rs index f33bc74..5237369 100644 --- a/crates/cli/src/lint.rs +++ b/crates/cli/src/lint.rs @@ -57,7 +57,7 @@ //! ``` use crate::config::{AndromedaConfig, ConfigManager, LintConfig}; -use crate::error::{AndromedaError, Result}; +use crate::error::{CliError, CliResult}; use console::Style; use miette as oxc_miette; use owo_colors::OwoColorize; @@ -1977,9 +1977,9 @@ fn report_prefer_const_violations( pub fn lint_file_with_config( path: &PathBuf, config_override: Option, -) -> Result<()> { +) -> CliResult<()> { let content = - fs::read_to_string(path).map_err(|e| AndromedaError::file_read_error(path.clone(), e))?; + fs::read_to_string(path).map_err(|e| CliError::file_read_error(path.clone(), e))?; // Load configuration let config = config_override.unwrap_or_else(|| ConfigManager::load_or_default(None)); @@ -1999,7 +1999,7 @@ pub fn lint_file_content_with_config( path: &PathBuf, content: &str, config_override: Option, -) -> Result> { +) -> CliResult> { let allocator = Allocator::default(); let source_type = SourceType::from_path(path).unwrap_or_default(); let ret = Parser::new(&allocator, content, source_type).parse(); diff --git a/crates/cli/src/lsp/mod.rs b/crates/cli/src/lsp/mod.rs index 1710eb0..e8d279e 100644 --- a/crates/cli/src/lsp/mod.rs +++ b/crates/cli/src/lsp/mod.rs @@ -8,22 +8,14 @@ pub mod diagnostic_converter; pub mod options; pub mod server; -use crate::error::Result; +use crate::error::{CliError, CliResult}; use server::run_server; /// Start the LSP server #[allow(clippy::result_large_err)] -pub fn run_lsp_server() -> Result<()> { +pub fn run_lsp_server() -> CliResult<()> { env_logger::init(); log::info!("Starting Andromeda Language Server"); - run_server().map_err(|e| { - crate::error::AndromedaError::runtime_error( - format!("LSP server failed: {e}"), - None, - None, - None, - None, - ) - }) + run_server().map_err(|e| CliError::runtime_error_simple(format!("LSP server failed: {e}"))) } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index ec61a57..d6bb92b 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -20,7 +20,7 @@ mod run; mod styles; use run::run; mod error; -use error::{Result, init_error_reporting, print_error}; +use error::{CliResult, init_error_reporting, print_error}; mod format; use format::{FormatResult, format_file}; mod helper; @@ -229,7 +229,7 @@ fn main() { #[allow(clippy::result_large_err)] #[hotpath::measure] -fn run_main() -> Result<()> { +fn run_main() -> CliResult<()> { // Check if this is currently a single-file executable if let Ok(Some(js)) = find_section(ANDROMEDA_JS_CODE_SECTION) { // Try to load embedded config, fall back to defaults if not found @@ -295,7 +295,7 @@ fn run_main() -> Result<()> { .enable_io() .build() .map_err(|e| { - error::AndromedaError::config_error( + error::CliError::config_error( "Failed to initialize async runtime".to_string(), None, Some(Box::new(e)), @@ -303,7 +303,7 @@ fn run_main() -> Result<()> { })?; // Run Nova in a secondary blocking thread so tokio tasks can still run - let nova_thread = rt.spawn_blocking(move || -> Result<()> { + let nova_thread = rt.spawn_blocking(move || -> CliResult<()> { match args.command { Command::Run { verbose, @@ -321,7 +321,7 @@ fn run_main() -> Result<()> { no_strict, } => { compile(out.as_path(), path.as_path(), verbose, no_strict).map_err(|e| { - error::AndromedaError::compile_error( + error::CliError::compile_error( format!("Compilation failed: {e}"), path.clone(), out.clone(), @@ -351,9 +351,7 @@ fn run_main() -> Result<()> { // Load configuration let config = ConfigManager::load_or_default(None); run_repl_with_config(expose_internals, print_internals, disable_gc, Some(config)) - .map_err(|e| { - error::AndromedaError::repl_error(format!("REPL failed: {e}"), Some(e)) - }) + .map_err(|e| error::CliError::repl_error(format!("REPL failed: {e}"), Some(e))) } Command::Fmt { paths } => { // Load configuration @@ -422,7 +420,7 @@ fn run_main() -> Result<()> { version, dry_run, } => upgrade::run_upgrade(force, version, dry_run).map_err(|e| { - error::AndromedaError::runtime_error( + error::CliError::runtime_error( format!("Upgrade failed: {e}"), None, None, @@ -432,7 +430,7 @@ fn run_main() -> Result<()> { }), Command::Bundle { input, output } => { bundle(input.to_str().unwrap(), output.to_str().unwrap()).map_err(|e| { - error::AndromedaError::runtime_error( + error::CliError::runtime_error( format!("Bundle failed: {e}"), None, None, @@ -461,7 +459,7 @@ fn run_main() -> Result<()> { } } if had_issues { - Err(error::AndromedaError::runtime_error( + Err(error::CliError::runtime_error( "Linting completed with errors".to_string(), None, None, @@ -480,7 +478,7 @@ fn run_main() -> Result<()> { } Command::Lsp => { run_lsp_server().map_err(|e| { - error::AndromedaError::runtime_error( + error::CliError::runtime_error( format!("LSP server failed: {e}"), None, None, @@ -496,7 +494,7 @@ fn run_main() -> Result<()> { }); match rt.block_on(nova_thread) { Ok(result) => result, - Err(e) => Err(error::AndromedaError::config_error( + Err(e) => Err(error::CliError::config_error( "Runtime execution failed".to_string(), None, Some(Box::new(e)), @@ -563,7 +561,7 @@ impl From for ConfigFormat { } #[allow(clippy::result_large_err)] -fn handle_config_command(action: ConfigAction) -> Result<()> { +fn handle_config_command(action: ConfigAction) -> CliResult<()> { match action { ConfigAction::Init { format, @@ -577,7 +575,7 @@ fn handle_config_command(action: ConfigAction) -> Result<()> { // Check if file exists and force is not set if config_path.exists() && !force { - return Err(error::AndromedaError::config_error( + return Err(error::CliError::config_error( format!( "Config file already exists: {}. Use --force to overwrite.", config_path.display() @@ -588,7 +586,7 @@ fn handle_config_command(action: ConfigAction) -> Result<()> { } ConfigManager::create_default_config(&config_path, config_format).map_err(|e| { - error::AndromedaError::config_error( + error::CliError::config_error( format!("Failed to create config file: {e}"), Some(config_path.clone()), None::, @@ -601,7 +599,7 @@ fn handle_config_command(action: ConfigAction) -> Result<()> { ConfigAction::Show { file } => { let config = if let Some(path) = file { ConfigManager::load_config(&path).map_err(|e| { - error::AndromedaError::config_error( + error::CliError::config_error( format!("Failed to load config: {e}"), Some(path), None::, @@ -618,7 +616,7 @@ fn handle_config_command(action: ConfigAction) -> Result<()> { ConfigAction::Validate { file } => { let config = if let Some(path) = file { ConfigManager::load_config(&path).map_err(|e| { - error::AndromedaError::config_error( + error::CliError::config_error( format!("Failed to load config: {e}"), Some(path), None::, @@ -626,7 +624,7 @@ fn handle_config_command(action: ConfigAction) -> Result<()> { })? } else if let Some((config_path, _)) = ConfigManager::find_config_file(None) { ConfigManager::load_config(&config_path).map_err(|e| { - error::AndromedaError::config_error( + error::CliError::config_error( format!("Failed to load config: {e}"), Some(config_path), None::, @@ -638,7 +636,7 @@ fn handle_config_command(action: ConfigAction) -> Result<()> { }; ConfigManager::validate_config(&config).map_err(|e| { - error::AndromedaError::config_error( + error::CliError::config_error( format!("Config validation failed: {e}"), None, None::, diff --git a/crates/cli/src/repl.rs b/crates/cli/src/repl.rs index 0acb01c..19adb5b 100644 --- a/crates/cli/src/repl.rs +++ b/crates/cli/src/repl.rs @@ -3,7 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::config::{AndromedaConfig, ConfigManager}; -use crate::error::{AndromedaError, Result, print_error}; +use crate::error::{CliError, CliResult, print_error}; use crate::repl::highlighter::JsHighlighter; use crate::repl::prompt::ReplPrompt; use crate::repl::validator::JsValidator; @@ -43,14 +43,14 @@ mod validator; /// Handle parse errors in REPL with beautiful formatting fn handle_parse_errors(errors: Vec, source_path: &str, source: &str) { - let error = AndromedaError::parse_error(errors, source_path.to_string(), source.to_string()); + let error = CliError::parse_error(errors, source_path.to_string(), source.to_string()); print_error(error); } /// Handle runtime errors in REPL with beautiful formatting fn handle_runtime_error_with_message(error_message: String) { let error = - AndromedaError::runtime_error(error_message, Some("".to_string()), None, None, None); + CliError::runtime_error(error_message, Some("".to_string()), None, None, None); print_error(error); } @@ -61,7 +61,7 @@ pub fn run_repl_with_config( print_internals: bool, disable_gc: bool, config_override: Option, -) -> Result<()> { +) -> CliResult<()> { // Load configuration let config = config_override.unwrap_or_else(|| ConfigManager::load_or_default(None)); diff --git a/crates/cli/src/run.rs b/crates/cli/src/run.rs index fe30606..d0157b9 100644 --- a/crates/cli/src/run.rs +++ b/crates/cli/src/run.rs @@ -3,9 +3,9 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::config::{AndromedaConfig, ConfigManager}; -use crate::error::{Result, read_file_with_context}; +use crate::error::{CliResult, read_file_with_context}; use andromeda_core::{ - AndromedaError, ErrorReporter, HostData, ImportMap, Runtime, RuntimeConfig, RuntimeFile, + ErrorReporter, HostData, ImportMap, Runtime, RuntimeConfig, RuntimeError, RuntimeFile, }; use andromeda_runtime::{ recommended_builtins, recommended_eventloop_handler, recommended_extensions, @@ -17,7 +17,7 @@ use andromeda_runtime::{ /// the CLI interface only passes a single file. #[allow(clippy::result_large_err)] #[hotpath::measure] -pub fn run(verbose: bool, no_strict: bool, files: Vec) -> Result<()> { +pub fn run(verbose: bool, no_strict: bool, files: Vec) -> CliResult<()> { create_runtime_files(verbose, no_strict, files, None) } @@ -28,7 +28,7 @@ pub fn create_runtime_files( no_strict: bool, files: Vec, config_override: Option, -) -> Result<()> { +) -> CliResult<()> { // Load configuration let config = config_override.unwrap_or_else(|| { // Try to load config from the directory of the first file, or current directory @@ -48,7 +48,7 @@ pub fn create_runtime_files( // Validate that we have files to run if files.is_empty() { - return Err(crate::error::AndromedaError::invalid_argument( + return Err(crate::error::CliError::invalid_argument( "files".to_string(), "at least one file path".to_string(), "empty list".to_string(), @@ -73,7 +73,7 @@ pub fn create_runtime_files( if let RuntimeFile::Local { path } = file { let file_path = std::path::Path::new(path); if !file_path.exists() { - return Err(crate::error::AndromedaError::file_not_found( + return Err(crate::error::CliError::file_not_found( file_path.to_path_buf(), std::io::Error::new(std::io::ErrorKind::NotFound, "File not found"), )); @@ -160,14 +160,14 @@ pub fn create_runtime_files( miette::SourceSpan::new(0.into(), 1) }; - AndromedaError::runtime_error_with_location( + RuntimeError::runtime_error_with_location( error_message.clone(), - &content, - &path, + content, + path, source_span, ) } else { - AndromedaError::runtime_error(error_message.clone()) + RuntimeError::runtime_error(error_message.clone()) }; // Print the enhanced error using our error reporting system @@ -184,7 +184,7 @@ pub fn create_runtime_files( fn apply_file_filters( files: Vec, config: &AndromedaConfig, -) -> Result> { +) -> CliResult> { if config.runtime.include.is_empty() && config.runtime.exclude.is_empty() { return Ok(files); } @@ -235,7 +235,7 @@ fn apply_file_filters( fn build_import_map( config: &AndromedaConfig, start_dir: Option<&std::path::Path>, -) -> Result> { +) -> CliResult> { if config.imports.is_empty() && config.scopes.is_empty() && config.import_map_files.is_empty() { return Ok(None); } @@ -257,7 +257,7 @@ fn build_import_map( }; if !config_path.exists() { - return Err(crate::error::AndromedaError::file_not_found( + return Err(crate::error::CliError::file_not_found( config_path.clone(), std::io::Error::new( std::io::ErrorKind::NotFound, @@ -267,7 +267,7 @@ fn build_import_map( } let file_import_map = ImportMap::from_file(&config_path).map_err(|e| { - crate::error::AndromedaError::config_error( + crate::error::CliError::config_error( format!( "Failed to load import map from {}: {}", config_path.display(), diff --git a/crates/cli/src/task.rs b/crates/cli/src/task.rs index b02d1fc..79718bf 100644 --- a/crates/cli/src/task.rs +++ b/crates/cli/src/task.rs @@ -3,14 +3,14 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::config::{AndromedaConfig, ConfigManager, TaskDefinition}; -use crate::error::AndromedaError; +use crate::error::CliError; use console::Style; use std::collections::HashSet; use std::path::Path; use std::process::{Command, Stdio}; /// Boxed result type to avoid large error variants -type Result = std::result::Result>; +type TaskResult = std::result::Result>; /// Task runner for executing defined tasks pub struct TaskRunner { @@ -25,7 +25,7 @@ impl TaskRunner { } /// List all available tasks - pub fn list_tasks(&self) -> Result<()> { + pub fn list_tasks(&self) -> TaskResult<()> { if self.config.tasks.is_empty() { println!("No tasks defined."); return Ok(()); @@ -62,14 +62,11 @@ impl TaskRunner { } /// Run a specific task - pub fn run_task(&self, task_name: &str) -> Result<()> { + pub fn run_task(&self, task_name: &str) -> TaskResult<()> { if !self.config.tasks.contains_key(task_name) { - return Err(Box::new(AndromedaError::runtime_error( + return Err(Box::new(CliError::task_error( format!("Task '{task_name}' not found"), - None, - None, - None, - None, + Some(task_name.to_string()), ))); } @@ -91,7 +88,7 @@ impl TaskRunner { } /// Resolve task dependencies and return execution order - fn resolve_task_dependencies(&self, task_name: &str) -> Result> { + fn resolve_task_dependencies(&self, task_name: &str) -> TaskResult> { let mut visited = HashSet::new(); let mut temp_visited = HashSet::new(); let mut execution_order = Vec::new(); @@ -113,14 +110,11 @@ impl TaskRunner { visited: &mut HashSet, temp_visited: &mut HashSet, execution_order: &mut Vec, - ) -> Result<()> { + ) -> TaskResult<()> { if temp_visited.contains(task_name) { - return Err(Box::new(AndromedaError::runtime_error( + return Err(Box::new(CliError::task_error( format!("Circular dependency detected involving task '{task_name}'"), - None, - None, - None, - None, + Some(task_name.to_string()), ))); } @@ -129,12 +123,9 @@ impl TaskRunner { } let task = self.config.tasks.get(task_name).ok_or_else(|| { - Box::new(AndromedaError::runtime_error( + Box::new(CliError::task_error( format!("Task '{task_name}' not found"), - None, - None, - None, - None, + Some(task_name.to_string()), )) })?; @@ -153,7 +144,7 @@ impl TaskRunner { } /// Execute a single task - fn execute_task(&self, task_name: &str, task: &TaskDefinition) -> Result<()> { + fn execute_task(&self, task_name: &str, task: &TaskDefinition) -> TaskResult<()> { let command_str = task.command(); // Set up working directory @@ -163,7 +154,7 @@ impl TaskRunner { self.config_dir.join(cwd) } else { std::env::current_dir().map_err(|e| { - Box::new(AndromedaError::config_error( + Box::new(CliError::config_error( "Failed to get current working directory".to_string(), None, Some(e), @@ -200,23 +191,17 @@ impl TaskRunner { // Execute the command let status = cmd.status().map_err(|e| { - Box::new(AndromedaError::runtime_error( + Box::new(CliError::task_error( format!("Failed to execute task '{task_name}': {e}"), - None, - None, - None, - None, + Some(task_name.to_string()), )) })?; if !status.success() { let exit_code = status.code().unwrap_or(-1); - return Err(Box::new(AndromedaError::runtime_error( + return Err(Box::new(CliError::task_error( format!("Task '{task_name}' failed with exit code {exit_code}"), - None, - None, - None, - None, + Some(task_name.to_string()), ))); } @@ -226,7 +211,7 @@ impl TaskRunner { } /// Run a task using the configuration found in the current directory -pub fn run_task(task_name: Option) -> Result<()> { +pub fn run_task(task_name: Option) -> TaskResult<()> { // Load configuration let config = ConfigManager::load_or_default(None); @@ -235,7 +220,7 @@ pub fn run_task(task_name: Option) -> Result<()> { config_path.parent().unwrap_or(Path::new(".")).to_path_buf() } else { std::env::current_dir().map_err(|e| { - Box::new(AndromedaError::config_error( + Box::new(CliError::config_error( "Failed to get current directory".to_string(), None, Some(e), diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index 3254788..a8f7470 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -10,7 +10,7 @@ use std::fmt; /// Comprehensive error type for Andromeda runtime operations #[derive(Diagnostic, Debug, Clone)] -pub enum AndromedaError { +pub enum RuntimeError { /// File system operation errors #[diagnostic( code(andromeda::fs::io_error), @@ -232,14 +232,14 @@ pub enum AndromedaError { }, } -impl AndromedaError { - /// Box this error for use with AndromedaResult +impl RuntimeError { + /// Box this error for use with RuntimeResult pub fn boxed(self) -> Box { Box::new(self) } /// Create a boxed error directly - pub fn into_result(self) -> AndromedaResult { + pub fn into_result(self) -> RuntimeResult { Err(Box::new(self)) } @@ -299,6 +299,7 @@ impl AndromedaError { } /// Create a new runtime error + #[allow(clippy::self_named_constructors)] pub fn runtime_error(message: impl Into) -> Self { Self::RuntimeError { message: message.into(), @@ -364,6 +365,7 @@ impl AndromedaError { execution_history: Vec::new(), } } + /// Create a new network error pub fn network_error( source: Box, @@ -406,28 +408,28 @@ impl AndromedaError { } } -impl fmt::Display for AndromedaError { +impl fmt::Display for RuntimeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - AndromedaError::FsError { + RuntimeError::FsError { operation, path, .. } => { write!(f, "File system error during {operation}: {path}") } - AndromedaError::ParseError { source_path, .. } => { + RuntimeError::ParseError { source_path, .. } => { write!(f, "Parse error in {source_path}") } - AndromedaError::RuntimeError { message, .. } => { + RuntimeError::RuntimeError { message, .. } => { write!(f, "Runtime error: {message}") } - AndromedaError::ExtensionError { + RuntimeError::ExtensionError { extension_name, message, .. } => { write!(f, "Extension '{extension_name}' error: {message}") } - AndromedaError::ResourceError { + RuntimeError::ResourceError { rid, operation, message, @@ -435,23 +437,23 @@ impl fmt::Display for AndromedaError { } => { write!(f, "Resource {rid} error during {operation}: {message}") } - AndromedaError::TaskError { + RuntimeError::TaskError { task_id, message, .. } => { write!(f, "Task {task_id} error: {message}") } - AndromedaError::NetworkError { url, operation, .. } => { + RuntimeError::NetworkError { url, operation, .. } => { write!(f, "Network error during {operation} for {url}") } - AndromedaError::EncodingError { + RuntimeError::EncodingError { format, message, .. } => { write!(f, "Encoding error ({format}): {message}") } - AndromedaError::ConfigError { field, message, .. } => { + RuntimeError::ConfigError { field, message, .. } => { write!(f, "Configuration error in field '{field}': {message}") } - AndromedaError::TypeError { + RuntimeError::TypeError { message, expected_type, actual_type, @@ -462,7 +464,7 @@ impl fmt::Display for AndromedaError { "Type error: {message} (expected {expected_type}, got {actual_type})" ) } - AndromedaError::MemoryError { + RuntimeError::MemoryError { message, operation, .. } => { write!(f, "Memory error during {operation}: {message}") @@ -471,34 +473,36 @@ impl fmt::Display for AndromedaError { } } -impl std::error::Error for AndromedaError {} +impl std::error::Error for RuntimeError {} /// Result type alias for Andromeda operations with boxed errors to reduce stack size -pub type AndromedaResult = Result>; +pub type RuntimeResult = Result>; + +// Keep the old names as aliases for backwards compatibility during migration +#[doc(hidden)] +#[deprecated(since = "0.2.0", note = "Use RuntimeError instead")] +pub type AndromedaError = RuntimeError; + +#[doc(hidden)] +#[deprecated(since = "0.2.0", note = "Use RuntimeResult instead")] +pub type AndromedaResult = RuntimeResult; /// Enhanced error reporting utilities with full miette integration +/// +/// This struct provides methods for printing and formatting RuntimeErrors +/// with rich visual output using miette. pub struct ErrorReporter; impl ErrorReporter { - /// Initialize miette with enhanced reporting capabilities + /// Initialize miette with enhanced reporting capabilities. + /// + /// This delegates to the shared error reporting module. pub fn init() { - let _ = oxc_miette::set_hook(Box::new(|_| { - Box::new( - oxc_miette::MietteHandlerOpts::new() - .terminal_links(true) - .unicode(true) - .color(true) - .context_lines(5) - .tab_width(4) - .force_graphical(true) - .width(120) - .build(), - ) - })); + crate::error_reporting::init_error_reporting_default(); } /// Print a formatted error with full miette reporting - pub fn print_error(error: &AndromedaError) { + pub fn print_error(error: &RuntimeError) { eprintln!(); eprintln!( "{} {}", @@ -510,7 +514,7 @@ impl ErrorReporter { } /// Print multiple errors with enhanced formatting - pub fn print_errors(errors: &[AndromedaError]) { + pub fn print_errors(errors: &[RuntimeError]) { eprintln!(); eprintln!( "{} {} ({} error{})", @@ -537,12 +541,12 @@ impl ErrorReporter { } /// Create a formatted error report as string with full context - pub fn format_error(error: &AndromedaError) -> String { + pub fn format_error(error: &RuntimeError) -> String { format!("{:?}", oxc_miette::Report::new(error.clone())) } /// Create a comprehensive error report with suggestions and related information - pub fn create_detailed_report(error: &AndromedaError) -> String { + pub fn create_detailed_report(error: &RuntimeError) -> String { let mut report = String::new(); // Header with emoji and color @@ -554,14 +558,14 @@ impl ErrorReporter { // Additional context based on error type match error { - AndromedaError::ParseError { errors, .. } => { + RuntimeError::ParseError { errors, .. } => { report.push_str(&format!("\n{} Parse Details:\n", "📝".bright_yellow())); report.push_str(&format!("Total errors found: {}\n", errors.len())); for (i, err) in errors.iter().enumerate() { report.push_str(&format!(" {}. {}\n", i + 1, err)); } } - AndromedaError::RuntimeError { + RuntimeError::RuntimeError { stack_trace: Some(stack), variable_context, .. @@ -582,7 +586,7 @@ impl ErrorReporter { } } } - AndromedaError::NetworkError { + RuntimeError::NetworkError { status_code: Some(code), request_headers, .. @@ -596,7 +600,7 @@ impl ErrorReporter { } } } - AndromedaError::MemoryError { + RuntimeError::MemoryError { memory_stats: Some(stats), heap_info: Some(heap), .. @@ -613,60 +617,60 @@ impl ErrorReporter { } } -/// Trait for converting various error types to AndromedaError -pub trait IntoAndromedaError { - fn into_andromeda_error(self) -> AndromedaResult; +/// Trait for converting various error types to RuntimeError +pub trait IntoRuntimeError { + fn into_runtime_error(self) -> RuntimeResult; } -impl IntoAndromedaError for Result { - fn into_andromeda_error(self) -> AndromedaResult { - self.map_err(|e| Box::new(AndromedaError::fs_error(e, "unknown", "unknown"))) +impl IntoRuntimeError for Result { + fn into_runtime_error(self) -> RuntimeResult { + self.map_err(|e| Box::new(RuntimeError::fs_error(e, "unknown", "unknown"))) } } /// Enhanced macros for quick error creation with location support #[macro_export] -macro_rules! andromeda_error { +macro_rules! runtime_error { // File system errors (fs: $op:expr, $path:expr, $source:expr) => { - $crate::AndromedaError::fs_error($source, $op, $path) + $crate::RuntimeError::fs_error($source, $op, $path) }; (fs: $op:expr, $path:expr, $source:expr, at $code:expr, $src_path:expr, $span:expr) => { - $crate::AndromedaError::fs_error_with_location($source, $op, $path, $code, $src_path, $span) + $crate::RuntimeError::fs_error_with_location($source, $op, $path, $code, $src_path, $span) }; // Runtime errors (runtime: $msg:expr) => { - $crate::AndromedaError::runtime_error($msg) + $crate::RuntimeError::runtime_error($msg) }; (runtime: $msg:expr, at $code:expr, $src_path:expr, $span:expr) => { - $crate::AndromedaError::runtime_error_with_location($msg, $code, $src_path, $span) + $crate::RuntimeError::runtime_error_with_location($msg, $code, $src_path, $span) }; (runtime: $msg:expr, with context $code:expr, $src_path:expr, $span:expr, stack $stack:expr, vars $vars:expr) => { - $crate::AndromedaError::runtime_error_with_context( + $crate::RuntimeError::runtime_error_with_context( $msg, $code, $src_path, $span, $stack, $vars, ) }; // Extension errors (extension: $name:expr, $msg:expr) => { - $crate::AndromedaError::extension_error($name, $msg) + $crate::RuntimeError::extension_error($name, $msg) }; (extension: $name:expr, $msg:expr, at $code:expr, $src_path:expr, $span:expr, missing $deps:expr) => { - $crate::AndromedaError::extension_error_with_context( + $crate::RuntimeError::extension_error_with_context( $name, $msg, $code, $src_path, $span, $deps, ) }; // Resource errors (resource: $rid:expr, $op:expr, $msg:expr) => { - $crate::AndromedaError::resource_error($rid, $op, $msg) + $crate::RuntimeError::resource_error($rid, $op, $msg) }; (resource: $rid:expr, $op:expr, $msg:expr, state $state:expr) => { - $crate::AndromedaError::resource_error_with_context($rid, $op, $msg, $state, None) + $crate::RuntimeError::resource_error_with_context($rid, $op, $msg, $state, None) }; (resource: $rid:expr, $op:expr, $msg:expr, state $state:expr, at $code:expr, $src_path:expr, $span:expr) => { - $crate::AndromedaError::resource_error_with_context( + $crate::RuntimeError::resource_error_with_context( $rid, $op, $msg, @@ -677,13 +681,13 @@ macro_rules! andromeda_error { // Task errors (task: $id:expr, $msg:expr) => { - $crate::AndromedaError::task_error($id, $msg) + $crate::RuntimeError::task_error($id, $msg) }; (task: $id:expr, $msg:expr, history $history:expr) => { - $crate::AndromedaError::task_error_with_history($id, $msg, $history, None) + $crate::RuntimeError::task_error_with_history($id, $msg, $history, None) }; (task: $id:expr, $msg:expr, history $history:expr, at $code:expr, $src_path:expr, $span:expr) => { - $crate::AndromedaError::task_error_with_history( + $crate::RuntimeError::task_error_with_history( $id, $msg, $history, @@ -693,15 +697,15 @@ macro_rules! andromeda_error { // Network errors (network: $source:expr, $url:expr, $op:expr) => { - $crate::AndromedaError::network_error($source, $url, $op) + $crate::RuntimeError::network_error($source, $url, $op) }; (network: $source:expr, $url:expr, $op:expr, status $status:expr, headers $headers:expr) => { - $crate::AndromedaError::network_error_with_context( + $crate::RuntimeError::network_error_with_context( $source, $url, $op, $status, $headers, None, ) }; (network: $source:expr, $url:expr, $op:expr, status $status:expr, headers $headers:expr, at $code:expr, $src_path:expr, $span:expr) => { - $crate::AndromedaError::network_error_with_context( + $crate::RuntimeError::network_error_with_context( $source, $url, $op, @@ -713,13 +717,13 @@ macro_rules! andromeda_error { // Encoding errors (encoding: $format:expr, $msg:expr) => { - $crate::AndromedaError::encoding_error($format, $msg) + $crate::RuntimeError::encoding_error($format, $msg) }; (encoding: $format:expr, $msg:expr, expected $expected:expr, actual $actual:expr) => { - $crate::AndromedaError::encoding_error_with_context($format, $msg, $expected, $actual, None) + $crate::RuntimeError::encoding_error_with_context($format, $msg, $expected, $actual, None) }; (encoding: $format:expr, $msg:expr, expected $expected:expr, actual $actual:expr, at $code:expr, $src_path:expr, $span:expr) => { - $crate::AndromedaError::encoding_error_with_context( + $crate::RuntimeError::encoding_error_with_context( $format, $msg, $expected, @@ -730,13 +734,13 @@ macro_rules! andromeda_error { // Configuration errors (config: $field:expr, $msg:expr) => { - $crate::AndromedaError::config_error($field, $msg) + $crate::RuntimeError::config_error($field, $msg) }; (config: $field:expr, $msg:expr, schema $schema:expr, fixes $fixes:expr) => { - $crate::AndromedaError::config_error_with_suggestions($field, $msg, None, $schema, $fixes) + $crate::RuntimeError::config_error_with_suggestions($field, $msg, None, $schema, $fixes) }; (config: $field:expr, $msg:expr, schema $schema:expr, fixes $fixes:expr, at $config:expr, $cfg_path:expr, $span:expr) => { - $crate::AndromedaError::config_error_with_suggestions( + $crate::RuntimeError::config_error_with_suggestions( $field, $msg, Some(($config, $cfg_path, $span)), @@ -747,10 +751,10 @@ macro_rules! andromeda_error { // Type errors (type_error: $msg:expr, expected $expected:expr, actual $actual:expr) => { - $crate::AndromedaError::type_error($msg, $expected, $actual) + $crate::RuntimeError::type_error($msg, $expected, $actual) }; (type_error: $msg:expr, expected $expected:expr, actual $actual:expr, suggestions $suggestions:expr) => { - $crate::AndromedaError::type_error_with_suggestions( + $crate::RuntimeError::type_error_with_suggestions( $msg, $expected, $actual, @@ -760,7 +764,7 @@ macro_rules! andromeda_error { ) }; (type_error: $msg:expr, expected $expected:expr, actual $actual:expr, suggestions $suggestions:expr, at $code:expr, $src_path:expr, $span:expr) => { - $crate::AndromedaError::type_error_with_suggestions( + $crate::RuntimeError::type_error_with_suggestions( $msg, $expected, $actual, @@ -772,13 +776,13 @@ macro_rules! andromeda_error { // Memory errors (memory: $msg:expr, $op:expr) => { - $crate::AndromedaError::memory_error($msg, $op) + $crate::RuntimeError::memory_error($msg, $op) }; (memory: $msg:expr, $op:expr, stats $stats:expr, heap $heap:expr) => { - $crate::AndromedaError::memory_error_with_stats($msg, $op, $stats, $heap, None) + $crate::RuntimeError::memory_error_with_stats($msg, $op, $stats, $heap, None) }; (memory: $msg:expr, $op:expr, stats $stats:expr, heap $heap:expr, at $code:expr, $src_path:expr, $span:expr) => { - $crate::AndromedaError::memory_error_with_stats( + $crate::RuntimeError::memory_error_with_stats( $msg, $op, $stats, @@ -788,6 +792,16 @@ macro_rules! andromeda_error { }; } +// Keep old macro name for backwards compatibility +#[macro_export] +#[doc(hidden)] +#[deprecated(since = "0.2.0", note = "Use runtime_error! instead")] +macro_rules! andromeda_error { + ($($tt:tt)*) => { + $crate::runtime_error!($($tt)*) + }; +} + /// Convenience macro for creating source spans #[macro_export] macro_rules! span { diff --git a/crates/core/src/error_reporting.rs b/crates/core/src/error_reporting.rs new file mode 100644 index 0000000..348a4fe --- /dev/null +++ b/crates/core/src/error_reporting.rs @@ -0,0 +1,206 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use miette::{MietteHandlerOpts, Report}; +use owo_colors::OwoColorize; +use std::sync::Once; + +use miette as oxc_miette; + +static INIT: Once = Once::new(); + +/// Configuration for error reporting +#[derive(Debug, Clone)] +pub struct ErrorReportingConfig { + /// Enable clickable terminal links for error codes/URLs + pub terminal_links: bool, + /// Use Unicode characters in error output + pub unicode: bool, + /// Enable colored output + pub color: bool, + /// Number of context lines to show around errors + pub context_lines: usize, + /// Tab width for source code display + pub tab_width: usize, + /// Force graphical error display + pub force_graphical: bool, + /// Maximum width for error output (None for terminal width) + pub width: Option, +} + +impl Default for ErrorReportingConfig { + fn default() -> Self { + Self { + terminal_links: true, + unicode: true, + color: true, + context_lines: 5, + tab_width: 4, + force_graphical: true, + width: Some(120), + } + } +} + +/// Initialize miette error reporting with the given configuration. +/// +/// This is safe to call multiple times - only the first call has effect. +/// Subsequent calls are no-ops. +/// +/// # Example +/// +/// ``` +/// use andromeda_core::{ErrorReportingConfig, init_error_reporting}; +/// +/// init_error_reporting(ErrorReportingConfig { +/// context_lines: 3, +/// ..Default::default() +/// }); +/// ``` +pub fn init_error_reporting(config: ErrorReportingConfig) { + INIT.call_once(|| { + let _ = oxc_miette::set_hook(Box::new(move |_| { + let mut opts = MietteHandlerOpts::new() + .terminal_links(config.terminal_links) + .unicode(config.unicode) + .color(config.color) + .context_lines(config.context_lines) + .tab_width(config.tab_width) + .force_graphical(config.force_graphical); + + if let Some(width) = config.width { + opts = opts.width(width); + } + + Box::new(opts.build()) + })); + }); +} + +/// Initialize error reporting with default configuration. +/// +/// This is a convenience function equivalent to: +/// ``` +/// use andromeda_core::{init_error_reporting, ErrorReportingConfig}; +/// +/// init_error_reporting(ErrorReportingConfig::default()); +/// ``` +pub fn init_error_reporting_default() { + init_error_reporting(ErrorReportingConfig::default()); +} + +/// Print a miette-compatible error with standard Andromeda formatting. +/// +/// The error is printed to stderr with a header and visual separator. +/// +/// # Example +/// +/// ``` +/// use andromeda_core::{print_error, RuntimeError}; +/// +/// let error = RuntimeError::runtime_error("Something went wrong"); +/// print_error(error); +/// ``` +pub fn print_error(error: E) +where + E: std::error::Error + miette::Diagnostic + Send + Sync + 'static, +{ + eprintln!(); + eprintln!( + "{} {}", + "🚨".red().bold(), + "Andromeda Error".bright_red().bold() + ); + eprintln!("{}", "─".repeat(50).red()); + eprintln!("{:?}", Report::new(error)); +} + +/// Print a cloneable miette-compatible error by reference. +/// +/// This variant accepts a reference and clones the error internally, +/// which is useful when you need to keep the original error. +pub fn print_error_ref(error: &E) +where + E: std::error::Error + miette::Diagnostic + Send + Sync + Clone + 'static, +{ + print_error(error.clone()); +} + +/// Format a miette-compatible error to a string. +/// +/// This is useful when you need to capture the error output for logging +/// or other purposes rather than printing directly to stderr. +/// +/// # Example +/// +/// ``` +/// use andromeda_core::{format_error, RuntimeError}; +/// +/// let error = RuntimeError::runtime_error("Something went wrong"); +/// let formatted = format_error(error); +/// println!("{}", formatted); +/// ``` +pub fn format_error(error: E) -> String +where + E: std::error::Error + miette::Diagnostic + Send + Sync + 'static, +{ + format!("{:?}", Report::new(error)) +} + +/// Format a cloneable miette-compatible error by reference. +pub fn format_error_ref(error: &E) -> String +where + E: std::error::Error + miette::Diagnostic + Send + Sync + Clone + 'static, +{ + format_error(error.clone()) +} + +/// Print multiple errors with enhanced formatting. +/// +/// When there are multiple errors, each is numbered and separated +/// for clarity. +/// +/// # Example +/// +/// ``` +/// use andromeda_core::{print_errors, RuntimeError}; +/// +/// let errors = vec![ +/// RuntimeError::runtime_error("First error"), +/// RuntimeError::runtime_error("Second error"), +/// ]; +/// print_errors(&errors); +/// ``` +pub fn print_errors(errors: &[E]) +where + E: std::error::Error + miette::Diagnostic + Send + Sync + Clone + 'static, +{ + if errors.is_empty() { + return; + } + + eprintln!(); + eprintln!( + "{} {} ({} error{})", + "🚨".red().bold(), + "Andromeda Errors".bright_red().bold(), + errors.len(), + if errors.len() == 1 { "" } else { "s" } + ); + eprintln!("{}", "─".repeat(50).red()); + + for (i, error) in errors.iter().enumerate() { + if errors.len() > 1 { + eprintln!(); + eprintln!( + "{} Error {} of {}:", + "📍".cyan(), + (i + 1).to_string().bright_cyan(), + errors.len().to_string().bright_cyan() + ); + eprintln!("{}", "─".repeat(30).cyan()); + } + eprintln!("{:?}", Report::new(error.clone())); + } +} diff --git a/crates/core/src/extension.rs b/crates/core/src/extension.rs index 087f2f7..f4d53a7 100644 --- a/crates/core/src/extension.rs +++ b/crates/core/src/extension.rs @@ -14,7 +14,7 @@ use nova_vm::{ engine::context::{Bindable, GcScope}, }; -use crate::{AndromedaError, HostData, OpsStorage, exit_with_parse_errors, print_enhanced_error}; +use crate::{HostData, OpsStorage, RuntimeError, exit_with_parse_errors, print_enhanced_error}; pub type ExtensionStorageInit = Box; @@ -86,7 +86,7 @@ impl Extension { .as_str(agent) .unwrap_or("") .to_string(); - let err = AndromedaError::runtime_error(message); + let err = RuntimeError::runtime_error(message); print_enhanced_error(&err); } } diff --git a/crates/core/src/helper.rs b/crates/core/src/helper.rs index 6ed1146..884b35f 100644 --- a/crates/core/src/helper.rs +++ b/crates/core/src/helper.rs @@ -4,7 +4,7 @@ use oxc_diagnostics::OxcDiagnostic; -use crate::{AndromedaError, ErrorReporter}; +use crate::{ErrorReporter, RuntimeError}; /// Initialize enhanced error reporting system pub fn init_error_system() { @@ -15,19 +15,19 @@ pub fn init_error_system() { pub fn exit_with_parse_errors(errors: Vec, source_path: &str, source: &str) -> ! { assert!(!errors.is_empty()); - let parse_error = AndromedaError::parse_error(errors, source_path, source); + let parse_error = RuntimeError::parse_error(errors, source_path, source); ErrorReporter::print_error(&parse_error); std::process::exit(1); } /// Exit the program with a formatted Andromeda error -pub fn exit_with_error(error: AndromedaError) -> ! { +pub fn exit_with_error(error: RuntimeError) -> ! { ErrorReporter::print_error(&error); std::process::exit(1); } /// Exit the program with multiple errors -pub fn exit_with_errors(errors: Vec) -> ! { +pub fn exit_with_errors(errors: Vec) -> ! { ErrorReporter::print_errors(&errors); std::process::exit(1); } @@ -38,21 +38,21 @@ pub fn create_parse_error_report( source_path: &str, source: &str, ) -> String { - let parse_error = AndromedaError::parse_error(errors, source_path, source); + let parse_error = RuntimeError::parse_error(errors, source_path, source); ErrorReporter::create_detailed_report(&parse_error) } /// Create a comprehensive error report with full miette integration -pub fn create_comprehensive_error_report(error: &AndromedaError) -> String { +pub fn create_comprehensive_error_report(error: &RuntimeError) -> String { ErrorReporter::create_detailed_report(error) } /// Print an error with enhanced formatting and context -pub fn print_enhanced_error(error: &AndromedaError) { +pub fn print_enhanced_error(error: &RuntimeError) { ErrorReporter::print_error(error); } /// Format an error as a string with full miette reporting -pub fn format_enhanced_error(error: &AndromedaError) -> String { +pub fn format_enhanced_error(error: &RuntimeError) -> String { ErrorReporter::format_error(error) } diff --git a/crates/core/src/host_data.rs b/crates/core/src/host_data.rs index a0075a9..7d52858 100644 --- a/crates/core/src/host_data.rs +++ b/crates/core/src/host_data.rs @@ -16,7 +16,7 @@ use std::{ use anymap::AnyMap; use tokio::task::JoinHandle; -use crate::{AndromedaError, AndromedaResult, MacroTask, TaskId}; +use crate::{MacroTask, RuntimeError, RuntimeResult, TaskId}; pub type OpsStorage = AnyMap; @@ -89,11 +89,11 @@ impl HostData { } /// Abort a MacroTask execution given it's [TaskId] with proper error handling. - pub fn abort_macro_task_safe(&self, task_id: TaskId) -> AndromedaResult<()> { + pub fn abort_macro_task_safe(&self, task_id: TaskId) -> RuntimeResult<()> { let tasks = self.tasks.borrow(); let task = tasks .get(&task_id) - .ok_or_else(|| AndromedaError::task_error(task_id.index(), "Task not found"))?; + .ok_or_else(|| RuntimeError::task_error(task_id.index(), "Task not found"))?; task.abort(); // Manually decrease the macro tasks counter as the task was aborted. @@ -102,11 +102,11 @@ impl HostData { } /// Clear a MacroTask given it's [TaskId] with proper error handling. - pub fn clear_macro_task_safe(&self, task_id: TaskId) -> AndromedaResult<()> { + pub fn clear_macro_task_safe(&self, task_id: TaskId) -> RuntimeResult<()> { self.tasks .borrow_mut() .remove(&task_id) - .ok_or_else(|| AndromedaError::task_error(task_id.index(), "Task not found"))?; + .ok_or_else(|| RuntimeError::task_error(task_id.index(), "Task not found"))?; Ok(()) } } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index f0465d9..aef255d 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -3,6 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. mod error; +mod error_reporting; mod event_loop; mod extension; mod helper; @@ -14,6 +15,7 @@ mod sync_resource_table; mod task; pub use error::*; +pub use error_reporting::*; pub use event_loop::*; pub use extension::*; pub use helper::*; diff --git a/crates/core/src/resource_table.rs b/crates/core/src/resource_table.rs index 006b100..03b12c4 100644 --- a/crates/core/src/resource_table.rs +++ b/crates/core/src/resource_table.rs @@ -8,7 +8,7 @@ use std::{ hash::Hash, }; -use crate::{AndromedaError, AndromedaResult}; +use crate::{RuntimeError, RuntimeResult}; #[derive(Debug, Clone, Copy, PartialEq, Hash, Eq)] pub struct Rid(u32); @@ -31,9 +31,9 @@ impl ResourceTable { } /// Get a clone of the resource by Rid with proper error handling. - pub fn get_or_error(&self, rid: Rid, operation: &str) -> AndromedaResult { + pub fn get_or_error(&self, rid: Rid, operation: &str) -> RuntimeResult { self.table.borrow().get(&rid).cloned().ok_or_else(|| { - Box::new(AndromedaError::resource_error( + Box::new(RuntimeError::resource_error( rid.index(), operation, "Resource not found", diff --git a/crates/core/src/runtime.rs b/crates/core/src/runtime.rs index 9b066c6..3e8414e 100644 --- a/crates/core/src/runtime.rs +++ b/crates/core/src/runtime.rs @@ -41,7 +41,7 @@ use nova_vm::{ }; use crate::{ - AndromedaError, AndromedaResult, Extension, HostData, MacroTask, exit_with_parse_errors, + Extension, HostData, MacroTask, RuntimeError, RuntimeResult, exit_with_parse_errors, module::ImportMap, }; @@ -540,13 +540,13 @@ pub enum RuntimeFile { } impl RuntimeFile { - fn read(&self) -> AndromedaResult { + fn read(&self) -> RuntimeResult { match self { RuntimeFile::Embedded { path: _, content } => { Ok(String::from_utf8_lossy(content).into_owned()) } RuntimeFile::Local { path } => std::fs::read_to_string(path) - .map_err(|e| Box::new(AndromedaError::fs_error(e, "read", path))), + .map_err(|e| Box::new(RuntimeError::fs_error(e, "read", path))), } } @@ -557,13 +557,13 @@ impl RuntimeFile { } } - fn validate(&self) -> AndromedaResult<()> { + fn validate(&self) -> RuntimeResult<()> { match self { RuntimeFile::Embedded { .. } => Ok(()), RuntimeFile::Local { path } => { let path_obj = std::path::Path::new(path); if !path_obj.exists() { - return Err(Box::new(AndromedaError::fs_error( + return Err(Box::new(RuntimeError::fs_error( std::io::Error::new( std::io::ErrorKind::NotFound, format!("File not found: {path}"), @@ -573,7 +573,7 @@ impl RuntimeFile { ))); } if !path_obj.is_file() { - return Err(Box::new(AndromedaError::fs_error( + return Err(Box::new(RuntimeError::fs_error( std::io::Error::new( std::io::ErrorKind::InvalidInput, format!("Path is not a file: {path}"), @@ -583,7 +583,7 @@ impl RuntimeFile { ))); } std::fs::File::open(path) - .map_err(|e| AndromedaError::fs_error(e, "validate", path))?; + .map_err(|e| RuntimeError::fs_error(e, "validate", path))?; Ok(()) } } diff --git a/crates/core/src/sync_resource_table.rs b/crates/core/src/sync_resource_table.rs index 29aab30..7e76b3c 100644 --- a/crates/core/src/sync_resource_table.rs +++ b/crates/core/src/sync_resource_table.rs @@ -10,7 +10,7 @@ use std::{ }, }; -use crate::{AndromedaError, AndromedaResult, Rid}; +use crate::{Rid, RuntimeError, RuntimeResult}; // Allow retrieving resources; requires T: Clone impl SyncResourceTable { @@ -20,14 +20,14 @@ impl SyncResourceTable { } /// Get a clone of the resource by Rid with proper error handling. - pub fn get_or_error(&self, rid: Rid, operation: &str) -> AndromedaResult { + pub fn get_or_error(&self, rid: Rid, operation: &str) -> RuntimeResult { self.table .lock() .unwrap() .get(&rid) .cloned() .ok_or_else(|| { - Box::new(AndromedaError::resource_error( + Box::new(RuntimeError::resource_error( rid.index(), operation, "Resource not found", diff --git a/crates/runtime/src/ext/console/mod.rs b/crates/runtime/src/ext/console/mod.rs index 5a604ff..849382e 100644 --- a/crates/runtime/src/ext/console/mod.rs +++ b/crates/runtime/src/ext/console/mod.rs @@ -6,7 +6,7 @@ use std::collections::HashMap; use std::io::{Write, stderr, stdout}; use std::time::{SystemTime, UNIX_EPOCH}; -use andromeda_core::{AndromedaError, ErrorReporter, Extension, ExtensionOp, HostData, OpsStorage}; +use andromeda_core::{ErrorReporter, Extension, ExtensionOp, HostData, OpsStorage, RuntimeError}; use nova_vm::{ ecmascript::{ builtins::ArgumentsList, @@ -74,11 +74,11 @@ impl ConsoleExt { .expect("String is not valid UTF-8") .as_bytes(), ) { - let error = AndromedaError::runtime_error(format!("Failed to write to stdout: {e}")); + let error = RuntimeError::runtime_error(format!("Failed to write to stdout: {e}")); ErrorReporter::print_error(&error); } if let Err(e) = stdout().flush() { - let error = AndromedaError::runtime_error(format!("Failed to flush stdout: {e}")); + let error = RuntimeError::runtime_error(format!("Failed to flush stdout: {e}")); ErrorReporter::print_error(&error); } Ok(Value::Undefined) @@ -99,11 +99,11 @@ impl ConsoleExt { .expect("String is not valid UTF-8") .as_bytes(), ) { - let error = AndromedaError::runtime_error(format!("Failed to write to stderr: {e}")); + let error = RuntimeError::runtime_error(format!("Failed to write to stderr: {e}")); ErrorReporter::print_error(&error); } if let Err(e) = stderr().flush() { - let error = AndromedaError::runtime_error(format!("Failed to flush stderr: {e}")); + let error = RuntimeError::runtime_error(format!("Failed to flush stderr: {e}")); ErrorReporter::print_error(&error); } Ok(Value::Undefined) @@ -386,7 +386,7 @@ impl ConsoleExt { match storage.get::() { Some(console_storage) => console_storage.group_indent_level, None => { - let error = AndromedaError::runtime_error( + let error = RuntimeError::runtime_error( "Console storage missing when querying group indent; defaulting to 0" .to_string(), ); @@ -465,7 +465,7 @@ impl ConsoleExt { // ANSI escape sequence to clear screen print!("\x1B[2J\x1B[H"); if let Err(e) = stdout().flush() { - let error = AndromedaError::runtime_error(format!("Failed to flush stdout: {e}")); + let error = RuntimeError::runtime_error(format!("Failed to flush stdout: {e}")); ErrorReporter::print_error(&error); } Ok(Value::Undefined) @@ -494,8 +494,7 @@ impl ConsoleExt { Ok(Value::from_string(agent, input.trim_end().to_string(), gc.nogc()).unbind()) } Err(e) => { - let error = - AndromedaError::runtime_error(format!("Failed to read from stdin: {e}")); + let error = RuntimeError::runtime_error(format!("Failed to read from stdin: {e}")); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -516,7 +515,7 @@ impl ConsoleExt { } Err(e) => { let error = - AndromedaError::runtime_error(format!("Failed to read line from stdin: {e}")); + RuntimeError::runtime_error(format!("Failed to read line from stdin: {e}")); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } diff --git a/crates/runtime/src/ext/fs.rs b/crates/runtime/src/ext/fs.rs index 9e0e1db..af77167 100644 --- a/crates/runtime/src/ext/fs.rs +++ b/crates/runtime/src/ext/fs.rs @@ -26,8 +26,8 @@ use nova_vm::{ }; use andromeda_core::{ - AndromedaError, ErrorReporter, Extension, ExtensionOp, HostData, MacroTask, OpsStorage, - ResourceTable, + ErrorReporter, Extension, ExtensionOp, HostData, MacroTask, OpsStorage, ResourceTable, + RuntimeError, }; use crate::RuntimeMacroTask; @@ -187,7 +187,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "read_text_file", path); + let error = RuntimeError::fs_error(e, "read_text_file", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -198,7 +198,7 @@ impl FsExt { match std::fs::read_to_string(&resolved_path) { Ok(content) => Ok(Value::from_string(agent, content, gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error(e, "read_text_file", path); + let error = RuntimeError::fs_error(e, "read_text_file", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -224,7 +224,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "write_text_file", path); + let error = RuntimeError::fs_error(e, "write_text_file", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -238,7 +238,7 @@ impl FsExt { ) { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error( + let error = RuntimeError::fs_error( e, "write_text_file", binding.as_str(agent).expect("String is not valid UTF-8"), @@ -261,7 +261,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "create_file", path); + let error = RuntimeError::fs_error(e, "create_file", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -272,7 +272,7 @@ impl FsExt { let file = match File::create(&resolved_path) { Ok(file) => file, Err(e) => { - let error = AndromedaError::fs_error(e, "create_file", path); + let error = RuntimeError::fs_error(e, "create_file", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -307,7 +307,7 @@ impl FsExt { let resolved_from = match resolve_path(from_path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "copy_file", from_path); + let error = RuntimeError::fs_error(e, "copy_file", from_path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -318,7 +318,7 @@ impl FsExt { let resolved_to = match resolve_path(to_path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "copy_file", to_path); + let error = RuntimeError::fs_error(e, "copy_file", to_path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -329,7 +329,7 @@ impl FsExt { match std::fs::copy(&resolved_from, &resolved_to) { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error( + let error = RuntimeError::fs_error( e, "copy_file", format!( @@ -356,7 +356,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "create_directory", path); + let error = RuntimeError::fs_error(e, "create_directory", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -367,7 +367,7 @@ impl FsExt { match std::fs::create_dir(&resolved_path) { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error(e, "create_directory", path); + let error = RuntimeError::fs_error(e, "create_directory", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -386,7 +386,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "create_dir_all", path); + let error = RuntimeError::fs_error(e, "create_dir_all", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -397,7 +397,7 @@ impl FsExt { match std::fs::create_dir_all(&resolved_path) { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error(e, "create_dir_all", path); + let error = RuntimeError::fs_error(e, "create_dir_all", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -417,7 +417,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "read_file", path); + let error = RuntimeError::fs_error(e, "read_file", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -437,7 +437,7 @@ impl FsExt { Ok(Value::from_string(agent, hex_content, gc.nogc()).unbind()) } Err(e) => { - let error = AndromedaError::fs_error(e, "read_file", path); + let error = RuntimeError::fs_error(e, "read_file", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -470,7 +470,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "write_file", path); + let error = RuntimeError::fs_error(e, "write_file", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -485,7 +485,7 @@ impl FsExt { match std::fs::write(&resolved_path, content) { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error(e, "write_file", path); + let error = RuntimeError::fs_error(e, "write_file", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -505,7 +505,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "stat", path); + let error = RuntimeError::fs_error(e, "stat", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -519,7 +519,7 @@ impl FsExt { Ok(Value::from_string(agent, stat_info, gc.nogc()).unbind()) } Err(e) => { - let error = AndromedaError::fs_error(e, "stat", path); + let error = RuntimeError::fs_error(e, "stat", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -539,7 +539,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "lstat", path); + let error = RuntimeError::fs_error(e, "lstat", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -553,7 +553,7 @@ impl FsExt { Ok(Value::from_string(agent, stat_info, gc.nogc()).unbind()) } Err(e) => { - let error = AndromedaError::fs_error(e, "lstat", path); + let error = RuntimeError::fs_error(e, "lstat", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -573,7 +573,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "read_dir", path); + let error = RuntimeError::fs_error(e, "read_dir", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -613,7 +613,7 @@ impl FsExt { Ok(Value::from_string(agent, result, gc.nogc()).unbind()) } Err(e) => { - let error = AndromedaError::fs_error(e, "read_dir", path); + let error = RuntimeError::fs_error(e, "read_dir", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -633,7 +633,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "remove", path); + let error = RuntimeError::fs_error(e, "remove", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -650,7 +650,7 @@ impl FsExt { match result { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error(e, "remove", path); + let error = RuntimeError::fs_error(e, "remove", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -670,7 +670,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "remove_all", path); + let error = RuntimeError::fs_error(e, "remove_all", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -687,7 +687,7 @@ impl FsExt { match result { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error(e, "remove_all", path); + let error = RuntimeError::fs_error(e, "remove_all", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -710,7 +710,7 @@ impl FsExt { let resolved_from = match resolve_path(from_path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "rename", from_path); + let error = RuntimeError::fs_error(e, "rename", from_path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -721,7 +721,7 @@ impl FsExt { let resolved_to = match resolve_path(to_path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "rename", to_path); + let error = RuntimeError::fs_error(e, "rename", to_path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -732,7 +732,7 @@ impl FsExt { match std::fs::rename(&resolved_from, &resolved_to) { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error( + let error = RuntimeError::fs_error( e, "rename", format!( @@ -806,7 +806,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "truncate", path); + let error = RuntimeError::fs_error(e, "truncate", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -819,7 +819,7 @@ impl FsExt { Ok(f) => match f.set_len(len) { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error(e, "truncate", path); + let error = RuntimeError::fs_error(e, "truncate", path); let error_msg = ErrorReporter::format_error(&error); Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()) @@ -828,7 +828,7 @@ impl FsExt { } }, Err(e) => { - let error = AndromedaError::fs_error(e, "truncate", path); + let error = RuntimeError::fs_error(e, "truncate", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -876,7 +876,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "chmod", path); + let error = RuntimeError::fs_error(e, "chmod", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()) @@ -889,7 +889,7 @@ impl FsExt { match std::fs::set_permissions(&resolved_path, permissions) { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error(e, "chmod", path); + let error = RuntimeError::fs_error(e, "chmod", path); let error_msg = ErrorReporter::format_error(&error); Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()) @@ -928,7 +928,7 @@ impl FsExt { let resolved_target = match resolve_path(target_path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "symlink", target_path); + let error = RuntimeError::fs_error(e, "symlink", target_path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -939,7 +939,7 @@ impl FsExt { let resolved_link = match resolve_path(link_path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "symlink", link_path); + let error = RuntimeError::fs_error(e, "symlink", link_path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -952,7 +952,7 @@ impl FsExt { match std::os::unix::fs::symlink(&resolved_target, &resolved_link) { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error( + let error = RuntimeError::fs_error( e, "symlink", format!( @@ -982,7 +982,7 @@ impl FsExt { match result { Ok(_) => Ok(Value::from_string(agent, "Success".to_string(), gc.nogc()).unbind()), Err(e) => { - let error = AndromedaError::fs_error( + let error = RuntimeError::fs_error( e, "symlink", format!( @@ -1014,7 +1014,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "read_link", path); + let error = RuntimeError::fs_error(e, "read_link", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -1028,7 +1028,7 @@ impl FsExt { Ok(Value::from_string(agent, target_str, gc.nogc()).unbind()) } Err(e) => { - let error = AndromedaError::fs_error(e, "read_link", path); + let error = RuntimeError::fs_error(e, "read_link", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -1048,7 +1048,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "real_path", path); + let error = RuntimeError::fs_error(e, "real_path", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -1062,7 +1062,7 @@ impl FsExt { Ok(Value::from_string(agent, path_str, gc.nogc()).unbind()) } Err(e) => { - let error = AndromedaError::fs_error(e, "real_path", path); + let error = RuntimeError::fs_error(e, "real_path", path); let error_msg = ErrorReporter::format_error(&error); Ok(Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind()) } @@ -1082,7 +1082,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "open_file", path); + let error = RuntimeError::fs_error(e, "open_file", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -1093,7 +1093,7 @@ impl FsExt { let file = match File::open(&resolved_path) { Ok(file) => file, Err(e) => { - let error = AndromedaError::fs_error(e, "open_file", path); + let error = RuntimeError::fs_error(e, "open_file", path); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -1164,7 +1164,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "read_text_file_async", path); + let error = RuntimeError::fs_error(e, "read_text_file_async", path); let error_msg = ErrorReporter::format_error(&error); let promise_capability = PromiseCapability::new(agent, gc.nogc()); let root_value = @@ -1201,7 +1201,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "read_text_file_async", &path_string); + let error = RuntimeError::fs_error(e, "read_text_file_async", &path_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( @@ -1243,7 +1243,7 @@ impl FsExt { let resolved_path = match resolve_path(path) { Ok(p) => p, Err(e) => { - let error = AndromedaError::fs_error(e, "write_text_file_async", path); + let error = RuntimeError::fs_error(e, "write_text_file_async", path); let error_msg = ErrorReporter::format_error(&error); let promise_capability = PromiseCapability::new(agent, gc.nogc()); let root_value = @@ -1281,7 +1281,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "write_text_file_async", &path_string); + let error = RuntimeError::fs_error(e, "write_text_file_async", &path_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( @@ -1326,7 +1326,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "read_file_async", &path_string); + let error = RuntimeError::fs_error(e, "read_file_async", &path_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( @@ -1387,7 +1387,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "write_file_async", &path_string); + let error = RuntimeError::fs_error(e, "write_file_async", &path_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( @@ -1442,7 +1442,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error( + let error = RuntimeError::fs_error( e, "copy_file_async", format!("{from_string} -> {to_string}"), @@ -1498,7 +1498,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "remove_async", &path_string); + let error = RuntimeError::fs_error(e, "remove_async", &path_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( @@ -1544,7 +1544,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "create_file_async", &path_string); + let error = RuntimeError::fs_error(e, "create_file_async", &path_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( @@ -1587,7 +1587,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "mk_dir_async", &path_string); + let error = RuntimeError::fs_error(e, "mk_dir_async", &path_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( @@ -1630,7 +1630,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "mk_dir_all_async", &path_string); + let error = RuntimeError::fs_error(e, "mk_dir_all_async", &path_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( @@ -1711,7 +1711,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "rename_async", &from_string); + let error = RuntimeError::fs_error(e, "rename_async", &from_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( @@ -1764,7 +1764,7 @@ impl FsExt { .unwrap(); } Err(e) => { - let error = AndromedaError::fs_error(e, "remove_all_async", &path_string); + let error = RuntimeError::fs_error(e, "remove_all_async", &path_string); let error_msg = ErrorReporter::format_error(&error); macro_task_tx .send(MacroTask::User(RuntimeMacroTask::RejectPromise( diff --git a/crates/runtime/src/ext/process.rs b/crates/runtime/src/ext/process.rs index 8be2919..5b7bc90 100644 --- a/crates/runtime/src/ext/process.rs +++ b/crates/runtime/src/ext/process.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use andromeda_core::{AndromedaError, ErrorReporter, Extension, ExtensionOp, HostData, OpsStorage}; +use andromeda_core::{ErrorReporter, Extension, ExtensionOp, HostData, OpsStorage, RuntimeError}; use nova_vm::{ ecmascript::{ builtins::{ArgumentsList, Array}, @@ -112,7 +112,7 @@ impl ProcessExt { } Err(env::VarError::NotPresent) => Ok(Value::Undefined), Err(env::VarError::NotUnicode(_)) => { - let error = AndromedaError::encoding_error( + let error = RuntimeError::encoding_error( "UTF-8", format!("Environment variable '{key_str}' contains invalid Unicode"), ); @@ -195,7 +195,7 @@ impl ProcessExt { .expect("String is not valid UTF-8"); let callback = args.get(1); if !callback.is_function() { - let error = AndromedaError::runtime_error("Callback must be a function"); + let error = RuntimeError::runtime_error("Callback must be a function"); let error_msg = ErrorReporter::format_error(&error); return Ok( Value::from_string(agent, format!("Error: {error_msg}"), gc.nogc()).unbind(), @@ -225,7 +225,7 @@ impl ProcessExt { let error_msg = format!( "Signal '{signal_name_str}' is not supported on Windows. Only SIGINT and SIGBREAK are supported." ); - let error = AndromedaError::runtime_error(error_msg); + let error = RuntimeError::runtime_error(error_msg); let error_formatted = ErrorReporter::format_error(&error); return Ok(Value::from_string( agent, @@ -237,7 +237,7 @@ impl ProcessExt { #[cfg(unix)] { let error_msg = format!("Unsupported signal: {signal_name_str}"); - let error = AndromedaError::runtime_error(error_msg); + let error = RuntimeError::runtime_error(error_msg); let error_formatted = ErrorReporter::format_error(&error); return Ok(Value::from_string( agent,