1pub mod brew;
21pub mod c;
22pub mod client;
23pub mod csharp;
24pub mod dart;
25pub mod elixir;
26pub mod gleam;
27pub mod go;
28pub mod java;
29pub mod kotlin;
30pub mod php;
31pub mod python;
32pub mod r;
33pub mod ruby;
34pub mod rust;
35pub mod swift;
36pub mod typescript;
37pub mod wasm;
38pub mod zig;
39
40use crate::config::E2eConfig;
41use crate::fixture::FixtureGroup;
42use alef_core::backend::GeneratedFile;
43use alef_core::config::AlefConfig;
44use anyhow::Result;
45
46pub(crate) fn normalize_json_keys_to_snake_case(value: &serde_json::Value) -> serde_json::Value {
51 use heck::ToSnakeCase;
52 match value {
53 serde_json::Value::Object(obj) => {
54 let new_obj: serde_json::Map<String, serde_json::Value> = obj
55 .iter()
56 .map(|(k, v)| (k.to_snake_case(), normalize_json_keys_to_snake_case(v)))
57 .collect();
58 serde_json::Value::Object(new_obj)
59 }
60 serde_json::Value::Array(arr) => {
61 serde_json::Value::Array(arr.iter().map(normalize_json_keys_to_snake_case).collect())
62 }
63 other => other.clone(),
64 }
65}
66
67pub trait E2eCodegen: Send + Sync {
69 fn generate(
71 &self,
72 groups: &[FixtureGroup],
73 e2e_config: &E2eConfig,
74 alef_config: &AlefConfig,
75 ) -> Result<Vec<GeneratedFile>>;
76
77 fn language_name(&self) -> &'static str;
79}
80
81pub fn all_generators() -> Vec<Box<dyn E2eCodegen>> {
83 vec![
84 Box::new(rust::RustE2eCodegen),
85 Box::new(python::PythonE2eCodegen),
86 Box::new(typescript::TypeScriptCodegen),
87 Box::new(go::GoCodegen),
88 Box::new(java::JavaCodegen),
89 Box::new(kotlin::KotlinE2eCodegen),
90 Box::new(csharp::CSharpCodegen),
91 Box::new(php::PhpCodegen),
92 Box::new(ruby::RubyCodegen),
93 Box::new(elixir::ElixirCodegen),
94 Box::new(gleam::GleamE2eCodegen),
95 Box::new(r::RCodegen),
96 Box::new(wasm::WasmCodegen),
97 Box::new(c::CCodegen),
98 Box::new(zig::ZigE2eCodegen),
99 Box::new(dart::DartE2eCodegen),
100 Box::new(swift::SwiftE2eCodegen),
101 Box::new(brew::BrewCodegen),
102 ]
103}
104
105pub fn generators_for(languages: &[String]) -> Vec<Box<dyn E2eCodegen>> {
107 all_generators()
108 .into_iter()
109 .filter(|g| languages.iter().any(|l| l == g.language_name()))
110 .collect()
111}
112
113pub(crate) fn resolve_field<'a>(input: &'a serde_json::Value, field_path: &str) -> &'a serde_json::Value {
118 let path = field_path.strip_prefix("input.").unwrap_or(field_path);
119 let mut current = input;
120 for part in path.split('.') {
121 current = current.get(part).unwrap_or(&serde_json::Value::Null);
122 }
123 current
124}