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::{Fixture, FixtureGroup};
42use alef_core::backend::GeneratedFile;
43use alef_core::config::ResolvedCrateConfig;
44use anyhow::Result;
45
46pub(crate) fn should_include_fixture(fixture: &Fixture, language: &str, e2e_config: &E2eConfig) -> bool {
55 if let Some(skip) = &fixture.skip {
56 if skip.should_skip(language) {
57 return false;
58 }
59 }
60 let call_config = e2e_config.resolve_call(fixture.call.as_deref());
61 if call_config.function.is_empty() && !call_config.overrides.contains_key(language) {
62 return false;
63 }
64 true
65}
66
67pub(crate) fn normalize_json_keys_to_snake_case(value: &serde_json::Value) -> serde_json::Value {
72 use heck::ToSnakeCase;
73 match value {
74 serde_json::Value::Object(obj) => {
75 let new_obj: serde_json::Map<String, serde_json::Value> = obj
76 .iter()
77 .map(|(k, v)| (k.to_snake_case(), normalize_json_keys_to_snake_case(v)))
78 .collect();
79 serde_json::Value::Object(new_obj)
80 }
81 serde_json::Value::Array(arr) => {
82 serde_json::Value::Array(arr.iter().map(normalize_json_keys_to_snake_case).collect())
83 }
84 other => other.clone(),
85 }
86}
87
88pub trait E2eCodegen: Send + Sync {
90 fn generate(
92 &self,
93 groups: &[FixtureGroup],
94 e2e_config: &E2eConfig,
95 config: &ResolvedCrateConfig,
96 ) -> Result<Vec<GeneratedFile>>;
97
98 fn language_name(&self) -> &'static str;
100}
101
102pub fn all_generators() -> Vec<Box<dyn E2eCodegen>> {
104 vec![
105 Box::new(rust::RustE2eCodegen),
106 Box::new(python::PythonE2eCodegen),
107 Box::new(typescript::TypeScriptCodegen),
108 Box::new(go::GoCodegen),
109 Box::new(java::JavaCodegen),
110 Box::new(kotlin::KotlinE2eCodegen),
111 Box::new(csharp::CSharpCodegen),
112 Box::new(php::PhpCodegen),
113 Box::new(ruby::RubyCodegen),
114 Box::new(elixir::ElixirCodegen),
115 Box::new(gleam::GleamE2eCodegen),
116 Box::new(r::RCodegen),
117 Box::new(wasm::WasmCodegen),
118 Box::new(c::CCodegen),
119 Box::new(zig::ZigE2eCodegen),
120 Box::new(dart::DartE2eCodegen),
121 Box::new(swift::SwiftE2eCodegen),
122 Box::new(brew::BrewCodegen),
123 ]
124}
125
126pub fn generators_for(languages: &[String]) -> Vec<Box<dyn E2eCodegen>> {
128 all_generators()
129 .into_iter()
130 .filter(|g| languages.iter().any(|l| l == g.language_name()))
131 .collect()
132}
133
134pub(crate) fn resolve_field<'a>(input: &'a serde_json::Value, field_path: &str) -> &'a serde_json::Value {
140 if field_path == "input" {
142 return input;
143 }
144 let path = field_path.strip_prefix("input.").unwrap_or(field_path);
145 let mut current = input;
146 for part in path.split('.') {
147 current = current.get(part).unwrap_or(&serde_json::Value::Null);
148 }
149 current
150}