1use serde_json::Value;
30
31mod utils;
32use utils::format_value;
33
34#[derive(Debug, Clone, Default)]
36pub struct LLMLOptions {
37 pub indent: String,
39 pub prefix: String,
41 pub strict: bool,
43}
44
45pub fn llml(data: &Value) -> String {
54 format_value(data, &LLMLOptions::default())
55}
56
57pub fn llml_with_options(data: &Value, options: Option<LLMLOptions>) -> String {
63 let opts = options.unwrap_or_default();
64 format_value(data, &opts)
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use serde_json::json;
71
72 #[test]
73 fn test_empty_values() {
74 assert_eq!(llml(&json!({})), "");
75 assert_eq!(llml(&json!([])), "");
76 assert_eq!(llml(&Value::Null), "null");
77 }
78
79 #[test]
80 fn test_simple_values() {
81 let result = llml(&json!({"instructions": "Follow these steps"}));
82 assert_eq!(result, "<instructions>Follow these steps</instructions>");
83
84 let result = llml(&json!({"count": 42}));
85 assert_eq!(result, "<count>42</count>");
86
87 let result = llml(&json!({"enabled": true}));
88 assert_eq!(result, "<enabled>true</enabled>");
89 }
90
91 #[test]
92 fn test_list_formatting() {
93 let result = llml(&json!({"rules": ["first", "second", "third"]}));
94 let expected = "<rules>\n <rules-1>first</rules-1>\n <rules-2>second</rules-2>\n <rules-3>third</rules-3>\n</rules>";
95 assert_eq!(result, expected);
96 }
97
98 #[test]
99 fn test_nested_objects() {
100 let result = llml(&json!({
101 "config": {
102 "debug": true,
103 "timeout": 30
104 }
105 }));
106
107 assert!(result.contains("<config>"));
108 assert!(result.contains("</config>"));
109 assert!(result.contains("<debug>true</debug>"));
110 assert!(result.contains("<timeout>30</timeout>"));
111 }
112
113 #[test]
114 fn test_optional_second_argument() {
115 let data = json!({"instructions": "Follow these steps"});
116
117 let result1 = llml(&data);
119 assert_eq!(result1, "<instructions>Follow these steps</instructions>");
120
121 let options = Some(LLMLOptions {
123 indent: " ".to_string(),
124 prefix: String::new(),
125 strict: false,
126 });
127 let result2 = llml_with_options(&data, options);
128 assert_eq!(result2, " <instructions>Follow these steps</instructions>");
129
130 let result3 = llml_with_options(&data, None);
132 assert_eq!(result3, "<instructions>Follow these steps</instructions>");
133
134 assert_eq!(result1, result3);
136 }
137
138 #[test]
139 fn test_with_LLMLOptions_function() {
140 let data = json!({"test": "value"});
141
142 let options = LLMLOptions {
144 indent: " ".to_string(),
145 prefix: String::new(),
146 strict: false,
147 };
148 let result = llml_with_options(&data, Some(options));
149 assert_eq!(result, " <test>value</test>");
150
151 let options = LLMLOptions {
153 indent: String::new(),
154 prefix: "app".to_string(),
155 strict: false,
156 };
157 let result = llml_with_options(&data, Some(options));
158 assert_eq!(result, "<app-test>value</app-test>");
159 }
160
161 #[test]
162 fn test_insertion_order_preservation() {
163 let result = llml(&json!({
165 "first": "1st",
166 "second": "2nd",
167 "third": "3rd"
168 }));
169
170 let expected = "<first>1st</first>\n<second>2nd</second>\n<third>3rd</third>";
172 assert_eq!(result, expected);
173 }
174
175 #[test]
176 fn test_deterministic_output() {
177 let data = json!({
179 "alpha": "value1",
180 "beta": "value2",
181 "gamma": "value3",
182 "delta": "value4"
183 });
184
185 let result1 = llml(&data);
186 let result2 = llml(&data);
187 let result3 = llml(&data);
188
189 assert_eq!(result1, result2);
191 assert_eq!(result2, result3);
192
193 let expected = "<alpha>value1</alpha>\n<beta>value2</beta>\n<delta>value4</delta>\n<gamma>value3</gamma>";
195 assert_eq!(result1, expected);
196 }
197}