1pub mod brew;
4pub mod c;
5pub mod csharp;
6pub mod elixir;
7pub mod go;
8pub mod java;
9pub mod php;
10pub mod python;
11pub mod r;
12pub mod ruby;
13pub mod rust;
14pub mod typescript;
15pub mod wasm;
16
17use crate::config::E2eConfig;
18use crate::fixture::FixtureGroup;
19use alef_core::backend::GeneratedFile;
20use alef_core::config::AlefConfig;
21use anyhow::Result;
22
23pub(crate) fn normalize_json_keys_to_snake_case(value: &serde_json::Value) -> serde_json::Value {
28 use heck::ToSnakeCase;
29 match value {
30 serde_json::Value::Object(obj) => {
31 let new_obj: serde_json::Map<String, serde_json::Value> = obj
32 .iter()
33 .map(|(k, v)| (k.to_snake_case(), normalize_json_keys_to_snake_case(v)))
34 .collect();
35 serde_json::Value::Object(new_obj)
36 }
37 serde_json::Value::Array(arr) => {
38 serde_json::Value::Array(arr.iter().map(normalize_json_keys_to_snake_case).collect())
39 }
40 other => other.clone(),
41 }
42}
43
44pub trait E2eCodegen: Send + Sync {
46 fn generate(
48 &self,
49 groups: &[FixtureGroup],
50 e2e_config: &E2eConfig,
51 alef_config: &AlefConfig,
52 ) -> Result<Vec<GeneratedFile>>;
53
54 fn language_name(&self) -> &'static str;
56}
57
58pub fn all_generators() -> Vec<Box<dyn E2eCodegen>> {
60 vec![
61 Box::new(rust::RustE2eCodegen),
62 Box::new(python::PythonE2eCodegen),
63 Box::new(typescript::TypeScriptCodegen),
64 Box::new(go::GoCodegen),
65 Box::new(java::JavaCodegen),
66 Box::new(csharp::CSharpCodegen),
67 Box::new(php::PhpCodegen),
68 Box::new(ruby::RubyCodegen),
69 Box::new(elixir::ElixirCodegen),
70 Box::new(r::RCodegen),
71 Box::new(wasm::WasmCodegen),
72 Box::new(c::CCodegen),
73 Box::new(brew::BrewCodegen),
74 ]
75}
76
77pub fn generators_for(languages: &[String]) -> Vec<Box<dyn E2eCodegen>> {
79 all_generators()
80 .into_iter()
81 .filter(|g| languages.iter().any(|l| l == g.language_name()))
82 .collect()
83}
84
85pub(crate) fn resolve_field<'a>(input: &'a serde_json::Value, field_path: &str) -> &'a serde_json::Value {
90 let path = field_path.strip_prefix("input.").unwrap_or(field_path);
91 let mut current = input;
92 for part in path.split('.') {
93 current = current.get(part).unwrap_or(&serde_json::Value::Null);
94 }
95 current
96}