use serde::{Deserialize, Serialize};
use super::ast::WireNode;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FormatCtx {
pub label: String,
pub params: Vec<(String, String)>,
pub node: WireNode,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub format_options: Option<serde_json::Value>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LexAnnotationOut {
pub label: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub params: Vec<(String, String)>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub body: String,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub verbatim_label: bool,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::wire::range::{Position, Range};
fn r(s_l: u32, s_c: u32, e_l: u32, e_c: u32) -> Range {
Range::new(Position::new(s_l, s_c), Position::new(e_l, e_c))
}
fn sample_node() -> WireNode {
WireNode::Paragraph {
range: r(0, 0, 0, 5),
origin: None,
inlines: vec![],
}
}
#[test]
fn format_ctx_round_trips_through_json() {
let c = FormatCtx {
label: "lex.tabular.table".into(),
params: vec![("align".into(), "lcr".into())],
node: sample_node(),
format_options: Some(serde_json::json!({ "max_width": 80 })),
};
let s = serde_json::to_string(&c).unwrap();
let back: FormatCtx = serde_json::from_str(&s).unwrap();
assert_eq!(back, c);
}
#[test]
fn format_ctx_omits_options_when_none() {
let c = FormatCtx {
label: "lex.media.image".into(),
params: vec![("src".into(), "x.png".into())],
node: sample_node(),
format_options: None,
};
let s = serde_json::to_string(&c).unwrap();
assert!(
!s.contains("format_options"),
"format_options must be omitted when None, got: {s}"
);
let back: FormatCtx = serde_json::from_str(&s).unwrap();
assert_eq!(back, c);
}
#[test]
fn lex_annotation_out_round_trips_through_json() {
let a = LexAnnotationOut {
label: "lex.tabular.table".into(),
params: vec![("header".into(), "1".into())],
body: "| a | b |\n|---|---|\n| 1 | 2 |".into(),
verbatim_label: true,
};
let s = serde_json::to_string(&a).unwrap();
let back: LexAnnotationOut = serde_json::from_str(&s).unwrap();
assert_eq!(back, a);
}
#[test]
fn lex_annotation_out_minimal_form_omits_defaults() {
let a = LexAnnotationOut {
label: "lex.metadata.author".into(),
params: vec![],
body: String::new(),
verbatim_label: false,
};
let s = serde_json::to_string(&a).unwrap();
assert!(!s.contains("params"), "params must be omitted: {s}");
assert!(!s.contains("body"), "body must be omitted: {s}");
assert!(
!s.contains("verbatim_label"),
"verbatim_label must be omitted when false: {s}"
);
let back: LexAnnotationOut = serde_json::from_str(&s).unwrap();
assert_eq!(back, a);
}
#[test]
fn lex_annotation_out_deserializes_with_omitted_defaults() {
let json = r#"{"label":"lex.metadata.date"}"#;
let a: LexAnnotationOut = serde_json::from_str(json).unwrap();
assert_eq!(a.label, "lex.metadata.date");
assert!(a.params.is_empty());
assert!(a.body.is_empty());
assert!(!a.verbatim_label);
}
}