Skip to content

Commit 1a8a8c4

Browse files
vivekprmlquerel
andauthored
to_yaml filter implementation (#626)
* to_yaml filter implementation * modified to_yaml filter to use implementation similar to minijinja tojson filter * added logic to return safe values * added coverage to test special characters * changed method signature --------- Co-authored-by: Laurent Quérel <[email protected]>
1 parent 61017ef commit 1a8a8c4

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
about: \u003ch1\u003eSoftware Engineer\u003ch1\u003e
2+
age: 30
3+
details:
4+
city: Wonderland
5+
6+
is_active: true
7+
name: Alice
8+
profile: https://example.com/?page=1\u0026section=about
9+
skills:
10+
- Rust
11+
- JavaScript

crates/weaver_forge/src/extensions/util.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub(crate) fn add_filters(env: &mut Environment<'_>, target_config: &WeaverConfi
1919
env.add_filter("flatten", flatten);
2020
env.add_filter("split_id", split_id);
2121
env.add_filter("regex_replace", regex_replace);
22+
env.add_filter("toyaml", to_yaml);
2223
}
2324

2425
/// Add utility functions to the environment.
@@ -131,10 +132,34 @@ pub fn acronym(acronyms: Vec<String>) -> impl Fn(&str) -> String {
131132
}
132133
}
133134

135+
// Helper filter to dump value (1st parameter) in yaml format.
136+
fn to_yaml(value: &Value) -> Result<Value, minijinja::Error> {
137+
let yaml = serde_yaml::to_string(&value)
138+
.map_err(|e| minijinja::Error::new(ErrorKind::BadSerialization, e.to_string()))
139+
.map(|s| {
140+
// When this filter is used the return value is safe for both HTML and JSON
141+
let mut rv = String::with_capacity(s.len());
142+
for c in s.chars() {
143+
match c {
144+
'<' => rv.push_str("\\u003c"),
145+
'>' => rv.push_str("\\u003e"),
146+
'&' => rv.push_str("\\u0026"),
147+
'\'' => rv.push_str("\\u0027"),
148+
_ => rv.push(c),
149+
}
150+
}
151+
Value::from_safe_string(rv)
152+
})?;
153+
Ok(yaml)
154+
}
155+
134156
#[cfg(test)]
135157
mod tests {
158+
use std::fs;
159+
136160
use crate::extensions::util::add_filters;
137161
use minijinja::Environment;
162+
use serde_yaml::{Mapping, Number, Value};
138163

139164
#[test]
140165
fn test_regex_replace() {
@@ -159,4 +184,58 @@ mod tests {
159184
"This A test with multiple A's"
160185
);
161186
}
187+
#[test]
188+
fn test_to_yaml() {
189+
let mut env = Environment::new();
190+
let mut inner_map = Mapping::new();
191+
let _ = inner_map.insert(
192+
Value::String("age".to_owned()),
193+
Value::Number(Number::from(30u64)),
194+
);
195+
let mut details_map = Mapping::new();
196+
let _ = details_map.insert(
197+
Value::String("city".to_owned()),
198+
Value::String("Wonderland".to_owned()),
199+
);
200+
let _ = details_map.insert(
201+
Value::String("email".to_owned()),
202+
Value::String("[email protected]".to_owned()),
203+
);
204+
let _ = inner_map.insert(
205+
Value::String("details".to_owned()),
206+
Value::Mapping(details_map),
207+
);
208+
let _ = inner_map.insert(Value::String("is_active".to_owned()), Value::Bool(true));
209+
let _ = inner_map.insert(
210+
Value::String("name".to_owned()),
211+
Value::String("Alice".to_owned()),
212+
);
213+
let _ = inner_map.insert(
214+
Value::String("about".to_owned()),
215+
Value::String("<h1>Software Engineer<h1>".to_owned()),
216+
);
217+
let _ = inner_map.insert(
218+
Value::String("profile".to_owned()),
219+
Value::String("https://example.com/?page=1&section=about".to_owned()),
220+
);
221+
let _ = inner_map.insert(
222+
Value::String("skills".to_owned()),
223+
Value::Sequence(vec![
224+
Value::String("Rust".to_owned()),
225+
Value::String("JavaScript".to_owned()),
226+
]),
227+
);
228+
let mut map = Mapping::new();
229+
let _ = map.insert(Value::String("user".to_owned()), Value::Mapping(inner_map));
230+
231+
let ctx = Value::Mapping(map);
232+
let config = crate::config::WeaverConfig::default();
233+
234+
add_filters(&mut env, &config);
235+
let expected_yaml = fs::read_to_string("expected_output/yaml/test.yaml").unwrap();
236+
assert_eq!(
237+
env.render_str("{{ user | toyaml }}", &ctx).unwrap(),
238+
expected_yaml
239+
);
240+
}
162241
}

0 commit comments

Comments
 (0)