use std::collections::HashMap;
pub const INSTRUCTIONS_URI: &str = "code-mode://instructions";
pub const POLICIES_URI: &str = "code-mode://policies";
#[derive(Debug, Clone, Default)]
pub struct TemplateContext {
vars: HashMap<String, String>,
}
impl TemplateContext {
pub fn new() -> Self {
Self::default()
}
pub fn set(mut self, key: &str, value: impl Into<String>) -> Self {
self.vars.insert(key.to_string(), value.into());
self
}
pub fn set_bool(self, key: &str, value: bool) -> Self {
self.set(key, if value { "true" } else { "false" })
}
pub fn set_num(self, key: &str, value: impl std::fmt::Display) -> Self {
self.set(key, value.to_string())
}
pub fn render(&self, template: &str) -> String {
let mut result = template.to_string();
for (key, value) in &self.vars {
let placeholder = format!("{{{{{}}}}}", key);
result = result.replace(&placeholder, value);
}
result
}
}
pub fn render(template: &str, ctx: &TemplateContext) -> String {
ctx.render(template)
}
pub fn conditional(condition: bool, content: &str) -> String {
if condition {
content.to_string()
} else {
String::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_render() {
let ctx = TemplateContext::new()
.set("name", "IMDB")
.set_num("timeout", 300);
let result = ctx.render("Server: {{name}}, Timeout: {{timeout}}s");
assert_eq!(result, "Server: IMDB, Timeout: 300s");
}
#[test]
fn test_unknown_keys_preserved() {
let ctx = TemplateContext::new().set("name", "test");
let result = ctx.render("{{name}} and {{unknown}}");
assert_eq!(result, "test and {{unknown}}");
}
#[test]
fn test_conditional() {
assert_eq!(conditional(true, "hello"), "hello");
assert_eq!(conditional(false, "hello"), "");
}
#[test]
fn test_code_examples_not_broken() {
let ctx = TemplateContext::new().set("server_name", "Test");
let template = r#"{{server_name}} API
```javascript
const path = `/users/${userId}`;
```"#;
let result = ctx.render(template);
assert!(result.contains("Test API"));
assert!(result.contains("${userId}"));
}
}