atom_engine/filters/
component.rs1use serde_json::{json, Value};
2use std::collections::HashMap;
3use tera::Function;
4
5use super::FilterResult;
6
7pub fn slot_filter(name: &Value, _: &HashMap<String, Value>) -> FilterResult {
8 let slot_name = name.as_str().unwrap_or("default").trim_start_matches('$');
9 let slot_key = format!("__slot_{}", slot_name);
10 if let Some(slot_content) = name.get(&slot_key) {
11 return Ok(slot_content.clone());
12 }
13 Ok(Value::String(String::new()))
14}
15
16pub fn has_slot_filter(name: &Value, _: &HashMap<String, Value>) -> FilterResult {
17 let slot_name = name.as_str().unwrap_or("default").trim_start_matches('$');
18 let slot_key = format!("__slot_{}", slot_name);
19 Ok(Value::Bool(name.get(&slot_key).is_some()))
20}
21
22pub fn stack_filter(name: &Value, _: &HashMap<String, Value>) -> FilterResult {
23 let stack_name = name.as_str().unwrap_or("");
24 let stack_key = format!("__stack_{}", stack_name);
25 Ok(name
26 .get(&stack_key)
27 .cloned()
28 .unwrap_or(Value::String(String::new())))
29}
30
31pub fn scoped_slot_filter(args: &Value, _: &HashMap<String, Value>) -> FilterResult {
32 let slot_name = args
33 .get("slot")
34 .and_then(|v| v.as_str())
35 .unwrap_or("default");
36 let data_key = args.get("key").and_then(|v| v.as_str()).unwrap_or("item");
37 let default_value = args.get("default");
38
39 let _slot_key = format!("__scoped_slot_{}", slot_name);
40 let data_key_full = format!("__scoped_data_{}_{}", slot_name, data_key);
41
42 if let Some(data) = args.get(&data_key_full) {
43 return Ok(data.clone());
44 }
45
46 Ok(default_value.cloned().unwrap_or(Value::Null))
47}
48
49pub fn with_scoped_data_filter(args: &Value, _: &HashMap<String, Value>) -> FilterResult {
50 let slot_name = args
51 .get("slot")
52 .and_then(|v| v.as_str())
53 .unwrap_or("default");
54 let data = args.get("data").cloned().unwrap_or(Value::Null);
55
56 let mut result = json!({
57 "slot": slot_name,
58 "data": data,
59 });
60
61 if let Some(obj) = result.as_object_mut() {
62 if let Some(data_obj) = data.as_object() {
63 for (key, value) in data_obj {
64 obj.insert(
65 format!("__scoped_data_{}_{}", slot_name, key),
66 value.clone(),
67 );
68 }
69 }
70 }
71
72 Ok(result)
73}
74
75pub struct PushFn;
76
77impl Function for PushFn {
78 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
79 let stack_name = args
80 .get("name")
81 .and_then(|v| v.as_str())
82 .unwrap_or("default");
83 let content = args.get("content").and_then(|v| v.as_str()).unwrap_or("");
84 let stack_key = format!("__stack_{}", stack_name);
85 Ok(Value::String(format!("{}__push__ {}", stack_key, content)))
86 }
87}
88
89pub struct PrependFn;
90
91impl Function for PrependFn {
92 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
93 let stack_name = args
94 .get("name")
95 .and_then(|v| v.as_str())
96 .unwrap_or("default");
97 let content = args.get("content").and_then(|v| v.as_str()).unwrap_or("");
98 let stack_key = format!("__stack_{}", stack_name);
99 Ok(Value::String(format!(
100 "{}__prepend__ {}",
101 stack_key, content
102 )))
103 }
104}
105
106pub struct SetSlotFn;
107
108impl Function for SetSlotFn {
109 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
110 let slot_name = args
111 .get("name")
112 .and_then(|v| v.as_str())
113 .unwrap_or("default")
114 .trim_start_matches('$');
115 let content = args.get("content").and_then(|v| v.as_str()).unwrap_or("");
116 let slot_key = format!("__slot_{}", slot_name);
117 Ok(Value::String(format!("{} {}", slot_key, content)))
118 }
119}
120
121pub struct OnceFn;
122
123impl Function for OnceFn {
124 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
125 let key = args
126 .get("key")
127 .and_then(|v| v.as_str())
128 .unwrap_or("default");
129 let hash = simple_hash(key);
130 let content = args.get("content").and_then(|v| v.as_str()).unwrap_or("");
131 Ok(json!({ "key": hash, "content": content }))
132 }
133}
134
135fn simple_hash(s: &str) -> u64 {
136 let mut hash: u64 = 0;
137 for (i, c) in s.bytes().enumerate() {
138 hash = hash.wrapping_add((c as u64).wrapping_mul(31_u64.wrapping_pow(i as u32)));
139 }
140 hash
141}