feat: add File.tryRead, File.tryWrite, File.tryDelete returning Result
Add safe variants of File operations that return Result<T, String> instead of crashing with RuntimeError. This prevents server crashes when a file is missing or unwritable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3991,6 +3991,72 @@ impl Interpreter {
|
||||
}
|
||||
}
|
||||
|
||||
// ===== File Effect (safe Result-returning variants) =====
|
||||
("File", "tryRead") => {
|
||||
let path = match request.args.first() {
|
||||
Some(Value::String(s)) => s.clone(),
|
||||
_ => return Err(RuntimeError {
|
||||
message: "File.tryRead requires a string path".to_string(),
|
||||
span: None,
|
||||
}),
|
||||
};
|
||||
match std::fs::read_to_string(&path) {
|
||||
Ok(content) => Ok(Value::Constructor {
|
||||
name: "Ok".to_string(),
|
||||
fields: vec![Value::String(content)],
|
||||
}),
|
||||
Err(e) => Ok(Value::Constructor {
|
||||
name: "Err".to_string(),
|
||||
fields: vec![Value::String(format!("Failed to read file '{}': {}", path, e))],
|
||||
}),
|
||||
}
|
||||
}
|
||||
("File", "tryWrite") => {
|
||||
let path = match request.args.first() {
|
||||
Some(Value::String(s)) => s.clone(),
|
||||
_ => return Err(RuntimeError {
|
||||
message: "File.tryWrite requires a string path".to_string(),
|
||||
span: None,
|
||||
}),
|
||||
};
|
||||
let content = match request.args.get(1) {
|
||||
Some(Value::String(s)) => s.clone(),
|
||||
_ => return Err(RuntimeError {
|
||||
message: "File.tryWrite requires string content".to_string(),
|
||||
span: None,
|
||||
}),
|
||||
};
|
||||
match std::fs::write(&path, &content) {
|
||||
Ok(()) => Ok(Value::Constructor {
|
||||
name: "Ok".to_string(),
|
||||
fields: vec![Value::Unit],
|
||||
}),
|
||||
Err(e) => Ok(Value::Constructor {
|
||||
name: "Err".to_string(),
|
||||
fields: vec![Value::String(format!("Failed to write file '{}': {}", path, e))],
|
||||
}),
|
||||
}
|
||||
}
|
||||
("File", "tryDelete") => {
|
||||
let path = match request.args.first() {
|
||||
Some(Value::String(s)) => s.clone(),
|
||||
_ => return Err(RuntimeError {
|
||||
message: "File.tryDelete requires a string path".to_string(),
|
||||
span: None,
|
||||
}),
|
||||
};
|
||||
match std::fs::remove_file(&path) {
|
||||
Ok(()) => Ok(Value::Constructor {
|
||||
name: "Ok".to_string(),
|
||||
fields: vec![Value::Unit],
|
||||
}),
|
||||
Err(e) => Ok(Value::Constructor {
|
||||
name: "Err".to_string(),
|
||||
fields: vec![Value::String(format!("Failed to delete file '{}': {}", path, e))],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Process Effect =====
|
||||
("Process", "exec") => {
|
||||
use std::process::Command;
|
||||
|
||||
Reference in New Issue
Block a user