Skip to main content

alef_e2e/codegen/
mod.rs

1//! E2e test code generation trait and language dispatch.
2
3pub mod c;
4pub mod csharp;
5pub mod elixir;
6pub mod go;
7pub mod java;
8pub mod php;
9pub mod python;
10pub mod r;
11pub mod ruby;
12pub mod rust;
13pub mod typescript;
14pub mod wasm;
15
16use crate::config::E2eConfig;
17use crate::fixture::FixtureGroup;
18use alef_core::backend::GeneratedFile;
19use alef_core::config::AlefConfig;
20use anyhow::Result;
21
22/// Convert a JSON value's object keys from camelCase to snake_case recursively.
23///
24/// Used when serializing fixture options for FFI-based languages (Rust, C, Java)
25/// where the receiving Rust type uses default serde (snake_case) without `rename_all`.
26pub(crate) fn normalize_json_keys_to_snake_case(value: &serde_json::Value) -> serde_json::Value {
27    use heck::ToSnakeCase;
28    match value {
29        serde_json::Value::Object(obj) => {
30            let new_obj: serde_json::Map<String, serde_json::Value> = obj
31                .iter()
32                .map(|(k, v)| (k.to_snake_case(), normalize_json_keys_to_snake_case(v)))
33                .collect();
34            serde_json::Value::Object(new_obj)
35        }
36        serde_json::Value::Array(arr) => {
37            serde_json::Value::Array(arr.iter().map(normalize_json_keys_to_snake_case).collect())
38        }
39        other => other.clone(),
40    }
41}
42
43/// Trait for per-language e2e test code generation.
44pub trait E2eCodegen: Send + Sync {
45    /// Generate all e2e test project files for this language.
46    fn generate(
47        &self,
48        groups: &[FixtureGroup],
49        e2e_config: &E2eConfig,
50        alef_config: &AlefConfig,
51    ) -> Result<Vec<GeneratedFile>>;
52
53    /// Language name for display and directory naming.
54    fn language_name(&self) -> &'static str;
55}
56
57/// Get all available e2e code generators.
58pub fn all_generators() -> Vec<Box<dyn E2eCodegen>> {
59    vec![
60        Box::new(rust::RustE2eCodegen),
61        Box::new(python::PythonE2eCodegen),
62        Box::new(typescript::TypeScriptCodegen),
63        Box::new(go::GoCodegen),
64        Box::new(java::JavaCodegen),
65        Box::new(csharp::CSharpCodegen),
66        Box::new(php::PhpCodegen),
67        Box::new(ruby::RubyCodegen),
68        Box::new(elixir::ElixirCodegen),
69        Box::new(r::RCodegen),
70        Box::new(wasm::WasmCodegen),
71        Box::new(c::CCodegen),
72    ]
73}
74
75/// Get e2e code generators for specific language names.
76pub fn generators_for(languages: &[String]) -> Vec<Box<dyn E2eCodegen>> {
77    all_generators()
78        .into_iter()
79        .filter(|g| languages.iter().any(|l| l == g.language_name()))
80        .collect()
81}