fix(config): accept integer 0/1 for bool fields in RawWiki deserialization
VimL dicts serialise boolean-like settings such as `auto_export = 1` as the JSON number `1`, not `true`. serde's default `Option<bool>` deserializer rejects that, causing `serde_json::from_value::<InitOptions>` to return `Err` and `.ok()` to silently discard the entire wikis list. The server then fell back to `wiki_root` and could not resolve per-wiki links, marking every cross-wiki link as broken. Add an `opt_bool_or_int` serde helper that accepts JSON bool, `null`, or integers (0 = false, non-zero = true), and apply it to `auto_export`, `html_filename_parameterization`, `listsyms_propagate`, and `auto_toc` in `RawWiki`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -389,6 +389,39 @@ impl Config {
|
||||
|
||||
// ===== Wire schema =====
|
||||
|
||||
/// Custom serde helper: accept JSON `true`/`false` **or** integers `0`/`1`
|
||||
/// for `Option<bool>` fields. VimL dicts serialise `auto_export = 1` as
|
||||
/// the JSON number `1`, not `true`, which would otherwise silently break
|
||||
/// deserialisation of the entire `RawWiki` and cause the server to fall
|
||||
/// back to `wiki_root` (ignoring the wikis list and marking every link
|
||||
/// broken).
|
||||
mod opt_bool_or_int {
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<bool>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let v = Option::<serde_json::Value>::deserialize(deserializer)?;
|
||||
match v {
|
||||
None | Some(serde_json::Value::Null) => Ok(None),
|
||||
Some(serde_json::Value::Bool(b)) => Ok(Some(b)),
|
||||
Some(serde_json::Value::Number(ref n)) => {
|
||||
if let Some(i) = n.as_i64() {
|
||||
Ok(Some(i != 0))
|
||||
} else {
|
||||
Err(serde::de::Error::custom(
|
||||
"expected bool or 0/1 integer for bool field",
|
||||
))
|
||||
}
|
||||
}
|
||||
Some(other) => Err(serde::de::Error::custom(format!(
|
||||
"expected bool or 0/1 integer, got {other}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
#[serde(default, rename_all = "snake_case")]
|
||||
struct InitOptions {
|
||||
@@ -427,9 +460,9 @@ struct RawWiki {
|
||||
template_date_format: Option<String>,
|
||||
#[serde(default)]
|
||||
css_name: Option<String>,
|
||||
#[serde(default)]
|
||||
#[serde(default, deserialize_with = "opt_bool_or_int::deserialize")]
|
||||
auto_export: Option<bool>,
|
||||
#[serde(default)]
|
||||
#[serde(default, deserialize_with = "opt_bool_or_int::deserialize")]
|
||||
html_filename_parameterization: Option<bool>,
|
||||
#[serde(default)]
|
||||
exclude_files: Option<Vec<String>>,
|
||||
@@ -453,7 +486,7 @@ struct RawWiki {
|
||||
maxhi: Option<u8>,
|
||||
#[serde(default)]
|
||||
listsyms: Option<String>,
|
||||
#[serde(default)]
|
||||
#[serde(default, deserialize_with = "opt_bool_or_int::deserialize")]
|
||||
listsyms_propagate: Option<bool>,
|
||||
#[serde(default)]
|
||||
list_margin: Option<i32>,
|
||||
@@ -461,7 +494,7 @@ struct RawWiki {
|
||||
links_space_char: Option<String>,
|
||||
#[serde(default)]
|
||||
nested_syntaxes: Option<std::collections::HashMap<String, String>>,
|
||||
#[serde(default)]
|
||||
#[serde(default, deserialize_with = "opt_bool_or_int::deserialize")]
|
||||
auto_toc: Option<bool>,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user