use heck::{
ToShoutyKebabCase,
ToShoutySnakeCase,
ToTitleCase, };
use inflector::{
cases::{
camelcase, classcase, kebabcase, pascalcase, sentencecase, snakecase, titlecase, traincase,
},
numbers::{deordinalize, ordinalize},
string::{deconstantize, demodulize, pluralize, singularize},
suffix::foreignkey,
};
use std::collections::HashMap;
use tera::{Context, Result as TeraResult, Tera, Value};
pub fn register_all(tera: &mut Tera) {
reg_str(tera, "camel", camelcase::to_camel_case);
reg_str(tera, "pascal", pascalcase::to_pascal_case);
reg_str(tera, "snake", snakecase::to_snake_case);
reg_str(tera, "kebab", kebabcase::to_kebab_case);
reg_str(tera, "class", classcase::to_class_case);
reg_str(tera, "title", titlecase::to_title_case);
reg_str(tera, "sentence", sentencecase::to_sentence_case);
reg_str(tera, "train", traincase::to_train_case);
reg_str(tera, "pluralize", pluralize::to_plural);
reg_str(tera, "singularize", singularize::to_singular);
reg_str(tera, "deconstantize", deconstantize::deconstantize);
reg_str(tera, "demodulize", demodulize::demodulize);
reg_str(tera, "ordinalize", ordinalize::ordinalize);
reg_str(tera, "deordinalize", deordinalize::deordinalize);
reg_str(tera, "foreign_key", foreignkey::to_foreign_key);
reg_str(tera, "shouty_snake", |s| s.to_shouty_snake_case());
reg_str(tera, "shouty_kebab", |s| s.to_shouty_kebab_case());
reg_str(tera, "titlecase", |s| s.to_title_case());
reg_str(tera, "param", kebabcase::to_kebab_case);
reg_str(tera, "constant", |s| s.to_shouty_snake_case());
reg_str(tera, "upper", |s| s.to_uppercase());
reg_str(tera, "lower", |s| s.to_lowercase());
reg_str(tera, "lcfirst", |s| {
let mut c = s.chars();
match c.next() {
Some(f) => f.to_lowercase().collect::<String>() + c.as_str(),
None => String::new(),
}
});
reg_str(tera, "ucfirst", |s| {
let mut c = s.chars();
match c.next() {
Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
None => String::new(),
}
});
tera.register_filter(
"pad_right",
|value: &tera::Value,
args: &std::collections::HashMap<String, tera::Value>|
-> tera::Result<tera::Value> {
let s = match value.as_str() {
Some(s) => s.to_string(),
None => value.to_string(),
};
let width = args.get("width").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
Ok(tera::Value::String(format!("{:<width$}", s, width = width)))
},
);
register_sparql_helpers(tera);
register_schema_filters(tera);
}
pub fn bless_context(context: &mut Context) {
if let Some(name_value) = context.get("name") {
if let Some(name_str) = name_value.as_str() {
let pascal_name = pascalcase::to_pascal_case(name_str);
context.insert("Name", &pascal_name);
}
}
context.insert("locals", &HashMap::<String, Value>::new());
}
fn register_sparql_helpers(tera: &mut Tera) {
tera.register_function("sparql_column", SparqlColumnFn);
tera.register_function("sparql_row", SparqlRowFn);
tera.register_function("sparql_first", SparqlFirstFn);
tera.register_function("sparql_values", SparqlValuesFn);
tera.register_function("sparql_empty", SparqlEmptyFn);
tera.register_function("sparql_count", SparqlCountFn);
}
fn register_schema_filters(tera: &mut Tera) {
tera.register_filter("schema_to_rust", schema_to_rust_filter);
tera.register_filter("schema_to_go", schema_to_go_filter);
tera.register_filter("schema_to_elixir", schema_to_elixir_filter);
tera.register_filter("schema_to_java", schema_to_java_filter);
tera.register_filter("schema_to_typescript", schema_to_typescript_filter);
}
fn schema_to_rust_filter(value: &Value, _args: &HashMap<String, Value>) -> TeraResult<Value> {
let schema_str = value
.as_str()
.ok_or_else(|| tera::Error::msg("schema_to_rust filter requires a string value"))?;
let result = crate::schema::SchemaParser::parse(schema_str)
.map_err(|e| tera::Error::msg(format!("Failed to parse schema: {}", e)))?;
let rust_code = crate::schema::generators::RustGenerator::generate(&result);
Ok(Value::String(rust_code))
}
fn schema_to_go_filter(value: &Value, _args: &HashMap<String, Value>) -> TeraResult<Value> {
let schema_str = value
.as_str()
.ok_or_else(|| tera::Error::msg("schema_to_go filter requires a string value"))?;
let result = crate::schema::SchemaParser::parse(schema_str)
.map_err(|e| tera::Error::msg(format!("Failed to parse schema: {}", e)))?;
let go_code = crate::schema::generators::GoGenerator::generate(&result);
Ok(Value::String(go_code))
}
fn schema_to_elixir_filter(value: &Value, _args: &HashMap<String, Value>) -> TeraResult<Value> {
let schema_str = value
.as_str()
.ok_or_else(|| tera::Error::msg("schema_to_elixir filter requires a string value"))?;
let result = crate::schema::SchemaParser::parse(schema_str)
.map_err(|e| tera::Error::msg(format!("Failed to parse schema: {}", e)))?;
let elixir_code = crate::schema::generators::ElixirGenerator::generate_struct(&result);
Ok(Value::String(elixir_code))
}
fn schema_to_java_filter(value: &Value, _args: &HashMap<String, Value>) -> TeraResult<Value> {
let schema_str = value
.as_str()
.ok_or_else(|| tera::Error::msg("schema_to_java filter requires a string value"))?;
let result = crate::schema::SchemaParser::parse(schema_str)
.map_err(|e| tera::Error::msg(format!("Failed to parse schema: {}", e)))?;
let java_code = crate::schema::generators::JavaGenerator::generate_class(&result);
Ok(Value::String(java_code))
}
fn schema_to_typescript_filter(value: &Value, _args: &HashMap<String, Value>) -> TeraResult<Value> {
let schema_str = value
.as_str()
.ok_or_else(|| tera::Error::msg("schema_to_typescript filter requires a string value"))?;
let result = crate::schema::SchemaParser::parse(schema_str)
.map_err(|e| tera::Error::msg(format!("Failed to parse schema: {}", e)))?;
let ts_code = crate::schema::generators::TypeScriptGenerator::generate_interface(&result);
Ok(Value::String(ts_code))
}
#[derive(Clone)]
struct SparqlColumnFn;
impl tera::Function for SparqlColumnFn {
fn call(&self, args: &HashMap<String, Value>) -> TeraResult<Value> {
let results = args
.get("results")
.ok_or_else(|| tera::Error::msg("sparql_column: results parameter required"))?;
let column = args
.get("column")
.and_then(|v| v.as_str())
.ok_or_else(|| tera::Error::msg("sparql_column: column parameter required"))?;
if let Some(array) = results.as_array() {
let mut column_values = Vec::new();
for row in array {
if let Some(obj) = row.as_object() {
if let Some(value) = obj.get(column) {
column_values.push(value.clone());
} else {
let sparql_column = format!("?{}", column);
if let Some(value) = obj.get(&sparql_column) {
column_values.push(value.clone());
}
}
}
}
Ok(Value::Array(column_values))
} else {
Ok(Value::Array(Vec::new()))
}
}
}
#[derive(Clone)]
struct SparqlRowFn;
impl tera::Function for SparqlRowFn {
fn call(&self, args: &HashMap<String, Value>) -> TeraResult<Value> {
let results = args
.get("results")
.ok_or_else(|| tera::Error::msg("sparql_row: results parameter required"))?;
let index = args
.get("index")
.and_then(|v| v.as_number())
.and_then(|n| n.as_u64())
.ok_or_else(|| tera::Error::msg("sparql_row: index parameter required"))?;
if let Some(array) = results.as_array() {
if let Some(row) = array.get(index as usize) {
Ok(row.clone())
} else {
Ok(Value::Null)
}
} else {
Ok(Value::Null)
}
}
}
#[derive(Clone)]
struct SparqlFirstFn;
impl tera::Function for SparqlFirstFn {
fn call(&self, args: &HashMap<String, Value>) -> TeraResult<Value> {
let results = args
.get("results")
.ok_or_else(|| tera::Error::msg("sparql_first: results parameter required"))?;
let column = args
.get("column")
.and_then(|v| v.as_str())
.ok_or_else(|| tera::Error::msg("sparql_first: column parameter required"))?;
if let Some(array) = results.as_array() {
if let Some(first_row) = array.first() {
if let Some(obj) = first_row.as_object() {
if let Some(value) = obj.get(column) {
return Ok(value.clone());
}
let sparql_column = format!("?{}", column);
if let Some(value) = obj.get(&sparql_column) {
return Ok(value.clone());
}
}
}
}
Ok(Value::Null)
}
}
#[derive(Clone)]
struct SparqlValuesFn;
impl tera::Function for SparqlValuesFn {
fn call(&self, args: &HashMap<String, Value>) -> TeraResult<Value> {
let results = args
.get("results")
.ok_or_else(|| tera::Error::msg("sparql_values: results parameter required"))?;
let column = args
.get("column")
.and_then(|v| v.as_str())
.ok_or_else(|| tera::Error::msg("sparql_values: column parameter required"))?;
if let Some(array) = results.as_array() {
let mut values = Vec::new();
for row in array {
if let Some(obj) = row.as_object() {
if let Some(value) = obj.get(column) {
if let Some(str_val) = value.as_str() {
values.push(Value::String(str_val.to_string()));
} else {
values.push(value.clone());
}
} else {
let sparql_column = format!("?{}", column);
if let Some(value) = obj.get(&sparql_column) {
if let Some(str_val) = value.as_str() {
values.push(Value::String(str_val.to_string()));
} else {
values.push(value.clone());
}
}
}
}
}
Ok(Value::Array(values))
} else {
Ok(Value::Array(Vec::new()))
}
}
}
#[derive(Clone)]
struct SparqlEmptyFn;
impl tera::Function for SparqlEmptyFn {
fn call(&self, args: &HashMap<String, Value>) -> TeraResult<Value> {
let results = args
.get("results")
.ok_or_else(|| tera::Error::msg("sparql_empty: results parameter required"))?;
let is_empty = match results {
Value::Array(arr) => arr.is_empty(),
Value::Bool(_) => false, _ => true,
};
Ok(Value::Bool(is_empty))
}
}
#[derive(Clone)]
struct SparqlCountFn;
impl tera::Function for SparqlCountFn {
fn call(&self, args: &HashMap<String, Value>) -> TeraResult<Value> {
let results = args
.get("results")
.ok_or_else(|| tera::Error::msg("sparql_count: results parameter required"))?;
let count = match results {
Value::Array(arr) => arr.len(),
Value::Bool(_) => 1, _ => 0,
};
Ok(Value::Number(tera::Number::from(count)))
}
}
fn reg_str<F>(tera: &mut Tera, name: &str, f: F)
where
F: Fn(&str) -> String + Send + Sync + 'static,
{
tera.register_filter(
name,
move |v: &Value, _a: &HashMap<String, Value>| -> TeraResult<Value> {
let input_str = match v.as_str() {
Some(s) => s.to_string(),
None => v.to_string(),
};
Ok(Value::String(f(&input_str)))
},
);
}
#[cfg(test)]
mod tests {
use super::*;
use tera::Context;
fn create_test_tera() -> Tera {
let mut tera = Tera::default();
register_all(&mut tera);
tera
}
#[test]
fn test_case_conversions() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("name", "hello_world_example");
let result = tera.render_str("{{ name | camel }}", &ctx).unwrap();
assert_eq!(result, "helloWorldExample");
let result = tera.render_str("{{ name | pascal }}", &ctx).unwrap();
assert_eq!(result, "HelloWorldExample");
let result = tera.render_str("{{ name | snake }}", &ctx).unwrap();
assert_eq!(result, "hello_world_example");
let result = tera.render_str("{{ name | kebab }}", &ctx).unwrap();
assert_eq!(result, "hello-world-example");
let result = tera.render_str("{{ name | class }}", &ctx).unwrap();
assert_eq!(result, "HelloWorldExample");
let result = tera.render_str("{{ name | title }}", &ctx).unwrap();
assert_eq!(result, "Hello World Example");
let result = tera.render_str("{{ name | sentence }}", &ctx).unwrap();
assert_eq!(result, "Hello world example");
let result = tera.render_str("{{ name | train }}", &ctx).unwrap();
assert_eq!(result, "Hello-World-Example");
}
#[test]
fn test_heck_fill_ins() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("name", "hello_world_example");
let result = tera.render_str("{{ name | shouty_snake }}", &ctx).unwrap();
assert_eq!(result, "HELLO_WORLD_EXAMPLE");
let result = tera.render_str("{{ name | shouty_kebab }}", &ctx).unwrap();
assert_eq!(result, "HELLO-WORLD-EXAMPLE");
let result = tera.render_str("{{ name | titlecase }}", &ctx).unwrap();
assert_eq!(result, "Hello World Example");
}
#[test]
fn test_ordinalization() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("num", "1");
let result = tera.render_str("{{ num | ordinalize }}", &ctx).unwrap();
assert_eq!(result, "1st");
ctx.insert("num", "2");
let result = tera.render_str("{{ num | ordinalize }}", &ctx).unwrap();
assert_eq!(result, "2nd");
ctx.insert("num", "3");
let result = tera.render_str("{{ num | ordinalize }}", &ctx).unwrap();
assert_eq!(result, "3rd");
ctx.insert("num", "4");
let result = tera.render_str("{{ num | ordinalize }}", &ctx).unwrap();
assert_eq!(result, "4th");
ctx.insert("num", "11");
let result = tera.render_str("{{ num | ordinalize }}", &ctx).unwrap();
assert_eq!(result, "11th");
ctx.insert("num", "1st");
let result = tera.render_str("{{ num | deordinalize }}", &ctx).unwrap();
assert_eq!(result, "1");
ctx.insert("num", "2nd");
let result = tera.render_str("{{ num | deordinalize }}", &ctx).unwrap();
assert_eq!(result, "2");
}
#[test]
fn test_string_manipulation() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("path", "ActiveRecord::Base");
let result = tera.render_str("{{ path | deconstantize }}", &ctx).unwrap();
assert_eq!(result, "ActiveRecord");
ctx.insert("path", "ActiveRecord::Base");
let result = tera.render_str("{{ path | demodulize }}", &ctx).unwrap();
assert_eq!(result, "Base");
ctx.insert("name", "Message");
let result = tera.render_str("{{ name | foreign_key }}", &ctx).unwrap();
assert_eq!(result, "message_id");
}
#[test]
fn test_complex_combinations() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("class_name", "UserProfile");
let result = tera
.render_str("{{ class_name | snake | pluralize }}", &ctx)
.unwrap();
assert_eq!(result, "user_profiles");
let result = tera
.render_str("{{ class_name | kebab | shouty_kebab }}", &ctx)
.unwrap();
assert_eq!(result, "USER-PROFILE");
let result = tera
.render_str("{{ class_name | demodulize | snake }}", &ctx)
.unwrap();
assert_eq!(result, "user_profile");
}
#[test]
fn test_edge_cases() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("empty", "");
let result = tera.render_str("{{ empty | camel }}", &ctx).unwrap();
assert_eq!(result, "");
ctx.insert("single", "A");
let result = tera.render_str("{{ single | snake }}", &ctx).unwrap();
assert_eq!(result, "a");
ctx.insert("number", "123");
let result = tera.render_str("{{ number | camel }}", &ctx).unwrap();
assert_eq!(result, "123");
ctx.insert("special", "hello@world#test");
let result = tera.render_str("{{ special | kebab }}", &ctx).unwrap();
assert_eq!(result, "hello-world-test");
}
#[test]
fn test_non_string_input() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("num", &42);
let result = tera.render_str("{{ num | camel }}", &ctx).unwrap();
assert_eq!(result, "42");
ctx.insert("flag", &true);
let result = tera.render_str("{{ flag | snake }}", &ctx).unwrap();
assert_eq!(result, "true");
}
#[test]
fn test_real_world_scenarios() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("model", "UserAccount");
let table_name = tera
.render_str("{{ model | snake | pluralize }}", &ctx)
.unwrap();
assert_eq!(table_name, "user_accounts");
ctx.insert("resource", "UserProfile");
let endpoint = tera
.render_str("{{ resource | kebab | pluralize }}", &ctx)
.unwrap();
assert_eq!(endpoint, "user-profiles");
ctx.insert("name", "max_retry_count");
let constant = tera.render_str("{{ name | shouty_snake }}", &ctx).unwrap();
assert_eq!(constant, "MAX_RETRY_COUNT");
ctx.insert("action", "get_user_profile");
let method = tera.render_str("{{ action | camel }}", &ctx).unwrap();
assert_eq!(method, "getUserProfile");
}
#[test]
fn test_change_case_aliases() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("name", "hello_world_example");
let result = tera.render_str("{{ name | param }}", &ctx).unwrap();
assert_eq!(result, "hello-world-example");
let result = tera.render_str("{{ name | constant }}", &ctx).unwrap();
assert_eq!(result, "HELLO_WORLD_EXAMPLE");
let result = tera.render_str("{{ name | upper }}", &ctx).unwrap();
assert_eq!(result, "HELLO_WORLD_EXAMPLE");
ctx.insert("name", "HELLO_WORLD_EXAMPLE");
let result = tera.render_str("{{ name | lower }}", &ctx).unwrap();
assert_eq!(result, "hello_world_example");
ctx.insert("name", "HelloWorld");
let result = tera.render_str("{{ name | lcfirst }}", &ctx).unwrap();
assert_eq!(result, "helloWorld");
ctx.insert("name", "helloWorld");
let result = tera.render_str("{{ name | ucfirst }}", &ctx).unwrap();
assert_eq!(result, "HelloWorld");
ctx.insert("name", "");
let result = tera.render_str("{{ name | lcfirst }}", &ctx).unwrap();
assert_eq!(result, "");
let result = tera.render_str("{{ name | ucfirst }}", &ctx).unwrap();
assert_eq!(result, "");
ctx.insert("name", "ñáéÃóú");
let result = tera.render_str("{{ name | ucfirst }}", &ctx).unwrap();
assert_eq!(result, "ÑáéÃóú");
}
#[test]
fn test_all_filters_registered() {
let mut tera = create_test_tera();
let expected_filters = vec![
"camel",
"pascal",
"snake",
"kebab",
"class",
"title",
"sentence",
"train",
"pluralize",
"singularize",
"deconstantize",
"demodulize",
"ordinalize",
"deordinalize",
"foreign_key",
"shouty_snake",
"shouty_kebab",
"titlecase",
"param",
"constant",
"upper",
"lower",
"lcfirst",
"ucfirst",
];
for filter in expected_filters {
let mut ctx = Context::new();
ctx.insert("test", "hello_world");
let result = tera.render_str(&format!("{{{{ test | {} }}}}", filter), &ctx);
assert!(result.is_ok(), "Filter '{}' should be registered", filter);
}
}
#[test]
fn test_bless_context_name() {
let mut ctx = Context::new();
ctx.insert("name", "hello_world");
bless_context(&mut ctx);
assert_eq!(ctx.get("Name").unwrap().as_str().unwrap(), "HelloWorld");
assert_eq!(ctx.get("name").unwrap().as_str().unwrap(), "hello_world");
}
#[test]
fn test_bless_context_no_name() {
let mut ctx = Context::new();
ctx.insert("other", "value");
bless_context(&mut ctx);
assert!(ctx.get("Name").is_none());
assert!(ctx.get("locals").is_some());
}
#[test]
fn test_bless_context_non_string_name() {
let mut ctx = Context::new();
ctx.insert("name", &42);
bless_context(&mut ctx);
assert!(ctx.get("Name").is_none());
}
#[test]
fn test_sparql_column_function() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
let results = serde_json::json!([
{"name": "Alice", "age": "30"},
{"name": "Bob", "age": "25"},
{"name": "Charlie", "age": "35"}
]);
ctx.insert("results", &results);
let result = tera
.render_str(
"{{ sparql_column(results=results, column=\"name\") }}",
&ctx,
)
.unwrap();
assert_eq!(result, "[Alice, Bob, Charlie]");
}
#[test]
fn test_sparql_row_function() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
let results = serde_json::json!([
{"name": "Alice", "age": "30"},
{"name": "Bob", "age": "25"}
]);
ctx.insert("results", &results);
let result = tera
.render_str("{{ sparql_row(results=results, index=0) }}", &ctx)
.unwrap();
assert_eq!(result, "[object]");
let result = tera
.render_str("{{ sparql_row(results=results, index=1) }}", &ctx)
.unwrap();
assert_eq!(result, "[object]");
let result = tera
.render_str("{{ sparql_row(results=results, index=5) }}", &ctx)
.unwrap();
assert_eq!(result, "");
}
#[test]
fn test_sparql_first_function() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
let results = serde_json::json!([
{"name": "Alice", "age": "30"},
{"name": "Bob", "age": "25"}
]);
ctx.insert("results", &results);
let result = tera
.render_str("{{ sparql_first(results=results, column=\"name\") }}", &ctx)
.unwrap();
assert_eq!(result, "Alice");
let result = tera
.render_str("{{ sparql_first(results=results, column=\"age\") }}", &ctx)
.unwrap();
assert_eq!(result, "30");
let result = tera
.render_str(
"{{ sparql_first(results=results, column=\"nonexistent\") }}",
&ctx,
)
.unwrap();
assert_eq!(result, "");
}
#[test]
fn test_sparql_values_function() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
let results = serde_json::json!([
{"name": "Alice", "age": "30"},
{"name": "Bob", "age": "25"},
{"name": "Charlie", "age": "35"}
]);
ctx.insert("results", &results);
let result = tera
.render_str(
"{{ sparql_values(results=results, column=\"name\") }}",
&ctx,
)
.unwrap();
assert_eq!(result, "[Alice, Bob, Charlie]");
}
#[test]
fn test_sparql_empty_function() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
let empty_results = serde_json::json!([]);
ctx.insert("empty_results", &empty_results);
let result = tera
.render_str("{{ sparql_empty(results=empty_results) }}", &ctx)
.unwrap();
assert_eq!(result, "true");
let non_empty_results = serde_json::json!([
{"name": "Alice", "age": "30"}
]);
ctx.insert("non_empty_results", &non_empty_results);
let result = tera
.render_str("{{ sparql_empty(results=non_empty_results) }}", &ctx)
.unwrap();
assert_eq!(result, "false");
let bool_results = serde_json::json!(true);
ctx.insert("bool_results", &bool_results);
let result = tera
.render_str("{{ sparql_empty(results=bool_results) }}", &ctx)
.unwrap();
assert_eq!(result, "false");
}
#[test]
fn test_sparql_count_function() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
let results = serde_json::json!([
{"name": "Alice", "age": "30"},
{"name": "Bob", "age": "25"},
{"name": "Charlie", "age": "35"}
]);
ctx.insert("results", &results);
let result = tera
.render_str("{{ sparql_count(results=results) }}", &ctx)
.unwrap();
assert_eq!(result, "3");
let empty_results = serde_json::json!([]);
ctx.insert("empty_results", &empty_results);
let result = tera
.render_str("{{ sparql_count(results=empty_results) }}", &ctx)
.unwrap();
assert_eq!(result, "0");
let bool_results = serde_json::json!(true);
ctx.insert("bool_results", &bool_results);
let result = tera
.render_str("{{ sparql_count(results=bool_results) }}", &ctx)
.unwrap();
assert_eq!(result, "1");
}
#[test]
fn test_schema_to_rust_filter() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert(
"schema",
"FileReadRequest { path: string, offset?: integer }",
);
let result = tera
.render_str("{{ schema | schema_to_rust }}", &ctx)
.expect("schema_to_rust filter failed");
assert!(result.contains("pub struct FileReadRequest"));
assert!(result.contains("pub path: String"));
assert!(result.contains("pub offset: Option<i64>"));
}
#[test]
fn test_schema_to_go_filter() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert(
"schema",
"FileReadRequest { path: string, offset?: integer }",
);
let result = tera
.render_str("{{ schema | schema_to_go }}", &ctx)
.expect("schema_to_go filter failed");
assert!(result.contains("type FileReadRequest struct"));
assert!(result.contains("Path string"));
assert!(result.contains("Offset int64"));
assert!(result.contains("omitempty"));
}
#[test]
fn test_schema_to_elixir_filter() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert(
"schema",
"FileReadRequest { path: string, offset?: integer }",
);
let result = tera
.render_str("{{ schema | schema_to_elixir }}", &ctx)
.expect("schema_to_elixir filter failed");
assert!(result.contains("defmodule FileReadRequest"));
assert!(result.contains("defstruct"));
}
#[test]
fn test_schema_to_typescript_filter() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert(
"schema",
"FileReadRequest { path: string, offset?: integer }",
);
let result = tera
.render_str("{{ schema | schema_to_typescript }}", &ctx)
.expect("schema_to_typescript filter failed");
assert!(result.contains("export interface FileReadRequest"));
assert!(result.contains("path: string"));
assert!(result.contains("offset?: number"));
}
#[test]
fn test_schema_to_java_filter() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert(
"schema",
"FileReadRequest { path: string, offset?: integer }",
);
let result = tera
.render_str("{{ schema | schema_to_java }}", &ctx)
.expect("schema_to_java filter failed");
assert!(result.contains("public class FileReadRequest"));
assert!(result.contains("private String path"));
assert!(result.contains("private Long offset"));
}
#[test]
fn test_schema_filters_all_registered() {
let mut tera = create_test_tera();
let mut ctx = Context::new();
ctx.insert("schema", "Test { field: string }");
let filters = vec![
"schema_to_rust",
"schema_to_go",
"schema_to_elixir",
"schema_to_java",
"schema_to_typescript",
];
for filter in filters {
let result = tera.render_str(&format!("{{{{ schema | {} }}}}", filter), &ctx);
assert!(
result.is_ok(),
"Filter '{}' should be registered and working",
filter
);
}
}
}