use std::path::Path;
use serde_json::{Map, Value};
use crate::error::AgentConfigError;
use crate::util::fs_atomic;
pub(crate) fn read_or_empty(path: &Path) -> Result<Value, AgentConfigError> {
let text = fs_atomic::read_to_string_or_empty(path)?;
if text.trim().is_empty() {
return Ok(Value::Object(Map::new()));
}
json5::from_str::<Value>(&text).map_err(|e| {
AgentConfigError::Other(anyhow::anyhow!(
"invalid JSON5 in {}: {}",
path.display(),
e
))
})
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
use tempfile::tempdir;
#[test]
fn reads_json5_with_comments_and_unquoted_keys() {
let dir = tempdir().unwrap();
let path = dir.path().join("openclaw.json");
std::fs::write(
&path,
r#"{
// OpenClaw accepts JSON5
mcp: { servers: { docs: { url: 'https://example.com' } } },
}
"#,
)
.unwrap();
let root = read_or_empty(&path).unwrap();
assert_eq!(
root["mcp"]["servers"]["docs"]["url"],
json!("https://example.com")
);
}
#[test]
fn missing_file_is_empty_object() {
let dir = tempdir().unwrap();
let root = read_or_empty(&dir.path().join("missing.json")).unwrap();
assert_eq!(root, Value::Object(Map::new()));
}
}