use servo::Preferences;
pub fn apply_pref_overrides(overrides: &[(String, String)]) -> Result<(), String> {
if overrides.is_empty() {
return Ok(());
}
let merged = apply_pref_overrides_to(servo::prefs::get().clone(), overrides)?;
servo::prefs::set(merged);
Ok(())
}
pub fn apply_pref_overrides_to(
mut preferences: Preferences,
overrides: &[(String, String)],
) -> Result<Preferences, String> {
if overrides.is_empty() {
return Ok(preferences);
}
let mut value = serde_json::to_value(&preferences)
.map_err(|e| format!("serializing builder prefs failed: {e}"))?;
let serde_json::Value::Object(ref mut map) = value else {
return Err("prefs did not serialize to a JSON object".into());
};
for (key, raw) in overrides {
let coerced = match raw.as_str() {
"true" => serde_json::Value::Bool(true),
"false" => serde_json::Value::Bool(false),
other => other
.parse::<f64>()
.ok()
.and_then(serde_json::Number::from_f64)
.map(serde_json::Value::Number)
.unwrap_or_else(|| serde_json::Value::String(other.to_string())),
};
map.insert(key.clone(), coerced);
}
preferences = serde_json::from_value(value)
.map_err(|e| format!("pref overrides do not match the Preferences schema: {e}"))?;
Ok(preferences)
}
pub fn load_prefs_file(path: &str) -> Result<Vec<(String, String)>, String> {
let raw = std::fs::read_to_string(path)
.map_err(|e| format!("reading prefs file {path} failed: {e}"))?;
let parsed: serde_json::Value =
serde_json::from_str(&raw).map_err(|e| format!("parsing prefs file {path} failed: {e}"))?;
let serde_json::Value::Object(map) = parsed else {
return Err(format!("prefs file {path} is not a JSON object"));
};
Ok(map
.into_iter()
.map(|(key, value)| {
let raw = match value {
serde_json::Value::Bool(true) => "true".to_string(),
serde_json::Value::Bool(false) => "false".to_string(),
serde_json::Value::Number(number) => number.to_string(),
serde_json::Value::String(string) => string,
other => other.to_string(),
};
(key, raw)
})
.collect())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bool_override_flips_pref() {
let mut prefs = Preferences::default();
assert!(!prefs.dom_exec_command_enabled);
prefs = apply_pref_overrides_to(
prefs,
&[("dom_exec_command_enabled".to_string(), "true".to_string())],
)
.expect("bool override must apply");
assert!(prefs.dom_exec_command_enabled);
}
#[test]
fn schema_mismatch_name_is_noop() {
let prefs = apply_pref_overrides_to(
Preferences::default(),
&[("no_such_pref_name".to_string(), "true".to_string())],
)
.expect("unknown pref name is a serde no-op, not an error");
assert!(!prefs.dom_exec_command_enabled);
}
#[test]
fn empty_overrides_are_identity() {
let prefs = apply_pref_overrides_to(Preferences::default(), &[])
.expect("empty override list must pass through");
assert!(!prefs.dom_exec_command_enabled);
}
}