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