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 =====
|
// ===== 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)]
|
#[derive(Debug, Default, Deserialize)]
|
||||||
#[serde(default, rename_all = "snake_case")]
|
#[serde(default, rename_all = "snake_case")]
|
||||||
struct InitOptions {
|
struct InitOptions {
|
||||||
@@ -427,9 +460,9 @@ struct RawWiki {
|
|||||||
template_date_format: Option<String>,
|
template_date_format: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
css_name: Option<String>,
|
css_name: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default, deserialize_with = "opt_bool_or_int::deserialize")]
|
||||||
auto_export: Option<bool>,
|
auto_export: Option<bool>,
|
||||||
#[serde(default)]
|
#[serde(default, deserialize_with = "opt_bool_or_int::deserialize")]
|
||||||
html_filename_parameterization: Option<bool>,
|
html_filename_parameterization: Option<bool>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
exclude_files: Option<Vec<String>>,
|
exclude_files: Option<Vec<String>>,
|
||||||
@@ -453,7 +486,7 @@ struct RawWiki {
|
|||||||
maxhi: Option<u8>,
|
maxhi: Option<u8>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
listsyms: Option<String>,
|
listsyms: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default, deserialize_with = "opt_bool_or_int::deserialize")]
|
||||||
listsyms_propagate: Option<bool>,
|
listsyms_propagate: Option<bool>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
list_margin: Option<i32>,
|
list_margin: Option<i32>,
|
||||||
@@ -461,7 +494,7 @@ struct RawWiki {
|
|||||||
links_space_char: Option<String>,
|
links_space_char: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
nested_syntaxes: Option<std::collections::HashMap<String, String>>,
|
nested_syntaxes: Option<std::collections::HashMap<String, String>>,
|
||||||
#[serde(default)]
|
#[serde(default, deserialize_with = "opt_bool_or_int::deserialize")]
|
||||||
auto_toc: Option<bool>,
|
auto_toc: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user